1026d7285Schristos /* 2026d7285Schristos * This module implements decoding of OpenFlow protocol version 1.0 (wire 3026d7285Schristos * protocol 0x01). The decoder implements terse (default), detailed (-v) and 4026d7285Schristos * full (-vv) output formats and, as much as each format implies, detects and 5026d7285Schristos * tries to work around sizing anomalies inside the messages. The decoder marks 6026d7285Schristos * up bogus values of selected message fields and decodes partially captured 7026d7285Schristos * messages up to the snapshot end. It is based on the specification below: 8026d7285Schristos * 9026d7285Schristos * [OF10] http://www.openflow.org/documents/openflow-spec-v1.0.0.pdf 10026d7285Schristos * 11*3d25ea14Schristos * Most functions in this file take 3 arguments into account: 12*3d25ea14Schristos * * cp -- the pointer to the first octet to decode 13*3d25ea14Schristos * * len -- the length of the current structure as declared on the wire 14*3d25ea14Schristos * * ep -- the pointer to the end of the captured frame 15*3d25ea14Schristos * They return either the pointer to the next not-yet-decoded part of the frame 16*3d25ea14Schristos * or the value of ep, which means the current frame processing is over as it 17*3d25ea14Schristos * has been fully decoded or is malformed or truncated. This way it is possible 18*3d25ea14Schristos * to chain and nest such functions uniformly to decode an OF1.0 message, which 19*3d25ea14Schristos * consists of several layers of nested structures. 20*3d25ea14Schristos * 21026d7285Schristos * Decoding of Ethernet frames nested in OFPT_PACKET_IN and OFPT_PACKET_OUT 22026d7285Schristos * messages is done only when the verbosity level set by command-line argument 23026d7285Schristos * is "-vvv" or higher. In that case the verbosity level is temporarily 24026d7285Schristos * decremented by 3 during the nested frame decoding. For example, running 25026d7285Schristos * tcpdump with "-vvvv" will do full decoding of OpenFlow and "-v" decoding of 26026d7285Schristos * the nested frames. 27026d7285Schristos * 28*3d25ea14Schristos * Partial decoding of Big Switch Networks vendor extensions is done after the 29*3d25ea14Schristos * oftest (OpenFlow Testing Framework) and Loxigen (library generator) source 30*3d25ea14Schristos * code. 31*3d25ea14Schristos * 32026d7285Schristos * 33026d7285Schristos * Copyright (c) 2013 The TCPDUMP project 34026d7285Schristos * All rights reserved. 35026d7285Schristos * 36026d7285Schristos * Redistribution and use in source and binary forms, with or without 37026d7285Schristos * modification, are permitted provided that the following conditions 38026d7285Schristos * are met: 39026d7285Schristos * 1. Redistributions of source code must retain the above copyright 40026d7285Schristos * notice, this list of conditions and the following disclaimer. 41026d7285Schristos * 2. Redistributions in binary form must reproduce the above copyright 42026d7285Schristos * notice, this list of conditions and the following disclaimer in the 43026d7285Schristos * documentation and/or other materials provided with the distribution. 44026d7285Schristos * 45026d7285Schristos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 46026d7285Schristos * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 47026d7285Schristos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 48026d7285Schristos * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 49026d7285Schristos * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 50026d7285Schristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 51026d7285Schristos * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 52026d7285Schristos * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 53026d7285Schristos * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54026d7285Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 55026d7285Schristos * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 56026d7285Schristos * POSSIBILITY OF SUCH DAMAGE. 57026d7285Schristos */ 58026d7285Schristos 59c47fd378Schristos #define NETDISSECT_REWORKED 60026d7285Schristos #ifdef HAVE_CONFIG_H 61026d7285Schristos #include "config.h" 62026d7285Schristos #endif 63026d7285Schristos 64026d7285Schristos #include <tcpdump-stdinc.h> 65026d7285Schristos 66026d7285Schristos #include "interface.h" 67026d7285Schristos #include "extract.h" 68026d7285Schristos #include "addrtoname.h" 69c47fd378Schristos #include "ether.h" 70026d7285Schristos #include "ethertype.h" 71026d7285Schristos #include "ipproto.h" 72*3d25ea14Schristos #include "oui.h" 73026d7285Schristos #include "openflow.h" 74026d7285Schristos 75c47fd378Schristos static const char tstr[] = " [|openflow]"; 76c47fd378Schristos static const char cstr[] = " (corrupt)"; 77c47fd378Schristos 78026d7285Schristos #define OFPT_HELLO 0x00 79026d7285Schristos #define OFPT_ERROR 0x01 80026d7285Schristos #define OFPT_ECHO_REQUEST 0x02 81026d7285Schristos #define OFPT_ECHO_REPLY 0x03 82026d7285Schristos #define OFPT_VENDOR 0x04 83026d7285Schristos #define OFPT_FEATURES_REQUEST 0x05 84026d7285Schristos #define OFPT_FEATURES_REPLY 0x06 85026d7285Schristos #define OFPT_GET_CONFIG_REQUEST 0x07 86026d7285Schristos #define OFPT_GET_CONFIG_REPLY 0x08 87026d7285Schristos #define OFPT_SET_CONFIG 0x09 88026d7285Schristos #define OFPT_PACKET_IN 0x0a 89026d7285Schristos #define OFPT_FLOW_REMOVED 0x0b 90026d7285Schristos #define OFPT_PORT_STATUS 0x0c 91026d7285Schristos #define OFPT_PACKET_OUT 0x0d 92026d7285Schristos #define OFPT_FLOW_MOD 0x0e 93026d7285Schristos #define OFPT_PORT_MOD 0x0f 94026d7285Schristos #define OFPT_STATS_REQUEST 0x10 95026d7285Schristos #define OFPT_STATS_REPLY 0x11 96026d7285Schristos #define OFPT_BARRIER_REQUEST 0x12 97026d7285Schristos #define OFPT_BARRIER_REPLY 0x13 98026d7285Schristos #define OFPT_QUEUE_GET_CONFIG_REQUEST 0x14 99026d7285Schristos #define OFPT_QUEUE_GET_CONFIG_REPLY 0x15 100026d7285Schristos static const struct tok ofpt_str[] = { 101026d7285Schristos { OFPT_HELLO, "HELLO" }, 102026d7285Schristos { OFPT_ERROR, "ERROR" }, 103026d7285Schristos { OFPT_ECHO_REQUEST, "ECHO_REQUEST" }, 104026d7285Schristos { OFPT_ECHO_REPLY, "ECHO_REPLY" }, 105026d7285Schristos { OFPT_VENDOR, "VENDOR" }, 106026d7285Schristos { OFPT_FEATURES_REQUEST, "FEATURES_REQUEST" }, 107026d7285Schristos { OFPT_FEATURES_REPLY, "FEATURES_REPLY" }, 108026d7285Schristos { OFPT_GET_CONFIG_REQUEST, "GET_CONFIG_REQUEST" }, 109026d7285Schristos { OFPT_GET_CONFIG_REPLY, "GET_CONFIG_REPLY" }, 110026d7285Schristos { OFPT_SET_CONFIG, "SET_CONFIG" }, 111026d7285Schristos { OFPT_PACKET_IN, "PACKET_IN" }, 112026d7285Schristos { OFPT_FLOW_REMOVED, "FLOW_REMOVED" }, 113026d7285Schristos { OFPT_PORT_STATUS, "PORT_STATUS" }, 114026d7285Schristos { OFPT_PACKET_OUT, "PACKET_OUT" }, 115026d7285Schristos { OFPT_FLOW_MOD, "FLOW_MOD" }, 116026d7285Schristos { OFPT_PORT_MOD, "PORT_MOD" }, 117026d7285Schristos { OFPT_STATS_REQUEST, "STATS_REQUEST" }, 118026d7285Schristos { OFPT_STATS_REPLY, "STATS_REPLY" }, 119026d7285Schristos { OFPT_BARRIER_REQUEST, "BARRIER_REQUEST" }, 120026d7285Schristos { OFPT_BARRIER_REPLY, "BARRIER_REPLY" }, 121026d7285Schristos { OFPT_QUEUE_GET_CONFIG_REQUEST, "QUEUE_GET_CONFIG_REQUEST" }, 122026d7285Schristos { OFPT_QUEUE_GET_CONFIG_REPLY, "QUEUE_GET_CONFIG_REPLY" }, 123026d7285Schristos { 0, NULL } 124026d7285Schristos }; 125026d7285Schristos 126026d7285Schristos #define OFPPC_PORT_DOWN (1 << 0) 127026d7285Schristos #define OFPPC_NO_STP (1 << 1) 128026d7285Schristos #define OFPPC_NO_RECV (1 << 2) 129026d7285Schristos #define OFPPC_NO_RECV_STP (1 << 3) 130026d7285Schristos #define OFPPC_NO_FLOOD (1 << 4) 131026d7285Schristos #define OFPPC_NO_FWD (1 << 5) 132026d7285Schristos #define OFPPC_NO_PACKET_IN (1 << 6) 133026d7285Schristos static const struct tok ofppc_bm[] = { 134026d7285Schristos { OFPPC_PORT_DOWN, "PORT_DOWN" }, 135026d7285Schristos { OFPPC_NO_STP, "NO_STP" }, 136026d7285Schristos { OFPPC_NO_RECV, "NO_RECV" }, 137026d7285Schristos { OFPPC_NO_RECV_STP, "NO_RECV_STP" }, 138026d7285Schristos { OFPPC_NO_FLOOD, "NO_FLOOD" }, 139026d7285Schristos { OFPPC_NO_FWD, "NO_FWD" }, 140026d7285Schristos { OFPPC_NO_PACKET_IN, "NO_PACKET_IN" }, 141026d7285Schristos { 0, NULL } 142026d7285Schristos }; 143026d7285Schristos #define OFPPC_U (~(OFPPC_PORT_DOWN | OFPPC_NO_STP | OFPPC_NO_RECV | \ 144026d7285Schristos OFPPC_NO_RECV_STP | OFPPC_NO_FLOOD | OFPPC_NO_FWD | \ 145026d7285Schristos OFPPC_NO_PACKET_IN)) 146026d7285Schristos 147026d7285Schristos #define OFPPS_LINK_DOWN (1 << 0) 148026d7285Schristos #define OFPPS_STP_LISTEN (0 << 8) 149026d7285Schristos #define OFPPS_STP_LEARN (1 << 8) 150026d7285Schristos #define OFPPS_STP_FORWARD (2 << 8) 151026d7285Schristos #define OFPPS_STP_BLOCK (3 << 8) 152026d7285Schristos #define OFPPS_STP_MASK (3 << 8) 153026d7285Schristos static const struct tok ofpps_bm[] = { 154026d7285Schristos { OFPPS_LINK_DOWN, "LINK_DOWN" }, 155026d7285Schristos { OFPPS_STP_LISTEN, "STP_LISTEN" }, 156026d7285Schristos { OFPPS_STP_LEARN, "STP_LEARN" }, 157026d7285Schristos { OFPPS_STP_FORWARD, "STP_FORWARD" }, 158026d7285Schristos { OFPPS_STP_BLOCK, "STP_BLOCK" }, 159026d7285Schristos { 0, NULL } 160026d7285Schristos }; 161026d7285Schristos #define OFPPS_U (~(OFPPS_LINK_DOWN | OFPPS_STP_LISTEN | OFPPS_STP_LEARN | \ 162026d7285Schristos OFPPS_STP_FORWARD | OFPPS_STP_BLOCK)) 163026d7285Schristos 164026d7285Schristos #define OFPP_MAX 0xff00 165026d7285Schristos #define OFPP_IN_PORT 0xfff8 166026d7285Schristos #define OFPP_TABLE 0xfff9 167026d7285Schristos #define OFPP_NORMAL 0xfffa 168026d7285Schristos #define OFPP_FLOOD 0xfffb 169026d7285Schristos #define OFPP_ALL 0xfffc 170026d7285Schristos #define OFPP_CONTROLLER 0xfffd 171026d7285Schristos #define OFPP_LOCAL 0xfffe 172026d7285Schristos #define OFPP_NONE 0xffff 173026d7285Schristos static const struct tok ofpp_str[] = { 174026d7285Schristos { OFPP_MAX, "MAX" }, 175026d7285Schristos { OFPP_IN_PORT, "IN_PORT" }, 176026d7285Schristos { OFPP_TABLE, "TABLE" }, 177026d7285Schristos { OFPP_NORMAL, "NORMAL" }, 178026d7285Schristos { OFPP_FLOOD, "FLOOD" }, 179026d7285Schristos { OFPP_ALL, "ALL" }, 180026d7285Schristos { OFPP_CONTROLLER, "CONTROLLER" }, 181026d7285Schristos { OFPP_LOCAL, "LOCAL" }, 182026d7285Schristos { OFPP_NONE, "NONE" }, 183026d7285Schristos { 0, NULL } 184026d7285Schristos }; 185026d7285Schristos 186026d7285Schristos #define OFPPF_10MB_HD (1 << 0) 187026d7285Schristos #define OFPPF_10MB_FD (1 << 1) 188026d7285Schristos #define OFPPF_100MB_HD (1 << 2) 189026d7285Schristos #define OFPPF_100MB_FD (1 << 3) 190026d7285Schristos #define OFPPF_1GB_HD (1 << 4) 191026d7285Schristos #define OFPPF_1GB_FD (1 << 5) 192026d7285Schristos #define OFPPF_10GB_FD (1 << 6) 193026d7285Schristos #define OFPPF_COPPER (1 << 7) 194026d7285Schristos #define OFPPF_FIBER (1 << 8) 195026d7285Schristos #define OFPPF_AUTONEG (1 << 9) 196026d7285Schristos #define OFPPF_PAUSE (1 << 10) 197026d7285Schristos #define OFPPF_PAUSE_ASYM (1 << 11) 198026d7285Schristos static const struct tok ofppf_bm[] = { 199026d7285Schristos { OFPPF_10MB_HD, "10MB_HD" }, 200026d7285Schristos { OFPPF_10MB_FD, "10MB_FD" }, 201026d7285Schristos { OFPPF_100MB_HD, "100MB_HD" }, 202026d7285Schristos { OFPPF_100MB_FD, "100MB_FD" }, 203026d7285Schristos { OFPPF_1GB_HD, "1GB_HD" }, 204026d7285Schristos { OFPPF_1GB_FD, "1GB_FD" }, 205026d7285Schristos { OFPPF_10GB_FD, "10GB_FD" }, 206026d7285Schristos { OFPPF_COPPER, "COPPER" }, 207026d7285Schristos { OFPPF_FIBER, "FIBER" }, 208026d7285Schristos { OFPPF_AUTONEG, "AUTONEG" }, 209026d7285Schristos { OFPPF_PAUSE, "PAUSE" }, 210026d7285Schristos { OFPPF_PAUSE_ASYM, "PAUSE_ASYM" }, 211026d7285Schristos { 0, NULL } 212026d7285Schristos }; 213026d7285Schristos #define OFPPF_U (~(OFPPF_10MB_HD | OFPPF_10MB_FD | OFPPF_100MB_HD | \ 214026d7285Schristos OFPPF_100MB_FD | OFPPF_1GB_HD | OFPPF_1GB_FD | \ 215026d7285Schristos OFPPF_10GB_FD | OFPPF_COPPER | OFPPF_FIBER | \ 216026d7285Schristos OFPPF_AUTONEG | OFPPF_PAUSE | OFPPF_PAUSE_ASYM)) 217026d7285Schristos 218026d7285Schristos #define OFPQT_NONE 0x0000 219026d7285Schristos #define OFPQT_MIN_RATE 0x0001 220026d7285Schristos static const struct tok ofpqt_str[] = { 221026d7285Schristos { OFPQT_NONE, "NONE" }, 222026d7285Schristos { OFPQT_MIN_RATE, "MIN_RATE" }, 223026d7285Schristos { 0, NULL } 224026d7285Schristos }; 225026d7285Schristos 226026d7285Schristos #define OFPFW_IN_PORT (1 << 0) 227026d7285Schristos #define OFPFW_DL_VLAN (1 << 1) 228026d7285Schristos #define OFPFW_DL_SRC (1 << 2) 229026d7285Schristos #define OFPFW_DL_DST (1 << 3) 230026d7285Schristos #define OFPFW_DL_TYPE (1 << 4) 231026d7285Schristos #define OFPFW_NW_PROTO (1 << 5) 232026d7285Schristos #define OFPFW_TP_SRC (1 << 6) 233026d7285Schristos #define OFPFW_TP_DST (1 << 7) 234026d7285Schristos #define OFPFW_NW_SRC_SHIFT 8 235026d7285Schristos #define OFPFW_NW_SRC_BITS 6 236026d7285Schristos #define OFPFW_NW_SRC_MASK (((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT) 237026d7285Schristos #define OFPFW_NW_DST_SHIFT 14 238026d7285Schristos #define OFPFW_NW_DST_BITS 6 239026d7285Schristos #define OFPFW_NW_DST_MASK (((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT) 240026d7285Schristos #define OFPFW_DL_VLAN_PCP (1 << 20) 241026d7285Schristos #define OFPFW_NW_TOS (1 << 21) 242026d7285Schristos #define OFPFW_ALL ((1 << 22) - 1) 243026d7285Schristos static const struct tok ofpfw_bm[] = { 244026d7285Schristos { OFPFW_IN_PORT, "IN_PORT" }, 245026d7285Schristos { OFPFW_DL_VLAN, "DL_VLAN" }, 246026d7285Schristos { OFPFW_DL_SRC, "DL_SRC" }, 247026d7285Schristos { OFPFW_DL_DST, "DL_DST" }, 248026d7285Schristos { OFPFW_DL_TYPE, "DL_TYPE" }, 249026d7285Schristos { OFPFW_NW_PROTO, "NW_PROTO" }, 250026d7285Schristos { OFPFW_TP_SRC, "TP_SRC" }, 251026d7285Schristos { OFPFW_TP_DST, "TP_DST" }, 252026d7285Schristos { OFPFW_DL_VLAN_PCP, "DL_VLAN_PCP" }, 253026d7285Schristos { OFPFW_NW_TOS, "NW_TOS" }, 254026d7285Schristos { 0, NULL } 255026d7285Schristos }; 256026d7285Schristos /* The above array does not include bits 8~13 (OFPFW_NW_SRC_*) and 14~19 257026d7285Schristos * (OFPFW_NW_DST_*), which are not a part of the bitmap and require decoding 258026d7285Schristos * other than that of tok2str(). The macro below includes these bits such that 259026d7285Schristos * they are not reported as bogus in the decoding. */ 260026d7285Schristos #define OFPFW_U (~(OFPFW_ALL)) 261026d7285Schristos 262026d7285Schristos #define OFPAT_OUTPUT 0x0000 263026d7285Schristos #define OFPAT_SET_VLAN_VID 0x0001 264026d7285Schristos #define OFPAT_SET_VLAN_PCP 0x0002 265026d7285Schristos #define OFPAT_STRIP_VLAN 0x0003 266026d7285Schristos #define OFPAT_SET_DL_SRC 0x0004 267026d7285Schristos #define OFPAT_SET_DL_DST 0x0005 268026d7285Schristos #define OFPAT_SET_NW_SRC 0x0006 269026d7285Schristos #define OFPAT_SET_NW_DST 0x0007 270026d7285Schristos #define OFPAT_SET_NW_TOS 0x0008 271026d7285Schristos #define OFPAT_SET_TP_SRC 0x0009 272026d7285Schristos #define OFPAT_SET_TP_DST 0x000a 273026d7285Schristos #define OFPAT_ENQUEUE 0x000b 274026d7285Schristos #define OFPAT_VENDOR 0xffff 275026d7285Schristos static const struct tok ofpat_str[] = { 276026d7285Schristos { OFPAT_OUTPUT, "OUTPUT" }, 277026d7285Schristos { OFPAT_SET_VLAN_VID, "SET_VLAN_VID" }, 278026d7285Schristos { OFPAT_SET_VLAN_PCP, "SET_VLAN_PCP" }, 279026d7285Schristos { OFPAT_STRIP_VLAN, "STRIP_VLAN" }, 280026d7285Schristos { OFPAT_SET_DL_SRC, "SET_DL_SRC" }, 281026d7285Schristos { OFPAT_SET_DL_DST, "SET_DL_DST" }, 282026d7285Schristos { OFPAT_SET_NW_SRC, "SET_NW_SRC" }, 283026d7285Schristos { OFPAT_SET_NW_DST, "SET_NW_DST" }, 284026d7285Schristos { OFPAT_SET_NW_TOS, "SET_NW_TOS" }, 285026d7285Schristos { OFPAT_SET_TP_SRC, "SET_TP_SRC" }, 286026d7285Schristos { OFPAT_SET_TP_DST, "SET_TP_DST" }, 287026d7285Schristos { OFPAT_ENQUEUE, "ENQUEUE" }, 288026d7285Schristos { OFPAT_VENDOR, "VENDOR" }, 289026d7285Schristos { 0, NULL } 290026d7285Schristos }; 291026d7285Schristos 292026d7285Schristos /* bit-shifted, w/o vendor action */ 293026d7285Schristos static const struct tok ofpat_bm[] = { 294026d7285Schristos { 1 << OFPAT_OUTPUT, "OUTPUT" }, 295026d7285Schristos { 1 << OFPAT_SET_VLAN_VID, "SET_VLAN_VID" }, 296026d7285Schristos { 1 << OFPAT_SET_VLAN_PCP, "SET_VLAN_PCP" }, 297026d7285Schristos { 1 << OFPAT_STRIP_VLAN, "STRIP_VLAN" }, 298026d7285Schristos { 1 << OFPAT_SET_DL_SRC, "SET_DL_SRC" }, 299026d7285Schristos { 1 << OFPAT_SET_DL_DST, "SET_DL_DST" }, 300026d7285Schristos { 1 << OFPAT_SET_NW_SRC, "SET_NW_SRC" }, 301026d7285Schristos { 1 << OFPAT_SET_NW_DST, "SET_NW_DST" }, 302026d7285Schristos { 1 << OFPAT_SET_NW_TOS, "SET_NW_TOS" }, 303026d7285Schristos { 1 << OFPAT_SET_TP_SRC, "SET_TP_SRC" }, 304026d7285Schristos { 1 << OFPAT_SET_TP_DST, "SET_TP_DST" }, 305026d7285Schristos { 1 << OFPAT_ENQUEUE, "ENQUEUE" }, 306026d7285Schristos { 0, NULL } 307026d7285Schristos }; 308026d7285Schristos #define OFPAT_U (~(1 << OFPAT_OUTPUT | 1 << OFPAT_SET_VLAN_VID | \ 309026d7285Schristos 1 << OFPAT_SET_VLAN_PCP | 1 << OFPAT_STRIP_VLAN | \ 310026d7285Schristos 1 << OFPAT_SET_DL_SRC | 1 << OFPAT_SET_DL_DST | \ 311026d7285Schristos 1 << OFPAT_SET_NW_SRC | 1 << OFPAT_SET_NW_DST | \ 312026d7285Schristos 1 << OFPAT_SET_NW_TOS | 1 << OFPAT_SET_TP_SRC | \ 313026d7285Schristos 1 << OFPAT_SET_TP_DST | 1 << OFPAT_ENQUEUE)) 314026d7285Schristos 315026d7285Schristos #define OFPC_FLOW_STATS (1 << 0) 316026d7285Schristos #define OFPC_TABLE_STATS (1 << 1) 317026d7285Schristos #define OFPC_PORT_STATS (1 << 2) 318026d7285Schristos #define OFPC_STP (1 << 3) 319026d7285Schristos #define OFPC_RESERVED (1 << 4) 320026d7285Schristos #define OFPC_IP_REASM (1 << 5) 321026d7285Schristos #define OFPC_QUEUE_STATS (1 << 6) 322026d7285Schristos #define OFPC_ARP_MATCH_IP (1 << 7) 323026d7285Schristos static const struct tok ofp_capabilities_bm[] = { 324026d7285Schristos { OFPC_FLOW_STATS, "FLOW_STATS" }, 325026d7285Schristos { OFPC_TABLE_STATS, "TABLE_STATS" }, 326026d7285Schristos { OFPC_PORT_STATS, "PORT_STATS" }, 327026d7285Schristos { OFPC_STP, "STP" }, 328026d7285Schristos { OFPC_RESERVED, "RESERVED" }, /* not in the mask below */ 329026d7285Schristos { OFPC_IP_REASM, "IP_REASM" }, 330026d7285Schristos { OFPC_QUEUE_STATS, "QUEUE_STATS" }, 331026d7285Schristos { OFPC_ARP_MATCH_IP, "ARP_MATCH_IP" }, 332026d7285Schristos { 0, NULL } 333026d7285Schristos }; 334026d7285Schristos #define OFPCAP_U (~(OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS | \ 335026d7285Schristos OFPC_STP | OFPC_IP_REASM | OFPC_QUEUE_STATS | \ 336026d7285Schristos OFPC_ARP_MATCH_IP)) 337026d7285Schristos 338026d7285Schristos #define OFPC_FRAG_NORMAL 0x0000 339026d7285Schristos #define OFPC_FRAG_DROP 0x0001 340026d7285Schristos #define OFPC_FRAG_REASM 0x0002 341026d7285Schristos #define OFPC_FRAG_MASK 0x0003 342026d7285Schristos static const struct tok ofp_config_str[] = { 343026d7285Schristos { OFPC_FRAG_NORMAL, "FRAG_NORMAL" }, 344026d7285Schristos { OFPC_FRAG_DROP, "FRAG_DROP" }, 345026d7285Schristos { OFPC_FRAG_REASM, "FRAG_REASM" }, 346026d7285Schristos { 0, NULL } 347026d7285Schristos }; 348026d7285Schristos 349026d7285Schristos #define OFPFC_ADD 0x0000 350026d7285Schristos #define OFPFC_MODIFY 0x0001 351026d7285Schristos #define OFPFC_MODIFY_STRICT 0x0002 352026d7285Schristos #define OFPFC_DELETE 0x0003 353026d7285Schristos #define OFPFC_DELETE_STRICT 0x0004 354026d7285Schristos static const struct tok ofpfc_str[] = { 355026d7285Schristos { OFPFC_ADD, "ADD" }, 356026d7285Schristos { OFPFC_MODIFY, "MODIFY" }, 357026d7285Schristos { OFPFC_MODIFY_STRICT, "MODIFY_STRICT" }, 358026d7285Schristos { OFPFC_DELETE, "DELETE" }, 359026d7285Schristos { OFPFC_DELETE_STRICT, "DELETE_STRICT" }, 360026d7285Schristos { 0, NULL } 361026d7285Schristos }; 362026d7285Schristos 363026d7285Schristos static const struct tok bufferid_str[] = { 364026d7285Schristos { 0xffffffff, "NONE" }, 365026d7285Schristos { 0, NULL } 366026d7285Schristos }; 367026d7285Schristos 368026d7285Schristos #define OFPFF_SEND_FLOW_REM (1 << 0) 369026d7285Schristos #define OFPFF_CHECK_OVERLAP (1 << 1) 370026d7285Schristos #define OFPFF_EMERG (1 << 2) 371026d7285Schristos static const struct tok ofpff_bm[] = { 372026d7285Schristos { OFPFF_SEND_FLOW_REM, "SEND_FLOW_REM" }, 373026d7285Schristos { OFPFF_CHECK_OVERLAP, "CHECK_OVERLAP" }, 374026d7285Schristos { OFPFF_EMERG, "EMERG" }, 375026d7285Schristos { 0, NULL } 376026d7285Schristos }; 377026d7285Schristos #define OFPFF_U (~(OFPFF_SEND_FLOW_REM | OFPFF_CHECK_OVERLAP | OFPFF_EMERG)) 378026d7285Schristos 379026d7285Schristos #define OFPST_DESC 0x0000 380026d7285Schristos #define OFPST_FLOW 0x0001 381026d7285Schristos #define OFPST_AGGREGATE 0x0002 382026d7285Schristos #define OFPST_TABLE 0x0003 383026d7285Schristos #define OFPST_PORT 0x0004 384026d7285Schristos #define OFPST_QUEUE 0x0005 385026d7285Schristos #define OFPST_VENDOR 0xffff 386026d7285Schristos static const struct tok ofpst_str[] = { 387026d7285Schristos { OFPST_DESC, "DESC" }, 388026d7285Schristos { OFPST_FLOW, "FLOW" }, 389026d7285Schristos { OFPST_AGGREGATE, "AGGREGATE" }, 390026d7285Schristos { OFPST_TABLE, "TABLE" }, 391026d7285Schristos { OFPST_PORT, "PORT" }, 392026d7285Schristos { OFPST_QUEUE, "QUEUE" }, 393026d7285Schristos { OFPST_VENDOR, "VENDOR" }, 394026d7285Schristos { 0, NULL } 395026d7285Schristos }; 396026d7285Schristos 397026d7285Schristos static const struct tok tableid_str[] = { 398026d7285Schristos { 0xfe, "EMERG" }, 399026d7285Schristos { 0xff, "ALL" }, 400026d7285Schristos { 0, NULL } 401026d7285Schristos }; 402026d7285Schristos 403026d7285Schristos #define OFPQ_ALL 0xffffffff 404026d7285Schristos static const struct tok ofpq_str[] = { 405026d7285Schristos { OFPQ_ALL, "ALL" }, 406026d7285Schristos { 0, NULL } 407026d7285Schristos }; 408026d7285Schristos 409026d7285Schristos #define OFPSF_REPLY_MORE 0x0001 410026d7285Schristos static const struct tok ofpsf_reply_bm[] = { 411026d7285Schristos { OFPSF_REPLY_MORE, "MORE" }, 412026d7285Schristos { 0, NULL } 413026d7285Schristos }; 414026d7285Schristos #define OFPSF_REPLY_U (~(OFPSF_REPLY_MORE)) 415026d7285Schristos 416026d7285Schristos #define OFPR_NO_MATCH 0x00 417026d7285Schristos #define OFPR_ACTION 0x01 418026d7285Schristos static const struct tok ofpr_str[] = { 419026d7285Schristos { OFPR_NO_MATCH, "NO_MATCH" }, 420026d7285Schristos { OFPR_ACTION, "ACTION" }, 421026d7285Schristos { 0, NULL } 422026d7285Schristos }; 423026d7285Schristos 424026d7285Schristos #define OFPRR_IDLE_TIMEOUT 0x00 425026d7285Schristos #define OFPRR_HARD_TIMEOUT 0x01 426026d7285Schristos #define OFPRR_DELETE 0x02 427026d7285Schristos static const struct tok ofprr_str[] = { 428026d7285Schristos { OFPRR_IDLE_TIMEOUT, "IDLE_TIMEOUT" }, 429026d7285Schristos { OFPRR_HARD_TIMEOUT, "HARD_TIMEOUT" }, 430026d7285Schristos { OFPRR_DELETE, "DELETE" }, 431026d7285Schristos { 0, NULL } 432026d7285Schristos }; 433026d7285Schristos 434026d7285Schristos #define OFPPR_ADD 0x00 435026d7285Schristos #define OFPPR_DELETE 0x01 436026d7285Schristos #define OFPPR_MODIFY 0x02 437026d7285Schristos static const struct tok ofppr_str[] = { 438026d7285Schristos { OFPPR_ADD, "ADD" }, 439026d7285Schristos { OFPPR_DELETE, "DELETE" }, 440026d7285Schristos { OFPPR_MODIFY, "MODIFY" }, 441026d7285Schristos { 0, NULL } 442026d7285Schristos }; 443026d7285Schristos 444026d7285Schristos #define OFPET_HELLO_FAILED 0x0000 445026d7285Schristos #define OFPET_BAD_REQUEST 0x0001 446026d7285Schristos #define OFPET_BAD_ACTION 0x0002 447026d7285Schristos #define OFPET_FLOW_MOD_FAILED 0x0003 448026d7285Schristos #define OFPET_PORT_MOD_FAILED 0x0004 449026d7285Schristos #define OFPET_QUEUE_OP_FAILED 0x0005 450026d7285Schristos static const struct tok ofpet_str[] = { 451026d7285Schristos { OFPET_HELLO_FAILED, "HELLO_FAILED" }, 452026d7285Schristos { OFPET_BAD_REQUEST, "BAD_REQUEST" }, 453026d7285Schristos { OFPET_BAD_ACTION, "BAD_ACTION" }, 454026d7285Schristos { OFPET_FLOW_MOD_FAILED, "FLOW_MOD_FAILED" }, 455026d7285Schristos { OFPET_PORT_MOD_FAILED, "PORT_MOD_FAILED" }, 456026d7285Schristos { OFPET_QUEUE_OP_FAILED, "QUEUE_OP_FAILED" }, 457026d7285Schristos { 0, NULL } 458026d7285Schristos }; 459026d7285Schristos 460026d7285Schristos #define OFPHFC_INCOMPATIBLE 0x0000 461026d7285Schristos #define OFPHFC_EPERM 0x0001 462026d7285Schristos static const struct tok ofphfc_str[] = { 463026d7285Schristos { OFPHFC_INCOMPATIBLE, "INCOMPATIBLE" }, 464026d7285Schristos { OFPHFC_EPERM, "EPERM" }, 465026d7285Schristos { 0, NULL } 466026d7285Schristos }; 467026d7285Schristos 468026d7285Schristos #define OFPBRC_BAD_VERSION 0x0000 469026d7285Schristos #define OFPBRC_BAD_TYPE 0x0001 470026d7285Schristos #define OFPBRC_BAD_STAT 0x0002 471026d7285Schristos #define OFPBRC_BAD_VENDOR 0x0003 472026d7285Schristos #define OFPBRC_BAD_SUBTYPE 0x0004 473026d7285Schristos #define OFPBRC_EPERM 0x0005 474026d7285Schristos #define OFPBRC_BAD_LEN 0x0006 475026d7285Schristos #define OFPBRC_BUFFER_EMPTY 0x0007 476026d7285Schristos #define OFPBRC_BUFFER_UNKNOWN 0x0008 477026d7285Schristos static const struct tok ofpbrc_str[] = { 478026d7285Schristos { OFPBRC_BAD_VERSION, "BAD_VERSION" }, 479026d7285Schristos { OFPBRC_BAD_TYPE, "BAD_TYPE" }, 480026d7285Schristos { OFPBRC_BAD_STAT, "BAD_STAT" }, 481026d7285Schristos { OFPBRC_BAD_VENDOR, "BAD_VENDOR" }, 482026d7285Schristos { OFPBRC_BAD_SUBTYPE, "BAD_SUBTYPE" }, 483026d7285Schristos { OFPBRC_EPERM, "EPERM" }, 484026d7285Schristos { OFPBRC_BAD_LEN, "BAD_LEN" }, 485026d7285Schristos { OFPBRC_BUFFER_EMPTY, "BUFFER_EMPTY" }, 486026d7285Schristos { OFPBRC_BUFFER_UNKNOWN, "BUFFER_UNKNOWN" }, 487026d7285Schristos { 0, NULL } 488026d7285Schristos }; 489026d7285Schristos 490026d7285Schristos #define OFPBAC_BAD_TYPE 0x0000 491026d7285Schristos #define OFPBAC_BAD_LEN 0x0001 492026d7285Schristos #define OFPBAC_BAD_VENDOR 0x0002 493026d7285Schristos #define OFPBAC_BAD_VENDOR_TYPE 0x0003 494026d7285Schristos #define OFPBAC_BAD_OUT_PORT 0x0004 495026d7285Schristos #define OFPBAC_BAD_ARGUMENT 0x0005 496026d7285Schristos #define OFPBAC_EPERM 0x0006 497026d7285Schristos #define OFPBAC_TOO_MANY 0x0007 498026d7285Schristos #define OFPBAC_BAD_QUEUE 0x0008 499026d7285Schristos static const struct tok ofpbac_str[] = { 500026d7285Schristos { OFPBAC_BAD_TYPE, "BAD_TYPE" }, 501026d7285Schristos { OFPBAC_BAD_LEN, "BAD_LEN" }, 502026d7285Schristos { OFPBAC_BAD_VENDOR, "BAD_VENDOR" }, 503026d7285Schristos { OFPBAC_BAD_VENDOR_TYPE, "BAD_VENDOR_TYPE" }, 504026d7285Schristos { OFPBAC_BAD_OUT_PORT, "BAD_OUT_PORT" }, 505026d7285Schristos { OFPBAC_BAD_ARGUMENT, "BAD_ARGUMENT" }, 506026d7285Schristos { OFPBAC_EPERM, "EPERM" }, 507026d7285Schristos { OFPBAC_TOO_MANY, "TOO_MANY" }, 508026d7285Schristos { OFPBAC_BAD_QUEUE, "BAD_QUEUE" }, 509026d7285Schristos { 0, NULL } 510026d7285Schristos }; 511026d7285Schristos 512026d7285Schristos #define OFPFMFC_ALL_TABLES_FULL 0x0000 513026d7285Schristos #define OFPFMFC_OVERLAP 0x0001 514026d7285Schristos #define OFPFMFC_EPERM 0x0002 515026d7285Schristos #define OFPFMFC_BAD_EMERG_TIMEOUT 0x0003 516026d7285Schristos #define OFPFMFC_BAD_COMMAND 0x0004 517026d7285Schristos #define OFPFMFC_UNSUPPORTED 0x0005 518026d7285Schristos static const struct tok ofpfmfc_str[] = { 519026d7285Schristos { OFPFMFC_ALL_TABLES_FULL, "ALL_TABLES_FULL" }, 520026d7285Schristos { OFPFMFC_OVERLAP, "OVERLAP" }, 521026d7285Schristos { OFPFMFC_EPERM, "EPERM" }, 522026d7285Schristos { OFPFMFC_BAD_EMERG_TIMEOUT, "BAD_EMERG_TIMEOUT" }, 523026d7285Schristos { OFPFMFC_BAD_COMMAND, "BAD_COMMAND" }, 524026d7285Schristos { OFPFMFC_UNSUPPORTED, "UNSUPPORTED" }, 525026d7285Schristos { 0, NULL } 526026d7285Schristos }; 527026d7285Schristos 528026d7285Schristos #define OFPPMFC_BAD_PORT 0x0000 529026d7285Schristos #define OFPPMFC_BAD_HW_ADDR 0x0001 530026d7285Schristos static const struct tok ofppmfc_str[] = { 531026d7285Schristos { OFPPMFC_BAD_PORT, "BAD_PORT" }, 532026d7285Schristos { OFPPMFC_BAD_HW_ADDR, "BAD_HW_ADDR" }, 533026d7285Schristos { 0, NULL } 534026d7285Schristos }; 535026d7285Schristos 536026d7285Schristos #define OFPQOFC_BAD_PORT 0x0000 537026d7285Schristos #define OFPQOFC_BAD_QUEUE 0x0001 538026d7285Schristos #define OFPQOFC_EPERM 0x0002 539026d7285Schristos static const struct tok ofpqofc_str[] = { 540026d7285Schristos { OFPQOFC_BAD_PORT, "BAD_PORT" }, 541026d7285Schristos { OFPQOFC_BAD_QUEUE, "BAD_QUEUE" }, 542026d7285Schristos { OFPQOFC_EPERM, "EPERM" }, 543026d7285Schristos { 0, NULL } 544026d7285Schristos }; 545026d7285Schristos 546026d7285Schristos static const struct tok empty_str[] = { 547026d7285Schristos { 0, NULL } 548026d7285Schristos }; 549026d7285Schristos 550026d7285Schristos /* lengths (fixed or minimal) of particular protocol structures */ 551026d7285Schristos #define OF_SWITCH_CONFIG_LEN 12 552026d7285Schristos #define OF_PHY_PORT_LEN 48 553026d7285Schristos #define OF_SWITCH_FEATURES_LEN 32 554026d7285Schristos #define OF_PORT_STATUS_LEN 64 555026d7285Schristos #define OF_PORT_MOD_LEN 32 556026d7285Schristos #define OF_PACKET_IN_LEN 20 557026d7285Schristos #define OF_ACTION_OUTPUT_LEN 8 558026d7285Schristos #define OF_ACTION_VLAN_VID_LEN 8 559026d7285Schristos #define OF_ACTION_VLAN_PCP_LEN 8 560026d7285Schristos #define OF_ACTION_DL_ADDR_LEN 16 561026d7285Schristos #define OF_ACTION_NW_ADDR_LEN 8 562026d7285Schristos #define OF_ACTION_TP_PORT_LEN 8 563026d7285Schristos #define OF_ACTION_NW_TOS_LEN 8 564026d7285Schristos #define OF_ACTION_VENDOR_HEADER_LEN 8 565026d7285Schristos #define OF_ACTION_HEADER_LEN 8 566026d7285Schristos #define OF_PACKET_OUT_LEN 16 567026d7285Schristos #define OF_MATCH_LEN 40 568026d7285Schristos #define OF_FLOW_MOD_LEN 72 569026d7285Schristos #define OF_FLOW_REMOVED_LEN 88 570026d7285Schristos #define OF_ERROR_MSG_LEN 12 571026d7285Schristos #define OF_STATS_REQUEST_LEN 12 572026d7285Schristos #define OF_STATS_REPLY_LEN 12 573026d7285Schristos #define OF_DESC_STATS_LEN 1056 574026d7285Schristos #define OF_FLOW_STATS_REQUEST_LEN 44 575026d7285Schristos #define OF_FLOW_STATS_LEN 88 576026d7285Schristos #define OF_AGGREGATE_STATS_REQUEST_LEN 44 577026d7285Schristos #define OF_AGGREGATE_STATS_REPLY_LEN 24 578026d7285Schristos #define OF_TABLE_STATS_LEN 64 579026d7285Schristos #define OF_PORT_STATS_REQUEST_LEN 8 580026d7285Schristos #define OF_PORT_STATS_LEN 104 581026d7285Schristos #define OF_VENDOR_HEADER_LEN 12 582026d7285Schristos #define OF_QUEUE_PROP_HEADER_LEN 8 583026d7285Schristos #define OF_QUEUE_PROP_MIN_RATE_LEN 16 584026d7285Schristos #define OF_PACKET_QUEUE_LEN 8 585026d7285Schristos #define OF_QUEUE_GET_CONFIG_REQUEST_LEN 12 586026d7285Schristos #define OF_QUEUE_GET_CONFIG_REPLY_LEN 16 587026d7285Schristos #define OF_ACTION_ENQUEUE_LEN 16 588026d7285Schristos #define OF_QUEUE_STATS_REQUEST_LEN 8 589026d7285Schristos #define OF_QUEUE_STATS_LEN 32 590026d7285Schristos 591026d7285Schristos /* miscellaneous constants from [OF10] */ 592026d7285Schristos #define OFP_MAX_TABLE_NAME_LEN 32 593026d7285Schristos #define OFP_MAX_PORT_NAME_LEN 16 594026d7285Schristos #define DESC_STR_LEN 256 595026d7285Schristos #define SERIAL_NUM_LEN 32 596026d7285Schristos #define OFP_VLAN_NONE 0xffff 597026d7285Schristos 598*3d25ea14Schristos /* vendor extensions */ 599*3d25ea14Schristos #define BSN_SET_IP_MASK 0 600*3d25ea14Schristos #define BSN_GET_IP_MASK_REQUEST 1 601*3d25ea14Schristos #define BSN_GET_IP_MASK_REPLY 2 602*3d25ea14Schristos #define BSN_SET_MIRRORING 3 603*3d25ea14Schristos #define BSN_GET_MIRRORING_REQUEST 4 604*3d25ea14Schristos #define BSN_GET_MIRRORING_REPLY 5 605*3d25ea14Schristos #define BSN_SHELL_COMMAND 6 606*3d25ea14Schristos #define BSN_SHELL_OUTPUT 7 607*3d25ea14Schristos #define BSN_SHELL_STATUS 8 608*3d25ea14Schristos #define BSN_GET_INTERFACES_REQUEST 9 609*3d25ea14Schristos #define BSN_GET_INTERFACES_REPLY 10 610*3d25ea14Schristos #define BSN_SET_PKTIN_SUPPRESSION_REQUEST 11 611*3d25ea14Schristos #define BSN_SET_L2_TABLE_REQUEST 12 612*3d25ea14Schristos #define BSN_GET_L2_TABLE_REQUEST 13 613*3d25ea14Schristos #define BSN_GET_L2_TABLE_REPLY 14 614*3d25ea14Schristos #define BSN_VIRTUAL_PORT_CREATE_REQUEST 15 615*3d25ea14Schristos #define BSN_VIRTUAL_PORT_CREATE_REPLY 16 616*3d25ea14Schristos #define BSN_VIRTUAL_PORT_REMOVE_REQUEST 17 617*3d25ea14Schristos #define BSN_BW_ENABLE_SET_REQUEST 18 618*3d25ea14Schristos #define BSN_BW_ENABLE_GET_REQUEST 19 619*3d25ea14Schristos #define BSN_BW_ENABLE_GET_REPLY 20 620*3d25ea14Schristos #define BSN_BW_CLEAR_DATA_REQUEST 21 621*3d25ea14Schristos #define BSN_BW_CLEAR_DATA_REPLY 22 622*3d25ea14Schristos #define BSN_BW_ENABLE_SET_REPLY 23 623*3d25ea14Schristos #define BSN_SET_L2_TABLE_REPLY 24 624*3d25ea14Schristos #define BSN_SET_PKTIN_SUPPRESSION_REPLY 25 625*3d25ea14Schristos #define BSN_VIRTUAL_PORT_REMOVE_REPLY 26 626*3d25ea14Schristos #define BSN_HYBRID_GET_REQUEST 27 627*3d25ea14Schristos #define BSN_HYBRID_GET_REPLY 28 628*3d25ea14Schristos /* 29 */ 629*3d25ea14Schristos /* 30 */ 630*3d25ea14Schristos #define BSN_PDU_TX_REQUEST 31 631*3d25ea14Schristos #define BSN_PDU_TX_REPLY 32 632*3d25ea14Schristos #define BSN_PDU_RX_REQUEST 33 633*3d25ea14Schristos #define BSN_PDU_RX_REPLY 34 634*3d25ea14Schristos #define BSN_PDU_RX_TIMEOUT 35 635*3d25ea14Schristos 636*3d25ea14Schristos static const struct tok bsn_subtype_str[] = { 637*3d25ea14Schristos { BSN_SET_IP_MASK, "SET_IP_MASK" }, 638*3d25ea14Schristos { BSN_GET_IP_MASK_REQUEST, "GET_IP_MASK_REQUEST" }, 639*3d25ea14Schristos { BSN_GET_IP_MASK_REPLY, "GET_IP_MASK_REPLY" }, 640*3d25ea14Schristos { BSN_SET_MIRRORING, "SET_MIRRORING" }, 641*3d25ea14Schristos { BSN_GET_MIRRORING_REQUEST, "GET_MIRRORING_REQUEST" }, 642*3d25ea14Schristos { BSN_GET_MIRRORING_REPLY, "GET_MIRRORING_REPLY" }, 643*3d25ea14Schristos { BSN_SHELL_COMMAND, "SHELL_COMMAND" }, 644*3d25ea14Schristos { BSN_SHELL_OUTPUT, "SHELL_OUTPUT" }, 645*3d25ea14Schristos { BSN_SHELL_STATUS, "SHELL_STATUS" }, 646*3d25ea14Schristos { BSN_GET_INTERFACES_REQUEST, "GET_INTERFACES_REQUEST" }, 647*3d25ea14Schristos { BSN_GET_INTERFACES_REPLY, "GET_INTERFACES_REPLY" }, 648*3d25ea14Schristos { BSN_SET_PKTIN_SUPPRESSION_REQUEST, "SET_PKTIN_SUPPRESSION_REQUEST" }, 649*3d25ea14Schristos { BSN_SET_L2_TABLE_REQUEST, "SET_L2_TABLE_REQUEST" }, 650*3d25ea14Schristos { BSN_GET_L2_TABLE_REQUEST, "GET_L2_TABLE_REQUEST" }, 651*3d25ea14Schristos { BSN_GET_L2_TABLE_REPLY, "GET_L2_TABLE_REPLY" }, 652*3d25ea14Schristos { BSN_VIRTUAL_PORT_CREATE_REQUEST, "VIRTUAL_PORT_CREATE_REQUEST" }, 653*3d25ea14Schristos { BSN_VIRTUAL_PORT_CREATE_REPLY, "VIRTUAL_PORT_CREATE_REPLY" }, 654*3d25ea14Schristos { BSN_VIRTUAL_PORT_REMOVE_REQUEST, "VIRTUAL_PORT_REMOVE_REQUEST" }, 655*3d25ea14Schristos { BSN_BW_ENABLE_SET_REQUEST, "BW_ENABLE_SET_REQUEST" }, 656*3d25ea14Schristos { BSN_BW_ENABLE_GET_REQUEST, "BW_ENABLE_GET_REQUEST" }, 657*3d25ea14Schristos { BSN_BW_ENABLE_GET_REPLY, "BW_ENABLE_GET_REPLY" }, 658*3d25ea14Schristos { BSN_BW_CLEAR_DATA_REQUEST, "BW_CLEAR_DATA_REQUEST" }, 659*3d25ea14Schristos { BSN_BW_CLEAR_DATA_REPLY, "BW_CLEAR_DATA_REPLY" }, 660*3d25ea14Schristos { BSN_BW_ENABLE_SET_REPLY, "BW_ENABLE_SET_REPLY" }, 661*3d25ea14Schristos { BSN_SET_L2_TABLE_REPLY, "SET_L2_TABLE_REPLY" }, 662*3d25ea14Schristos { BSN_SET_PKTIN_SUPPRESSION_REPLY, "SET_PKTIN_SUPPRESSION_REPLY" }, 663*3d25ea14Schristos { BSN_VIRTUAL_PORT_REMOVE_REPLY, "VIRTUAL_PORT_REMOVE_REPLY" }, 664*3d25ea14Schristos { BSN_HYBRID_GET_REQUEST, "HYBRID_GET_REQUEST" }, 665*3d25ea14Schristos { BSN_HYBRID_GET_REPLY, "HYBRID_GET_REPLY" }, 666*3d25ea14Schristos { BSN_PDU_TX_REQUEST, "PDU_TX_REQUEST" }, 667*3d25ea14Schristos { BSN_PDU_TX_REPLY, "PDU_TX_REPLY" }, 668*3d25ea14Schristos { BSN_PDU_RX_REQUEST, "PDU_RX_REQUEST" }, 669*3d25ea14Schristos { BSN_PDU_RX_REPLY, "PDU_RX_REPLY" }, 670*3d25ea14Schristos { BSN_PDU_RX_TIMEOUT, "PDU_RX_TIMEOUT" }, 671*3d25ea14Schristos { 0, NULL } 672*3d25ea14Schristos }; 673*3d25ea14Schristos 674*3d25ea14Schristos #define BSN_ACTION_MIRROR 1 675*3d25ea14Schristos #define BSN_ACTION_SET_TUNNEL_DST 2 676*3d25ea14Schristos /* 3 */ 677*3d25ea14Schristos #define BSN_ACTION_CHECKSUM 4 678*3d25ea14Schristos 679*3d25ea14Schristos static const struct tok bsn_action_subtype_str[] = { 680*3d25ea14Schristos { BSN_ACTION_MIRROR, "MIRROR" }, 681*3d25ea14Schristos { BSN_ACTION_SET_TUNNEL_DST, "SET_TUNNEL_DST" }, 682*3d25ea14Schristos { BSN_ACTION_CHECKSUM, "CHECKSUM" }, 683*3d25ea14Schristos { 0, NULL } 684*3d25ea14Schristos }; 685*3d25ea14Schristos 686*3d25ea14Schristos static const struct tok bsn_mirror_copy_stage_str[] = { 687*3d25ea14Schristos { 0, "INGRESS" }, 688*3d25ea14Schristos { 1, "EGRESS" }, 689*3d25ea14Schristos { 0, NULL }, 690*3d25ea14Schristos }; 691*3d25ea14Schristos 692*3d25ea14Schristos static const struct tok bsn_onoff_str[] = { 693*3d25ea14Schristos { 0, "OFF" }, 694*3d25ea14Schristos { 1, "ON" }, 695*3d25ea14Schristos { 0, NULL }, 696*3d25ea14Schristos }; 697*3d25ea14Schristos 698026d7285Schristos static const char * 699*3d25ea14Schristos vlan_str(const uint16_t vid) 700*3d25ea14Schristos { 701026d7285Schristos static char buf[sizeof("65535 (bogus)")]; 702026d7285Schristos const char *fmt; 703026d7285Schristos 704026d7285Schristos if (vid == OFP_VLAN_NONE) 705026d7285Schristos return "NONE"; 706026d7285Schristos fmt = (vid > 0 && vid < 0x0fff) ? "%u" : "%u (bogus)"; 707026d7285Schristos snprintf(buf, sizeof(buf), fmt, vid); 708026d7285Schristos return buf; 709026d7285Schristos } 710026d7285Schristos 711026d7285Schristos static const char * 712*3d25ea14Schristos pcp_str(const uint8_t pcp) 713*3d25ea14Schristos { 714026d7285Schristos static char buf[sizeof("255 (bogus)")]; 715026d7285Schristos snprintf(buf, sizeof(buf), pcp <= 7 ? "%u" : "%u (bogus)", pcp); 716026d7285Schristos return buf; 717026d7285Schristos } 718026d7285Schristos 719026d7285Schristos static void 720c47fd378Schristos of10_bitmap_print(netdissect_options *ndo, 721*3d25ea14Schristos const struct tok *t, const uint32_t v, const uint32_t u) 722*3d25ea14Schristos { 723026d7285Schristos const char *sep = " ("; 724026d7285Schristos 725026d7285Schristos if (v == 0) 726026d7285Schristos return; 727026d7285Schristos /* assigned bits */ 728026d7285Schristos for (; t->s != NULL; t++) 729026d7285Schristos if (v & t->v) { 730c47fd378Schristos ND_PRINT((ndo, "%s%s", sep, t->s)); 731026d7285Schristos sep = ", "; 732026d7285Schristos } 733026d7285Schristos /* unassigned bits? */ 734c47fd378Schristos ND_PRINT((ndo, v & u ? ") (bogus)" : ")")); 735026d7285Schristos } 736026d7285Schristos 737026d7285Schristos static const u_char * 738c47fd378Schristos of10_data_print(netdissect_options *ndo, 739*3d25ea14Schristos const u_char *cp, const u_char *ep, const u_int len) 740*3d25ea14Schristos { 741026d7285Schristos if (len == 0) 742026d7285Schristos return cp; 743026d7285Schristos /* data */ 744c47fd378Schristos ND_PRINT((ndo, "\n\t data (%u octets)", len)); 745c47fd378Schristos ND_TCHECK2(*cp, len); 746c47fd378Schristos if (ndo->ndo_vflag >= 2) 747c47fd378Schristos hex_and_ascii_print(ndo, "\n\t ", cp, len); 748026d7285Schristos return cp + len; 749026d7285Schristos 750026d7285Schristos trunc: 751c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 752026d7285Schristos return ep; 753026d7285Schristos } 754026d7285Schristos 755026d7285Schristos static const u_char * 756*3d25ea14Schristos of10_bsn_message_print(netdissect_options *ndo, 757*3d25ea14Schristos const u_char *cp, const u_char *ep, const u_int len) 758*3d25ea14Schristos { 759*3d25ea14Schristos const u_char *cp0 = cp; 760*3d25ea14Schristos uint32_t subtype; 761*3d25ea14Schristos 762*3d25ea14Schristos if (len < 4) 763*3d25ea14Schristos goto corrupt; 764*3d25ea14Schristos /* subtype */ 765*3d25ea14Schristos ND_TCHECK2(*cp, 4); 766*3d25ea14Schristos subtype = EXTRACT_32BITS(cp); 767*3d25ea14Schristos cp += 4; 768*3d25ea14Schristos ND_PRINT((ndo, "\n\t subtype %s", tok2str(bsn_subtype_str, "unknown (0x%08x)", subtype))); 769*3d25ea14Schristos switch (subtype) { 770*3d25ea14Schristos case BSN_GET_IP_MASK_REQUEST: 771*3d25ea14Schristos /* 772*3d25ea14Schristos * 0 1 2 3 773*3d25ea14Schristos * 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*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 775*3d25ea14Schristos * | subtype | 776*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 777*3d25ea14Schristos * | index | pad | 778*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 779*3d25ea14Schristos * | pad | 780*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 781*3d25ea14Schristos * 782*3d25ea14Schristos */ 783*3d25ea14Schristos if (len != 12) 784*3d25ea14Schristos goto corrupt; 785*3d25ea14Schristos /* index */ 786*3d25ea14Schristos ND_TCHECK2(*cp, 1); 787*3d25ea14Schristos ND_PRINT((ndo, ", index %u", *cp)); 788*3d25ea14Schristos cp += 1; 789*3d25ea14Schristos /* pad */ 790*3d25ea14Schristos ND_TCHECK2(*cp, 7); 791*3d25ea14Schristos cp += 7; 792*3d25ea14Schristos break; 793*3d25ea14Schristos case BSN_SET_IP_MASK: 794*3d25ea14Schristos case BSN_GET_IP_MASK_REPLY: 795*3d25ea14Schristos /* 796*3d25ea14Schristos * 0 1 2 3 797*3d25ea14Schristos * 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*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 799*3d25ea14Schristos * | subtype | 800*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 801*3d25ea14Schristos * | index | pad | 802*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 803*3d25ea14Schristos * | mask | 804*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 805*3d25ea14Schristos * 806*3d25ea14Schristos */ 807*3d25ea14Schristos if (len != 12) 808*3d25ea14Schristos goto corrupt; 809*3d25ea14Schristos /* index */ 810*3d25ea14Schristos ND_TCHECK2(*cp, 1); 811*3d25ea14Schristos ND_PRINT((ndo, ", index %u", *cp)); 812*3d25ea14Schristos cp += 1; 813*3d25ea14Schristos /* pad */ 814*3d25ea14Schristos ND_TCHECK2(*cp, 3); 815*3d25ea14Schristos cp += 3; 816*3d25ea14Schristos /* mask */ 817*3d25ea14Schristos ND_TCHECK2(*cp, 4); 818*3d25ea14Schristos ND_PRINT((ndo, ", mask %s", ipaddr_string(ndo, cp))); 819*3d25ea14Schristos cp += 4; 820*3d25ea14Schristos break; 821*3d25ea14Schristos case BSN_SET_MIRRORING: 822*3d25ea14Schristos case BSN_GET_MIRRORING_REQUEST: 823*3d25ea14Schristos case BSN_GET_MIRRORING_REPLY: 824*3d25ea14Schristos /* 825*3d25ea14Schristos * 0 1 2 3 826*3d25ea14Schristos * 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*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 828*3d25ea14Schristos * | subtype | 829*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 830*3d25ea14Schristos * | report m. p. | pad | 831*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 832*3d25ea14Schristos * 833*3d25ea14Schristos */ 834*3d25ea14Schristos if (len != 8) 835*3d25ea14Schristos goto corrupt; 836*3d25ea14Schristos /* report_mirror_ports */ 837*3d25ea14Schristos ND_TCHECK2(*cp, 1); 838*3d25ea14Schristos ND_PRINT((ndo, ", report_mirror_ports %s", tok2str(bsn_onoff_str, "bogus (%u)", *cp))); 839*3d25ea14Schristos cp += 1; 840*3d25ea14Schristos /* pad */ 841*3d25ea14Schristos ND_TCHECK2(*cp, 3); 842*3d25ea14Schristos cp += 3; 843*3d25ea14Schristos break; 844*3d25ea14Schristos case BSN_GET_INTERFACES_REQUEST: 845*3d25ea14Schristos case BSN_GET_L2_TABLE_REQUEST: 846*3d25ea14Schristos case BSN_BW_ENABLE_GET_REQUEST: 847*3d25ea14Schristos case BSN_BW_CLEAR_DATA_REQUEST: 848*3d25ea14Schristos case BSN_HYBRID_GET_REQUEST: 849*3d25ea14Schristos /* 850*3d25ea14Schristos * 0 1 2 3 851*3d25ea14Schristos * 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*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 853*3d25ea14Schristos * | subtype | 854*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 855*3d25ea14Schristos * 856*3d25ea14Schristos */ 857*3d25ea14Schristos if (len != 4) 858*3d25ea14Schristos goto corrupt; 859*3d25ea14Schristos break; 860*3d25ea14Schristos case BSN_VIRTUAL_PORT_REMOVE_REQUEST: 861*3d25ea14Schristos /* 862*3d25ea14Schristos * 0 1 2 3 863*3d25ea14Schristos * 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*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 865*3d25ea14Schristos * | subtype | 866*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 867*3d25ea14Schristos * | vport_no | 868*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 869*3d25ea14Schristos * 870*3d25ea14Schristos */ 871*3d25ea14Schristos if (len != 8) 872*3d25ea14Schristos goto corrupt; 873*3d25ea14Schristos /* vport_no */ 874*3d25ea14Schristos ND_TCHECK2(*cp, 4); 875*3d25ea14Schristos ND_PRINT((ndo, ", vport_no %u", EXTRACT_32BITS(cp))); 876*3d25ea14Schristos cp += 4; 877*3d25ea14Schristos break; 878*3d25ea14Schristos case BSN_SHELL_COMMAND: 879*3d25ea14Schristos /* 880*3d25ea14Schristos * 0 1 2 3 881*3d25ea14Schristos * 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*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 883*3d25ea14Schristos * | subtype | 884*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 885*3d25ea14Schristos * | service | 886*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 887*3d25ea14Schristos * | data ... 888*3d25ea14Schristos * +---------------+---------------+-------- 889*3d25ea14Schristos * 890*3d25ea14Schristos */ 891*3d25ea14Schristos if (len < 8) 892*3d25ea14Schristos goto corrupt; 893*3d25ea14Schristos /* service */ 894*3d25ea14Schristos ND_TCHECK2(*cp, 4); 895*3d25ea14Schristos ND_PRINT((ndo, ", service %u", EXTRACT_32BITS(cp))); 896*3d25ea14Schristos cp += 4; 897*3d25ea14Schristos /* data */ 898*3d25ea14Schristos ND_PRINT((ndo, ", data '")); 899*3d25ea14Schristos if (fn_printn(ndo, cp, len - 8, ep)) { 900*3d25ea14Schristos ND_PRINT((ndo, "'")); 901*3d25ea14Schristos goto trunc; 902*3d25ea14Schristos } 903*3d25ea14Schristos ND_PRINT((ndo, "'")); 904*3d25ea14Schristos cp += len - 8; 905*3d25ea14Schristos break; 906*3d25ea14Schristos case BSN_SHELL_OUTPUT: 907*3d25ea14Schristos /* 908*3d25ea14Schristos * 0 1 2 3 909*3d25ea14Schristos * 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*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 911*3d25ea14Schristos * | subtype | 912*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 913*3d25ea14Schristos * | data ... 914*3d25ea14Schristos * +---------------+---------------+-------- 915*3d25ea14Schristos * 916*3d25ea14Schristos */ 917*3d25ea14Schristos /* already checked that len >= 4 */ 918*3d25ea14Schristos /* data */ 919*3d25ea14Schristos ND_PRINT((ndo, ", data '")); 920*3d25ea14Schristos if (fn_printn(ndo, cp, len - 4, ep)) { 921*3d25ea14Schristos ND_PRINT((ndo, "'")); 922*3d25ea14Schristos goto trunc; 923*3d25ea14Schristos } 924*3d25ea14Schristos ND_PRINT((ndo, "'")); 925*3d25ea14Schristos cp += len - 4; 926*3d25ea14Schristos break; 927*3d25ea14Schristos case BSN_SHELL_STATUS: 928*3d25ea14Schristos /* 929*3d25ea14Schristos * 0 1 2 3 930*3d25ea14Schristos * 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*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 932*3d25ea14Schristos * | subtype | 933*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 934*3d25ea14Schristos * | status | 935*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 936*3d25ea14Schristos * 937*3d25ea14Schristos */ 938*3d25ea14Schristos if (len != 8) 939*3d25ea14Schristos goto corrupt; 940*3d25ea14Schristos /* status */ 941*3d25ea14Schristos ND_TCHECK2(*cp, 4); 942*3d25ea14Schristos ND_PRINT((ndo, ", status 0x%08x", EXTRACT_32BITS(cp))); 943*3d25ea14Schristos cp += 4; 944*3d25ea14Schristos break; 945*3d25ea14Schristos default: 946*3d25ea14Schristos ND_TCHECK2(*cp, len - 4); 947*3d25ea14Schristos cp += len - 4; 948*3d25ea14Schristos } 949*3d25ea14Schristos return cp; 950*3d25ea14Schristos 951*3d25ea14Schristos corrupt: /* skip the undersized data */ 952*3d25ea14Schristos ND_PRINT((ndo, "%s", cstr)); 953*3d25ea14Schristos ND_TCHECK2(*cp0, len); 954*3d25ea14Schristos return cp0 + len; 955*3d25ea14Schristos trunc: 956*3d25ea14Schristos ND_PRINT((ndo, "%s", tstr)); 957*3d25ea14Schristos return ep; 958*3d25ea14Schristos } 959*3d25ea14Schristos 960*3d25ea14Schristos static const u_char * 961*3d25ea14Schristos of10_bsn_actions_print(netdissect_options *ndo, 962*3d25ea14Schristos const u_char *cp, const u_char *ep, const u_int len) 963*3d25ea14Schristos { 964*3d25ea14Schristos const u_char *cp0 = cp; 965*3d25ea14Schristos uint32_t subtype, vlan_tag; 966*3d25ea14Schristos 967*3d25ea14Schristos if (len < 4) 968*3d25ea14Schristos goto corrupt; 969*3d25ea14Schristos /* subtype */ 970*3d25ea14Schristos ND_TCHECK2(*cp, 4); 971*3d25ea14Schristos subtype = EXTRACT_32BITS(cp); 972*3d25ea14Schristos cp += 4; 973*3d25ea14Schristos ND_PRINT((ndo, "\n\t subtype %s", tok2str(bsn_action_subtype_str, "unknown (0x%08x)", subtype))); 974*3d25ea14Schristos switch (subtype) { 975*3d25ea14Schristos case BSN_ACTION_MIRROR: 976*3d25ea14Schristos /* 977*3d25ea14Schristos * 0 1 2 3 978*3d25ea14Schristos * 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*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 980*3d25ea14Schristos * | subtype | 981*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 982*3d25ea14Schristos * | dest_port | 983*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 984*3d25ea14Schristos * | vlan_tag | 985*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 986*3d25ea14Schristos * | copy_stage | pad | 987*3d25ea14Schristos * +---------------+---------------+---------------+---------------+ 988*3d25ea14Schristos * 989*3d25ea14Schristos */ 990*3d25ea14Schristos if (len != 16) 991*3d25ea14Schristos goto corrupt; 992*3d25ea14Schristos /* dest_port */ 993*3d25ea14Schristos ND_TCHECK2(*cp, 4); 994*3d25ea14Schristos ND_PRINT((ndo, ", dest_port %u", EXTRACT_32BITS(cp))); 995*3d25ea14Schristos cp += 4; 996*3d25ea14Schristos /* vlan_tag */ 997*3d25ea14Schristos ND_TCHECK2(*cp, 4); 998*3d25ea14Schristos vlan_tag = EXTRACT_32BITS(cp); 999*3d25ea14Schristos cp += 4; 1000*3d25ea14Schristos switch (vlan_tag >> 16) { 1001*3d25ea14Schristos case 0: 1002*3d25ea14Schristos ND_PRINT((ndo, ", vlan_tag none")); 1003*3d25ea14Schristos break; 1004*3d25ea14Schristos case ETHERTYPE_8021Q: 1005*3d25ea14Schristos ND_PRINT((ndo, ", vlan_tag 802.1Q (%s)", ieee8021q_tci_string(vlan_tag & 0xffff))); 1006*3d25ea14Schristos break; 1007*3d25ea14Schristos default: 1008*3d25ea14Schristos ND_PRINT((ndo, ", vlan_tag unknown (0x%04x)", vlan_tag >> 16)); 1009*3d25ea14Schristos } 1010*3d25ea14Schristos /* copy_stage */ 1011*3d25ea14Schristos ND_TCHECK2(*cp, 1); 1012*3d25ea14Schristos ND_PRINT((ndo, ", copy_stage %s", tok2str(bsn_mirror_copy_stage_str, "unknown (%u)", *cp))); 1013*3d25ea14Schristos cp += 1; 1014*3d25ea14Schristos /* pad */ 1015*3d25ea14Schristos ND_TCHECK2(*cp, 3); 1016*3d25ea14Schristos cp += 3; 1017*3d25ea14Schristos break; 1018*3d25ea14Schristos default: 1019*3d25ea14Schristos ND_TCHECK2(*cp, len - 4); 1020*3d25ea14Schristos cp += len - 4; 1021*3d25ea14Schristos } 1022*3d25ea14Schristos 1023*3d25ea14Schristos return cp; 1024*3d25ea14Schristos 1025*3d25ea14Schristos corrupt: 1026*3d25ea14Schristos ND_PRINT((ndo, "%s", cstr)); 1027*3d25ea14Schristos ND_TCHECK2(*cp0, len); 1028*3d25ea14Schristos return cp0 + len; 1029*3d25ea14Schristos trunc: 1030*3d25ea14Schristos ND_PRINT((ndo, "%s", tstr)); 1031*3d25ea14Schristos return ep; 1032*3d25ea14Schristos } 1033*3d25ea14Schristos 1034*3d25ea14Schristos static const u_char * 1035*3d25ea14Schristos of10_vendor_action_print(netdissect_options *ndo, 1036*3d25ea14Schristos const u_char *cp, const u_char *ep, const u_int len) 1037*3d25ea14Schristos { 1038*3d25ea14Schristos uint32_t vendor; 1039*3d25ea14Schristos const u_char *(*decoder)(netdissect_options *, const u_char *, const u_char *, const u_int); 1040*3d25ea14Schristos 1041026d7285Schristos if (len < 4) 1042026d7285Schristos goto corrupt; 1043026d7285Schristos /* vendor */ 1044c47fd378Schristos ND_TCHECK2(*cp, 4); 1045*3d25ea14Schristos vendor = EXTRACT_32BITS(cp); 1046026d7285Schristos cp += 4; 1047*3d25ea14Schristos ND_PRINT((ndo, ", vendor 0x%08x (%s)", vendor, of_vendor_name(vendor))); 1048*3d25ea14Schristos /* data */ 1049*3d25ea14Schristos decoder = 1050*3d25ea14Schristos vendor == OUI_BSN ? of10_bsn_actions_print : 1051*3d25ea14Schristos of10_data_print; 1052*3d25ea14Schristos return decoder(ndo, cp, ep, len - 4); 1053*3d25ea14Schristos 1054*3d25ea14Schristos corrupt: /* skip the undersized data */ 1055*3d25ea14Schristos ND_PRINT((ndo, "%s", cstr)); 1056*3d25ea14Schristos ND_TCHECK2(*cp, len); 1057*3d25ea14Schristos return cp + len; 1058*3d25ea14Schristos trunc: 1059*3d25ea14Schristos ND_PRINT((ndo, "%s", tstr)); 1060*3d25ea14Schristos return ep; 1061*3d25ea14Schristos } 1062*3d25ea14Schristos 1063*3d25ea14Schristos static const u_char * 1064*3d25ea14Schristos of10_vendor_message_print(netdissect_options *ndo, 1065*3d25ea14Schristos const u_char *cp, const u_char *ep, const u_int len) 1066*3d25ea14Schristos { 1067*3d25ea14Schristos uint32_t vendor; 1068*3d25ea14Schristos const u_char *(*decoder)(netdissect_options *, const u_char *, const u_char *, u_int); 1069*3d25ea14Schristos 1070*3d25ea14Schristos if (len < 4) 1071*3d25ea14Schristos goto corrupt; 1072*3d25ea14Schristos /* vendor */ 1073*3d25ea14Schristos ND_TCHECK2(*cp, 4); 1074*3d25ea14Schristos vendor = EXTRACT_32BITS(cp); 1075*3d25ea14Schristos cp += 4; 1076*3d25ea14Schristos ND_PRINT((ndo, ", vendor 0x%08x (%s)", vendor, of_vendor_name(vendor))); 1077*3d25ea14Schristos /* data */ 1078*3d25ea14Schristos decoder = 1079*3d25ea14Schristos vendor == OUI_BSN ? of10_bsn_message_print : 1080*3d25ea14Schristos of10_data_print; 1081*3d25ea14Schristos return decoder(ndo, cp, ep, len - 4); 1082*3d25ea14Schristos 1083*3d25ea14Schristos corrupt: /* skip the undersized data */ 1084*3d25ea14Schristos ND_PRINT((ndo, "%s", cstr)); 1085*3d25ea14Schristos ND_TCHECK2(*cp, len); 1086*3d25ea14Schristos return cp + len; 1087*3d25ea14Schristos trunc: 1088*3d25ea14Schristos ND_PRINT((ndo, "%s", tstr)); 1089*3d25ea14Schristos return ep; 1090*3d25ea14Schristos } 1091*3d25ea14Schristos 1092*3d25ea14Schristos /* Vendor ID is mandatory, data is optional. */ 1093*3d25ea14Schristos static const u_char * 1094*3d25ea14Schristos of10_vendor_data_print(netdissect_options *ndo, 1095*3d25ea14Schristos const u_char *cp, const u_char *ep, const u_int len) 1096*3d25ea14Schristos { 1097*3d25ea14Schristos uint32_t vendor; 1098*3d25ea14Schristos 1099*3d25ea14Schristos if (len < 4) 1100*3d25ea14Schristos goto corrupt; 1101*3d25ea14Schristos /* vendor */ 1102*3d25ea14Schristos ND_TCHECK2(*cp, 4); 1103*3d25ea14Schristos vendor = EXTRACT_32BITS(cp); 1104*3d25ea14Schristos cp += 4; 1105*3d25ea14Schristos ND_PRINT((ndo, ", vendor 0x%08x (%s)", vendor, of_vendor_name(vendor))); 1106026d7285Schristos /* data */ 1107c47fd378Schristos return of10_data_print(ndo, cp, ep, len - 4); 1108026d7285Schristos 1109026d7285Schristos corrupt: /* skip the undersized data */ 1110c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 1111c47fd378Schristos ND_TCHECK2(*cp, len); 1112026d7285Schristos return cp + len; 1113026d7285Schristos trunc: 1114c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 1115026d7285Schristos return ep; 1116026d7285Schristos } 1117026d7285Schristos 1118026d7285Schristos static const u_char * 1119c47fd378Schristos of10_packet_data_print(netdissect_options *ndo, 1120*3d25ea14Schristos const u_char *cp, const u_char *ep, const u_int len) 1121*3d25ea14Schristos { 1122026d7285Schristos if (len == 0) 1123026d7285Schristos return cp; 1124026d7285Schristos /* data */ 1125c47fd378Schristos ND_PRINT((ndo, "\n\t data (%u octets)", len)); 1126c47fd378Schristos if (ndo->ndo_vflag < 3) 1127026d7285Schristos return cp + len; 1128c47fd378Schristos ND_TCHECK2(*cp, len); 1129c47fd378Schristos ndo->ndo_vflag -= 3; 1130c47fd378Schristos ND_PRINT((ndo, ", frame decoding below\n")); 1131c47fd378Schristos ether_print(ndo, cp, len, ndo->ndo_snapend - cp, NULL, NULL); 1132c47fd378Schristos ndo->ndo_vflag += 3; 1133026d7285Schristos return cp + len; 1134026d7285Schristos 1135026d7285Schristos trunc: 1136c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 1137026d7285Schristos return ep; 1138026d7285Schristos } 1139026d7285Schristos 1140026d7285Schristos /* [OF10] Section 5.2.1 */ 1141026d7285Schristos static const u_char * 1142c47fd378Schristos of10_phy_ports_print(netdissect_options *ndo, 1143*3d25ea14Schristos const u_char *cp, const u_char *ep, u_int len) 1144*3d25ea14Schristos { 1145026d7285Schristos const u_char *cp0 = cp; 1146026d7285Schristos const u_int len0 = len; 1147026d7285Schristos 1148026d7285Schristos while (len) { 1149026d7285Schristos if (len < OF_PHY_PORT_LEN) 1150026d7285Schristos goto corrupt; 1151026d7285Schristos /* port_no */ 1152c47fd378Schristos ND_TCHECK2(*cp, 2); 1153c47fd378Schristos ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp)))); 1154026d7285Schristos cp += 2; 1155026d7285Schristos /* hw_addr */ 1156c47fd378Schristos ND_TCHECK2(*cp, ETHER_ADDR_LEN); 1157c47fd378Schristos ND_PRINT((ndo, ", hw_addr %s", etheraddr_string(ndo, cp))); 1158c47fd378Schristos cp += ETHER_ADDR_LEN; 1159026d7285Schristos /* name */ 1160c47fd378Schristos ND_TCHECK2(*cp, OFP_MAX_PORT_NAME_LEN); 1161c47fd378Schristos ND_PRINT((ndo, ", name '")); 1162c47fd378Schristos fn_print(ndo, cp, cp + OFP_MAX_PORT_NAME_LEN); 1163c47fd378Schristos ND_PRINT((ndo, "'")); 1164026d7285Schristos cp += OFP_MAX_PORT_NAME_LEN; 1165026d7285Schristos 1166c47fd378Schristos if (ndo->ndo_vflag < 2) { 1167c47fd378Schristos ND_TCHECK2(*cp, 24); 1168026d7285Schristos cp += 24; 1169026d7285Schristos goto next_port; 1170026d7285Schristos } 1171026d7285Schristos /* config */ 1172c47fd378Schristos ND_TCHECK2(*cp, 4); 1173c47fd378Schristos ND_PRINT((ndo, "\n\t config 0x%08x", EXTRACT_32BITS(cp))); 1174c47fd378Schristos of10_bitmap_print(ndo, ofppc_bm, EXTRACT_32BITS(cp), OFPPC_U); 1175026d7285Schristos cp += 4; 1176026d7285Schristos /* state */ 1177c47fd378Schristos ND_TCHECK2(*cp, 4); 1178c47fd378Schristos ND_PRINT((ndo, "\n\t state 0x%08x", EXTRACT_32BITS(cp))); 1179c47fd378Schristos of10_bitmap_print(ndo, ofpps_bm, EXTRACT_32BITS(cp), OFPPS_U); 1180026d7285Schristos cp += 4; 1181026d7285Schristos /* curr */ 1182c47fd378Schristos ND_TCHECK2(*cp, 4); 1183c47fd378Schristos ND_PRINT((ndo, "\n\t curr 0x%08x", EXTRACT_32BITS(cp))); 1184c47fd378Schristos of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U); 1185026d7285Schristos cp += 4; 1186026d7285Schristos /* advertised */ 1187c47fd378Schristos ND_TCHECK2(*cp, 4); 1188c47fd378Schristos ND_PRINT((ndo, "\n\t advertised 0x%08x", EXTRACT_32BITS(cp))); 1189c47fd378Schristos of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U); 1190026d7285Schristos cp += 4; 1191026d7285Schristos /* supported */ 1192c47fd378Schristos ND_TCHECK2(*cp, 4); 1193c47fd378Schristos ND_PRINT((ndo, "\n\t supported 0x%08x", EXTRACT_32BITS(cp))); 1194c47fd378Schristos of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U); 1195026d7285Schristos cp += 4; 1196026d7285Schristos /* peer */ 1197c47fd378Schristos ND_TCHECK2(*cp, 4); 1198c47fd378Schristos ND_PRINT((ndo, "\n\t peer 0x%08x", EXTRACT_32BITS(cp))); 1199c47fd378Schristos of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U); 1200026d7285Schristos cp += 4; 1201026d7285Schristos next_port: 1202026d7285Schristos len -= OF_PHY_PORT_LEN; 1203026d7285Schristos } /* while */ 1204026d7285Schristos return cp; 1205026d7285Schristos 1206026d7285Schristos corrupt: /* skip the undersized trailing data */ 1207c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 1208c47fd378Schristos ND_TCHECK2(*cp0, len0); 1209026d7285Schristos return cp0 + len0; 1210026d7285Schristos trunc: 1211c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 1212026d7285Schristos return ep; 1213026d7285Schristos } 1214026d7285Schristos 1215026d7285Schristos /* [OF10] Section 5.2.2 */ 1216026d7285Schristos static const u_char * 1217c47fd378Schristos of10_queue_props_print(netdissect_options *ndo, 1218*3d25ea14Schristos const u_char *cp, const u_char *ep, u_int len) 1219*3d25ea14Schristos { 1220026d7285Schristos const u_char *cp0 = cp; 1221026d7285Schristos const u_int len0 = len; 1222026d7285Schristos uint16_t property, plen, rate; 1223026d7285Schristos 1224026d7285Schristos while (len) { 1225026d7285Schristos u_char plen_bogus = 0, skip = 0; 1226026d7285Schristos 1227026d7285Schristos if (len < OF_QUEUE_PROP_HEADER_LEN) 1228026d7285Schristos goto corrupt; 1229026d7285Schristos /* property */ 1230c47fd378Schristos ND_TCHECK2(*cp, 2); 1231026d7285Schristos property = EXTRACT_16BITS(cp); 1232026d7285Schristos cp += 2; 1233c47fd378Schristos ND_PRINT((ndo, "\n\t property %s", tok2str(ofpqt_str, "invalid (0x%04x)", property))); 1234026d7285Schristos /* len */ 1235c47fd378Schristos ND_TCHECK2(*cp, 2); 1236026d7285Schristos plen = EXTRACT_16BITS(cp); 1237026d7285Schristos cp += 2; 1238c47fd378Schristos ND_PRINT((ndo, ", len %u", plen)); 1239026d7285Schristos if (plen < OF_QUEUE_PROP_HEADER_LEN || plen > len) 1240026d7285Schristos goto corrupt; 1241026d7285Schristos /* pad */ 1242c47fd378Schristos ND_TCHECK2(*cp, 4); 1243026d7285Schristos cp += 4; 1244026d7285Schristos /* property-specific constraints and decoding */ 1245026d7285Schristos switch (property) { 1246026d7285Schristos case OFPQT_NONE: 1247026d7285Schristos plen_bogus = plen != OF_QUEUE_PROP_HEADER_LEN; 1248026d7285Schristos break; 1249026d7285Schristos case OFPQT_MIN_RATE: 1250026d7285Schristos plen_bogus = plen != OF_QUEUE_PROP_MIN_RATE_LEN; 1251026d7285Schristos break; 1252026d7285Schristos default: 1253026d7285Schristos skip = 1; 1254026d7285Schristos } 1255026d7285Schristos if (plen_bogus) { 1256c47fd378Schristos ND_PRINT((ndo, " (bogus)")); 1257026d7285Schristos skip = 1; 1258026d7285Schristos } 1259026d7285Schristos if (skip) { 1260c47fd378Schristos ND_TCHECK2(*cp, plen - 4); 1261026d7285Schristos cp += plen - 4; 1262026d7285Schristos goto next_property; 1263026d7285Schristos } 1264026d7285Schristos if (property == OFPQT_MIN_RATE) { /* the only case of property decoding */ 1265026d7285Schristos /* rate */ 1266c47fd378Schristos ND_TCHECK2(*cp, 2); 1267026d7285Schristos rate = EXTRACT_16BITS(cp); 1268026d7285Schristos cp += 2; 1269026d7285Schristos if (rate > 1000) 1270c47fd378Schristos ND_PRINT((ndo, ", rate disabled")); 1271026d7285Schristos else 1272c47fd378Schristos ND_PRINT((ndo, ", rate %u.%u%%", rate / 10, rate % 10)); 1273026d7285Schristos /* pad */ 1274c47fd378Schristos ND_TCHECK2(*cp, 6); 1275026d7285Schristos cp += 6; 1276026d7285Schristos } 1277026d7285Schristos next_property: 1278026d7285Schristos len -= plen; 1279026d7285Schristos } /* while */ 1280026d7285Schristos return cp; 1281026d7285Schristos 1282026d7285Schristos corrupt: /* skip the rest of queue properties */ 1283c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 1284c47fd378Schristos ND_TCHECK2(*cp0, len0); 1285026d7285Schristos return cp0 + len0; 1286026d7285Schristos trunc: 1287c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 1288026d7285Schristos return ep; 1289026d7285Schristos } 1290026d7285Schristos 1291026d7285Schristos /* ibid */ 1292026d7285Schristos static const u_char * 1293c47fd378Schristos of10_queues_print(netdissect_options *ndo, 1294*3d25ea14Schristos const u_char *cp, const u_char *ep, u_int len) 1295*3d25ea14Schristos { 1296026d7285Schristos const u_char *cp0 = cp; 1297026d7285Schristos const u_int len0 = len; 1298026d7285Schristos uint16_t desclen; 1299026d7285Schristos 1300026d7285Schristos while (len) { 1301026d7285Schristos if (len < OF_PACKET_QUEUE_LEN) 1302026d7285Schristos goto corrupt; 1303026d7285Schristos /* queue_id */ 1304c47fd378Schristos ND_TCHECK2(*cp, 4); 1305c47fd378Schristos ND_PRINT((ndo, "\n\t queue_id %u", EXTRACT_32BITS(cp))); 1306026d7285Schristos cp += 4; 1307026d7285Schristos /* len */ 1308c47fd378Schristos ND_TCHECK2(*cp, 2); 1309026d7285Schristos desclen = EXTRACT_16BITS(cp); 1310026d7285Schristos cp += 2; 1311c47fd378Schristos ND_PRINT((ndo, ", len %u", desclen)); 1312026d7285Schristos if (desclen < OF_PACKET_QUEUE_LEN || desclen > len) 1313026d7285Schristos goto corrupt; 1314026d7285Schristos /* pad */ 1315c47fd378Schristos ND_TCHECK2(*cp, 2); 1316026d7285Schristos cp += 2; 1317026d7285Schristos /* properties */ 1318c47fd378Schristos if (ndo->ndo_vflag < 2) { 1319c47fd378Schristos ND_TCHECK2(*cp, desclen - OF_PACKET_QUEUE_LEN); 1320026d7285Schristos cp += desclen - OF_PACKET_QUEUE_LEN; 1321026d7285Schristos goto next_queue; 1322026d7285Schristos } 1323c47fd378Schristos if (ep == (cp = of10_queue_props_print(ndo, cp, ep, desclen - OF_PACKET_QUEUE_LEN))) 1324026d7285Schristos return ep; /* end of snapshot */ 1325026d7285Schristos next_queue: 1326026d7285Schristos len -= desclen; 1327026d7285Schristos } /* while */ 1328026d7285Schristos return cp; 1329026d7285Schristos 1330026d7285Schristos corrupt: /* skip the rest of queues */ 1331c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 1332c47fd378Schristos ND_TCHECK2(*cp0, len0); 1333026d7285Schristos return cp0 + len0; 1334026d7285Schristos trunc: 1335c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 1336026d7285Schristos return ep; 1337026d7285Schristos } 1338026d7285Schristos 1339026d7285Schristos /* [OF10] Section 5.2.3 */ 1340026d7285Schristos static const u_char * 1341c47fd378Schristos of10_match_print(netdissect_options *ndo, 1342*3d25ea14Schristos const char *pfx, const u_char *cp, const u_char *ep) 1343*3d25ea14Schristos { 1344026d7285Schristos uint32_t wildcards; 1345026d7285Schristos uint16_t dl_type; 1346026d7285Schristos uint8_t nw_proto; 1347026d7285Schristos u_char nw_bits; 1348026d7285Schristos const char *field_name; 1349026d7285Schristos 1350026d7285Schristos /* wildcards */ 1351c47fd378Schristos ND_TCHECK2(*cp, 4); 1352026d7285Schristos wildcards = EXTRACT_32BITS(cp); 1353026d7285Schristos if (wildcards & OFPFW_U) 1354c47fd378Schristos ND_PRINT((ndo, "%swildcards 0x%08x (bogus)", pfx, wildcards)); 1355026d7285Schristos cp += 4; 1356026d7285Schristos /* in_port */ 1357c47fd378Schristos ND_TCHECK2(*cp, 2); 1358026d7285Schristos if (! (wildcards & OFPFW_IN_PORT)) 1359c47fd378Schristos ND_PRINT((ndo, "%smatch in_port %s", pfx, tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp)))); 1360026d7285Schristos cp += 2; 1361026d7285Schristos /* dl_src */ 1362c47fd378Schristos ND_TCHECK2(*cp, ETHER_ADDR_LEN); 1363026d7285Schristos if (! (wildcards & OFPFW_DL_SRC)) 1364c47fd378Schristos ND_PRINT((ndo, "%smatch dl_src %s", pfx, etheraddr_string(ndo, cp))); 1365c47fd378Schristos cp += ETHER_ADDR_LEN; 1366026d7285Schristos /* dl_dst */ 1367c47fd378Schristos ND_TCHECK2(*cp, ETHER_ADDR_LEN); 1368026d7285Schristos if (! (wildcards & OFPFW_DL_DST)) 1369c47fd378Schristos ND_PRINT((ndo, "%smatch dl_dst %s", pfx, etheraddr_string(ndo, cp))); 1370c47fd378Schristos cp += ETHER_ADDR_LEN; 1371026d7285Schristos /* dl_vlan */ 1372c47fd378Schristos ND_TCHECK2(*cp, 2); 1373026d7285Schristos if (! (wildcards & OFPFW_DL_VLAN)) 1374c47fd378Schristos ND_PRINT((ndo, "%smatch dl_vlan %s", pfx, vlan_str(EXTRACT_16BITS(cp)))); 1375026d7285Schristos cp += 2; 1376026d7285Schristos /* dl_vlan_pcp */ 1377c47fd378Schristos ND_TCHECK2(*cp, 1); 1378026d7285Schristos if (! (wildcards & OFPFW_DL_VLAN_PCP)) 1379c47fd378Schristos ND_PRINT((ndo, "%smatch dl_vlan_pcp %s", pfx, pcp_str(*cp))); 1380026d7285Schristos cp += 1; 1381026d7285Schristos /* pad1 */ 1382c47fd378Schristos ND_TCHECK2(*cp, 1); 1383026d7285Schristos cp += 1; 1384026d7285Schristos /* dl_type */ 1385c47fd378Schristos ND_TCHECK2(*cp, 2); 1386026d7285Schristos dl_type = EXTRACT_16BITS(cp); 1387026d7285Schristos cp += 2; 1388026d7285Schristos if (! (wildcards & OFPFW_DL_TYPE)) 1389c47fd378Schristos ND_PRINT((ndo, "%smatch dl_type 0x%04x", pfx, dl_type)); 1390026d7285Schristos /* nw_tos */ 1391c47fd378Schristos ND_TCHECK2(*cp, 1); 1392026d7285Schristos if (! (wildcards & OFPFW_NW_TOS)) 1393c47fd378Schristos ND_PRINT((ndo, "%smatch nw_tos 0x%02x", pfx, *cp)); 1394026d7285Schristos cp += 1; 1395026d7285Schristos /* nw_proto */ 1396c47fd378Schristos ND_TCHECK2(*cp, 1); 1397026d7285Schristos nw_proto = *cp; 1398026d7285Schristos cp += 1; 1399026d7285Schristos if (! (wildcards & OFPFW_NW_PROTO)) { 1400026d7285Schristos field_name = ! (wildcards & OFPFW_DL_TYPE) && dl_type == ETHERTYPE_ARP 1401026d7285Schristos ? "arp_opcode" : "nw_proto"; 1402c47fd378Schristos ND_PRINT((ndo, "%smatch %s %u", pfx, field_name, nw_proto)); 1403026d7285Schristos } 1404026d7285Schristos /* pad2 */ 1405c47fd378Schristos ND_TCHECK2(*cp, 2); 1406026d7285Schristos cp += 2; 1407026d7285Schristos /* nw_src */ 1408c47fd378Schristos ND_TCHECK2(*cp, 4); 1409026d7285Schristos nw_bits = (wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT; 1410026d7285Schristos if (nw_bits < 32) 1411c47fd378Schristos ND_PRINT((ndo, "%smatch nw_src %s/%u", pfx, ipaddr_string(ndo, cp), 32 - nw_bits)); 1412026d7285Schristos cp += 4; 1413026d7285Schristos /* nw_dst */ 1414c47fd378Schristos ND_TCHECK2(*cp, 4); 1415026d7285Schristos nw_bits = (wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT; 1416026d7285Schristos if (nw_bits < 32) 1417c47fd378Schristos ND_PRINT((ndo, "%smatch nw_dst %s/%u", pfx, ipaddr_string(ndo, cp), 32 - nw_bits)); 1418026d7285Schristos cp += 4; 1419026d7285Schristos /* tp_src */ 1420c47fd378Schristos ND_TCHECK2(*cp, 2); 1421026d7285Schristos if (! (wildcards & OFPFW_TP_SRC)) { 1422026d7285Schristos field_name = ! (wildcards & OFPFW_DL_TYPE) && dl_type == ETHERTYPE_IP 1423026d7285Schristos && ! (wildcards & OFPFW_NW_PROTO) && nw_proto == IPPROTO_ICMP 1424026d7285Schristos ? "icmp_type" : "tp_src"; 1425c47fd378Schristos ND_PRINT((ndo, "%smatch %s %u", pfx, field_name, EXTRACT_16BITS(cp))); 1426026d7285Schristos } 1427026d7285Schristos cp += 2; 1428026d7285Schristos /* tp_dst */ 1429c47fd378Schristos ND_TCHECK2(*cp, 2); 1430026d7285Schristos if (! (wildcards & OFPFW_TP_DST)) { 1431026d7285Schristos field_name = ! (wildcards & OFPFW_DL_TYPE) && dl_type == ETHERTYPE_IP 1432026d7285Schristos && ! (wildcards & OFPFW_NW_PROTO) && nw_proto == IPPROTO_ICMP 1433026d7285Schristos ? "icmp_code" : "tp_dst"; 1434c47fd378Schristos ND_PRINT((ndo, "%smatch %s %u", pfx, field_name, EXTRACT_16BITS(cp))); 1435026d7285Schristos } 1436026d7285Schristos return cp + 2; 1437026d7285Schristos 1438026d7285Schristos trunc: 1439c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 1440026d7285Schristos return ep; 1441026d7285Schristos } 1442026d7285Schristos 1443026d7285Schristos /* [OF10] Section 5.2.4 */ 1444026d7285Schristos static const u_char * 1445c47fd378Schristos of10_actions_print(netdissect_options *ndo, 1446c47fd378Schristos const char *pfx, const u_char *cp, const u_char *ep, 1447*3d25ea14Schristos u_int len) 1448*3d25ea14Schristos { 1449026d7285Schristos const u_char *cp0 = cp; 1450026d7285Schristos const u_int len0 = len; 1451026d7285Schristos uint16_t type, alen, output_port; 1452026d7285Schristos 1453026d7285Schristos while (len) { 1454026d7285Schristos u_char alen_bogus = 0, skip = 0; 1455026d7285Schristos 1456026d7285Schristos if (len < OF_ACTION_HEADER_LEN) 1457026d7285Schristos goto corrupt; 1458026d7285Schristos /* type */ 1459c47fd378Schristos ND_TCHECK2(*cp, 2); 1460026d7285Schristos type = EXTRACT_16BITS(cp); 1461026d7285Schristos cp += 2; 1462c47fd378Schristos ND_PRINT((ndo, "%saction type %s", pfx, tok2str(ofpat_str, "invalid (0x%04x)", type))); 1463026d7285Schristos /* length */ 1464c47fd378Schristos ND_TCHECK2(*cp, 2); 1465026d7285Schristos alen = EXTRACT_16BITS(cp); 1466026d7285Schristos cp += 2; 1467c47fd378Schristos ND_PRINT((ndo, ", len %u", alen)); 1468026d7285Schristos /* On action size underrun/overrun skip the rest of the action list. */ 1469026d7285Schristos if (alen < OF_ACTION_HEADER_LEN || alen > len) 1470026d7285Schristos goto corrupt; 1471026d7285Schristos /* On action size inappropriate for the given type or invalid type just skip 1472026d7285Schristos * the current action, as the basic length constraint has been met. */ 1473026d7285Schristos switch (type) { 1474026d7285Schristos case OFPAT_OUTPUT: 1475026d7285Schristos case OFPAT_SET_VLAN_VID: 1476026d7285Schristos case OFPAT_SET_VLAN_PCP: 1477026d7285Schristos case OFPAT_STRIP_VLAN: 1478026d7285Schristos case OFPAT_SET_NW_SRC: 1479026d7285Schristos case OFPAT_SET_NW_DST: 1480026d7285Schristos case OFPAT_SET_NW_TOS: 1481026d7285Schristos case OFPAT_SET_TP_SRC: 1482026d7285Schristos case OFPAT_SET_TP_DST: 1483026d7285Schristos alen_bogus = alen != 8; 1484026d7285Schristos break; 1485026d7285Schristos case OFPAT_SET_DL_SRC: 1486026d7285Schristos case OFPAT_SET_DL_DST: 1487026d7285Schristos case OFPAT_ENQUEUE: 1488026d7285Schristos alen_bogus = alen != 16; 1489026d7285Schristos break; 1490026d7285Schristos case OFPAT_VENDOR: 1491026d7285Schristos alen_bogus = alen % 8 != 0; /* already >= 8 so far */ 1492026d7285Schristos break; 1493026d7285Schristos default: 1494026d7285Schristos skip = 1; 1495026d7285Schristos } 1496026d7285Schristos if (alen_bogus) { 1497c47fd378Schristos ND_PRINT((ndo, " (bogus)")); 1498026d7285Schristos skip = 1; 1499026d7285Schristos } 1500026d7285Schristos if (skip) { 1501c47fd378Schristos ND_TCHECK2(*cp, alen - 4); 1502026d7285Schristos cp += alen - 4; 1503026d7285Schristos goto next_action; 1504026d7285Schristos } 1505026d7285Schristos /* OK to decode the rest of the action structure */ 1506026d7285Schristos switch (type) { 1507026d7285Schristos case OFPAT_OUTPUT: 1508026d7285Schristos /* port */ 1509c47fd378Schristos ND_TCHECK2(*cp, 2); 1510026d7285Schristos output_port = EXTRACT_16BITS(cp); 1511026d7285Schristos cp += 2; 1512c47fd378Schristos ND_PRINT((ndo, ", port %s", tok2str(ofpp_str, "%u", output_port))); 1513026d7285Schristos /* max_len */ 1514c47fd378Schristos ND_TCHECK2(*cp, 2); 1515026d7285Schristos if (output_port == OFPP_CONTROLLER) 1516c47fd378Schristos ND_PRINT((ndo, ", max_len %u", EXTRACT_16BITS(cp))); 1517026d7285Schristos cp += 2; 1518026d7285Schristos break; 1519026d7285Schristos case OFPAT_SET_VLAN_VID: 1520026d7285Schristos /* vlan_vid */ 1521c47fd378Schristos ND_TCHECK2(*cp, 2); 1522c47fd378Schristos ND_PRINT((ndo, ", vlan_vid %s", vlan_str(EXTRACT_16BITS(cp)))); 1523026d7285Schristos cp += 2; 1524026d7285Schristos /* pad */ 1525c47fd378Schristos ND_TCHECK2(*cp, 2); 1526026d7285Schristos cp += 2; 1527026d7285Schristos break; 1528026d7285Schristos case OFPAT_SET_VLAN_PCP: 1529026d7285Schristos /* vlan_pcp */ 1530c47fd378Schristos ND_TCHECK2(*cp, 1); 1531c47fd378Schristos ND_PRINT((ndo, ", vlan_pcp %s", pcp_str(*cp))); 1532026d7285Schristos cp += 1; 1533026d7285Schristos /* pad */ 1534c47fd378Schristos ND_TCHECK2(*cp, 3); 1535026d7285Schristos cp += 3; 1536026d7285Schristos break; 1537026d7285Schristos case OFPAT_SET_DL_SRC: 1538026d7285Schristos case OFPAT_SET_DL_DST: 1539026d7285Schristos /* dl_addr */ 1540c47fd378Schristos ND_TCHECK2(*cp, ETHER_ADDR_LEN); 1541c47fd378Schristos ND_PRINT((ndo, ", dl_addr %s", etheraddr_string(ndo, cp))); 1542c47fd378Schristos cp += ETHER_ADDR_LEN; 1543026d7285Schristos /* pad */ 1544c47fd378Schristos ND_TCHECK2(*cp, 6); 1545026d7285Schristos cp += 6; 1546026d7285Schristos break; 1547026d7285Schristos case OFPAT_SET_NW_SRC: 1548026d7285Schristos case OFPAT_SET_NW_DST: 1549026d7285Schristos /* nw_addr */ 1550c47fd378Schristos ND_TCHECK2(*cp, 4); 1551c47fd378Schristos ND_PRINT((ndo, ", nw_addr %s", ipaddr_string(ndo, cp))); 1552026d7285Schristos cp += 4; 1553026d7285Schristos break; 1554026d7285Schristos case OFPAT_SET_NW_TOS: 1555026d7285Schristos /* nw_tos */ 1556c47fd378Schristos ND_TCHECK2(*cp, 1); 1557c47fd378Schristos ND_PRINT((ndo, ", nw_tos 0x%02x", *cp)); 1558026d7285Schristos cp += 1; 1559026d7285Schristos /* pad */ 1560c47fd378Schristos ND_TCHECK2(*cp, 3); 1561026d7285Schristos cp += 3; 1562026d7285Schristos break; 1563026d7285Schristos case OFPAT_SET_TP_SRC: 1564026d7285Schristos case OFPAT_SET_TP_DST: 1565026d7285Schristos /* nw_tos */ 1566c47fd378Schristos ND_TCHECK2(*cp, 2); 1567c47fd378Schristos ND_PRINT((ndo, ", tp_port %u", EXTRACT_16BITS(cp))); 1568026d7285Schristos cp += 2; 1569026d7285Schristos /* pad */ 1570c47fd378Schristos ND_TCHECK2(*cp, 2); 1571026d7285Schristos cp += 2; 1572026d7285Schristos break; 1573026d7285Schristos case OFPAT_ENQUEUE: 1574026d7285Schristos /* port */ 1575c47fd378Schristos ND_TCHECK2(*cp, 2); 1576c47fd378Schristos ND_PRINT((ndo, ", port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp)))); 1577026d7285Schristos cp += 2; 1578026d7285Schristos /* pad */ 1579c47fd378Schristos ND_TCHECK2(*cp, 6); 1580026d7285Schristos cp += 6; 1581026d7285Schristos /* queue_id */ 1582c47fd378Schristos ND_TCHECK2(*cp, 4); 1583c47fd378Schristos ND_PRINT((ndo, ", queue_id %s", tok2str(ofpq_str, "%u", EXTRACT_32BITS(cp)))); 1584026d7285Schristos cp += 4; 1585026d7285Schristos break; 1586026d7285Schristos case OFPAT_VENDOR: 1587*3d25ea14Schristos if (ep == (cp = of10_vendor_action_print(ndo, cp, ep, alen - 4))) 1588026d7285Schristos return ep; /* end of snapshot */ 1589026d7285Schristos break; 1590026d7285Schristos case OFPAT_STRIP_VLAN: 1591026d7285Schristos /* pad */ 1592c47fd378Schristos ND_TCHECK2(*cp, 4); 1593026d7285Schristos cp += 4; 1594026d7285Schristos break; 1595026d7285Schristos } /* switch */ 1596026d7285Schristos next_action: 1597026d7285Schristos len -= alen; 1598026d7285Schristos } /* while */ 1599026d7285Schristos return cp; 1600026d7285Schristos 1601026d7285Schristos corrupt: /* skip the rest of actions */ 1602c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 1603c47fd378Schristos ND_TCHECK2(*cp0, len0); 1604026d7285Schristos return cp0 + len0; 1605026d7285Schristos trunc: 1606c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 1607026d7285Schristos return ep; 1608026d7285Schristos } 1609026d7285Schristos 1610026d7285Schristos /* [OF10] Section 5.3.1 */ 1611026d7285Schristos static const u_char * 1612c47fd378Schristos of10_features_reply_print(netdissect_options *ndo, 1613*3d25ea14Schristos const u_char *cp, const u_char *ep, const u_int len) 1614*3d25ea14Schristos { 1615026d7285Schristos /* datapath_id */ 1616c47fd378Schristos ND_TCHECK2(*cp, 8); 1617c47fd378Schristos ND_PRINT((ndo, "\n\t dpid 0x%016" PRIx64, EXTRACT_64BITS(cp))); 1618026d7285Schristos cp += 8; 1619026d7285Schristos /* n_buffers */ 1620c47fd378Schristos ND_TCHECK2(*cp, 4); 1621c47fd378Schristos ND_PRINT((ndo, ", n_buffers %u", EXTRACT_32BITS(cp))); 1622026d7285Schristos cp += 4; 1623026d7285Schristos /* n_tables */ 1624c47fd378Schristos ND_TCHECK2(*cp, 1); 1625c47fd378Schristos ND_PRINT((ndo, ", n_tables %u", *cp)); 1626026d7285Schristos cp += 1; 1627026d7285Schristos /* pad */ 1628c47fd378Schristos ND_TCHECK2(*cp, 3); 1629026d7285Schristos cp += 3; 1630026d7285Schristos /* capabilities */ 1631c47fd378Schristos ND_TCHECK2(*cp, 4); 1632c47fd378Schristos ND_PRINT((ndo, "\n\t capabilities 0x%08x", EXTRACT_32BITS(cp))); 1633c47fd378Schristos of10_bitmap_print(ndo, ofp_capabilities_bm, EXTRACT_32BITS(cp), OFPCAP_U); 1634026d7285Schristos cp += 4; 1635026d7285Schristos /* actions */ 1636c47fd378Schristos ND_TCHECK2(*cp, 4); 1637c47fd378Schristos ND_PRINT((ndo, "\n\t actions 0x%08x", EXTRACT_32BITS(cp))); 1638c47fd378Schristos of10_bitmap_print(ndo, ofpat_bm, EXTRACT_32BITS(cp), OFPAT_U); 1639026d7285Schristos cp += 4; 1640026d7285Schristos /* ports */ 1641c47fd378Schristos return of10_phy_ports_print(ndo, cp, ep, len - OF_SWITCH_FEATURES_LEN); 1642026d7285Schristos 1643026d7285Schristos trunc: 1644c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 1645026d7285Schristos return ep; 1646026d7285Schristos } 1647026d7285Schristos 1648026d7285Schristos /* [OF10] Section 5.3.3 */ 1649026d7285Schristos static const u_char * 1650c47fd378Schristos of10_flow_mod_print(netdissect_options *ndo, 1651*3d25ea14Schristos const u_char *cp, const u_char *ep, const u_int len) 1652*3d25ea14Schristos { 1653026d7285Schristos uint16_t command; 1654026d7285Schristos 1655026d7285Schristos /* match */ 1656c47fd378Schristos if (ep == (cp = of10_match_print(ndo, "\n\t ", cp, ep))) 1657026d7285Schristos return ep; /* end of snapshot */ 1658026d7285Schristos /* cookie */ 1659c47fd378Schristos ND_TCHECK2(*cp, 8); 1660c47fd378Schristos ND_PRINT((ndo, "\n\t cookie 0x%016" PRIx64, EXTRACT_64BITS(cp))); 1661026d7285Schristos cp += 8; 1662026d7285Schristos /* command */ 1663c47fd378Schristos ND_TCHECK2(*cp, 2); 1664026d7285Schristos command = EXTRACT_16BITS(cp); 1665c47fd378Schristos ND_PRINT((ndo, ", command %s", tok2str(ofpfc_str, "invalid (0x%04x)", command))); 1666026d7285Schristos cp += 2; 1667026d7285Schristos /* idle_timeout */ 1668c47fd378Schristos ND_TCHECK2(*cp, 2); 1669026d7285Schristos if (EXTRACT_16BITS(cp)) 1670c47fd378Schristos ND_PRINT((ndo, ", idle_timeout %u", EXTRACT_16BITS(cp))); 1671026d7285Schristos cp += 2; 1672026d7285Schristos /* hard_timeout */ 1673c47fd378Schristos ND_TCHECK2(*cp, 2); 1674026d7285Schristos if (EXTRACT_16BITS(cp)) 1675c47fd378Schristos ND_PRINT((ndo, ", hard_timeout %u", EXTRACT_16BITS(cp))); 1676026d7285Schristos cp += 2; 1677026d7285Schristos /* priority */ 1678c47fd378Schristos ND_TCHECK2(*cp, 2); 1679026d7285Schristos if (EXTRACT_16BITS(cp)) 1680c47fd378Schristos ND_PRINT((ndo, ", priority %u", EXTRACT_16BITS(cp))); 1681026d7285Schristos cp += 2; 1682026d7285Schristos /* buffer_id */ 1683c47fd378Schristos ND_TCHECK2(*cp, 4); 1684026d7285Schristos if (command == OFPFC_ADD || command == OFPFC_MODIFY || 1685026d7285Schristos command == OFPFC_MODIFY_STRICT) 1686c47fd378Schristos ND_PRINT((ndo, ", buffer_id %s", tok2str(bufferid_str, "0x%08x", EXTRACT_32BITS(cp)))); 1687026d7285Schristos cp += 4; 1688026d7285Schristos /* out_port */ 1689c47fd378Schristos ND_TCHECK2(*cp, 2); 1690026d7285Schristos if (command == OFPFC_DELETE || command == OFPFC_DELETE_STRICT) 1691c47fd378Schristos ND_PRINT((ndo, ", out_port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp)))); 1692026d7285Schristos cp += 2; 1693026d7285Schristos /* flags */ 1694c47fd378Schristos ND_TCHECK2(*cp, 2); 1695c47fd378Schristos ND_PRINT((ndo, ", flags 0x%04x", EXTRACT_16BITS(cp))); 1696c47fd378Schristos of10_bitmap_print(ndo, ofpff_bm, EXTRACT_16BITS(cp), OFPFF_U); 1697026d7285Schristos cp += 2; 1698026d7285Schristos /* actions */ 1699c47fd378Schristos return of10_actions_print(ndo, "\n\t ", cp, ep, len - OF_FLOW_MOD_LEN); 1700026d7285Schristos 1701026d7285Schristos trunc: 1702c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 1703026d7285Schristos return ep; 1704026d7285Schristos } 1705026d7285Schristos 1706026d7285Schristos /* ibid */ 1707026d7285Schristos static const u_char * 1708c47fd378Schristos of10_port_mod_print(netdissect_options *ndo, 1709*3d25ea14Schristos const u_char *cp, const u_char *ep) 1710*3d25ea14Schristos { 1711026d7285Schristos /* port_no */ 1712c47fd378Schristos ND_TCHECK2(*cp, 2); 1713c47fd378Schristos ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp)))); 1714026d7285Schristos cp += 2; 1715026d7285Schristos /* hw_addr */ 1716c47fd378Schristos ND_TCHECK2(*cp, ETHER_ADDR_LEN); 1717c47fd378Schristos ND_PRINT((ndo, ", hw_addr %s", etheraddr_string(ndo, cp))); 1718c47fd378Schristos cp += ETHER_ADDR_LEN; 1719026d7285Schristos /* config */ 1720c47fd378Schristos ND_TCHECK2(*cp, 4); 1721c47fd378Schristos ND_PRINT((ndo, "\n\t config 0x%08x", EXTRACT_32BITS(cp))); 1722c47fd378Schristos of10_bitmap_print(ndo, ofppc_bm, EXTRACT_32BITS(cp), OFPPC_U); 1723026d7285Schristos cp += 4; 1724026d7285Schristos /* mask */ 1725c47fd378Schristos ND_TCHECK2(*cp, 4); 1726c47fd378Schristos ND_PRINT((ndo, "\n\t mask 0x%08x", EXTRACT_32BITS(cp))); 1727c47fd378Schristos of10_bitmap_print(ndo, ofppc_bm, EXTRACT_32BITS(cp), OFPPC_U); 1728026d7285Schristos cp += 4; 1729026d7285Schristos /* advertise */ 1730c47fd378Schristos ND_TCHECK2(*cp, 4); 1731c47fd378Schristos ND_PRINT((ndo, "\n\t advertise 0x%08x", EXTRACT_32BITS(cp))); 1732c47fd378Schristos of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U); 1733026d7285Schristos cp += 4; 1734026d7285Schristos /* pad */ 1735c47fd378Schristos ND_TCHECK2(*cp, 4); 1736026d7285Schristos return cp + 4; 1737026d7285Schristos 1738026d7285Schristos trunc: 1739c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 1740026d7285Schristos return ep; 1741026d7285Schristos } 1742026d7285Schristos 1743026d7285Schristos /* [OF10] Section 5.3.5 */ 1744026d7285Schristos static const u_char * 1745c47fd378Schristos of10_stats_request_print(netdissect_options *ndo, 1746*3d25ea14Schristos const u_char *cp, const u_char *ep, u_int len) 1747*3d25ea14Schristos { 1748026d7285Schristos const u_char *cp0 = cp; 1749026d7285Schristos const u_int len0 = len; 1750026d7285Schristos uint16_t type; 1751026d7285Schristos 1752026d7285Schristos /* type */ 1753c47fd378Schristos ND_TCHECK2(*cp, 2); 1754026d7285Schristos type = EXTRACT_16BITS(cp); 1755026d7285Schristos cp += 2; 1756c47fd378Schristos ND_PRINT((ndo, "\n\t type %s", tok2str(ofpst_str, "invalid (0x%04x)", type))); 1757026d7285Schristos /* flags */ 1758c47fd378Schristos ND_TCHECK2(*cp, 2); 1759c47fd378Schristos ND_PRINT((ndo, ", flags 0x%04x", EXTRACT_16BITS(cp))); 1760026d7285Schristos if (EXTRACT_16BITS(cp)) 1761c47fd378Schristos ND_PRINT((ndo, " (bogus)")); 1762026d7285Schristos cp += 2; 1763026d7285Schristos /* type-specific body of one of fixed lengths */ 1764026d7285Schristos len -= OF_STATS_REQUEST_LEN; 1765026d7285Schristos switch(type) { 1766026d7285Schristos case OFPST_DESC: 1767026d7285Schristos case OFPST_TABLE: 1768026d7285Schristos if (len) 1769026d7285Schristos goto corrupt; 1770026d7285Schristos return cp; 1771026d7285Schristos case OFPST_FLOW: 1772026d7285Schristos case OFPST_AGGREGATE: 1773026d7285Schristos if (len != OF_FLOW_STATS_REQUEST_LEN) 1774026d7285Schristos goto corrupt; 1775026d7285Schristos /* match */ 1776c47fd378Schristos if (ep == (cp = of10_match_print(ndo, "\n\t ", cp, ep))) 1777026d7285Schristos return ep; /* end of snapshot */ 1778026d7285Schristos /* table_id */ 1779c47fd378Schristos ND_TCHECK2(*cp, 1); 1780c47fd378Schristos ND_PRINT((ndo, "\n\t table_id %s", tok2str(tableid_str, "%u", *cp))); 1781026d7285Schristos cp += 1; 1782026d7285Schristos /* pad */ 1783c47fd378Schristos ND_TCHECK2(*cp, 1); 1784026d7285Schristos cp += 1; 1785026d7285Schristos /* out_port */ 1786c47fd378Schristos ND_TCHECK2(*cp, 2); 1787c47fd378Schristos ND_PRINT((ndo, ", out_port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp)))); 1788026d7285Schristos return cp + 2; 1789026d7285Schristos case OFPST_PORT: 1790026d7285Schristos if (len != OF_PORT_STATS_REQUEST_LEN) 1791026d7285Schristos goto corrupt; 1792026d7285Schristos /* port_no */ 1793c47fd378Schristos ND_TCHECK2(*cp, 2); 1794c47fd378Schristos ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp)))); 1795026d7285Schristos cp += 2; 1796026d7285Schristos /* pad */ 1797c47fd378Schristos ND_TCHECK2(*cp, 6); 1798026d7285Schristos return cp + 6; 1799026d7285Schristos case OFPST_QUEUE: 1800026d7285Schristos if (len != OF_QUEUE_STATS_REQUEST_LEN) 1801026d7285Schristos goto corrupt; 1802026d7285Schristos /* port_no */ 1803c47fd378Schristos ND_TCHECK2(*cp, 2); 1804c47fd378Schristos ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp)))); 1805026d7285Schristos cp += 2; 1806026d7285Schristos /* pad */ 1807c47fd378Schristos ND_TCHECK2(*cp, 2); 1808026d7285Schristos cp += 2; 1809026d7285Schristos /* queue_id */ 1810c47fd378Schristos ND_TCHECK2(*cp, 4); 1811c47fd378Schristos ND_PRINT((ndo, ", queue_id %s", tok2str(ofpq_str, "%u", EXTRACT_32BITS(cp)))); 1812026d7285Schristos return cp + 4; 1813026d7285Schristos case OFPST_VENDOR: 1814c47fd378Schristos return of10_vendor_data_print(ndo, cp, ep, len); 1815026d7285Schristos } 1816026d7285Schristos return cp; 1817026d7285Schristos 1818026d7285Schristos corrupt: /* skip the message body */ 1819c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 1820c47fd378Schristos ND_TCHECK2(*cp0, len0); 1821026d7285Schristos return cp0 + len0; 1822026d7285Schristos trunc: 1823c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 1824026d7285Schristos return ep; 1825026d7285Schristos } 1826026d7285Schristos 1827026d7285Schristos /* ibid */ 1828026d7285Schristos static const u_char * 1829c47fd378Schristos of10_desc_stats_reply_print(netdissect_options *ndo, 1830*3d25ea14Schristos const u_char *cp, const u_char *ep, const u_int len) 1831*3d25ea14Schristos { 1832026d7285Schristos if (len != OF_DESC_STATS_LEN) 1833026d7285Schristos goto corrupt; 1834026d7285Schristos /* mfr_desc */ 1835c47fd378Schristos ND_TCHECK2(*cp, DESC_STR_LEN); 1836c47fd378Schristos ND_PRINT((ndo, "\n\t mfr_desc '")); 1837c47fd378Schristos fn_print(ndo, cp, cp + DESC_STR_LEN); 1838c47fd378Schristos ND_PRINT((ndo, "'")); 1839026d7285Schristos cp += DESC_STR_LEN; 1840026d7285Schristos /* hw_desc */ 1841c47fd378Schristos ND_TCHECK2(*cp, DESC_STR_LEN); 1842c47fd378Schristos ND_PRINT((ndo, "\n\t hw_desc '")); 1843c47fd378Schristos fn_print(ndo, cp, cp + DESC_STR_LEN); 1844c47fd378Schristos ND_PRINT((ndo, "'")); 1845026d7285Schristos cp += DESC_STR_LEN; 1846026d7285Schristos /* sw_desc */ 1847c47fd378Schristos ND_TCHECK2(*cp, DESC_STR_LEN); 1848c47fd378Schristos ND_PRINT((ndo, "\n\t sw_desc '")); 1849c47fd378Schristos fn_print(ndo, cp, cp + DESC_STR_LEN); 1850c47fd378Schristos ND_PRINT((ndo, "'")); 1851026d7285Schristos cp += DESC_STR_LEN; 1852026d7285Schristos /* serial_num */ 1853c47fd378Schristos ND_TCHECK2(*cp, SERIAL_NUM_LEN); 1854c47fd378Schristos ND_PRINT((ndo, "\n\t serial_num '")); 1855c47fd378Schristos fn_print(ndo, cp, cp + SERIAL_NUM_LEN); 1856c47fd378Schristos ND_PRINT((ndo, "'")); 1857026d7285Schristos cp += SERIAL_NUM_LEN; 1858026d7285Schristos /* dp_desc */ 1859c47fd378Schristos ND_TCHECK2(*cp, DESC_STR_LEN); 1860c47fd378Schristos ND_PRINT((ndo, "\n\t dp_desc '")); 1861c47fd378Schristos fn_print(ndo, cp, cp + DESC_STR_LEN); 1862c47fd378Schristos ND_PRINT((ndo, "'")); 1863026d7285Schristos return cp + DESC_STR_LEN; 1864026d7285Schristos 1865026d7285Schristos corrupt: /* skip the message body */ 1866c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 1867c47fd378Schristos ND_TCHECK2(*cp, len); 1868026d7285Schristos return cp + len; 1869026d7285Schristos trunc: 1870c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 1871026d7285Schristos return ep; 1872026d7285Schristos } 1873026d7285Schristos 1874026d7285Schristos /* ibid */ 1875026d7285Schristos static const u_char * 1876c47fd378Schristos of10_flow_stats_reply_print(netdissect_options *ndo, 1877*3d25ea14Schristos const u_char *cp, const u_char *ep, u_int len) 1878*3d25ea14Schristos { 1879026d7285Schristos const u_char *cp0 = cp; 1880026d7285Schristos const u_int len0 = len; 1881026d7285Schristos uint16_t entry_len; 1882026d7285Schristos 1883026d7285Schristos while (len) { 1884026d7285Schristos if (len < OF_FLOW_STATS_LEN) 1885026d7285Schristos goto corrupt; 1886026d7285Schristos /* length */ 1887c47fd378Schristos ND_TCHECK2(*cp, 2); 1888026d7285Schristos entry_len = EXTRACT_16BITS(cp); 1889c47fd378Schristos ND_PRINT((ndo, "\n\t length %u", entry_len)); 1890026d7285Schristos if (entry_len < OF_FLOW_STATS_LEN || entry_len > len) 1891026d7285Schristos goto corrupt; 1892026d7285Schristos cp += 2; 1893026d7285Schristos /* table_id */ 1894c47fd378Schristos ND_TCHECK2(*cp, 1); 1895c47fd378Schristos ND_PRINT((ndo, ", table_id %s", tok2str(tableid_str, "%u", *cp))); 1896026d7285Schristos cp += 1; 1897026d7285Schristos /* pad */ 1898c47fd378Schristos ND_TCHECK2(*cp, 1); 1899026d7285Schristos cp += 1; 1900026d7285Schristos /* match */ 1901c47fd378Schristos if (ep == (cp = of10_match_print(ndo, "\n\t ", cp, ep))) 1902026d7285Schristos return ep; /* end of snapshot */ 1903026d7285Schristos /* duration_sec */ 1904c47fd378Schristos ND_TCHECK2(*cp, 4); 1905c47fd378Schristos ND_PRINT((ndo, "\n\t duration_sec %u", EXTRACT_32BITS(cp))); 1906026d7285Schristos cp += 4; 1907026d7285Schristos /* duration_nsec */ 1908c47fd378Schristos ND_TCHECK2(*cp, 4); 1909c47fd378Schristos ND_PRINT((ndo, ", duration_nsec %u", EXTRACT_32BITS(cp))); 1910026d7285Schristos cp += 4; 1911026d7285Schristos /* priority */ 1912c47fd378Schristos ND_TCHECK2(*cp, 2); 1913c47fd378Schristos ND_PRINT((ndo, ", priority %u", EXTRACT_16BITS(cp))); 1914026d7285Schristos cp += 2; 1915026d7285Schristos /* idle_timeout */ 1916c47fd378Schristos ND_TCHECK2(*cp, 2); 1917c47fd378Schristos ND_PRINT((ndo, ", idle_timeout %u", EXTRACT_16BITS(cp))); 1918026d7285Schristos cp += 2; 1919026d7285Schristos /* hard_timeout */ 1920c47fd378Schristos ND_TCHECK2(*cp, 2); 1921c47fd378Schristos ND_PRINT((ndo, ", hard_timeout %u", EXTRACT_16BITS(cp))); 1922026d7285Schristos cp += 2; 1923026d7285Schristos /* pad2 */ 1924c47fd378Schristos ND_TCHECK2(*cp, 6); 1925026d7285Schristos cp += 6; 1926026d7285Schristos /* cookie */ 1927c47fd378Schristos ND_TCHECK2(*cp, 8); 1928c47fd378Schristos ND_PRINT((ndo, ", cookie 0x%016" PRIx64, EXTRACT_64BITS(cp))); 1929026d7285Schristos cp += 8; 1930026d7285Schristos /* packet_count */ 1931c47fd378Schristos ND_TCHECK2(*cp, 8); 1932c47fd378Schristos ND_PRINT((ndo, ", packet_count %" PRIu64, EXTRACT_64BITS(cp))); 1933026d7285Schristos cp += 8; 1934026d7285Schristos /* byte_count */ 1935c47fd378Schristos ND_TCHECK2(*cp, 8); 1936c47fd378Schristos ND_PRINT((ndo, ", byte_count %" PRIu64, EXTRACT_64BITS(cp))); 1937026d7285Schristos cp += 8; 1938026d7285Schristos /* actions */ 1939c47fd378Schristos if (ep == (cp = of10_actions_print(ndo, "\n\t ", cp, ep, entry_len - OF_FLOW_STATS_LEN))) 1940026d7285Schristos return ep; /* end of snapshot */ 1941026d7285Schristos 1942026d7285Schristos len -= entry_len; 1943026d7285Schristos } /* while */ 1944026d7285Schristos return cp; 1945026d7285Schristos 1946026d7285Schristos corrupt: /* skip the rest of flow statistics entries */ 1947c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 1948c47fd378Schristos ND_TCHECK2(*cp0, len0); 1949026d7285Schristos return cp0 + len0; 1950026d7285Schristos trunc: 1951c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 1952026d7285Schristos return ep; 1953026d7285Schristos } 1954026d7285Schristos 1955026d7285Schristos /* ibid */ 1956026d7285Schristos static const u_char * 1957c47fd378Schristos of10_aggregate_stats_reply_print(netdissect_options *ndo, 1958c47fd378Schristos const u_char *cp, const u_char *ep, 1959*3d25ea14Schristos const u_int len) 1960*3d25ea14Schristos { 1961026d7285Schristos if (len != OF_AGGREGATE_STATS_REPLY_LEN) 1962026d7285Schristos goto corrupt; 1963026d7285Schristos /* packet_count */ 1964c47fd378Schristos ND_TCHECK2(*cp, 8); 1965c47fd378Schristos ND_PRINT((ndo, "\n\t packet_count %" PRIu64, EXTRACT_64BITS(cp))); 1966026d7285Schristos cp += 8; 1967026d7285Schristos /* byte_count */ 1968c47fd378Schristos ND_TCHECK2(*cp, 8); 1969c47fd378Schristos ND_PRINT((ndo, ", byte_count %" PRIu64, EXTRACT_64BITS(cp))); 1970026d7285Schristos cp += 8; 1971026d7285Schristos /* flow_count */ 1972c47fd378Schristos ND_TCHECK2(*cp, 4); 1973c47fd378Schristos ND_PRINT((ndo, ", flow_count %u", EXTRACT_32BITS(cp))); 1974026d7285Schristos cp += 4; 1975026d7285Schristos /* pad */ 1976c47fd378Schristos ND_TCHECK2(*cp, 4); 1977026d7285Schristos return cp + 4; 1978026d7285Schristos 1979026d7285Schristos corrupt: /* skip the message body */ 1980c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 1981c47fd378Schristos ND_TCHECK2(*cp, len); 1982026d7285Schristos return cp + len; 1983026d7285Schristos trunc: 1984c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 1985026d7285Schristos return ep; 1986026d7285Schristos } 1987026d7285Schristos 1988026d7285Schristos /* ibid */ 1989026d7285Schristos static const u_char * 1990c47fd378Schristos of10_table_stats_reply_print(netdissect_options *ndo, 1991*3d25ea14Schristos const u_char *cp, const u_char *ep, u_int len) 1992*3d25ea14Schristos { 1993026d7285Schristos const u_char *cp0 = cp; 1994026d7285Schristos const u_int len0 = len; 1995026d7285Schristos 1996026d7285Schristos while (len) { 1997026d7285Schristos if (len < OF_TABLE_STATS_LEN) 1998026d7285Schristos goto corrupt; 1999026d7285Schristos /* table_id */ 2000c47fd378Schristos ND_TCHECK2(*cp, 1); 2001c47fd378Schristos ND_PRINT((ndo, "\n\t table_id %s", tok2str(tableid_str, "%u", *cp))); 2002026d7285Schristos cp += 1; 2003026d7285Schristos /* pad */ 2004c47fd378Schristos ND_TCHECK2(*cp, 3); 2005026d7285Schristos cp += 3; 2006026d7285Schristos /* name */ 2007c47fd378Schristos ND_TCHECK2(*cp, OFP_MAX_TABLE_NAME_LEN); 2008c47fd378Schristos ND_PRINT((ndo, ", name '")); 2009c47fd378Schristos fn_print(ndo, cp, cp + OFP_MAX_TABLE_NAME_LEN); 2010c47fd378Schristos ND_PRINT((ndo, "'")); 2011026d7285Schristos cp += OFP_MAX_TABLE_NAME_LEN; 2012026d7285Schristos /* wildcards */ 2013c47fd378Schristos ND_TCHECK2(*cp, 4); 2014c47fd378Schristos ND_PRINT((ndo, "\n\t wildcards 0x%08x", EXTRACT_32BITS(cp))); 2015c47fd378Schristos of10_bitmap_print(ndo, ofpfw_bm, EXTRACT_32BITS(cp), OFPFW_U); 2016026d7285Schristos cp += 4; 2017026d7285Schristos /* max_entries */ 2018c47fd378Schristos ND_TCHECK2(*cp, 4); 2019c47fd378Schristos ND_PRINT((ndo, "\n\t max_entries %u", EXTRACT_32BITS(cp))); 2020026d7285Schristos cp += 4; 2021026d7285Schristos /* active_count */ 2022c47fd378Schristos ND_TCHECK2(*cp, 4); 2023c47fd378Schristos ND_PRINT((ndo, ", active_count %u", EXTRACT_32BITS(cp))); 2024026d7285Schristos cp += 4; 2025026d7285Schristos /* lookup_count */ 2026c47fd378Schristos ND_TCHECK2(*cp, 8); 2027c47fd378Schristos ND_PRINT((ndo, ", lookup_count %" PRIu64, EXTRACT_64BITS(cp))); 2028026d7285Schristos cp += 8; 2029026d7285Schristos /* matched_count */ 2030c47fd378Schristos ND_TCHECK2(*cp, 8); 2031c47fd378Schristos ND_PRINT((ndo, ", matched_count %" PRIu64, EXTRACT_64BITS(cp))); 2032026d7285Schristos cp += 8; 2033026d7285Schristos 2034026d7285Schristos len -= OF_TABLE_STATS_LEN; 2035026d7285Schristos } /* while */ 2036026d7285Schristos return cp; 2037026d7285Schristos 2038026d7285Schristos corrupt: /* skip the undersized trailing data */ 2039c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 2040c47fd378Schristos ND_TCHECK2(*cp0, len0); 2041026d7285Schristos return cp0 + len0; 2042026d7285Schristos trunc: 2043c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 2044026d7285Schristos return ep; 2045026d7285Schristos } 2046026d7285Schristos 2047026d7285Schristos /* ibid */ 2048026d7285Schristos static const u_char * 2049c47fd378Schristos of10_port_stats_reply_print(netdissect_options *ndo, 2050*3d25ea14Schristos const u_char *cp, const u_char *ep, u_int len) 2051*3d25ea14Schristos { 2052026d7285Schristos const u_char *cp0 = cp; 2053026d7285Schristos const u_int len0 = len; 2054026d7285Schristos 2055026d7285Schristos while (len) { 2056026d7285Schristos if (len < OF_PORT_STATS_LEN) 2057026d7285Schristos goto corrupt; 2058026d7285Schristos /* port_no */ 2059c47fd378Schristos ND_TCHECK2(*cp, 2); 2060c47fd378Schristos ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp)))); 2061026d7285Schristos cp += 2; 2062c47fd378Schristos if (ndo->ndo_vflag < 2) { 2063c47fd378Schristos ND_TCHECK2(*cp, OF_PORT_STATS_LEN - 2); 2064026d7285Schristos cp += OF_PORT_STATS_LEN - 2; 2065026d7285Schristos goto next_port; 2066026d7285Schristos } 2067026d7285Schristos /* pad */ 2068c47fd378Schristos ND_TCHECK2(*cp, 6); 2069026d7285Schristos cp += 6; 2070026d7285Schristos /* rx_packets */ 2071c47fd378Schristos ND_TCHECK2(*cp, 8); 2072c47fd378Schristos ND_PRINT((ndo, ", rx_packets %" PRIu64, EXTRACT_64BITS(cp))); 2073026d7285Schristos cp += 8; 2074026d7285Schristos /* tx_packets */ 2075c47fd378Schristos ND_TCHECK2(*cp, 8); 2076c47fd378Schristos ND_PRINT((ndo, ", tx_packets %" PRIu64, EXTRACT_64BITS(cp))); 2077026d7285Schristos cp += 8; 2078026d7285Schristos /* rx_bytes */ 2079c47fd378Schristos ND_TCHECK2(*cp, 8); 2080c47fd378Schristos ND_PRINT((ndo, ", rx_bytes %" PRIu64, EXTRACT_64BITS(cp))); 2081026d7285Schristos cp += 8; 2082026d7285Schristos /* tx_bytes */ 2083c47fd378Schristos ND_TCHECK2(*cp, 8); 2084c47fd378Schristos ND_PRINT((ndo, ", tx_bytes %" PRIu64, EXTRACT_64BITS(cp))); 2085026d7285Schristos cp += 8; 2086026d7285Schristos /* rx_dropped */ 2087c47fd378Schristos ND_TCHECK2(*cp, 8); 2088c47fd378Schristos ND_PRINT((ndo, ", rx_dropped %" PRIu64, EXTRACT_64BITS(cp))); 2089026d7285Schristos cp += 8; 2090026d7285Schristos /* tx_dropped */ 2091c47fd378Schristos ND_TCHECK2(*cp, 8); 2092c47fd378Schristos ND_PRINT((ndo, ", tx_dropped %" PRIu64, EXTRACT_64BITS(cp))); 2093026d7285Schristos cp += 8; 2094026d7285Schristos /* rx_errors */ 2095c47fd378Schristos ND_TCHECK2(*cp, 8); 2096c47fd378Schristos ND_PRINT((ndo, ", rx_errors %" PRIu64, EXTRACT_64BITS(cp))); 2097026d7285Schristos cp += 8; 2098026d7285Schristos /* tx_errors */ 2099c47fd378Schristos ND_TCHECK2(*cp, 8); 2100c47fd378Schristos ND_PRINT((ndo, ", tx_errors %" PRIu64, EXTRACT_64BITS(cp))); 2101026d7285Schristos cp += 8; 2102026d7285Schristos /* rx_frame_err */ 2103c47fd378Schristos ND_TCHECK2(*cp, 8); 2104c47fd378Schristos ND_PRINT((ndo, ", rx_frame_err %" PRIu64, EXTRACT_64BITS(cp))); 2105026d7285Schristos cp += 8; 2106026d7285Schristos /* rx_over_err */ 2107c47fd378Schristos ND_TCHECK2(*cp, 8); 2108c47fd378Schristos ND_PRINT((ndo, ", rx_over_err %" PRIu64, EXTRACT_64BITS(cp))); 2109026d7285Schristos cp += 8; 2110026d7285Schristos /* rx_crc_err */ 2111c47fd378Schristos ND_TCHECK2(*cp, 8); 2112c47fd378Schristos ND_PRINT((ndo, ", rx_crc_err %" PRIu64, EXTRACT_64BITS(cp))); 2113026d7285Schristos cp += 8; 2114026d7285Schristos /* collisions */ 2115c47fd378Schristos ND_TCHECK2(*cp, 8); 2116c47fd378Schristos ND_PRINT((ndo, ", collisions %" PRIu64, EXTRACT_64BITS(cp))); 2117026d7285Schristos cp += 8; 2118026d7285Schristos next_port: 2119026d7285Schristos len -= OF_PORT_STATS_LEN; 2120026d7285Schristos } /* while */ 2121026d7285Schristos return cp; 2122026d7285Schristos 2123026d7285Schristos corrupt: /* skip the undersized trailing data */ 2124c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 2125c47fd378Schristos ND_TCHECK2(*cp0, len0); 2126026d7285Schristos return cp0 + len0; 2127026d7285Schristos trunc: 2128c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 2129026d7285Schristos return ep; 2130026d7285Schristos } 2131026d7285Schristos 2132026d7285Schristos /* ibid */ 2133026d7285Schristos static const u_char * 2134c47fd378Schristos of10_queue_stats_reply_print(netdissect_options *ndo, 2135*3d25ea14Schristos const u_char *cp, const u_char *ep, u_int len) 2136*3d25ea14Schristos { 2137026d7285Schristos const u_char *cp0 = cp; 2138026d7285Schristos const u_int len0 = len; 2139026d7285Schristos 2140026d7285Schristos while (len) { 2141026d7285Schristos if (len < OF_QUEUE_STATS_LEN) 2142026d7285Schristos goto corrupt; 2143026d7285Schristos /* port_no */ 2144c47fd378Schristos ND_TCHECK2(*cp, 2); 2145c47fd378Schristos ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp)))); 2146026d7285Schristos cp += 2; 2147026d7285Schristos /* pad */ 2148c47fd378Schristos ND_TCHECK2(*cp, 2); 2149026d7285Schristos cp += 2; 2150026d7285Schristos /* queue_id */ 2151c47fd378Schristos ND_TCHECK2(*cp, 4); 2152c47fd378Schristos ND_PRINT((ndo, ", queue_id %u", EXTRACT_32BITS(cp))); 2153026d7285Schristos cp += 4; 2154026d7285Schristos /* tx_bytes */ 2155c47fd378Schristos ND_TCHECK2(*cp, 8); 2156c47fd378Schristos ND_PRINT((ndo, ", tx_bytes %" PRIu64, EXTRACT_64BITS(cp))); 2157026d7285Schristos cp += 8; 2158026d7285Schristos /* tx_packets */ 2159c47fd378Schristos ND_TCHECK2(*cp, 8); 2160c47fd378Schristos ND_PRINT((ndo, ", tx_packets %" PRIu64, EXTRACT_64BITS(cp))); 2161026d7285Schristos cp += 8; 2162026d7285Schristos /* tx_errors */ 2163c47fd378Schristos ND_TCHECK2(*cp, 8); 2164c47fd378Schristos ND_PRINT((ndo, ", tx_errors %" PRIu64, EXTRACT_64BITS(cp))); 2165026d7285Schristos cp += 8; 2166026d7285Schristos 2167026d7285Schristos len -= OF_QUEUE_STATS_LEN; 2168026d7285Schristos } /* while */ 2169026d7285Schristos return cp; 2170026d7285Schristos 2171026d7285Schristos corrupt: /* skip the undersized trailing data */ 2172c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 2173c47fd378Schristos ND_TCHECK2(*cp0, len0); 2174026d7285Schristos return cp0 + len0; 2175026d7285Schristos trunc: 2176c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 2177026d7285Schristos return ep; 2178026d7285Schristos } 2179026d7285Schristos 2180026d7285Schristos /* ibid */ 2181026d7285Schristos static const u_char * 2182c47fd378Schristos of10_stats_reply_print(netdissect_options *ndo, 2183*3d25ea14Schristos const u_char *cp, const u_char *ep, const u_int len) 2184*3d25ea14Schristos { 2185026d7285Schristos const u_char *cp0 = cp; 2186026d7285Schristos uint16_t type; 2187026d7285Schristos 2188026d7285Schristos /* type */ 2189c47fd378Schristos ND_TCHECK2(*cp, 2); 2190026d7285Schristos type = EXTRACT_16BITS(cp); 2191c47fd378Schristos ND_PRINT((ndo, "\n\t type %s", tok2str(ofpst_str, "invalid (0x%04x)", type))); 2192026d7285Schristos cp += 2; 2193026d7285Schristos /* flags */ 2194c47fd378Schristos ND_TCHECK2(*cp, 2); 2195c47fd378Schristos ND_PRINT((ndo, ", flags 0x%04x", EXTRACT_16BITS(cp))); 2196c47fd378Schristos of10_bitmap_print(ndo, ofpsf_reply_bm, EXTRACT_16BITS(cp), OFPSF_REPLY_U); 2197026d7285Schristos cp += 2; 2198026d7285Schristos 2199c47fd378Schristos if (ndo->ndo_vflag > 0) { 2200c47fd378Schristos const u_char *(*decoder)(netdissect_options *, const u_char *, const u_char *, u_int) = 2201026d7285Schristos type == OFPST_DESC ? of10_desc_stats_reply_print : 2202026d7285Schristos type == OFPST_FLOW ? of10_flow_stats_reply_print : 2203026d7285Schristos type == OFPST_AGGREGATE ? of10_aggregate_stats_reply_print : 2204026d7285Schristos type == OFPST_TABLE ? of10_table_stats_reply_print : 2205026d7285Schristos type == OFPST_PORT ? of10_port_stats_reply_print : 2206026d7285Schristos type == OFPST_QUEUE ? of10_queue_stats_reply_print : 2207026d7285Schristos type == OFPST_VENDOR ? of10_vendor_data_print : 2208026d7285Schristos NULL; 2209026d7285Schristos if (decoder != NULL) 2210c47fd378Schristos return decoder(ndo, cp, ep, len - OF_STATS_REPLY_LEN); 2211026d7285Schristos } 2212c47fd378Schristos ND_TCHECK2(*cp0, len); 2213026d7285Schristos return cp0 + len; 2214026d7285Schristos 2215026d7285Schristos trunc: 2216c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 2217026d7285Schristos return ep; 2218026d7285Schristos } 2219026d7285Schristos 2220026d7285Schristos /* [OF10] Section 5.3.6 */ 2221026d7285Schristos static const u_char * 2222c47fd378Schristos of10_packet_out_print(netdissect_options *ndo, 2223*3d25ea14Schristos const u_char *cp, const u_char *ep, const u_int len) 2224*3d25ea14Schristos { 2225026d7285Schristos const u_char *cp0 = cp; 2226026d7285Schristos const u_int len0 = len; 2227026d7285Schristos uint16_t actions_len; 2228026d7285Schristos 2229026d7285Schristos /* buffer_id */ 2230c47fd378Schristos ND_TCHECK2(*cp, 4); 2231c47fd378Schristos ND_PRINT((ndo, "\n\t buffer_id 0x%08x", EXTRACT_32BITS(cp))); 2232026d7285Schristos cp += 4; 2233026d7285Schristos /* in_port */ 2234c47fd378Schristos ND_TCHECK2(*cp, 2); 2235c47fd378Schristos ND_PRINT((ndo, ", in_port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp)))); 2236026d7285Schristos cp += 2; 2237026d7285Schristos /* actions_len */ 2238c47fd378Schristos ND_TCHECK2(*cp, 2); 2239026d7285Schristos actions_len = EXTRACT_16BITS(cp); 2240026d7285Schristos cp += 2; 2241026d7285Schristos if (actions_len > len - OF_PACKET_OUT_LEN) 2242026d7285Schristos goto corrupt; 2243026d7285Schristos /* actions */ 2244c47fd378Schristos if (ep == (cp = of10_actions_print(ndo, "\n\t ", cp, ep, actions_len))) 2245026d7285Schristos return ep; /* end of snapshot */ 2246026d7285Schristos /* data */ 2247c47fd378Schristos return of10_packet_data_print(ndo, cp, ep, len - OF_PACKET_OUT_LEN - actions_len); 2248026d7285Schristos 2249026d7285Schristos corrupt: /* skip the rest of the message body */ 2250c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 2251c47fd378Schristos ND_TCHECK2(*cp0, len0); 2252026d7285Schristos return cp0 + len0; 2253026d7285Schristos trunc: 2254c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 2255026d7285Schristos return ep; 2256026d7285Schristos } 2257026d7285Schristos 2258026d7285Schristos /* [OF10] Section 5.4.1 */ 2259026d7285Schristos static const u_char * 2260c47fd378Schristos of10_packet_in_print(netdissect_options *ndo, 2261*3d25ea14Schristos const u_char *cp, const u_char *ep, const u_int len) 2262*3d25ea14Schristos { 2263026d7285Schristos /* buffer_id */ 2264c47fd378Schristos ND_TCHECK2(*cp, 4); 2265c47fd378Schristos ND_PRINT((ndo, "\n\t buffer_id %s", tok2str(bufferid_str, "0x%08x", EXTRACT_32BITS(cp)))); 2266026d7285Schristos cp += 4; 2267026d7285Schristos /* total_len */ 2268c47fd378Schristos ND_TCHECK2(*cp, 2); 2269c47fd378Schristos ND_PRINT((ndo, ", total_len %u", EXTRACT_16BITS(cp))); 2270026d7285Schristos cp += 2; 2271026d7285Schristos /* in_port */ 2272c47fd378Schristos ND_TCHECK2(*cp, 2); 2273c47fd378Schristos ND_PRINT((ndo, ", in_port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp)))); 2274026d7285Schristos cp += 2; 2275026d7285Schristos /* reason */ 2276c47fd378Schristos ND_TCHECK2(*cp, 1); 2277c47fd378Schristos ND_PRINT((ndo, ", reason %s", tok2str(ofpr_str, "invalid (0x%02x)", *cp))); 2278026d7285Schristos cp += 1; 2279026d7285Schristos /* pad */ 2280c47fd378Schristos ND_TCHECK2(*cp, 1); 2281026d7285Schristos cp += 1; 2282026d7285Schristos /* data */ 2283026d7285Schristos /* 2 mock octets count in OF_PACKET_IN_LEN but not in len */ 2284c47fd378Schristos return of10_packet_data_print(ndo, cp, ep, len - (OF_PACKET_IN_LEN - 2)); 2285026d7285Schristos 2286026d7285Schristos trunc: 2287c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 2288026d7285Schristos return ep; 2289026d7285Schristos } 2290026d7285Schristos 2291026d7285Schristos /* [OF10] Section 5.4.2 */ 2292026d7285Schristos static const u_char * 2293c47fd378Schristos of10_flow_removed_print(netdissect_options *ndo, 2294*3d25ea14Schristos const u_char *cp, const u_char *ep) 2295*3d25ea14Schristos { 2296026d7285Schristos /* match */ 2297c47fd378Schristos if (ep == (cp = of10_match_print(ndo, "\n\t ", cp, ep))) 2298026d7285Schristos return ep; /* end of snapshot */ 2299026d7285Schristos /* cookie */ 2300c47fd378Schristos ND_TCHECK2(*cp, 8); 2301c47fd378Schristos ND_PRINT((ndo, "\n\t cookie 0x%016" PRIx64, EXTRACT_64BITS(cp))); 2302026d7285Schristos cp += 8; 2303026d7285Schristos /* priority */ 2304c47fd378Schristos ND_TCHECK2(*cp, 2); 2305026d7285Schristos if (EXTRACT_16BITS(cp)) 2306c47fd378Schristos ND_PRINT((ndo, ", priority %u", EXTRACT_16BITS(cp))); 2307026d7285Schristos cp += 2; 2308026d7285Schristos /* reason */ 2309c47fd378Schristos ND_TCHECK2(*cp, 1); 2310c47fd378Schristos ND_PRINT((ndo, ", reason %s", tok2str(ofprr_str, "unknown (0x%02x)", *cp))); 2311026d7285Schristos cp += 1; 2312026d7285Schristos /* pad */ 2313c47fd378Schristos ND_TCHECK2(*cp, 1); 2314026d7285Schristos cp += 1; 2315026d7285Schristos /* duration_sec */ 2316c47fd378Schristos ND_TCHECK2(*cp, 4); 2317c47fd378Schristos ND_PRINT((ndo, ", duration_sec %u", EXTRACT_32BITS(cp))); 2318026d7285Schristos cp += 4; 2319026d7285Schristos /* duration_nsec */ 2320c47fd378Schristos ND_TCHECK2(*cp, 4); 2321c47fd378Schristos ND_PRINT((ndo, ", duration_nsec %u", EXTRACT_32BITS(cp))); 2322026d7285Schristos cp += 4; 2323026d7285Schristos /* idle_timeout */ 2324c47fd378Schristos ND_TCHECK2(*cp, 2); 2325026d7285Schristos if (EXTRACT_16BITS(cp)) 2326c47fd378Schristos ND_PRINT((ndo, ", idle_timeout %u", EXTRACT_16BITS(cp))); 2327026d7285Schristos cp += 2; 2328026d7285Schristos /* pad2 */ 2329c47fd378Schristos ND_TCHECK2(*cp, 2); 2330026d7285Schristos cp += 2; 2331026d7285Schristos /* packet_count */ 2332c47fd378Schristos ND_TCHECK2(*cp, 8); 2333c47fd378Schristos ND_PRINT((ndo, ", packet_count %" PRIu64, EXTRACT_64BITS(cp))); 2334026d7285Schristos cp += 8; 2335026d7285Schristos /* byte_count */ 2336c47fd378Schristos ND_TCHECK2(*cp, 8); 2337c47fd378Schristos ND_PRINT((ndo, ", byte_count %" PRIu64, EXTRACT_64BITS(cp))); 2338026d7285Schristos return cp + 8; 2339026d7285Schristos 2340026d7285Schristos trunc: 2341c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 2342026d7285Schristos return ep; 2343026d7285Schristos } 2344026d7285Schristos 2345026d7285Schristos /* [OF10] Section 5.4.4 */ 2346026d7285Schristos static const u_char * 2347c47fd378Schristos of10_error_print(netdissect_options *ndo, 2348*3d25ea14Schristos const u_char *cp, const u_char *ep, const u_int len) 2349*3d25ea14Schristos { 2350026d7285Schristos uint16_t type; 2351026d7285Schristos const struct tok *code_str; 2352026d7285Schristos 2353026d7285Schristos /* type */ 2354c47fd378Schristos ND_TCHECK2(*cp, 2); 2355026d7285Schristos type = EXTRACT_16BITS(cp); 2356026d7285Schristos cp += 2; 2357c47fd378Schristos ND_PRINT((ndo, "\n\t type %s", tok2str(ofpet_str, "invalid (0x%04x)", type))); 2358026d7285Schristos /* code */ 2359c47fd378Schristos ND_TCHECK2(*cp, 2); 2360026d7285Schristos code_str = 2361026d7285Schristos type == OFPET_HELLO_FAILED ? ofphfc_str : 2362026d7285Schristos type == OFPET_BAD_REQUEST ? ofpbrc_str : 2363026d7285Schristos type == OFPET_BAD_ACTION ? ofpbac_str : 2364026d7285Schristos type == OFPET_FLOW_MOD_FAILED ? ofpfmfc_str : 2365026d7285Schristos type == OFPET_PORT_MOD_FAILED ? ofppmfc_str : 2366026d7285Schristos type == OFPET_QUEUE_OP_FAILED ? ofpqofc_str : 2367026d7285Schristos empty_str; 2368c47fd378Schristos ND_PRINT((ndo, ", code %s", tok2str(code_str, "invalid (0x%04x)", EXTRACT_16BITS(cp)))); 2369026d7285Schristos cp += 2; 2370026d7285Schristos /* data */ 2371c47fd378Schristos return of10_data_print(ndo, cp, ep, len - OF_ERROR_MSG_LEN); 2372026d7285Schristos 2373026d7285Schristos trunc: 2374c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 2375026d7285Schristos return ep; 2376026d7285Schristos } 2377026d7285Schristos 2378026d7285Schristos const u_char * 2379c47fd378Schristos of10_header_body_print(netdissect_options *ndo, 2380c47fd378Schristos const u_char *cp, const u_char *ep, const uint8_t type, 2381*3d25ea14Schristos const uint16_t len, const uint32_t xid) 2382*3d25ea14Schristos { 2383026d7285Schristos const u_char *cp0 = cp; 2384026d7285Schristos const u_int len0 = len; 2385026d7285Schristos /* Thus far message length is not less than the basic header size, but most 2386026d7285Schristos * message types have additional assorted constraints on the length. Wherever 2387026d7285Schristos * possible, check that message length meets the constraint, in remaining 2388026d7285Schristos * cases check that the length is OK to begin decoding and leave any final 2389026d7285Schristos * verification up to a lower-layer function. When the current message is 2390026d7285Schristos * corrupt, proceed to the next message. */ 2391026d7285Schristos 2392026d7285Schristos /* [OF10] Section 5.1 */ 2393c47fd378Schristos ND_PRINT((ndo, "\n\tversion 1.0, type %s, length %u, xid 0x%08x", 2394c47fd378Schristos tok2str(ofpt_str, "invalid (0x%02x)", type), len, xid)); 2395026d7285Schristos switch (type) { 2396026d7285Schristos /* OpenFlow header only. */ 2397026d7285Schristos case OFPT_FEATURES_REQUEST: /* [OF10] Section 5.3.1 */ 2398026d7285Schristos case OFPT_GET_CONFIG_REQUEST: /* [OF10] Section 5.3.2 */ 2399026d7285Schristos case OFPT_BARRIER_REQUEST: /* [OF10] Section 5.3.7 */ 2400026d7285Schristos case OFPT_BARRIER_REPLY: /* ibid */ 2401026d7285Schristos if (len != OF_HEADER_LEN) 2402026d7285Schristos goto corrupt; 2403026d7285Schristos break; 2404026d7285Schristos 2405026d7285Schristos /* OpenFlow header and fixed-size message body. */ 2406026d7285Schristos case OFPT_SET_CONFIG: /* [OF10] Section 5.3.2 */ 2407026d7285Schristos case OFPT_GET_CONFIG_REPLY: /* ibid */ 2408026d7285Schristos if (len != OF_SWITCH_CONFIG_LEN) 2409026d7285Schristos goto corrupt; 2410c47fd378Schristos if (ndo->ndo_vflag < 1) 2411026d7285Schristos goto next_message; 2412026d7285Schristos /* flags */ 2413c47fd378Schristos ND_TCHECK2(*cp, 2); 2414c47fd378Schristos ND_PRINT((ndo, "\n\t flags %s", tok2str(ofp_config_str, "invalid (0x%04x)", EXTRACT_16BITS(cp)))); 2415026d7285Schristos cp += 2; 2416026d7285Schristos /* miss_send_len */ 2417c47fd378Schristos ND_TCHECK2(*cp, 2); 2418c47fd378Schristos ND_PRINT((ndo, ", miss_send_len %u", EXTRACT_16BITS(cp))); 2419026d7285Schristos return cp + 2; 2420026d7285Schristos case OFPT_PORT_MOD: 2421026d7285Schristos if (len != OF_PORT_MOD_LEN) 2422026d7285Schristos goto corrupt; 2423c47fd378Schristos if (ndo->ndo_vflag < 1) 2424026d7285Schristos goto next_message; 2425c47fd378Schristos return of10_port_mod_print(ndo, cp, ep); 2426026d7285Schristos case OFPT_QUEUE_GET_CONFIG_REQUEST: /* [OF10] Section 5.3.4 */ 2427026d7285Schristos if (len != OF_QUEUE_GET_CONFIG_REQUEST_LEN) 2428026d7285Schristos goto corrupt; 2429c47fd378Schristos if (ndo->ndo_vflag < 1) 2430026d7285Schristos goto next_message; 2431026d7285Schristos /* port */ 2432c47fd378Schristos ND_TCHECK2(*cp, 2); 2433c47fd378Schristos ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp)))); 2434026d7285Schristos cp += 2; 2435026d7285Schristos /* pad */ 2436c47fd378Schristos ND_TCHECK2(*cp, 2); 2437026d7285Schristos return cp + 2; 2438026d7285Schristos case OFPT_FLOW_REMOVED: 2439026d7285Schristos if (len != OF_FLOW_REMOVED_LEN) 2440026d7285Schristos goto corrupt; 2441c47fd378Schristos if (ndo->ndo_vflag < 1) 2442026d7285Schristos goto next_message; 2443c47fd378Schristos return of10_flow_removed_print(ndo, cp, ep); 2444026d7285Schristos case OFPT_PORT_STATUS: /* [OF10] Section 5.4.3 */ 2445026d7285Schristos if (len != OF_PORT_STATUS_LEN) 2446026d7285Schristos goto corrupt; 2447c47fd378Schristos if (ndo->ndo_vflag < 1) 2448026d7285Schristos goto next_message; 2449026d7285Schristos /* reason */ 2450c47fd378Schristos ND_TCHECK2(*cp, 1); 2451c47fd378Schristos ND_PRINT((ndo, "\n\t reason %s", tok2str(ofppr_str, "invalid (0x%02x)", *cp))); 2452026d7285Schristos cp += 1; 2453026d7285Schristos /* pad */ 2454c47fd378Schristos ND_TCHECK2(*cp, 7); 2455026d7285Schristos cp += 7; 2456026d7285Schristos /* desc */ 2457c47fd378Schristos return of10_phy_ports_print(ndo, cp, ep, OF_PHY_PORT_LEN); 2458026d7285Schristos 2459026d7285Schristos /* OpenFlow header, fixed-size message body and n * fixed-size data units. */ 2460026d7285Schristos case OFPT_FEATURES_REPLY: 2461026d7285Schristos if (len < OF_SWITCH_FEATURES_LEN) 2462026d7285Schristos goto corrupt; 2463c47fd378Schristos if (ndo->ndo_vflag < 1) 2464026d7285Schristos goto next_message; 2465c47fd378Schristos return of10_features_reply_print(ndo, cp, ep, len); 2466026d7285Schristos 2467026d7285Schristos /* OpenFlow header and variable-size data. */ 2468026d7285Schristos case OFPT_HELLO: /* [OF10] Section 5.5.1 */ 2469026d7285Schristos case OFPT_ECHO_REQUEST: /* [OF10] Section 5.5.2 */ 2470026d7285Schristos case OFPT_ECHO_REPLY: /* [OF10] Section 5.5.3 */ 2471c47fd378Schristos if (ndo->ndo_vflag < 1) 2472026d7285Schristos goto next_message; 2473c47fd378Schristos return of10_data_print(ndo, cp, ep, len - OF_HEADER_LEN); 2474026d7285Schristos 2475026d7285Schristos /* OpenFlow header, fixed-size message body and variable-size data. */ 2476026d7285Schristos case OFPT_ERROR: 2477026d7285Schristos if (len < OF_ERROR_MSG_LEN) 2478026d7285Schristos goto corrupt; 2479c47fd378Schristos if (ndo->ndo_vflag < 1) 2480026d7285Schristos goto next_message; 2481c47fd378Schristos return of10_error_print(ndo, cp, ep, len); 2482026d7285Schristos case OFPT_VENDOR: 2483026d7285Schristos /* [OF10] Section 5.5.4 */ 2484026d7285Schristos if (len < OF_VENDOR_HEADER_LEN) 2485026d7285Schristos goto corrupt; 2486c47fd378Schristos if (ndo->ndo_vflag < 1) 2487026d7285Schristos goto next_message; 2488*3d25ea14Schristos return of10_vendor_message_print(ndo, cp, ep, len - OF_HEADER_LEN); 2489026d7285Schristos case OFPT_PACKET_IN: 2490026d7285Schristos /* 2 mock octets count in OF_PACKET_IN_LEN but not in len */ 2491026d7285Schristos if (len < OF_PACKET_IN_LEN - 2) 2492026d7285Schristos goto corrupt; 2493c47fd378Schristos if (ndo->ndo_vflag < 1) 2494026d7285Schristos goto next_message; 2495c47fd378Schristos return of10_packet_in_print(ndo, cp, ep, len); 2496026d7285Schristos 2497026d7285Schristos /* a. OpenFlow header. */ 2498026d7285Schristos /* b. OpenFlow header and one of the fixed-size message bodies. */ 2499026d7285Schristos /* c. OpenFlow header, fixed-size message body and variable-size data. */ 2500026d7285Schristos case OFPT_STATS_REQUEST: 2501026d7285Schristos if (len < OF_STATS_REQUEST_LEN) 2502026d7285Schristos goto corrupt; 2503c47fd378Schristos if (ndo->ndo_vflag < 1) 2504026d7285Schristos goto next_message; 2505c47fd378Schristos return of10_stats_request_print(ndo, cp, ep, len); 2506026d7285Schristos 2507026d7285Schristos /* a. OpenFlow header and fixed-size message body. */ 2508026d7285Schristos /* b. OpenFlow header and n * fixed-size data units. */ 2509026d7285Schristos /* c. OpenFlow header and n * variable-size data units. */ 2510026d7285Schristos /* d. OpenFlow header, fixed-size message body and variable-size data. */ 2511026d7285Schristos case OFPT_STATS_REPLY: 2512026d7285Schristos if (len < OF_STATS_REPLY_LEN) 2513026d7285Schristos goto corrupt; 2514c47fd378Schristos if (ndo->ndo_vflag < 1) 2515026d7285Schristos goto next_message; 2516c47fd378Schristos return of10_stats_reply_print(ndo, cp, ep, len); 2517026d7285Schristos 2518026d7285Schristos /* OpenFlow header and n * variable-size data units and variable-size data. */ 2519026d7285Schristos case OFPT_PACKET_OUT: 2520026d7285Schristos if (len < OF_PACKET_OUT_LEN) 2521026d7285Schristos goto corrupt; 2522c47fd378Schristos if (ndo->ndo_vflag < 1) 2523026d7285Schristos goto next_message; 2524c47fd378Schristos return of10_packet_out_print(ndo, cp, ep, len); 2525026d7285Schristos 2526026d7285Schristos /* OpenFlow header, fixed-size message body and n * variable-size data units. */ 2527026d7285Schristos case OFPT_FLOW_MOD: 2528026d7285Schristos if (len < OF_FLOW_MOD_LEN) 2529026d7285Schristos goto corrupt; 2530c47fd378Schristos if (ndo->ndo_vflag < 1) 2531026d7285Schristos goto next_message; 2532c47fd378Schristos return of10_flow_mod_print(ndo, cp, ep, len); 2533026d7285Schristos 2534026d7285Schristos /* OpenFlow header, fixed-size message body and n * variable-size data units. */ 2535026d7285Schristos case OFPT_QUEUE_GET_CONFIG_REPLY: /* [OF10] Section 5.3.4 */ 2536026d7285Schristos if (len < OF_QUEUE_GET_CONFIG_REPLY_LEN) 2537026d7285Schristos goto corrupt; 2538c47fd378Schristos if (ndo->ndo_vflag < 1) 2539026d7285Schristos goto next_message; 2540026d7285Schristos /* port */ 2541c47fd378Schristos ND_TCHECK2(*cp, 2); 2542c47fd378Schristos ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp)))); 2543026d7285Schristos cp += 2; 2544026d7285Schristos /* pad */ 2545c47fd378Schristos ND_TCHECK2(*cp, 6); 2546026d7285Schristos cp += 6; 2547026d7285Schristos /* queues */ 2548c47fd378Schristos return of10_queues_print(ndo, cp, ep, len - OF_QUEUE_GET_CONFIG_REPLY_LEN); 2549026d7285Schristos } /* switch (type) */ 2550026d7285Schristos goto next_message; 2551026d7285Schristos 2552026d7285Schristos corrupt: /* skip the message body */ 2553c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 2554026d7285Schristos next_message: 2555c47fd378Schristos ND_TCHECK2(*cp0, len0 - OF_HEADER_LEN); 2556026d7285Schristos return cp0 + len0 - OF_HEADER_LEN; 2557026d7285Schristos trunc: 2558c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 2559026d7285Schristos return ep; 2560026d7285Schristos } 2561