if (p->cf->ipatt || p->cf->c.parent)
return 0;
- /* We assume that cf->iface is defined iff cf->local_ip is link-local */
+ /* Set parameters of the listening socket
+ *
+ * If strict_bind is set, we need local_ip and maybe also iface. Mandatory if
+ * local_ip is link-local. If strict_bind is not set, we bind to all addresses
+ * of that family and match the local IP later when accepting the connection. */
+
struct bgp_listen_request *req = mb_allocz(p->p.pool, sizeof *req);
- req->params = (struct bgp_socket_params) {
- .iface = p->cf->strict_bind ? p->cf->iface : NULL,
- .vrf = p->p.vrf,
- .addr = p->cf->strict_bind && ipa_nonzero(p->cf->local_ip) ? p->cf->local_ip :
- (p->ipv4 ? IPA_NONE4 : IPA_NONE6),
- .port = p->cf->local_port,
- .flags = p->cf->free_bind ? SKF_FREEBIND : 0,
- };
+ struct bgp_socket_params *par = &req->params;
+ par->iface = p->cf->strict_bind ? p->cf->iface : NULL;
+ par->vrf = p->p.vrf;
+ par->addr = p->cf->strict_bind && ipa_nonzero(p->cf->local_ip) ? p->cf->local_ip :
+ (p->ipv4 ? IPA_NONE4 : IPA_NONE6);
+ par->port = p->cf->local_port;
+ par->flags = p->cf->free_bind ? SKF_FREEBIND : 0;
+
+ /* Set parameters of the accepted socket */
+ req->local_ip = p->cf->local_ip;
+ req->iface = p->cf->iface;
++ req->ipatt = p->cf->ipatt;
+ req->remote_ip = p->remote_ip;
+ req->remote_range = p->cf->remote_range;
+
+ /* Initialize the incoming socket queue */
+ init_list(&req->incoming_sockets);
+
+ BGP_TRACE(D_EVENTS, "Requesting listen socket at %I%J port %u", req->params.addr, req->params.iface, req->params.port);
+
+ if (bgp_is_dynamic(p))
+ callback_init(&req->incoming_connection, bgp_incoming_connection_dynamic, &main_birdloop);
+ else
+ callback_init(&req->incoming_connection, bgp_incoming_connection_single, p->p.loop);
+
+ req->p = p;
return bgp_listen_open(p, req);
}
* @sk: TCP socket
*
*/
-static struct bgp_proto *
-bgp_find_proto(sock *sk)
+static struct bgp_listen_request *
+bgp_find_proto(struct bgp_socket_private *bs, sock *sk)
{
- struct bgp_proto *best = NULL;
- struct bgp_proto *p;
+ struct bgp_listen_request *best = NULL;
- /* sk->iface is valid only if src or dst address is link-local */
- int link = ipa_is_link_local(sk->saddr) || ipa_is_link_local(sk->daddr);
+ /* sk->iface is valid only if src or dst address is link-local or if strict bind on interface is set */
+ bool link = ipa_is_link_local(sk->saddr) || ipa_is_link_local(sk->daddr);
- WALK_LIST(p, proto_list)
+ struct bgp_listen_request *req; node *nxt;
+ WALK_LIST2(req, nxt, bs->requests, sn)
{
- if ((ipa_equal(req->remote_ip, sk->daddr) || bgp_is_dynamic(req)) &&
- (!req->remote_range || ipa_in_netX(sk->daddr, req->remote_range)) &&
- (req->params.vrf == sk->vrf) &&
- (req->params.port == sk->sport) &&
- (!link || (req->iface == sk->iface) || req->ipatt && sk->iface && iface_patt_match(req->ipatt, sk->iface, NULL)) &&
- (ipa_zero(req->local_ip) || ipa_equal(req->local_ip, sk->saddr)))
- {
- /* Non-dynamic protocol instance matched */
- if (!bgp_is_dynamic(req))
- return req;
- /* Not a BGP */
- if (p->p.proto != &proto_bgp)
- continue;
-
+ /* Remote address configured but not the right one */
- if (!ipa_equal(p->remote_ip, sk->daddr) && !bgp_is_dynamic(p))
++ if (!ipa_equal(req->remote_ip, sk->daddr) && !bgp_is_dynamic(req))
+ continue;
- best = req;
- }
+ /* Remote range configured but the remote address is not in it */
- if (p->cf->remote_range && !ipa_in_netX(sk->daddr, p->cf->remote_range))
++ if (req->remote_range && !ipa_in_netX(sk->daddr, req->remote_range))
+ continue;
+
+ /* Not the right VRF */
- if (p->p.vrf != sk->vrf)
++ if (req->params.vrf != sk->vrf)
+ continue;
+
+ /* Not the right local port */
- if (p->cf->local_port != sk->sport)
++ if (req->params.port != sk->sport)
+ continue;
+
+ /* Local address set but not matching */
- if (!ipa_zero(p->cf->local_ip) && !ipa_equal(p->cf->local_ip, sk->saddr))
++ if (!ipa_zero(req->local_ip) && !ipa_equal(req->local_ip, sk->saddr))
+ continue;
+
+ /* The interface set but not matching */
- if ((link || p->cf->strict_bind) && p->cf->iface && (p->cf->iface != sk->iface))
++ if (link && req->iface && (req->iface != sk->iface))
+ continue;
+
+ /* Interface pattern configured and not matching */
- if ((link || p->cf->strict_bind) && p->cf->ipatt && !iface_patt_match(p->cf->ipatt, sk->iface, NULL))
++ if (link && req->ipatt && (!sk->iface || !iface_patt_match(req->ipatt, sk->iface, NULL)))
+ continue;
+
- best = p;
++ best = req;
+
- if (!bgp_is_dynamic(p))
++ if (!bgp_is_dynamic(req))
+ break;
}
return best;