X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/3b46f347ca330d3a063aeede8e96e00265dfaab6..82cfcd4391f9f6c748634bfd7b48a44f42e6a53d:/print-openflow-1.0.c diff --git a/print-openflow-1.0.c b/print-openflow-1.0.c index dd42866a..00c4fdd3 100644 --- a/print-openflow-1.0.c +++ b/print-openflow-1.0.c @@ -97,31 +97,7 @@ #define OFPT_BARRIER_REPLY 0x13 #define OFPT_QUEUE_GET_CONFIG_REQUEST 0x14 #define OFPT_QUEUE_GET_CONFIG_REPLY 0x15 -static const struct tok ofpt_str[] = { - { OFPT_HELLO, "HELLO" }, - { OFPT_ERROR, "ERROR" }, - { OFPT_ECHO_REQUEST, "ECHO_REQUEST" }, - { OFPT_ECHO_REPLY, "ECHO_REPLY" }, - { OFPT_VENDOR, "VENDOR" }, - { OFPT_FEATURES_REQUEST, "FEATURES_REQUEST" }, - { OFPT_FEATURES_REPLY, "FEATURES_REPLY" }, - { OFPT_GET_CONFIG_REQUEST, "GET_CONFIG_REQUEST" }, - { OFPT_GET_CONFIG_REPLY, "GET_CONFIG_REPLY" }, - { OFPT_SET_CONFIG, "SET_CONFIG" }, - { OFPT_PACKET_IN, "PACKET_IN" }, - { OFPT_FLOW_REMOVED, "FLOW_REMOVED" }, - { OFPT_PORT_STATUS, "PORT_STATUS" }, - { OFPT_PACKET_OUT, "PACKET_OUT" }, - { OFPT_FLOW_MOD, "FLOW_MOD" }, - { OFPT_PORT_MOD, "PORT_MOD" }, - { OFPT_STATS_REQUEST, "STATS_REQUEST" }, - { OFPT_STATS_REPLY, "STATS_REPLY" }, - { OFPT_BARRIER_REQUEST, "BARRIER_REQUEST" }, - { OFPT_BARRIER_REPLY, "BARRIER_REPLY" }, - { OFPT_QUEUE_GET_CONFIG_REQUEST, "QUEUE_GET_CONFIG_REQUEST" }, - { OFPT_QUEUE_GET_CONFIG_REPLY, "QUEUE_GET_CONFIG_REPLY" }, - { 0, NULL } -}; +#define OFPT_MAX OFPT_QUEUE_GET_CONFIG_REPLY #define OFPPC_PORT_DOWN (1U <<0) #define OFPPC_NO_STP (1U <<1) @@ -342,7 +318,6 @@ static const struct tok ofp_capabilities_bm[] = { #define OFPC_FRAG_NORMAL 0x0000U #define OFPC_FRAG_DROP 0x0001U #define OFPC_FRAG_REASM 0x0002U -#define OFPC_FRAG_MASK 0x0003U static const struct tok ofp_config_str[] = { { OFPC_FRAG_NORMAL, "FRAG_NORMAL" }, { OFPC_FRAG_DROP, "FRAG_DROP" }, @@ -557,21 +532,26 @@ static const struct uint_tokary of10_ofpet2tokary[] = { /* uint2tokary() does not use array termination. */ }; +/* lengths (fixed or minimal) of particular message types, where not 0 */ +#define OF_SWITCH_CONFIG_FIXLEN (12U - OF_HEADER_FIXLEN) +#define OF_FEATURES_REPLY_MINLEN (32U - OF_HEADER_FIXLEN) +#define OF_PORT_STATUS_FIXLEN (64U - OF_HEADER_FIXLEN) +#define OF_PORT_MOD_FIXLEN (32U - OF_HEADER_FIXLEN) +#define OF_PACKET_IN_MINLEN (20U - OF_HEADER_FIXLEN) /* with 2 mock octets */ +#define OF_PACKET_OUT_MINLEN (16U - OF_HEADER_FIXLEN) +#define OF_FLOW_MOD_MINLEN (72U - OF_HEADER_FIXLEN) +#define OF_FLOW_REMOVED_FIXLEN (88U - OF_HEADER_FIXLEN) +#define OF_ERROR_MSG_MINLEN (12U - OF_HEADER_FIXLEN) +#define OF_STATS_REQUEST_MINLEN (12U - OF_HEADER_FIXLEN) +#define OF_STATS_REPLY_MINLEN (12U - OF_HEADER_FIXLEN) +#define OF_VENDOR_MINLEN (12U - OF_HEADER_FIXLEN) +#define OF_QUEUE_GET_CONFIG_REQUEST_FIXLEN (12U - OF_HEADER_FIXLEN) +#define OF_QUEUE_GET_CONFIG_REPLY_MINLEN (16U - OF_HEADER_FIXLEN) + /* lengths (fixed or minimal) of particular protocol structures */ -#define OF_SWITCH_CONFIG_FIXLEN 12 #define OF_PHY_PORT_FIXLEN 48 -#define OF_FEATURES_REPLY_MINLEN 32 -#define OF_PORT_STATUS_FIXLEN 64 -#define OF_PORT_MOD_FIXLEN 32 -#define OF_PACKET_IN_MINLEN 20 /* with 2 mock octets */ #define OF_ACTION_MINLEN 8 -#define OF_PACKET_OUT_MINLEN 16 #define OF_MATCH_FIXLEN 40 -#define OF_FLOW_MOD_MINLEN 72 -#define OF_FLOW_REMOVED_FIXLEN 88 -#define OF_ERROR_MSG_MINLEN 12 -#define OF_STATS_REQUEST_MINLEN 12 -#define OF_STATS_REPLY_MINLEN 12 #define OF_DESC_STATS_REPLY_FIXLEN 1056 #define OF_FLOW_STATS_REQUEST_FIXLEN 44 #define OF_FLOW_STATS_REPLY_MINLEN 88 @@ -579,12 +559,9 @@ static const struct uint_tokary of10_ofpet2tokary[] = { #define OF_TABLE_STATS_REPLY_FIXLEN 64 #define OF_PORT_STATS_REQUEST_FIXLEN 8 #define OF_PORT_STATS_REPLY_FIXLEN 104 -#define OF_VENDOR_MINLEN 12 #define OF_QUEUE_PROP_MINLEN 8 #define OF_QUEUE_PROP_MIN_RATE_FIXLEN 16 #define OF_PACKET_QUEUE_MINLEN 8 -#define OF_QUEUE_GET_CONFIG_REQUEST_FIXLEN 12 -#define OF_QUEUE_GET_CONFIG_REPLY_MINLEN 16 #define OF_QUEUE_STATS_REQUEST_FIXLEN 8 #define OF_QUEUE_STATS_REPLY_FIXLEN 32 @@ -695,12 +672,6 @@ static const struct tok bsn_onoff_str[] = { { 0, NULL }, }; -/* [OF10] Section 5.1 */ -const char * of10_msgtype_str(const uint8_t type) -{ - return tok2str(ofpt_str, "invalid (0x%02x)", type); -} - static const char * vlan_str(const uint16_t vid) { @@ -728,12 +699,12 @@ of10_bsn_message_print(netdissect_options *ndo, { uint32_t subtype; - if (len < 4) - goto invalid; + ND_PRINT("\n\t"); + ND_ICHECK_U(len, <, 4); /* subtype */ subtype = GET_BE_U_4(cp); OF_FWD(4); - ND_PRINT("\n\t subtype %s", tok2str(bsn_subtype_str, "unknown (0x%08x)", subtype)); + ND_PRINT(" subtype %s", tok2str(bsn_subtype_str, "unknown (0x%08x)", subtype)); switch (subtype) { case BSN_GET_IP_MASK_REQUEST: /* @@ -748,8 +719,7 @@ of10_bsn_message_print(netdissect_options *ndo, * +---------------+---------------+---------------+---------------+ * */ - if (len != 8) - goto invalid; + ND_ICHECK_U(len, !=, 8); /* index */ ND_PRINT(", index %u", GET_U_1(cp)); OF_FWD(1); @@ -771,8 +741,7 @@ of10_bsn_message_print(netdissect_options *ndo, * +---------------+---------------+---------------+---------------+ * */ - if (len != 8) - goto invalid; + ND_ICHECK_U(len, !=, 8); /* index */ ND_PRINT(", index %u", GET_U_1(cp)); OF_FWD(1); @@ -794,8 +763,7 @@ of10_bsn_message_print(netdissect_options *ndo, * +---------------+---------------+---------------+---------------+ * */ - if (len != 4) - goto invalid; + ND_ICHECK_U(len, !=, 4); /* report_mirror_ports */ ND_PRINT(", report_mirror_ports %s", tok2str(bsn_onoff_str, "bogus (%u)", GET_U_1(cp))); @@ -817,8 +785,7 @@ of10_bsn_message_print(netdissect_options *ndo, * +---------------+---------------+---------------+---------------+ * */ - if (len) - goto invalid; + ND_ICHECK_U(len, !=, 0); break; case BSN_VIRTUAL_PORT_REMOVE_REQUEST: /* @@ -831,8 +798,7 @@ of10_bsn_message_print(netdissect_options *ndo, * +---------------+---------------+---------------+---------------+ * */ - if (len != 4) - goto invalid; + ND_ICHECK_U(len, !=, 4); /* vport_no */ ND_PRINT(", vport_no %u", GET_BE_U_4(cp)); break; @@ -849,14 +815,13 @@ of10_bsn_message_print(netdissect_options *ndo, * +---------------+---------------+-------- * */ - if (len < 4) - goto invalid; + ND_ICHECK_U(len, <, 4); /* service */ ND_PRINT(", service %u", GET_BE_U_4(cp)); OF_FWD(4); /* data */ ND_PRINT(", data '"); - nd_printn(ndo, cp, len, NULL); + nd_printjn(ndo, cp, len); ND_PRINT("'"); break; case BSN_SHELL_OUTPUT: @@ -873,7 +838,7 @@ of10_bsn_message_print(netdissect_options *ndo, /* already checked that len >= 4 */ /* data */ ND_PRINT(", data '"); - nd_printn(ndo, cp, len, NULL); + nd_printjn(ndo, cp, len); ND_PRINT("'"); break; case BSN_SHELL_STATUS: @@ -887,8 +852,7 @@ of10_bsn_message_print(netdissect_options *ndo, * +---------------+---------------+---------------+---------------+ * */ - if (len != 4) - goto invalid; + ND_ICHECK_U(len, !=, 4); /* status */ ND_PRINT(", status 0x%08x", GET_BE_U_4(cp)); break; @@ -908,12 +872,12 @@ of10_bsn_actions_print(netdissect_options *ndo, { uint32_t subtype, vlan_tag; - if (len < 4) - goto invalid; + ND_PRINT("\n\t "); + ND_ICHECK_U(len, <, 4); /* subtype */ subtype = GET_BE_U_4(cp); OF_FWD(4); - ND_PRINT("\n\t subtype %s", tok2str(bsn_action_subtype_str, "unknown (0x%08x)", subtype)); + ND_PRINT(" subtype %s", tok2str(bsn_action_subtype_str, "unknown (0x%08x)", subtype)); switch (subtype) { case BSN_ACTION_MIRROR: /* @@ -930,8 +894,7 @@ of10_bsn_actions_print(netdissect_options *ndo, * +---------------+---------------+---------------+---------------+ * */ - if (len != 12) - goto invalid; + ND_ICHECK_U(len, !=, 12); /* dest_port */ ND_PRINT(", dest_port %u", GET_BE_U_4(cp)); OF_FWD(4); @@ -973,8 +936,7 @@ of10_vendor_action_print(netdissect_options *ndo, uint32_t vendor; void (*decoder)(netdissect_options *, const u_char *, u_int); - if (len < 4) - goto invalid; + ND_ICHECK_U(len, <, 4); /* vendor */ vendor = GET_BE_U_4(cp); OF_FWD(4); @@ -991,6 +953,7 @@ invalid: /* skip the undersized data */ ND_TCHECK_LEN(cp, len); } +/* [OF10] Section 5.5.4 */ static void of10_vendor_message_print(netdissect_options *ndo, const u_char *cp, u_int len) @@ -998,8 +961,6 @@ of10_vendor_message_print(netdissect_options *ndo, uint32_t vendor; void (*decoder)(netdissect_options *, const u_char *, u_int); - if (len < 4) - goto invalid; /* vendor */ vendor = GET_BE_U_4(cp); OF_FWD(4); @@ -1009,11 +970,6 @@ of10_vendor_message_print(netdissect_options *ndo, vendor == OUI_BSN ? of10_bsn_message_print : of_data_print; decoder(ndo, cp, len); - return; - -invalid: /* skip the undersized data */ - nd_print_invalid(ndo); - ND_TCHECK_LEN(cp, len); } /* Vendor ID is mandatory, data is optional. */ @@ -1023,8 +979,7 @@ of10_vendor_data_print(netdissect_options *ndo, { uint32_t vendor; - if (len < 4) - goto invalid; + ND_ICHECK_U(len, <, 4); /* vendor */ vendor = GET_BE_U_4(cp); OF_FWD(4); @@ -1052,75 +1007,76 @@ of10_packet_data_print(netdissect_options *ndo, } ndo->ndo_vflag -= 3; ND_PRINT(", frame decoding below\n"); + /* + * The encapsulated Ethernet frame is not necessarily the last + * data of this packet (i.e. there may be more OpenFlow messages + * after the current OFPT_PACKET_IN/OFPT_PACKET_OUT message, in + * which case the current (outer) packet's snapshot end is not + * what ether_print() needs to decode an Ethernet frame nested in + * the middle of a TCP payload. + */ + const u_char *snapend_save = ndo->ndo_snapend; + ndo->ndo_snapend = ND_MIN(cp + len, ndo->ndo_snapend); ether_print(ndo, cp, len, ND_BYTES_AVAILABLE_AFTER(cp), NULL, NULL); + ndo->ndo_snapend = snapend_save; ndo->ndo_vflag += 3; } /* [OF10] Section 5.2.1 */ static void -of10_phy_ports_print(netdissect_options *ndo, - const u_char *cp, u_int len) +of10_phy_port_print(netdissect_options *ndo, + const u_char *cp) { - while (len) { - uint32_t state; - - if (len < OF_PHY_PORT_FIXLEN) - goto invalid; - /* port_no */ - ND_PRINT("\n\t port_no %s", - tok2str(ofpp_str, "%u", GET_BE_U_2(cp))); - OF_FWD(2); - /* hw_addr */ - ND_PRINT(", hw_addr %s", GET_ETHERADDR_STRING(cp)); - OF_FWD(MAC_ADDR_LEN); - /* name */ - ND_PRINT(", name '"); - (void)nd_print(ndo, cp, cp + OFP_MAX_PORT_NAME_LEN); - ND_PRINT("'"); - OF_FWD(OFP_MAX_PORT_NAME_LEN); + uint32_t state; - if (ndo->ndo_vflag < 2) { - OF_CHK_FWD(24); - continue; - } - /* config */ - ND_PRINT("\n\t config 0x%08x", GET_BE_U_4(cp)); - of_bitmap_print(ndo, ofppc_bm, GET_BE_U_4(cp), OFPPC_U); - OF_FWD(4); - /* state */ - state = GET_BE_U_4(cp); - /* - * Decode the code point and the single bit separately, but - * format the result as a single sequence of comma-separated - * strings (see the comments at the OFPPS_ props). - */ - ND_PRINT("\n\t state 0x%08x (%s%s)%s", state, - tok2str(ofpps_stp_str, "", state & OFPPS_STP_MASK), - state & OFPPS_LINK_DOWN ? ", LINK_DOWN" : "", - state & OFPPS_U ? " (bogus)" : ""); - OF_FWD(4); - /* curr */ - ND_PRINT("\n\t curr 0x%08x", GET_BE_U_4(cp)); - of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U); - OF_FWD(4); - /* advertised */ - ND_PRINT("\n\t advertised 0x%08x", GET_BE_U_4(cp)); - of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U); - OF_FWD(4); - /* supported */ - ND_PRINT("\n\t supported 0x%08x", GET_BE_U_4(cp)); - of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U); - OF_FWD(4); - /* peer */ - ND_PRINT("\n\t peer 0x%08x", GET_BE_U_4(cp)); - of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U); - OF_FWD(4); - } /* while */ - return; + /* port_no */ + ND_PRINT("\n\t port_no %s", + tok2str(ofpp_str, "%u", GET_BE_U_2(cp))); + cp += 2; + /* hw_addr */ + ND_PRINT(", hw_addr %s", GET_ETHERADDR_STRING(cp)); + cp += MAC_ADDR_LEN; + /* name */ + ND_PRINT(", name '"); + nd_printjnp(ndo, cp, OFP_MAX_PORT_NAME_LEN); + ND_PRINT("'"); + cp += OFP_MAX_PORT_NAME_LEN; -invalid: /* skip the undersized trailing data */ - nd_print_invalid(ndo); - ND_TCHECK_LEN(cp, len); + if (ndo->ndo_vflag < 2) { + ND_TCHECK_LEN(cp, 24); + return; + } + /* config */ + ND_PRINT("\n\t config 0x%08x", GET_BE_U_4(cp)); + of_bitmap_print(ndo, ofppc_bm, GET_BE_U_4(cp), OFPPC_U); + cp += 4; + /* state */ + state = GET_BE_U_4(cp); + /* + * Decode the code point and the single bit separately, but + * format the result as a single sequence of comma-separated + * strings (see the comments at the OFPPS_ props). + */ + ND_PRINT("\n\t state 0x%08x (%s%s)%s", state, + tok2str(ofpps_stp_str, "", state & OFPPS_STP_MASK), + state & OFPPS_LINK_DOWN ? ", LINK_DOWN" : "", + state & OFPPS_U ? " (bogus)" : ""); + cp += 4; + /* curr */ + ND_PRINT("\n\t curr 0x%08x", GET_BE_U_4(cp)); + of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U); + cp += 4; + /* advertised */ + ND_PRINT("\n\t advertised 0x%08x", GET_BE_U_4(cp)); + of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U); + cp += 4; + /* supported */ + ND_PRINT("\n\t supported 0x%08x", GET_BE_U_4(cp)); + of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U); + cp += 4; + /* peer */ + ND_PRINT("\n\t peer 0x%08x", GET_BE_U_4(cp)); + of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U); } /* [OF10] Section 5.2.2 */ @@ -1132,18 +1088,18 @@ of10_queue_props_print(netdissect_options *ndo, uint16_t property, plen; u_char plen_bogus = 0, skip = 0; - if (len < OF_QUEUE_PROP_MINLEN) - goto invalid; + ND_PRINT("\n\t "); + ND_ICHECKMSG_U("remaining length", len, <, OF_QUEUE_PROP_MINLEN); /* property */ property = GET_BE_U_2(cp); OF_FWD(2); - ND_PRINT("\n\t property %s", tok2str(ofpqt_str, "invalid (0x%04x)", property)); + ND_PRINT(" property %s", tok2str(ofpqt_str, "invalid (0x%04x)", property)); /* len */ plen = GET_BE_U_2(cp); OF_FWD(2); ND_PRINT(", len %u", plen); - if (plen < OF_QUEUE_PROP_MINLEN || plen > len + 4) - goto invalid; + ND_ICHECKMSG_U("property length", plen, <, OF_QUEUE_PROP_MINLEN); + ND_ICHECKMSG_U("property length", plen, >, len + 4); /* pad */ /* Sometimes the last field, check bounds. */ OF_CHK_FWD(4); @@ -1198,17 +1154,17 @@ of10_queues_print(netdissect_options *ndo, while (len) { uint16_t desclen; - if (len < OF_PACKET_QUEUE_MINLEN) - goto invalid; + ND_PRINT("\n\t "); + ND_ICHECKMSG_U("remaining length", len, <, OF_PACKET_QUEUE_MINLEN); /* queue_id */ - ND_PRINT("\n\t queue_id %u", GET_BE_U_4(cp)); + ND_PRINT(" queue_id %u", GET_BE_U_4(cp)); OF_FWD(4); /* len */ desclen = GET_BE_U_2(cp); OF_FWD(2); ND_PRINT(", len %u", desclen); - if (desclen < OF_PACKET_QUEUE_MINLEN || desclen > len + 6) - goto invalid; + ND_ICHECKMSG_U("prop. desc. length", desclen, <, OF_PACKET_QUEUE_MINLEN); + ND_ICHECKMSG_U("prop. desc. length", desclen, >, len + 6); /* pad */ /* Sometimes the last field, check bounds. */ OF_CHK_FWD(2); @@ -1323,12 +1279,12 @@ of10_actions_print(netdissect_options *ndo, uint16_t type, alen, output_port; u_char alen_bogus = 0, skip = 0; - if (len < OF_ACTION_MINLEN) - goto invalid; + ND_PRINT("%saction", pfx); + ND_ICHECKMSG_U("remaining length", len, <, OF_ACTION_MINLEN); /* type */ type = GET_BE_U_2(cp); OF_FWD(2); - ND_PRINT("%saction type %s", pfx, tok2str(ofpat_str, "invalid (0x%04x)", type)); + ND_PRINT(" type %s", tok2str(ofpat_str, "invalid (0x%04x)", type)); /* length */ alen = GET_BE_U_2(cp); OF_FWD(2); @@ -1341,8 +1297,8 @@ of10_actions_print(netdissect_options *ndo, */ /* On action size underrun/overrun skip the rest of the action list. */ - if (alen < OF_ACTION_MINLEN || alen > len + 4) - goto invalid; + ND_ICHECK_U(alen, <, OF_ACTION_MINLEN); + ND_ICHECK_U(alen, >, len + 4); /* * After validating the basic length constraint it will be safe * to skip the current action if the action size is not valid @@ -1500,7 +1456,29 @@ of10_features_reply_print(netdissect_options *ndo, of_bitmap_print(ndo, ofpat_bm, GET_BE_U_4(cp), OFPAT_U); OF_FWD(4); /* ports */ - of10_phy_ports_print(ndo, cp, len); + while (len) { + ND_ICHECKMSG_U("\n\t port def. length", len, <, OF_PHY_PORT_FIXLEN); + of10_phy_port_print(ndo, cp); + OF_FWD(OF_PHY_PORT_FIXLEN); + } + return; + +invalid: /* skip the undersized trailing data */ + nd_print_invalid(ndo); + ND_TCHECK_LEN(cp, len); +} + +/* [OF10] Section 5.3.2 */ +static void +of10_switch_config_msg_print(netdissect_options *ndo, + const u_char *cp, u_int len _U_) +{ + /* flags */ + ND_PRINT("\n\t flags %s", + tok2str(ofp_config_str, "invalid (0x%04x)", GET_BE_U_2(cp))); + cp += 2; + /* miss_send_len */ + ND_PRINT(", miss_send_len %u", GET_BE_U_2(cp)); } /* [OF10] Section 5.3.3 */ @@ -1554,7 +1532,7 @@ of10_flow_mod_print(netdissect_options *ndo, /* ibid */ static void of10_port_mod_print(netdissect_options *ndo, - const u_char *cp) + const u_char *cp, u_int len _U_) { /* port_no */ ND_PRINT("\n\t port_no %s", tok2str(ofpp_str, "%u", GET_BE_U_2(cp))); @@ -1563,15 +1541,15 @@ of10_port_mod_print(netdissect_options *ndo, ND_PRINT(", hw_addr %s", GET_ETHERADDR_STRING(cp)); cp += MAC_ADDR_LEN; /* config */ - ND_PRINT("\n\t config 0x%08x", GET_BE_U_4(cp)); + ND_PRINT("\n\t config 0x%08x", GET_BE_U_4(cp)); of_bitmap_print(ndo, ofppc_bm, GET_BE_U_4(cp), OFPPC_U); cp += 4; /* mask */ - ND_PRINT("\n\t mask 0x%08x", GET_BE_U_4(cp)); + ND_PRINT("\n\t mask 0x%08x", GET_BE_U_4(cp)); of_bitmap_print(ndo, ofppc_bm, GET_BE_U_4(cp), OFPPC_U); cp += 4; /* advertise */ - ND_PRINT("\n\t advertise 0x%08x", GET_BE_U_4(cp)); + ND_PRINT("\n\t advertise 0x%08x", GET_BE_U_4(cp)); of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U); cp += 4; /* pad */ @@ -1579,6 +1557,34 @@ of10_port_mod_print(netdissect_options *ndo, ND_TCHECK_4(cp); } +/* [OF10] Section 5.3.4 */ +static void +of10_queue_get_config_request_print(netdissect_options *ndo, + const u_char *cp, u_int len _U_) +{ + /* port */ + ND_PRINT("\n\t port %s", tok2str(ofpp_str, "%u", GET_BE_U_2(cp))); + cp += 2; + /* pad */ + /* Always the last field, check bounds. */ + ND_TCHECK_2(cp); +} + +/* ibid */ +static void +of10_queue_get_config_reply_print(netdissect_options *ndo, + const u_char *cp, u_int len) +{ + /* port */ + ND_PRINT("\n\t port %s", tok2str(ofpp_str, "%u", GET_BE_U_2(cp))); + OF_FWD(2); + /* pad */ + /* Sometimes the last field, check bounds. */ + OF_CHK_FWD(6); + /* queues */ + of10_queues_print(ndo, cp, len); +} + /* [OF10] Section 5.3.5 */ static void of10_stats_request_print(netdissect_options *ndo, @@ -1599,13 +1605,11 @@ of10_stats_request_print(netdissect_options *ndo, switch(type) { case OFPST_DESC: case OFPST_TABLE: - if (len) - goto invalid; + ND_ICHECK_U(len, !=, 0); return; case OFPST_FLOW: case OFPST_AGGREGATE: - if (len != OF_FLOW_STATS_REQUEST_FIXLEN) - goto invalid; + ND_ICHECK_U(len, !=, OF_FLOW_STATS_REQUEST_FIXLEN); /* match */ of10_match_print(ndo, "\n\t ", cp); OF_FWD(OF_MATCH_FIXLEN); @@ -1620,8 +1624,7 @@ of10_stats_request_print(netdissect_options *ndo, tok2str(ofpp_str, "%u", GET_BE_U_2(cp))); return; case OFPST_PORT: - if (len != OF_PORT_STATS_REQUEST_FIXLEN) - goto invalid; + ND_ICHECK_U(len, !=, OF_PORT_STATS_REQUEST_FIXLEN); /* port_no */ ND_PRINT("\n\t port_no %s", tok2str(ofpp_str, "%u", GET_BE_U_2(cp))); @@ -1631,8 +1634,7 @@ of10_stats_request_print(netdissect_options *ndo, OF_CHK_FWD(6); return; case OFPST_QUEUE: - if (len != OF_QUEUE_STATS_REQUEST_FIXLEN) - goto invalid; + ND_ICHECK_U(len, !=, OF_QUEUE_STATS_REQUEST_FIXLEN); /* port_no */ ND_PRINT("\n\t port_no %s", tok2str(ofpp_str, "%u", GET_BE_U_2(cp))); @@ -1659,31 +1661,31 @@ static void of10_desc_stats_reply_print(netdissect_options *ndo, const u_char *cp, u_int len) { - if (len != OF_DESC_STATS_REPLY_FIXLEN) - goto invalid; + ND_PRINT("\n\t "); + ND_ICHECK_U(len, !=, OF_DESC_STATS_REPLY_FIXLEN); /* mfr_desc */ - ND_PRINT("\n\t mfr_desc '"); - (void)nd_print(ndo, cp, cp + DESC_STR_LEN); + ND_PRINT(" mfr_desc '"); + nd_printjnp(ndo, cp, DESC_STR_LEN); ND_PRINT("'"); OF_FWD(DESC_STR_LEN); /* hw_desc */ ND_PRINT("\n\t hw_desc '"); - (void)nd_print(ndo, cp, cp + DESC_STR_LEN); + nd_printjnp(ndo, cp, DESC_STR_LEN); ND_PRINT("'"); OF_FWD(DESC_STR_LEN); /* sw_desc */ ND_PRINT("\n\t sw_desc '"); - (void)nd_print(ndo, cp, cp + DESC_STR_LEN); + nd_printjnp(ndo, cp, DESC_STR_LEN); ND_PRINT("'"); OF_FWD(DESC_STR_LEN); /* serial_num */ ND_PRINT("\n\t serial_num '"); - (void)nd_print(ndo, cp, cp + SERIAL_NUM_LEN); + nd_printjnp(ndo, cp, SERIAL_NUM_LEN); ND_PRINT("'"); OF_FWD(SERIAL_NUM_LEN); /* dp_desc */ ND_PRINT("\n\t dp_desc '"); - (void)nd_print(ndo, cp, cp + DESC_STR_LEN); + nd_printjnp(ndo, cp, DESC_STR_LEN); ND_PRINT("'"); return; @@ -1700,13 +1702,13 @@ of10_flow_stats_reply_print(netdissect_options *ndo, while (len) { uint16_t entry_len; - if (len < OF_FLOW_STATS_REPLY_MINLEN) - goto invalid; + ND_PRINT("\n\t"); + ND_ICHECKMSG_U("remaining length", len, <, OF_FLOW_STATS_REPLY_MINLEN); /* length */ entry_len = GET_BE_U_2(cp); - ND_PRINT("\n\t length %u", entry_len); - if (entry_len < OF_FLOW_STATS_REPLY_MINLEN || entry_len > len) - goto invalid; + ND_PRINT(" length %u", entry_len); + ND_ICHECK_U(entry_len, <, OF_FLOW_STATS_REPLY_MINLEN); + ND_ICHECK_U(entry_len, >, len); OF_FWD(2); /* table_id */ ND_PRINT(", table_id %s", @@ -1759,10 +1761,10 @@ static void of10_aggregate_stats_reply_print(netdissect_options *ndo, const u_char *cp, u_int len) { - if (len != OF_AGGREGATE_STATS_REPLY_FIXLEN) - goto invalid; + ND_PRINT("\n\t"); + ND_ICHECKMSG_U("remaining length", len, !=, OF_AGGREGATE_STATS_REPLY_FIXLEN); /* packet_count */ - ND_PRINT("\n\t packet_count %" PRIu64, GET_BE_U_8(cp)); + ND_PRINT(" packet_count %" PRIu64, GET_BE_U_8(cp)); OF_FWD(8); /* byte_count */ ND_PRINT(", byte_count %" PRIu64, GET_BE_U_8(cp)); @@ -1786,17 +1788,17 @@ of10_table_stats_reply_print(netdissect_options *ndo, const u_char *cp, u_int len) { while (len) { - if (len < OF_TABLE_STATS_REPLY_FIXLEN) - goto invalid; + ND_PRINT("\n\t"); + ND_ICHECKMSG_U("remaining length", len, <, OF_TABLE_STATS_REPLY_FIXLEN); /* table_id */ - ND_PRINT("\n\t table_id %s", + ND_PRINT(" table_id %s", tok2str(tableid_str, "%u", GET_U_1(cp))); OF_FWD(1); /* pad */ OF_FWD(3); /* name */ ND_PRINT(", name '"); - (void)nd_print(ndo, cp, cp + OFP_MAX_TABLE_NAME_LEN); + nd_printjnp(ndo, cp, OFP_MAX_TABLE_NAME_LEN); ND_PRINT("'"); OF_FWD(OFP_MAX_TABLE_NAME_LEN); /* wildcards */ @@ -1829,10 +1831,10 @@ of10_port_stats_reply_print(netdissect_options *ndo, const u_char *cp, u_int len) { while (len) { - if (len < OF_PORT_STATS_REPLY_FIXLEN) - goto invalid; + ND_PRINT("\n\t "); + ND_ICHECKMSG_U("remaining length", len, <, OF_PORT_STATS_REPLY_FIXLEN); /* port_no */ - ND_PRINT("\n\t port_no %s", + ND_PRINT(" port_no %s", tok2str(ofpp_str, "%u", GET_BE_U_2(cp))); OF_FWD(2); if (ndo->ndo_vflag < 2) { @@ -1891,10 +1893,10 @@ of10_queue_stats_reply_print(netdissect_options *ndo, const u_char *cp, u_int len) { while (len) { - if (len < OF_QUEUE_STATS_REPLY_FIXLEN) - goto invalid; + ND_PRINT("\n\t "); + ND_ICHECKMSG_U("remaining length", len, <, OF_QUEUE_STATS_REPLY_FIXLEN); /* port_no */ - ND_PRINT("\n\t port_no %s", + ND_PRINT(" port_no %s", tok2str(ofpp_str, "%u", GET_BE_U_2(cp))); OF_FWD(2); /* pad */ @@ -1968,9 +1970,9 @@ of10_packet_out_print(netdissect_options *ndo, OF_FWD(2); /* actions_len */ actions_len = GET_BE_U_2(cp); + ND_PRINT(", actions_len %u", actions_len); OF_FWD(2); - if (actions_len > len) - goto invalid; + ND_ICHECK_U(actions_len, >, len); /* actions */ of10_actions_print(ndo, "\n\t ", cp, actions_len); OF_FWD(actions_len); @@ -2012,7 +2014,7 @@ of10_packet_in_print(netdissect_options *ndo, /* [OF10] Section 5.4.2 */ static void of10_flow_removed_print(netdissect_options *ndo, - const u_char *cp) + const u_char *cp, u_int len _U_) { /* match */ of10_match_print(ndo, "\n\t ", cp); @@ -2049,6 +2051,22 @@ of10_flow_removed_print(netdissect_options *ndo, ND_PRINT(", byte_count %" PRIu64, GET_BE_U_8(cp)); } +/* [OF10] Section 5.4.3 */ +static void +of10_port_status_print(netdissect_options *ndo, + const u_char *cp, u_int len _U_) +{ + /* reason */ + ND_PRINT("\n\t reason %s", + tok2str(ofppr_str, "invalid (0x%02x)", GET_U_1(cp))); + cp += 1; + /* pad */ + /* No need to check bounds, more data follows. */ + cp += 7; + /* desc */ + of10_phy_port_print(ndo, cp); +} + /* [OF10] Section 5.4.4 */ static void of10_error_print(netdissect_options *ndo, @@ -2074,200 +2092,191 @@ of10_error_print(netdissect_options *ndo, of_data_print(ndo, cp, len); } -void -of10_message_print(netdissect_options *ndo, - const u_char *cp, uint16_t len, const uint8_t type) -{ +static const struct of_msgtypeinfo of10_msgtypeinfo[OFPT_MAX + 1] = { /* - * Here "cp" and "len" stand for the message part beyond the common - * OpenFlow 1.0 header, if any. Subtract OF_HEADER_FIXLEN from the - * type-specific lengths, which include the header length, when (and - * only when) validating the length in this function. No other code - * in this file needs to take OF_HEADER_FIXLEN into account. - * - * Most message types are longer than just the header, and the length - * constraints may be complex. When possible, validate the constraint - * completely here, otherwise check that the message is long enough to - * begin the decoding and let the lower-layer function do any remaining - * validation. + * [OF10] Section 5.5.1 + * Variable-size data. */ - switch (type) { - /* OpenFlow header only. */ - case OFPT_FEATURES_REQUEST: /* [OF10] Section 5.3.1 */ - case OFPT_GET_CONFIG_REQUEST: /* [OF10] Section 5.3.2 */ - case OFPT_BARRIER_REQUEST: /* [OF10] Section 5.3.7 */ - case OFPT_BARRIER_REPLY: /* ibid */ - if (len) - goto invalid; - return; - - /* OpenFlow header and fixed-size message body. */ - case OFPT_SET_CONFIG: /* [OF10] Section 5.3.2 */ - case OFPT_GET_CONFIG_REPLY: /* ibid */ - if (len != OF_SWITCH_CONFIG_FIXLEN - OF_HEADER_FIXLEN) - goto invalid; - if (ndo->ndo_vflag < 1) - break; - /* flags */ - ND_PRINT("\n\t flags %s", - tok2str(ofp_config_str, "invalid (0x%04x)", - GET_BE_U_2(cp))); - OF_FWD(2); - /* miss_send_len */ - ND_PRINT(", miss_send_len %u", GET_BE_U_2(cp)); - return; - case OFPT_PORT_MOD: - if (len != OF_PORT_MOD_FIXLEN - OF_HEADER_FIXLEN) - goto invalid; - if (ndo->ndo_vflag < 1) - break; - of10_port_mod_print(ndo, cp); - return; - case OFPT_QUEUE_GET_CONFIG_REQUEST: /* [OF10] Section 5.3.4 */ - if (len != OF_QUEUE_GET_CONFIG_REQUEST_FIXLEN - OF_HEADER_FIXLEN) - goto invalid; - if (ndo->ndo_vflag < 1) - break; - /* port */ - ND_PRINT("\n\t port %s", - tok2str(ofpp_str, "%u", GET_BE_U_2(cp))); - OF_FWD(2); - /* pad */ - /* Always the last field, check bounds. */ - ND_TCHECK_2(cp); - return; - case OFPT_FLOW_REMOVED: - if (len != OF_FLOW_REMOVED_FIXLEN - OF_HEADER_FIXLEN) - goto invalid; - if (ndo->ndo_vflag < 1) - break; - of10_flow_removed_print(ndo, cp); - return; - case OFPT_PORT_STATUS: /* [OF10] Section 5.4.3 */ - if (len != OF_PORT_STATUS_FIXLEN - OF_HEADER_FIXLEN) - goto invalid; - if (ndo->ndo_vflag < 1) - break; - /* reason */ - ND_PRINT("\n\t reason %s", - tok2str(ofppr_str, "invalid (0x%02x)", GET_U_1(cp))); - OF_FWD(1); - /* pad */ - /* No need to check bounds, more data follows. */ - OF_FWD(7); - /* desc */ - of10_phy_ports_print(ndo, cp, len); - return; - - /* OpenFlow header, fixed-size message body and n * fixed-size data units. */ - case OFPT_FEATURES_REPLY: - if (len < OF_FEATURES_REPLY_MINLEN - OF_HEADER_FIXLEN) - goto invalid; - if (ndo->ndo_vflag < 1) - break; - of10_features_reply_print(ndo, cp, len); - return; - - /* OpenFlow header and variable-size data. */ - case OFPT_HELLO: /* [OF10] Section 5.5.1 */ - case OFPT_ECHO_REQUEST: /* [OF10] Section 5.5.2 */ - case OFPT_ECHO_REPLY: /* [OF10] Section 5.5.3 */ - if (ndo->ndo_vflag < 1) - break; - of_data_print(ndo, cp, len); - return; - - /* OpenFlow header, fixed-size message body and variable-size data. */ - case OFPT_ERROR: - if (len < OF_ERROR_MSG_MINLEN - OF_HEADER_FIXLEN) - goto invalid; - if (ndo->ndo_vflag < 1) - break; - of10_error_print(ndo, cp, len); - return; - case OFPT_VENDOR: - /* [OF10] Section 5.5.4 */ - if (len < OF_VENDOR_MINLEN - OF_HEADER_FIXLEN) - goto invalid; - if (ndo->ndo_vflag < 1) - break; - of10_vendor_message_print(ndo, cp, len); - return; - case OFPT_PACKET_IN: - /* 2 mock octets count in OF_PACKET_IN_MINLEN but not in len */ - if (len < OF_PACKET_IN_MINLEN - 2 - OF_HEADER_FIXLEN) - goto invalid; - if (ndo->ndo_vflag < 1) - break; - of10_packet_in_print(ndo, cp, len); - return; - - /* a. OpenFlow header. */ - /* b. OpenFlow header and one of the fixed-size message bodies. */ - /* c. OpenFlow header, fixed-size message body and variable-size data. */ - case OFPT_STATS_REQUEST: - if (len < OF_STATS_REQUEST_MINLEN - OF_HEADER_FIXLEN) - goto invalid; - if (ndo->ndo_vflag < 1) - break; - of10_stats_request_print(ndo, cp, len); - return; - - /* a. OpenFlow header and fixed-size message body. */ - /* b. OpenFlow header and n * fixed-size data units. */ - /* c. OpenFlow header and n * variable-size data units. */ - /* d. OpenFlow header, fixed-size message body and variable-size data. */ - case OFPT_STATS_REPLY: - if (len < OF_STATS_REPLY_MINLEN - OF_HEADER_FIXLEN) - goto invalid; - if (ndo->ndo_vflag < 1) - break; - of10_stats_reply_print(ndo, cp, len); - return; - - /* OpenFlow header and n * variable-size data units and variable-size data. */ - case OFPT_PACKET_OUT: - if (len < OF_PACKET_OUT_MINLEN - OF_HEADER_FIXLEN) - goto invalid; - if (ndo->ndo_vflag < 1) - break; - of10_packet_out_print(ndo, cp, len); - return; - - /* OpenFlow header, fixed-size message body and n * variable-size data units. */ - case OFPT_FLOW_MOD: - if (len < OF_FLOW_MOD_MINLEN - OF_HEADER_FIXLEN) - goto invalid; - if (ndo->ndo_vflag < 1) - break; - of10_flow_mod_print(ndo, cp, len); - return; - - /* OpenFlow header, fixed-size message body and n * variable-size data units. */ - case OFPT_QUEUE_GET_CONFIG_REPLY: /* [OF10] Section 5.3.4 */ - if (len < OF_QUEUE_GET_CONFIG_REPLY_MINLEN - OF_HEADER_FIXLEN) - goto invalid; - if (ndo->ndo_vflag < 1) - break; - /* port */ - ND_PRINT("\n\t port %s", - tok2str(ofpp_str, "%u", GET_BE_U_2(cp))); - OF_FWD(2); - /* pad */ - /* Sometimes the last field, check bounds. */ - OF_CHK_FWD(6); - /* queues */ - of10_queues_print(ndo, cp, len); - return; - } /* switch (type) */ + { + "HELLO", of_data_print, + REQ_MINLEN, 0 + }, /* - * Not a recognised type or did not print the details, fall back to - * a bounds check. + * [OF10] Section 5.4.4 + * A fixed-size message body and variable-size data. */ - ND_TCHECK_LEN(cp, len); - return; + { + "ERROR", of10_error_print, + REQ_MINLEN, OF_ERROR_MSG_MINLEN + }, + /* + * [OF10] Section 5.5.2 + * Variable-size data. + */ + { + "ECHO_REQUEST", of_data_print, + REQ_MINLEN, 0 + }, + /* + * [OF10] Section 5.5.3 + * Variable-size data. + */ + { + "ECHO_REPLY", of_data_print, + REQ_MINLEN, 0 + }, + /* + * [OF10] Section 5.5.4 + * A fixed-size message body and variable-size data. + */ + { + "VENDOR", of10_vendor_message_print, + REQ_MINLEN, OF_VENDOR_MINLEN + }, + /* + * [OF10] Section 5.3.1 + * No message body. + */ + { + "FEATURES_REQUEST", NULL, + REQ_FIXLEN, 0 + }, + /* + * [OF10] Section 5.3.1 + * A fixed-size message body and n * fixed-size data units. + */ + { + "FEATURES_REPLY", of10_features_reply_print, + REQ_MINLEN, OF_FEATURES_REPLY_MINLEN + }, + /* + * [OF10] Section 5.3.2 + * No message body. + */ + { + "GET_CONFIG_REQUEST", NULL, + REQ_FIXLEN, 0 + }, + /* + * [OF10] Section 5.3.2 + * A fixed-size message body. + */ + { + "GET_CONFIG_REPLY", of10_switch_config_msg_print, + REQ_FIXLEN, OF_SWITCH_CONFIG_FIXLEN + }, + /* + * [OF10] Section 5.3.2 + * A fixed-size message body. + */ + { + "SET_CONFIG", of10_switch_config_msg_print, + REQ_FIXLEN, OF_SWITCH_CONFIG_FIXLEN + }, + /* + * [OF10] Section 5.4.1 + * A fixed-size message body and variable-size data. + * (The 2 mock octets count in OF_PACKET_IN_MINLEN only.) + */ + { + "PACKET_IN", of10_packet_in_print, + REQ_MINLEN, OF_PACKET_IN_MINLEN - 2 + }, + /* + * [OF10] Section 5.4.2 + * A fixed-size message body. + */ + { + "FLOW_REMOVED", of10_flow_removed_print, + REQ_FIXLEN, OF_FLOW_REMOVED_FIXLEN + }, + /* + * [OF10] Section 5.4.3 + * A fixed-size message body. + */ + { + "PORT_STATUS", of10_port_status_print, + REQ_FIXLEN, OF_PORT_STATUS_FIXLEN + }, + /* + * [OF10] Section 5.3.6 + * A fixed-size message body, n * variable-size data units and + * variable-size data. + */ + { + "PACKET_OUT", of10_packet_out_print, + REQ_MINLEN, OF_PACKET_OUT_MINLEN + }, + /* + * [OF10] Section 5.3.3 + * A fixed-size message body and n * variable-size data units. + */ + { + "FLOW_MOD", of10_flow_mod_print, + REQ_MINLEN, OF_FLOW_MOD_MINLEN + }, + /* + * [OF10] Section 5.3.3 + * A fixed-size message body. + */ + { + "PORT_MOD", of10_port_mod_print, + REQ_FIXLEN, OF_PORT_MOD_FIXLEN + }, + /* + * [OF10] Section 5.3.5 + * A fixed-size message body and possibly more data of varying size + * and structure. + */ + { + "STATS_REQUEST", of10_stats_request_print, + REQ_MINLEN, OF_STATS_REQUEST_MINLEN + }, + /* + * [OF10] Section 5.3.5 + * A fixed-size message body and possibly more data of varying size + * and structure. + */ + { + "STATS_REPLY", of10_stats_reply_print, + REQ_MINLEN, OF_STATS_REPLY_MINLEN + }, + /* + * [OF10] Section 5.3.7 + * No message body. + */ + { + "BARRIER_REQUEST", NULL, + REQ_FIXLEN, 0 + }, + /* + * [OF10] Section 5.3.7 + * No message body. + */ + { + "BARRIER_REPLY", NULL, + REQ_FIXLEN, 0 + }, + /* + * [OF10] Section 5.3.4 + * A fixed-size message body. + */ + { + "QUEUE_GET_CONFIG_REQUEST", of10_queue_get_config_request_print, + REQ_FIXLEN, OF_QUEUE_GET_CONFIG_REQUEST_FIXLEN + }, + /* + * [OF10] Section 5.3.4 + * A fixed-size message body and n * variable-size data units. + */ + { + "QUEUE_GET_CONFIG_REPLY", of10_queue_get_config_reply_print, + REQ_MINLEN, OF_QUEUE_GET_CONFIG_REPLY_MINLEN + }, +}; -invalid: /* skip the message body */ - nd_print_invalid(ndo); - ND_TCHECK_LEN(cp, len); +const struct of_msgtypeinfo * +of10_identify_msgtype(const uint8_t type) +{ + return type <= OFPT_MAX ? &of10_msgtypeinfo[type] : NULL; }