]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-openflow-1.0.c
OpenFlow 1.3: Add initial partial support.
[tcpdump] / print-openflow-1.0.c
index 557d1e9c2ecfb4436759de7c654dcef88df428d9..ed9c2b4ca88de0ae031215c625de0f97a703fe85 100644 (file)
@@ -14,7 +14,7 @@
  * The convention is that a printer function returns iff the given structure is
  * completely within the packet buffer; otherwise it processes the part that is
  * within the buffer, sooner of later takes the "truncated packet" shortcut via
- * nd_trunc() and never returns. With that in mind, the function may return
+ * longjmp() and never returns. With that in mind, the function may return
  * without printing the structure completely if it is invalid or the ndo_vflag
  * value is not high enough. This way the calling function can try to decode
  * the next data item.
@@ -65,6 +65,7 @@
 
 #include "netdissect-stdinc.h"
 
+#define ND_LONGJMP_FROM_TCHECK
 #include "netdissect.h"
 #include "extract.h"
 #include "addrtoname.h"
@@ -455,6 +456,7 @@ static const struct tok ofpet_str[] = {
        { OFPET_QUEUE_OP_FAILED, "QUEUE_OP_FAILED" },
        { 0, NULL }
 };
+#define OFPET_MAX OFPET_QUEUE_OP_FAILED /* for of10_error_print() */
 
 #define OFPHFC_INCOMPATIBLE 0x0000U
 #define OFPHFC_EPERM        0x0001U
@@ -542,10 +544,6 @@ static const struct tok ofpqofc_str[] = {
        { 0, NULL }
 };
 
-static const struct tok empty_str[] = {
-       { 0, NULL }
-};
-
 /* lengths (fixed or minimal) of particular protocol structures */
 #define OF_SWITCH_CONFIG_FIXLEN               12
 #define OF_PHY_PORT_FIXLEN                    48
