/** * bgp_incoming_connection - handle an incoming connection * @sk: TCP socket * @dummy: unused * * This function serves as a socket hook for accepting of new BGP * connections. It searches a BGP instance corresponding to the peer * which has connected and if such an instance exists, it creates a * &bgp_conn structure, attaches it to the instance and either sends * an Open message or (if there already is an active connection) it * closes the new connection by sending a Notification message. */ static int bgp_incoming_connection(sock *sk, int dummy UNUSED) { struct proto_config *pc; DBG("BGP: Incoming connection from %I port %d\n", sk->daddr, sk->dport); WALK_LIST(pc, config->protos) if (pc->protocol == &proto_bgp && pc->proto) { struct bgp_proto *p = (struct bgp_proto *) pc->proto; if (ipa_equal(p->cf->remote_ip, sk->daddr) && (!ipa_has_link_scope(sk->daddr) || (p->cf->iface == sk->iface))) { /* We are in proper state and there is no other incoming connection */ int acc = (p->p.proto_state == PS_START || p->p.proto_state == PS_UP) && (p->start_state >= BSS_CONNECT) && (!p->incoming_conn.sk); if (p->conn && (p->conn->state == BS_ESTABLISHED) && p->gr_ready) { bgp_store_error(p, NULL, BE_MISC, BEM_GRACEFUL_RESTART); bgp_handle_graceful_restart(p); bgp_conn_enter_idle_state(p->conn); acc = 1; } BGP_TRACE(D_EVENTS, "Incoming connection from %I%J (port %d) %s", sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL, sk->dport, acc ? "accepted" : "rejected"); if (!acc) goto reject; int hops = p->cf->multihop ? : 1; if (sk_set_ttl(sk, p->cf->ttl_security ? 255 : hops) < 0) goto err; if (p->cf->ttl_security) if (sk_set_min_ttl(sk, 256 - hops) < 0) goto err; bgp_setup_conn(p, &p->incoming_conn); bgp_setup_sk(&p->incoming_conn, sk); bgp_send_open(&p->incoming_conn); return 0; err: sk_log_error(sk, p->p.name); log(L_ERR "%s: Incoming connection aborted", p->p.name); rfree(sk); return 0; } }
/** * bgp_close - close a BGP instance * @p: BGP instance * @apply_md5: 0 to disable unsetting MD5 auth * * This function frees and deconfigures shared BGP resources. * @apply_md5 is set to 0 when bgp_close is called as a cleanup * from failed bgp_open(). */ static void bgp_close(struct bgp_proto *p, int apply_md5) { ASSERT(bgp_counter); bgp_counter--; if (p->cf->password && apply_md5) if (sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->iface, NULL) < 0) sk_log_error(bgp_listen_sk, p->p.name); if (!bgp_counter) { rfree(bgp_listen_sk); bgp_listen_sk = NULL; rfree(bgp_linpool); bgp_linpool = NULL; } }
/** * bgp_connect - initiate an outgoing connection * @p: BGP instance * * The bgp_connect() function creates a new &bgp_conn and initiates * a TCP connection to the peer. The rest of connection setup is governed * by the BGP state machine as described in the standard. */ static void bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing connection */ { sock *s; struct bgp_conn *conn = &p->outgoing_conn; int hops = p->cf->multihop ? : 1; DBG("BGP: Connecting\n"); s = sk_new(p->p.pool); s->type = SK_TCP_ACTIVE; s->saddr = p->source_addr; s->daddr = p->cf->remote_ip; s->iface = p->neigh ? p->neigh->iface : NULL; s->dport = BGP_PORT; s->ttl = p->cf->ttl_security ? 255 : hops; s->rbsize = BGP_RX_BUFFER_SIZE; s->tbsize = BGP_TX_BUFFER_SIZE; s->tos = IP_PREC_INTERNET_CONTROL; s->password = p->cf->password; s->tx_hook = bgp_connected; BGP_TRACE(D_EVENTS, "Connecting to %I%J from local address %I%J", s->daddr, p->cf->iface, s->saddr, ipa_has_link_scope(s->saddr) ? s->iface : NULL); bgp_setup_conn(p, conn); bgp_setup_sk(conn, s); bgp_conn_set_state(conn, BS_CONNECT); if (sk_open(s) < 0) goto err; /* Set minimal receive TTL if needed */ if (p->cf->ttl_security) if (sk_set_min_ttl(s, 256 - hops) < 0) goto err; DBG("BGP: Waiting for connect success\n"); bgp_start_timer(conn->connect_retry_timer, p->cf->connect_retry_time); return; err: sk_log_error(s, p->p.name); bgp_sock_err(s, 0); return; }
/** * bgp_open - open a BGP instance * @p: BGP instance * * This function allocates and configures shared BGP resources. * Should be called as the last step during initialization * (when lock is acquired and neighbor is ready). * When error, state changed to PS_DOWN, -1 is returned and caller * should return immediately. */ static int bgp_open(struct bgp_proto *p) { struct config *cfg = p->cf->c.global; int errcode; if (!bgp_listen_sk) bgp_listen_sk = bgp_setup_listen_sk(cfg->listen_bgp_addr, cfg->listen_bgp_port, cfg->listen_bgp_flags); if (!bgp_listen_sk) { errcode = BEM_NO_SOCKET; goto err; } if (!bgp_linpool) bgp_linpool = lp_new(&root_pool, 4080); bgp_counter++; if (p->cf->password) if (sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->iface, p->cf->password) < 0) { sk_log_error(bgp_listen_sk, p->p.name); bgp_close(p, 0); errcode = BEM_INVALID_MD5; goto err; } return 0; err: p->p.disabled = 1; bgp_store_error(p, NULL, BE_MISC, errcode); proto_notify_state(&p->p, PS_DOWN); return -1; }
/** * bgp_incoming_connection - handle an incoming connection * @sk: TCP socket * @dummy: unused * * This function serves as a socket hook for accepting of new BGP * connections. It searches a BGP instance corresponding to the peer * which has connected and if such an instance exists, it creates a * &bgp_conn structure, attaches it to the instance and either sends * an Open message or (if there already is an active connection) it * closes the new connection by sending a Notification message. */ static int bgp_incoming_connection(sock *sk, int dummy UNUSED) { struct bgp_proto *p; int acc, hops; DBG("BGP: Incoming connection from %I port %d\n", sk->daddr, sk->dport); p = bgp_find_proto(sk); if (!p) { log(L_WARN "BGP: Unexpected connect from unknown address %I%J (port %d)", sk->daddr, ipa_is_link_local(sk->daddr) ? sk->iface : NULL, sk->dport); rfree(sk); return 0; } /* We are in proper state and there is no other incoming connection */ acc = (p->p.proto_state == PS_START || p->p.proto_state == PS_UP) && (p->start_state >= BSS_CONNECT) && (!p->incoming_conn.sk); if (p->conn && (p->conn->state == BS_ESTABLISHED) && p->gr_ready) { bgp_store_error(p, NULL, BE_MISC, BEM_GRACEFUL_RESTART); bgp_handle_graceful_restart(p); bgp_conn_enter_idle_state(p->conn); acc = 1; } BGP_TRACE(D_EVENTS, "Incoming connection from %I%J (port %d) %s", sk->daddr, ipa_is_link_local(sk->daddr) ? sk->iface : NULL, sk->dport, acc ? "accepted" : "rejected"); if (!acc) { rfree(sk); return 0; } hops = p->cf->multihop ? : 1; if (sk_set_ttl(sk, p->cf->ttl_security ? 255 : hops) < 0) goto err; if (p->cf->ttl_security) if (sk_set_min_ttl(sk, 256 - hops) < 0) goto err; if (p->cf->enable_extended_messages) { sk->rbsize = BGP_RX_BUFFER_EXT_SIZE; sk->tbsize = BGP_TX_BUFFER_EXT_SIZE; sk_reallocate(sk); } bgp_setup_conn(p, &p->incoming_conn); bgp_setup_sk(&p->incoming_conn, sk); bgp_send_open(&p->incoming_conn); return 0; err: sk_log_error(sk, p->p.name); log(L_ERR "%s: Incoming connection aborted", p->p.name); rfree(sk); return 0; }