+#define OF_HELLO_ELEM_MINSIZE 4U
+
+/* miscellaneous constants from [OF13] */
+#define OFP_MAX_PORT_NAME_LEN 16U
+
+/* [OF13] Section 7.2.1 */
+static void
+of13_port_print(netdissect_options *ndo,
+ const u_char *cp)
+{
+ /* port_no */
+ ND_PRINT("\n\t port_no %s",
+ tok2str(ofpp_str, "%u", GET_BE_U_4(cp)));
+ cp += 4;
+ /* pad */
+ cp += 4;
+ /* hw_addr */
+ ND_PRINT(", hw_addr %s", GET_ETHERADDR_STRING(cp));
+ cp += MAC_ADDR_LEN;
+ /* pad2 */
+ cp += 2;
+ /* name */
+ ND_PRINT(", name '");
+ nd_printjnp(ndo, cp, OFP_MAX_PORT_NAME_LEN);
+ ND_PRINT("'");
+ cp += OFP_MAX_PORT_NAME_LEN;
+
+ if (ndo->ndo_vflag < 2) {
+ ND_TCHECK_LEN(cp, 32);
+ 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 */
+ ND_PRINT("\n\t state 0x%08x", GET_BE_U_4(cp));
+ of_bitmap_print(ndo, ofpps_bm, GET_BE_U_4(cp), OFPPS_U);;
+ 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);
+ cp += 4;
+ /* curr_speed */
+ ND_PRINT("\n\t curr_speed %ukbps", GET_BE_U_4(cp));
+ cp += 4;
+ /* max_speed */
+ ND_PRINT("\n\t max_speed %ukbps", GET_BE_U_4(cp));
+}
+
+/* [OF13] Section 7.3.1 */
+static void
+of13_features_reply_print(netdissect_options *ndo,
+ const u_char *cp, u_int len _U_)
+{
+ /* datapath_id */
+ ND_PRINT("\n\t dpid 0x%016" PRIx64, GET_BE_U_8(cp));
+ cp += 8;
+ /* n_buffers */
+ ND_PRINT(", n_buffers %u", GET_BE_U_4(cp));
+ cp += 4;
+ /* n_tables */
+ ND_PRINT(", n_tables %u", GET_U_1(cp));
+ cp += 1;
+ /* auxiliary_id */
+ ND_PRINT(", auxiliary_id %u", GET_U_1(cp));
+ cp += 1;
+ /* pad */
+ cp += 2;
+ /* capabilities */
+ ND_PRINT("\n\t capabilities 0x%08x", GET_BE_U_4(cp));
+ of_bitmap_print(ndo, ofp_capabilities_bm, GET_BE_U_4(cp), OFPCAP_U);
+ cp += 4;
+ /* reserved */
+ ND_TCHECK_4(cp);
+}
+
+/* [OF13] Section 7.3.2 */
+static void
+of13_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 %s",
+ tok2str(ofpcml_str, "%u", GET_BE_U_2(cp)));
+}
+
+/* [OF13] Section 7.3.3 */
+static void
+of13_table_mod_print(netdissect_options *ndo,
+ const u_char *cp, u_int len _U_)
+{
+ /* table_id */
+ ND_PRINT("\n\t table_id %s", tok2str(ofptt_str, "%u", GET_U_1(cp)));
+ cp += 1;
+ /* pad */
+ cp += 3;
+ /* config */
+ ND_PRINT(", config 0x%08x", GET_BE_U_4(cp));
+}
+
+/* [OF13] Section 7.3.9 */
+static void
+of13_role_msg_print(netdissect_options *ndo,
+ const u_char *cp, u_int len _U_)
+{
+ /* role */
+ ND_PRINT("\n\t role %s",
+ tok2str(ofpcr_str, "invalid (0x%08x)", GET_BE_U_4(cp)));
+ cp += 4;
+ /* pad */
+ cp += 4;
+ /* generation_id */
+ ND_PRINT(", generation_id 0x%016" PRIx64, GET_BE_U_8(cp));
+}
+
+/* [OF13] Section 7.3.10 */
+static void
+of13_async_msg_print(netdissect_options *ndo,
+ const u_char *cp, u_int len _U_)
+{
+ /* packet_in_mask[0] */
+ ND_PRINT("\n\t packet_in_mask[EM] 0x%08x", GET_BE_U_4(cp));
+ of_bitmap_print(ndo, async_ofpr_bm, GET_BE_U_4(cp), ASYNC_OFPR_U);
+ cp += 4;
+ /* packet_in_mask[1] */
+ ND_PRINT("\n\t packet_in_mask[S] 0x%08x", GET_BE_U_4(cp));
+ of_bitmap_print(ndo, async_ofpr_bm, GET_BE_U_4(cp), ASYNC_OFPR_U);
+ cp += 4;
+ /* port_status_mask[0] */
+ ND_PRINT("\n\t port_status_mask[EM] 0x%08x", GET_BE_U_4(cp));
+ of_bitmap_print(ndo, async_ofppr_bm, GET_BE_U_4(cp), ASYNC_OFPPR_U);
+ cp += 4;
+ /* port_status_mask[1] */
+ ND_PRINT("\n\t port_status_mask[S] 0x%08x", GET_BE_U_4(cp));
+ of_bitmap_print(ndo, async_ofppr_bm, GET_BE_U_4(cp), ASYNC_OFPPR_U);
+ cp += 4;
+ /* flow_removed_mask[0] */
+ ND_PRINT("\n\t flow_removed_mask[EM] 0x%08x", GET_BE_U_4(cp));
+ of_bitmap_print(ndo, async_ofppr_bm, GET_BE_U_4(cp), ASYNC_OFPPR_U);
+ cp += 4;
+ /* flow_removed_mask[1] */
+ ND_PRINT("\n\t flow_removed_mask[S] 0x%08x", GET_BE_U_4(cp));
+ of_bitmap_print(ndo, async_ofppr_bm, GET_BE_U_4(cp), ASYNC_OFPPR_U);
+}
+
+/* [OF13] Section 7.3.4.3 */
+static void
+of13_port_mod_print(netdissect_options *ndo,
+ const u_char *cp, u_int len _U_)
+{
+ /* port_no */
+ ND_PRINT("\n\t port_no %s", tok2str(ofpp_str, "%u", GET_BE_U_4(cp)));
+ cp += 4;
+ /* pad */
+ cp += 4;
+ /* hw_addr */
+ ND_PRINT(", hw_addr %s", GET_ETHERADDR_STRING(cp));
+ cp += MAC_ADDR_LEN;
+ /* pad2 */
+ cp += 2;
+ /* 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;
+ /* mask */
+ 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));
+ of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U);
+ cp += 4;
+ /* pad3 */
+ /* Always the last field, check bounds. */
+ ND_TCHECK_4(cp);
+}
+
+/* [OF13] Section 7.4.3 */
+static void
+of13_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 (0x02x)", GET_U_1(cp)));
+ cp += 1;
+ /* pad */
+ cp += 7;
+ /* desc */
+ of13_port_print(ndo, cp);
+}
+
+/* [OF13] Section 7.5.1 */
+static void
+of13_hello_elements_print(netdissect_options *ndo,
+ const u_char *cp, u_int len)
+{
+ while (len) {
+ uint16_t type, bmlen;
+
+ if (len < OF_HELLO_ELEM_MINSIZE)
+ goto invalid;
+ /* type */
+ type = GET_BE_U_2(cp);
+ OF_FWD(2);
+ ND_PRINT("\n\t type %s",
+ tok2str(ofphet_str, "unknown (0x%04x)", type));
+ /* length */
+ bmlen = GET_BE_U_2(cp);
+ OF_FWD(2);
+ ND_PRINT(", length %u", bmlen);
+ /* cp is OF_HELLO_ELEM_MINSIZE bytes in */
+ if (bmlen < OF_HELLO_ELEM_MINSIZE ||
+ bmlen > OF_HELLO_ELEM_MINSIZE + len)
+ goto invalid;
+ switch (type) {
+ case OFPHET_VERSIONBITMAP:
+ /*
+ * The specification obviously overprovisions the space
+ * for version bitmaps in this element ("ofp versions
+ * 32 to 63 are encoded in the second bitmap and so
+ * on"). Keep this code simple for now and recognize
+ * only a single bitmap with no padding.
+ */
+ if (bmlen == OF_HELLO_ELEM_MINSIZE + 4) {
+ uint32_t bitmap = GET_BE_U_4(cp);
+ ND_PRINT(", bitmap 0x%08x", bitmap);
+ of_bitmap_print(ndo, ofverbm_str, bitmap,
+ OF_BIT_VER_U);
+ } else {
+ ND_PRINT(" (bogus)");
+ ND_TCHECK_LEN(cp, bmlen - OF_HELLO_ELEM_MINSIZE);
+ }
+ break;
+ default:
+ ND_TCHECK_LEN(cp, bmlen - OF_HELLO_ELEM_MINSIZE);
+ }
+ OF_FWD(bmlen - OF_HELLO_ELEM_MINSIZE);
+ }
+ return;