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); }
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 struct list* mcp_pppd_interface_parse(struct stream *data_s) { int type; int len; struct list* digt_list; struct pppd_interface_info* info = NULL; digt_list = list_new(); digt_list->del = (void (*) (void *))mcp_ppp_config_info_free; 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(STREAM_READABLE(data_s) < 2) { zlog_err("mcp<%s:%d> stream readable bytes %d less %d",__FUNCTION__,__LINE__,((data_s)->endp-(data_s)->getp),len); return NULL; } switch(type) { case PPP_INTERFACE_SEQ: info = mcp_pppd_interface_new(); info->seq = stream_getl(data_s); //zlog_err("yang test ...seq:%u", (info->seq)); break; case PPP_INTERFACE_GWID: info->gwid= stream_getl(data_s); //zlog_err("yang test ...gwid:%s", remark_ip2str(info->gwid)); break; case PPP_INTERFACE_SEVTYPE: info->dev_type = stream_getl(data_s); //zlog_err("yang test ...dev_type:%u", (info->dev_type)); break; case PPP_INTERFACE_INTERFACEID: info->interfaceid = stream_getl(data_s); //zlog_err("yang test ...dev_type:%u", (info->dev_type)); break; case PPP_INTERFACE_MULTIFLAGE: info->multi_group = stream_getl(data_s); //zlog_err("yang test ...multi_flag:%u", (info->multi_group)); break; case PPP_INTERFACE_INTERFACEIP: memset(info->interfaceip, 0, sizeof(info->interfaceip)); stream_get(info->interfaceip, data_s, len); //zlog_err("yang test interfaceip:%s", info->interfaceip); break; case PPP_INTERFACE_ENABLE: info->enable = stream_getl(data_s); break; case PPP_INTERFACE_AUTHTYPE: info->auth_type = stream_getl(data_s); //zlog_err("yang test ...auth_type:%u", (info->auth_type)); break; case PPP_INTERFACE_AUTHNAME: memset(info->auth_name, 0, sizeof(info->auth_name)); stream_get(info->auth_name, data_s, len); //zlog_err("yang test auth_name:%s", info->auth_name); break; case PPP_INTERFACE_USERNAME: memset(info->username, 0, sizeof(info->username)); stream_get(info->username, data_s, len); //zlog_err("yang test username:%s", info->username); break; case PPP_INTERFACE_PSWD: memset(info->pswd, 0, sizeof(info->pswd)); stream_get(info->pswd, data_s, len); //zlog_err("yang test pswd:%s", info->pswd); break; case PPP_INTERFACE_TIME: memset(info->time, 0, sizeof(info->time)); stream_get(info->time, data_s, len); //zlog_err("yang test time:%s", info->time); break; case PPP_INTERFACE_REMARK: memset(info->remark, 0, sizeof(info->remark)); stream_get(info->remark, data_s, len); //zlog_err("yang test remark:%s", info->remark); break; case PPP_INTERFACE_ACTION: info->action = stream_getl(data_s); listnode_add(digt_list, info); //zlog_err("yang test ...action:%u", (info->action)); break; default: list_delete(digt_list); zlog_err("mcp<%s:%d> wrong type:%u",__FUNCTION__,__LINE__,type); goto error; } } return digt_list; error: return NULL; }
static struct list* mcp_ppp_multilink_info_parse(struct stream *data_s) { int type; int len; struct list* digt_list; struct pppd_multilink_info* info = NULL; digt_list = list_new(); digt_list->del = (void (*) (void *))mcp_ppp_config_info_free; 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(STREAM_READABLE(data_s) < 2) { zlog_err("mcp<%s:%d> stream readable bytes %d less %d",__FUNCTION__,__LINE__,((data_s)->endp-(data_s)->getp),len); return NULL; } switch(type) { case PPP_MULTILINK_INFO_SEQ: info = mcp_pppd_multilink_malloc_new(); info->seq = stream_getl(data_s); //zlog_err("yang test ...seq:%u", (info->seq)); break; case PPP_MULTILINK_INFO_GWID: info->gwid= stream_getl(data_s); //zlog_err("yang test ...gwid:%s", remark_ip2str(info->gwid)); break; case PPP_MULTILINK_INFO_MULTIIP: memset(info->multi_ip, 0, sizeof(info->multi_ip)); stream_get(info->multi_ip, data_s, len); //zlog_err("yang test multi_ip:%s", info->multi_ip); break; case PPP_MULTILINK_INFO_TIME: memset(info->create_time, 0, sizeof(info->create_time)); stream_get(info->create_time, data_s, len); //zlog_err("yang test create_time:%s", info->create_time); break; case PPP_MULTILINK_INFO_REMARK: memset(info->remark, 0, sizeof(info->remark)); stream_get(info->remark, data_s, len); //zlog_err("yang test remark:%s", info->remark); break; case PPP_MULTILINK_INFO_ACTION: info->action = stream_getl(data_s); listnode_add(digt_list, info); //zlog_err("yang test ...action:%u", (info->action)); break; default: list_delete(digt_list); zlog_err("mcp<%s:%d> wrong type:%u",__FUNCTION__,__LINE__,type); goto error; } } return digt_list; error: return NULL; }
/** * 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; }
/* 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; }
/** * 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; }