@@ -684,6 +682,12 @@ 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)
 {
@@ -723,24 +727,6 @@ of10_bitmap_print(netdissect_options *ndo,
        ND_PRINT((v & u) ? ") (bogus)" : ")");
 }
 
-static void
-of10_data_print(netdissect_options *ndo,
-                const u_char *cp, const u_int len)
-{
-       if (len == 0)
-               return;
-       /* data */
-       ND_PRINT("\n\t data (%u octets)", len);
-       if (ndo->ndo_vflag >= 2)
-               hex_and_ascii_print(ndo, "\n\t  ", cp, len);
-       else
-               ND_TCHECK_LEN(cp, len);
-       return;
-
-trunc:
-       nd_trunc(ndo);
-}
-
 static void
 of10_bsn_message_print(netdissect_options *ndo,
                        const u_char *cp, u_int len)
@@ -919,9 +905,6 @@ of10_bsn_message_print(netdissect_options *ndo,
 invalid: /* skip the undersized data */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 static void
@@ -986,9 +969,6 @@ of10_bsn_actions_print(netdissect_options *ndo,
 invalid:
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 static void
@@ -1007,16 +987,13 @@ of10_vendor_action_print(netdissect_options *ndo,
        /* data */
        decoder =
                vendor == OUI_BSN         ? of10_bsn_actions_print         :
-               of10_data_print;
+               of_data_print;
        decoder(ndo, cp, len);
        return;
 
 invalid: /* skip the undersized data */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 static void
@@ -1035,16 +1012,13 @@ of10_vendor_message_print(netdissect_options *ndo,
        /* data */
        decoder =
                vendor == OUI_BSN         ? of10_bsn_message_print         :
-               of10_data_print;
+               of_data_print;
        decoder(ndo, cp, len);
        return;
 
 invalid: /* skip the undersized data */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 /* Vendor ID is mandatory, data is optional. */
@@ -1061,15 +1035,12 @@ of10_vendor_data_print(netdissect_options *ndo,
        OF_FWD(4);
        ND_PRINT(", vendor 0x%08x (%s)", vendor, of_vendor_name(vendor));
        /* data */
-       of10_data_print(ndo, cp, len);
+       of_data_print(ndo, cp, len);
        return;
 
 invalid: /* skip the undersized data */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 static void
@@ -1088,10 +1059,6 @@ of10_packet_data_print(netdissect_options *ndo,
        ND_PRINT(", frame decoding below\n");
        ether_print(ndo, cp, len, ND_BYTES_AVAILABLE_AFTER(cp), NULL, NULL);
        ndo->ndo_vflag += 3;
-       return;
-
-trunc:
-       nd_trunc(ndo);
 }
 
 /* [OF10] Section 5.2.1 */
@@ -1149,9 +1116,6 @@ of10_phy_ports_print(netdissect_options *ndo,
 invalid: /* skip the undersized trailing data */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 /* [OF10] Section 5.2.2 */
@@ -1219,9 +1183,6 @@ of10_queue_props_print(netdissect_options *ndo,
 invalid: /* skip the rest of queue properties */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 /* ibid */
@@ -1258,9 +1219,6 @@ of10_queues_print(netdissect_options *ndo,
 invalid: /* skip the rest of queues */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 /* [OF10] Section 5.2.3 */
@@ -1349,10 +1307,6 @@ of10_match_print(netdissect_options *ndo,
        }
        else
                ND_TCHECK_2(cp);
-       return;
-
-trunc:
-       nd_trunc(ndo);
 }
 
 /* [OF10] Section 5.2.4 */
@@ -1514,9 +1468,6 @@ of10_actions_print(netdissect_options *ndo,
 invalid: /* skip the rest of actions */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 /* [OF10] Section 5.3.1 */
@@ -1621,10 +1572,6 @@ of10_port_mod_print(netdissect_options *ndo,
        /* pad */
        /* Always the last field, check bounds. */
        ND_TCHECK_4(cp);
-       return;
-
-trunc:
-       nd_trunc(ndo);
 }
 
 /* [OF10] Section 5.3.5 */
@@ -1700,9 +1647,6 @@ of10_stats_request_print(netdissect_options *ndo,
 invalid: /* skip the message body */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 /* ibid */
@@ -1741,9 +1685,6 @@ of10_desc_stats_reply_print(netdissect_options *ndo,
 invalid: /* skip the message body */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 /* ibid */
@@ -1806,9 +1747,6 @@ of10_flow_stats_reply_print(netdissect_options *ndo,
 invalid: /* skip the rest of flow statistics entries */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 /* ibid */
@@ -1835,9 +1773,6 @@ of10_aggregate_stats_reply_print(netdissect_options *ndo,
 invalid: /* skip the message body */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 /* ibid */
@@ -1881,9 +1816,6 @@ of10_table_stats_reply_print(netdissect_options *ndo,
 invalid: /* skip the undersized trailing data */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 /* ibid */
@@ -1946,9 +1878,6 @@ of10_port_stats_reply_print(netdissect_options *ndo,
 invalid: /* skip the undersized trailing data */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 /* ibid */
@@ -1983,9 +1912,6 @@ of10_queue_stats_reply_print(netdissect_options *ndo,
 invalid: /* skip the undersized trailing data */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 /* ibid */
@@ -2020,10 +1946,6 @@ of10_stats_reply_print(netdissect_options *ndo,
                }
        }
        ND_TCHECK_LEN(cp, len);
-       return;
-
-trunc:
-       nd_trunc(ndo);
 }
 
 /* [OF10] Section 5.3.6 */
@@ -2054,9 +1976,6 @@ of10_packet_out_print(netdissect_options *ndo,
 invalid: /* skip the rest of the message body */
        nd_print_invalid(ndo);
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }
 
 /* [OF10] Section 5.4.1 */
@@ -2083,10 +2002,6 @@ of10_packet_in_print(netdissect_options *ndo,
        OF_CHK_FWD(1);
        /* data */
        of10_packet_data_print(ndo, cp, len);
-       return;
-
-trunc:
-       nd_trunc(ndo);
 }
 
 /* [OF10] Section 5.4.2 */
@@ -2134,41 +2049,42 @@ static void
 of10_error_print(netdissect_options *ndo,
                  const u_char *cp, u_int len)
 {
-       uint16_t type;
-       const struct tok *code_str;
+       uint16_t type, code;
+       const struct tok *code_str[OFPET_MAX + 1] = {
+               /* [OFPET_HELLO_FAILED   ] = */ ofphfc_str,
+               /* [OFPET_BAD_REQUEST    ] = */ ofpbrc_str,
+               /* [OFPET_BAD_ACTION     ] = */ ofpbac_str,
+               /* [OFPET_FLOW_MOD_FAILED] = */ ofpfmfc_str,
+               /* [OFPET_PORT_MOD_FAILED] = */ ofppmfc_str,
+               /* [OFPET_QUEUE_OP_FAILED] = */ ofpqofc_str,
+       };
 
        /* type */
        type = GET_BE_U_2(cp);
        OF_FWD(2);
        ND_PRINT("\n\t type %s", tok2str(ofpet_str, "invalid (0x%04x)", type));
        /* code */
-       code_str =
-               type == OFPET_HELLO_FAILED    ? ofphfc_str  :
-               type == OFPET_BAD_REQUEST     ? ofpbrc_str  :
-               type == OFPET_BAD_ACTION      ? ofpbac_str  :
-               type == OFPET_FLOW_MOD_FAILED ? ofpfmfc_str :
-               type == OFPET_PORT_MOD_FAILED ? ofppmfc_str :
-               type == OFPET_QUEUE_OP_FAILED ? ofpqofc_str :
-               empty_str;
-       ND_PRINT(", code %s",
-                tok2str(code_str, "invalid (0x%04x)", GET_BE_U_2(cp)));
+       code = GET_BE_U_2(cp);
        OF_FWD(2);
+       if (type <= OFPET_MAX && code_str[type] != NULL)
+               ND_PRINT(", code %s",
+                        tok2str(code_str[type], "invalid (0x%04x)", code));
+       else
+               ND_PRINT(", code invalid (0x%04x)", code);
        /* data */
-       of10_data_print(ndo, cp, len);
+       of_data_print(ndo, cp, len);
 }
 
 void
-of10_header_body_print(netdissect_options *ndo,
-                       const u_char *cp, const uint8_t type,
-                       uint16_t len, const uint32_t xid)
+of10_message_print(netdissect_options *ndo,
+                   const u_char *cp, uint16_t len, const uint8_t type)
 {
        /*
         * Here "cp" and "len" stand for the message part beyond the common
-        * OpenFlow 1.0 header, if any. Add OF_HEADER_FIXLEN when printing the
-        * message header. Subtract OF_HEADER_FIXLEN from the type-specific
-        * lengths, which include the header length, when (and only when)
-        * validating the length in this function, which is the only one in
-        * this file that needs to know about OF_HEADER_FIXLEN.
+        * 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
@@ -2176,11 +2092,6 @@ of10_header_body_print(netdissect_options *ndo,
         * begin the decoding and let the lower-layer function do any remaining
         * validation.
         */
-
-       /* [OF10] Section 5.1 */
-       ND_PRINT("\n\tversion 1.0, type %s, length %u, xid 0x%08x",
-                tok2str(ofpt_str, "invalid (0x%02x)", type),
-                OF_HEADER_FIXLEN + len, xid);
        switch (type) {
        /* OpenFlow header only. */
        case OFPT_FEATURES_REQUEST: /* [OF10] Section 5.3.1 */
@@ -2189,7 +2100,7 @@ of10_header_body_print(netdissect_options *ndo,
        case OFPT_BARRIER_REPLY: /* ibid */
                if (len)
                        goto invalid;
-               break;
+               return;
 
        /* OpenFlow header and fixed-size message body. */
        case OFPT_SET_CONFIG: /* [OF10] Section 5.3.2 */
@@ -2197,7 +2108,7 @@ of10_header_body_print(netdissect_options *ndo,
                if (len != OF_SWITCH_CONFIG_FIXLEN - OF_HEADER_FIXLEN)
                        goto invalid;
                if (ndo->ndo_vflag < 1)
-                       goto next_message;
+                       break;
                /* flags */
                ND_PRINT("\n\t flags %s",
                         tok2str(ofp_config_str, "invalid (0x%04x)",
@@ -2210,16 +2121,16 @@ of10_header_body_print(netdissect_options *ndo,
                if (len != OF_PORT_MOD_FIXLEN - OF_HEADER_FIXLEN)
                        goto invalid;
                if (ndo->ndo_vflag < 1)
-                       goto next_message;
+                       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)
-                       goto next_message;
+                       break;
                /* port */
-               ND_PRINT("\n\t port_no %s",
+               ND_PRINT("\n\t port %s",
                         tok2str(ofpp_str, "%u", GET_BE_U_2(cp)));
                OF_FWD(2);
                /* pad */
@@ -2230,14 +2141,14 @@ of10_header_body_print(netdissect_options *ndo,
                if (len != OF_FLOW_REMOVED_FIXLEN - OF_HEADER_FIXLEN)
                        goto invalid;
                if (ndo->ndo_vflag < 1)
-                       goto next_message;
+                       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)
-                       goto next_message;
+                       break;
                /* reason */
                ND_PRINT("\n\t reason %s",
                         tok2str(ofppr_str, "invalid (0x%02x)", GET_U_1(cp)));
@@ -2254,7 +2165,7 @@ of10_header_body_print(netdissect_options *ndo,
                if (len < OF_FEATURES_REPLY_MINLEN - OF_HEADER_FIXLEN)
                        goto invalid;
                if (ndo->ndo_vflag < 1)
-                       goto next_message;
+                       break;
                of10_features_reply_print(ndo, cp, len);
                return;
 
@@ -2263,8 +2174,8 @@ of10_header_body_print(netdissect_options *ndo,
        case OFPT_ECHO_REQUEST: /* [OF10] Section 5.5.2 */
        case OFPT_ECHO_REPLY: /* [OF10] Section 5.5.3 */
                if (ndo->ndo_vflag < 1)
-                       goto next_message;
-               of10_data_print(ndo, cp, len);
+                       break;
+               of_data_print(ndo, cp, len);
                return;
 
        /* OpenFlow header, fixed-size message body and variable-size data. */
@@ -2272,7 +2183,7 @@ of10_header_body_print(netdissect_options *ndo,
                if (len < OF_ERROR_MSG_MINLEN - OF_HEADER_FIXLEN)
                        goto invalid;
                if (ndo->ndo_vflag < 1)
-                       goto next_message;
+                       break;
                of10_error_print(ndo, cp, len);
                return;
        case OFPT_VENDOR:
@@ -2280,7 +2191,7 @@ of10_header_body_print(netdissect_options *ndo,
                if (len < OF_VENDOR_MINLEN - OF_HEADER_FIXLEN)
                        goto invalid;
                if (ndo->ndo_vflag < 1)
-                       goto next_message;
+                       break;
                of10_vendor_message_print(ndo, cp, len);
                return;
        case OFPT_PACKET_IN:
@@ -2288,7 +2199,7 @@ of10_header_body_print(netdissect_options *ndo,
                if (len < OF_PACKET_IN_MINLEN - 2 - OF_HEADER_FIXLEN)
                        goto invalid;
                if (ndo->ndo_vflag < 1)
-                       goto next_message;
+                       break;
                of10_packet_in_print(ndo, cp, len);
                return;
 
@@ -2299,7 +2210,7 @@ of10_header_body_print(netdissect_options *ndo,
                if (len < OF_STATS_REQUEST_MINLEN - OF_HEADER_FIXLEN)
                        goto invalid;
                if (ndo->ndo_vflag < 1)
-                       goto next_message;
+                       break;
                of10_stats_request_print(ndo, cp, len);
                return;
 
@@ -2311,7 +2222,7 @@ of10_header_body_print(netdissect_options *ndo,
                if (len < OF_STATS_REPLY_MINLEN - OF_HEADER_FIXLEN)
                        goto invalid;
                if (ndo->ndo_vflag < 1)
-                       goto next_message;
+                       break;
                of10_stats_reply_print(ndo, cp, len);
                return;
 
@@ -2320,7 +2231,7 @@ of10_header_body_print(netdissect_options *ndo,
                if (len < OF_PACKET_OUT_MINLEN - OF_HEADER_FIXLEN)
                        goto invalid;
                if (ndo->ndo_vflag < 1)
-                       goto next_message;
+                       break;
                of10_packet_out_print(ndo, cp, len);
                return;
 
@@ -2329,7 +2240,7 @@ of10_header_body_print(netdissect_options *ndo,
                if (len < OF_FLOW_MOD_MINLEN - OF_HEADER_FIXLEN)
                        goto invalid;
                if (ndo->ndo_vflag < 1)
-                       goto next_message;
+                       break;
                of10_flow_mod_print(ndo, cp, len);
                return;
 
@@ -2338,9 +2249,9 @@ of10_header_body_print(netdissect_options *ndo,
                if (len < OF_QUEUE_GET_CONFIG_REPLY_MINLEN - OF_HEADER_FIXLEN)
                        goto invalid;
                if (ndo->ndo_vflag < 1)
-                       goto next_message;
+                       break;
                /* port */
-               ND_PRINT("\n\t port_no %s",
+               ND_PRINT("\n\t port %s",
                         tok2str(ofpp_str, "%u", GET_BE_U_2(cp)));
                OF_FWD(2);
                /* pad */
@@ -2350,13 +2261,14 @@ of10_header_body_print(netdissect_options *ndo,
                of10_queues_print(ndo, cp, len);
                return;
        } /* switch (type) */
-       goto next_message;
+       /*
+        * Not a recognised type or did not print the details, fall back to
+        * a bounds check.
+        */
+       ND_TCHECK_LEN(cp, len);
+       return;
 
 invalid: /* skip the message body */
        nd_print_invalid(ndo);
-next_message:
        ND_TCHECK_LEN(cp, len);
-       return;
-trunc:
-       nd_trunc(ndo);
 }