xref: /freebsd/contrib/tcpdump/print-openflow-1.0.c (revision 8bdc5a6251ddffc81a013f36b4384c8ace9c4bec)
13c602fabSXin LI /*
23c602fabSXin LI  * This module implements decoding of OpenFlow protocol version 1.0 (wire
33c602fabSXin LI  * protocol 0x01). The decoder implements terse (default), detailed (-v) and
43c602fabSXin LI  * full (-vv) output formats and, as much as each format implies, detects and
53c602fabSXin LI  * tries to work around sizing anomalies inside the messages. The decoder marks
63c602fabSXin LI  * up bogus values of selected message fields and decodes partially captured
73c602fabSXin LI  * messages up to the snapshot end. It is based on the specification below:
83c602fabSXin LI  *
93c602fabSXin LI  * [OF10] http://www.openflow.org/documents/openflow-spec-v1.0.0.pdf
103c602fabSXin LI  *
11*8bdc5a62SPatrick Kelsey  * Most functions in this file take 3 arguments into account:
12*8bdc5a62SPatrick Kelsey  * * cp -- the pointer to the first octet to decode
13*8bdc5a62SPatrick Kelsey  * * len -- the length of the current structure as declared on the wire
14*8bdc5a62SPatrick Kelsey  * * ep -- the pointer to the end of the captured frame
15*8bdc5a62SPatrick Kelsey  * They return either the pointer to the next not-yet-decoded part of the frame
16*8bdc5a62SPatrick Kelsey  * or the value of ep, which means the current frame processing is over as it
17*8bdc5a62SPatrick Kelsey  * has been fully decoded or is malformed or truncated. This way it is possible
18*8bdc5a62SPatrick Kelsey  * to chain and nest such functions uniformly to decode an OF1.0 message, which
19*8bdc5a62SPatrick Kelsey  * consists of several layers of nested structures.
20*8bdc5a62SPatrick Kelsey  *
213c602fabSXin LI  * Decoding of Ethernet frames nested in OFPT_PACKET_IN and OFPT_PACKET_OUT
223c602fabSXin LI  * messages is done only when the verbosity level set by command-line argument
233c602fabSXin LI  * is "-vvv" or higher. In that case the verbosity level is temporarily
243c602fabSXin LI  * decremented by 3 during the nested frame decoding. For example, running
253c602fabSXin LI  * tcpdump with "-vvvv" will do full decoding of OpenFlow and "-v" decoding of
263c602fabSXin LI  * the nested frames.
273c602fabSXin LI  *
28*8bdc5a62SPatrick Kelsey  * Partial decoding of Big Switch Networks vendor extensions is done after the
29*8bdc5a62SPatrick Kelsey  * oftest (OpenFlow Testing Framework) and Loxigen (library generator) source
30*8bdc5a62SPatrick Kelsey  * code.
31*8bdc5a62SPatrick Kelsey  *
323c602fabSXin LI  *
333c602fabSXin LI  * Copyright (c) 2013 The TCPDUMP project
343c602fabSXin LI  * All rights reserved.
353c602fabSXin LI  *
363c602fabSXin LI  * Redistribution and use in source and binary forms, with or without
373c602fabSXin LI  * modification, are permitted provided that the following conditions
383c602fabSXin LI  * are met:
393c602fabSXin LI  * 1. Redistributions of source code must retain the above copyright
403c602fabSXin LI  *    notice, this list of conditions and the following disclaimer.
413c602fabSXin LI  * 2. Redistributions in binary form must reproduce the above copyright
423c602fabSXin LI  *    notice, this list of conditions and the following disclaimer in the
433c602fabSXin LI  *    documentation and/or other materials provided with the distribution.
443c602fabSXin LI  *
453c602fabSXin LI  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
463c602fabSXin LI  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
473c602fabSXin LI  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
483c602fabSXin LI  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
493c602fabSXin LI  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
503c602fabSXin LI  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
513c602fabSXin LI  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
523c602fabSXin LI  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
533c602fabSXin LI  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
543c602fabSXin LI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
553c602fabSXin LI  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
563c602fabSXin LI  * POSSIBILITY OF SUCH DAMAGE.
573c602fabSXin LI  */
583c602fabSXin LI 
593c602fabSXin LI #define NETDISSECT_REWORKED
603c602fabSXin LI #ifdef HAVE_CONFIG_H
613c602fabSXin LI #include "config.h"
623c602fabSXin LI #endif
633c602fabSXin LI 
643c602fabSXin LI #include <tcpdump-stdinc.h>
653c602fabSXin LI 
663c602fabSXin LI #include "interface.h"
673c602fabSXin LI #include "extract.h"
683c602fabSXin LI #include "addrtoname.h"
693c602fabSXin LI #include "ether.h"
703c602fabSXin LI #include "ethertype.h"
713c602fabSXin LI #include "ipproto.h"
72*8bdc5a62SPatrick Kelsey #include "oui.h"
733c602fabSXin LI #include "openflow.h"
743c602fabSXin LI 
753c602fabSXin LI static const char tstr[] = " [|openflow]";
763c602fabSXin LI static const char cstr[] = " (corrupt)";
773c602fabSXin LI 
783c602fabSXin LI #define OFPT_HELLO                    0x00
793c602fabSXin LI #define OFPT_ERROR                    0x01
803c602fabSXin LI #define OFPT_ECHO_REQUEST             0x02
813c602fabSXin LI #define OFPT_ECHO_REPLY               0x03
823c602fabSXin LI #define OFPT_VENDOR                   0x04
833c602fabSXin LI #define OFPT_FEATURES_REQUEST         0x05
843c602fabSXin LI #define OFPT_FEATURES_REPLY           0x06
853c602fabSXin LI #define OFPT_GET_CONFIG_REQUEST       0x07
863c602fabSXin LI #define OFPT_GET_CONFIG_REPLY         0x08
873c602fabSXin LI #define OFPT_SET_CONFIG               0x09
883c602fabSXin LI #define OFPT_PACKET_IN                0x0a
893c602fabSXin LI #define OFPT_FLOW_REMOVED             0x0b
903c602fabSXin LI #define OFPT_PORT_STATUS              0x0c
913c602fabSXin LI #define OFPT_PACKET_OUT               0x0d
923c602fabSXin LI #define OFPT_FLOW_MOD                 0x0e
933c602fabSXin LI #define OFPT_PORT_MOD                 0x0f
943c602fabSXin LI #define OFPT_STATS_REQUEST            0x10
953c602fabSXin LI #define OFPT_STATS_REPLY              0x11
963c602fabSXin LI #define OFPT_BARRIER_REQUEST          0x12
973c602fabSXin LI #define OFPT_BARRIER_REPLY            0x13
983c602fabSXin LI #define OFPT_QUEUE_GET_CONFIG_REQUEST 0x14
993c602fabSXin LI #define OFPT_QUEUE_GET_CONFIG_REPLY   0x15
1003c602fabSXin LI static const struct tok ofpt_str[] = {
1013c602fabSXin LI 	{ OFPT_HELLO,                    "HELLO"                    },
1023c602fabSXin LI 	{ OFPT_ERROR,                    "ERROR"                    },
1033c602fabSXin LI 	{ OFPT_ECHO_REQUEST,             "ECHO_REQUEST"             },
1043c602fabSXin LI 	{ OFPT_ECHO_REPLY,               "ECHO_REPLY"               },
1053c602fabSXin LI 	{ OFPT_VENDOR,                   "VENDOR"                   },
1063c602fabSXin LI 	{ OFPT_FEATURES_REQUEST,         "FEATURES_REQUEST"         },
1073c602fabSXin LI 	{ OFPT_FEATURES_REPLY,           "FEATURES_REPLY"           },
1083c602fabSXin LI 	{ OFPT_GET_CONFIG_REQUEST,       "GET_CONFIG_REQUEST"       },
1093c602fabSXin LI 	{ OFPT_GET_CONFIG_REPLY,         "GET_CONFIG_REPLY"         },
1103c602fabSXin LI 	{ OFPT_SET_CONFIG,               "SET_CONFIG"               },
1113c602fabSXin LI 	{ OFPT_PACKET_IN,                "PACKET_IN"                },
1123c602fabSXin LI 	{ OFPT_FLOW_REMOVED,             "FLOW_REMOVED"             },
1133c602fabSXin LI 	{ OFPT_PORT_STATUS,              "PORT_STATUS"              },
1143c602fabSXin LI 	{ OFPT_PACKET_OUT,               "PACKET_OUT"               },
1153c602fabSXin LI 	{ OFPT_FLOW_MOD,                 "FLOW_MOD"                 },
1163c602fabSXin LI 	{ OFPT_PORT_MOD,                 "PORT_MOD"                 },
1173c602fabSXin LI 	{ OFPT_STATS_REQUEST,            "STATS_REQUEST"            },
1183c602fabSXin LI 	{ OFPT_STATS_REPLY,              "STATS_REPLY"              },
1193c602fabSXin LI 	{ OFPT_BARRIER_REQUEST,          "BARRIER_REQUEST"          },
1203c602fabSXin LI 	{ OFPT_BARRIER_REPLY,            "BARRIER_REPLY"            },
1213c602fabSXin LI 	{ OFPT_QUEUE_GET_CONFIG_REQUEST, "QUEUE_GET_CONFIG_REQUEST" },
1223c602fabSXin LI 	{ OFPT_QUEUE_GET_CONFIG_REPLY,   "QUEUE_GET_CONFIG_REPLY"   },
1233c602fabSXin LI 	{ 0, NULL }
1243c602fabSXin LI };
1253c602fabSXin LI 
1263c602fabSXin LI #define OFPPC_PORT_DOWN    (1 << 0)
1273c602fabSXin LI #define OFPPC_NO_STP       (1 << 1)
1283c602fabSXin LI #define OFPPC_NO_RECV      (1 << 2)
1293c602fabSXin LI #define OFPPC_NO_RECV_STP  (1 << 3)
1303c602fabSXin LI #define OFPPC_NO_FLOOD     (1 << 4)
1313c602fabSXin LI #define OFPPC_NO_FWD       (1 << 5)
1323c602fabSXin LI #define OFPPC_NO_PACKET_IN (1 << 6)
1333c602fabSXin LI static const struct tok ofppc_bm[] = {
1343c602fabSXin LI 	{ OFPPC_PORT_DOWN,    "PORT_DOWN"    },
1353c602fabSXin LI 	{ OFPPC_NO_STP,       "NO_STP"       },
1363c602fabSXin LI 	{ OFPPC_NO_RECV,      "NO_RECV"      },
1373c602fabSXin LI 	{ OFPPC_NO_RECV_STP,  "NO_RECV_STP"  },
1383c602fabSXin LI 	{ OFPPC_NO_FLOOD,     "NO_FLOOD"     },
1393c602fabSXin LI 	{ OFPPC_NO_FWD,       "NO_FWD"       },
1403c602fabSXin LI 	{ OFPPC_NO_PACKET_IN, "NO_PACKET_IN" },
1413c602fabSXin LI 	{ 0, NULL }
1423c602fabSXin LI };
1433c602fabSXin LI #define OFPPC_U (~(OFPPC_PORT_DOWN | OFPPC_NO_STP | OFPPC_NO_RECV | \
1443c602fabSXin LI                    OFPPC_NO_RECV_STP | OFPPC_NO_FLOOD | OFPPC_NO_FWD | \
1453c602fabSXin LI                    OFPPC_NO_PACKET_IN))
1463c602fabSXin LI 
1473c602fabSXin LI #define OFPPS_LINK_DOWN   (1 << 0)
1483c602fabSXin LI #define OFPPS_STP_LISTEN  (0 << 8)
1493c602fabSXin LI #define OFPPS_STP_LEARN   (1 << 8)
1503c602fabSXin LI #define OFPPS_STP_FORWARD (2 << 8)
1513c602fabSXin LI #define OFPPS_STP_BLOCK   (3 << 8)
1523c602fabSXin LI #define OFPPS_STP_MASK    (3 << 8)
1533c602fabSXin LI static const struct tok ofpps_bm[] = {
1543c602fabSXin LI 	{ OFPPS_LINK_DOWN,   "LINK_DOWN"   },
1553c602fabSXin LI 	{ OFPPS_STP_LISTEN,  "STP_LISTEN"  },
1563c602fabSXin LI 	{ OFPPS_STP_LEARN,   "STP_LEARN"   },
1573c602fabSXin LI 	{ OFPPS_STP_FORWARD, "STP_FORWARD" },
1583c602fabSXin LI 	{ OFPPS_STP_BLOCK,   "STP_BLOCK"   },
1593c602fabSXin LI 	{ 0, NULL }
1603c602fabSXin LI };
1613c602fabSXin LI #define OFPPS_U (~(OFPPS_LINK_DOWN | OFPPS_STP_LISTEN | OFPPS_STP_LEARN | \
1623c602fabSXin LI                    OFPPS_STP_FORWARD | OFPPS_STP_BLOCK))
1633c602fabSXin LI 
1643c602fabSXin LI #define OFPP_MAX        0xff00
1653c602fabSXin LI #define OFPP_IN_PORT    0xfff8
1663c602fabSXin LI #define OFPP_TABLE      0xfff9
1673c602fabSXin LI #define OFPP_NORMAL     0xfffa
1683c602fabSXin LI #define OFPP_FLOOD      0xfffb
1693c602fabSXin LI #define OFPP_ALL        0xfffc
1703c602fabSXin LI #define OFPP_CONTROLLER 0xfffd
1713c602fabSXin LI #define OFPP_LOCAL      0xfffe
1723c602fabSXin LI #define OFPP_NONE       0xffff
1733c602fabSXin LI static const struct tok ofpp_str[] = {
1743c602fabSXin LI 	{ OFPP_MAX,        "MAX"        },
1753c602fabSXin LI 	{ OFPP_IN_PORT,    "IN_PORT"    },
1763c602fabSXin LI 	{ OFPP_TABLE,      "TABLE"      },
1773c602fabSXin LI 	{ OFPP_NORMAL,     "NORMAL"     },
1783c602fabSXin LI 	{ OFPP_FLOOD,      "FLOOD"      },
1793c602fabSXin LI 	{ OFPP_ALL,        "ALL"        },
1803c602fabSXin LI 	{ OFPP_CONTROLLER, "CONTROLLER" },
1813c602fabSXin LI 	{ OFPP_LOCAL,      "LOCAL"      },
1823c602fabSXin LI 	{ OFPP_NONE,       "NONE"       },
1833c602fabSXin LI 	{ 0, NULL }
1843c602fabSXin LI };
1853c602fabSXin LI 
1863c602fabSXin LI #define OFPPF_10MB_HD    (1 <<  0)
1873c602fabSXin LI #define OFPPF_10MB_FD    (1 <<  1)
1883c602fabSXin LI #define OFPPF_100MB_HD   (1 <<  2)
1893c602fabSXin LI #define OFPPF_100MB_FD   (1 <<  3)
1903c602fabSXin LI #define OFPPF_1GB_HD     (1 <<  4)
1913c602fabSXin LI #define OFPPF_1GB_FD     (1 <<  5)
1923c602fabSXin LI #define OFPPF_10GB_FD    (1 <<  6)
1933c602fabSXin LI #define OFPPF_COPPER     (1 <<  7)
1943c602fabSXin LI #define OFPPF_FIBER      (1 <<  8)
1953c602fabSXin LI #define OFPPF_AUTONEG    (1 <<  9)
1963c602fabSXin LI #define OFPPF_PAUSE      (1 << 10)
1973c602fabSXin LI #define OFPPF_PAUSE_ASYM (1 << 11)
1983c602fabSXin LI static const struct tok ofppf_bm[] = {
1993c602fabSXin LI 	{ OFPPF_10MB_HD,    "10MB_HD"    },
2003c602fabSXin LI 	{ OFPPF_10MB_FD,    "10MB_FD"    },
2013c602fabSXin LI 	{ OFPPF_100MB_HD,   "100MB_HD"   },
2023c602fabSXin LI 	{ OFPPF_100MB_FD,   "100MB_FD"   },
2033c602fabSXin LI 	{ OFPPF_1GB_HD,     "1GB_HD"     },
2043c602fabSXin LI 	{ OFPPF_1GB_FD,     "1GB_FD"     },
2053c602fabSXin LI 	{ OFPPF_10GB_FD,    "10GB_FD"    },
2063c602fabSXin LI 	{ OFPPF_COPPER,     "COPPER"     },
2073c602fabSXin LI 	{ OFPPF_FIBER,      "FIBER"      },
2083c602fabSXin LI 	{ OFPPF_AUTONEG,    "AUTONEG"    },
2093c602fabSXin LI 	{ OFPPF_PAUSE,      "PAUSE"      },
2103c602fabSXin LI 	{ OFPPF_PAUSE_ASYM, "PAUSE_ASYM" },
2113c602fabSXin LI 	{ 0, NULL }
2123c602fabSXin LI };
2133c602fabSXin LI #define OFPPF_U (~(OFPPF_10MB_HD | OFPPF_10MB_FD | OFPPF_100MB_HD | \
2143c602fabSXin LI                    OFPPF_100MB_FD | OFPPF_1GB_HD | OFPPF_1GB_FD | \
2153c602fabSXin LI                    OFPPF_10GB_FD | OFPPF_COPPER | OFPPF_FIBER | \
2163c602fabSXin LI                    OFPPF_AUTONEG | OFPPF_PAUSE | OFPPF_PAUSE_ASYM))
2173c602fabSXin LI 
2183c602fabSXin LI #define OFPQT_NONE     0x0000
2193c602fabSXin LI #define OFPQT_MIN_RATE 0x0001
2203c602fabSXin LI static const struct tok ofpqt_str[] = {
2213c602fabSXin LI 	{ OFPQT_NONE,     "NONE"     },
2223c602fabSXin LI 	{ OFPQT_MIN_RATE, "MIN_RATE" },
2233c602fabSXin LI 	{ 0, NULL }
2243c602fabSXin LI };
2253c602fabSXin LI 
2263c602fabSXin LI #define OFPFW_IN_PORT      (1 << 0)
2273c602fabSXin LI #define OFPFW_DL_VLAN      (1 << 1)
2283c602fabSXin LI #define OFPFW_DL_SRC       (1 << 2)
2293c602fabSXin LI #define OFPFW_DL_DST       (1 << 3)
2303c602fabSXin LI #define OFPFW_DL_TYPE      (1 << 4)
2313c602fabSXin LI #define OFPFW_NW_PROTO     (1 << 5)
2323c602fabSXin LI #define OFPFW_TP_SRC       (1 << 6)
2333c602fabSXin LI #define OFPFW_TP_DST       (1 << 7)
2343c602fabSXin LI #define OFPFW_NW_SRC_SHIFT 8
2353c602fabSXin LI #define OFPFW_NW_SRC_BITS  6
2363c602fabSXin LI #define OFPFW_NW_SRC_MASK  (((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT)
2373c602fabSXin LI #define OFPFW_NW_DST_SHIFT 14
2383c602fabSXin LI #define OFPFW_NW_DST_BITS  6
2393c602fabSXin LI #define OFPFW_NW_DST_MASK  (((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT)
2403c602fabSXin LI #define OFPFW_DL_VLAN_PCP  (1 << 20)
2413c602fabSXin LI #define OFPFW_NW_TOS       (1 << 21)
2423c602fabSXin LI #define OFPFW_ALL          ((1 << 22) - 1)
2433c602fabSXin LI static const struct tok ofpfw_bm[] = {
2443c602fabSXin LI 	{ OFPFW_IN_PORT,     "IN_PORT"     },
2453c602fabSXin LI 	{ OFPFW_DL_VLAN,     "DL_VLAN"     },
2463c602fabSXin LI 	{ OFPFW_DL_SRC,      "DL_SRC"      },
2473c602fabSXin LI 	{ OFPFW_DL_DST,      "DL_DST"      },
2483c602fabSXin LI 	{ OFPFW_DL_TYPE,     "DL_TYPE"     },
2493c602fabSXin LI 	{ OFPFW_NW_PROTO,    "NW_PROTO"    },
2503c602fabSXin LI 	{ OFPFW_TP_SRC,      "TP_SRC"      },
2513c602fabSXin LI 	{ OFPFW_TP_DST,      "TP_DST"      },
2523c602fabSXin LI 	{ OFPFW_DL_VLAN_PCP, "DL_VLAN_PCP" },
2533c602fabSXin LI 	{ OFPFW_NW_TOS,      "NW_TOS"      },
2543c602fabSXin LI 	{ 0, NULL }
2553c602fabSXin LI };
2563c602fabSXin LI /* The above array does not include bits 8~13 (OFPFW_NW_SRC_*) and 14~19
2573c602fabSXin LI  * (OFPFW_NW_DST_*), which are not a part of the bitmap and require decoding
2583c602fabSXin LI  * other than that of tok2str(). The macro below includes these bits such that
2593c602fabSXin LI  * they are not reported as bogus in the decoding. */
2603c602fabSXin LI #define OFPFW_U (~(OFPFW_ALL))
2613c602fabSXin LI 
2623c602fabSXin LI #define OFPAT_OUTPUT       0x0000
2633c602fabSXin LI #define OFPAT_SET_VLAN_VID 0x0001
2643c602fabSXin LI #define OFPAT_SET_VLAN_PCP 0x0002
2653c602fabSXin LI #define OFPAT_STRIP_VLAN   0x0003
2663c602fabSXin LI #define OFPAT_SET_DL_SRC   0x0004
2673c602fabSXin LI #define OFPAT_SET_DL_DST   0x0005
2683c602fabSXin LI #define OFPAT_SET_NW_SRC   0x0006
2693c602fabSXin LI #define OFPAT_SET_NW_DST   0x0007
2703c602fabSXin LI #define OFPAT_SET_NW_TOS   0x0008
2713c602fabSXin LI #define OFPAT_SET_TP_SRC   0x0009
2723c602fabSXin LI #define OFPAT_SET_TP_DST   0x000a
2733c602fabSXin LI #define OFPAT_ENQUEUE      0x000b
2743c602fabSXin LI #define OFPAT_VENDOR       0xffff
2753c602fabSXin LI static const struct tok ofpat_str[] = {
2763c602fabSXin LI 	{ OFPAT_OUTPUT,       "OUTPUT"       },
2773c602fabSXin LI 	{ OFPAT_SET_VLAN_VID, "SET_VLAN_VID" },
2783c602fabSXin LI 	{ OFPAT_SET_VLAN_PCP, "SET_VLAN_PCP" },
2793c602fabSXin LI 	{ OFPAT_STRIP_VLAN,   "STRIP_VLAN"   },
2803c602fabSXin LI 	{ OFPAT_SET_DL_SRC,   "SET_DL_SRC"   },
2813c602fabSXin LI 	{ OFPAT_SET_DL_DST,   "SET_DL_DST"   },
2823c602fabSXin LI 	{ OFPAT_SET_NW_SRC,   "SET_NW_SRC"   },
2833c602fabSXin LI 	{ OFPAT_SET_NW_DST,   "SET_NW_DST"   },
2843c602fabSXin LI 	{ OFPAT_SET_NW_TOS,   "SET_NW_TOS"   },
2853c602fabSXin LI 	{ OFPAT_SET_TP_SRC,   "SET_TP_SRC"   },
2863c602fabSXin LI 	{ OFPAT_SET_TP_DST,   "SET_TP_DST"   },
2873c602fabSXin LI 	{ OFPAT_ENQUEUE,      "ENQUEUE"      },
2883c602fabSXin LI 	{ OFPAT_VENDOR,       "VENDOR"       },
2893c602fabSXin LI 	{ 0, NULL }
2903c602fabSXin LI };
2913c602fabSXin LI 
2923c602fabSXin LI /* bit-shifted, w/o vendor action */
2933c602fabSXin LI static const struct tok ofpat_bm[] = {
2943c602fabSXin LI 	{ 1 << OFPAT_OUTPUT,       "OUTPUT"       },
2953c602fabSXin LI 	{ 1 << OFPAT_SET_VLAN_VID, "SET_VLAN_VID" },
2963c602fabSXin LI 	{ 1 << OFPAT_SET_VLAN_PCP, "SET_VLAN_PCP" },
2973c602fabSXin LI 	{ 1 << OFPAT_STRIP_VLAN,   "STRIP_VLAN"   },
2983c602fabSXin LI 	{ 1 << OFPAT_SET_DL_SRC,   "SET_DL_SRC"   },
2993c602fabSXin LI 	{ 1 << OFPAT_SET_DL_DST,   "SET_DL_DST"   },
3003c602fabSXin LI 	{ 1 << OFPAT_SET_NW_SRC,   "SET_NW_SRC"   },
3013c602fabSXin LI 	{ 1 << OFPAT_SET_NW_DST,   "SET_NW_DST"   },
3023c602fabSXin LI 	{ 1 << OFPAT_SET_NW_TOS,   "SET_NW_TOS"   },
3033c602fabSXin LI 	{ 1 << OFPAT_SET_TP_SRC,   "SET_TP_SRC"   },
3043c602fabSXin LI 	{ 1 << OFPAT_SET_TP_DST,   "SET_TP_DST"   },
3053c602fabSXin LI 	{ 1 << OFPAT_ENQUEUE,      "ENQUEUE"      },
3063c602fabSXin LI 	{ 0, NULL }
3073c602fabSXin LI };
3083c602fabSXin LI #define OFPAT_U (~(1 << OFPAT_OUTPUT | 1 << OFPAT_SET_VLAN_VID | \
3093c602fabSXin LI                    1 << OFPAT_SET_VLAN_PCP | 1 << OFPAT_STRIP_VLAN | \
3103c602fabSXin LI                    1 << OFPAT_SET_DL_SRC | 1 << OFPAT_SET_DL_DST | \
3113c602fabSXin LI                    1 << OFPAT_SET_NW_SRC | 1 << OFPAT_SET_NW_DST | \
3123c602fabSXin LI                    1 << OFPAT_SET_NW_TOS | 1 << OFPAT_SET_TP_SRC | \
3133c602fabSXin LI                    1 << OFPAT_SET_TP_DST | 1 << OFPAT_ENQUEUE))
3143c602fabSXin LI 
3153c602fabSXin LI #define OFPC_FLOW_STATS   (1 << 0)
3163c602fabSXin LI #define OFPC_TABLE_STATS  (1 << 1)
3173c602fabSXin LI #define OFPC_PORT_STATS   (1 << 2)
3183c602fabSXin LI #define OFPC_STP          (1 << 3)
3193c602fabSXin LI #define OFPC_RESERVED     (1 << 4)
3203c602fabSXin LI #define OFPC_IP_REASM     (1 << 5)
3213c602fabSXin LI #define OFPC_QUEUE_STATS  (1 << 6)
3223c602fabSXin LI #define OFPC_ARP_MATCH_IP (1 << 7)
3233c602fabSXin LI static const struct tok ofp_capabilities_bm[] = {
3243c602fabSXin LI 	{ OFPC_FLOW_STATS,   "FLOW_STATS"   },
3253c602fabSXin LI 	{ OFPC_TABLE_STATS,  "TABLE_STATS"  },
3263c602fabSXin LI 	{ OFPC_PORT_STATS,   "PORT_STATS"   },
3273c602fabSXin LI 	{ OFPC_STP,          "STP"          },
3283c602fabSXin LI 	{ OFPC_RESERVED,     "RESERVED"     }, /* not in the mask below */
3293c602fabSXin LI 	{ OFPC_IP_REASM,     "IP_REASM"     },
3303c602fabSXin LI 	{ OFPC_QUEUE_STATS,  "QUEUE_STATS"  },
3313c602fabSXin LI 	{ OFPC_ARP_MATCH_IP, "ARP_MATCH_IP" },
3323c602fabSXin LI 	{ 0, NULL }
3333c602fabSXin LI };
3343c602fabSXin LI #define OFPCAP_U (~(OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS | \
3353c602fabSXin LI                     OFPC_STP | OFPC_IP_REASM | OFPC_QUEUE_STATS | \
3363c602fabSXin LI                     OFPC_ARP_MATCH_IP))
3373c602fabSXin LI 
3383c602fabSXin LI #define OFPC_FRAG_NORMAL 0x0000
3393c602fabSXin LI #define OFPC_FRAG_DROP   0x0001
3403c602fabSXin LI #define OFPC_FRAG_REASM  0x0002
3413c602fabSXin LI #define OFPC_FRAG_MASK   0x0003
3423c602fabSXin LI static const struct tok ofp_config_str[] = {
3433c602fabSXin LI 	{ OFPC_FRAG_NORMAL, "FRAG_NORMAL" },
3443c602fabSXin LI 	{ OFPC_FRAG_DROP,   "FRAG_DROP"   },
3453c602fabSXin LI 	{ OFPC_FRAG_REASM,  "FRAG_REASM"  },
3463c602fabSXin LI 	{ 0, NULL }
3473c602fabSXin LI };
3483c602fabSXin LI 
3493c602fabSXin LI #define OFPFC_ADD           0x0000
3503c602fabSXin LI #define OFPFC_MODIFY        0x0001
3513c602fabSXin LI #define OFPFC_MODIFY_STRICT 0x0002
3523c602fabSXin LI #define OFPFC_DELETE        0x0003
3533c602fabSXin LI #define OFPFC_DELETE_STRICT 0x0004
3543c602fabSXin LI static const struct tok ofpfc_str[] = {
3553c602fabSXin LI 	{ OFPFC_ADD,           "ADD"           },
3563c602fabSXin LI 	{ OFPFC_MODIFY,        "MODIFY"        },
3573c602fabSXin LI 	{ OFPFC_MODIFY_STRICT, "MODIFY_STRICT" },
3583c602fabSXin LI 	{ OFPFC_DELETE,        "DELETE"        },
3593c602fabSXin LI 	{ OFPFC_DELETE_STRICT, "DELETE_STRICT" },
3603c602fabSXin LI 	{ 0, NULL }
3613c602fabSXin LI };
3623c602fabSXin LI 
3633c602fabSXin LI static const struct tok bufferid_str[] = {
3643c602fabSXin LI 	{ 0xffffffff, "NONE" },
3653c602fabSXin LI 	{ 0, NULL }
3663c602fabSXin LI };
3673c602fabSXin LI 
3683c602fabSXin LI #define OFPFF_SEND_FLOW_REM (1 << 0)
3693c602fabSXin LI #define OFPFF_CHECK_OVERLAP (1 << 1)
3703c602fabSXin LI #define OFPFF_EMERG         (1 << 2)
3713c602fabSXin LI static const struct tok ofpff_bm[] = {
3723c602fabSXin LI 	{ OFPFF_SEND_FLOW_REM, "SEND_FLOW_REM" },
3733c602fabSXin LI 	{ OFPFF_CHECK_OVERLAP, "CHECK_OVERLAP" },
3743c602fabSXin LI 	{ OFPFF_EMERG,         "EMERG"         },
3753c602fabSXin LI 	{ 0, NULL }
3763c602fabSXin LI };
3773c602fabSXin LI #define OFPFF_U (~(OFPFF_SEND_FLOW_REM | OFPFF_CHECK_OVERLAP | OFPFF_EMERG))
3783c602fabSXin LI 
3793c602fabSXin LI #define OFPST_DESC      0x0000
3803c602fabSXin LI #define OFPST_FLOW      0x0001
3813c602fabSXin LI #define OFPST_AGGREGATE 0x0002
3823c602fabSXin LI #define OFPST_TABLE     0x0003
3833c602fabSXin LI #define OFPST_PORT      0x0004
3843c602fabSXin LI #define OFPST_QUEUE     0x0005
3853c602fabSXin LI #define OFPST_VENDOR    0xffff
3863c602fabSXin LI static const struct tok ofpst_str[] = {
3873c602fabSXin LI 	{ OFPST_DESC,      "DESC"      },
3883c602fabSXin LI 	{ OFPST_FLOW,      "FLOW"      },
3893c602fabSXin LI 	{ OFPST_AGGREGATE, "AGGREGATE" },
3903c602fabSXin LI 	{ OFPST_TABLE,     "TABLE"     },
3913c602fabSXin LI 	{ OFPST_PORT,      "PORT"      },
3923c602fabSXin LI 	{ OFPST_QUEUE,     "QUEUE"     },
3933c602fabSXin LI 	{ OFPST_VENDOR,    "VENDOR"    },
3943c602fabSXin LI 	{ 0, NULL }
3953c602fabSXin LI };
3963c602fabSXin LI 
3973c602fabSXin LI static const struct tok tableid_str[] = {
3983c602fabSXin LI 	{ 0xfe, "EMERG" },
3993c602fabSXin LI 	{ 0xff, "ALL"   },
4003c602fabSXin LI 	{ 0, NULL }
4013c602fabSXin LI };
4023c602fabSXin LI 
4033c602fabSXin LI #define OFPQ_ALL      0xffffffff
4043c602fabSXin LI static const struct tok ofpq_str[] = {
4053c602fabSXin LI 	{ OFPQ_ALL, "ALL" },
4063c602fabSXin LI 	{ 0, NULL }
4073c602fabSXin LI };
4083c602fabSXin LI 
4093c602fabSXin LI #define OFPSF_REPLY_MORE 0x0001
4103c602fabSXin LI static const struct tok ofpsf_reply_bm[] = {
4113c602fabSXin LI 	{ OFPSF_REPLY_MORE, "MORE" },
4123c602fabSXin LI 	{ 0, NULL }
4133c602fabSXin LI };
4143c602fabSXin LI #define OFPSF_REPLY_U (~(OFPSF_REPLY_MORE))
4153c602fabSXin LI 
4163c602fabSXin LI #define OFPR_NO_MATCH 0x00
4173c602fabSXin LI #define OFPR_ACTION   0x01
4183c602fabSXin LI static const struct tok ofpr_str[] = {
4193c602fabSXin LI 	{ OFPR_NO_MATCH, "NO_MATCH" },
4203c602fabSXin LI 	{ OFPR_ACTION,   "ACTION"   },
4213c602fabSXin LI 	{ 0, NULL }
4223c602fabSXin LI };
4233c602fabSXin LI 
4243c602fabSXin LI #define OFPRR_IDLE_TIMEOUT 0x00
4253c602fabSXin LI #define OFPRR_HARD_TIMEOUT 0x01
4263c602fabSXin LI #define OFPRR_DELETE       0x02
4273c602fabSXin LI static const struct tok ofprr_str[] = {
4283c602fabSXin LI 	{ OFPRR_IDLE_TIMEOUT, "IDLE_TIMEOUT" },
4293c602fabSXin LI 	{ OFPRR_HARD_TIMEOUT, "HARD_TIMEOUT" },
4303c602fabSXin LI 	{ OFPRR_DELETE,       "DELETE"       },
4313c602fabSXin LI 	{ 0, NULL }
4323c602fabSXin LI };
4333c602fabSXin LI 
4343c602fabSXin LI #define OFPPR_ADD    0x00
4353c602fabSXin LI #define OFPPR_DELETE 0x01
4363c602fabSXin LI #define OFPPR_MODIFY 0x02
4373c602fabSXin LI static const struct tok ofppr_str[] = {
4383c602fabSXin LI 	{ OFPPR_ADD,    "ADD"    },
4393c602fabSXin LI 	{ OFPPR_DELETE, "DELETE" },
4403c602fabSXin LI 	{ OFPPR_MODIFY, "MODIFY" },
4413c602fabSXin LI 	{ 0, NULL }
4423c602fabSXin LI };
4433c602fabSXin LI 
4443c602fabSXin LI #define OFPET_HELLO_FAILED    0x0000
4453c602fabSXin LI #define OFPET_BAD_REQUEST     0x0001
4463c602fabSXin LI #define OFPET_BAD_ACTION      0x0002
4473c602fabSXin LI #define OFPET_FLOW_MOD_FAILED 0x0003
4483c602fabSXin LI #define OFPET_PORT_MOD_FAILED 0x0004
4493c602fabSXin LI #define OFPET_QUEUE_OP_FAILED 0x0005
4503c602fabSXin LI static const struct tok ofpet_str[] = {
4513c602fabSXin LI 	{ OFPET_HELLO_FAILED,    "HELLO_FAILED"    },
4523c602fabSXin LI 	{ OFPET_BAD_REQUEST,     "BAD_REQUEST"     },
4533c602fabSXin LI 	{ OFPET_BAD_ACTION,      "BAD_ACTION"      },
4543c602fabSXin LI 	{ OFPET_FLOW_MOD_FAILED, "FLOW_MOD_FAILED" },
4553c602fabSXin LI 	{ OFPET_PORT_MOD_FAILED, "PORT_MOD_FAILED" },
4563c602fabSXin LI 	{ OFPET_QUEUE_OP_FAILED, "QUEUE_OP_FAILED" },
4573c602fabSXin LI 	{ 0, NULL }
4583c602fabSXin LI };
4593c602fabSXin LI 
4603c602fabSXin LI #define OFPHFC_INCOMPATIBLE 0x0000
4613c602fabSXin LI #define OFPHFC_EPERM        0x0001
4623c602fabSXin LI static const struct tok ofphfc_str[] = {
4633c602fabSXin LI 	{ OFPHFC_INCOMPATIBLE, "INCOMPATIBLE" },
4643c602fabSXin LI 	{ OFPHFC_EPERM,        "EPERM"        },
4653c602fabSXin LI 	{ 0, NULL }
4663c602fabSXin LI };
4673c602fabSXin LI 
4683c602fabSXin LI #define OFPBRC_BAD_VERSION    0x0000
4693c602fabSXin LI #define OFPBRC_BAD_TYPE       0x0001
4703c602fabSXin LI #define OFPBRC_BAD_STAT       0x0002
4713c602fabSXin LI #define OFPBRC_BAD_VENDOR     0x0003
4723c602fabSXin LI #define OFPBRC_BAD_SUBTYPE    0x0004
4733c602fabSXin LI #define OFPBRC_EPERM          0x0005
4743c602fabSXin LI #define OFPBRC_BAD_LEN        0x0006
4753c602fabSXin LI #define OFPBRC_BUFFER_EMPTY   0x0007
4763c602fabSXin LI #define OFPBRC_BUFFER_UNKNOWN 0x0008
4773c602fabSXin LI static const struct tok ofpbrc_str[] = {
4783c602fabSXin LI 	{ OFPBRC_BAD_VERSION,    "BAD_VERSION"    },
4793c602fabSXin LI 	{ OFPBRC_BAD_TYPE,       "BAD_TYPE"       },
4803c602fabSXin LI 	{ OFPBRC_BAD_STAT,       "BAD_STAT"       },
4813c602fabSXin LI 	{ OFPBRC_BAD_VENDOR,     "BAD_VENDOR"     },
4823c602fabSXin LI 	{ OFPBRC_BAD_SUBTYPE,    "BAD_SUBTYPE"    },
4833c602fabSXin LI 	{ OFPBRC_EPERM,          "EPERM"          },
4843c602fabSXin LI 	{ OFPBRC_BAD_LEN,        "BAD_LEN"        },
4853c602fabSXin LI 	{ OFPBRC_BUFFER_EMPTY,   "BUFFER_EMPTY"   },
4863c602fabSXin LI 	{ OFPBRC_BUFFER_UNKNOWN, "BUFFER_UNKNOWN" },
4873c602fabSXin LI 	{ 0, NULL }
4883c602fabSXin LI };
4893c602fabSXin LI 
4903c602fabSXin LI #define OFPBAC_BAD_TYPE        0x0000
4913c602fabSXin LI #define OFPBAC_BAD_LEN         0x0001
4923c602fabSXin LI #define OFPBAC_BAD_VENDOR      0x0002
4933c602fabSXin LI #define OFPBAC_BAD_VENDOR_TYPE 0x0003
4943c602fabSXin LI #define OFPBAC_BAD_OUT_PORT    0x0004
4953c602fabSXin LI #define OFPBAC_BAD_ARGUMENT    0x0005
4963c602fabSXin LI #define OFPBAC_EPERM           0x0006
4973c602fabSXin LI #define OFPBAC_TOO_MANY        0x0007
4983c602fabSXin LI #define OFPBAC_BAD_QUEUE       0x0008
4993c602fabSXin LI static const struct tok ofpbac_str[] = {
5003c602fabSXin LI 	{ OFPBAC_BAD_TYPE,        "BAD_TYPE"        },
5013c602fabSXin LI 	{ OFPBAC_BAD_LEN,         "BAD_LEN"         },
5023c602fabSXin LI 	{ OFPBAC_BAD_VENDOR,      "BAD_VENDOR"      },
5033c602fabSXin LI 	{ OFPBAC_BAD_VENDOR_TYPE, "BAD_VENDOR_TYPE" },
5043c602fabSXin LI 	{ OFPBAC_BAD_OUT_PORT,    "BAD_OUT_PORT"    },
5053c602fabSXin LI 	{ OFPBAC_BAD_ARGUMENT,    "BAD_ARGUMENT"    },
5063c602fabSXin LI 	{ OFPBAC_EPERM,           "EPERM"           },
5073c602fabSXin LI 	{ OFPBAC_TOO_MANY,        "TOO_MANY"        },
5083c602fabSXin LI 	{ OFPBAC_BAD_QUEUE,       "BAD_QUEUE"       },
5093c602fabSXin LI 	{ 0, NULL }
5103c602fabSXin LI };
5113c602fabSXin LI 
5123c602fabSXin LI #define OFPFMFC_ALL_TABLES_FULL   0x0000
5133c602fabSXin LI #define OFPFMFC_OVERLAP           0x0001
5143c602fabSXin LI #define OFPFMFC_EPERM             0x0002
5153c602fabSXin LI #define OFPFMFC_BAD_EMERG_TIMEOUT 0x0003
5163c602fabSXin LI #define OFPFMFC_BAD_COMMAND       0x0004
5173c602fabSXin LI #define OFPFMFC_UNSUPPORTED       0x0005
5183c602fabSXin LI static const struct tok ofpfmfc_str[] = {
5193c602fabSXin LI 	{ OFPFMFC_ALL_TABLES_FULL,   "ALL_TABLES_FULL"   },
5203c602fabSXin LI 	{ OFPFMFC_OVERLAP,           "OVERLAP"           },
5213c602fabSXin LI 	{ OFPFMFC_EPERM,             "EPERM"             },
5223c602fabSXin LI 	{ OFPFMFC_BAD_EMERG_TIMEOUT, "BAD_EMERG_TIMEOUT" },
5233c602fabSXin LI 	{ OFPFMFC_BAD_COMMAND,       "BAD_COMMAND"       },
5243c602fabSXin LI 	{ OFPFMFC_UNSUPPORTED,       "UNSUPPORTED"       },
5253c602fabSXin LI 	{ 0, NULL }
5263c602fabSXin LI };
5273c602fabSXin LI 
5283c602fabSXin LI #define OFPPMFC_BAD_PORT    0x0000
5293c602fabSXin LI #define OFPPMFC_BAD_HW_ADDR 0x0001
5303c602fabSXin LI static const struct tok ofppmfc_str[] = {
5313c602fabSXin LI 	{ OFPPMFC_BAD_PORT,    "BAD_PORT"    },
5323c602fabSXin LI 	{ OFPPMFC_BAD_HW_ADDR, "BAD_HW_ADDR" },
5333c602fabSXin LI 	{ 0, NULL }
5343c602fabSXin LI };
5353c602fabSXin LI 
5363c602fabSXin LI #define OFPQOFC_BAD_PORT  0x0000
5373c602fabSXin LI #define OFPQOFC_BAD_QUEUE 0x0001
5383c602fabSXin LI #define OFPQOFC_EPERM     0x0002
5393c602fabSXin LI static const struct tok ofpqofc_str[] = {
5403c602fabSXin LI 	{ OFPQOFC_BAD_PORT,  "BAD_PORT"  },
5413c602fabSXin LI 	{ OFPQOFC_BAD_QUEUE, "BAD_QUEUE" },
5423c602fabSXin LI 	{ OFPQOFC_EPERM,     "EPERM"     },
5433c602fabSXin LI 	{ 0, NULL }
5443c602fabSXin LI };
5453c602fabSXin LI 
5463c602fabSXin LI static const struct tok empty_str[] = {
5473c602fabSXin LI 	{ 0, NULL }
5483c602fabSXin LI };
5493c602fabSXin LI 
5503c602fabSXin LI /* lengths (fixed or minimal) of particular protocol structures */
5513c602fabSXin LI #define OF_SWITCH_CONFIG_LEN              12
5523c602fabSXin LI #define OF_PHY_PORT_LEN                   48
5533c602fabSXin LI #define OF_SWITCH_FEATURES_LEN            32
5543c602fabSXin LI #define OF_PORT_STATUS_LEN                64
5553c602fabSXin LI #define OF_PORT_MOD_LEN                   32
5563c602fabSXin LI #define OF_PACKET_IN_LEN                  20
5573c602fabSXin LI #define OF_ACTION_OUTPUT_LEN               8
5583c602fabSXin LI #define OF_ACTION_VLAN_VID_LEN             8
5593c602fabSXin LI #define OF_ACTION_VLAN_PCP_LEN             8
5603c602fabSXin LI #define OF_ACTION_DL_ADDR_LEN             16
5613c602fabSXin LI #define OF_ACTION_NW_ADDR_LEN              8
5623c602fabSXin LI #define OF_ACTION_TP_PORT_LEN              8
5633c602fabSXin LI #define OF_ACTION_NW_TOS_LEN               8
5643c602fabSXin LI #define OF_ACTION_VENDOR_HEADER_LEN        8
5653c602fabSXin LI #define OF_ACTION_HEADER_LEN               8
5663c602fabSXin LI #define OF_PACKET_OUT_LEN                 16
5673c602fabSXin LI #define OF_MATCH_LEN                      40
5683c602fabSXin LI #define OF_FLOW_MOD_LEN                   72
5693c602fabSXin LI #define OF_FLOW_REMOVED_LEN               88
5703c602fabSXin LI #define OF_ERROR_MSG_LEN                  12
5713c602fabSXin LI #define OF_STATS_REQUEST_LEN              12
5723c602fabSXin LI #define OF_STATS_REPLY_LEN                12
5733c602fabSXin LI #define OF_DESC_STATS_LEN               1056
5743c602fabSXin LI #define OF_FLOW_STATS_REQUEST_LEN         44
5753c602fabSXin LI #define OF_FLOW_STATS_LEN                 88
5763c602fabSXin LI #define OF_AGGREGATE_STATS_REQUEST_LEN    44
5773c602fabSXin LI #define OF_AGGREGATE_STATS_REPLY_LEN      24
5783c602fabSXin LI #define OF_TABLE_STATS_LEN                64
5793c602fabSXin LI #define OF_PORT_STATS_REQUEST_LEN          8
5803c602fabSXin LI #define OF_PORT_STATS_LEN                104
5813c602fabSXin LI #define OF_VENDOR_HEADER_LEN              12
5823c602fabSXin LI #define OF_QUEUE_PROP_HEADER_LEN           8
5833c602fabSXin LI #define OF_QUEUE_PROP_MIN_RATE_LEN        16
5843c602fabSXin LI #define OF_PACKET_QUEUE_LEN                8
5853c602fabSXin LI #define OF_QUEUE_GET_CONFIG_REQUEST_LEN   12
5863c602fabSXin LI #define OF_QUEUE_GET_CONFIG_REPLY_LEN     16
5873c602fabSXin LI #define OF_ACTION_ENQUEUE_LEN             16
5883c602fabSXin LI #define OF_QUEUE_STATS_REQUEST_LEN         8
5893c602fabSXin LI #define OF_QUEUE_STATS_LEN                32
5903c602fabSXin LI 
5913c602fabSXin LI /* miscellaneous constants from [OF10] */
5923c602fabSXin LI #define OFP_MAX_TABLE_NAME_LEN     32
5933c602fabSXin LI #define OFP_MAX_PORT_NAME_LEN      16
5943c602fabSXin LI #define DESC_STR_LEN              256
5953c602fabSXin LI #define SERIAL_NUM_LEN             32
5963c602fabSXin LI #define OFP_VLAN_NONE          0xffff
5973c602fabSXin LI 
598*8bdc5a62SPatrick Kelsey /* vendor extensions */
599*8bdc5a62SPatrick Kelsey #define BSN_SET_IP_MASK                    0
600*8bdc5a62SPatrick Kelsey #define BSN_GET_IP_MASK_REQUEST            1
601*8bdc5a62SPatrick Kelsey #define BSN_GET_IP_MASK_REPLY              2
602*8bdc5a62SPatrick Kelsey #define BSN_SET_MIRRORING                  3
603*8bdc5a62SPatrick Kelsey #define BSN_GET_MIRRORING_REQUEST          4
604*8bdc5a62SPatrick Kelsey #define BSN_GET_MIRRORING_REPLY            5
605*8bdc5a62SPatrick Kelsey #define BSN_SHELL_COMMAND                  6
606*8bdc5a62SPatrick Kelsey #define BSN_SHELL_OUTPUT                   7
607*8bdc5a62SPatrick Kelsey #define BSN_SHELL_STATUS                   8
608*8bdc5a62SPatrick Kelsey #define BSN_GET_INTERFACES_REQUEST         9
609*8bdc5a62SPatrick Kelsey #define BSN_GET_INTERFACES_REPLY          10
610*8bdc5a62SPatrick Kelsey #define BSN_SET_PKTIN_SUPPRESSION_REQUEST 11
611*8bdc5a62SPatrick Kelsey #define BSN_SET_L2_TABLE_REQUEST          12
612*8bdc5a62SPatrick Kelsey #define BSN_GET_L2_TABLE_REQUEST          13
613*8bdc5a62SPatrick Kelsey #define BSN_GET_L2_TABLE_REPLY            14
614*8bdc5a62SPatrick Kelsey #define BSN_VIRTUAL_PORT_CREATE_REQUEST   15
615*8bdc5a62SPatrick Kelsey #define BSN_VIRTUAL_PORT_CREATE_REPLY     16
616*8bdc5a62SPatrick Kelsey #define BSN_VIRTUAL_PORT_REMOVE_REQUEST   17
617*8bdc5a62SPatrick Kelsey #define BSN_BW_ENABLE_SET_REQUEST         18
618*8bdc5a62SPatrick Kelsey #define BSN_BW_ENABLE_GET_REQUEST         19
619*8bdc5a62SPatrick Kelsey #define BSN_BW_ENABLE_GET_REPLY           20
620*8bdc5a62SPatrick Kelsey #define BSN_BW_CLEAR_DATA_REQUEST         21
621*8bdc5a62SPatrick Kelsey #define BSN_BW_CLEAR_DATA_REPLY           22
622*8bdc5a62SPatrick Kelsey #define BSN_BW_ENABLE_SET_REPLY           23
623*8bdc5a62SPatrick Kelsey #define BSN_SET_L2_TABLE_REPLY            24
624*8bdc5a62SPatrick Kelsey #define BSN_SET_PKTIN_SUPPRESSION_REPLY   25
625*8bdc5a62SPatrick Kelsey #define BSN_VIRTUAL_PORT_REMOVE_REPLY     26
626*8bdc5a62SPatrick Kelsey #define BSN_HYBRID_GET_REQUEST            27
627*8bdc5a62SPatrick Kelsey #define BSN_HYBRID_GET_REPLY              28
628*8bdc5a62SPatrick Kelsey                                        /* 29 */
629*8bdc5a62SPatrick Kelsey                                        /* 30 */
630*8bdc5a62SPatrick Kelsey #define BSN_PDU_TX_REQUEST                31
631*8bdc5a62SPatrick Kelsey #define BSN_PDU_TX_REPLY                  32
632*8bdc5a62SPatrick Kelsey #define BSN_PDU_RX_REQUEST                33
633*8bdc5a62SPatrick Kelsey #define BSN_PDU_RX_REPLY                  34
634*8bdc5a62SPatrick Kelsey #define BSN_PDU_RX_TIMEOUT                35
635*8bdc5a62SPatrick Kelsey 
636*8bdc5a62SPatrick Kelsey static const struct tok bsn_subtype_str[] = {
637*8bdc5a62SPatrick Kelsey 	{ BSN_SET_IP_MASK,                   "SET_IP_MASK"                   },
638*8bdc5a62SPatrick Kelsey 	{ BSN_GET_IP_MASK_REQUEST,           "GET_IP_MASK_REQUEST"           },
639*8bdc5a62SPatrick Kelsey 	{ BSN_GET_IP_MASK_REPLY,             "GET_IP_MASK_REPLY"             },
640*8bdc5a62SPatrick Kelsey 	{ BSN_SET_MIRRORING,                 "SET_MIRRORING"                 },
641*8bdc5a62SPatrick Kelsey 	{ BSN_GET_MIRRORING_REQUEST,         "GET_MIRRORING_REQUEST"         },
642*8bdc5a62SPatrick Kelsey 	{ BSN_GET_MIRRORING_REPLY,           "GET_MIRRORING_REPLY"           },
643*8bdc5a62SPatrick Kelsey 	{ BSN_SHELL_COMMAND,                 "SHELL_COMMAND"                 },
644*8bdc5a62SPatrick Kelsey 	{ BSN_SHELL_OUTPUT,                  "SHELL_OUTPUT"                  },
645*8bdc5a62SPatrick Kelsey 	{ BSN_SHELL_STATUS,                  "SHELL_STATUS"                  },
646*8bdc5a62SPatrick Kelsey 	{ BSN_GET_INTERFACES_REQUEST,        "GET_INTERFACES_REQUEST"        },
647*8bdc5a62SPatrick Kelsey 	{ BSN_GET_INTERFACES_REPLY,          "GET_INTERFACES_REPLY"          },
648*8bdc5a62SPatrick Kelsey 	{ BSN_SET_PKTIN_SUPPRESSION_REQUEST, "SET_PKTIN_SUPPRESSION_REQUEST" },
649*8bdc5a62SPatrick Kelsey 	{ BSN_SET_L2_TABLE_REQUEST,          "SET_L2_TABLE_REQUEST"          },
650*8bdc5a62SPatrick Kelsey 	{ BSN_GET_L2_TABLE_REQUEST,          "GET_L2_TABLE_REQUEST"          },
651*8bdc5a62SPatrick Kelsey 	{ BSN_GET_L2_TABLE_REPLY,            "GET_L2_TABLE_REPLY"            },
652*8bdc5a62SPatrick Kelsey 	{ BSN_VIRTUAL_PORT_CREATE_REQUEST,   "VIRTUAL_PORT_CREATE_REQUEST"   },
653*8bdc5a62SPatrick Kelsey 	{ BSN_VIRTUAL_PORT_CREATE_REPLY,     "VIRTUAL_PORT_CREATE_REPLY"     },
654*8bdc5a62SPatrick Kelsey 	{ BSN_VIRTUAL_PORT_REMOVE_REQUEST,   "VIRTUAL_PORT_REMOVE_REQUEST"   },
655*8bdc5a62SPatrick Kelsey 	{ BSN_BW_ENABLE_SET_REQUEST,         "BW_ENABLE_SET_REQUEST"         },
656*8bdc5a62SPatrick Kelsey 	{ BSN_BW_ENABLE_GET_REQUEST,         "BW_ENABLE_GET_REQUEST"         },
657*8bdc5a62SPatrick Kelsey 	{ BSN_BW_ENABLE_GET_REPLY,           "BW_ENABLE_GET_REPLY"           },
658*8bdc5a62SPatrick Kelsey 	{ BSN_BW_CLEAR_DATA_REQUEST,         "BW_CLEAR_DATA_REQUEST"         },
659*8bdc5a62SPatrick Kelsey 	{ BSN_BW_CLEAR_DATA_REPLY,           "BW_CLEAR_DATA_REPLY"           },
660*8bdc5a62SPatrick Kelsey 	{ BSN_BW_ENABLE_SET_REPLY,           "BW_ENABLE_SET_REPLY"           },
661*8bdc5a62SPatrick Kelsey 	{ BSN_SET_L2_TABLE_REPLY,            "SET_L2_TABLE_REPLY"            },
662*8bdc5a62SPatrick Kelsey 	{ BSN_SET_PKTIN_SUPPRESSION_REPLY,   "SET_PKTIN_SUPPRESSION_REPLY"   },
663*8bdc5a62SPatrick Kelsey 	{ BSN_VIRTUAL_PORT_REMOVE_REPLY,     "VIRTUAL_PORT_REMOVE_REPLY"     },
664*8bdc5a62SPatrick Kelsey 	{ BSN_HYBRID_GET_REQUEST,            "HYBRID_GET_REQUEST"            },
665*8bdc5a62SPatrick Kelsey 	{ BSN_HYBRID_GET_REPLY,              "HYBRID_GET_REPLY"              },
666*8bdc5a62SPatrick Kelsey 	{ BSN_PDU_TX_REQUEST,                "PDU_TX_REQUEST"                },
667*8bdc5a62SPatrick Kelsey 	{ BSN_PDU_TX_REPLY,                  "PDU_TX_REPLY"                  },
668*8bdc5a62SPatrick Kelsey 	{ BSN_PDU_RX_REQUEST,                "PDU_RX_REQUEST"                },
669*8bdc5a62SPatrick Kelsey 	{ BSN_PDU_RX_REPLY,                  "PDU_RX_REPLY"                  },
670*8bdc5a62SPatrick Kelsey 	{ BSN_PDU_RX_TIMEOUT,                "PDU_RX_TIMEOUT"                },
671*8bdc5a62SPatrick Kelsey 	{ 0, NULL }
672*8bdc5a62SPatrick Kelsey };
673*8bdc5a62SPatrick Kelsey 
674*8bdc5a62SPatrick Kelsey #define BSN_ACTION_MIRROR                  1
675*8bdc5a62SPatrick Kelsey #define BSN_ACTION_SET_TUNNEL_DST          2
676*8bdc5a62SPatrick Kelsey                                         /* 3 */
677*8bdc5a62SPatrick Kelsey #define BSN_ACTION_CHECKSUM                4
678*8bdc5a62SPatrick Kelsey 
679*8bdc5a62SPatrick Kelsey static const struct tok bsn_action_subtype_str[] = {
680*8bdc5a62SPatrick Kelsey 	{ BSN_ACTION_MIRROR,                 "MIRROR"                        },
681*8bdc5a62SPatrick Kelsey 	{ BSN_ACTION_SET_TUNNEL_DST,         "SET_TUNNEL_DST"                },
682*8bdc5a62SPatrick Kelsey 	{ BSN_ACTION_CHECKSUM,               "CHECKSUM"                      },
683*8bdc5a62SPatrick Kelsey 	{ 0, NULL }
684*8bdc5a62SPatrick Kelsey };
685*8bdc5a62SPatrick Kelsey 
686*8bdc5a62SPatrick Kelsey static const struct tok bsn_mirror_copy_stage_str[] = {
687*8bdc5a62SPatrick Kelsey 	{ 0, "INGRESS" },
688*8bdc5a62SPatrick Kelsey 	{ 1, "EGRESS"  },
689*8bdc5a62SPatrick Kelsey 	{ 0, NULL },
690*8bdc5a62SPatrick Kelsey };
691*8bdc5a62SPatrick Kelsey 
692*8bdc5a62SPatrick Kelsey static const struct tok bsn_onoff_str[] = {
693*8bdc5a62SPatrick Kelsey 	{ 0, "OFF" },
694*8bdc5a62SPatrick Kelsey 	{ 1, "ON"  },
695*8bdc5a62SPatrick Kelsey 	{ 0, NULL },
696*8bdc5a62SPatrick Kelsey };
697*8bdc5a62SPatrick Kelsey 
6983c602fabSXin LI static const char *
699*8bdc5a62SPatrick Kelsey vlan_str(const uint16_t vid)
700*8bdc5a62SPatrick Kelsey {
7013c602fabSXin LI 	static char buf[sizeof("65535 (bogus)")];
7023c602fabSXin LI 	const char *fmt;
7033c602fabSXin LI 
7043c602fabSXin LI 	if (vid == OFP_VLAN_NONE)
7053c602fabSXin LI 		return "NONE";
7063c602fabSXin LI 	fmt = (vid > 0 && vid < 0x0fff) ? "%u" : "%u (bogus)";
7073c602fabSXin LI 	snprintf(buf, sizeof(buf), fmt, vid);
7083c602fabSXin LI 	return buf;
7093c602fabSXin LI }
7103c602fabSXin LI 
7113c602fabSXin LI static const char *
712*8bdc5a62SPatrick Kelsey pcp_str(const uint8_t pcp)
713*8bdc5a62SPatrick Kelsey {
7143c602fabSXin LI 	static char buf[sizeof("255 (bogus)")];
7153c602fabSXin LI 	snprintf(buf, sizeof(buf), pcp <= 7 ? "%u" : "%u (bogus)", pcp);
7163c602fabSXin LI 	return buf;
7173c602fabSXin LI }
7183c602fabSXin LI 
7193c602fabSXin LI static void
7203c602fabSXin LI of10_bitmap_print(netdissect_options *ndo,
721*8bdc5a62SPatrick Kelsey                   const struct tok *t, const uint32_t v, const uint32_t u)
722*8bdc5a62SPatrick Kelsey {
7233c602fabSXin LI 	const char *sep = " (";
7243c602fabSXin LI 
7253c602fabSXin LI 	if (v == 0)
7263c602fabSXin LI 		return;
7273c602fabSXin LI 	/* assigned bits */
7283c602fabSXin LI 	for (; t->s != NULL; t++)
7293c602fabSXin LI 		if (v & t->v) {
7303c602fabSXin LI 			ND_PRINT((ndo, "%s%s", sep, t->s));
7313c602fabSXin LI 			sep = ", ";
7323c602fabSXin LI 		}
7333c602fabSXin LI 	/* unassigned bits? */
7343c602fabSXin LI 	ND_PRINT((ndo, v & u ? ") (bogus)" : ")"));
7353c602fabSXin LI }
7363c602fabSXin LI 
7373c602fabSXin LI static const u_char *
7383c602fabSXin LI of10_data_print(netdissect_options *ndo,
739*8bdc5a62SPatrick Kelsey                 const u_char *cp, const u_char *ep, const u_int len)
740*8bdc5a62SPatrick Kelsey {
7413c602fabSXin LI 	if (len == 0)
7423c602fabSXin LI 		return cp;
7433c602fabSXin LI 	/* data */
7443c602fabSXin LI 	ND_PRINT((ndo, "\n\t data (%u octets)", len));
7453c602fabSXin LI 	ND_TCHECK2(*cp, len);
7463c602fabSXin LI 	if (ndo->ndo_vflag >= 2)
7473c602fabSXin LI 		hex_and_ascii_print(ndo, "\n\t  ", cp, len);
7483c602fabSXin LI 	return cp + len;
7493c602fabSXin LI 
7503c602fabSXin LI trunc:
7513c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
7523c602fabSXin LI 	return ep;
7533c602fabSXin LI }
7543c602fabSXin LI 
7553c602fabSXin LI static const u_char *
756*8bdc5a62SPatrick Kelsey of10_bsn_message_print(netdissect_options *ndo,
757*8bdc5a62SPatrick Kelsey                        const u_char *cp, const u_char *ep, const u_int len)
758*8bdc5a62SPatrick Kelsey {
759*8bdc5a62SPatrick Kelsey 	const u_char *cp0 = cp;
760*8bdc5a62SPatrick Kelsey 	uint32_t subtype;
761*8bdc5a62SPatrick Kelsey 
762*8bdc5a62SPatrick Kelsey 	if (len < 4)
763*8bdc5a62SPatrick Kelsey 		goto corrupt;
764*8bdc5a62SPatrick Kelsey 	/* subtype */
765*8bdc5a62SPatrick Kelsey 	ND_TCHECK2(*cp, 4);
766*8bdc5a62SPatrick Kelsey 	subtype = EXTRACT_32BITS(cp);
767*8bdc5a62SPatrick Kelsey 	cp += 4;
768*8bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, "\n\t subtype %s", tok2str(bsn_subtype_str, "unknown (0x%08x)", subtype)));
769*8bdc5a62SPatrick Kelsey 	switch (subtype) {
770*8bdc5a62SPatrick Kelsey 	case BSN_GET_IP_MASK_REQUEST:
771*8bdc5a62SPatrick Kelsey 		/*
772*8bdc5a62SPatrick Kelsey 		 *  0                   1                   2                   3
773*8bdc5a62SPatrick Kelsey 		 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
774*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
775*8bdc5a62SPatrick Kelsey 		 * |                            subtype                            |
776*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
777*8bdc5a62SPatrick Kelsey 		 * |     index     |                      pad                      |
778*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
779*8bdc5a62SPatrick Kelsey 		 * |                              pad                              |
780*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
781*8bdc5a62SPatrick Kelsey 		 *
782*8bdc5a62SPatrick Kelsey 		 */
783*8bdc5a62SPatrick Kelsey 		if (len != 12)
784*8bdc5a62SPatrick Kelsey 			goto corrupt;
785*8bdc5a62SPatrick Kelsey 		/* index */
786*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, 1);
787*8bdc5a62SPatrick Kelsey 		ND_PRINT((ndo, ", index %u", *cp));
788*8bdc5a62SPatrick Kelsey 		cp += 1;
789*8bdc5a62SPatrick Kelsey 		/* pad */
790*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, 7);
791*8bdc5a62SPatrick Kelsey 		cp += 7;
792*8bdc5a62SPatrick Kelsey 		break;
793*8bdc5a62SPatrick Kelsey 	case BSN_SET_IP_MASK:
794*8bdc5a62SPatrick Kelsey 	case BSN_GET_IP_MASK_REPLY:
795*8bdc5a62SPatrick Kelsey 		/*
796*8bdc5a62SPatrick Kelsey 		 *  0                   1                   2                   3
797*8bdc5a62SPatrick Kelsey 		 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
798*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
799*8bdc5a62SPatrick Kelsey 		 * |                            subtype                            |
800*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
801*8bdc5a62SPatrick Kelsey 		 * |     index     |                      pad                      |
802*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
803*8bdc5a62SPatrick Kelsey 		 * |                              mask                             |
804*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
805*8bdc5a62SPatrick Kelsey 		 *
806*8bdc5a62SPatrick Kelsey 		 */
807*8bdc5a62SPatrick Kelsey 		if (len != 12)
808*8bdc5a62SPatrick Kelsey 			goto corrupt;
809*8bdc5a62SPatrick Kelsey 		/* index */
810*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, 1);
811*8bdc5a62SPatrick Kelsey 		ND_PRINT((ndo, ", index %u", *cp));
812*8bdc5a62SPatrick Kelsey 		cp += 1;
813*8bdc5a62SPatrick Kelsey 		/* pad */
814*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, 3);
815*8bdc5a62SPatrick Kelsey 		cp += 3;
816*8bdc5a62SPatrick Kelsey 		/* mask */
817*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, 4);
818*8bdc5a62SPatrick Kelsey 		ND_PRINT((ndo, ", mask %s", ipaddr_string(ndo, cp)));
819*8bdc5a62SPatrick Kelsey 		cp += 4;
820*8bdc5a62SPatrick Kelsey 		break;
821*8bdc5a62SPatrick Kelsey 	case BSN_SET_MIRRORING:
822*8bdc5a62SPatrick Kelsey 	case BSN_GET_MIRRORING_REQUEST:
823*8bdc5a62SPatrick Kelsey 	case BSN_GET_MIRRORING_REPLY:
824*8bdc5a62SPatrick Kelsey 		/*
825*8bdc5a62SPatrick Kelsey 		 *  0                   1                   2                   3
826*8bdc5a62SPatrick Kelsey 		 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
827*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
828*8bdc5a62SPatrick Kelsey 		 * |                            subtype                            |
829*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
830*8bdc5a62SPatrick Kelsey 		 * | report m. p.  |                      pad                      |
831*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
832*8bdc5a62SPatrick Kelsey 		 *
833*8bdc5a62SPatrick Kelsey 		 */
834*8bdc5a62SPatrick Kelsey 		if (len != 8)
835*8bdc5a62SPatrick Kelsey 			goto corrupt;
836*8bdc5a62SPatrick Kelsey 		/* report_mirror_ports */
837*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, 1);
838*8bdc5a62SPatrick Kelsey 		ND_PRINT((ndo, ", report_mirror_ports %s", tok2str(bsn_onoff_str, "bogus (%u)", *cp)));
839*8bdc5a62SPatrick Kelsey 		cp += 1;
840*8bdc5a62SPatrick Kelsey 		/* pad */
841*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, 3);
842*8bdc5a62SPatrick Kelsey 		cp += 3;
843*8bdc5a62SPatrick Kelsey 		break;
844*8bdc5a62SPatrick Kelsey 	case BSN_GET_INTERFACES_REQUEST:
845*8bdc5a62SPatrick Kelsey 	case BSN_GET_L2_TABLE_REQUEST:
846*8bdc5a62SPatrick Kelsey 	case BSN_BW_ENABLE_GET_REQUEST:
847*8bdc5a62SPatrick Kelsey 	case BSN_BW_CLEAR_DATA_REQUEST:
848*8bdc5a62SPatrick Kelsey 	case BSN_HYBRID_GET_REQUEST:
849*8bdc5a62SPatrick Kelsey 		/*
850*8bdc5a62SPatrick Kelsey 		 *  0                   1                   2                   3
851*8bdc5a62SPatrick Kelsey 		 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
852*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
853*8bdc5a62SPatrick Kelsey 		 * |                            subtype                            |
854*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
855*8bdc5a62SPatrick Kelsey 		 *
856*8bdc5a62SPatrick Kelsey 		 */
857*8bdc5a62SPatrick Kelsey 		if (len != 4)
858*8bdc5a62SPatrick Kelsey 			goto corrupt;
859*8bdc5a62SPatrick Kelsey 		break;
860*8bdc5a62SPatrick Kelsey 	case BSN_VIRTUAL_PORT_REMOVE_REQUEST:
861*8bdc5a62SPatrick Kelsey 		/*
862*8bdc5a62SPatrick Kelsey 		 *  0                   1                   2                   3
863*8bdc5a62SPatrick Kelsey 		 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
864*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
865*8bdc5a62SPatrick Kelsey 		 * |                            subtype                            |
866*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
867*8bdc5a62SPatrick Kelsey 		 * |                           vport_no                            |
868*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
869*8bdc5a62SPatrick Kelsey 		 *
870*8bdc5a62SPatrick Kelsey 		 */
871*8bdc5a62SPatrick Kelsey 		if (len != 8)
872*8bdc5a62SPatrick Kelsey 			goto corrupt;
873*8bdc5a62SPatrick Kelsey 		/* vport_no */
874*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, 4);
875*8bdc5a62SPatrick Kelsey 		ND_PRINT((ndo, ", vport_no %u", EXTRACT_32BITS(cp)));
876*8bdc5a62SPatrick Kelsey 		cp += 4;
877*8bdc5a62SPatrick Kelsey 		break;
878*8bdc5a62SPatrick Kelsey 	case BSN_SHELL_COMMAND:
879*8bdc5a62SPatrick Kelsey 		/*
880*8bdc5a62SPatrick Kelsey 		 *  0                   1                   2                   3
881*8bdc5a62SPatrick Kelsey 		 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
882*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
883*8bdc5a62SPatrick Kelsey 		 * |                            subtype                            |
884*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
885*8bdc5a62SPatrick Kelsey 		 * |                            service                            |
886*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
887*8bdc5a62SPatrick Kelsey 		 * |                             data ...
888*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+--------
889*8bdc5a62SPatrick Kelsey 		 *
890*8bdc5a62SPatrick Kelsey 		 */
891*8bdc5a62SPatrick Kelsey 		if (len < 8)
892*8bdc5a62SPatrick Kelsey 			goto corrupt;
893*8bdc5a62SPatrick Kelsey 		/* service */
894*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, 4);
895*8bdc5a62SPatrick Kelsey 		ND_PRINT((ndo, ", service %u", EXTRACT_32BITS(cp)));
896*8bdc5a62SPatrick Kelsey 		cp += 4;
897*8bdc5a62SPatrick Kelsey 		/* data */
898*8bdc5a62SPatrick Kelsey 		ND_PRINT((ndo, ", data '"));
899*8bdc5a62SPatrick Kelsey 		if (fn_printn(ndo, cp, len - 8, ep)) {
900*8bdc5a62SPatrick Kelsey 			ND_PRINT((ndo, "'"));
901*8bdc5a62SPatrick Kelsey 			goto trunc;
902*8bdc5a62SPatrick Kelsey 		}
903*8bdc5a62SPatrick Kelsey 		ND_PRINT((ndo, "'"));
904*8bdc5a62SPatrick Kelsey 		cp += len - 8;
905*8bdc5a62SPatrick Kelsey 		break;
906*8bdc5a62SPatrick Kelsey 	case BSN_SHELL_OUTPUT:
907*8bdc5a62SPatrick Kelsey 		/*
908*8bdc5a62SPatrick Kelsey 		 *  0                   1                   2                   3
909*8bdc5a62SPatrick Kelsey 		 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
910*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
911*8bdc5a62SPatrick Kelsey 		 * |                            subtype                            |
912*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
913*8bdc5a62SPatrick Kelsey 		 * |                             data ...
914*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+--------
915*8bdc5a62SPatrick Kelsey 		 *
916*8bdc5a62SPatrick Kelsey 		 */
917*8bdc5a62SPatrick Kelsey 		/* already checked that len >= 4 */
918*8bdc5a62SPatrick Kelsey 		/* data */
919*8bdc5a62SPatrick Kelsey 		ND_PRINT((ndo, ", data '"));
920*8bdc5a62SPatrick Kelsey 		if (fn_printn(ndo, cp, len - 4, ep)) {
921*8bdc5a62SPatrick Kelsey 			ND_PRINT((ndo, "'"));
922*8bdc5a62SPatrick Kelsey 			goto trunc;
923*8bdc5a62SPatrick Kelsey 		}
924*8bdc5a62SPatrick Kelsey 		ND_PRINT((ndo, "'"));
925*8bdc5a62SPatrick Kelsey 		cp += len - 4;
926*8bdc5a62SPatrick Kelsey 		break;
927*8bdc5a62SPatrick Kelsey 	case BSN_SHELL_STATUS:
928*8bdc5a62SPatrick Kelsey 		/*
929*8bdc5a62SPatrick Kelsey 		 *  0                   1                   2                   3
930*8bdc5a62SPatrick Kelsey 		 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
931*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
932*8bdc5a62SPatrick Kelsey 		 * |                            subtype                            |
933*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
934*8bdc5a62SPatrick Kelsey 		 * |                            status                             |
935*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
936*8bdc5a62SPatrick Kelsey 		 *
937*8bdc5a62SPatrick Kelsey 		 */
938*8bdc5a62SPatrick Kelsey 		if (len != 8)
939*8bdc5a62SPatrick Kelsey 			goto corrupt;
940*8bdc5a62SPatrick Kelsey 		/* status */
941*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, 4);
942*8bdc5a62SPatrick Kelsey 		ND_PRINT((ndo, ", status 0x%08x", EXTRACT_32BITS(cp)));
943*8bdc5a62SPatrick Kelsey 		cp += 4;
944*8bdc5a62SPatrick Kelsey 		break;
945*8bdc5a62SPatrick Kelsey 	default:
946*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, len - 4);
947*8bdc5a62SPatrick Kelsey 		cp += len - 4;
948*8bdc5a62SPatrick Kelsey 	}
949*8bdc5a62SPatrick Kelsey 	return cp;
950*8bdc5a62SPatrick Kelsey 
951*8bdc5a62SPatrick Kelsey corrupt: /* skip the undersized data */
952*8bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, "%s", cstr));
953*8bdc5a62SPatrick Kelsey 	ND_TCHECK2(*cp0, len);
954*8bdc5a62SPatrick Kelsey 	return cp0 + len;
955*8bdc5a62SPatrick Kelsey trunc:
956*8bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, "%s", tstr));
957*8bdc5a62SPatrick Kelsey 	return ep;
958*8bdc5a62SPatrick Kelsey }
959*8bdc5a62SPatrick Kelsey 
960*8bdc5a62SPatrick Kelsey static const u_char *
961*8bdc5a62SPatrick Kelsey of10_bsn_actions_print(netdissect_options *ndo,
962*8bdc5a62SPatrick Kelsey                        const u_char *cp, const u_char *ep, const u_int len)
963*8bdc5a62SPatrick Kelsey {
964*8bdc5a62SPatrick Kelsey 	const u_char *cp0 = cp;
965*8bdc5a62SPatrick Kelsey 	uint32_t subtype, vlan_tag;
966*8bdc5a62SPatrick Kelsey 
967*8bdc5a62SPatrick Kelsey 	if (len < 4)
968*8bdc5a62SPatrick Kelsey 		goto corrupt;
969*8bdc5a62SPatrick Kelsey 	/* subtype */
970*8bdc5a62SPatrick Kelsey 	ND_TCHECK2(*cp, 4);
971*8bdc5a62SPatrick Kelsey 	subtype = EXTRACT_32BITS(cp);
972*8bdc5a62SPatrick Kelsey 	cp += 4;
973*8bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, "\n\t  subtype %s", tok2str(bsn_action_subtype_str, "unknown (0x%08x)", subtype)));
974*8bdc5a62SPatrick Kelsey 	switch (subtype) {
975*8bdc5a62SPatrick Kelsey 	case BSN_ACTION_MIRROR:
976*8bdc5a62SPatrick Kelsey 		/*
977*8bdc5a62SPatrick Kelsey 		 *  0                   1                   2                   3
978*8bdc5a62SPatrick Kelsey 		 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
979*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
980*8bdc5a62SPatrick Kelsey 		 * |                            subtype                            |
981*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
982*8bdc5a62SPatrick Kelsey 		 * |                           dest_port                           |
983*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
984*8bdc5a62SPatrick Kelsey 		 * |                           vlan_tag                            |
985*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
986*8bdc5a62SPatrick Kelsey 		 * |  copy_stage   |                      pad                      |
987*8bdc5a62SPatrick Kelsey 		 * +---------------+---------------+---------------+---------------+
988*8bdc5a62SPatrick Kelsey 		 *
989*8bdc5a62SPatrick Kelsey 		 */
990*8bdc5a62SPatrick Kelsey 		if (len != 16)
991*8bdc5a62SPatrick Kelsey 			goto corrupt;
992*8bdc5a62SPatrick Kelsey 		/* dest_port */
993*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, 4);
994*8bdc5a62SPatrick Kelsey 		ND_PRINT((ndo, ", dest_port %u", EXTRACT_32BITS(cp)));
995*8bdc5a62SPatrick Kelsey 		cp += 4;
996*8bdc5a62SPatrick Kelsey 		/* vlan_tag */
997*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, 4);
998*8bdc5a62SPatrick Kelsey 		vlan_tag = EXTRACT_32BITS(cp);
999*8bdc5a62SPatrick Kelsey 		cp += 4;
1000*8bdc5a62SPatrick Kelsey 		switch (vlan_tag >> 16) {
1001*8bdc5a62SPatrick Kelsey 		case 0:
1002*8bdc5a62SPatrick Kelsey 			ND_PRINT((ndo, ", vlan_tag none"));
1003*8bdc5a62SPatrick Kelsey 			break;
1004*8bdc5a62SPatrick Kelsey 		case ETHERTYPE_8021Q:
1005*8bdc5a62SPatrick Kelsey 			ND_PRINT((ndo, ", vlan_tag 802.1Q (%s)", ieee8021q_tci_string(vlan_tag & 0xffff)));
1006*8bdc5a62SPatrick Kelsey 			break;
1007*8bdc5a62SPatrick Kelsey 		default:
1008*8bdc5a62SPatrick Kelsey 			ND_PRINT((ndo, ", vlan_tag unknown (0x%04x)", vlan_tag >> 16));
1009*8bdc5a62SPatrick Kelsey 		}
1010*8bdc5a62SPatrick Kelsey 		/* copy_stage */
1011*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, 1);
1012*8bdc5a62SPatrick Kelsey 		ND_PRINT((ndo, ", copy_stage %s", tok2str(bsn_mirror_copy_stage_str, "unknown (%u)", *cp)));
1013*8bdc5a62SPatrick Kelsey 		cp += 1;
1014*8bdc5a62SPatrick Kelsey 		/* pad */
1015*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, 3);
1016*8bdc5a62SPatrick Kelsey 		cp += 3;
1017*8bdc5a62SPatrick Kelsey 		break;
1018*8bdc5a62SPatrick Kelsey 	default:
1019*8bdc5a62SPatrick Kelsey 		ND_TCHECK2(*cp, len - 4);
1020*8bdc5a62SPatrick Kelsey 		cp += len - 4;
1021*8bdc5a62SPatrick Kelsey 	}
1022*8bdc5a62SPatrick Kelsey 
1023*8bdc5a62SPatrick Kelsey 	return cp;
1024*8bdc5a62SPatrick Kelsey 
1025*8bdc5a62SPatrick Kelsey corrupt:
1026*8bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, "%s", cstr));
1027*8bdc5a62SPatrick Kelsey 	ND_TCHECK2(*cp0, len);
1028*8bdc5a62SPatrick Kelsey 	return cp0 + len;
1029*8bdc5a62SPatrick Kelsey trunc:
1030*8bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, "%s", tstr));
1031*8bdc5a62SPatrick Kelsey 	return ep;
1032*8bdc5a62SPatrick Kelsey }
1033*8bdc5a62SPatrick Kelsey 
1034*8bdc5a62SPatrick Kelsey static const u_char *
1035*8bdc5a62SPatrick Kelsey of10_vendor_action_print(netdissect_options *ndo,
1036*8bdc5a62SPatrick Kelsey                          const u_char *cp, const u_char *ep, const u_int len)
1037*8bdc5a62SPatrick Kelsey {
1038*8bdc5a62SPatrick Kelsey 	uint32_t vendor;
1039*8bdc5a62SPatrick Kelsey 	const u_char *(*decoder)(netdissect_options *, const u_char *, const u_char *, const u_int);
1040*8bdc5a62SPatrick Kelsey 
10413c602fabSXin LI 	if (len < 4)
10423c602fabSXin LI 		goto corrupt;
10433c602fabSXin LI 	/* vendor */
10443c602fabSXin LI 	ND_TCHECK2(*cp, 4);
1045*8bdc5a62SPatrick Kelsey 	vendor = EXTRACT_32BITS(cp);
10463c602fabSXin LI 	cp += 4;
1047*8bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, ", vendor 0x%08x (%s)", vendor, of_vendor_name(vendor)));
1048*8bdc5a62SPatrick Kelsey 	/* data */
1049*8bdc5a62SPatrick Kelsey 	decoder =
1050*8bdc5a62SPatrick Kelsey 		vendor == OUI_BSN         ? of10_bsn_actions_print         :
1051*8bdc5a62SPatrick Kelsey 		of10_data_print;
1052*8bdc5a62SPatrick Kelsey 	return decoder(ndo, cp, ep, len - 4);
1053*8bdc5a62SPatrick Kelsey 
1054*8bdc5a62SPatrick Kelsey corrupt: /* skip the undersized data */
1055*8bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, "%s", cstr));
1056*8bdc5a62SPatrick Kelsey 	ND_TCHECK2(*cp, len);
1057*8bdc5a62SPatrick Kelsey 	return cp + len;
1058*8bdc5a62SPatrick Kelsey trunc:
1059*8bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, "%s", tstr));
1060*8bdc5a62SPatrick Kelsey 	return ep;
1061*8bdc5a62SPatrick Kelsey }
1062*8bdc5a62SPatrick Kelsey 
1063*8bdc5a62SPatrick Kelsey static const u_char *
1064*8bdc5a62SPatrick Kelsey of10_vendor_message_print(netdissect_options *ndo,
1065*8bdc5a62SPatrick Kelsey                           const u_char *cp, const u_char *ep, const u_int len)
1066*8bdc5a62SPatrick Kelsey {
1067*8bdc5a62SPatrick Kelsey 	uint32_t vendor;
1068*8bdc5a62SPatrick Kelsey 	const u_char *(*decoder)(netdissect_options *, const u_char *, const u_char *, u_int);
1069*8bdc5a62SPatrick Kelsey 
1070*8bdc5a62SPatrick Kelsey 	if (len < 4)
1071*8bdc5a62SPatrick Kelsey 		goto corrupt;
1072*8bdc5a62SPatrick Kelsey 	/* vendor */
1073*8bdc5a62SPatrick Kelsey 	ND_TCHECK2(*cp, 4);
1074*8bdc5a62SPatrick Kelsey 	vendor = EXTRACT_32BITS(cp);
1075*8bdc5a62SPatrick Kelsey 	cp += 4;
1076*8bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, ", vendor 0x%08x (%s)", vendor, of_vendor_name(vendor)));
1077*8bdc5a62SPatrick Kelsey 	/* data */
1078*8bdc5a62SPatrick Kelsey 	decoder =
1079*8bdc5a62SPatrick Kelsey 		vendor == OUI_BSN         ? of10_bsn_message_print         :
1080*8bdc5a62SPatrick Kelsey 		of10_data_print;
1081*8bdc5a62SPatrick Kelsey 	return decoder(ndo, cp, ep, len - 4);
1082*8bdc5a62SPatrick Kelsey 
1083*8bdc5a62SPatrick Kelsey corrupt: /* skip the undersized data */
1084*8bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, "%s", cstr));
1085*8bdc5a62SPatrick Kelsey 	ND_TCHECK2(*cp, len);
1086*8bdc5a62SPatrick Kelsey 	return cp + len;
1087*8bdc5a62SPatrick Kelsey trunc:
1088*8bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, "%s", tstr));
1089*8bdc5a62SPatrick Kelsey 	return ep;
1090*8bdc5a62SPatrick Kelsey }
1091*8bdc5a62SPatrick Kelsey 
1092*8bdc5a62SPatrick Kelsey /* Vendor ID is mandatory, data is optional. */
1093*8bdc5a62SPatrick Kelsey static const u_char *
1094*8bdc5a62SPatrick Kelsey of10_vendor_data_print(netdissect_options *ndo,
1095*8bdc5a62SPatrick Kelsey                        const u_char *cp, const u_char *ep, const u_int len)
1096*8bdc5a62SPatrick Kelsey {
1097*8bdc5a62SPatrick Kelsey 	uint32_t vendor;
1098*8bdc5a62SPatrick Kelsey 
1099*8bdc5a62SPatrick Kelsey 	if (len < 4)
1100*8bdc5a62SPatrick Kelsey 		goto corrupt;
1101*8bdc5a62SPatrick Kelsey 	/* vendor */
1102*8bdc5a62SPatrick Kelsey 	ND_TCHECK2(*cp, 4);
1103*8bdc5a62SPatrick Kelsey 	vendor = EXTRACT_32BITS(cp);
1104*8bdc5a62SPatrick Kelsey 	cp += 4;
1105*8bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, ", vendor 0x%08x (%s)", vendor, of_vendor_name(vendor)));
11063c602fabSXin LI 	/* data */
11073c602fabSXin LI 	return of10_data_print(ndo, cp, ep, len - 4);
11083c602fabSXin LI 
11093c602fabSXin LI corrupt: /* skip the undersized data */
11103c602fabSXin LI 	ND_PRINT((ndo, "%s", cstr));
11113c602fabSXin LI 	ND_TCHECK2(*cp, len);
11123c602fabSXin LI 	return cp + len;
11133c602fabSXin LI trunc:
11143c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
11153c602fabSXin LI 	return ep;
11163c602fabSXin LI }
11173c602fabSXin LI 
11183c602fabSXin LI static const u_char *
11193c602fabSXin LI of10_packet_data_print(netdissect_options *ndo,
1120*8bdc5a62SPatrick Kelsey                        const u_char *cp, const u_char *ep, const u_int len)
1121*8bdc5a62SPatrick Kelsey {
11223c602fabSXin LI 	if (len == 0)
11233c602fabSXin LI 		return cp;
11243c602fabSXin LI 	/* data */
11253c602fabSXin LI 	ND_PRINT((ndo, "\n\t data (%u octets)", len));
11263c602fabSXin LI 	if (ndo->ndo_vflag < 3)
11273c602fabSXin LI 		return cp + len;
11283c602fabSXin LI 	ND_TCHECK2(*cp, len);
11293c602fabSXin LI 	ndo->ndo_vflag -= 3;
11303c602fabSXin LI 	ND_PRINT((ndo, ", frame decoding below\n"));
11313c602fabSXin LI 	ether_print(ndo, cp, len, ndo->ndo_snapend - cp, NULL, NULL);
11323c602fabSXin LI 	ndo->ndo_vflag += 3;
11333c602fabSXin LI 	return cp + len;
11343c602fabSXin LI 
11353c602fabSXin LI trunc:
11363c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
11373c602fabSXin LI 	return ep;
11383c602fabSXin LI }
11393c602fabSXin LI 
11403c602fabSXin LI /* [OF10] Section 5.2.1 */
11413c602fabSXin LI static const u_char *
11423c602fabSXin LI of10_phy_ports_print(netdissect_options *ndo,
1143*8bdc5a62SPatrick Kelsey                      const u_char *cp, const u_char *ep, u_int len)
1144*8bdc5a62SPatrick Kelsey {
11453c602fabSXin LI 	const u_char *cp0 = cp;
11463c602fabSXin LI 	const u_int len0 = len;
11473c602fabSXin LI 
11483c602fabSXin LI 	while (len) {
11493c602fabSXin LI 		if (len < OF_PHY_PORT_LEN)
11503c602fabSXin LI 			goto corrupt;
11513c602fabSXin LI 		/* port_no */
11523c602fabSXin LI 		ND_TCHECK2(*cp, 2);
11533c602fabSXin LI 		ND_PRINT((ndo, "\n\t  port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
11543c602fabSXin LI 		cp += 2;
11553c602fabSXin LI 		/* hw_addr */
11563c602fabSXin LI 		ND_TCHECK2(*cp, ETHER_ADDR_LEN);
11573c602fabSXin LI 		ND_PRINT((ndo, ", hw_addr %s", etheraddr_string(ndo, cp)));
11583c602fabSXin LI 		cp += ETHER_ADDR_LEN;
11593c602fabSXin LI 		/* name */
11603c602fabSXin LI 		ND_TCHECK2(*cp, OFP_MAX_PORT_NAME_LEN);
11613c602fabSXin LI 		ND_PRINT((ndo, ", name '"));
11623c602fabSXin LI 		fn_print(ndo, cp, cp + OFP_MAX_PORT_NAME_LEN);
11633c602fabSXin LI 		ND_PRINT((ndo, "'"));
11643c602fabSXin LI 		cp += OFP_MAX_PORT_NAME_LEN;
11653c602fabSXin LI 
11663c602fabSXin LI 		if (ndo->ndo_vflag < 2) {
11673c602fabSXin LI 			ND_TCHECK2(*cp, 24);
11683c602fabSXin LI 			cp += 24;
11693c602fabSXin LI 			goto next_port;
11703c602fabSXin LI 		}
11713c602fabSXin LI 		/* config */
11723c602fabSXin LI 		ND_TCHECK2(*cp, 4);
11733c602fabSXin LI 		ND_PRINT((ndo, "\n\t   config 0x%08x", EXTRACT_32BITS(cp)));
11743c602fabSXin LI 		of10_bitmap_print(ndo, ofppc_bm, EXTRACT_32BITS(cp), OFPPC_U);
11753c602fabSXin LI 		cp += 4;
11763c602fabSXin LI 		/* state */
11773c602fabSXin LI 		ND_TCHECK2(*cp, 4);
11783c602fabSXin LI 		ND_PRINT((ndo, "\n\t   state 0x%08x", EXTRACT_32BITS(cp)));
11793c602fabSXin LI 		of10_bitmap_print(ndo, ofpps_bm, EXTRACT_32BITS(cp), OFPPS_U);
11803c602fabSXin LI 		cp += 4;
11813c602fabSXin LI 		/* curr */
11823c602fabSXin LI 		ND_TCHECK2(*cp, 4);
11833c602fabSXin LI 		ND_PRINT((ndo, "\n\t   curr 0x%08x", EXTRACT_32BITS(cp)));
11843c602fabSXin LI 		of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U);
11853c602fabSXin LI 		cp += 4;
11863c602fabSXin LI 		/* advertised */
11873c602fabSXin LI 		ND_TCHECK2(*cp, 4);
11883c602fabSXin LI 		ND_PRINT((ndo, "\n\t   advertised 0x%08x", EXTRACT_32BITS(cp)));
11893c602fabSXin LI 		of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U);
11903c602fabSXin LI 		cp += 4;
11913c602fabSXin LI 		/* supported */
11923c602fabSXin LI 		ND_TCHECK2(*cp, 4);
11933c602fabSXin LI 		ND_PRINT((ndo, "\n\t   supported 0x%08x", EXTRACT_32BITS(cp)));
11943c602fabSXin LI 		of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U);
11953c602fabSXin LI 		cp += 4;
11963c602fabSXin LI 		/* peer */
11973c602fabSXin LI 		ND_TCHECK2(*cp, 4);
11983c602fabSXin LI 		ND_PRINT((ndo, "\n\t   peer 0x%08x", EXTRACT_32BITS(cp)));
11993c602fabSXin LI 		of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U);
12003c602fabSXin LI 		cp += 4;
12013c602fabSXin LI next_port:
12023c602fabSXin LI 		len -= OF_PHY_PORT_LEN;
12033c602fabSXin LI 	} /* while */
12043c602fabSXin LI 	return cp;
12053c602fabSXin LI 
12063c602fabSXin LI corrupt: /* skip the undersized trailing data */
12073c602fabSXin LI 	ND_PRINT((ndo, "%s", cstr));
12083c602fabSXin LI 	ND_TCHECK2(*cp0, len0);
12093c602fabSXin LI 	return cp0 + len0;
12103c602fabSXin LI trunc:
12113c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
12123c602fabSXin LI 	return ep;
12133c602fabSXin LI }
12143c602fabSXin LI 
12153c602fabSXin LI /* [OF10] Section 5.2.2 */
12163c602fabSXin LI static const u_char *
12173c602fabSXin LI of10_queue_props_print(netdissect_options *ndo,
1218*8bdc5a62SPatrick Kelsey                        const u_char *cp, const u_char *ep, u_int len)
1219*8bdc5a62SPatrick Kelsey {
12203c602fabSXin LI 	const u_char *cp0 = cp;
12213c602fabSXin LI 	const u_int len0 = len;
12223c602fabSXin LI 	uint16_t property, plen, rate;
12233c602fabSXin LI 
12243c602fabSXin LI 	while (len) {
12253c602fabSXin LI 		u_char plen_bogus = 0, skip = 0;
12263c602fabSXin LI 
12273c602fabSXin LI 		if (len < OF_QUEUE_PROP_HEADER_LEN)
12283c602fabSXin LI 			goto corrupt;
12293c602fabSXin LI 		/* property */
12303c602fabSXin LI 		ND_TCHECK2(*cp, 2);
12313c602fabSXin LI 		property = EXTRACT_16BITS(cp);
12323c602fabSXin LI 		cp += 2;
12333c602fabSXin LI 		ND_PRINT((ndo, "\n\t   property %s", tok2str(ofpqt_str, "invalid (0x%04x)", property)));
12343c602fabSXin LI 		/* len */
12353c602fabSXin LI 		ND_TCHECK2(*cp, 2);
12363c602fabSXin LI 		plen = EXTRACT_16BITS(cp);
12373c602fabSXin LI 		cp += 2;
12383c602fabSXin LI 		ND_PRINT((ndo, ", len %u", plen));
12393c602fabSXin LI 		if (plen < OF_QUEUE_PROP_HEADER_LEN || plen > len)
12403c602fabSXin LI 			goto corrupt;
12413c602fabSXin LI 		/* pad */
12423c602fabSXin LI 		ND_TCHECK2(*cp, 4);
12433c602fabSXin LI 		cp += 4;
12443c602fabSXin LI 		/* property-specific constraints and decoding */
12453c602fabSXin LI 		switch (property) {
12463c602fabSXin LI 		case OFPQT_NONE:
12473c602fabSXin LI 			plen_bogus = plen != OF_QUEUE_PROP_HEADER_LEN;
12483c602fabSXin LI 			break;
12493c602fabSXin LI 		case OFPQT_MIN_RATE:
12503c602fabSXin LI 			plen_bogus = plen != OF_QUEUE_PROP_MIN_RATE_LEN;
12513c602fabSXin LI 			break;
12523c602fabSXin LI 		default:
12533c602fabSXin LI 			skip = 1;
12543c602fabSXin LI 		}
12553c602fabSXin LI 		if (plen_bogus) {
12563c602fabSXin LI 			ND_PRINT((ndo, " (bogus)"));
12573c602fabSXin LI 			skip = 1;
12583c602fabSXin LI 		}
12593c602fabSXin LI 		if (skip) {
12603c602fabSXin LI 			ND_TCHECK2(*cp, plen - 4);
12613c602fabSXin LI 			cp += plen - 4;
12623c602fabSXin LI 			goto next_property;
12633c602fabSXin LI 		}
12643c602fabSXin LI 		if (property == OFPQT_MIN_RATE) { /* the only case of property decoding */
12653c602fabSXin LI 			/* rate */
12663c602fabSXin LI 			ND_TCHECK2(*cp, 2);
12673c602fabSXin LI 			rate = EXTRACT_16BITS(cp);
12683c602fabSXin LI 			cp += 2;
12693c602fabSXin LI 			if (rate > 1000)
12703c602fabSXin LI 				ND_PRINT((ndo, ", rate disabled"));
12713c602fabSXin LI 			else
12723c602fabSXin LI 				ND_PRINT((ndo, ", rate %u.%u%%", rate / 10, rate % 10));
12733c602fabSXin LI 			/* pad */
12743c602fabSXin LI 			ND_TCHECK2(*cp, 6);
12753c602fabSXin LI 			cp += 6;
12763c602fabSXin LI 		}
12773c602fabSXin LI next_property:
12783c602fabSXin LI 		len -= plen;
12793c602fabSXin LI 	} /* while */
12803c602fabSXin LI 	return cp;
12813c602fabSXin LI 
12823c602fabSXin LI corrupt: /* skip the rest of queue properties */
12833c602fabSXin LI 	ND_PRINT((ndo, "%s", cstr));
12843c602fabSXin LI 	ND_TCHECK2(*cp0, len0);
12853c602fabSXin LI 	return cp0 + len0;
12863c602fabSXin LI trunc:
12873c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
12883c602fabSXin LI 	return ep;
12893c602fabSXin LI }
12903c602fabSXin LI 
12913c602fabSXin LI /* ibid */
12923c602fabSXin LI static const u_char *
12933c602fabSXin LI of10_queues_print(netdissect_options *ndo,
1294*8bdc5a62SPatrick Kelsey                   const u_char *cp, const u_char *ep, u_int len)
1295*8bdc5a62SPatrick Kelsey {
12963c602fabSXin LI 	const u_char *cp0 = cp;
12973c602fabSXin LI 	const u_int len0 = len;
12983c602fabSXin LI 	uint16_t desclen;
12993c602fabSXin LI 
13003c602fabSXin LI 	while (len) {
13013c602fabSXin LI 		if (len < OF_PACKET_QUEUE_LEN)
13023c602fabSXin LI 			goto corrupt;
13033c602fabSXin LI 		/* queue_id */
13043c602fabSXin LI 		ND_TCHECK2(*cp, 4);
13053c602fabSXin LI 		ND_PRINT((ndo, "\n\t  queue_id %u", EXTRACT_32BITS(cp)));
13063c602fabSXin LI 		cp += 4;
13073c602fabSXin LI 		/* len */
13083c602fabSXin LI 		ND_TCHECK2(*cp, 2);
13093c602fabSXin LI 		desclen = EXTRACT_16BITS(cp);
13103c602fabSXin LI 		cp += 2;
13113c602fabSXin LI 		ND_PRINT((ndo, ", len %u", desclen));
13123c602fabSXin LI 		if (desclen < OF_PACKET_QUEUE_LEN || desclen > len)
13133c602fabSXin LI 			goto corrupt;
13143c602fabSXin LI 		/* pad */
13153c602fabSXin LI 		ND_TCHECK2(*cp, 2);
13163c602fabSXin LI 		cp += 2;
13173c602fabSXin LI 		/* properties */
13183c602fabSXin LI 		if (ndo->ndo_vflag < 2) {
13193c602fabSXin LI 			ND_TCHECK2(*cp, desclen - OF_PACKET_QUEUE_LEN);
13203c602fabSXin LI 			cp += desclen - OF_PACKET_QUEUE_LEN;
13213c602fabSXin LI 			goto next_queue;
13223c602fabSXin LI 		}
13233c602fabSXin LI 		if (ep == (cp = of10_queue_props_print(ndo, cp, ep, desclen - OF_PACKET_QUEUE_LEN)))
13243c602fabSXin LI 			return ep; /* end of snapshot */
13253c602fabSXin LI next_queue:
13263c602fabSXin LI 		len -= desclen;
13273c602fabSXin LI 	} /* while */
13283c602fabSXin LI 	return cp;
13293c602fabSXin LI 
13303c602fabSXin LI corrupt: /* skip the rest of queues */
13313c602fabSXin LI 	ND_PRINT((ndo, "%s", cstr));
13323c602fabSXin LI 	ND_TCHECK2(*cp0, len0);
13333c602fabSXin LI 	return cp0 + len0;
13343c602fabSXin LI trunc:
13353c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
13363c602fabSXin LI 	return ep;
13373c602fabSXin LI }
13383c602fabSXin LI 
13393c602fabSXin LI /* [OF10] Section 5.2.3 */
13403c602fabSXin LI static const u_char *
13413c602fabSXin LI of10_match_print(netdissect_options *ndo,
1342*8bdc5a62SPatrick Kelsey                  const char *pfx, const u_char *cp, const u_char *ep)
1343*8bdc5a62SPatrick Kelsey {
13443c602fabSXin LI 	uint32_t wildcards;
13453c602fabSXin LI 	uint16_t dl_type;
13463c602fabSXin LI 	uint8_t nw_proto;
13473c602fabSXin LI 	u_char nw_bits;
13483c602fabSXin LI 	const char *field_name;
13493c602fabSXin LI 
13503c602fabSXin LI 	/* wildcards */
13513c602fabSXin LI 	ND_TCHECK2(*cp, 4);
13523c602fabSXin LI 	wildcards = EXTRACT_32BITS(cp);
13533c602fabSXin LI 	if (wildcards & OFPFW_U)
13543c602fabSXin LI 		ND_PRINT((ndo, "%swildcards 0x%08x (bogus)", pfx, wildcards));
13553c602fabSXin LI 	cp += 4;
13563c602fabSXin LI 	/* in_port */
13573c602fabSXin LI 	ND_TCHECK2(*cp, 2);
13583c602fabSXin LI 	if (! (wildcards & OFPFW_IN_PORT))
13593c602fabSXin LI 		ND_PRINT((ndo, "%smatch in_port %s", pfx, tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
13603c602fabSXin LI 	cp += 2;
13613c602fabSXin LI 	/* dl_src */
13623c602fabSXin LI 	ND_TCHECK2(*cp, ETHER_ADDR_LEN);
13633c602fabSXin LI 	if (! (wildcards & OFPFW_DL_SRC))
13643c602fabSXin LI 		ND_PRINT((ndo, "%smatch dl_src %s", pfx, etheraddr_string(ndo, cp)));
13653c602fabSXin LI 	cp += ETHER_ADDR_LEN;
13663c602fabSXin LI 	/* dl_dst */
13673c602fabSXin LI 	ND_TCHECK2(*cp, ETHER_ADDR_LEN);
13683c602fabSXin LI 	if (! (wildcards & OFPFW_DL_DST))
13693c602fabSXin LI 		ND_PRINT((ndo, "%smatch dl_dst %s", pfx, etheraddr_string(ndo, cp)));
13703c602fabSXin LI 	cp += ETHER_ADDR_LEN;
13713c602fabSXin LI 	/* dl_vlan */
13723c602fabSXin LI 	ND_TCHECK2(*cp, 2);
13733c602fabSXin LI 	if (! (wildcards & OFPFW_DL_VLAN))
13743c602fabSXin LI 		ND_PRINT((ndo, "%smatch dl_vlan %s", pfx, vlan_str(EXTRACT_16BITS(cp))));
13753c602fabSXin LI 	cp += 2;
13763c602fabSXin LI 	/* dl_vlan_pcp */
13773c602fabSXin LI 	ND_TCHECK2(*cp, 1);
13783c602fabSXin LI 	if (! (wildcards & OFPFW_DL_VLAN_PCP))
13793c602fabSXin LI 		ND_PRINT((ndo, "%smatch dl_vlan_pcp %s", pfx, pcp_str(*cp)));
13803c602fabSXin LI 	cp += 1;
13813c602fabSXin LI 	/* pad1 */
13823c602fabSXin LI 	ND_TCHECK2(*cp, 1);
13833c602fabSXin LI 	cp += 1;
13843c602fabSXin LI 	/* dl_type */
13853c602fabSXin LI 	ND_TCHECK2(*cp, 2);
13863c602fabSXin LI 	dl_type = EXTRACT_16BITS(cp);
13873c602fabSXin LI 	cp += 2;
13883c602fabSXin LI 	if (! (wildcards & OFPFW_DL_TYPE))
13893c602fabSXin LI 		ND_PRINT((ndo, "%smatch dl_type 0x%04x", pfx, dl_type));
13903c602fabSXin LI 	/* nw_tos */
13913c602fabSXin LI 	ND_TCHECK2(*cp, 1);
13923c602fabSXin LI 	if (! (wildcards & OFPFW_NW_TOS))
13933c602fabSXin LI 		ND_PRINT((ndo, "%smatch nw_tos 0x%02x", pfx, *cp));
13943c602fabSXin LI 	cp += 1;
13953c602fabSXin LI 	/* nw_proto */
13963c602fabSXin LI 	ND_TCHECK2(*cp, 1);
13973c602fabSXin LI 	nw_proto = *cp;
13983c602fabSXin LI 	cp += 1;
13993c602fabSXin LI 	if (! (wildcards & OFPFW_NW_PROTO)) {
14003c602fabSXin LI 		field_name = ! (wildcards & OFPFW_DL_TYPE) && dl_type == ETHERTYPE_ARP
14013c602fabSXin LI 		  ? "arp_opcode" : "nw_proto";
14023c602fabSXin LI 		ND_PRINT((ndo, "%smatch %s %u", pfx, field_name, nw_proto));
14033c602fabSXin LI 	}
14043c602fabSXin LI 	/* pad2 */
14053c602fabSXin LI 	ND_TCHECK2(*cp, 2);
14063c602fabSXin LI 	cp += 2;
14073c602fabSXin LI 	/* nw_src */
14083c602fabSXin LI 	ND_TCHECK2(*cp, 4);
14093c602fabSXin LI 	nw_bits = (wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT;
14103c602fabSXin LI 	if (nw_bits < 32)
14113c602fabSXin LI 		ND_PRINT((ndo, "%smatch nw_src %s/%u", pfx, ipaddr_string(ndo, cp), 32 - nw_bits));
14123c602fabSXin LI 	cp += 4;
14133c602fabSXin LI 	/* nw_dst */
14143c602fabSXin LI 	ND_TCHECK2(*cp, 4);
14153c602fabSXin LI 	nw_bits = (wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT;
14163c602fabSXin LI 	if (nw_bits < 32)
14173c602fabSXin LI 		ND_PRINT((ndo, "%smatch nw_dst %s/%u", pfx, ipaddr_string(ndo, cp), 32 - nw_bits));
14183c602fabSXin LI 	cp += 4;
14193c602fabSXin LI 	/* tp_src */
14203c602fabSXin LI 	ND_TCHECK2(*cp, 2);
14213c602fabSXin LI 	if (! (wildcards & OFPFW_TP_SRC)) {
14223c602fabSXin LI 		field_name = ! (wildcards & OFPFW_DL_TYPE) && dl_type == ETHERTYPE_IP
14233c602fabSXin LI 		  && ! (wildcards & OFPFW_NW_PROTO) && nw_proto == IPPROTO_ICMP
14243c602fabSXin LI 		  ? "icmp_type" : "tp_src";
14253c602fabSXin LI 		ND_PRINT((ndo, "%smatch %s %u", pfx, field_name, EXTRACT_16BITS(cp)));
14263c602fabSXin LI 	}
14273c602fabSXin LI 	cp += 2;
14283c602fabSXin LI 	/* tp_dst */
14293c602fabSXin LI 	ND_TCHECK2(*cp, 2);
14303c602fabSXin LI 	if (! (wildcards & OFPFW_TP_DST)) {
14313c602fabSXin LI 		field_name = ! (wildcards & OFPFW_DL_TYPE) && dl_type == ETHERTYPE_IP
14323c602fabSXin LI 		  && ! (wildcards & OFPFW_NW_PROTO) && nw_proto == IPPROTO_ICMP
14333c602fabSXin LI 		  ? "icmp_code" : "tp_dst";
14343c602fabSXin LI 		ND_PRINT((ndo, "%smatch %s %u", pfx, field_name, EXTRACT_16BITS(cp)));
14353c602fabSXin LI 	}
14363c602fabSXin LI 	return cp + 2;
14373c602fabSXin LI 
14383c602fabSXin LI trunc:
14393c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
14403c602fabSXin LI 	return ep;
14413c602fabSXin LI }
14423c602fabSXin LI 
14433c602fabSXin LI /* [OF10] Section 5.2.4 */
14443c602fabSXin LI static const u_char *
14453c602fabSXin LI of10_actions_print(netdissect_options *ndo,
14463c602fabSXin LI                    const char *pfx, const u_char *cp, const u_char *ep,
1447*8bdc5a62SPatrick Kelsey                    u_int len)
1448*8bdc5a62SPatrick Kelsey {
14493c602fabSXin LI 	const u_char *cp0 = cp;
14503c602fabSXin LI 	const u_int len0 = len;
14513c602fabSXin LI 	uint16_t type, alen, output_port;
14523c602fabSXin LI 
14533c602fabSXin LI 	while (len) {
14543c602fabSXin LI 		u_char alen_bogus = 0, skip = 0;
14553c602fabSXin LI 
14563c602fabSXin LI 		if (len < OF_ACTION_HEADER_LEN)
14573c602fabSXin LI 			goto corrupt;
14583c602fabSXin LI 		/* type */
14593c602fabSXin LI 		ND_TCHECK2(*cp, 2);
14603c602fabSXin LI 		type = EXTRACT_16BITS(cp);
14613c602fabSXin LI 		cp += 2;
14623c602fabSXin LI 		ND_PRINT((ndo, "%saction type %s", pfx, tok2str(ofpat_str, "invalid (0x%04x)", type)));
14633c602fabSXin LI 		/* length */
14643c602fabSXin LI 		ND_TCHECK2(*cp, 2);
14653c602fabSXin LI 		alen = EXTRACT_16BITS(cp);
14663c602fabSXin LI 		cp += 2;
14673c602fabSXin LI 		ND_PRINT((ndo, ", len %u", alen));
14683c602fabSXin LI 		/* On action size underrun/overrun skip the rest of the action list. */
14693c602fabSXin LI 		if (alen < OF_ACTION_HEADER_LEN || alen > len)
14703c602fabSXin LI 			goto corrupt;
14713c602fabSXin LI 		/* On action size inappropriate for the given type or invalid type just skip
14723c602fabSXin LI 		 * the current action, as the basic length constraint has been met. */
14733c602fabSXin LI 		switch (type) {
14743c602fabSXin LI 		case OFPAT_OUTPUT:
14753c602fabSXin LI 		case OFPAT_SET_VLAN_VID:
14763c602fabSXin LI 		case OFPAT_SET_VLAN_PCP:
14773c602fabSXin LI 		case OFPAT_STRIP_VLAN:
14783c602fabSXin LI 		case OFPAT_SET_NW_SRC:
14793c602fabSXin LI 		case OFPAT_SET_NW_DST:
14803c602fabSXin LI 		case OFPAT_SET_NW_TOS:
14813c602fabSXin LI 		case OFPAT_SET_TP_SRC:
14823c602fabSXin LI 		case OFPAT_SET_TP_DST:
14833c602fabSXin LI 			alen_bogus = alen != 8;
14843c602fabSXin LI 			break;
14853c602fabSXin LI 		case OFPAT_SET_DL_SRC:
14863c602fabSXin LI 		case OFPAT_SET_DL_DST:
14873c602fabSXin LI 		case OFPAT_ENQUEUE:
14883c602fabSXin LI 			alen_bogus = alen != 16;
14893c602fabSXin LI 			break;
14903c602fabSXin LI 		case OFPAT_VENDOR:
14913c602fabSXin LI 			alen_bogus = alen % 8 != 0; /* already >= 8 so far */
14923c602fabSXin LI 			break;
14933c602fabSXin LI 		default:
14943c602fabSXin LI 			skip = 1;
14953c602fabSXin LI 		}
14963c602fabSXin LI 		if (alen_bogus) {
14973c602fabSXin LI 			ND_PRINT((ndo, " (bogus)"));
14983c602fabSXin LI 			skip = 1;
14993c602fabSXin LI 		}
15003c602fabSXin LI 		if (skip) {
15013c602fabSXin LI 			ND_TCHECK2(*cp, alen - 4);
15023c602fabSXin LI 			cp += alen - 4;
15033c602fabSXin LI 			goto next_action;
15043c602fabSXin LI 		}
15053c602fabSXin LI 		/* OK to decode the rest of the action structure */
15063c602fabSXin LI 		switch (type) {
15073c602fabSXin LI 		case OFPAT_OUTPUT:
15083c602fabSXin LI 			/* port */
15093c602fabSXin LI 			ND_TCHECK2(*cp, 2);
15103c602fabSXin LI 			output_port = EXTRACT_16BITS(cp);
15113c602fabSXin LI 			cp += 2;
15123c602fabSXin LI 			ND_PRINT((ndo, ", port %s", tok2str(ofpp_str, "%u", output_port)));
15133c602fabSXin LI 			/* max_len */
15143c602fabSXin LI 			ND_TCHECK2(*cp, 2);
15153c602fabSXin LI 			if (output_port == OFPP_CONTROLLER)
15163c602fabSXin LI 				ND_PRINT((ndo, ", max_len %u", EXTRACT_16BITS(cp)));
15173c602fabSXin LI 			cp += 2;
15183c602fabSXin LI 			break;
15193c602fabSXin LI 		case OFPAT_SET_VLAN_VID:
15203c602fabSXin LI 			/* vlan_vid */
15213c602fabSXin LI 			ND_TCHECK2(*cp, 2);
15223c602fabSXin LI 			ND_PRINT((ndo, ", vlan_vid %s", vlan_str(EXTRACT_16BITS(cp))));
15233c602fabSXin LI 			cp += 2;
15243c602fabSXin LI 			/* pad */
15253c602fabSXin LI 			ND_TCHECK2(*cp, 2);
15263c602fabSXin LI 			cp += 2;
15273c602fabSXin LI 			break;
15283c602fabSXin LI 		case OFPAT_SET_VLAN_PCP:
15293c602fabSXin LI 			/* vlan_pcp */
15303c602fabSXin LI 			ND_TCHECK2(*cp, 1);
15313c602fabSXin LI 			ND_PRINT((ndo, ", vlan_pcp %s", pcp_str(*cp)));
15323c602fabSXin LI 			cp += 1;
15333c602fabSXin LI 			/* pad */
15343c602fabSXin LI 			ND_TCHECK2(*cp, 3);
15353c602fabSXin LI 			cp += 3;
15363c602fabSXin LI 			break;
15373c602fabSXin LI 		case OFPAT_SET_DL_SRC:
15383c602fabSXin LI 		case OFPAT_SET_DL_DST:
15393c602fabSXin LI 			/* dl_addr */
15403c602fabSXin LI 			ND_TCHECK2(*cp, ETHER_ADDR_LEN);
15413c602fabSXin LI 			ND_PRINT((ndo, ", dl_addr %s", etheraddr_string(ndo, cp)));
15423c602fabSXin LI 			cp += ETHER_ADDR_LEN;
15433c602fabSXin LI 			/* pad */
15443c602fabSXin LI 			ND_TCHECK2(*cp, 6);
15453c602fabSXin LI 			cp += 6;
15463c602fabSXin LI 			break;
15473c602fabSXin LI 		case OFPAT_SET_NW_SRC:
15483c602fabSXin LI 		case OFPAT_SET_NW_DST:
15493c602fabSXin LI 			/* nw_addr */
15503c602fabSXin LI 			ND_TCHECK2(*cp, 4);
15513c602fabSXin LI 			ND_PRINT((ndo, ", nw_addr %s", ipaddr_string(ndo, cp)));
15523c602fabSXin LI 			cp += 4;
15533c602fabSXin LI 			break;
15543c602fabSXin LI 		case OFPAT_SET_NW_TOS:
15553c602fabSXin LI 			/* nw_tos */
15563c602fabSXin LI 			ND_TCHECK2(*cp, 1);
15573c602fabSXin LI 			ND_PRINT((ndo, ", nw_tos 0x%02x", *cp));
15583c602fabSXin LI 			cp += 1;
15593c602fabSXin LI 			/* pad */
15603c602fabSXin LI 			ND_TCHECK2(*cp, 3);
15613c602fabSXin LI 			cp += 3;
15623c602fabSXin LI 			break;
15633c602fabSXin LI 		case OFPAT_SET_TP_SRC:
15643c602fabSXin LI 		case OFPAT_SET_TP_DST:
15653c602fabSXin LI 			/* nw_tos */
15663c602fabSXin LI 			ND_TCHECK2(*cp, 2);
15673c602fabSXin LI 			ND_PRINT((ndo, ", tp_port %u", EXTRACT_16BITS(cp)));
15683c602fabSXin LI 			cp += 2;
15693c602fabSXin LI 			/* pad */
15703c602fabSXin LI 			ND_TCHECK2(*cp, 2);
15713c602fabSXin LI 			cp += 2;
15723c602fabSXin LI 			break;
15733c602fabSXin LI 		case OFPAT_ENQUEUE:
15743c602fabSXin LI 			/* port */
15753c602fabSXin LI 			ND_TCHECK2(*cp, 2);
15763c602fabSXin LI 			ND_PRINT((ndo, ", port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
15773c602fabSXin LI 			cp += 2;
15783c602fabSXin LI 			/* pad */
15793c602fabSXin LI 			ND_TCHECK2(*cp, 6);
15803c602fabSXin LI 			cp += 6;
15813c602fabSXin LI 			/* queue_id */
15823c602fabSXin LI 			ND_TCHECK2(*cp, 4);
15833c602fabSXin LI 			ND_PRINT((ndo, ", queue_id %s", tok2str(ofpq_str, "%u", EXTRACT_32BITS(cp))));
15843c602fabSXin LI 			cp += 4;
15853c602fabSXin LI 			break;
15863c602fabSXin LI 		case OFPAT_VENDOR:
1587*8bdc5a62SPatrick Kelsey 			if (ep == (cp = of10_vendor_action_print(ndo, cp, ep, alen - 4)))
15883c602fabSXin LI 				return ep; /* end of snapshot */
15893c602fabSXin LI 			break;
15903c602fabSXin LI 		case OFPAT_STRIP_VLAN:
15913c602fabSXin LI 			/* pad */
15923c602fabSXin LI 			ND_TCHECK2(*cp, 4);
15933c602fabSXin LI 			cp += 4;
15943c602fabSXin LI 			break;
15953c602fabSXin LI 		} /* switch */
15963c602fabSXin LI next_action:
15973c602fabSXin LI 		len -= alen;
15983c602fabSXin LI 	} /* while */
15993c602fabSXin LI 	return cp;
16003c602fabSXin LI 
16013c602fabSXin LI corrupt: /* skip the rest of actions */
16023c602fabSXin LI 	ND_PRINT((ndo, "%s", cstr));
16033c602fabSXin LI 	ND_TCHECK2(*cp0, len0);
16043c602fabSXin LI 	return cp0 + len0;
16053c602fabSXin LI trunc:
16063c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
16073c602fabSXin LI 	return ep;
16083c602fabSXin LI }
16093c602fabSXin LI 
16103c602fabSXin LI /* [OF10] Section 5.3.1 */
16113c602fabSXin LI static const u_char *
16123c602fabSXin LI of10_features_reply_print(netdissect_options *ndo,
1613*8bdc5a62SPatrick Kelsey                           const u_char *cp, const u_char *ep, const u_int len)
1614*8bdc5a62SPatrick Kelsey {
16153c602fabSXin LI 	/* datapath_id */
16163c602fabSXin LI 	ND_TCHECK2(*cp, 8);
16173c602fabSXin LI 	ND_PRINT((ndo, "\n\t dpid 0x%016" PRIx64, EXTRACT_64BITS(cp)));
16183c602fabSXin LI 	cp += 8;
16193c602fabSXin LI 	/* n_buffers */
16203c602fabSXin LI 	ND_TCHECK2(*cp, 4);
16213c602fabSXin LI 	ND_PRINT((ndo, ", n_buffers %u", EXTRACT_32BITS(cp)));
16223c602fabSXin LI 	cp += 4;
16233c602fabSXin LI 	/* n_tables */
16243c602fabSXin LI 	ND_TCHECK2(*cp, 1);
16253c602fabSXin LI 	ND_PRINT((ndo, ", n_tables %u", *cp));
16263c602fabSXin LI 	cp += 1;
16273c602fabSXin LI 	/* pad */
16283c602fabSXin LI 	ND_TCHECK2(*cp, 3);
16293c602fabSXin LI 	cp += 3;
16303c602fabSXin LI 	/* capabilities */
16313c602fabSXin LI 	ND_TCHECK2(*cp, 4);
16323c602fabSXin LI 	ND_PRINT((ndo, "\n\t capabilities 0x%08x", EXTRACT_32BITS(cp)));
16333c602fabSXin LI 	of10_bitmap_print(ndo, ofp_capabilities_bm, EXTRACT_32BITS(cp), OFPCAP_U);
16343c602fabSXin LI 	cp += 4;
16353c602fabSXin LI 	/* actions */
16363c602fabSXin LI 	ND_TCHECK2(*cp, 4);
16373c602fabSXin LI 	ND_PRINT((ndo, "\n\t actions 0x%08x", EXTRACT_32BITS(cp)));
16383c602fabSXin LI 	of10_bitmap_print(ndo, ofpat_bm, EXTRACT_32BITS(cp), OFPAT_U);
16393c602fabSXin LI 	cp += 4;
16403c602fabSXin LI 	/* ports */
16413c602fabSXin LI 	return of10_phy_ports_print(ndo, cp, ep, len - OF_SWITCH_FEATURES_LEN);
16423c602fabSXin LI 
16433c602fabSXin LI trunc:
16443c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
16453c602fabSXin LI 	return ep;
16463c602fabSXin LI }
16473c602fabSXin LI 
16483c602fabSXin LI /* [OF10] Section 5.3.3 */
16493c602fabSXin LI static const u_char *
16503c602fabSXin LI of10_flow_mod_print(netdissect_options *ndo,
1651*8bdc5a62SPatrick Kelsey                     const u_char *cp, const u_char *ep, const u_int len)
1652*8bdc5a62SPatrick Kelsey {
16533c602fabSXin LI 	uint16_t command;
16543c602fabSXin LI 
16553c602fabSXin LI 	/* match */
16563c602fabSXin LI 	if (ep == (cp = of10_match_print(ndo, "\n\t ", cp, ep)))
16573c602fabSXin LI 		return ep; /* end of snapshot */
16583c602fabSXin LI 	/* cookie */
16593c602fabSXin LI 	ND_TCHECK2(*cp, 8);
16603c602fabSXin LI 	ND_PRINT((ndo, "\n\t cookie 0x%016" PRIx64, EXTRACT_64BITS(cp)));
16613c602fabSXin LI 	cp += 8;
16623c602fabSXin LI 	/* command */
16633c602fabSXin LI 	ND_TCHECK2(*cp, 2);
16643c602fabSXin LI 	command = EXTRACT_16BITS(cp);
16653c602fabSXin LI 	ND_PRINT((ndo, ", command %s", tok2str(ofpfc_str, "invalid (0x%04x)", command)));
16663c602fabSXin LI 	cp += 2;
16673c602fabSXin LI 	/* idle_timeout */
16683c602fabSXin LI 	ND_TCHECK2(*cp, 2);
16693c602fabSXin LI 	if (EXTRACT_16BITS(cp))
16703c602fabSXin LI 		ND_PRINT((ndo, ", idle_timeout %u", EXTRACT_16BITS(cp)));
16713c602fabSXin LI 	cp += 2;
16723c602fabSXin LI 	/* hard_timeout */
16733c602fabSXin LI 	ND_TCHECK2(*cp, 2);
16743c602fabSXin LI 	if (EXTRACT_16BITS(cp))
16753c602fabSXin LI 		ND_PRINT((ndo, ", hard_timeout %u", EXTRACT_16BITS(cp)));
16763c602fabSXin LI 	cp += 2;
16773c602fabSXin LI 	/* priority */
16783c602fabSXin LI 	ND_TCHECK2(*cp, 2);
16793c602fabSXin LI 	if (EXTRACT_16BITS(cp))
16803c602fabSXin LI 		ND_PRINT((ndo, ", priority %u", EXTRACT_16BITS(cp)));
16813c602fabSXin LI 	cp += 2;
16823c602fabSXin LI 	/* buffer_id */
16833c602fabSXin LI 	ND_TCHECK2(*cp, 4);
16843c602fabSXin LI 	if (command == OFPFC_ADD || command == OFPFC_MODIFY ||
16853c602fabSXin LI 	    command == OFPFC_MODIFY_STRICT)
16863c602fabSXin LI 		ND_PRINT((ndo, ", buffer_id %s", tok2str(bufferid_str, "0x%08x", EXTRACT_32BITS(cp))));
16873c602fabSXin LI 	cp += 4;
16883c602fabSXin LI 	/* out_port */
16893c602fabSXin LI 	ND_TCHECK2(*cp, 2);
16903c602fabSXin LI 	if (command == OFPFC_DELETE || command == OFPFC_DELETE_STRICT)
16913c602fabSXin LI 		ND_PRINT((ndo, ", out_port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
16923c602fabSXin LI 	cp += 2;
16933c602fabSXin LI 	/* flags */
16943c602fabSXin LI 	ND_TCHECK2(*cp, 2);
16953c602fabSXin LI 	ND_PRINT((ndo, ", flags 0x%04x", EXTRACT_16BITS(cp)));
16963c602fabSXin LI 	of10_bitmap_print(ndo, ofpff_bm, EXTRACT_16BITS(cp), OFPFF_U);
16973c602fabSXin LI 	cp += 2;
16983c602fabSXin LI 	/* actions */
16993c602fabSXin LI 	return of10_actions_print(ndo, "\n\t ", cp, ep, len - OF_FLOW_MOD_LEN);
17003c602fabSXin LI 
17013c602fabSXin LI trunc:
17023c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
17033c602fabSXin LI 	return ep;
17043c602fabSXin LI }
17053c602fabSXin LI 
17063c602fabSXin LI /* ibid */
17073c602fabSXin LI static const u_char *
17083c602fabSXin LI of10_port_mod_print(netdissect_options *ndo,
1709*8bdc5a62SPatrick Kelsey                     const u_char *cp, const u_char *ep)
1710*8bdc5a62SPatrick Kelsey {
17113c602fabSXin LI 	/* port_no */
17123c602fabSXin LI 	ND_TCHECK2(*cp, 2);
17133c602fabSXin LI 	ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
17143c602fabSXin LI 	cp += 2;
17153c602fabSXin LI 	/* hw_addr */
17163c602fabSXin LI 	ND_TCHECK2(*cp, ETHER_ADDR_LEN);
17173c602fabSXin LI 	ND_PRINT((ndo, ", hw_addr %s", etheraddr_string(ndo, cp)));
17183c602fabSXin LI 	cp += ETHER_ADDR_LEN;
17193c602fabSXin LI 	/* config */
17203c602fabSXin LI 	ND_TCHECK2(*cp, 4);
17213c602fabSXin LI 	ND_PRINT((ndo, "\n\t config 0x%08x", EXTRACT_32BITS(cp)));
17223c602fabSXin LI 	of10_bitmap_print(ndo, ofppc_bm, EXTRACT_32BITS(cp), OFPPC_U);
17233c602fabSXin LI 	cp += 4;
17243c602fabSXin LI 	/* mask */
17253c602fabSXin LI 	ND_TCHECK2(*cp, 4);
17263c602fabSXin LI 	ND_PRINT((ndo, "\n\t mask 0x%08x", EXTRACT_32BITS(cp)));
17273c602fabSXin LI 	of10_bitmap_print(ndo, ofppc_bm, EXTRACT_32BITS(cp), OFPPC_U);
17283c602fabSXin LI 	cp += 4;
17293c602fabSXin LI 	/* advertise */
17303c602fabSXin LI 	ND_TCHECK2(*cp, 4);
17313c602fabSXin LI 	ND_PRINT((ndo, "\n\t advertise 0x%08x", EXTRACT_32BITS(cp)));
17323c602fabSXin LI 	of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U);
17333c602fabSXin LI 	cp += 4;
17343c602fabSXin LI 	/* pad */
17353c602fabSXin LI 	ND_TCHECK2(*cp, 4);
17363c602fabSXin LI 	return cp + 4;
17373c602fabSXin LI 
17383c602fabSXin LI trunc:
17393c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
17403c602fabSXin LI 	return ep;
17413c602fabSXin LI }
17423c602fabSXin LI 
17433c602fabSXin LI /* [OF10] Section 5.3.5 */
17443c602fabSXin LI static const u_char *
17453c602fabSXin LI of10_stats_request_print(netdissect_options *ndo,
1746*8bdc5a62SPatrick Kelsey                          const u_char *cp, const u_char *ep, u_int len)
1747*8bdc5a62SPatrick Kelsey {
17483c602fabSXin LI 	const u_char *cp0 = cp;
17493c602fabSXin LI 	const u_int len0 = len;
17503c602fabSXin LI 	uint16_t type;
17513c602fabSXin LI 
17523c602fabSXin LI 	/* type */
17533c602fabSXin LI 	ND_TCHECK2(*cp, 2);
17543c602fabSXin LI 	type = EXTRACT_16BITS(cp);
17553c602fabSXin LI 	cp += 2;
17563c602fabSXin LI 	ND_PRINT((ndo, "\n\t type %s", tok2str(ofpst_str, "invalid (0x%04x)", type)));
17573c602fabSXin LI 	/* flags */
17583c602fabSXin LI 	ND_TCHECK2(*cp, 2);
17593c602fabSXin LI 	ND_PRINT((ndo, ", flags 0x%04x", EXTRACT_16BITS(cp)));
17603c602fabSXin LI 	if (EXTRACT_16BITS(cp))
17613c602fabSXin LI 		ND_PRINT((ndo, " (bogus)"));
17623c602fabSXin LI 	cp += 2;
17633c602fabSXin LI 	/* type-specific body of one of fixed lengths */
17643c602fabSXin LI 	len -= OF_STATS_REQUEST_LEN;
17653c602fabSXin LI 	switch(type) {
17663c602fabSXin LI 	case OFPST_DESC:
17673c602fabSXin LI 	case OFPST_TABLE:
17683c602fabSXin LI 		if (len)
17693c602fabSXin LI 			goto corrupt;
17703c602fabSXin LI 		return cp;
17713c602fabSXin LI 	case OFPST_FLOW:
17723c602fabSXin LI 	case OFPST_AGGREGATE:
17733c602fabSXin LI 		if (len != OF_FLOW_STATS_REQUEST_LEN)
17743c602fabSXin LI 			goto corrupt;
17753c602fabSXin LI 		/* match */
17763c602fabSXin LI 		if (ep == (cp = of10_match_print(ndo, "\n\t ", cp, ep)))
17773c602fabSXin LI 			return ep; /* end of snapshot */
17783c602fabSXin LI 		/* table_id */
17793c602fabSXin LI 		ND_TCHECK2(*cp, 1);
17803c602fabSXin LI 		ND_PRINT((ndo, "\n\t table_id %s", tok2str(tableid_str, "%u", *cp)));
17813c602fabSXin LI 		cp += 1;
17823c602fabSXin LI 		/* pad */
17833c602fabSXin LI 		ND_TCHECK2(*cp, 1);
17843c602fabSXin LI 		cp += 1;
17853c602fabSXin LI 		/* out_port */
17863c602fabSXin LI 		ND_TCHECK2(*cp, 2);
17873c602fabSXin LI 		ND_PRINT((ndo, ", out_port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
17883c602fabSXin LI 		return cp + 2;
17893c602fabSXin LI 	case OFPST_PORT:
17903c602fabSXin LI 		if (len != OF_PORT_STATS_REQUEST_LEN)
17913c602fabSXin LI 			goto corrupt;
17923c602fabSXin LI 		/* port_no */
17933c602fabSXin LI 		ND_TCHECK2(*cp, 2);
17943c602fabSXin LI 		ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
17953c602fabSXin LI 		cp += 2;
17963c602fabSXin LI 		/* pad */
17973c602fabSXin LI 		ND_TCHECK2(*cp, 6);
17983c602fabSXin LI 		return cp + 6;
17993c602fabSXin LI 	case OFPST_QUEUE:
18003c602fabSXin LI 		if (len != OF_QUEUE_STATS_REQUEST_LEN)
18013c602fabSXin LI 			goto corrupt;
18023c602fabSXin LI 		/* port_no */
18033c602fabSXin LI 		ND_TCHECK2(*cp, 2);
18043c602fabSXin LI 		ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
18053c602fabSXin LI 		cp += 2;
18063c602fabSXin LI 		/* pad */
18073c602fabSXin LI 		ND_TCHECK2(*cp, 2);
18083c602fabSXin LI 		cp += 2;
18093c602fabSXin LI 		/* queue_id */
18103c602fabSXin LI 		ND_TCHECK2(*cp, 4);
18113c602fabSXin LI 		ND_PRINT((ndo, ", queue_id %s", tok2str(ofpq_str, "%u", EXTRACT_32BITS(cp))));
18123c602fabSXin LI 		return cp + 4;
18133c602fabSXin LI 	case OFPST_VENDOR:
18143c602fabSXin LI 		return of10_vendor_data_print(ndo, cp, ep, len);
18153c602fabSXin LI 	}
18163c602fabSXin LI 	return cp;
18173c602fabSXin LI 
18183c602fabSXin LI corrupt: /* skip the message body */
18193c602fabSXin LI 	ND_PRINT((ndo, "%s", cstr));
18203c602fabSXin LI 	ND_TCHECK2(*cp0, len0);
18213c602fabSXin LI 	return cp0 + len0;
18223c602fabSXin LI trunc:
18233c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
18243c602fabSXin LI 	return ep;
18253c602fabSXin LI }
18263c602fabSXin LI 
18273c602fabSXin LI /* ibid */
18283c602fabSXin LI static const u_char *
18293c602fabSXin LI of10_desc_stats_reply_print(netdissect_options *ndo,
1830*8bdc5a62SPatrick Kelsey                             const u_char *cp, const u_char *ep, const u_int len)
1831*8bdc5a62SPatrick Kelsey {
18323c602fabSXin LI 	if (len != OF_DESC_STATS_LEN)
18333c602fabSXin LI 		goto corrupt;
18343c602fabSXin LI 	/* mfr_desc */
18353c602fabSXin LI 	ND_TCHECK2(*cp, DESC_STR_LEN);
18363c602fabSXin LI 	ND_PRINT((ndo, "\n\t  mfr_desc '"));
18373c602fabSXin LI 	fn_print(ndo, cp, cp + DESC_STR_LEN);
18383c602fabSXin LI 	ND_PRINT((ndo, "'"));
18393c602fabSXin LI 	cp += DESC_STR_LEN;
18403c602fabSXin LI 	/* hw_desc */
18413c602fabSXin LI 	ND_TCHECK2(*cp, DESC_STR_LEN);
18423c602fabSXin LI 	ND_PRINT((ndo, "\n\t  hw_desc '"));
18433c602fabSXin LI 	fn_print(ndo, cp, cp + DESC_STR_LEN);
18443c602fabSXin LI 	ND_PRINT((ndo, "'"));
18453c602fabSXin LI 	cp += DESC_STR_LEN;
18463c602fabSXin LI 	/* sw_desc */
18473c602fabSXin LI 	ND_TCHECK2(*cp, DESC_STR_LEN);
18483c602fabSXin LI 	ND_PRINT((ndo, "\n\t  sw_desc '"));
18493c602fabSXin LI 	fn_print(ndo, cp, cp + DESC_STR_LEN);
18503c602fabSXin LI 	ND_PRINT((ndo, "'"));
18513c602fabSXin LI 	cp += DESC_STR_LEN;
18523c602fabSXin LI 	/* serial_num */
18533c602fabSXin LI 	ND_TCHECK2(*cp, SERIAL_NUM_LEN);
18543c602fabSXin LI 	ND_PRINT((ndo, "\n\t  serial_num '"));
18553c602fabSXin LI 	fn_print(ndo, cp, cp + SERIAL_NUM_LEN);
18563c602fabSXin LI 	ND_PRINT((ndo, "'"));
18573c602fabSXin LI 	cp += SERIAL_NUM_LEN;
18583c602fabSXin LI 	/* dp_desc */
18593c602fabSXin LI 	ND_TCHECK2(*cp, DESC_STR_LEN);
18603c602fabSXin LI 	ND_PRINT((ndo, "\n\t  dp_desc '"));
18613c602fabSXin LI 	fn_print(ndo, cp, cp + DESC_STR_LEN);
18623c602fabSXin LI 	ND_PRINT((ndo, "'"));
18633c602fabSXin LI 	return cp + DESC_STR_LEN;
18643c602fabSXin LI 
18653c602fabSXin LI corrupt: /* skip the message body */
18663c602fabSXin LI 	ND_PRINT((ndo, "%s", cstr));
18673c602fabSXin LI 	ND_TCHECK2(*cp, len);
18683c602fabSXin LI 	return cp + len;
18693c602fabSXin LI trunc:
18703c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
18713c602fabSXin LI 	return ep;
18723c602fabSXin LI }
18733c602fabSXin LI 
18743c602fabSXin LI /* ibid */
18753c602fabSXin LI static const u_char *
18763c602fabSXin LI of10_flow_stats_reply_print(netdissect_options *ndo,
1877*8bdc5a62SPatrick Kelsey                             const u_char *cp, const u_char *ep, u_int len)
1878*8bdc5a62SPatrick Kelsey {
18793c602fabSXin LI 	const u_char *cp0 = cp;
18803c602fabSXin LI 	const u_int len0 = len;
18813c602fabSXin LI 	uint16_t entry_len;
18823c602fabSXin LI 
18833c602fabSXin LI 	while (len) {
18843c602fabSXin LI 		if (len < OF_FLOW_STATS_LEN)
18853c602fabSXin LI 			goto corrupt;
18863c602fabSXin LI 		/* length */
18873c602fabSXin LI 		ND_TCHECK2(*cp, 2);
18883c602fabSXin LI 		entry_len = EXTRACT_16BITS(cp);
18893c602fabSXin LI 		ND_PRINT((ndo, "\n\t length %u", entry_len));
18903c602fabSXin LI 		if (entry_len < OF_FLOW_STATS_LEN || entry_len > len)
18913c602fabSXin LI 			goto corrupt;
18923c602fabSXin LI 		cp += 2;
18933c602fabSXin LI 		/* table_id */
18943c602fabSXin LI 		ND_TCHECK2(*cp, 1);
18953c602fabSXin LI 		ND_PRINT((ndo, ", table_id %s", tok2str(tableid_str, "%u", *cp)));
18963c602fabSXin LI 		cp += 1;
18973c602fabSXin LI 		/* pad */
18983c602fabSXin LI 		ND_TCHECK2(*cp, 1);
18993c602fabSXin LI 		cp += 1;
19003c602fabSXin LI 		/* match */
19013c602fabSXin LI 		if (ep == (cp = of10_match_print(ndo, "\n\t  ", cp, ep)))
19023c602fabSXin LI 			return ep; /* end of snapshot */
19033c602fabSXin LI 		/* duration_sec */
19043c602fabSXin LI 		ND_TCHECK2(*cp, 4);
19053c602fabSXin LI 		ND_PRINT((ndo, "\n\t  duration_sec %u", EXTRACT_32BITS(cp)));
19063c602fabSXin LI 		cp += 4;
19073c602fabSXin LI 		/* duration_nsec */
19083c602fabSXin LI 		ND_TCHECK2(*cp, 4);
19093c602fabSXin LI 		ND_PRINT((ndo, ", duration_nsec %u", EXTRACT_32BITS(cp)));
19103c602fabSXin LI 		cp += 4;
19113c602fabSXin LI 		/* priority */
19123c602fabSXin LI 		ND_TCHECK2(*cp, 2);
19133c602fabSXin LI 		ND_PRINT((ndo, ", priority %u", EXTRACT_16BITS(cp)));
19143c602fabSXin LI 		cp += 2;
19153c602fabSXin LI 		/* idle_timeout */
19163c602fabSXin LI 		ND_TCHECK2(*cp, 2);
19173c602fabSXin LI 		ND_PRINT((ndo, ", idle_timeout %u", EXTRACT_16BITS(cp)));
19183c602fabSXin LI 		cp += 2;
19193c602fabSXin LI 		/* hard_timeout */
19203c602fabSXin LI 		ND_TCHECK2(*cp, 2);
19213c602fabSXin LI 		ND_PRINT((ndo, ", hard_timeout %u", EXTRACT_16BITS(cp)));
19223c602fabSXin LI 		cp += 2;
19233c602fabSXin LI 		/* pad2 */
19243c602fabSXin LI 		ND_TCHECK2(*cp, 6);
19253c602fabSXin LI 		cp += 6;
19263c602fabSXin LI 		/* cookie */
19273c602fabSXin LI 		ND_TCHECK2(*cp, 8);
19283c602fabSXin LI 		ND_PRINT((ndo, ", cookie 0x%016" PRIx64, EXTRACT_64BITS(cp)));
19293c602fabSXin LI 		cp += 8;
19303c602fabSXin LI 		/* packet_count */
19313c602fabSXin LI 		ND_TCHECK2(*cp, 8);
19323c602fabSXin LI 		ND_PRINT((ndo, ", packet_count %" PRIu64, EXTRACT_64BITS(cp)));
19333c602fabSXin LI 		cp += 8;
19343c602fabSXin LI 		/* byte_count */
19353c602fabSXin LI 		ND_TCHECK2(*cp, 8);
19363c602fabSXin LI 		ND_PRINT((ndo, ", byte_count %" PRIu64, EXTRACT_64BITS(cp)));
19373c602fabSXin LI 		cp += 8;
19383c602fabSXin LI 		/* actions */
19393c602fabSXin LI 		if (ep == (cp = of10_actions_print(ndo, "\n\t  ", cp, ep, entry_len - OF_FLOW_STATS_LEN)))
19403c602fabSXin LI 			return ep; /* end of snapshot */
19413c602fabSXin LI 
19423c602fabSXin LI 		len -= entry_len;
19433c602fabSXin LI 	} /* while */
19443c602fabSXin LI 	return cp;
19453c602fabSXin LI 
19463c602fabSXin LI corrupt: /* skip the rest of flow statistics entries */
19473c602fabSXin LI 	ND_PRINT((ndo, "%s", cstr));
19483c602fabSXin LI 	ND_TCHECK2(*cp0, len0);
19493c602fabSXin LI 	return cp0 + len0;
19503c602fabSXin LI trunc:
19513c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
19523c602fabSXin LI 	return ep;
19533c602fabSXin LI }
19543c602fabSXin LI 
19553c602fabSXin LI /* ibid */
19563c602fabSXin LI static const u_char *
19573c602fabSXin LI of10_aggregate_stats_reply_print(netdissect_options *ndo,
19583c602fabSXin LI                                  const u_char *cp, const u_char *ep,
1959*8bdc5a62SPatrick Kelsey                                  const u_int len)
1960*8bdc5a62SPatrick Kelsey {
19613c602fabSXin LI 	if (len != OF_AGGREGATE_STATS_REPLY_LEN)
19623c602fabSXin LI 		goto corrupt;
19633c602fabSXin LI 	/* packet_count */
19643c602fabSXin LI 	ND_TCHECK2(*cp, 8);
19653c602fabSXin LI 	ND_PRINT((ndo, "\n\t packet_count %" PRIu64, EXTRACT_64BITS(cp)));
19663c602fabSXin LI 	cp += 8;
19673c602fabSXin LI 	/* byte_count */
19683c602fabSXin LI 	ND_TCHECK2(*cp, 8);
19693c602fabSXin LI 	ND_PRINT((ndo, ", byte_count %" PRIu64, EXTRACT_64BITS(cp)));
19703c602fabSXin LI 	cp += 8;
19713c602fabSXin LI 	/* flow_count */
19723c602fabSXin LI 	ND_TCHECK2(*cp, 4);
19733c602fabSXin LI 	ND_PRINT((ndo, ", flow_count %u", EXTRACT_32BITS(cp)));
19743c602fabSXin LI 	cp += 4;
19753c602fabSXin LI 	/* pad */
19763c602fabSXin LI 	ND_TCHECK2(*cp, 4);
19773c602fabSXin LI 	return cp + 4;
19783c602fabSXin LI 
19793c602fabSXin LI corrupt: /* skip the message body */
19803c602fabSXin LI 	ND_PRINT((ndo, "%s", cstr));
19813c602fabSXin LI 	ND_TCHECK2(*cp, len);
19823c602fabSXin LI 	return cp + len;
19833c602fabSXin LI trunc:
19843c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
19853c602fabSXin LI 	return ep;
19863c602fabSXin LI }
19873c602fabSXin LI 
19883c602fabSXin LI /* ibid */
19893c602fabSXin LI static const u_char *
19903c602fabSXin LI of10_table_stats_reply_print(netdissect_options *ndo,
1991*8bdc5a62SPatrick Kelsey                              const u_char *cp, const u_char *ep, u_int len)
1992*8bdc5a62SPatrick Kelsey {
19933c602fabSXin LI 	const u_char *cp0 = cp;
19943c602fabSXin LI 	const u_int len0 = len;
19953c602fabSXin LI 
19963c602fabSXin LI 	while (len) {
19973c602fabSXin LI 		if (len < OF_TABLE_STATS_LEN)
19983c602fabSXin LI 			goto corrupt;
19993c602fabSXin LI 		/* table_id */
20003c602fabSXin LI 		ND_TCHECK2(*cp, 1);
20013c602fabSXin LI 		ND_PRINT((ndo, "\n\t table_id %s", tok2str(tableid_str, "%u", *cp)));
20023c602fabSXin LI 		cp += 1;
20033c602fabSXin LI 		/* pad */
20043c602fabSXin LI 		ND_TCHECK2(*cp, 3);
20053c602fabSXin LI 		cp += 3;
20063c602fabSXin LI 		/* name */
20073c602fabSXin LI 		ND_TCHECK2(*cp, OFP_MAX_TABLE_NAME_LEN);
20083c602fabSXin LI 		ND_PRINT((ndo, ", name '"));
20093c602fabSXin LI 		fn_print(ndo, cp, cp + OFP_MAX_TABLE_NAME_LEN);
20103c602fabSXin LI 		ND_PRINT((ndo, "'"));
20113c602fabSXin LI 		cp += OFP_MAX_TABLE_NAME_LEN;
20123c602fabSXin LI 		/* wildcards */
20133c602fabSXin LI 		ND_TCHECK2(*cp, 4);
20143c602fabSXin LI 		ND_PRINT((ndo, "\n\t  wildcards 0x%08x", EXTRACT_32BITS(cp)));
20153c602fabSXin LI 		of10_bitmap_print(ndo, ofpfw_bm, EXTRACT_32BITS(cp), OFPFW_U);
20163c602fabSXin LI 		cp += 4;
20173c602fabSXin LI 		/* max_entries */
20183c602fabSXin LI 		ND_TCHECK2(*cp, 4);
20193c602fabSXin LI 		ND_PRINT((ndo, "\n\t  max_entries %u", EXTRACT_32BITS(cp)));
20203c602fabSXin LI 		cp += 4;
20213c602fabSXin LI 		/* active_count */
20223c602fabSXin LI 		ND_TCHECK2(*cp, 4);
20233c602fabSXin LI 		ND_PRINT((ndo, ", active_count %u", EXTRACT_32BITS(cp)));
20243c602fabSXin LI 		cp += 4;
20253c602fabSXin LI 		/* lookup_count */
20263c602fabSXin LI 		ND_TCHECK2(*cp, 8);
20273c602fabSXin LI 		ND_PRINT((ndo, ", lookup_count %" PRIu64, EXTRACT_64BITS(cp)));
20283c602fabSXin LI 		cp += 8;
20293c602fabSXin LI 		/* matched_count */
20303c602fabSXin LI 		ND_TCHECK2(*cp, 8);
20313c602fabSXin LI 		ND_PRINT((ndo, ", matched_count %" PRIu64, EXTRACT_64BITS(cp)));
20323c602fabSXin LI 		cp += 8;
20333c602fabSXin LI 
20343c602fabSXin LI 		len -= OF_TABLE_STATS_LEN;
20353c602fabSXin LI 	} /* while */
20363c602fabSXin LI 	return cp;
20373c602fabSXin LI 
20383c602fabSXin LI corrupt: /* skip the undersized trailing data */
20393c602fabSXin LI 	ND_PRINT((ndo, "%s", cstr));
20403c602fabSXin LI 	ND_TCHECK2(*cp0, len0);
20413c602fabSXin LI 	return cp0 + len0;
20423c602fabSXin LI trunc:
20433c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
20443c602fabSXin LI 	return ep;
20453c602fabSXin LI }
20463c602fabSXin LI 
20473c602fabSXin LI /* ibid */
20483c602fabSXin LI static const u_char *
20493c602fabSXin LI of10_port_stats_reply_print(netdissect_options *ndo,
2050*8bdc5a62SPatrick Kelsey                             const u_char *cp, const u_char *ep, u_int len)
2051*8bdc5a62SPatrick Kelsey {
20523c602fabSXin LI 	const u_char *cp0 = cp;
20533c602fabSXin LI 	const u_int len0 = len;
20543c602fabSXin LI 
20553c602fabSXin LI 	while (len) {
20563c602fabSXin LI 		if (len < OF_PORT_STATS_LEN)
20573c602fabSXin LI 			goto corrupt;
20583c602fabSXin LI 		/* port_no */
20593c602fabSXin LI 		ND_TCHECK2(*cp, 2);
20603c602fabSXin LI 		ND_PRINT((ndo, "\n\t  port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
20613c602fabSXin LI 		cp += 2;
20623c602fabSXin LI 		if (ndo->ndo_vflag < 2) {
20633c602fabSXin LI 			ND_TCHECK2(*cp, OF_PORT_STATS_LEN - 2);
20643c602fabSXin LI 			cp += OF_PORT_STATS_LEN - 2;
20653c602fabSXin LI 			goto next_port;
20663c602fabSXin LI 		}
20673c602fabSXin LI 		/* pad */
20683c602fabSXin LI 		ND_TCHECK2(*cp, 6);
20693c602fabSXin LI 		cp += 6;
20703c602fabSXin LI 		/* rx_packets */
20713c602fabSXin LI 		ND_TCHECK2(*cp, 8);
20723c602fabSXin LI 		ND_PRINT((ndo, ", rx_packets %" PRIu64, EXTRACT_64BITS(cp)));
20733c602fabSXin LI 		cp += 8;
20743c602fabSXin LI 		/* tx_packets */
20753c602fabSXin LI 		ND_TCHECK2(*cp, 8);
20763c602fabSXin LI 		ND_PRINT((ndo, ", tx_packets %" PRIu64, EXTRACT_64BITS(cp)));
20773c602fabSXin LI 		cp += 8;
20783c602fabSXin LI 		/* rx_bytes */
20793c602fabSXin LI 		ND_TCHECK2(*cp, 8);
20803c602fabSXin LI 		ND_PRINT((ndo, ", rx_bytes %" PRIu64, EXTRACT_64BITS(cp)));
20813c602fabSXin LI 		cp += 8;
20823c602fabSXin LI 		/* tx_bytes */
20833c602fabSXin LI 		ND_TCHECK2(*cp, 8);
20843c602fabSXin LI 		ND_PRINT((ndo, ", tx_bytes %" PRIu64, EXTRACT_64BITS(cp)));
20853c602fabSXin LI 		cp += 8;
20863c602fabSXin LI 		/* rx_dropped */
20873c602fabSXin LI 		ND_TCHECK2(*cp, 8);
20883c602fabSXin LI 		ND_PRINT((ndo, ", rx_dropped %" PRIu64, EXTRACT_64BITS(cp)));
20893c602fabSXin LI 		cp += 8;
20903c602fabSXin LI 		/* tx_dropped */
20913c602fabSXin LI 		ND_TCHECK2(*cp, 8);
20923c602fabSXin LI 		ND_PRINT((ndo, ", tx_dropped %" PRIu64, EXTRACT_64BITS(cp)));
20933c602fabSXin LI 		cp += 8;
20943c602fabSXin LI 		/* rx_errors */
20953c602fabSXin LI 		ND_TCHECK2(*cp, 8);
20963c602fabSXin LI 		ND_PRINT((ndo, ", rx_errors %" PRIu64, EXTRACT_64BITS(cp)));
20973c602fabSXin LI 		cp += 8;
20983c602fabSXin LI 		/* tx_errors */
20993c602fabSXin LI 		ND_TCHECK2(*cp, 8);
21003c602fabSXin LI 		ND_PRINT((ndo, ", tx_errors %" PRIu64, EXTRACT_64BITS(cp)));
21013c602fabSXin LI 		cp += 8;
21023c602fabSXin LI 		/* rx_frame_err */
21033c602fabSXin LI 		ND_TCHECK2(*cp, 8);
21043c602fabSXin LI 		ND_PRINT((ndo, ", rx_frame_err %" PRIu64, EXTRACT_64BITS(cp)));
21053c602fabSXin LI 		cp += 8;
21063c602fabSXin LI 		/* rx_over_err */
21073c602fabSXin LI 		ND_TCHECK2(*cp, 8);
21083c602fabSXin LI 		ND_PRINT((ndo, ", rx_over_err %" PRIu64, EXTRACT_64BITS(cp)));
21093c602fabSXin LI 		cp += 8;
21103c602fabSXin LI 		/* rx_crc_err */
21113c602fabSXin LI 		ND_TCHECK2(*cp, 8);
21123c602fabSXin LI 		ND_PRINT((ndo, ", rx_crc_err %" PRIu64, EXTRACT_64BITS(cp)));
21133c602fabSXin LI 		cp += 8;
21143c602fabSXin LI 		/* collisions */
21153c602fabSXin LI 		ND_TCHECK2(*cp, 8);
21163c602fabSXin LI 		ND_PRINT((ndo, ", collisions %" PRIu64, EXTRACT_64BITS(cp)));
21173c602fabSXin LI 		cp += 8;
21183c602fabSXin LI next_port:
21193c602fabSXin LI 		len -= OF_PORT_STATS_LEN;
21203c602fabSXin LI 	} /* while */
21213c602fabSXin LI 	return cp;
21223c602fabSXin LI 
21233c602fabSXin LI corrupt: /* skip the undersized trailing data */
21243c602fabSXin LI 	ND_PRINT((ndo, "%s", cstr));
21253c602fabSXin LI 	ND_TCHECK2(*cp0, len0);
21263c602fabSXin LI 	return cp0 + len0;
21273c602fabSXin LI trunc:
21283c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
21293c602fabSXin LI 	return ep;
21303c602fabSXin LI }
21313c602fabSXin LI 
21323c602fabSXin LI /* ibid */
21333c602fabSXin LI static const u_char *
21343c602fabSXin LI of10_queue_stats_reply_print(netdissect_options *ndo,
2135*8bdc5a62SPatrick Kelsey                              const u_char *cp, const u_char *ep, u_int len)
2136*8bdc5a62SPatrick Kelsey {
21373c602fabSXin LI 	const u_char *cp0 = cp;
21383c602fabSXin LI 	const u_int len0 = len;
21393c602fabSXin LI 
21403c602fabSXin LI 	while (len) {
21413c602fabSXin LI 		if (len < OF_QUEUE_STATS_LEN)
21423c602fabSXin LI 			goto corrupt;
21433c602fabSXin LI 		/* port_no */
21443c602fabSXin LI 		ND_TCHECK2(*cp, 2);
21453c602fabSXin LI 		ND_PRINT((ndo, "\n\t  port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
21463c602fabSXin LI 		cp += 2;
21473c602fabSXin LI 		/* pad */
21483c602fabSXin LI 		ND_TCHECK2(*cp, 2);
21493c602fabSXin LI 		cp += 2;
21503c602fabSXin LI 		/* queue_id */
21513c602fabSXin LI 		ND_TCHECK2(*cp, 4);
21523c602fabSXin LI 		ND_PRINT((ndo, ", queue_id %u", EXTRACT_32BITS(cp)));
21533c602fabSXin LI 		cp += 4;
21543c602fabSXin LI 		/* tx_bytes */
21553c602fabSXin LI 		ND_TCHECK2(*cp, 8);
21563c602fabSXin LI 		ND_PRINT((ndo, ", tx_bytes %" PRIu64, EXTRACT_64BITS(cp)));
21573c602fabSXin LI 		cp += 8;
21583c602fabSXin LI 		/* tx_packets */
21593c602fabSXin LI 		ND_TCHECK2(*cp, 8);
21603c602fabSXin LI 		ND_PRINT((ndo, ", tx_packets %" PRIu64, EXTRACT_64BITS(cp)));
21613c602fabSXin LI 		cp += 8;
21623c602fabSXin LI 		/* tx_errors */
21633c602fabSXin LI 		ND_TCHECK2(*cp, 8);
21643c602fabSXin LI 		ND_PRINT((ndo, ", tx_errors %" PRIu64, EXTRACT_64BITS(cp)));
21653c602fabSXin LI 		cp += 8;
21663c602fabSXin LI 
21673c602fabSXin LI 		len -= OF_QUEUE_STATS_LEN;
21683c602fabSXin LI 	} /* while */
21693c602fabSXin LI 	return cp;
21703c602fabSXin LI 
21713c602fabSXin LI corrupt: /* skip the undersized trailing data */
21723c602fabSXin LI 	ND_PRINT((ndo, "%s", cstr));
21733c602fabSXin LI 	ND_TCHECK2(*cp0, len0);
21743c602fabSXin LI 	return cp0 + len0;
21753c602fabSXin LI trunc:
21763c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
21773c602fabSXin LI 	return ep;
21783c602fabSXin LI }
21793c602fabSXin LI 
21803c602fabSXin LI /* ibid */
21813c602fabSXin LI static const u_char *
21823c602fabSXin LI of10_stats_reply_print(netdissect_options *ndo,
2183*8bdc5a62SPatrick Kelsey                        const u_char *cp, const u_char *ep, const u_int len)
2184*8bdc5a62SPatrick Kelsey {
21853c602fabSXin LI 	const u_char *cp0 = cp;
21863c602fabSXin LI 	uint16_t type;
21873c602fabSXin LI 
21883c602fabSXin LI 	/* type */
21893c602fabSXin LI 	ND_TCHECK2(*cp, 2);
21903c602fabSXin LI 	type = EXTRACT_16BITS(cp);
21913c602fabSXin LI 	ND_PRINT((ndo, "\n\t type %s", tok2str(ofpst_str, "invalid (0x%04x)", type)));
21923c602fabSXin LI 	cp += 2;
21933c602fabSXin LI 	/* flags */
21943c602fabSXin LI 	ND_TCHECK2(*cp, 2);
21953c602fabSXin LI 	ND_PRINT((ndo, ", flags 0x%04x", EXTRACT_16BITS(cp)));
21963c602fabSXin LI 	of10_bitmap_print(ndo, ofpsf_reply_bm, EXTRACT_16BITS(cp), OFPSF_REPLY_U);
21973c602fabSXin LI 	cp += 2;
21983c602fabSXin LI 
21993c602fabSXin LI 	if (ndo->ndo_vflag > 0) {
22003c602fabSXin LI 		const u_char *(*decoder)(netdissect_options *, const u_char *, const u_char *, u_int) =
22013c602fabSXin LI 			type == OFPST_DESC      ? of10_desc_stats_reply_print      :
22023c602fabSXin LI 			type == OFPST_FLOW      ? of10_flow_stats_reply_print      :
22033c602fabSXin LI 			type == OFPST_AGGREGATE ? of10_aggregate_stats_reply_print :
22043c602fabSXin LI 			type == OFPST_TABLE     ? of10_table_stats_reply_print     :
22053c602fabSXin LI 			type == OFPST_PORT      ? of10_port_stats_reply_print      :
22063c602fabSXin LI 			type == OFPST_QUEUE     ? of10_queue_stats_reply_print     :
22073c602fabSXin LI 			type == OFPST_VENDOR    ? of10_vendor_data_print           :
22083c602fabSXin LI 			NULL;
22093c602fabSXin LI 		if (decoder != NULL)
22103c602fabSXin LI 			return decoder(ndo, cp, ep, len - OF_STATS_REPLY_LEN);
22113c602fabSXin LI 	}
22123c602fabSXin LI 	ND_TCHECK2(*cp0, len);
22133c602fabSXin LI 	return cp0 + len;
22143c602fabSXin LI 
22153c602fabSXin LI trunc:
22163c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
22173c602fabSXin LI 	return ep;
22183c602fabSXin LI }
22193c602fabSXin LI 
22203c602fabSXin LI /* [OF10] Section 5.3.6 */
22213c602fabSXin LI static const u_char *
22223c602fabSXin LI of10_packet_out_print(netdissect_options *ndo,
2223*8bdc5a62SPatrick Kelsey                       const u_char *cp, const u_char *ep, const u_int len)
2224*8bdc5a62SPatrick Kelsey {
22253c602fabSXin LI 	const u_char *cp0 = cp;
22263c602fabSXin LI 	const u_int len0 = len;
22273c602fabSXin LI 	uint16_t actions_len;
22283c602fabSXin LI 
22293c602fabSXin LI 	/* buffer_id */
22303c602fabSXin LI 	ND_TCHECK2(*cp, 4);
22313c602fabSXin LI 	ND_PRINT((ndo, "\n\t buffer_id 0x%08x", EXTRACT_32BITS(cp)));
22323c602fabSXin LI 	cp += 4;
22333c602fabSXin LI 	/* in_port */
22343c602fabSXin LI 	ND_TCHECK2(*cp, 2);
22353c602fabSXin LI 	ND_PRINT((ndo, ", in_port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
22363c602fabSXin LI 	cp += 2;
22373c602fabSXin LI 	/* actions_len */
22383c602fabSXin LI 	ND_TCHECK2(*cp, 2);
22393c602fabSXin LI 	actions_len = EXTRACT_16BITS(cp);
22403c602fabSXin LI 	cp += 2;
22413c602fabSXin LI 	if (actions_len > len - OF_PACKET_OUT_LEN)
22423c602fabSXin LI 		goto corrupt;
22433c602fabSXin LI 	/* actions */
22443c602fabSXin LI 	if (ep == (cp = of10_actions_print(ndo, "\n\t ", cp, ep, actions_len)))
22453c602fabSXin LI 		return ep; /* end of snapshot */
22463c602fabSXin LI 	/* data */
22473c602fabSXin LI 	return of10_packet_data_print(ndo, cp, ep, len - OF_PACKET_OUT_LEN - actions_len);
22483c602fabSXin LI 
22493c602fabSXin LI corrupt: /* skip the rest of the message body */
22503c602fabSXin LI 	ND_PRINT((ndo, "%s", cstr));
22513c602fabSXin LI 	ND_TCHECK2(*cp0, len0);
22523c602fabSXin LI 	return cp0 + len0;
22533c602fabSXin LI trunc:
22543c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
22553c602fabSXin LI 	return ep;
22563c602fabSXin LI }
22573c602fabSXin LI 
22583c602fabSXin LI /* [OF10] Section 5.4.1 */
22593c602fabSXin LI static const u_char *
22603c602fabSXin LI of10_packet_in_print(netdissect_options *ndo,
2261*8bdc5a62SPatrick Kelsey                      const u_char *cp, const u_char *ep, const u_int len)
2262*8bdc5a62SPatrick Kelsey {
22633c602fabSXin LI 	/* buffer_id */
22643c602fabSXin LI 	ND_TCHECK2(*cp, 4);
22653c602fabSXin LI 	ND_PRINT((ndo, "\n\t buffer_id %s", tok2str(bufferid_str, "0x%08x", EXTRACT_32BITS(cp))));
22663c602fabSXin LI 	cp += 4;
22673c602fabSXin LI 	/* total_len */
22683c602fabSXin LI 	ND_TCHECK2(*cp, 2);
22693c602fabSXin LI 	ND_PRINT((ndo, ", total_len %u", EXTRACT_16BITS(cp)));
22703c602fabSXin LI 	cp += 2;
22713c602fabSXin LI 	/* in_port */
22723c602fabSXin LI 	ND_TCHECK2(*cp, 2);
22733c602fabSXin LI 	ND_PRINT((ndo, ", in_port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
22743c602fabSXin LI 	cp += 2;
22753c602fabSXin LI 	/* reason */
22763c602fabSXin LI 	ND_TCHECK2(*cp, 1);
22773c602fabSXin LI 	ND_PRINT((ndo, ", reason %s", tok2str(ofpr_str, "invalid (0x%02x)", *cp)));
22783c602fabSXin LI 	cp += 1;
22793c602fabSXin LI 	/* pad */
22803c602fabSXin LI 	ND_TCHECK2(*cp, 1);
22813c602fabSXin LI 	cp += 1;
22823c602fabSXin LI 	/* data */
22833c602fabSXin LI 	/* 2 mock octets count in OF_PACKET_IN_LEN but not in len */
22843c602fabSXin LI 	return of10_packet_data_print(ndo, cp, ep, len - (OF_PACKET_IN_LEN - 2));
22853c602fabSXin LI 
22863c602fabSXin LI trunc:
22873c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
22883c602fabSXin LI 	return ep;
22893c602fabSXin LI }
22903c602fabSXin LI 
22913c602fabSXin LI /* [OF10] Section 5.4.2 */
22923c602fabSXin LI static const u_char *
22933c602fabSXin LI of10_flow_removed_print(netdissect_options *ndo,
2294*8bdc5a62SPatrick Kelsey                         const u_char *cp, const u_char *ep)
2295*8bdc5a62SPatrick Kelsey {
22963c602fabSXin LI 	/* match */
22973c602fabSXin LI 	if (ep == (cp = of10_match_print(ndo, "\n\t ", cp, ep)))
22983c602fabSXin LI 		return ep; /* end of snapshot */
22993c602fabSXin LI 	/* cookie */
23003c602fabSXin LI 	ND_TCHECK2(*cp, 8);
23013c602fabSXin LI 	ND_PRINT((ndo, "\n\t cookie 0x%016" PRIx64, EXTRACT_64BITS(cp)));
23023c602fabSXin LI 	cp += 8;
23033c602fabSXin LI 	/* priority */
23043c602fabSXin LI 	ND_TCHECK2(*cp, 2);
23053c602fabSXin LI 	if (EXTRACT_16BITS(cp))
23063c602fabSXin LI 		ND_PRINT((ndo, ", priority %u", EXTRACT_16BITS(cp)));
23073c602fabSXin LI 	cp += 2;
23083c602fabSXin LI 	/* reason */
23093c602fabSXin LI 	ND_TCHECK2(*cp, 1);
23103c602fabSXin LI 	ND_PRINT((ndo, ", reason %s", tok2str(ofprr_str, "unknown (0x%02x)", *cp)));
23113c602fabSXin LI 	cp += 1;
23123c602fabSXin LI 	/* pad */
23133c602fabSXin LI 	ND_TCHECK2(*cp, 1);
23143c602fabSXin LI 	cp += 1;
23153c602fabSXin LI 	/* duration_sec */
23163c602fabSXin LI 	ND_TCHECK2(*cp, 4);
23173c602fabSXin LI 	ND_PRINT((ndo, ", duration_sec %u", EXTRACT_32BITS(cp)));
23183c602fabSXin LI 	cp += 4;
23193c602fabSXin LI 	/* duration_nsec */
23203c602fabSXin LI 	ND_TCHECK2(*cp, 4);
23213c602fabSXin LI 	ND_PRINT((ndo, ", duration_nsec %u", EXTRACT_32BITS(cp)));
23223c602fabSXin LI 	cp += 4;
23233c602fabSXin LI 	/* idle_timeout */
23243c602fabSXin LI 	ND_TCHECK2(*cp, 2);
23253c602fabSXin LI 	if (EXTRACT_16BITS(cp))
23263c602fabSXin LI 		ND_PRINT((ndo, ", idle_timeout %u", EXTRACT_16BITS(cp)));
23273c602fabSXin LI 	cp += 2;
23283c602fabSXin LI 	/* pad2 */
23293c602fabSXin LI 	ND_TCHECK2(*cp, 2);
23303c602fabSXin LI 	cp += 2;
23313c602fabSXin LI 	/* packet_count */
23323c602fabSXin LI 	ND_TCHECK2(*cp, 8);
23333c602fabSXin LI 	ND_PRINT((ndo, ", packet_count %" PRIu64, EXTRACT_64BITS(cp)));
23343c602fabSXin LI 	cp += 8;
23353c602fabSXin LI 	/* byte_count */
23363c602fabSXin LI 	ND_TCHECK2(*cp, 8);
23373c602fabSXin LI 	ND_PRINT((ndo, ", byte_count %" PRIu64, EXTRACT_64BITS(cp)));
23383c602fabSXin LI 	return cp + 8;
23393c602fabSXin LI 
23403c602fabSXin LI trunc:
23413c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
23423c602fabSXin LI 	return ep;
23433c602fabSXin LI }
23443c602fabSXin LI 
23453c602fabSXin LI /* [OF10] Section 5.4.4 */
23463c602fabSXin LI static const u_char *
23473c602fabSXin LI of10_error_print(netdissect_options *ndo,
2348*8bdc5a62SPatrick Kelsey                  const u_char *cp, const u_char *ep, const u_int len)
2349*8bdc5a62SPatrick Kelsey {
23503c602fabSXin LI 	uint16_t type;
23513c602fabSXin LI 	const struct tok *code_str;
23523c602fabSXin LI 
23533c602fabSXin LI 	/* type */
23543c602fabSXin LI 	ND_TCHECK2(*cp, 2);
23553c602fabSXin LI 	type = EXTRACT_16BITS(cp);
23563c602fabSXin LI 	cp += 2;
23573c602fabSXin LI 	ND_PRINT((ndo, "\n\t type %s", tok2str(ofpet_str, "invalid (0x%04x)", type)));
23583c602fabSXin LI 	/* code */
23593c602fabSXin LI 	ND_TCHECK2(*cp, 2);
23603c602fabSXin LI 	code_str =
23613c602fabSXin LI 		type == OFPET_HELLO_FAILED    ? ofphfc_str  :
23623c602fabSXin LI 		type == OFPET_BAD_REQUEST     ? ofpbrc_str  :
23633c602fabSXin LI 		type == OFPET_BAD_ACTION      ? ofpbac_str  :
23643c602fabSXin LI 		type == OFPET_FLOW_MOD_FAILED ? ofpfmfc_str :
23653c602fabSXin LI 		type == OFPET_PORT_MOD_FAILED ? ofppmfc_str :
23663c602fabSXin LI 		type == OFPET_QUEUE_OP_FAILED ? ofpqofc_str :
23673c602fabSXin LI 		empty_str;
23683c602fabSXin LI 	ND_PRINT((ndo, ", code %s", tok2str(code_str, "invalid (0x%04x)", EXTRACT_16BITS(cp))));
23693c602fabSXin LI 	cp += 2;
23703c602fabSXin LI 	/* data */
23713c602fabSXin LI 	return of10_data_print(ndo, cp, ep, len - OF_ERROR_MSG_LEN);
23723c602fabSXin LI 
23733c602fabSXin LI trunc:
23743c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
23753c602fabSXin LI 	return ep;
23763c602fabSXin LI }
23773c602fabSXin LI 
23783c602fabSXin LI const u_char *
23793c602fabSXin LI of10_header_body_print(netdissect_options *ndo,
23803c602fabSXin LI                        const u_char *cp, const u_char *ep, const uint8_t type,
2381*8bdc5a62SPatrick Kelsey                        const uint16_t len, const uint32_t xid)
2382*8bdc5a62SPatrick Kelsey {
23833c602fabSXin LI 	const u_char *cp0 = cp;
23843c602fabSXin LI 	const u_int len0 = len;
23853c602fabSXin LI 	/* Thus far message length is not less than the basic header size, but most
23863c602fabSXin LI 	 * message types have additional assorted constraints on the length. Wherever
23873c602fabSXin LI 	 * possible, check that message length meets the constraint, in remaining
23883c602fabSXin LI 	 * cases check that the length is OK to begin decoding and leave any final
23893c602fabSXin LI 	 * verification up to a lower-layer function. When the current message is
23903c602fabSXin LI 	 * corrupt, proceed to the next message. */
23913c602fabSXin LI 
23923c602fabSXin LI 	/* [OF10] Section 5.1 */
23933c602fabSXin LI 	ND_PRINT((ndo, "\n\tversion 1.0, type %s, length %u, xid 0x%08x",
23943c602fabSXin LI 	       tok2str(ofpt_str, "invalid (0x%02x)", type), len, xid));
23953c602fabSXin LI 	switch (type) {
23963c602fabSXin LI 	/* OpenFlow header only. */
23973c602fabSXin LI 	case OFPT_FEATURES_REQUEST: /* [OF10] Section 5.3.1 */
23983c602fabSXin LI 	case OFPT_GET_CONFIG_REQUEST: /* [OF10] Section 5.3.2 */
23993c602fabSXin LI 	case OFPT_BARRIER_REQUEST: /* [OF10] Section 5.3.7 */
24003c602fabSXin LI 	case OFPT_BARRIER_REPLY: /* ibid */
24013c602fabSXin LI 		if (len != OF_HEADER_LEN)
24023c602fabSXin LI 			goto corrupt;
24033c602fabSXin LI 		break;
24043c602fabSXin LI 
24053c602fabSXin LI 	/* OpenFlow header and fixed-size message body. */
24063c602fabSXin LI 	case OFPT_SET_CONFIG: /* [OF10] Section 5.3.2 */
24073c602fabSXin LI 	case OFPT_GET_CONFIG_REPLY: /* ibid */
24083c602fabSXin LI 		if (len != OF_SWITCH_CONFIG_LEN)
24093c602fabSXin LI 			goto corrupt;
24103c602fabSXin LI 		if (ndo->ndo_vflag < 1)
24113c602fabSXin LI 			goto next_message;
24123c602fabSXin LI 		/* flags */
24133c602fabSXin LI 		ND_TCHECK2(*cp, 2);
24143c602fabSXin LI 		ND_PRINT((ndo, "\n\t flags %s", tok2str(ofp_config_str, "invalid (0x%04x)", EXTRACT_16BITS(cp))));
24153c602fabSXin LI 		cp += 2;
24163c602fabSXin LI 		/* miss_send_len */
24173c602fabSXin LI 		ND_TCHECK2(*cp, 2);
24183c602fabSXin LI 		ND_PRINT((ndo, ", miss_send_len %u", EXTRACT_16BITS(cp)));
24193c602fabSXin LI 		return cp + 2;
24203c602fabSXin LI 	case OFPT_PORT_MOD:
24213c602fabSXin LI 		if (len != OF_PORT_MOD_LEN)
24223c602fabSXin LI 			goto corrupt;
24233c602fabSXin LI 		if (ndo->ndo_vflag < 1)
24243c602fabSXin LI 			goto next_message;
24253c602fabSXin LI 		return of10_port_mod_print(ndo, cp, ep);
24263c602fabSXin LI 	case OFPT_QUEUE_GET_CONFIG_REQUEST: /* [OF10] Section 5.3.4 */
24273c602fabSXin LI 		if (len != OF_QUEUE_GET_CONFIG_REQUEST_LEN)
24283c602fabSXin LI 			goto corrupt;
24293c602fabSXin LI 		if (ndo->ndo_vflag < 1)
24303c602fabSXin LI 			goto next_message;
24313c602fabSXin LI 		/* port */
24323c602fabSXin LI 		ND_TCHECK2(*cp, 2);
24333c602fabSXin LI 		ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
24343c602fabSXin LI 		cp += 2;
24353c602fabSXin LI 		/* pad */
24363c602fabSXin LI 		ND_TCHECK2(*cp, 2);
24373c602fabSXin LI 		return cp + 2;
24383c602fabSXin LI 	case OFPT_FLOW_REMOVED:
24393c602fabSXin LI 		if (len != OF_FLOW_REMOVED_LEN)
24403c602fabSXin LI 			goto corrupt;
24413c602fabSXin LI 		if (ndo->ndo_vflag < 1)
24423c602fabSXin LI 			goto next_message;
24433c602fabSXin LI 		return of10_flow_removed_print(ndo, cp, ep);
24443c602fabSXin LI 	case OFPT_PORT_STATUS: /* [OF10] Section 5.4.3 */
24453c602fabSXin LI 		if (len != OF_PORT_STATUS_LEN)
24463c602fabSXin LI 			goto corrupt;
24473c602fabSXin LI 		if (ndo->ndo_vflag < 1)
24483c602fabSXin LI 			goto next_message;
24493c602fabSXin LI 		/* reason */
24503c602fabSXin LI 		ND_TCHECK2(*cp, 1);
24513c602fabSXin LI 		ND_PRINT((ndo, "\n\t reason %s", tok2str(ofppr_str, "invalid (0x%02x)", *cp)));
24523c602fabSXin LI 		cp += 1;
24533c602fabSXin LI 		/* pad */
24543c602fabSXin LI 		ND_TCHECK2(*cp, 7);
24553c602fabSXin LI 		cp += 7;
24563c602fabSXin LI 		/* desc */
24573c602fabSXin LI 		return of10_phy_ports_print(ndo, cp, ep, OF_PHY_PORT_LEN);
24583c602fabSXin LI 
24593c602fabSXin LI 	/* OpenFlow header, fixed-size message body and n * fixed-size data units. */
24603c602fabSXin LI 	case OFPT_FEATURES_REPLY:
24613c602fabSXin LI 		if (len < OF_SWITCH_FEATURES_LEN)
24623c602fabSXin LI 			goto corrupt;
24633c602fabSXin LI 		if (ndo->ndo_vflag < 1)
24643c602fabSXin LI 			goto next_message;
24653c602fabSXin LI 		return of10_features_reply_print(ndo, cp, ep, len);
24663c602fabSXin LI 
24673c602fabSXin LI 	/* OpenFlow header and variable-size data. */
24683c602fabSXin LI 	case OFPT_HELLO: /* [OF10] Section 5.5.1 */
24693c602fabSXin LI 	case OFPT_ECHO_REQUEST: /* [OF10] Section 5.5.2 */
24703c602fabSXin LI 	case OFPT_ECHO_REPLY: /* [OF10] Section 5.5.3 */
24713c602fabSXin LI 		if (ndo->ndo_vflag < 1)
24723c602fabSXin LI 			goto next_message;
24733c602fabSXin LI 		return of10_data_print(ndo, cp, ep, len - OF_HEADER_LEN);
24743c602fabSXin LI 
24753c602fabSXin LI 	/* OpenFlow header, fixed-size message body and variable-size data. */
24763c602fabSXin LI 	case OFPT_ERROR:
24773c602fabSXin LI 		if (len < OF_ERROR_MSG_LEN)
24783c602fabSXin LI 			goto corrupt;
24793c602fabSXin LI 		if (ndo->ndo_vflag < 1)
24803c602fabSXin LI 			goto next_message;
24813c602fabSXin LI 		return of10_error_print(ndo, cp, ep, len);
24823c602fabSXin LI 	case OFPT_VENDOR:
24833c602fabSXin LI 	  /* [OF10] Section 5.5.4 */
24843c602fabSXin LI 		if (len < OF_VENDOR_HEADER_LEN)
24853c602fabSXin LI 			goto corrupt;
24863c602fabSXin LI 		if (ndo->ndo_vflag < 1)
24873c602fabSXin LI 			goto next_message;
2488*8bdc5a62SPatrick Kelsey 		return of10_vendor_message_print(ndo, cp, ep, len - OF_HEADER_LEN);
24893c602fabSXin LI 	case OFPT_PACKET_IN:
24903c602fabSXin LI 		/* 2 mock octets count in OF_PACKET_IN_LEN but not in len */
24913c602fabSXin LI 		if (len < OF_PACKET_IN_LEN - 2)
24923c602fabSXin LI 			goto corrupt;
24933c602fabSXin LI 		if (ndo->ndo_vflag < 1)
24943c602fabSXin LI 			goto next_message;
24953c602fabSXin LI 		return of10_packet_in_print(ndo, cp, ep, len);
24963c602fabSXin LI 
24973c602fabSXin LI 	/* a. OpenFlow header. */
24983c602fabSXin LI 	/* b. OpenFlow header and one of the fixed-size message bodies. */
24993c602fabSXin LI 	/* c. OpenFlow header, fixed-size message body and variable-size data. */
25003c602fabSXin LI 	case OFPT_STATS_REQUEST:
25013c602fabSXin LI 		if (len < OF_STATS_REQUEST_LEN)
25023c602fabSXin LI 			goto corrupt;
25033c602fabSXin LI 		if (ndo->ndo_vflag < 1)
25043c602fabSXin LI 			goto next_message;
25053c602fabSXin LI 		return of10_stats_request_print(ndo, cp, ep, len);
25063c602fabSXin LI 
25073c602fabSXin LI 	/* a. OpenFlow header and fixed-size message body. */
25083c602fabSXin LI 	/* b. OpenFlow header and n * fixed-size data units. */
25093c602fabSXin LI 	/* c. OpenFlow header and n * variable-size data units. */
25103c602fabSXin LI 	/* d. OpenFlow header, fixed-size message body and variable-size data. */
25113c602fabSXin LI 	case OFPT_STATS_REPLY:
25123c602fabSXin LI 		if (len < OF_STATS_REPLY_LEN)
25133c602fabSXin LI 			goto corrupt;
25143c602fabSXin LI 		if (ndo->ndo_vflag < 1)
25153c602fabSXin LI 			goto next_message;
25163c602fabSXin LI 		return of10_stats_reply_print(ndo, cp, ep, len);
25173c602fabSXin LI 
25183c602fabSXin LI 	/* OpenFlow header and n * variable-size data units and variable-size data. */
25193c602fabSXin LI 	case OFPT_PACKET_OUT:
25203c602fabSXin LI 		if (len < OF_PACKET_OUT_LEN)
25213c602fabSXin LI 			goto corrupt;
25223c602fabSXin LI 		if (ndo->ndo_vflag < 1)
25233c602fabSXin LI 			goto next_message;
25243c602fabSXin LI 		return of10_packet_out_print(ndo, cp, ep, len);
25253c602fabSXin LI 
25263c602fabSXin LI 	/* OpenFlow header, fixed-size message body and n * variable-size data units. */
25273c602fabSXin LI 	case OFPT_FLOW_MOD:
25283c602fabSXin LI 		if (len < OF_FLOW_MOD_LEN)
25293c602fabSXin LI 			goto corrupt;
25303c602fabSXin LI 		if (ndo->ndo_vflag < 1)
25313c602fabSXin LI 			goto next_message;
25323c602fabSXin LI 		return of10_flow_mod_print(ndo, cp, ep, len);
25333c602fabSXin LI 
25343c602fabSXin LI 	/* OpenFlow header, fixed-size message body and n * variable-size data units. */
25353c602fabSXin LI 	case OFPT_QUEUE_GET_CONFIG_REPLY: /* [OF10] Section 5.3.4 */
25363c602fabSXin LI 		if (len < OF_QUEUE_GET_CONFIG_REPLY_LEN)
25373c602fabSXin LI 			goto corrupt;
25383c602fabSXin LI 		if (ndo->ndo_vflag < 1)
25393c602fabSXin LI 			goto next_message;
25403c602fabSXin LI 		/* port */
25413c602fabSXin LI 		ND_TCHECK2(*cp, 2);
25423c602fabSXin LI 		ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
25433c602fabSXin LI 		cp += 2;
25443c602fabSXin LI 		/* pad */
25453c602fabSXin LI 		ND_TCHECK2(*cp, 6);
25463c602fabSXin LI 		cp += 6;
25473c602fabSXin LI 		/* queues */
25483c602fabSXin LI 		return of10_queues_print(ndo, cp, ep, len - OF_QUEUE_GET_CONFIG_REPLY_LEN);
25493c602fabSXin LI 	} /* switch (type) */
25503c602fabSXin LI 	goto next_message;
25513c602fabSXin LI 
25523c602fabSXin LI corrupt: /* skip the message body */
25533c602fabSXin LI 	ND_PRINT((ndo, "%s", cstr));
25543c602fabSXin LI next_message:
25553c602fabSXin LI 	ND_TCHECK2(*cp0, len0 - OF_HEADER_LEN);
25563c602fabSXin LI 	return cp0 + len0 - OF_HEADER_LEN;
25573c602fabSXin LI trunc:
25583c602fabSXin LI 	ND_PRINT((ndo, "%s", tstr));
25593c602fabSXin LI 	return ep;
25603c602fabSXin LI }
2561