* 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.
#include "netdissect-stdinc.h"
+#define ND_LONGJMP_FROM_TCHECK
#include "netdissect.h"
#include "extract.h"
#include "addrtoname.h"
{ 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
{ 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
{ 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)
{
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)
invalid: /* skip the undersized data */
nd_print_invalid(ndo);
ND_TCHECK_LEN(cp, len);
- return;
-trunc:
- nd_trunc(ndo);
}
static void
invalid:
nd_print_invalid(ndo);
ND_TCHECK_LEN(cp, len);
- return;
-trunc:
- nd_trunc(ndo);
}
static void
/* 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
/* 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. */
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
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 */
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 */
invalid: /* skip the rest of queue properties */
nd_print_invalid(ndo);
ND_TCHECK_LEN(cp, len);
- return;
-trunc:
- nd_trunc(ndo);
}
/* ibid */
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 */
}
else
ND_TCHECK_2(cp);
- return;
-
-trunc:
- nd_trunc(ndo);
}
/* [OF10] Section 5.2.4 */
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 */
/* pad */
/* Always the last field, check bounds. */
ND_TCHECK_4(cp);
- return;
-
-trunc:
- nd_trunc(ndo);
}
/* [OF10] Section 5.3.5 */
invalid: /* skip the message body */
nd_print_invalid(ndo);
ND_TCHECK_LEN(cp, len);
- return;
-trunc:
- nd_trunc(ndo);
}
/* ibid */
invalid: /* skip the message body */
nd_print_invalid(ndo);
ND_TCHECK_LEN(cp, len);
- return;
-trunc:
- nd_trunc(ndo);
}
/* ibid */
invalid: /* skip the rest of flow statistics entries */
nd_print_invalid(ndo);
ND_TCHECK_LEN(cp, len);
- return;
-trunc:
- nd_trunc(ndo);
}
/* ibid */
invalid: /* skip the message body */
nd_print_invalid(ndo);
ND_TCHECK_LEN(cp, len);
- return;
-trunc:
- nd_trunc(ndo);
}
/* ibid */
invalid: /* skip the undersized trailing data */
nd_print_invalid(ndo);
ND_TCHECK_LEN(cp, len);
- return;
-trunc:
- nd_trunc(ndo);
}
/* ibid */
invalid: /* skip the undersized trailing data */
nd_print_invalid(ndo);
ND_TCHECK_LEN(cp, len);
- return;
-trunc:
- nd_trunc(ndo);
}
/* ibid */
invalid: /* skip the undersized trailing data */
nd_print_invalid(ndo);
ND_TCHECK_LEN(cp, len);
- return;
-trunc:
- nd_trunc(ndo);
}
/* ibid */
}
}
ND_TCHECK_LEN(cp, len);
- return;
-
-trunc:
- nd_trunc(ndo);
}
/* [OF10] Section 5.3.6 */
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 */
OF_CHK_FWD(1);
/* data */
of10_packet_data_print(ndo, cp, len);
- return;
-
-trunc:
- nd_trunc(ndo);
}
/* [OF10] Section 5.4.2 */
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
* 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 */
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 */
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)",
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 */
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)));
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;
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. */
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:
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:
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;
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;
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;
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;
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;
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 */
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);
}