static int bgp_auth_parse (struct peer *peer, size_t length) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_AUTH_FAILURE); return -1; }
/* Hold timer expire. This is error of BGP connection. So cut the peer and change to Idle status. */ static int bgp_fsm_holdtime_expire (struct peer *peer) { if (BGP_DEBUG (fsm, FSM)) zlog (peer->log, LOG_DEBUG, "%s [FSM] Hold timer expire", peer->host); /* Send notify to remote peer. */ bgp_notify_send (peer, BGP_NOTIFY_HOLD_ERR, 0); /* Sweep if it is temporary peer. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host); peer_delete (peer); return -1; } return 0; }
/* something went wrong, send notify and tear down */ static int bgp_stop_with_notify (struct peer *peer, u_char code, u_char sub_code) { /* Send notify to remote peer */ bgp_notify_send (peer, code, sub_code); /* Sweep if it is temporary peer. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host); peer_delete (peer); return -1; } /* Clear start timer value to default. */ peer->v_start = BGP_INIT_START_TIMER; /* bgp_stop needs to be invoked while in Established state */ bgp_stop(peer); 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; }
/** * 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; }
static int bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr) { struct stream *s = BGP_INPUT (peer); struct capability_orf_entry entry; afi_t afi; safi_t safi; u_char type; u_char mode; u_int16_t sm_cap = 0; /* capability send-mode receive */ u_int16_t rm_cap = 0; /* capability receive-mode receive */ int i; /* ORF Entry header */ bgp_capability_mp_data (s, &entry.mpc); entry.num = stream_getc (s); afi = entry.mpc.afi; safi = entry.mpc.safi; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u", peer->host, entry.mpc.afi, entry.mpc.safi); /* Check AFI and SAFI. */ if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi)) { zlog_info ("%s Addr-family %d/%d not supported." " Ignoring the ORF capability", peer->host, entry.mpc.afi, entry.mpc.safi); return 0; } /* validate number field */ if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length) { zlog_info ("%s ORF Capability entry length error," " Cap length %u, num %u", peer->host, hdr->length, entry.num); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } for (i = 0 ; i < entry.num ; i++) { type = stream_getc(s); mode = stream_getc(s); /* ORF Mode error check */ switch (mode) { case ORF_MODE_BOTH: case ORF_MODE_SEND: case ORF_MODE_RECEIVE: break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } /* ORF Type and afi/safi error checks */ /* capcode versus type */ switch (hdr->code) { case CAPABILITY_CODE_ORF: switch (type) { case ORF_TYPE_PREFIX: break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } break; case CAPABILITY_CODE_ORF_OLD: switch (type) { case ORF_TYPE_PREFIX_OLD: break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } /* AFI vs SAFI */ if (!((afi == AFI_IP && safi == SAFI_UNICAST) || (afi == AFI_IP && safi == SAFI_MULTICAST) || (afi == AFI_IP6 && safi == SAFI_UNICAST))) { bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s OPEN has %s ORF capability" " as %s for afi/safi: %d/%d", peer->host, LOOKUP (orf_type_str, type), LOOKUP (orf_mode_str, mode), entry.mpc.afi, safi); if (hdr->code == CAPABILITY_CODE_ORF) { sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV; rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV; } else if (hdr->code == CAPABILITY_CODE_ORF_OLD) { sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV; rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV; } else { bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } switch (mode) { case ORF_MODE_BOTH: SET_FLAG (peer->af_cap[afi][safi], sm_cap); SET_FLAG (peer->af_cap[afi][safi], rm_cap); break; case ORF_MODE_SEND: SET_FLAG (peer->af_cap[afi][safi], sm_cap); break; case ORF_MODE_RECEIVE: SET_FLAG (peer->af_cap[afi][safi], rm_cap); break; } } return 0; }
/* Parse open option */ int bgp_open_option_parse (struct peer *peer, u_char length, int *capability) { int ret; u_char *end; u_char opt_type; u_char opt_length; u_char *pnt; u_char *error; u_char error_data[BGP_MAX_PACKET_SIZE]; /* Fetch pointer. */ pnt = stream_pnt (peer->ibuf); ret = 0; opt_type = 0; opt_length = 0; end = pnt + length; error = error_data; if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s rcv OPEN w/ OPTION parameter len: %u", peer->host, length); while (pnt < end) { /* Check the length. */ if (pnt + 2 > end) { 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 = *pnt++; opt_length = *pnt++; /* Option length check. */ if (pnt + opt_length > end) { zlog_info ("%s Option length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%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, pnt, opt_length); break; case BGP_OPEN_OPT_CAP: ret = bgp_capability_parse (peer, pnt, opt_length, &error); *capability = 1; 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; /* Forward pointer. */ pnt += opt_length; } /* 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 is no common capability send Unsupported Capability error. */ if (*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] No common capability", 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; }
/* Parse given capability. */ int bgp_capability_parse (struct peer *peer, u_char *pnt, u_char length, u_char **error) { int ret; u_char *end; struct capability cap; end = pnt + length; while (pnt < end) { afi_t afi; safi_t safi; /* Fetch structure to the byte stream. */ memcpy (&cap, pnt, sizeof (struct capability)); afi = ntohs(cap.mpc.afi); safi = cap.mpc.safi; if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s OPEN has CAPABILITY code: %d, length %d", peer->host, cap.code, cap.length); /* We need at least capability code and capability length. */ if (pnt + 2 > end) { zlog_info ("%s Capability length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } /* Capability length check. */ if (pnt + (cap.length + 2) > end) { zlog_info ("%s Capability length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } /* We know MP Capability Code. */ if (cap.code == CAPABILITY_CODE_MP) { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u", peer->host, afi, safi); /* Ignore capability when override-capability is set. */ if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { /* Set negotiated value. */ ret = bgp_capability_mp (peer, &cap); /* Unsupported Capability. */ if (ret < 0) { /* Store return data. */ memcpy (*error, &cap, cap.length + 2); *error += cap.length + 2; } } } else if (cap.code == CAPABILITY_CODE_REFRESH || cap.code == CAPABILITY_CODE_REFRESH_OLD) { /* Check length. */ if (cap.length != 0) { zlog_info ("%s Route Refresh Capability length error %d", peer->host, cap.length); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s OPEN has ROUTE-REFRESH capability(%s) for all address-families", peer->host, cap.code == CAPABILITY_CODE_REFRESH_OLD ? "old" : "new"); /* BGP refresh capability */ if (cap.code == CAPABILITY_CODE_REFRESH_OLD) SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV); else SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV); } else if (cap.code == CAPABILITY_CODE_ORF || cap.code == CAPABILITY_CODE_ORF_OLD) bgp_capability_orf (peer, &cap, pnt + sizeof (struct capability)); else if (cap.code == CAPABILITY_CODE_DYNAMIC) { /* Check length. */ if (cap.length != 0) { zlog_info ("%s Dynamic Capability length error %d", peer->host, cap.length); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s OPEN has DYNAMIC capability", peer->host); SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV); } else if (cap.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, cap.code); } else { zlog_warn ("%s unrecognized capability code: %d - ignored", peer->host, cap.code); memcpy (*error, &cap, cap.length + 2); *error += cap.length + 2; } pnt += cap.length + 2; } return 0; }
int bgp_capability_orf (struct peer *peer, struct capability *cap, u_char *pnt) { afi_t afi = ntohs(cap->mpc.afi); safi_t safi = cap->mpc.safi; u_char number_of_orfs; u_char type; u_char mode; u_int16_t sm_cap = 0; /* capability send-mode receive */ u_int16_t rm_cap = 0; /* capability receive-mode receive */ int i; /* Check length. */ if (cap->length < 7) { zlog_info ("%s ORF Capability length error %d", peer->host, cap->length); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s OPEN has ORF CAP(%s) for afi/safi: %u/%u", peer->host, (cap->code == CAPABILITY_CODE_ORF ? "new" : "old"), afi, safi); /* Check AFI and SAFI. */ if ((afi != AFI_IP && afi != AFI_IP6) || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST && safi != BGP_SAFI_VPNV4)) { zlog_info ("%s Addr-family %d/%d not supported. Ignoring the ORF capability", peer->host, afi, safi); return -1; } number_of_orfs = *pnt++; for (i = 0 ; i < number_of_orfs ; i++) { type = *pnt++; mode = *pnt++; /* ORF Mode error check */ if (mode != ORF_MODE_BOTH && mode != ORF_MODE_SEND && mode != ORF_MODE_RECEIVE) { bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } /* ORF Type and afi/safi error check */ if (cap->code == CAPABILITY_CODE_ORF) { if (type == ORF_TYPE_PREFIX && ((afi == AFI_IP && safi == SAFI_UNICAST) || (afi == AFI_IP && safi == SAFI_MULTICAST) || (afi == AFI_IP6 && safi == SAFI_UNICAST))) { sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV; rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV; if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s OPEN has Prefixlist ORF(%d) capability as %s for afi/safi: %d/%d", peer->host, ORF_TYPE_PREFIX, (mode == ORF_MODE_SEND ? "SEND" : mode == ORF_MODE_RECEIVE ? "RECEIVE" : "BOTH") , afi, safi); } else { bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } } else if (cap->code == CAPABILITY_CODE_ORF_OLD) { if (type == ORF_TYPE_PREFIX_OLD && ((afi == AFI_IP && safi == SAFI_UNICAST) || (afi == AFI_IP && safi == SAFI_MULTICAST) || (afi == AFI_IP6 && safi == SAFI_UNICAST))) { sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV; rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV; if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s OPEN has Prefixlist ORF(%d) capability as %s for afi/safi: %d/%d", peer->host, ORF_TYPE_PREFIX_OLD, (mode == ORF_MODE_SEND ? "SEND" : mode == ORF_MODE_RECEIVE ? "RECEIVE" : "BOTH") , afi, safi); } else { bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } } else { bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } switch (mode) { case ORF_MODE_BOTH: SET_FLAG (peer->af_cap[afi][safi], sm_cap); SET_FLAG (peer->af_cap[afi][safi], rm_cap); break; case ORF_MODE_SEND: SET_FLAG (peer->af_cap[afi][safi], sm_cap); break; case ORF_MODE_RECEIVE: SET_FLAG (peer->af_cap[afi][safi], rm_cap); break; } } return 0; }