static int bgp_capability_restart (struct peer *peer, struct capability_header *caphdr) { struct stream *s = BGP_INPUT (peer); u_int16_t restart_flag_time; int restart_bit = 0; size_t end = stream_get_getp (s) + caphdr->length; SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV); restart_flag_time = stream_getw(s); if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT)) restart_bit = 1; UNSET_FLAG (restart_flag_time, 0xF000); peer->v_gr_restart = restart_flag_time; if (BGP_DEBUG (normal, NORMAL)) { zlog_debug ("%s OPEN has Graceful Restart capability", peer->host); zlog_debug ("%s Peer has%srestarted. Restart Time : %d", peer->host, restart_bit ? " " : " not ", peer->v_gr_restart); } while (stream_get_getp (s) + 4 <= end) { afi_t afi = stream_getw (s); safi_t safi = stream_getc (s); u_char flag = stream_getc (s); if (!bgp_afi_safi_valid_indices (afi, &safi)) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported." " Ignore the Graceful Restart capability", peer->host, afi, safi); } else if (!peer->afc[afi][safi]) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled." " Ignore the Graceful Restart capability", peer->host, afi, safi); } else { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Address family %s is%spreserved", peer->host, afi_safi_print (afi, safi), CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV) ? " " : " not "); SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV); if (CHECK_FLAG (flag, RESTART_F_BIT)) SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV); } } return 0; }
static int mcp_ppp_all_config_syn_parse_update(struct stream *data_s) { int type; int len; struct stream* tmp_s; tmp_s = stream_new(10240); while(STREAM_READABLE(data_s) >= 4) { type = stream_getw(data_s); len = stream_getw(data_s); //zlog_debug("<%s,%d> type:%d len:%d", __FUNCTION__, __LINE__, type, len); if(len == 0) continue; switch(type) { case MCP_PPPD_CONFIG_SYN_REMOT_USERINFO: stream_put(tmp_s, data_s->data + stream_get_getp(data_s), len); mcp_recv_pppd_remote_userinfo_ack(tmp_s); stream_forward_getp(data_s, len); stream_reset(tmp_s); break; case MCP_PPPD_CONFIG_SYN_MULTILINK_INFO: stream_put(tmp_s, data_s->data + stream_get_getp(data_s), len); mcp_recv_pppd_multilink_info_ack(tmp_s); stream_forward_getp(data_s, len); stream_reset(tmp_s); break; case MCP_PPPD_CONFIG_SYN_INTERFACE_INFO: stream_put(tmp_s, data_s->data + stream_get_getp(data_s), len); mcp_recv_pppd_interface_info_ack(tmp_s, 1); stream_forward_getp(data_s, len); stream_reset(tmp_s); break; default: zlog_err("mcp<%s:%d> wrong type:%u",__FUNCTION__,__LINE__,type); goto error; } } stream_free(tmp_s); return 0; error: stream_free(tmp_s); return -1; }
static void ospf_packet_db_desc_dump(struct stream *s, uint16_t length) { struct ospf_db_desc *dd; char dd_flags[8]; uint32_t gp; gp = stream_get_getp(s); dd = (struct ospf_db_desc *)stream_pnt(s); zlog_debug("Database Description"); zlog_debug(" Interface MTU %d", ntohs(dd->mtu)); zlog_debug(" Options %d (%s)", dd->options, ospf_options_dump(dd->options)); zlog_debug(" Flags %d (%s)", dd->flags, ospf_dd_flags_dump(dd->flags, dd_flags, sizeof dd_flags)); zlog_debug(" Sequence Number 0x%08lx", (unsigned long)ntohl(dd->dd_seqnum)); length -= OSPF_HEADER_SIZE + OSPF_DB_DESC_MIN_SIZE; stream_forward_getp(s, OSPF_DB_DESC_MIN_SIZE); ospf_lsa_header_list_dump(s, length); stream_set_getp(s, gp); }
static void ospf_packet_ls_req_dump(struct stream *s, uint16_t length) { uint32_t sp; uint32_t ls_type; struct in_addr ls_id; struct in_addr adv_router; sp = stream_get_getp(s); length -= OSPF_HEADER_SIZE; zlog_debug("Link State Request"); zlog_debug(" # Requests %d", length / 12); for (; length > 0; length -= 12) { ls_type = stream_getl(s); ls_id.s_addr = stream_get_ipv4(s); adv_router.s_addr = stream_get_ipv4(s); zlog_debug(" LS type %d", ls_type); zlog_debug(" Link State ID %s", inet_ntoa(ls_id)); zlog_debug(" Advertising Router %s", inet_ntoa(adv_router)); } stream_set_getp(s, sp); }
void clear_checksum_streams (uint16_t checksum) { struct listnode * node, * nnode; struct sisis_listener * listener; for(ALL_LIST_ELEMENTS (sm->listen_sockets, node, nnode, listener)) { if(stream_get_getp(listener->chksum_stream) < stream_get_endp(listener->chksum_stream)) { uint16_t checksum_head = stream_getw(listener->chksum_stream); if(checksum_head != checksum) { stream_putw(listener->chksum_stream, checksum_head); uint16_t next_checksum = stream_peekw(listener->chksum_stream); while(next_checksum != checksum_head) { next_checksum = stream_getw(listener->chksum_stream); if(next_checksum != checksum) stream_putw(listener->chksum_stream, next_checksum); } } } } }
unsigned int are_checksums_same (void) { int same = 0; int first_iter = 1; struct listnode * node, * nnode; struct sisis_listener * listener; u_int16_t chksum_swp; int i = 0; for(ALL_LIST_ELEMENTS (sm->listen_sockets, node, nnode, listener)) { zlog_debug("iter: %d", i); i++; zlog_debug("getp before: %d", stream_get_getp(listener->chksum_stream)); zlog_debug("endp before: %d", stream_get_endp(listener->chksum_stream)); if(stream_get_endp(listener->chksum_stream) != stream_get_getp(listener->chksum_stream)) { u_int16_t chksum = stream_getw(listener->chksum_stream); zlog_debug("getp after: %d", stream_get_getp(listener->chksum_stream)); zlog_debug("endp after: %d", stream_get_endp(listener->chksum_stream)); zlog_debug("checksum: %d", chksum); if(first_iter) { chksum_swp = chksum; first_iter = 0; } else if(chksum == chksum_swp) { same = 1; chksum_swp = chksum; } else { return 0; } } } return same; }
static int bgp_capability_orf (struct peer *peer, struct capability_header *hdr) { struct stream *s = BGP_INPUT (peer); size_t end = stream_get_getp (s) + hdr->length; assert (stream_get_getp(s) + sizeof(struct capability_orf_entry) <= end); /* We must have at least one ORF entry, as the caller has already done * minimum length validation for the capability code - for ORF there must * at least one ORF entry (header and unknown number of pairs of bytes). */ do { if (bgp_capability_orf_entry (peer, hdr) == -1) return -1; } while (stream_get_getp(s) + sizeof(struct capability_orf_entry) < end); return 0; }
static void ospf_packet_ls_ack_dump(struct stream *s, uint16_t length) { uint32_t sp; length -= OSPF_HEADER_SIZE; sp = stream_get_getp(s); zlog_debug("Link State Acknowledgment"); ospf_lsa_header_list_dump(s, length); stream_set_getp(s, sp); }
void reset_checksum_streams (void) { struct listnode * node, * nnode; struct sisis_listener * listener; for(ALL_LIST_ELEMENTS (sm->listen_sockets, node, nnode, listener)) { if(stream_get_endp(listener->chksum_stream) == stream_get_getp(listener->chksum_stream)) stream_reset(listener->chksum_stream); } }
int svz_tunnel_send_message (struct tclient * tclient) { if (tclient->sock < 0) return -1; switch(buffer_write(tclient->wb, tclient->sock, STREAM_DATA(tclient->obuf) + stream_get_getp(tclient->obuf), stream_get_endp(tclient->obuf) - stream_get_getp(tclient->obuf))) { case BUFFER_ERROR: zlog_warn("%s: buffer_write failed to tclient fd %d, closing", __func__, tclient->sock); return svz_tunnel_failed(tclient); case BUFFER_EMPTY: THREAD_OFF(tclient->t_write); break; case BUFFER_PENDING: THREAD_WRITE_ON(master, tclient->t_write, svz_tunnel_flush_data, tclient, tclient->sock); break; } return 0; }
void ospf_packet_dump(struct stream *s) { struct ospf_header *ospfh; unsigned long gp; /* Preserve pointer. */ gp = stream_get_getp(s); /* OSPF Header dump. */ ospfh = (struct ospf_header *)stream_pnt(s); /* Until detail flag is set, return. */ if (!(term_debug_ospf_packet[ospfh->type - 1] & OSPF_DEBUG_DETAIL)) return; /* Show OSPF header detail. */ ospf_header_dump(ospfh); stream_forward_getp(s, OSPF_HEADER_SIZE); switch (ospfh->type) { case OSPF_MSG_HELLO: ospf_packet_hello_dump(s, ntohs(ospfh->length)); break; case OSPF_MSG_DB_DESC: ospf_packet_db_desc_dump(s, ntohs(ospfh->length)); break; case OSPF_MSG_LS_REQ: ospf_packet_ls_req_dump(s, ntohs(ospfh->length)); break; case OSPF_MSG_LS_UPD: ospf_packet_ls_upd_dump(s, ntohs(ospfh->length)); break; case OSPF_MSG_LS_ACK: ospf_packet_ls_ack_dump(s, ntohs(ospfh->length)); break; default: break; } stream_set_getp(s, gp); }
static void print_stream (struct stream *s) { size_t getp = stream_get_getp (s); printf ("endp: %zu, readable: %zu, writeable: %zu\n", stream_get_endp (s), STREAM_READABLE (s), STREAM_WRITEABLE (s)); while (STREAM_READABLE (s)) { printf ("0x%x ", *stream_pnt (s)); stream_forward_getp (s, 1); } printf ("\n"); /* put getp back to where it was */ stream_set_getp (s, getp); }
/*udp write process*/ int udp_write(struct peer *peer){ struct stream *s; int num; int count =0; int writenum; //get first stream; s = misaka_write_packet (peer->obuf); if (!s) return 0; /* udp Nonblocking write */ do { /* Number of bytes to be sent. */ writenum = stream_get_endp (s) - stream_get_getp (s); /* Call write() system call.*/ num = sendto(peer->fd, STREAM_PNT (s), writenum, \ 0, (struct sockaddr*)&s->dsu.sin, sizeof(struct sockaddr)); if (num < 0) { } if (num != writenum) { } /*OK we send packet so delete packet. */ misaka_packet_delete (peer->obuf); }while (++count < MISAKA_WRITE_PACKET_MAX && (s = misaka_write_packet (peer->obuf)) != NULL); return count; }
static void ospf_packet_ls_upd_dump(struct stream *s, uint16_t length) { uint32_t sp; struct lsa_header *lsa; int lsa_len; uint32_t count; length -= OSPF_HEADER_SIZE; sp = stream_get_getp(s); count = stream_getl(s); length -= 4; zlog_debug("Link State Update"); zlog_debug(" # LSAs %d", count); while (length > 0 && count > 0) { if (length < OSPF_HEADER_SIZE || length % 4 != 0) { zlog_debug(" Remaining %d bytes; Incorrect length.", length); break; } lsa = (struct lsa_header *)stream_pnt(s); lsa_len = ntohs(lsa->length); ospf_lsa_header_dump(lsa); switch (lsa->type) { case OSPF_ROUTER_LSA: ospf_router_lsa_dump(s, length); break; case OSPF_NETWORK_LSA: ospf_network_lsa_dump(s, length); break; case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: ospf_summary_lsa_dump(s, length); break; case OSPF_AS_EXTERNAL_LSA: ospf_as_external_lsa_dump(s, length); break; case OSPF_AS_NSSA_LSA: ospf_as_external_lsa_dump(s, length); break; case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: ospf_opaque_lsa_dump(s, length); break; default: break; } stream_forward_getp(s, lsa_len); length -= lsa_len; count--; } stream_set_getp(s, sp); }
/** * Parse given capability. * XXX: This is reading into a stream, but not using stream API * * @param[out] mp_capability Set to 1 on return iff one or more Multiprotocol * capabilities were encountered. */ static int bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability, u_char **error) { int ret; struct stream *s = BGP_INPUT (peer); size_t end = stream_get_getp (s) + length; assert (STREAM_READABLE (s) >= length); while (stream_get_getp (s) < end) { size_t start; u_char *sp = stream_pnt (s); struct capability_header caphdr; /* We need at least capability code and capability length. */ if (stream_get_getp(s) + 2 > end) { zlog_info ("%s Capability length error (< header)", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } caphdr.code = stream_getc (s); caphdr.length = stream_getc (s); start = stream_get_getp (s); /* Capability length check sanity check. */ if (start + caphdr.length > end) { zlog_info ("%s Capability length error (< length)", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s OPEN has %s capability (%u), length %u", peer->host, LOOKUP (capcode_str, caphdr.code), caphdr.code, caphdr.length); /* Length sanity check, type-specific, for known capabilities */ switch (caphdr.code) { case CAPABILITY_CODE_MP: case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_REFRESH_OLD: case CAPABILITY_CODE_ORF: case CAPABILITY_CODE_ORF_OLD: case CAPABILITY_CODE_RESTART: case CAPABILITY_CODE_AS4: case CAPABILITY_CODE_DYNAMIC: /* Check length. */ if (caphdr.length < cap_minsizes[caphdr.code]) { zlog_info ("%s %s Capability length error: got %u," " expected at least %u", peer->host, LOOKUP (capcode_str, caphdr.code), caphdr.length, (unsigned) cap_minsizes[caphdr.code]); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } /* we deliberately ignore unknown codes, see below */ default: break; } switch (caphdr.code) { case CAPABILITY_CODE_MP: { *mp_capability = 1; /* Ignore capability when override-capability is set. */ if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { /* Set negotiated value. */ ret = bgp_capability_mp (peer, &caphdr); /* Unsupported Capability. */ if (ret < 0) { /* Store return data. */ memcpy (*error, sp, caphdr.length + 2); *error += caphdr.length + 2; } } } break; case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_REFRESH_OLD: { /* BGP refresh capability */ if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD) SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV); else SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV); } break; case CAPABILITY_CODE_ORF: case CAPABILITY_CODE_ORF_OLD: if (bgp_capability_orf (peer, &caphdr)) return -1; break; case CAPABILITY_CODE_RESTART: if (bgp_capability_restart (peer, &caphdr)) return -1; break; case CAPABILITY_CODE_DYNAMIC: SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV); break; case CAPABILITY_CODE_AS4: /* Already handled as a special-case parsing of the capabilities * at the beginning of OPEN processing. So we care not a jot * for the value really, only error case. */ if (!bgp_capability_as4 (peer, &caphdr)) return -1; break; default: if (caphdr.code > 128) { /* We don't send Notification for unknown vendor specific capabilities. It seems reasonable for now... */ zlog_warn ("%s Vendor specific capability %d", peer->host, caphdr.code); } else { zlog_warn ("%s unrecognized capability code: %d - ignored", peer->host, caphdr.code); memcpy (*error, sp, caphdr.length + 2); *error += caphdr.length + 2; } } if (stream_get_getp(s) != (start + caphdr.length)) { if (stream_get_getp(s) > (start + caphdr.length)) zlog_warn ("%s Cap-parser for %s read past cap-length, %u!", peer->host, LOOKUP (capcode_str, caphdr.code), caphdr.length); stream_set_getp (s, start + caphdr.length); } } return 0; }
/* peek into option, stores ASN to *as4 if the AS4 capability was found. * Returns 0 if no as4 found, as4cap value otherwise. */ as_t peek_for_as4_capability (struct peer *peer, u_char length) { struct stream *s = BGP_INPUT (peer); size_t orig_getp = stream_get_getp (s); size_t end = orig_getp + length; as_t as4 = 0; /* The full capability parser will better flag the error.. */ if (STREAM_READABLE(s) < length) return 0; if (BGP_DEBUG (as4, AS4)) zlog_info ("%s [AS4] rcv OPEN w/ OPTION parameter len: %u," " peeking for as4", peer->host, length); /* the error cases we DONT handle, we ONLY try to read as4 out of * correctly formatted options. */ while (stream_get_getp(s) < end) { u_char opt_type; u_char opt_length; /* Check the length. */ if (stream_get_getp (s) + 2 > end) goto end; /* Fetch option type and length. */ opt_type = stream_getc (s); opt_length = stream_getc (s); /* Option length check. */ if (stream_get_getp (s) + opt_length > end) goto end; if (opt_type == BGP_OPEN_OPT_CAP) { unsigned long capd_start = stream_get_getp (s); unsigned long capd_end = capd_start + opt_length; assert (capd_end <= end); while (stream_get_getp (s) < capd_end) { struct capability_header hdr; if (stream_get_getp (s) + 2 > capd_end) goto end; hdr.code = stream_getc (s); hdr.length = stream_getc (s); if ((stream_get_getp(s) + hdr.length) > capd_end) goto end; if (hdr.code == CAPABILITY_CODE_AS4) { if (BGP_DEBUG (as4, AS4)) zlog_info ("[AS4] found AS4 capability, about to parse"); as4 = bgp_capability_as4 (peer, &hdr); goto end; } stream_forward_getp (s, hdr.length); } } } end: stream_set_getp (s, orig_getp); return as4; }
/* basic parsing test */ static void parse_test (struct peer *peer, struct test_segment *t, int type) { int ret; int capability = 0; as_t as4 = 0; int oldfailed = failed; int len = t->len; #define RANDOM_FUZZ 35 stream_reset (peer->ibuf); stream_put (peer->ibuf, NULL, RANDOM_FUZZ); stream_set_getp (peer->ibuf, RANDOM_FUZZ); switch (type) { case CAPABILITY: stream_putc (peer->ibuf, BGP_OPEN_OPT_CAP); stream_putc (peer->ibuf, t->len); break; case DYNCAP: /* for (i = 0; i < BGP_MARKER_SIZE; i++) stream_putc (peer->, 0xff); stream_putw (s, 0); stream_putc (s, BGP_MSG_CAPABILITY);*/ break; } stream_write (peer->ibuf, t->data, t->len); printf ("%s: %s\n", t->name, t->desc); switch (type) { case CAPABILITY: len += 2; /* to cover the OPT-Param header */ case OPT_PARAM: printf ("len: %u\n", len); /* peek_for_as4 wants getp at capibility*/ as4 = peek_for_as4_capability (peer, len); printf ("peek_for_as4: as4 is %u\n", as4); /* and it should leave getp as it found it */ assert (stream_get_getp (peer->ibuf) == RANDOM_FUZZ); ret = bgp_open_option_parse (peer, len, &capability); break; case DYNCAP: ret = bgp_capability_receive (peer, t->len); break; default: printf ("unknown type %u\n", type); exit(1); } if (!ret && t->validate_afi) { safi_t safi = t->safi; if (bgp_afi_safi_valid_indices (t->afi, &safi) != t->afi_valid) failed++; printf ("MP: %u/%u (%u): recv %u, nego %u\n", t->afi, t->safi, safi, peer->afc_recv[t->afi][safi], peer->afc_nego[t->afi][safi]); if (t->afi_valid == VALID_AFI) { if (!peer->afc_recv[t->afi][safi]) failed++; if (!peer->afc_nego[t->afi][safi]) failed++; } } if (as4 != t->peek_for) { printf ("as4 %u != %u\n", as4, t->peek_for); failed++; } printf ("parsed?: %s\n", ret ? "no" : "yes"); if (ret != t->parses) failed++; if (tty) printf ("%s", (failed > oldfailed) ? VT100_RED "failed!" VT100_RESET : VT100_GREEN "OK" VT100_RESET); else printf ("%s", (failed > oldfailed) ? "failed!" : "OK" ); if (failed) printf (" (%u)", failed); printf ("\n\n"); }
int ppp_tcp_write (struct thread *thread) { struct ppp_mcp_sock *peer; struct stream *stream; int num; int write_errno; int val, writenum; /* Yes first of all get peer pointer. */ peer = THREAD_ARG (thread); peer->t_write = NULL; if (peer->fd < 0) { PPPD_DEBUG_TCP("write: peer's fd is negative value %d", peer->fd); return -1; } if(peer->connect_status != CLIENT_CONNECT_SERVER_OK) return -1; while (1) { stream = stream_fifo_head(peer->obuf); if (stream == NULL) return 0; val = fcntl (peer->fd, F_GETFL, 0); fcntl (peer->fd, F_SETFL, val | O_NONBLOCK); /* Number of bytes to be sent. */ writenum = stream_get_endp (stream) - stream_get_getp (stream); /* Call write() system call. */ num = write (peer->fd, STREAM_PNT (stream), writenum); write_errno = errno; fcntl (peer->fd, F_SETFL, val); if (num < 0) { if (write_errno == EWOULDBLOCK || write_errno == EAGAIN || write_errno == EINTR) break; PPPD_DEBUG_TCP("erro,write packet to peer:%s, fd:%u", peer->hostname, peer->fd); ppp_connect_mcp_error_deal(peer); return 0; } /*发送了数据之后,推迟保活定时器*/ if(num > 0) pppd_postpone_keepalive_timer(peer); if (num != writenum) { stream_forward_getp(stream, num); break; } else stream_free(stream_fifo_pop (peer->obuf)); break; } if(stream_fifo_head (peer->obuf)) MCP_WRITE_ON (peer->t_write, ppp_tcp_write, peer, peer->fd); return 0; }
/** * Parse open option. * * @param[out] mp_capability @see bgp_capability_parse() for semantics. */ int bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability) { int ret; u_char *error; u_char error_data[BGP_MAX_PACKET_SIZE]; struct stream *s = BGP_INPUT(peer); size_t end = stream_get_getp (s) + length; ret = 0; error = error_data; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u", peer->host, length); while (stream_get_getp(s) < end) { u_char opt_type; u_char opt_length; /* Must have at least an OPEN option header */ if (STREAM_READABLE(s) < 2) { zlog_info ("%s Option length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } /* Fetch option type and length. */ opt_type = stream_getc (s); opt_length = stream_getc (s); /* Option length check. */ if (STREAM_READABLE (s) < opt_length) { zlog_info ("%s Option length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u", peer->host, opt_type, opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" : opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown", opt_length); switch (opt_type) { case BGP_OPEN_OPT_AUTH: ret = bgp_auth_parse (peer, opt_length); break; case BGP_OPEN_OPT_CAP: ret = bgp_capability_parse (peer, opt_length, mp_capability, &error); break; default: bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_PARAM); ret = -1; break; } /* Parse error. To accumulate all unsupported capability codes, bgp_capability_parse does not return -1 when encounter unsupported capability code. To detect that, please check error and erro_data pointer, like below. */ if (ret < 0) return -1; } /* All OPEN option is parsed. Check capability when strict compare flag is enabled.*/ if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) { /* If Unsupported Capability exists. */ if (error != error_data) { bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL, error_data, error - error_data); return -1; } /* Check local capability does not negotiated with remote peer. */ if (! strict_capability_same (peer)) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL); return -1; } } /* Check there are no common AFI/SAFIs and send Unsupported Capability error. */ if (*mp_capability && ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST] && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) { plog_err (peer->log, "%s [Error] Configured AFI/SAFIs do not " "overlap with received MP capabilities", peer->host); if (error != error_data) bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL, error_data, error - error_data); else bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL); return -1; } } return 0; }