babel: Don't try to remove multicast seqno request objects from neighbour list

The Babel seqno request code keeps track of which seqno requests are
outstanding for a neighbour by putting them onto a per-neighbour list. When
reusing a seqno request, it will try to remove this node, but if the seqno
request in question was a multicast request with no neighbour attached this
will result in a crash because it tries to remove a list node that wasn't
added to any list.

Fix this by making the list remove conditional. Also add a check so that
seqno requests are only reused if the neighbour also matches, allowing
multiple outstanding requests for the same router ID.

Fixes: ebd5751cde ("Babel: Seqno requests are properly decoupled from neighbors when the underlying interface disappears")
Reported-by: Stefan Haller <stefan.haller@stha.de>
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
This commit is contained in:
Toke Høiland-Jørgensen 2022-05-12 13:50:18 +02:00
parent 207ac48533
commit 8f9a091d30

View file

@ -304,7 +304,7 @@ babel_add_seqno_request(struct babel_proto *p, struct babel_entry *e,
struct babel_seqno_request *sr; struct babel_seqno_request *sr;
WALK_LIST(sr, e->requests) WALK_LIST(sr, e->requests)
if (sr->router_id == router_id) if (sr->router_id == router_id && sr->nbr == nbr)
{ {
/* Found matching or newer */ /* Found matching or newer */
if (ge_mod64k(sr->seqno, seqno) && seqno_request_valid(sr)) if (ge_mod64k(sr->seqno, seqno) && seqno_request_valid(sr))
@ -312,7 +312,8 @@ babel_add_seqno_request(struct babel_proto *p, struct babel_entry *e,
/* Found older */ /* Found older */
rem_node(NODE sr); rem_node(NODE sr);
rem_node(&sr->nbr_node); if (sr->nbr)
rem_node(&sr->nbr_node);
goto found; goto found;
} }
@ -349,17 +350,20 @@ static int
babel_satisfy_seqno_request(struct babel_proto *p, struct babel_entry *e, babel_satisfy_seqno_request(struct babel_proto *p, struct babel_entry *e,
u64 router_id, u16 seqno) u64 router_id, u16 seqno)
{ {
struct babel_seqno_request *sr; struct babel_seqno_request *sr, *srx;
int ret = 0;
WALK_LIST(sr, e->requests) WALK_LIST_DELSAFE(sr, srx, e->requests)
if ((sr->router_id == router_id) && ge_mod64k(seqno, sr->seqno)) if ((sr->router_id == router_id) && ge_mod64k(seqno, sr->seqno))
{ {
/* Found the request, remove it */ /* Found a matching request, remove it; there may be multiple outstanding
* requests, so continue looping
*/
babel_remove_seqno_request(p, sr); babel_remove_seqno_request(p, sr);
return 1; ret = 1;
} }
return 0; return ret;
} }
static void static void