1/*
2 * This module implements decoding of OpenFlow protocol version 1.0 (wire
3 * protocol 0x01). The decoder implements terse (default), detailed (-v) and
4 * full (-vv) output formats and, as much as each format implies, detects and
5 * tries to work around sizing anomalies inside the messages. The decoder marks
6 * up bogus values of selected message fields and decodes partially captured
7 * messages up to the snapshot end. It is based on the specification below:
8 *
9 * [OF10] http://www.openflow.org/documents/openflow-spec-v1.0.0.pdf
10 *
11 * Most functions in this file take 3 arguments into account:
12 * * cp -- the pointer to the first octet to decode
13 * * len -- the length of the current structure as declared on the wire
14 * * ep -- the pointer to the end of the captured frame
15 * They return either the pointer to the next not-yet-decoded part of the frame
16 * or the value of ep, which means the current frame processing is over as it
17 * has been fully decoded or is invalid or truncated. This way it is possible
18 * to chain and nest such functions uniformly to decode an OF1.0 message, which
19 * consists of several layers of nested structures.
20 *
21 * Decoding of Ethernet frames nested in OFPT_PACKET_IN and OFPT_PACKET_OUT
22 * messages is done only when the verbosity level set by command-line argument
23 * is "-vvv" or higher. In that case the verbosity level is temporarily
24 * decremented by 3 during the nested frame decoding. For example, running
25 * tcpdump with "-vvvv" will do full decoding of OpenFlow and "-v" decoding of
26 * the nested frames.
27 *
28 * Partial decoding of Big Switch Networks vendor extensions is done after the
29 * oftest (OpenFlow Testing Framework) and Loxigen (library generator) source
30 * code.
31 *
32 *
33 * Copyright (c) 2013 The TCPDUMP project
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 *    notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 *    notice, this list of conditions and the following disclaimer in the
43 *    documentation and/or other materials provided with the distribution.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
46 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
47 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
48 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
49 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
50 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
51 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
52 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
53 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
55 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
56 * POSSIBILITY OF SUCH DAMAGE.
57 */
58
59/* \summary: OpenFlow protocol version 1.0 printer */
60
61#ifdef HAVE_CONFIG_H
62#include "config.h"
63#endif
64
65#include <netdissect-stdinc.h>
66
67#include "netdissect.h"
68#include "extract.h"
69#include "addrtoname.h"
70#include "ether.h"
71#include "ethertype.h"
72#include "ipproto.h"
73#include "oui.h"
74#include "openflow.h"
75
76static const char tstr[] = " [|openflow]";
77
78#define OFPT_HELLO                    0x00
79#define OFPT_ERROR                    0x01
80#define OFPT_ECHO_REQUEST             0x02
81#define OFPT_ECHO_REPLY               0x03
82#define OFPT_VENDOR                   0x04
83#define OFPT_FEATURES_REQUEST         0x05
84#define OFPT_FEATURES_REPLY           0x06
85#define OFPT_GET_CONFIG_REQUEST       0x07
86#define OFPT_GET_CONFIG_REPLY         0x08
87#define OFPT_SET_CONFIG               0x09
88#define OFPT_PACKET_IN                0x0a
89#define OFPT_FLOW_REMOVED             0x0b
90#define OFPT_PORT_STATUS              0x0c
91#define OFPT_PACKET_OUT               0x0d
92#define OFPT_FLOW_MOD                 0x0e
93#define OFPT_PORT_MOD                 0x0f
94#define OFPT_STATS_REQUEST            0x10
95#define OFPT_STATS_REPLY              0x11
96#define OFPT_BARRIER_REQUEST          0x12
97#define OFPT_BARRIER_REPLY            0x13
98#define OFPT_QUEUE_GET_CONFIG_REQUEST 0x14
99#define OFPT_QUEUE_GET_CONFIG_REPLY   0x15
100static const struct tok ofpt_str[] = {
101	{ OFPT_HELLO,                    "HELLO"                    },
102	{ OFPT_ERROR,                    "ERROR"                    },
103	{ OFPT_ECHO_REQUEST,             "ECHO_REQUEST"             },
104	{ OFPT_ECHO_REPLY,               "ECHO_REPLY"               },
105	{ OFPT_VENDOR,                   "VENDOR"                   },
106	{ OFPT_FEATURES_REQUEST,         "FEATURES_REQUEST"         },
107	{ OFPT_FEATURES_REPLY,           "FEATURES_REPLY"           },
108	{ OFPT_GET_CONFIG_REQUEST,       "GET_CONFIG_REQUEST"       },
109	{ OFPT_GET_CONFIG_REPLY,         "GET_CONFIG_REPLY"         },
110	{ OFPT_SET_CONFIG,               "SET_CONFIG"               },
111	{ OFPT_PACKET_IN,                "PACKET_IN"                },
112	{ OFPT_FLOW_REMOVED,             "FLOW_REMOVED"             },
113	{ OFPT_PORT_STATUS,              "PORT_STATUS"              },
114	{ OFPT_PACKET_OUT,               "PACKET_OUT"               },
115	{ OFPT_FLOW_MOD,                 "FLOW_MOD"                 },
116	{ OFPT_PORT_MOD,                 "PORT_MOD"                 },
117	{ OFPT_STATS_REQUEST,            "STATS_REQUEST"            },
118	{ OFPT_STATS_REPLY,              "STATS_REPLY"              },
119	{ OFPT_BARRIER_REQUEST,          "BARRIER_REQUEST"          },
120	{ OFPT_BARRIER_REPLY,            "BARRIER_REPLY"            },
121	{ OFPT_QUEUE_GET_CONFIG_REQUEST, "QUEUE_GET_CONFIG_REQUEST" },
122	{ OFPT_QUEUE_GET_CONFIG_REPLY,   "QUEUE_GET_CONFIG_REPLY"   },
123	{ 0, NULL }
124};
125
126#define OFPPC_PORT_DOWN    (1 << 0)
127#define OFPPC_NO_STP       (1 << 1)
128#define OFPPC_NO_RECV      (1 << 2)
129#define OFPPC_NO_RECV_STP  (1 << 3)
130#define OFPPC_NO_FLOOD     (1 << 4)
131#define OFPPC_NO_FWD       (1 << 5)
132#define OFPPC_NO_PACKET_IN (1 << 6)
133static const struct tok ofppc_bm[] = {
134	{ OFPPC_PORT_DOWN,    "PORT_DOWN"    },
135	{ OFPPC_NO_STP,       "NO_STP"       },
136	{ OFPPC_NO_RECV,      "NO_RECV"      },
137	{ OFPPC_NO_RECV_STP,  "NO_RECV_STP"  },
138	{ OFPPC_NO_FLOOD,     "NO_FLOOD"     },
139	{ OFPPC_NO_FWD,       "NO_FWD"       },
140	{ OFPPC_NO_PACKET_IN, "NO_PACKET_IN" },
141	{ 0, NULL }
142};
143#define OFPPC_U (~(OFPPC_PORT_DOWN | OFPPC_NO_STP | OFPPC_NO_RECV | \
144                   OFPPC_NO_RECV_STP | OFPPC_NO_FLOOD | OFPPC_NO_FWD | \
145                   OFPPC_NO_PACKET_IN))
146
147#define OFPPS_LINK_DOWN   (1 << 0)
148#define OFPPS_STP_LISTEN  (0 << 8)
149#define OFPPS_STP_LEARN   (1 << 8)
150#define OFPPS_STP_FORWARD (2 << 8)
151#define OFPPS_STP_BLOCK   (3 << 8)
152#define OFPPS_STP_MASK    (3 << 8)
153static const struct tok ofpps_bm[] = {
154	{ OFPPS_LINK_DOWN,   "LINK_DOWN"   },
155	{ OFPPS_STP_LISTEN,  "STP_LISTEN"  },
156	{ OFPPS_STP_LEARN,   "STP_LEARN"   },
157	{ OFPPS_STP_FORWARD, "STP_FORWARD" },
158	{ OFPPS_STP_BLOCK,   "STP_BLOCK"   },
159	{ 0, NULL }
160};
161#define OFPPS_U (~(OFPPS_LINK_DOWN | OFPPS_STP_LISTEN | OFPPS_STP_LEARN | \
162                   OFPPS_STP_FORWARD | OFPPS_STP_BLOCK))
163
164#define OFPP_MAX        0xff00
165#define OFPP_IN_PORT    0xfff8
166#define OFPP_TABLE      0xfff9
167#define OFPP_NORMAL     0xfffa
168#define OFPP_FLOOD      0xfffb
169#define OFPP_ALL        0xfffc
170#define OFPP_CONTROLLER 0xfffd
171#define OFPP_LOCAL      0xfffe
172#define OFPP_NONE       0xffff
173static const struct tok ofpp_str[] = {
174	{ OFPP_MAX,        "MAX"        },
175	{ OFPP_IN_PORT,    "IN_PORT"    },
176	{ OFPP_TABLE,      "TABLE"      },
177	{ OFPP_NORMAL,     "NORMAL"     },
178	{ OFPP_FLOOD,      "FLOOD"      },
179	{ OFPP_ALL,        "ALL"        },
180	{ OFPP_CONTROLLER, "CONTROLLER" },
181	{ OFPP_LOCAL,      "LOCAL"      },
182	{ OFPP_NONE,       "NONE"       },
183	{ 0, NULL }
184};
185
186#define OFPPF_10MB_HD    (1 <<  0)
187#define OFPPF_10MB_FD    (1 <<  1)
188#define OFPPF_100MB_HD   (1 <<  2)
189#define OFPPF_100MB_FD   (1 <<  3)
190#define OFPPF_1GB_HD     (1 <<  4)
191#define OFPPF_1GB_FD     (1 <<  5)
192#define OFPPF_10GB_FD    (1 <<  6)
193#define OFPPF_COPPER     (1 <<  7)
194#define OFPPF_FIBER      (1 <<  8)
195#define OFPPF_AUTONEG    (1 <<  9)
196#define OFPPF_PAUSE      (1 << 10)
197#define OFPPF_PAUSE_ASYM (1 << 11)
198static const struct tok ofppf_bm[] = {
199	{ OFPPF_10MB_HD,    "10MB_HD"    },
200	{ OFPPF_10MB_FD,    "10MB_FD"    },
201	{ OFPPF_100MB_HD,   "100MB_HD"   },
202	{ OFPPF_100MB_FD,   "100MB_FD"   },
203	{ OFPPF_1GB_HD,     "1GB_HD"     },
204	{ OFPPF_1GB_FD,     "1GB_FD"     },
205	{ OFPPF_10GB_FD,    "10GB_FD"    },
206	{ OFPPF_COPPER,     "COPPER"     },
207	{ OFPPF_FIBER,      "FIBER"      },
208	{ OFPPF_AUTONEG,    "AUTONEG"    },
209	{ OFPPF_PAUSE,      "PAUSE"      },
210	{ OFPPF_PAUSE_ASYM, "PAUSE_ASYM" },
211	{ 0, NULL }
212};
213#define OFPPF_U (~(OFPPF_10MB_HD | OFPPF_10MB_FD | OFPPF_100MB_HD | \
214                   OFPPF_100MB_FD | OFPPF_1GB_HD | OFPPF_1GB_FD | \
215                   OFPPF_10GB_FD | OFPPF_COPPER | OFPPF_FIBER | \
216                   OFPPF_AUTONEG | OFPPF_PAUSE | OFPPF_PAUSE_ASYM))
217
218#define OFPQT_NONE     0x0000
219#define OFPQT_MIN_RATE 0x0001
220static const struct tok ofpqt_str[] = {
221	{ OFPQT_NONE,     "NONE"     },
222	{ OFPQT_MIN_RATE, "MIN_RATE" },
223	{ 0, NULL }
224};
225
226#define OFPFW_IN_PORT      (1 << 0)
227#define OFPFW_DL_VLAN      (1 << 1)
228#define OFPFW_DL_SRC       (1 << 2)
229#define OFPFW_DL_DST       (1 << 3)
230#define OFPFW_DL_TYPE      (1 << 4)
231#define OFPFW_NW_PROTO     (1 << 5)
232#define OFPFW_TP_SRC       (1 << 6)
233#define OFPFW_TP_DST       (1 << 7)
234#define OFPFW_NW_SRC_SHIFT 8
235#define OFPFW_NW_SRC_BITS  6
236#define OFPFW_NW_SRC_MASK  (((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT)
237#define OFPFW_NW_DST_SHIFT 14
238#define OFPFW_NW_DST_BITS  6
239#define OFPFW_NW_DST_MASK  (((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT)
240#define OFPFW_DL_VLAN_PCP  (1 << 20)
241#define OFPFW_NW_TOS       (1 << 21)
242#define OFPFW_ALL          ((1 << 22) - 1)
243static const struct tok ofpfw_bm[] = {
244	{ OFPFW_IN_PORT,     "IN_PORT"     },
245	{ OFPFW_DL_VLAN,     "DL_VLAN"     },
246	{ OFPFW_DL_SRC,      "DL_SRC"      },
247	{ OFPFW_DL_DST,      "DL_DST"      },
248	{ OFPFW_DL_TYPE,     "DL_TYPE"     },
249	{ OFPFW_NW_PROTO,    "NW_PROTO"    },
250	{ OFPFW_TP_SRC,      "TP_SRC"      },
251	{ OFPFW_TP_DST,      "TP_DST"      },
252	{ OFPFW_DL_VLAN_PCP, "DL_VLAN_PCP" },
253	{ OFPFW_NW_TOS,      "NW_TOS"      },
254	{ 0, NULL }
255};
256/* The above array does not include bits 8~13 (OFPFW_NW_SRC_*) and 14~19
257 * (OFPFW_NW_DST_*), which are not a part of the bitmap and require decoding
258 * other than that of tok2str(). The macro below includes these bits such that
259 * they are not reported as bogus in the decoding. */
260#define OFPFW_U (~(OFPFW_ALL))
261
262#define OFPAT_OUTPUT       0x0000
263#define OFPAT_SET_VLAN_VID 0x0001
264#define OFPAT_SET_VLAN_PCP 0x0002
265#define OFPAT_STRIP_VLAN   0x0003
266#define OFPAT_SET_DL_SRC   0x0004
267#define OFPAT_SET_DL_DST   0x0005
268#define OFPAT_SET_NW_SRC   0x0006
269#define OFPAT_SET_NW_DST   0x0007
270#define OFPAT_SET_NW_TOS   0x0008
271#define OFPAT_SET_TP_SRC   0x0009
272#define OFPAT_SET_TP_DST   0x000a
273#define OFPAT_ENQUEUE      0x000b
274#define OFPAT_VENDOR       0xffff
275static const struct tok ofpat_str[] = {
276	{ OFPAT_OUTPUT,       "OUTPUT"       },
277	{ OFPAT_SET_VLAN_VID, "SET_VLAN_VID" },
278	{ OFPAT_SET_VLAN_PCP, "SET_VLAN_PCP" },
279	{ OFPAT_STRIP_VLAN,   "STRIP_VLAN"   },
280	{ OFPAT_SET_DL_SRC,   "SET_DL_SRC"   },
281	{ OFPAT_SET_DL_DST,   "SET_DL_DST"   },
282	{ OFPAT_SET_NW_SRC,   "SET_NW_SRC"   },
283	{ OFPAT_SET_NW_DST,   "SET_NW_DST"   },
284	{ OFPAT_SET_NW_TOS,   "SET_NW_TOS"   },
285	{ OFPAT_SET_TP_SRC,   "SET_TP_SRC"   },
286	{ OFPAT_SET_TP_DST,   "SET_TP_DST"   },
287	{ OFPAT_ENQUEUE,      "ENQUEUE"      },
288	{ OFPAT_VENDOR,       "VENDOR"       },
289	{ 0, NULL }
290};
291
292/* bit-shifted, w/o vendor action */
293static const struct tok ofpat_bm[] = {
294	{ 1 << OFPAT_OUTPUT,       "OUTPUT"       },
295	{ 1 << OFPAT_SET_VLAN_VID, "SET_VLAN_VID" },
296	{ 1 << OFPAT_SET_VLAN_PCP, "SET_VLAN_PCP" },
297	{ 1 << OFPAT_STRIP_VLAN,   "STRIP_VLAN"   },
298	{ 1 << OFPAT_SET_DL_SRC,   "SET_DL_SRC"   },
299	{ 1 << OFPAT_SET_DL_DST,   "SET_DL_DST"   },
300	{ 1 << OFPAT_SET_NW_SRC,   "SET_NW_SRC"   },
301	{ 1 << OFPAT_SET_NW_DST,   "SET_NW_DST"   },
302	{ 1 << OFPAT_SET_NW_TOS,   "SET_NW_TOS"   },
303	{ 1 << OFPAT_SET_TP_SRC,   "SET_TP_SRC"   },
304	{ 1 << OFPAT_SET_TP_DST,   "SET_TP_DST"   },
305	{ 1 << OFPAT_ENQUEUE,      "ENQUEUE"      },
306	{ 0, NULL }
307};
308#define OFPAT_U (~(1 << OFPAT_OUTPUT | 1 << OFPAT_SET_VLAN_VID | \
309                   1 << OFPAT_SET_VLAN_PCP | 1 << OFPAT_STRIP_VLAN | \
310                   1 << OFPAT_SET_DL_SRC | 1 << OFPAT_SET_DL_DST | \
311                   1 << OFPAT_SET_NW_SRC | 1 << OFPAT_SET_NW_DST | \
312                   1 << OFPAT_SET_NW_TOS | 1 << OFPAT_SET_TP_SRC | \
313                   1 << OFPAT_SET_TP_DST | 1 << OFPAT_ENQUEUE))
314
315#define OFPC_FLOW_STATS   (1 << 0)
316#define OFPC_TABLE_STATS  (1 << 1)
317#define OFPC_PORT_STATS   (1 << 2)
318#define OFPC_STP          (1 << 3)
319#define OFPC_RESERVED     (1 << 4)
320#define OFPC_IP_REASM     (1 << 5)
321#define OFPC_QUEUE_STATS  (1 << 6)
322#define OFPC_ARP_MATCH_IP (1 << 7)
323static const struct tok ofp_capabilities_bm[] = {
324	{ OFPC_FLOW_STATS,   "FLOW_STATS"   },
325	{ OFPC_TABLE_STATS,  "TABLE_STATS"  },
326	{ OFPC_PORT_STATS,   "PORT_STATS"   },
327	{ OFPC_STP,          "STP"          },
328	{ OFPC_RESERVED,     "RESERVED"     }, /* not in the mask below */
329	{ OFPC_IP_REASM,     "IP_REASM"     },
330	{ OFPC_QUEUE_STATS,  "QUEUE_STATS"  },
331	{ OFPC_ARP_MATCH_IP, "ARP_MATCH_IP" },
332	{ 0, NULL }
333};
334#define OFPCAP_U (~(OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS | \
335                    OFPC_STP | OFPC_IP_REASM | OFPC_QUEUE_STATS | \
336                    OFPC_ARP_MATCH_IP))
337
338#define OFPC_FRAG_NORMAL 0x0000
339#define OFPC_FRAG_DROP   0x0001
340#define OFPC_FRAG_REASM  0x0002
341#define OFPC_FRAG_MASK   0x0003
342static const struct tok ofp_config_str[] = {
343	{ OFPC_FRAG_NORMAL, "FRAG_NORMAL" },
344	{ OFPC_FRAG_DROP,   "FRAG_DROP"   },
345	{ OFPC_FRAG_REASM,  "FRAG_REASM"  },
346	{ 0, NULL }
347};
348
349#define OFPFC_ADD           0x0000
350#define OFPFC_MODIFY        0x0001
351#define OFPFC_MODIFY_STRICT 0x0002
352#define OFPFC_DELETE        0x0003
353#define OFPFC_DELETE_STRICT 0x0004
354static const struct tok ofpfc_str[] = {
355	{ OFPFC_ADD,           "ADD"           },
356	{ OFPFC_MODIFY,        "MODIFY"        },
357	{ OFPFC_MODIFY_STRICT, "MODIFY_STRICT" },
358	{ OFPFC_DELETE,        "DELETE"        },
359	{ OFPFC_DELETE_STRICT, "DELETE_STRICT" },
360	{ 0, NULL }
361};
362
363static const struct tok bufferid_str[] = {
364	{ 0xffffffff, "NONE" },
365	{ 0, NULL }
366};
367
368#define OFPFF_SEND_FLOW_REM (1 << 0)
369#define OFPFF_CHECK_OVERLAP (1 << 1)
370#define OFPFF_EMERG         (1 << 2)
371static const struct tok ofpff_bm[] = {
372	{ OFPFF_SEND_FLOW_REM, "SEND_FLOW_REM" },
373	{ OFPFF_CHECK_OVERLAP, "CHECK_OVERLAP" },
374	{ OFPFF_EMERG,         "EMERG"         },
375	{ 0, NULL }
376};
377#define OFPFF_U (~(OFPFF_SEND_FLOW_REM | OFPFF_CHECK_OVERLAP | OFPFF_EMERG))
378
379#define OFPST_DESC      0x0000
380#define OFPST_FLOW      0x0001
381#define OFPST_AGGREGATE 0x0002
382#define OFPST_TABLE     0x0003
383#define OFPST_PORT      0x0004
384#define OFPST_QUEUE     0x0005
385#define OFPST_VENDOR    0xffff
386static const struct tok ofpst_str[] = {
387	{ OFPST_DESC,      "DESC"      },
388	{ OFPST_FLOW,      "FLOW"      },
389	{ OFPST_AGGREGATE, "AGGREGATE" },
390	{ OFPST_TABLE,     "TABLE"     },
391	{ OFPST_PORT,      "PORT"      },
392	{ OFPST_QUEUE,     "QUEUE"     },
393	{ OFPST_VENDOR,    "VENDOR"    },
394	{ 0, NULL }
395};
396
397static const struct tok tableid_str[] = {
398	{ 0xfe, "EMERG" },
399	{ 0xff, "ALL"   },
400	{ 0, NULL }
401};
402
403#define OFPQ_ALL      0xffffffff
404static const struct tok ofpq_str[] = {
405	{ OFPQ_ALL, "ALL" },
406	{ 0, NULL }
407};
408
409#define OFPSF_REPLY_MORE 0x0001
410static const struct tok ofpsf_reply_bm[] = {
411	{ OFPSF_REPLY_MORE, "MORE" },
412	{ 0, NULL }
413};
414#define OFPSF_REPLY_U (~(OFPSF_REPLY_MORE))
415
416#define OFPR_NO_MATCH 0x00
417#define OFPR_ACTION   0x01
418static const struct tok ofpr_str[] = {
419	{ OFPR_NO_MATCH, "NO_MATCH" },
420	{ OFPR_ACTION,   "ACTION"   },
421	{ 0, NULL }
422};
423
424#define OFPRR_IDLE_TIMEOUT 0x00
425#define OFPRR_HARD_TIMEOUT 0x01
426#define OFPRR_DELETE       0x02
427static const struct tok ofprr_str[] = {
428	{ OFPRR_IDLE_TIMEOUT, "IDLE_TIMEOUT" },
429	{ OFPRR_HARD_TIMEOUT, "HARD_TIMEOUT" },
430	{ OFPRR_DELETE,       "DELETE"       },
431	{ 0, NULL }
432};
433
434#define OFPPR_ADD    0x00
435#define OFPPR_DELETE 0x01
436#define OFPPR_MODIFY 0x02
437static const struct tok ofppr_str[] = {
438	{ OFPPR_ADD,    "ADD"    },
439	{ OFPPR_DELETE, "DELETE" },
440	{ OFPPR_MODIFY, "MODIFY" },
441	{ 0, NULL }
442};
443
444#define OFPET_HELLO_FAILED    0x0000
445#define OFPET_BAD_REQUEST     0x0001
446#define OFPET_BAD_ACTION      0x0002
447#define OFPET_FLOW_MOD_FAILED 0x0003
448#define OFPET_PORT_MOD_FAILED 0x0004
449#define OFPET_QUEUE_OP_FAILED 0x0005
450static const struct tok ofpet_str[] = {
451	{ OFPET_HELLO_FAILED,    "HELLO_FAILED"    },
452	{ OFPET_BAD_REQUEST,     "BAD_REQUEST"     },
453	{ OFPET_BAD_ACTION,      "BAD_ACTION"      },
454	{ OFPET_FLOW_MOD_FAILED, "FLOW_MOD_FAILED" },
455	{ OFPET_PORT_MOD_FAILED, "PORT_MOD_FAILED" },
456	{ OFPET_QUEUE_OP_FAILED, "QUEUE_OP_FAILED" },
457	{ 0, NULL }
458};
459
460#define OFPHFC_INCOMPATIBLE 0x0000
461#define OFPHFC_EPERM        0x0001
462static const struct tok ofphfc_str[] = {
463	{ OFPHFC_INCOMPATIBLE, "INCOMPATIBLE" },
464	{ OFPHFC_EPERM,        "EPERM"        },
465	{ 0, NULL }
466};
467
468#define OFPBRC_BAD_VERSION    0x0000
469#define OFPBRC_BAD_TYPE       0x0001
470#define OFPBRC_BAD_STAT       0x0002
471#define OFPBRC_BAD_VENDOR     0x0003
472#define OFPBRC_BAD_SUBTYPE    0x0004
473#define OFPBRC_EPERM          0x0005
474#define OFPBRC_BAD_LEN        0x0006
475#define OFPBRC_BUFFER_EMPTY   0x0007
476#define OFPBRC_BUFFER_UNKNOWN 0x0008
477static const struct tok ofpbrc_str[] = {
478	{ OFPBRC_BAD_VERSION,    "BAD_VERSION"    },
479	{ OFPBRC_BAD_TYPE,       "BAD_TYPE"       },
480	{ OFPBRC_BAD_STAT,       "BAD_STAT"       },
481	{ OFPBRC_BAD_VENDOR,     "BAD_VENDOR"     },
482	{ OFPBRC_BAD_SUBTYPE,    "BAD_SUBTYPE"    },
483	{ OFPBRC_EPERM,          "EPERM"          },
484	{ OFPBRC_BAD_LEN,        "BAD_LEN"        },
485	{ OFPBRC_BUFFER_EMPTY,   "BUFFER_EMPTY"   },
486	{ OFPBRC_BUFFER_UNKNOWN, "BUFFER_UNKNOWN" },
487	{ 0, NULL }
488};
489
490#define OFPBAC_BAD_TYPE        0x0000
491#define OFPBAC_BAD_LEN         0x0001
492#define OFPBAC_BAD_VENDOR      0x0002
493#define OFPBAC_BAD_VENDOR_TYPE 0x0003
494#define OFPBAC_BAD_OUT_PORT    0x0004
495#define OFPBAC_BAD_ARGUMENT    0x0005
496#define OFPBAC_EPERM           0x0006
497#define OFPBAC_TOO_MANY        0x0007
498#define OFPBAC_BAD_QUEUE       0x0008
499static const struct tok ofpbac_str[] = {
500	{ OFPBAC_BAD_TYPE,        "BAD_TYPE"        },
501	{ OFPBAC_BAD_LEN,         "BAD_LEN"         },
502	{ OFPBAC_BAD_VENDOR,      "BAD_VENDOR"      },
503	{ OFPBAC_BAD_VENDOR_TYPE, "BAD_VENDOR_TYPE" },
504	{ OFPBAC_BAD_OUT_PORT,    "BAD_OUT_PORT"    },
505	{ OFPBAC_BAD_ARGUMENT,    "BAD_ARGUMENT"    },
506	{ OFPBAC_EPERM,           "EPERM"           },
507	{ OFPBAC_TOO_MANY,        "TOO_MANY"        },
508	{ OFPBAC_BAD_QUEUE,       "BAD_QUEUE"       },
509	{ 0, NULL }
510};
511
512#define OFPFMFC_ALL_TABLES_FULL   0x0000
513#define OFPFMFC_OVERLAP           0x0001
514#define OFPFMFC_EPERM             0x0002
515#define OFPFMFC_BAD_EMERG_TIMEOUT 0x0003
516#define OFPFMFC_BAD_COMMAND       0x0004
517#define OFPFMFC_UNSUPPORTED       0x0005
518static const struct tok ofpfmfc_str[] = {
519	{ OFPFMFC_ALL_TABLES_FULL,   "ALL_TABLES_FULL"   },
520	{ OFPFMFC_OVERLAP,           "OVERLAP"           },
521	{ OFPFMFC_EPERM,             "EPERM"             },
522	{ OFPFMFC_BAD_EMERG_TIMEOUT, "BAD_EMERG_TIMEOUT" },
523	{ OFPFMFC_BAD_COMMAND,       "BAD_COMMAND"       },
524	{ OFPFMFC_UNSUPPORTED,       "UNSUPPORTED"       },
525	{ 0, NULL }
526};
527
528#define OFPPMFC_BAD_PORT    0x0000
529#define OFPPMFC_BAD_HW_ADDR 0x0001
530static const struct tok ofppmfc_str[] = {
531	{ OFPPMFC_BAD_PORT,    "BAD_PORT"    },
532	{ OFPPMFC_BAD_HW_ADDR, "BAD_HW_ADDR" },
533	{ 0, NULL }
534};
535
536#define OFPQOFC_BAD_PORT  0x0000
537#define OFPQOFC_BAD_QUEUE 0x0001
538#define OFPQOFC_EPERM     0x0002
539static const struct tok ofpqofc_str[] = {
540	{ OFPQOFC_BAD_PORT,  "BAD_PORT"  },
541	{ OFPQOFC_BAD_QUEUE, "BAD_QUEUE" },
542	{ OFPQOFC_EPERM,     "EPERM"     },
543	{ 0, NULL }
544};
545
546static const struct tok empty_str[] = {
547	{ 0, NULL }
548};
549
550/* lengths (fixed or minimal) of particular protocol structures */
551#define OF_SWITCH_CONFIG_LEN              12
552#define OF_PHY_PORT_LEN                   48
553#define OF_SWITCH_FEATURES_LEN            32
554#define OF_PORT_STATUS_LEN                64
555#define OF_PORT_MOD_LEN                   32
556#define OF_PACKET_IN_LEN                  20
557#define OF_ACTION_OUTPUT_LEN               8
558#define OF_ACTION_VLAN_VID_LEN             8
559#define OF_ACTION_VLAN_PCP_LEN             8
560#define OF_ACTION_DL_ADDR_LEN             16
561#define OF_ACTION_NW_ADDR_LEN              8
562#define OF_ACTION_TP_PORT_LEN              8
563#define OF_ACTION_NW_TOS_LEN               8
564#define OF_ACTION_VENDOR_HEADER_LEN        8
565#define OF_ACTION_HEADER_LEN               8
566#define OF_PACKET_OUT_LEN                 16
567#define OF_MATCH_LEN                      40
568#define OF_FLOW_MOD_LEN                   72
569#define OF_FLOW_REMOVED_LEN               88
570#define OF_ERROR_MSG_LEN                  12
571#define OF_STATS_REQUEST_LEN              12
572#define OF_STATS_REPLY_LEN                12
573#define OF_DESC_STATS_LEN               1056
574#define OF_FLOW_STATS_REQUEST_LEN         44
575#define OF_FLOW_STATS_LEN                 88
576#define OF_AGGREGATE_STATS_REQUEST_LEN    44
577#define OF_AGGREGATE_STATS_REPLY_LEN      24
578#define OF_TABLE_STATS_LEN                64
579#define OF_PORT_STATS_REQUEST_LEN          8
580#define OF_PORT_STATS_LEN                104
581#define OF_VENDOR_HEADER_LEN              12
582#define OF_QUEUE_PROP_HEADER_LEN           8
583#define OF_QUEUE_PROP_MIN_RATE_LEN        16
584#define OF_PACKET_QUEUE_LEN                8
585#define OF_QUEUE_GET_CONFIG_REQUEST_LEN   12
586#define OF_QUEUE_GET_CONFIG_REPLY_LEN     16
587#define OF_ACTION_ENQUEUE_LEN             16
588#define OF_QUEUE_STATS_REQUEST_LEN         8
589#define OF_QUEUE_STATS_LEN                32
590
591/* miscellaneous constants from [OF10] */
592#define OFP_MAX_TABLE_NAME_LEN     32
593#define OFP_MAX_PORT_NAME_LEN      16
594#define DESC_STR_LEN              256
595#define SERIAL_NUM_LEN             32
596#define OFP_VLAN_NONE          0xffff
597
598/* vendor extensions */
599#define BSN_SET_IP_MASK                    0
600#define BSN_GET_IP_MASK_REQUEST            1
601#define BSN_GET_IP_MASK_REPLY              2
602#define BSN_SET_MIRRORING                  3
603#define BSN_GET_MIRRORING_REQUEST          4
604#define BSN_GET_MIRRORING_REPLY            5
605#define BSN_SHELL_COMMAND                  6
606#define BSN_SHELL_OUTPUT                   7
607#define BSN_SHELL_STATUS                   8
608#define BSN_GET_INTERFACES_REQUEST         9
609#define BSN_GET_INTERFACES_REPLY          10
610#define BSN_SET_PKTIN_SUPPRESSION_REQUEST 11
611#define BSN_SET_L2_TABLE_REQUEST          12
612#define BSN_GET_L2_TABLE_REQUEST          13
613#define BSN_GET_L2_TABLE_REPLY            14
614#define BSN_VIRTUAL_PORT_CREATE_REQUEST   15
615#define BSN_VIRTUAL_PORT_CREATE_REPLY     16
616#define BSN_VIRTUAL_PORT_REMOVE_REQUEST   17
617#define BSN_BW_ENABLE_SET_REQUEST         18
618#define BSN_BW_ENABLE_GET_REQUEST         19
619#define BSN_BW_ENABLE_GET_REPLY           20
620#define BSN_BW_CLEAR_DATA_REQUEST         21
621#define BSN_BW_CLEAR_DATA_REPLY           22
622#define BSN_BW_ENABLE_SET_REPLY           23
623#define BSN_SET_L2_TABLE_REPLY            24
624#define BSN_SET_PKTIN_SUPPRESSION_REPLY   25
625#define BSN_VIRTUAL_PORT_REMOVE_REPLY     26
626#define BSN_HYBRID_GET_REQUEST            27
627#define BSN_HYBRID_GET_REPLY              28
628                                       /* 29 */
629                                       /* 30 */
630#define BSN_PDU_TX_REQUEST                31
631#define BSN_PDU_TX_REPLY                  32
632#define BSN_PDU_RX_REQUEST                33
633#define BSN_PDU_RX_REPLY                  34
634#define BSN_PDU_RX_TIMEOUT                35
635
636static const struct tok bsn_subtype_str[] = {
637	{ BSN_SET_IP_MASK,                   "SET_IP_MASK"                   },
638	{ BSN_GET_IP_MASK_REQUEST,           "GET_IP_MASK_REQUEST"           },
639	{ BSN_GET_IP_MASK_REPLY,             "GET_IP_MASK_REPLY"             },
640	{ BSN_SET_MIRRORING,                 "SET_MIRRORING"                 },
641	{ BSN_GET_MIRRORING_REQUEST,         "GET_MIRRORING_REQUEST"         },
642	{ BSN_GET_MIRRORING_REPLY,           "GET_MIRRORING_REPLY"           },
643	{ BSN_SHELL_COMMAND,                 "SHELL_COMMAND"                 },
644	{ BSN_SHELL_OUTPUT,                  "SHELL_OUTPUT"                  },
645	{ BSN_SHELL_STATUS,                  "SHELL_STATUS"                  },
646	{ BSN_GET_INTERFACES_REQUEST,        "GET_INTERFACES_REQUEST"        },
647	{ BSN_GET_INTERFACES_REPLY,          "GET_INTERFACES_REPLY"          },
648	{ BSN_SET_PKTIN_SUPPRESSION_REQUEST, "SET_PKTIN_SUPPRESSION_REQUEST" },
649	{ BSN_SET_L2_TABLE_REQUEST,          "SET_L2_TABLE_REQUEST"          },
650	{ BSN_GET_L2_TABLE_REQUEST,          "GET_L2_TABLE_REQUEST"          },
651	{ BSN_GET_L2_TABLE_REPLY,            "GET_L2_TABLE_REPLY"            },
652	{ BSN_VIRTUAL_PORT_CREATE_REQUEST,   "VIRTUAL_PORT_CREATE_REQUEST"   },
653	{ BSN_VIRTUAL_PORT_CREATE_REPLY,     "VIRTUAL_PORT_CREATE_REPLY"     },
654	{ BSN_VIRTUAL_PORT_REMOVE_REQUEST,   "VIRTUAL_PORT_REMOVE_REQUEST"   },
655	{ BSN_BW_ENABLE_SET_REQUEST,         "BW_ENABLE_SET_REQUEST"         },
656	{ BSN_BW_ENABLE_GET_REQUEST,         "BW_ENABLE_GET_REQUEST"         },
657	{ BSN_BW_ENABLE_GET_REPLY,           "BW_ENABLE_GET_REPLY"           },
658	{ BSN_BW_CLEAR_DATA_REQUEST,         "BW_CLEAR_DATA_REQUEST"         },
659	{ BSN_BW_CLEAR_DATA_REPLY,           "BW_CLEAR_DATA_REPLY"           },
660	{ BSN_BW_ENABLE_SET_REPLY,           "BW_ENABLE_SET_REPLY"           },
661	{ BSN_SET_L2_TABLE_REPLY,            "SET_L2_TABLE_REPLY"            },
662	{ BSN_SET_PKTIN_SUPPRESSION_REPLY,   "SET_PKTIN_SUPPRESSION_REPLY"   },
663	{ BSN_VIRTUAL_PORT_REMOVE_REPLY,     "VIRTUAL_PORT_REMOVE_REPLY"     },
664	{ BSN_HYBRID_GET_REQUEST,            "HYBRID_GET_REQUEST"            },
665	{ BSN_HYBRID_GET_REPLY,              "HYBRID_GET_REPLY"              },
666	{ BSN_PDU_TX_REQUEST,                "PDU_TX_REQUEST"                },
667	{ BSN_PDU_TX_REPLY,                  "PDU_TX_REPLY"                  },
668	{ BSN_PDU_RX_REQUEST,                "PDU_RX_REQUEST"                },
669	{ BSN_PDU_RX_REPLY,                  "PDU_RX_REPLY"                  },
670	{ BSN_PDU_RX_TIMEOUT,                "PDU_RX_TIMEOUT"                },
671	{ 0, NULL }
672};
673
674#define BSN_ACTION_MIRROR                  1
675#define BSN_ACTION_SET_TUNNEL_DST          2
676                                        /* 3 */
677#define BSN_ACTION_CHECKSUM                4
678
679static const struct tok bsn_action_subtype_str[] = {
680	{ BSN_ACTION_MIRROR,                 "MIRROR"                        },
681	{ BSN_ACTION_SET_TUNNEL_DST,         "SET_TUNNEL_DST"                },
682	{ BSN_ACTION_CHECKSUM,               "CHECKSUM"                      },
683	{ 0, NULL }
684};
685
686static const struct tok bsn_mirror_copy_stage_str[] = {
687	{ 0, "INGRESS" },
688	{ 1, "EGRESS"  },
689	{ 0, NULL },
690};
691
692static const struct tok bsn_onoff_str[] = {
693	{ 0, "OFF" },
694	{ 1, "ON"  },
695	{ 0, NULL },
696};
697
698static const char *
699vlan_str(const uint16_t vid)
700{
701	static char buf[sizeof("65535 (bogus)")];
702	const char *fmt;
703
704	if (vid == OFP_VLAN_NONE)
705		return "NONE";
706	fmt = (vid > 0 && vid < 0x0fff) ? "%u" : "%u (bogus)";
707	snprintf(buf, sizeof(buf), fmt, vid);
708	return buf;
709}
710
711static const char *
712pcp_str(const uint8_t pcp)
713{
714	static char buf[sizeof("255 (bogus)")];
715	snprintf(buf, sizeof(buf), pcp <= 7 ? "%u" : "%u (bogus)", pcp);
716	return buf;
717}
718
719static void
720of10_bitmap_print(netdissect_options *ndo,
721                  const struct tok *t, const uint32_t v, const uint32_t u)
722{
723	const char *sep = " (";
724
725	if (v == 0)
726		return;
727	/* assigned bits */
728	for (; t->s != NULL; t++)
729		if (v & t->v) {
730			ND_PRINT((ndo, "%s%s", sep, t->s));
731			sep = ", ";
732		}
733	/* unassigned bits? */
734	ND_PRINT((ndo, v & u ? ") (bogus)" : ")"));
735}
736
737static const u_char *
738of10_data_print(netdissect_options *ndo,
739                const u_char *cp, const u_char *ep, const u_int len)
740{
741	if (len == 0)
742		return cp;
743	/* data */
744	ND_PRINT((ndo, "\n\t data (%u octets)", len));
745	ND_TCHECK2(*cp, len);
746	if (ndo->ndo_vflag >= 2)
747		hex_and_ascii_print(ndo, "\n\t  ", cp, len);
748	return cp + len;
749
750trunc:
751	ND_PRINT((ndo, "%s", tstr));
752	return ep;
753}
754
755static const u_char *
756of10_bsn_message_print(netdissect_options *ndo,
757                       const u_char *cp, const u_char *ep, const u_int len)
758{
759	const u_char *cp0 = cp;
760	uint32_t subtype;
761
762	if (len < 4)
763		goto invalid;
764	/* subtype */
765	ND_TCHECK2(*cp, 4);
766	subtype = EXTRACT_32BITS(cp);
767	cp += 4;
768	ND_PRINT((ndo, "\n\t subtype %s", tok2str(bsn_subtype_str, "unknown (0x%08x)", subtype)));
769	switch (subtype) {
770	case BSN_GET_IP_MASK_REQUEST:
771		/*
772		 *  0                   1                   2                   3
773		 *  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		 * +---------------+---------------+---------------+---------------+
775		 * |                            subtype                            |
776		 * +---------------+---------------+---------------+---------------+
777		 * |     index     |                      pad                      |
778		 * +---------------+---------------+---------------+---------------+
779		 * |                              pad                              |
780		 * +---------------+---------------+---------------+---------------+
781		 *
782		 */
783		if (len != 12)
784			goto invalid;
785		/* index */
786		ND_TCHECK2(*cp, 1);
787		ND_PRINT((ndo, ", index %u", *cp));
788		cp += 1;
789		/* pad */
790		ND_TCHECK2(*cp, 7);
791		cp += 7;
792		break;
793	case BSN_SET_IP_MASK:
794	case BSN_GET_IP_MASK_REPLY:
795		/*
796		 *  0                   1                   2                   3
797		 *  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		 * +---------------+---------------+---------------+---------------+
799		 * |                            subtype                            |
800		 * +---------------+---------------+---------------+---------------+
801		 * |     index     |                      pad                      |
802		 * +---------------+---------------+---------------+---------------+
803		 * |                              mask                             |
804		 * +---------------+---------------+---------------+---------------+
805		 *
806		 */
807		if (len != 12)
808			goto invalid;
809		/* index */
810		ND_TCHECK2(*cp, 1);
811		ND_PRINT((ndo, ", index %u", *cp));
812		cp += 1;
813		/* pad */
814		ND_TCHECK2(*cp, 3);
815		cp += 3;
816		/* mask */
817		ND_TCHECK2(*cp, 4);
818		ND_PRINT((ndo, ", mask %s", ipaddr_string(ndo, cp)));
819		cp += 4;
820		break;
821	case BSN_SET_MIRRORING:
822	case BSN_GET_MIRRORING_REQUEST:
823	case BSN_GET_MIRRORING_REPLY:
824		/*
825		 *  0                   1                   2                   3
826		 *  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		 * +---------------+---------------+---------------+---------------+
828		 * |                            subtype                            |
829		 * +---------------+---------------+---------------+---------------+
830		 * | report m. p.  |                      pad                      |
831		 * +---------------+---------------+---------------+---------------+
832		 *
833		 */
834		if (len != 8)
835			goto invalid;
836		/* report_mirror_ports */
837		ND_TCHECK2(*cp, 1);
838		ND_PRINT((ndo, ", report_mirror_ports %s", tok2str(bsn_onoff_str, "bogus (%u)", *cp)));
839		cp += 1;
840		/* pad */
841		ND_TCHECK2(*cp, 3);
842		cp += 3;
843		break;
844	case BSN_GET_INTERFACES_REQUEST:
845	case BSN_GET_L2_TABLE_REQUEST:
846	case BSN_BW_ENABLE_GET_REQUEST:
847	case BSN_BW_CLEAR_DATA_REQUEST:
848	case BSN_HYBRID_GET_REQUEST:
849		/*
850		 *  0                   1                   2                   3
851		 *  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		 * +---------------+---------------+---------------+---------------+
853		 * |                            subtype                            |
854		 * +---------------+---------------+---------------+---------------+
855		 *
856		 */
857		if (len != 4)
858			goto invalid;
859		break;
860	case BSN_VIRTUAL_PORT_REMOVE_REQUEST:
861		/*
862		 *  0                   1                   2                   3
863		 *  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		 * +---------------+---------------+---------------+---------------+
865		 * |                            subtype                            |
866		 * +---------------+---------------+---------------+---------------+
867		 * |                           vport_no                            |
868		 * +---------------+---------------+---------------+---------------+
869		 *
870		 */
871		if (len != 8)
872			goto invalid;
873		/* vport_no */
874		ND_TCHECK2(*cp, 4);
875		ND_PRINT((ndo, ", vport_no %u", EXTRACT_32BITS(cp)));
876		cp += 4;
877		break;
878	case BSN_SHELL_COMMAND:
879		/*
880		 *  0                   1                   2                   3
881		 *  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		 * +---------------+---------------+---------------+---------------+
883		 * |                            subtype                            |
884		 * +---------------+---------------+---------------+---------------+
885		 * |                            service                            |
886		 * +---------------+---------------+---------------+---------------+
887		 * |                             data ...
888		 * +---------------+---------------+--------
889		 *
890		 */
891		if (len < 8)
892			goto invalid;
893		/* service */
894		ND_TCHECK2(*cp, 4);
895		ND_PRINT((ndo, ", service %u", EXTRACT_32BITS(cp)));
896		cp += 4;
897		/* data */
898		ND_PRINT((ndo, ", data '"));
899		if (fn_printn(ndo, cp, len - 8, ep)) {
900			ND_PRINT((ndo, "'"));
901			goto trunc;
902		}
903		ND_PRINT((ndo, "'"));
904		cp += len - 8;
905		break;
906	case BSN_SHELL_OUTPUT:
907		/*
908		 *  0                   1                   2                   3
909		 *  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		 * +---------------+---------------+---------------+---------------+
911		 * |                            subtype                            |
912		 * +---------------+---------------+---------------+---------------+
913		 * |                             data ...
914		 * +---------------+---------------+--------
915		 *
916		 */
917		/* already checked that len >= 4 */
918		/* data */
919		ND_PRINT((ndo, ", data '"));
920		if (fn_printn(ndo, cp, len - 4, ep)) {
921			ND_PRINT((ndo, "'"));
922			goto trunc;
923		}
924		ND_PRINT((ndo, "'"));
925		cp += len - 4;
926		break;
927	case BSN_SHELL_STATUS:
928		/*
929		 *  0                   1                   2                   3
930		 *  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		 * +---------------+---------------+---------------+---------------+
932		 * |                            subtype                            |
933		 * +---------------+---------------+---------------+---------------+
934		 * |                            status                             |
935		 * +---------------+---------------+---------------+---------------+
936		 *
937		 */
938		if (len != 8)
939			goto invalid;
940		/* status */
941		ND_TCHECK2(*cp, 4);
942		ND_PRINT((ndo, ", status 0x%08x", EXTRACT_32BITS(cp)));
943		cp += 4;
944		break;
945	default:
946		ND_TCHECK2(*cp, len - 4);
947		cp += len - 4;
948	}
949	return cp;
950
951invalid: /* skip the undersized data */
952	ND_PRINT((ndo, "%s", istr));
953	ND_TCHECK2(*cp0, len);
954	return cp0 + len;
955trunc:
956	ND_PRINT((ndo, "%s", tstr));
957	return ep;
958}
959
960static const u_char *
961of10_bsn_actions_print(netdissect_options *ndo,
962                       const u_char *cp, const u_char *ep, const u_int len)
963{
964	const u_char *cp0 = cp;
965	uint32_t subtype, vlan_tag;
966
967	if (len < 4)
968		goto invalid;
969	/* subtype */
970	ND_TCHECK2(*cp, 4);
971	subtype = EXTRACT_32BITS(cp);
972	cp += 4;
973	ND_PRINT((ndo, "\n\t  subtype %s", tok2str(bsn_action_subtype_str, "unknown (0x%08x)", subtype)));
974	switch (subtype) {
975	case BSN_ACTION_MIRROR:
976		/*
977		 *  0                   1                   2                   3
978		 *  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		 * +---------------+---------------+---------------+---------------+
980		 * |                            subtype                            |
981		 * +---------------+---------------+---------------+---------------+
982		 * |                           dest_port                           |
983		 * +---------------+---------------+---------------+---------------+
984		 * |                           vlan_tag                            |
985		 * +---------------+---------------+---------------+---------------+
986		 * |  copy_stage   |                      pad                      |
987		 * +---------------+---------------+---------------+---------------+
988		 *
989		 */
990		if (len != 16)
991			goto invalid;
992		/* dest_port */
993		ND_TCHECK2(*cp, 4);
994		ND_PRINT((ndo, ", dest_port %u", EXTRACT_32BITS(cp)));
995		cp += 4;
996		/* vlan_tag */
997		ND_TCHECK2(*cp, 4);
998		vlan_tag = EXTRACT_32BITS(cp);
999		cp += 4;
1000		switch (vlan_tag >> 16) {
1001		case 0:
1002			ND_PRINT((ndo, ", vlan_tag none"));
1003			break;
1004		case ETHERTYPE_8021Q:
1005			ND_PRINT((ndo, ", vlan_tag 802.1Q (%s)", ieee8021q_tci_string(vlan_tag & 0xffff)));
1006			break;
1007		default:
1008			ND_PRINT((ndo, ", vlan_tag unknown (0x%04x)", vlan_tag >> 16));
1009		}
1010		/* copy_stage */
1011		ND_TCHECK2(*cp, 1);
1012		ND_PRINT((ndo, ", copy_stage %s", tok2str(bsn_mirror_copy_stage_str, "unknown (%u)", *cp)));
1013		cp += 1;
1014		/* pad */
1015		ND_TCHECK2(*cp, 3);
1016		cp += 3;
1017		break;
1018	default:
1019		ND_TCHECK2(*cp, len - 4);
1020		cp += len - 4;
1021	}
1022
1023	return cp;
1024
1025invalid:
1026	ND_PRINT((ndo, "%s", istr));
1027	ND_TCHECK2(*cp0, len);
1028	return cp0 + len;
1029trunc:
1030	ND_PRINT((ndo, "%s", tstr));
1031	return ep;
1032}
1033
1034static const u_char *
1035of10_vendor_action_print(netdissect_options *ndo,
1036                         const u_char *cp, const u_char *ep, const u_int len)
1037{
1038	uint32_t vendor;
1039	const u_char *(*decoder)(netdissect_options *, const u_char *, const u_char *, const u_int);
1040
1041	if (len < 4)
1042		goto invalid;
1043	/* vendor */
1044	ND_TCHECK2(*cp, 4);
1045	vendor = EXTRACT_32BITS(cp);
1046	cp += 4;
1047	ND_PRINT((ndo, ", vendor 0x%08x (%s)", vendor, of_vendor_name(vendor)));
1048	/* data */
1049	decoder =
1050		vendor == OUI_BSN         ? of10_bsn_actions_print         :
1051		of10_data_print;
1052	return decoder(ndo, cp, ep, len - 4);
1053
1054invalid: /* skip the undersized data */
1055	ND_PRINT((ndo, "%s", istr));
1056	ND_TCHECK2(*cp, len);
1057	return cp + len;
1058trunc:
1059	ND_PRINT((ndo, "%s", tstr));
1060	return ep;
1061}
1062
1063static const u_char *
1064of10_vendor_message_print(netdissect_options *ndo,
1065                          const u_char *cp, const u_char *ep, const u_int len)
1066{
1067	uint32_t vendor;
1068	const u_char *(*decoder)(netdissect_options *, const u_char *, const u_char *, u_int);
1069
1070	if (len < 4)
1071		goto invalid;
1072	/* vendor */
1073	ND_TCHECK2(*cp, 4);
1074	vendor = EXTRACT_32BITS(cp);
1075	cp += 4;
1076	ND_PRINT((ndo, ", vendor 0x%08x (%s)", vendor, of_vendor_name(vendor)));
1077	/* data */
1078	decoder =
1079		vendor == OUI_BSN         ? of10_bsn_message_print         :
1080		of10_data_print;
1081	return decoder(ndo, cp, ep, len - 4);
1082
1083invalid: /* skip the undersized data */
1084	ND_PRINT((ndo, "%s", istr));
1085	ND_TCHECK2(*cp, len);
1086	return cp + len;
1087trunc:
1088	ND_PRINT((ndo, "%s", tstr));
1089	return ep;
1090}
1091
1092/* Vendor ID is mandatory, data is optional. */
1093static const u_char *
1094of10_vendor_data_print(netdissect_options *ndo,
1095                       const u_char *cp, const u_char *ep, const u_int len)
1096{
1097	uint32_t vendor;
1098
1099	if (len < 4)
1100		goto invalid;
1101	/* vendor */
1102	ND_TCHECK2(*cp, 4);
1103	vendor = EXTRACT_32BITS(cp);
1104	cp += 4;
1105	ND_PRINT((ndo, ", vendor 0x%08x (%s)", vendor, of_vendor_name(vendor)));
1106	/* data */
1107	return of10_data_print(ndo, cp, ep, len - 4);
1108
1109invalid: /* skip the undersized data */
1110	ND_PRINT((ndo, "%s", istr));
1111	ND_TCHECK2(*cp, len);
1112	return cp + len;
1113trunc:
1114	ND_PRINT((ndo, "%s", tstr));
1115	return ep;
1116}
1117
1118static const u_char *
1119of10_packet_data_print(netdissect_options *ndo,
1120                       const u_char *cp, const u_char *ep, const u_int len)
1121{
1122	if (len == 0)
1123		return cp;
1124	/* data */
1125	ND_PRINT((ndo, "\n\t data (%u octets)", len));
1126	if (ndo->ndo_vflag < 3)
1127		return cp + len;
1128	ND_TCHECK2(*cp, len);
1129	ndo->ndo_vflag -= 3;
1130	ND_PRINT((ndo, ", frame decoding below\n"));
1131	ether_print(ndo, cp, len, ndo->ndo_snapend - cp, NULL, NULL);
1132	ndo->ndo_vflag += 3;
1133	return cp + len;
1134
1135trunc:
1136	ND_PRINT((ndo, "%s", tstr));
1137	return ep;
1138}
1139
1140/* [OF10] Section 5.2.1 */
1141static const u_char *
1142of10_phy_ports_print(netdissect_options *ndo,
1143                     const u_char *cp, const u_char *ep, u_int len)
1144{
1145	const u_char *cp0 = cp;
1146	const u_int len0 = len;
1147
1148	while (len) {
1149		if (len < OF_PHY_PORT_LEN)
1150			goto invalid;
1151		/* port_no */
1152		ND_TCHECK2(*cp, 2);
1153		ND_PRINT((ndo, "\n\t  port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
1154		cp += 2;
1155		/* hw_addr */
1156		ND_TCHECK2(*cp, ETHER_ADDR_LEN);
1157		ND_PRINT((ndo, ", hw_addr %s", etheraddr_string(ndo, cp)));
1158		cp += ETHER_ADDR_LEN;
1159		/* name */
1160		ND_TCHECK2(*cp, OFP_MAX_PORT_NAME_LEN);
1161		ND_PRINT((ndo, ", name '"));
1162		fn_print(ndo, cp, cp + OFP_MAX_PORT_NAME_LEN);
1163		ND_PRINT((ndo, "'"));
1164		cp += OFP_MAX_PORT_NAME_LEN;
1165
1166		if (ndo->ndo_vflag < 2) {
1167			ND_TCHECK2(*cp, 24);
1168			cp += 24;
1169			goto next_port;
1170		}
1171		/* config */
1172		ND_TCHECK2(*cp, 4);
1173		ND_PRINT((ndo, "\n\t   config 0x%08x", EXTRACT_32BITS(cp)));
1174		of10_bitmap_print(ndo, ofppc_bm, EXTRACT_32BITS(cp), OFPPC_U);
1175		cp += 4;
1176		/* state */
1177		ND_TCHECK2(*cp, 4);
1178		ND_PRINT((ndo, "\n\t   state 0x%08x", EXTRACT_32BITS(cp)));
1179		of10_bitmap_print(ndo, ofpps_bm, EXTRACT_32BITS(cp), OFPPS_U);
1180		cp += 4;
1181		/* curr */
1182		ND_TCHECK2(*cp, 4);
1183		ND_PRINT((ndo, "\n\t   curr 0x%08x", EXTRACT_32BITS(cp)));
1184		of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U);
1185		cp += 4;
1186		/* advertised */
1187		ND_TCHECK2(*cp, 4);
1188		ND_PRINT((ndo, "\n\t   advertised 0x%08x", EXTRACT_32BITS(cp)));
1189		of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U);
1190		cp += 4;
1191		/* supported */
1192		ND_TCHECK2(*cp, 4);
1193		ND_PRINT((ndo, "\n\t   supported 0x%08x", EXTRACT_32BITS(cp)));
1194		of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U);
1195		cp += 4;
1196		/* peer */
1197		ND_TCHECK2(*cp, 4);
1198		ND_PRINT((ndo, "\n\t   peer 0x%08x", EXTRACT_32BITS(cp)));
1199		of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U);
1200		cp += 4;
1201next_port:
1202		len -= OF_PHY_PORT_LEN;
1203	} /* while */
1204	return cp;
1205
1206invalid: /* skip the undersized trailing data */
1207	ND_PRINT((ndo, "%s", istr));
1208	ND_TCHECK2(*cp0, len0);
1209	return cp0 + len0;
1210trunc:
1211	ND_PRINT((ndo, "%s", tstr));
1212	return ep;
1213}
1214
1215/* [OF10] Section 5.2.2 */
1216static const u_char *
1217of10_queue_props_print(netdissect_options *ndo,
1218                       const u_char *cp, const u_char *ep, u_int len)
1219{
1220	const u_char *cp0 = cp;
1221	const u_int len0 = len;
1222	uint16_t property, plen, rate;
1223
1224	while (len) {
1225		u_char plen_bogus = 0, skip = 0;
1226
1227		if (len < OF_QUEUE_PROP_HEADER_LEN)
1228			goto invalid;
1229		/* property */
1230		ND_TCHECK2(*cp, 2);
1231		property = EXTRACT_16BITS(cp);
1232		cp += 2;
1233		ND_PRINT((ndo, "\n\t   property %s", tok2str(ofpqt_str, "invalid (0x%04x)", property)));
1234		/* len */
1235		ND_TCHECK2(*cp, 2);
1236		plen = EXTRACT_16BITS(cp);
1237		cp += 2;
1238		ND_PRINT((ndo, ", len %u", plen));
1239		if (plen < OF_QUEUE_PROP_HEADER_LEN || plen > len)
1240			goto invalid;
1241		/* pad */
1242		ND_TCHECK2(*cp, 4);
1243		cp += 4;
1244		/* property-specific constraints and decoding */
1245		switch (property) {
1246		case OFPQT_NONE:
1247			plen_bogus = plen != OF_QUEUE_PROP_HEADER_LEN;
1248			break;
1249		case OFPQT_MIN_RATE:
1250			plen_bogus = plen != OF_QUEUE_PROP_MIN_RATE_LEN;
1251			break;
1252		default:
1253			skip = 1;
1254		}
1255		if (plen_bogus) {
1256			ND_PRINT((ndo, " (bogus)"));
1257			skip = 1;
1258		}
1259		if (skip) {
1260			ND_TCHECK2(*cp, plen - 4);
1261			cp += plen - 4;
1262			goto next_property;
1263		}
1264		if (property == OFPQT_MIN_RATE) { /* the only case of property decoding */
1265			/* rate */
1266			ND_TCHECK2(*cp, 2);
1267			rate = EXTRACT_16BITS(cp);
1268			cp += 2;
1269			if (rate > 1000)
1270				ND_PRINT((ndo, ", rate disabled"));
1271			else
1272				ND_PRINT((ndo, ", rate %u.%u%%", rate / 10, rate % 10));
1273			/* pad */
1274			ND_TCHECK2(*cp, 6);
1275			cp += 6;
1276		}
1277next_property:
1278		len -= plen;
1279	} /* while */
1280	return cp;
1281
1282invalid: /* skip the rest of queue properties */
1283	ND_PRINT((ndo, "%s", istr));
1284	ND_TCHECK2(*cp0, len0);
1285	return cp0 + len0;
1286trunc:
1287	ND_PRINT((ndo, "%s", tstr));
1288	return ep;
1289}
1290
1291/* ibid */
1292static const u_char *
1293of10_queues_print(netdissect_options *ndo,
1294                  const u_char *cp, const u_char *ep, u_int len)
1295{
1296	const u_char *cp0 = cp;
1297	const u_int len0 = len;
1298	uint16_t desclen;
1299
1300	while (len) {
1301		if (len < OF_PACKET_QUEUE_LEN)
1302			goto invalid;
1303		/* queue_id */
1304		ND_TCHECK2(*cp, 4);
1305		ND_PRINT((ndo, "\n\t  queue_id %u", EXTRACT_32BITS(cp)));
1306		cp += 4;
1307		/* len */
1308		ND_TCHECK2(*cp, 2);
1309		desclen = EXTRACT_16BITS(cp);
1310		cp += 2;
1311		ND_PRINT((ndo, ", len %u", desclen));
1312		if (desclen < OF_PACKET_QUEUE_LEN || desclen > len)
1313			goto invalid;
1314		/* pad */
1315		ND_TCHECK2(*cp, 2);
1316		cp += 2;
1317		/* properties */
1318		if (ndo->ndo_vflag < 2) {
1319			ND_TCHECK2(*cp, desclen - OF_PACKET_QUEUE_LEN);
1320			cp += desclen - OF_PACKET_QUEUE_LEN;
1321			goto next_queue;
1322		}
1323		if (ep == (cp = of10_queue_props_print(ndo, cp, ep, desclen - OF_PACKET_QUEUE_LEN)))
1324			return ep; /* end of snapshot */
1325next_queue:
1326		len -= desclen;
1327	} /* while */
1328	return cp;
1329
1330invalid: /* skip the rest of queues */
1331	ND_PRINT((ndo, "%s", istr));
1332	ND_TCHECK2(*cp0, len0);
1333	return cp0 + len0;
1334trunc:
1335	ND_PRINT((ndo, "%s", tstr));
1336	return ep;
1337}
1338
1339/* [OF10] Section 5.2.3 */
1340static const u_char *
1341of10_match_print(netdissect_options *ndo,
1342                 const char *pfx, const u_char *cp, const u_char *ep)
1343{
1344	uint32_t wildcards;
1345	uint16_t dl_type;
1346	uint8_t nw_proto;
1347	u_char nw_bits;
1348	const char *field_name;
1349
1350	/* wildcards */
1351	ND_TCHECK2(*cp, 4);
1352	wildcards = EXTRACT_32BITS(cp);
1353	if (wildcards & OFPFW_U)
1354		ND_PRINT((ndo, "%swildcards 0x%08x (bogus)", pfx, wildcards));
1355	cp += 4;
1356	/* in_port */
1357	ND_TCHECK2(*cp, 2);
1358	if (! (wildcards & OFPFW_IN_PORT))
1359		ND_PRINT((ndo, "%smatch in_port %s", pfx, tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
1360	cp += 2;
1361	/* dl_src */
1362	ND_TCHECK2(*cp, ETHER_ADDR_LEN);
1363	if (! (wildcards & OFPFW_DL_SRC))
1364		ND_PRINT((ndo, "%smatch dl_src %s", pfx, etheraddr_string(ndo, cp)));
1365	cp += ETHER_ADDR_LEN;
1366	/* dl_dst */
1367	ND_TCHECK2(*cp, ETHER_ADDR_LEN);
1368	if (! (wildcards & OFPFW_DL_DST))
1369		ND_PRINT((ndo, "%smatch dl_dst %s", pfx, etheraddr_string(ndo, cp)));
1370	cp += ETHER_ADDR_LEN;
1371	/* dl_vlan */
1372	ND_TCHECK2(*cp, 2);
1373	if (! (wildcards & OFPFW_DL_VLAN))
1374		ND_PRINT((ndo, "%smatch dl_vlan %s", pfx, vlan_str(EXTRACT_16BITS(cp))));
1375	cp += 2;
1376	/* dl_vlan_pcp */
1377	ND_TCHECK2(*cp, 1);
1378	if (! (wildcards & OFPFW_DL_VLAN_PCP))
1379		ND_PRINT((ndo, "%smatch dl_vlan_pcp %s", pfx, pcp_str(*cp)));
1380	cp += 1;
1381	/* pad1 */
1382	ND_TCHECK2(*cp, 1);
1383	cp += 1;
1384	/* dl_type */
1385	ND_TCHECK2(*cp, 2);
1386	dl_type = EXTRACT_16BITS(cp);
1387	cp += 2;
1388	if (! (wildcards & OFPFW_DL_TYPE))
1389		ND_PRINT((ndo, "%smatch dl_type 0x%04x", pfx, dl_type));
1390	/* nw_tos */
1391	ND_TCHECK2(*cp, 1);
1392	if (! (wildcards & OFPFW_NW_TOS))
1393		ND_PRINT((ndo, "%smatch nw_tos 0x%02x", pfx, *cp));
1394	cp += 1;
1395	/* nw_proto */
1396	ND_TCHECK2(*cp, 1);
1397	nw_proto = *cp;
1398	cp += 1;
1399	if (! (wildcards & OFPFW_NW_PROTO)) {
1400		field_name = ! (wildcards & OFPFW_DL_TYPE) && dl_type == ETHERTYPE_ARP
1401		  ? "arp_opcode" : "nw_proto";
1402		ND_PRINT((ndo, "%smatch %s %u", pfx, field_name, nw_proto));
1403	}
1404	/* pad2 */
1405	ND_TCHECK2(*cp, 2);
1406	cp += 2;
1407	/* nw_src */
1408	ND_TCHECK2(*cp, 4);
1409	nw_bits = (wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT;
1410	if (nw_bits < 32)
1411		ND_PRINT((ndo, "%smatch nw_src %s/%u", pfx, ipaddr_string(ndo, cp), 32 - nw_bits));
1412	cp += 4;
1413	/* nw_dst */
1414	ND_TCHECK2(*cp, 4);
1415	nw_bits = (wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT;
1416	if (nw_bits < 32)
1417		ND_PRINT((ndo, "%smatch nw_dst %s/%u", pfx, ipaddr_string(ndo, cp), 32 - nw_bits));
1418	cp += 4;
1419	/* tp_src */
1420	ND_TCHECK2(*cp, 2);
1421	if (! (wildcards & OFPFW_TP_SRC)) {
1422		field_name = ! (wildcards & OFPFW_DL_TYPE) && dl_type == ETHERTYPE_IP
1423		  && ! (wildcards & OFPFW_NW_PROTO) && nw_proto == IPPROTO_ICMP
1424		  ? "icmp_type" : "tp_src";
1425		ND_PRINT((ndo, "%smatch %s %u", pfx, field_name, EXTRACT_16BITS(cp)));
1426	}
1427	cp += 2;
1428	/* tp_dst */
1429	ND_TCHECK2(*cp, 2);
1430	if (! (wildcards & OFPFW_TP_DST)) {
1431		field_name = ! (wildcards & OFPFW_DL_TYPE) && dl_type == ETHERTYPE_IP
1432		  && ! (wildcards & OFPFW_NW_PROTO) && nw_proto == IPPROTO_ICMP
1433		  ? "icmp_code" : "tp_dst";
1434		ND_PRINT((ndo, "%smatch %s %u", pfx, field_name, EXTRACT_16BITS(cp)));
1435	}
1436	return cp + 2;
1437
1438trunc:
1439	ND_PRINT((ndo, "%s", tstr));
1440	return ep;
1441}
1442
1443/* [OF10] Section 5.2.4 */
1444static const u_char *
1445of10_actions_print(netdissect_options *ndo,
1446                   const char *pfx, const u_char *cp, const u_char *ep,
1447                   u_int len)
1448{
1449	const u_char *cp0 = cp;
1450	const u_int len0 = len;
1451	uint16_t type, alen, output_port;
1452
1453	while (len) {
1454		u_char alen_bogus = 0, skip = 0;
1455
1456		if (len < OF_ACTION_HEADER_LEN)
1457			goto invalid;
1458		/* type */
1459		ND_TCHECK2(*cp, 2);
1460		type = EXTRACT_16BITS(cp);
1461		cp += 2;
1462		ND_PRINT((ndo, "%saction type %s", pfx, tok2str(ofpat_str, "invalid (0x%04x)", type)));
1463		/* length */
1464		ND_TCHECK2(*cp, 2);
1465		alen = EXTRACT_16BITS(cp);
1466		cp += 2;
1467		ND_PRINT((ndo, ", len %u", alen));
1468		/* On action size underrun/overrun skip the rest of the action list. */
1469		if (alen < OF_ACTION_HEADER_LEN || alen > len)
1470			goto invalid;
1471		/* On action size inappropriate for the given type or invalid type just skip
1472		 * the current action, as the basic length constraint has been met. */
1473		switch (type) {
1474		case OFPAT_OUTPUT:
1475		case OFPAT_SET_VLAN_VID:
1476		case OFPAT_SET_VLAN_PCP:
1477		case OFPAT_STRIP_VLAN:
1478		case OFPAT_SET_NW_SRC:
1479		case OFPAT_SET_NW_DST:
1480		case OFPAT_SET_NW_TOS:
1481		case OFPAT_SET_TP_SRC:
1482		case OFPAT_SET_TP_DST:
1483			alen_bogus = alen != 8;
1484			break;
1485		case OFPAT_SET_DL_SRC:
1486		case OFPAT_SET_DL_DST:
1487		case OFPAT_ENQUEUE:
1488			alen_bogus = alen != 16;
1489			break;
1490		case OFPAT_VENDOR:
1491			alen_bogus = alen % 8 != 0; /* already >= 8 so far */
1492			break;
1493		default:
1494			skip = 1;
1495		}
1496		if (alen_bogus) {
1497			ND_PRINT((ndo, " (bogus)"));
1498			skip = 1;
1499		}
1500		if (skip) {
1501			ND_TCHECK2(*cp, alen - 4);
1502			cp += alen - 4;
1503			goto next_action;
1504		}
1505		/* OK to decode the rest of the action structure */
1506		switch (type) {
1507		case OFPAT_OUTPUT:
1508			/* port */
1509			ND_TCHECK2(*cp, 2);
1510			output_port = EXTRACT_16BITS(cp);
1511			cp += 2;
1512			ND_PRINT((ndo, ", port %s", tok2str(ofpp_str, "%u", output_port)));
1513			/* max_len */
1514			ND_TCHECK2(*cp, 2);
1515			if (output_port == OFPP_CONTROLLER)
1516				ND_PRINT((ndo, ", max_len %u", EXTRACT_16BITS(cp)));
1517			cp += 2;
1518			break;
1519		case OFPAT_SET_VLAN_VID:
1520			/* vlan_vid */
1521			ND_TCHECK2(*cp, 2);
1522			ND_PRINT((ndo, ", vlan_vid %s", vlan_str(EXTRACT_16BITS(cp))));
1523			cp += 2;
1524			/* pad */
1525			ND_TCHECK2(*cp, 2);
1526			cp += 2;
1527			break;
1528		case OFPAT_SET_VLAN_PCP:
1529			/* vlan_pcp */
1530			ND_TCHECK2(*cp, 1);
1531			ND_PRINT((ndo, ", vlan_pcp %s", pcp_str(*cp)));
1532			cp += 1;
1533			/* pad */
1534			ND_TCHECK2(*cp, 3);
1535			cp += 3;
1536			break;
1537		case OFPAT_SET_DL_SRC:
1538		case OFPAT_SET_DL_DST:
1539			/* dl_addr */
1540			ND_TCHECK2(*cp, ETHER_ADDR_LEN);
1541			ND_PRINT((ndo, ", dl_addr %s", etheraddr_string(ndo, cp)));
1542			cp += ETHER_ADDR_LEN;
1543			/* pad */
1544			ND_TCHECK2(*cp, 6);
1545			cp += 6;
1546			break;
1547		case OFPAT_SET_NW_SRC:
1548		case OFPAT_SET_NW_DST:
1549			/* nw_addr */
1550			ND_TCHECK2(*cp, 4);
1551			ND_PRINT((ndo, ", nw_addr %s", ipaddr_string(ndo, cp)));
1552			cp += 4;
1553			break;
1554		case OFPAT_SET_NW_TOS:
1555			/* nw_tos */
1556			ND_TCHECK2(*cp, 1);
1557			ND_PRINT((ndo, ", nw_tos 0x%02x", *cp));
1558			cp += 1;
1559			/* pad */
1560			ND_TCHECK2(*cp, 3);
1561			cp += 3;
1562			break;
1563		case OFPAT_SET_TP_SRC:
1564		case OFPAT_SET_TP_DST:
1565			/* nw_tos */
1566			ND_TCHECK2(*cp, 2);
1567			ND_PRINT((ndo, ", tp_port %u", EXTRACT_16BITS(cp)));
1568			cp += 2;
1569			/* pad */
1570			ND_TCHECK2(*cp, 2);
1571			cp += 2;
1572			break;
1573		case OFPAT_ENQUEUE:
1574			/* port */
1575			ND_TCHECK2(*cp, 2);
1576			ND_PRINT((ndo, ", port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
1577			cp += 2;
1578			/* pad */
1579			ND_TCHECK2(*cp, 6);
1580			cp += 6;
1581			/* queue_id */
1582			ND_TCHECK2(*cp, 4);
1583			ND_PRINT((ndo, ", queue_id %s", tok2str(ofpq_str, "%u", EXTRACT_32BITS(cp))));
1584			cp += 4;
1585			break;
1586		case OFPAT_VENDOR:
1587			if (ep == (cp = of10_vendor_action_print(ndo, cp, ep, alen - 4)))
1588				return ep; /* end of snapshot */
1589			break;
1590		case OFPAT_STRIP_VLAN:
1591			/* pad */
1592			ND_TCHECK2(*cp, 4);
1593			cp += 4;
1594			break;
1595		} /* switch */
1596next_action:
1597		len -= alen;
1598	} /* while */
1599	return cp;
1600
1601invalid: /* skip the rest of actions */
1602	ND_PRINT((ndo, "%s", istr));
1603	ND_TCHECK2(*cp0, len0);
1604	return cp0 + len0;
1605trunc:
1606	ND_PRINT((ndo, "%s", tstr));
1607	return ep;
1608}
1609
1610/* [OF10] Section 5.3.1 */
1611static const u_char *
1612of10_features_reply_print(netdissect_options *ndo,
1613                          const u_char *cp, const u_char *ep, const u_int len)
1614{
1615	/* datapath_id */
1616	ND_TCHECK2(*cp, 8);
1617	ND_PRINT((ndo, "\n\t dpid 0x%016" PRIx64, EXTRACT_64BITS(cp)));
1618	cp += 8;
1619	/* n_buffers */
1620	ND_TCHECK2(*cp, 4);
1621	ND_PRINT((ndo, ", n_buffers %u", EXTRACT_32BITS(cp)));
1622	cp += 4;
1623	/* n_tables */
1624	ND_TCHECK2(*cp, 1);
1625	ND_PRINT((ndo, ", n_tables %u", *cp));
1626	cp += 1;
1627	/* pad */
1628	ND_TCHECK2(*cp, 3);
1629	cp += 3;
1630	/* capabilities */
1631	ND_TCHECK2(*cp, 4);
1632	ND_PRINT((ndo, "\n\t capabilities 0x%08x", EXTRACT_32BITS(cp)));
1633	of10_bitmap_print(ndo, ofp_capabilities_bm, EXTRACT_32BITS(cp), OFPCAP_U);
1634	cp += 4;
1635	/* actions */
1636	ND_TCHECK2(*cp, 4);
1637	ND_PRINT((ndo, "\n\t actions 0x%08x", EXTRACT_32BITS(cp)));
1638	of10_bitmap_print(ndo, ofpat_bm, EXTRACT_32BITS(cp), OFPAT_U);
1639	cp += 4;
1640	/* ports */
1641	return of10_phy_ports_print(ndo, cp, ep, len - OF_SWITCH_FEATURES_LEN);
1642
1643trunc:
1644	ND_PRINT((ndo, "%s", tstr));
1645	return ep;
1646}
1647
1648/* [OF10] Section 5.3.3 */
1649static const u_char *
1650of10_flow_mod_print(netdissect_options *ndo,
1651                    const u_char *cp, const u_char *ep, const u_int len)
1652{
1653	uint16_t command;
1654
1655	/* match */
1656	if (ep == (cp = of10_match_print(ndo, "\n\t ", cp, ep)))
1657		return ep; /* end of snapshot */
1658	/* cookie */
1659	ND_TCHECK2(*cp, 8);
1660	ND_PRINT((ndo, "\n\t cookie 0x%016" PRIx64, EXTRACT_64BITS(cp)));
1661	cp += 8;
1662	/* command */
1663	ND_TCHECK2(*cp, 2);
1664	command = EXTRACT_16BITS(cp);
1665	ND_PRINT((ndo, ", command %s", tok2str(ofpfc_str, "invalid (0x%04x)", command)));
1666	cp += 2;
1667	/* idle_timeout */
1668	ND_TCHECK2(*cp, 2);
1669	if (EXTRACT_16BITS(cp))
1670		ND_PRINT((ndo, ", idle_timeout %u", EXTRACT_16BITS(cp)));
1671	cp += 2;
1672	/* hard_timeout */
1673	ND_TCHECK2(*cp, 2);
1674	if (EXTRACT_16BITS(cp))
1675		ND_PRINT((ndo, ", hard_timeout %u", EXTRACT_16BITS(cp)));
1676	cp += 2;
1677	/* priority */
1678	ND_TCHECK2(*cp, 2);
1679	if (EXTRACT_16BITS(cp))
1680		ND_PRINT((ndo, ", priority %u", EXTRACT_16BITS(cp)));
1681	cp += 2;
1682	/* buffer_id */
1683	ND_TCHECK2(*cp, 4);
1684	if (command == OFPFC_ADD || command == OFPFC_MODIFY ||
1685	    command == OFPFC_MODIFY_STRICT)
1686		ND_PRINT((ndo, ", buffer_id %s", tok2str(bufferid_str, "0x%08x", EXTRACT_32BITS(cp))));
1687	cp += 4;
1688	/* out_port */
1689	ND_TCHECK2(*cp, 2);
1690	if (command == OFPFC_DELETE || command == OFPFC_DELETE_STRICT)
1691		ND_PRINT((ndo, ", out_port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
1692	cp += 2;
1693	/* flags */
1694	ND_TCHECK2(*cp, 2);
1695	ND_PRINT((ndo, ", flags 0x%04x", EXTRACT_16BITS(cp)));
1696	of10_bitmap_print(ndo, ofpff_bm, EXTRACT_16BITS(cp), OFPFF_U);
1697	cp += 2;
1698	/* actions */
1699	return of10_actions_print(ndo, "\n\t ", cp, ep, len - OF_FLOW_MOD_LEN);
1700
1701trunc:
1702	ND_PRINT((ndo, "%s", tstr));
1703	return ep;
1704}
1705
1706/* ibid */
1707static const u_char *
1708of10_port_mod_print(netdissect_options *ndo,
1709                    const u_char *cp, const u_char *ep)
1710{
1711	/* port_no */
1712	ND_TCHECK2(*cp, 2);
1713	ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
1714	cp += 2;
1715	/* hw_addr */
1716	ND_TCHECK2(*cp, ETHER_ADDR_LEN);
1717	ND_PRINT((ndo, ", hw_addr %s", etheraddr_string(ndo, cp)));
1718	cp += ETHER_ADDR_LEN;
1719	/* config */
1720	ND_TCHECK2(*cp, 4);
1721	ND_PRINT((ndo, "\n\t config 0x%08x", EXTRACT_32BITS(cp)));
1722	of10_bitmap_print(ndo, ofppc_bm, EXTRACT_32BITS(cp), OFPPC_U);
1723	cp += 4;
1724	/* mask */
1725	ND_TCHECK2(*cp, 4);
1726	ND_PRINT((ndo, "\n\t mask 0x%08x", EXTRACT_32BITS(cp)));
1727	of10_bitmap_print(ndo, ofppc_bm, EXTRACT_32BITS(cp), OFPPC_U);
1728	cp += 4;
1729	/* advertise */
1730	ND_TCHECK2(*cp, 4);
1731	ND_PRINT((ndo, "\n\t advertise 0x%08x", EXTRACT_32BITS(cp)));
1732	of10_bitmap_print(ndo, ofppf_bm, EXTRACT_32BITS(cp), OFPPF_U);
1733	cp += 4;
1734	/* pad */
1735	ND_TCHECK2(*cp, 4);
1736	return cp + 4;
1737
1738trunc:
1739	ND_PRINT((ndo, "%s", tstr));
1740	return ep;
1741}
1742
1743/* [OF10] Section 5.3.5 */
1744static const u_char *
1745of10_stats_request_print(netdissect_options *ndo,
1746                         const u_char *cp, const u_char *ep, u_int len)
1747{
1748	const u_char *cp0 = cp;
1749	const u_int len0 = len;
1750	uint16_t type;
1751
1752	/* type */
1753	ND_TCHECK2(*cp, 2);
1754	type = EXTRACT_16BITS(cp);
1755	cp += 2;
1756	ND_PRINT((ndo, "\n\t type %s", tok2str(ofpst_str, "invalid (0x%04x)", type)));
1757	/* flags */
1758	ND_TCHECK2(*cp, 2);
1759	ND_PRINT((ndo, ", flags 0x%04x", EXTRACT_16BITS(cp)));
1760	if (EXTRACT_16BITS(cp))
1761		ND_PRINT((ndo, " (bogus)"));
1762	cp += 2;
1763	/* type-specific body of one of fixed lengths */
1764	len -= OF_STATS_REQUEST_LEN;
1765	switch(type) {
1766	case OFPST_DESC:
1767	case OFPST_TABLE:
1768		if (len)
1769			goto invalid;
1770		return cp;
1771	case OFPST_FLOW:
1772	case OFPST_AGGREGATE:
1773		if (len != OF_FLOW_STATS_REQUEST_LEN)
1774			goto invalid;
1775		/* match */
1776		if (ep == (cp = of10_match_print(ndo, "\n\t ", cp, ep)))
1777			return ep; /* end of snapshot */
1778		/* table_id */
1779		ND_TCHECK2(*cp, 1);
1780		ND_PRINT((ndo, "\n\t table_id %s", tok2str(tableid_str, "%u", *cp)));
1781		cp += 1;
1782		/* pad */
1783		ND_TCHECK2(*cp, 1);
1784		cp += 1;
1785		/* out_port */
1786		ND_TCHECK2(*cp, 2);
1787		ND_PRINT((ndo, ", out_port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
1788		return cp + 2;
1789	case OFPST_PORT:
1790		if (len != OF_PORT_STATS_REQUEST_LEN)
1791			goto invalid;
1792		/* port_no */
1793		ND_TCHECK2(*cp, 2);
1794		ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
1795		cp += 2;
1796		/* pad */
1797		ND_TCHECK2(*cp, 6);
1798		return cp + 6;
1799	case OFPST_QUEUE:
1800		if (len != OF_QUEUE_STATS_REQUEST_LEN)
1801			goto invalid;
1802		/* port_no */
1803		ND_TCHECK2(*cp, 2);
1804		ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
1805		cp += 2;
1806		/* pad */
1807		ND_TCHECK2(*cp, 2);
1808		cp += 2;
1809		/* queue_id */
1810		ND_TCHECK2(*cp, 4);
1811		ND_PRINT((ndo, ", queue_id %s", tok2str(ofpq_str, "%u", EXTRACT_32BITS(cp))));
1812		return cp + 4;
1813	case OFPST_VENDOR:
1814		return of10_vendor_data_print(ndo, cp, ep, len);
1815	}
1816	return cp;
1817
1818invalid: /* skip the message body */
1819	ND_PRINT((ndo, "%s", istr));
1820	ND_TCHECK2(*cp0, len0);
1821	return cp0 + len0;
1822trunc:
1823	ND_PRINT((ndo, "%s", tstr));
1824	return ep;
1825}
1826
1827/* ibid */
1828static const u_char *
1829of10_desc_stats_reply_print(netdissect_options *ndo,
1830                            const u_char *cp, const u_char *ep, const u_int len)
1831{
1832	if (len != OF_DESC_STATS_LEN)
1833		goto invalid;
1834	/* mfr_desc */
1835	ND_TCHECK2(*cp, DESC_STR_LEN);
1836	ND_PRINT((ndo, "\n\t  mfr_desc '"));
1837	fn_print(ndo, cp, cp + DESC_STR_LEN);
1838	ND_PRINT((ndo, "'"));
1839	cp += DESC_STR_LEN;
1840	/* hw_desc */
1841	ND_TCHECK2(*cp, DESC_STR_LEN);
1842	ND_PRINT((ndo, "\n\t  hw_desc '"));
1843	fn_print(ndo, cp, cp + DESC_STR_LEN);
1844	ND_PRINT((ndo, "'"));
1845	cp += DESC_STR_LEN;
1846	/* sw_desc */
1847	ND_TCHECK2(*cp, DESC_STR_LEN);
1848	ND_PRINT((ndo, "\n\t  sw_desc '"));
1849	fn_print(ndo, cp, cp + DESC_STR_LEN);
1850	ND_PRINT((ndo, "'"));
1851	cp += DESC_STR_LEN;
1852	/* serial_num */
1853	ND_TCHECK2(*cp, SERIAL_NUM_LEN);
1854	ND_PRINT((ndo, "\n\t  serial_num '"));
1855	fn_print(ndo, cp, cp + SERIAL_NUM_LEN);
1856	ND_PRINT((ndo, "'"));
1857	cp += SERIAL_NUM_LEN;
1858	/* dp_desc */
1859	ND_TCHECK2(*cp, DESC_STR_LEN);
1860	ND_PRINT((ndo, "\n\t  dp_desc '"));
1861	fn_print(ndo, cp, cp + DESC_STR_LEN);
1862	ND_PRINT((ndo, "'"));
1863	return cp + DESC_STR_LEN;
1864
1865invalid: /* skip the message body */
1866	ND_PRINT((ndo, "%s", istr));
1867	ND_TCHECK2(*cp, len);
1868	return cp + len;
1869trunc:
1870	ND_PRINT((ndo, "%s", tstr));
1871	return ep;
1872}
1873
1874/* ibid */
1875static const u_char *
1876of10_flow_stats_reply_print(netdissect_options *ndo,
1877                            const u_char *cp, const u_char *ep, u_int len)
1878{
1879	const u_char *cp0 = cp;
1880	const u_int len0 = len;
1881	uint16_t entry_len;
1882
1883	while (len) {
1884		if (len < OF_FLOW_STATS_LEN)
1885			goto invalid;
1886		/* length */
1887		ND_TCHECK2(*cp, 2);
1888		entry_len = EXTRACT_16BITS(cp);
1889		ND_PRINT((ndo, "\n\t length %u", entry_len));
1890		if (entry_len < OF_FLOW_STATS_LEN || entry_len > len)
1891			goto invalid;
1892		cp += 2;
1893		/* table_id */
1894		ND_TCHECK2(*cp, 1);
1895		ND_PRINT((ndo, ", table_id %s", tok2str(tableid_str, "%u", *cp)));
1896		cp += 1;
1897		/* pad */
1898		ND_TCHECK2(*cp, 1);
1899		cp += 1;
1900		/* match */
1901		if (ep == (cp = of10_match_print(ndo, "\n\t  ", cp, ep)))
1902			return ep; /* end of snapshot */
1903		/* duration_sec */
1904		ND_TCHECK2(*cp, 4);
1905		ND_PRINT((ndo, "\n\t  duration_sec %u", EXTRACT_32BITS(cp)));
1906		cp += 4;
1907		/* duration_nsec */
1908		ND_TCHECK2(*cp, 4);
1909		ND_PRINT((ndo, ", duration_nsec %u", EXTRACT_32BITS(cp)));
1910		cp += 4;
1911		/* priority */
1912		ND_TCHECK2(*cp, 2);
1913		ND_PRINT((ndo, ", priority %u", EXTRACT_16BITS(cp)));
1914		cp += 2;
1915		/* idle_timeout */
1916		ND_TCHECK2(*cp, 2);
1917		ND_PRINT((ndo, ", idle_timeout %u", EXTRACT_16BITS(cp)));
1918		cp += 2;
1919		/* hard_timeout */
1920		ND_TCHECK2(*cp, 2);
1921		ND_PRINT((ndo, ", hard_timeout %u", EXTRACT_16BITS(cp)));
1922		cp += 2;
1923		/* pad2 */
1924		ND_TCHECK2(*cp, 6);
1925		cp += 6;
1926		/* cookie */
1927		ND_TCHECK2(*cp, 8);
1928		ND_PRINT((ndo, ", cookie 0x%016" PRIx64, EXTRACT_64BITS(cp)));
1929		cp += 8;
1930		/* packet_count */
1931		ND_TCHECK2(*cp, 8);
1932		ND_PRINT((ndo, ", packet_count %" PRIu64, EXTRACT_64BITS(cp)));
1933		cp += 8;
1934		/* byte_count */
1935		ND_TCHECK2(*cp, 8);
1936		ND_PRINT((ndo, ", byte_count %" PRIu64, EXTRACT_64BITS(cp)));
1937		cp += 8;
1938		/* actions */
1939		if (ep == (cp = of10_actions_print(ndo, "\n\t  ", cp, ep, entry_len - OF_FLOW_STATS_LEN)))
1940			return ep; /* end of snapshot */
1941
1942		len -= entry_len;
1943	} /* while */
1944	return cp;
1945
1946invalid: /* skip the rest of flow statistics entries */
1947	ND_PRINT((ndo, "%s", istr));
1948	ND_TCHECK2(*cp0, len0);
1949	return cp0 + len0;
1950trunc:
1951	ND_PRINT((ndo, "%s", tstr));
1952	return ep;
1953}
1954
1955/* ibid */
1956static const u_char *
1957of10_aggregate_stats_reply_print(netdissect_options *ndo,
1958                                 const u_char *cp, const u_char *ep,
1959                                 const u_int len)
1960{
1961	if (len != OF_AGGREGATE_STATS_REPLY_LEN)
1962		goto invalid;
1963	/* packet_count */
1964	ND_TCHECK2(*cp, 8);
1965	ND_PRINT((ndo, "\n\t packet_count %" PRIu64, EXTRACT_64BITS(cp)));
1966	cp += 8;
1967	/* byte_count */
1968	ND_TCHECK2(*cp, 8);
1969	ND_PRINT((ndo, ", byte_count %" PRIu64, EXTRACT_64BITS(cp)));
1970	cp += 8;
1971	/* flow_count */
1972	ND_TCHECK2(*cp, 4);
1973	ND_PRINT((ndo, ", flow_count %u", EXTRACT_32BITS(cp)));
1974	cp += 4;
1975	/* pad */
1976	ND_TCHECK2(*cp, 4);
1977	return cp + 4;
1978
1979invalid: /* skip the message body */
1980	ND_PRINT((ndo, "%s", istr));
1981	ND_TCHECK2(*cp, len);
1982	return cp + len;
1983trunc:
1984	ND_PRINT((ndo, "%s", tstr));
1985	return ep;
1986}
1987
1988/* ibid */
1989static const u_char *
1990of10_table_stats_reply_print(netdissect_options *ndo,
1991                             const u_char *cp, const u_char *ep, u_int len)
1992{
1993	const u_char *cp0 = cp;
1994	const u_int len0 = len;
1995
1996	while (len) {
1997		if (len < OF_TABLE_STATS_LEN)
1998			goto invalid;
1999		/* table_id */
2000		ND_TCHECK2(*cp, 1);
2001		ND_PRINT((ndo, "\n\t table_id %s", tok2str(tableid_str, "%u", *cp)));
2002		cp += 1;
2003		/* pad */
2004		ND_TCHECK2(*cp, 3);
2005		cp += 3;
2006		/* name */
2007		ND_TCHECK2(*cp, OFP_MAX_TABLE_NAME_LEN);
2008		ND_PRINT((ndo, ", name '"));
2009		fn_print(ndo, cp, cp + OFP_MAX_TABLE_NAME_LEN);
2010		ND_PRINT((ndo, "'"));
2011		cp += OFP_MAX_TABLE_NAME_LEN;
2012		/* wildcards */
2013		ND_TCHECK2(*cp, 4);
2014		ND_PRINT((ndo, "\n\t  wildcards 0x%08x", EXTRACT_32BITS(cp)));
2015		of10_bitmap_print(ndo, ofpfw_bm, EXTRACT_32BITS(cp), OFPFW_U);
2016		cp += 4;
2017		/* max_entries */
2018		ND_TCHECK2(*cp, 4);
2019		ND_PRINT((ndo, "\n\t  max_entries %u", EXTRACT_32BITS(cp)));
2020		cp += 4;
2021		/* active_count */
2022		ND_TCHECK2(*cp, 4);
2023		ND_PRINT((ndo, ", active_count %u", EXTRACT_32BITS(cp)));
2024		cp += 4;
2025		/* lookup_count */
2026		ND_TCHECK2(*cp, 8);
2027		ND_PRINT((ndo, ", lookup_count %" PRIu64, EXTRACT_64BITS(cp)));
2028		cp += 8;
2029		/* matched_count */
2030		ND_TCHECK2(*cp, 8);
2031		ND_PRINT((ndo, ", matched_count %" PRIu64, EXTRACT_64BITS(cp)));
2032		cp += 8;
2033
2034		len -= OF_TABLE_STATS_LEN;
2035	} /* while */
2036	return cp;
2037
2038invalid: /* skip the undersized trailing data */
2039	ND_PRINT((ndo, "%s", istr));
2040	ND_TCHECK2(*cp0, len0);
2041	return cp0 + len0;
2042trunc:
2043	ND_PRINT((ndo, "%s", tstr));
2044	return ep;
2045}
2046
2047/* ibid */
2048static const u_char *
2049of10_port_stats_reply_print(netdissect_options *ndo,
2050                            const u_char *cp, const u_char *ep, u_int len)
2051{
2052	const u_char *cp0 = cp;
2053	const u_int len0 = len;
2054
2055	while (len) {
2056		if (len < OF_PORT_STATS_LEN)
2057			goto invalid;
2058		/* port_no */
2059		ND_TCHECK2(*cp, 2);
2060		ND_PRINT((ndo, "\n\t  port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
2061		cp += 2;
2062		if (ndo->ndo_vflag < 2) {
2063			ND_TCHECK2(*cp, OF_PORT_STATS_LEN - 2);
2064			cp += OF_PORT_STATS_LEN - 2;
2065			goto next_port;
2066		}
2067		/* pad */
2068		ND_TCHECK2(*cp, 6);
2069		cp += 6;
2070		/* rx_packets */
2071		ND_TCHECK2(*cp, 8);
2072		ND_PRINT((ndo, ", rx_packets %" PRIu64, EXTRACT_64BITS(cp)));
2073		cp += 8;
2074		/* tx_packets */
2075		ND_TCHECK2(*cp, 8);
2076		ND_PRINT((ndo, ", tx_packets %" PRIu64, EXTRACT_64BITS(cp)));
2077		cp += 8;
2078		/* rx_bytes */
2079		ND_TCHECK2(*cp, 8);
2080		ND_PRINT((ndo, ", rx_bytes %" PRIu64, EXTRACT_64BITS(cp)));
2081		cp += 8;
2082		/* tx_bytes */
2083		ND_TCHECK2(*cp, 8);
2084		ND_PRINT((ndo, ", tx_bytes %" PRIu64, EXTRACT_64BITS(cp)));
2085		cp += 8;
2086		/* rx_dropped */
2087		ND_TCHECK2(*cp, 8);
2088		ND_PRINT((ndo, ", rx_dropped %" PRIu64, EXTRACT_64BITS(cp)));
2089		cp += 8;
2090		/* tx_dropped */
2091		ND_TCHECK2(*cp, 8);
2092		ND_PRINT((ndo, ", tx_dropped %" PRIu64, EXTRACT_64BITS(cp)));
2093		cp += 8;
2094		/* rx_errors */
2095		ND_TCHECK2(*cp, 8);
2096		ND_PRINT((ndo, ", rx_errors %" PRIu64, EXTRACT_64BITS(cp)));
2097		cp += 8;
2098		/* tx_errors */
2099		ND_TCHECK2(*cp, 8);
2100		ND_PRINT((ndo, ", tx_errors %" PRIu64, EXTRACT_64BITS(cp)));
2101		cp += 8;
2102		/* rx_frame_err */
2103		ND_TCHECK2(*cp, 8);
2104		ND_PRINT((ndo, ", rx_frame_err %" PRIu64, EXTRACT_64BITS(cp)));
2105		cp += 8;
2106		/* rx_over_err */
2107		ND_TCHECK2(*cp, 8);
2108		ND_PRINT((ndo, ", rx_over_err %" PRIu64, EXTRACT_64BITS(cp)));
2109		cp += 8;
2110		/* rx_crc_err */
2111		ND_TCHECK2(*cp, 8);
2112		ND_PRINT((ndo, ", rx_crc_err %" PRIu64, EXTRACT_64BITS(cp)));
2113		cp += 8;
2114		/* collisions */
2115		ND_TCHECK2(*cp, 8);
2116		ND_PRINT((ndo, ", collisions %" PRIu64, EXTRACT_64BITS(cp)));
2117		cp += 8;
2118next_port:
2119		len -= OF_PORT_STATS_LEN;
2120	} /* while */
2121	return cp;
2122
2123invalid: /* skip the undersized trailing data */
2124	ND_PRINT((ndo, "%s", istr));
2125	ND_TCHECK2(*cp0, len0);
2126	return cp0 + len0;
2127trunc:
2128	ND_PRINT((ndo, "%s", tstr));
2129	return ep;
2130}
2131
2132/* ibid */
2133static const u_char *
2134of10_queue_stats_reply_print(netdissect_options *ndo,
2135                             const u_char *cp, const u_char *ep, u_int len)
2136{
2137	const u_char *cp0 = cp;
2138	const u_int len0 = len;
2139
2140	while (len) {
2141		if (len < OF_QUEUE_STATS_LEN)
2142			goto invalid;
2143		/* port_no */
2144		ND_TCHECK2(*cp, 2);
2145		ND_PRINT((ndo, "\n\t  port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
2146		cp += 2;
2147		/* pad */
2148		ND_TCHECK2(*cp, 2);
2149		cp += 2;
2150		/* queue_id */
2151		ND_TCHECK2(*cp, 4);
2152		ND_PRINT((ndo, ", queue_id %u", EXTRACT_32BITS(cp)));
2153		cp += 4;
2154		/* tx_bytes */
2155		ND_TCHECK2(*cp, 8);
2156		ND_PRINT((ndo, ", tx_bytes %" PRIu64, EXTRACT_64BITS(cp)));
2157		cp += 8;
2158		/* tx_packets */
2159		ND_TCHECK2(*cp, 8);
2160		ND_PRINT((ndo, ", tx_packets %" PRIu64, EXTRACT_64BITS(cp)));
2161		cp += 8;
2162		/* tx_errors */
2163		ND_TCHECK2(*cp, 8);
2164		ND_PRINT((ndo, ", tx_errors %" PRIu64, EXTRACT_64BITS(cp)));
2165		cp += 8;
2166
2167		len -= OF_QUEUE_STATS_LEN;
2168	} /* while */
2169	return cp;
2170
2171invalid: /* skip the undersized trailing data */
2172	ND_PRINT((ndo, "%s", istr));
2173	ND_TCHECK2(*cp0, len0);
2174	return cp0 + len0;
2175trunc:
2176	ND_PRINT((ndo, "%s", tstr));
2177	return ep;
2178}
2179
2180/* ibid */
2181static const u_char *
2182of10_stats_reply_print(netdissect_options *ndo,
2183                       const u_char *cp, const u_char *ep, const u_int len)
2184{
2185	const u_char *cp0 = cp;
2186	uint16_t type;
2187
2188	/* type */
2189	ND_TCHECK2(*cp, 2);
2190	type = EXTRACT_16BITS(cp);
2191	ND_PRINT((ndo, "\n\t type %s", tok2str(ofpst_str, "invalid (0x%04x)", type)));
2192	cp += 2;
2193	/* flags */
2194	ND_TCHECK2(*cp, 2);
2195	ND_PRINT((ndo, ", flags 0x%04x", EXTRACT_16BITS(cp)));
2196	of10_bitmap_print(ndo, ofpsf_reply_bm, EXTRACT_16BITS(cp), OFPSF_REPLY_U);
2197	cp += 2;
2198
2199	if (ndo->ndo_vflag > 0) {
2200		const u_char *(*decoder)(netdissect_options *, const u_char *, const u_char *, u_int) =
2201			type == OFPST_DESC      ? of10_desc_stats_reply_print      :
2202			type == OFPST_FLOW      ? of10_flow_stats_reply_print      :
2203			type == OFPST_AGGREGATE ? of10_aggregate_stats_reply_print :
2204			type == OFPST_TABLE     ? of10_table_stats_reply_print     :
2205			type == OFPST_PORT      ? of10_port_stats_reply_print      :
2206			type == OFPST_QUEUE     ? of10_queue_stats_reply_print     :
2207			type == OFPST_VENDOR    ? of10_vendor_data_print           :
2208			NULL;
2209		if (decoder != NULL)
2210			return decoder(ndo, cp, ep, len - OF_STATS_REPLY_LEN);
2211	}
2212	ND_TCHECK2(*cp0, len);
2213	return cp0 + len;
2214
2215trunc:
2216	ND_PRINT((ndo, "%s", tstr));
2217	return ep;
2218}
2219
2220/* [OF10] Section 5.3.6 */
2221static const u_char *
2222of10_packet_out_print(netdissect_options *ndo,
2223                      const u_char *cp, const u_char *ep, const u_int len)
2224{
2225	const u_char *cp0 = cp;
2226	const u_int len0 = len;
2227	uint16_t actions_len;
2228
2229	/* buffer_id */
2230	ND_TCHECK2(*cp, 4);
2231	ND_PRINT((ndo, "\n\t buffer_id 0x%08x", EXTRACT_32BITS(cp)));
2232	cp += 4;
2233	/* in_port */
2234	ND_TCHECK2(*cp, 2);
2235	ND_PRINT((ndo, ", in_port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
2236	cp += 2;
2237	/* actions_len */
2238	ND_TCHECK2(*cp, 2);
2239	actions_len = EXTRACT_16BITS(cp);
2240	cp += 2;
2241	if (actions_len > len - OF_PACKET_OUT_LEN)
2242		goto invalid;
2243	/* actions */
2244	if (ep == (cp = of10_actions_print(ndo, "\n\t ", cp, ep, actions_len)))
2245		return ep; /* end of snapshot */
2246	/* data */
2247	return of10_packet_data_print(ndo, cp, ep, len - OF_PACKET_OUT_LEN - actions_len);
2248
2249invalid: /* skip the rest of the message body */
2250	ND_PRINT((ndo, "%s", istr));
2251	ND_TCHECK2(*cp0, len0);
2252	return cp0 + len0;
2253trunc:
2254	ND_PRINT((ndo, "%s", tstr));
2255	return ep;
2256}
2257
2258/* [OF10] Section 5.4.1 */
2259static const u_char *
2260of10_packet_in_print(netdissect_options *ndo,
2261                     const u_char *cp, const u_char *ep, const u_int len)
2262{
2263	/* buffer_id */
2264	ND_TCHECK2(*cp, 4);
2265	ND_PRINT((ndo, "\n\t buffer_id %s", tok2str(bufferid_str, "0x%08x", EXTRACT_32BITS(cp))));
2266	cp += 4;
2267	/* total_len */
2268	ND_TCHECK2(*cp, 2);
2269	ND_PRINT((ndo, ", total_len %u", EXTRACT_16BITS(cp)));
2270	cp += 2;
2271	/* in_port */
2272	ND_TCHECK2(*cp, 2);
2273	ND_PRINT((ndo, ", in_port %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
2274	cp += 2;
2275	/* reason */
2276	ND_TCHECK2(*cp, 1);
2277	ND_PRINT((ndo, ", reason %s", tok2str(ofpr_str, "invalid (0x%02x)", *cp)));
2278	cp += 1;
2279	/* pad */
2280	ND_TCHECK2(*cp, 1);
2281	cp += 1;
2282	/* data */
2283	/* 2 mock octets count in OF_PACKET_IN_LEN but not in len */
2284	return of10_packet_data_print(ndo, cp, ep, len - (OF_PACKET_IN_LEN - 2));
2285
2286trunc:
2287	ND_PRINT((ndo, "%s", tstr));
2288	return ep;
2289}
2290
2291/* [OF10] Section 5.4.2 */
2292static const u_char *
2293of10_flow_removed_print(netdissect_options *ndo,
2294                        const u_char *cp, const u_char *ep)
2295{
2296	/* match */
2297	if (ep == (cp = of10_match_print(ndo, "\n\t ", cp, ep)))
2298		return ep; /* end of snapshot */
2299	/* cookie */
2300	ND_TCHECK2(*cp, 8);
2301	ND_PRINT((ndo, "\n\t cookie 0x%016" PRIx64, EXTRACT_64BITS(cp)));
2302	cp += 8;
2303	/* priority */
2304	ND_TCHECK2(*cp, 2);
2305	if (EXTRACT_16BITS(cp))
2306		ND_PRINT((ndo, ", priority %u", EXTRACT_16BITS(cp)));
2307	cp += 2;
2308	/* reason */
2309	ND_TCHECK2(*cp, 1);
2310	ND_PRINT((ndo, ", reason %s", tok2str(ofprr_str, "unknown (0x%02x)", *cp)));
2311	cp += 1;
2312	/* pad */
2313	ND_TCHECK2(*cp, 1);
2314	cp += 1;
2315	/* duration_sec */
2316	ND_TCHECK2(*cp, 4);
2317	ND_PRINT((ndo, ", duration_sec %u", EXTRACT_32BITS(cp)));
2318	cp += 4;
2319	/* duration_nsec */
2320	ND_TCHECK2(*cp, 4);
2321	ND_PRINT((ndo, ", duration_nsec %u", EXTRACT_32BITS(cp)));
2322	cp += 4;
2323	/* idle_timeout */
2324	ND_TCHECK2(*cp, 2);
2325	if (EXTRACT_16BITS(cp))
2326		ND_PRINT((ndo, ", idle_timeout %u", EXTRACT_16BITS(cp)));
2327	cp += 2;
2328	/* pad2 */
2329	ND_TCHECK2(*cp, 2);
2330	cp += 2;
2331	/* packet_count */
2332	ND_TCHECK2(*cp, 8);
2333	ND_PRINT((ndo, ", packet_count %" PRIu64, EXTRACT_64BITS(cp)));
2334	cp += 8;
2335	/* byte_count */
2336	ND_TCHECK2(*cp, 8);
2337	ND_PRINT((ndo, ", byte_count %" PRIu64, EXTRACT_64BITS(cp)));
2338	return cp + 8;
2339
2340trunc:
2341	ND_PRINT((ndo, "%s", tstr));
2342	return ep;
2343}
2344
2345/* [OF10] Section 5.4.4 */
2346static const u_char *
2347of10_error_print(netdissect_options *ndo,
2348                 const u_char *cp, const u_char *ep, const u_int len)
2349{
2350	uint16_t type;
2351	const struct tok *code_str;
2352
2353	/* type */
2354	ND_TCHECK2(*cp, 2);
2355	type = EXTRACT_16BITS(cp);
2356	cp += 2;
2357	ND_PRINT((ndo, "\n\t type %s", tok2str(ofpet_str, "invalid (0x%04x)", type)));
2358	/* code */
2359	ND_TCHECK2(*cp, 2);
2360	code_str =
2361		type == OFPET_HELLO_FAILED    ? ofphfc_str  :
2362		type == OFPET_BAD_REQUEST     ? ofpbrc_str  :
2363		type == OFPET_BAD_ACTION      ? ofpbac_str  :
2364		type == OFPET_FLOW_MOD_FAILED ? ofpfmfc_str :
2365		type == OFPET_PORT_MOD_FAILED ? ofppmfc_str :
2366		type == OFPET_QUEUE_OP_FAILED ? ofpqofc_str :
2367		empty_str;
2368	ND_PRINT((ndo, ", code %s", tok2str(code_str, "invalid (0x%04x)", EXTRACT_16BITS(cp))));
2369	cp += 2;
2370	/* data */
2371	return of10_data_print(ndo, cp, ep, len - OF_ERROR_MSG_LEN);
2372
2373trunc:
2374	ND_PRINT((ndo, "%s", tstr));
2375	return ep;
2376}
2377
2378const u_char *
2379of10_header_body_print(netdissect_options *ndo,
2380                       const u_char *cp, const u_char *ep, const uint8_t type,
2381                       const uint16_t len, const uint32_t xid)
2382{
2383	const u_char *cp0 = cp;
2384	const u_int len0 = len;
2385	/* Thus far message length is not less than the basic header size, but most
2386	 * message types have additional assorted constraints on the length. Wherever
2387	 * possible, check that message length meets the constraint, in remaining
2388	 * cases check that the length is OK to begin decoding and leave any final
2389	 * verification up to a lower-layer function. When the current message is
2390	 * invalid, proceed to the next message. */
2391
2392	/* [OF10] Section 5.1 */
2393	ND_PRINT((ndo, "\n\tversion 1.0, type %s, length %u, xid 0x%08x",
2394	       tok2str(ofpt_str, "invalid (0x%02x)", type), len, xid));
2395	switch (type) {
2396	/* OpenFlow header only. */
2397	case OFPT_FEATURES_REQUEST: /* [OF10] Section 5.3.1 */
2398	case OFPT_GET_CONFIG_REQUEST: /* [OF10] Section 5.3.2 */
2399	case OFPT_BARRIER_REQUEST: /* [OF10] Section 5.3.7 */
2400	case OFPT_BARRIER_REPLY: /* ibid */
2401		if (len != OF_HEADER_LEN)
2402			goto invalid;
2403		break;
2404
2405	/* OpenFlow header and fixed-size message body. */
2406	case OFPT_SET_CONFIG: /* [OF10] Section 5.3.2 */
2407	case OFPT_GET_CONFIG_REPLY: /* ibid */
2408		if (len != OF_SWITCH_CONFIG_LEN)
2409			goto invalid;
2410		if (ndo->ndo_vflag < 1)
2411			goto next_message;
2412		/* flags */
2413		ND_TCHECK2(*cp, 2);
2414		ND_PRINT((ndo, "\n\t flags %s", tok2str(ofp_config_str, "invalid (0x%04x)", EXTRACT_16BITS(cp))));
2415		cp += 2;
2416		/* miss_send_len */
2417		ND_TCHECK2(*cp, 2);
2418		ND_PRINT((ndo, ", miss_send_len %u", EXTRACT_16BITS(cp)));
2419		return cp + 2;
2420	case OFPT_PORT_MOD:
2421		if (len != OF_PORT_MOD_LEN)
2422			goto invalid;
2423		if (ndo->ndo_vflag < 1)
2424			goto next_message;
2425		return of10_port_mod_print(ndo, cp, ep);
2426	case OFPT_QUEUE_GET_CONFIG_REQUEST: /* [OF10] Section 5.3.4 */
2427		if (len != OF_QUEUE_GET_CONFIG_REQUEST_LEN)
2428			goto invalid;
2429		if (ndo->ndo_vflag < 1)
2430			goto next_message;
2431		/* port */
2432		ND_TCHECK2(*cp, 2);
2433		ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
2434		cp += 2;
2435		/* pad */
2436		ND_TCHECK2(*cp, 2);
2437		return cp + 2;
2438	case OFPT_FLOW_REMOVED:
2439		if (len != OF_FLOW_REMOVED_LEN)
2440			goto invalid;
2441		if (ndo->ndo_vflag < 1)
2442			goto next_message;
2443		return of10_flow_removed_print(ndo, cp, ep);
2444	case OFPT_PORT_STATUS: /* [OF10] Section 5.4.3 */
2445		if (len != OF_PORT_STATUS_LEN)
2446			goto invalid;
2447		if (ndo->ndo_vflag < 1)
2448			goto next_message;
2449		/* reason */
2450		ND_TCHECK2(*cp, 1);
2451		ND_PRINT((ndo, "\n\t reason %s", tok2str(ofppr_str, "invalid (0x%02x)", *cp)));
2452		cp += 1;
2453		/* pad */
2454		ND_TCHECK2(*cp, 7);
2455		cp += 7;
2456		/* desc */
2457		return of10_phy_ports_print(ndo, cp, ep, OF_PHY_PORT_LEN);
2458
2459	/* OpenFlow header, fixed-size message body and n * fixed-size data units. */
2460	case OFPT_FEATURES_REPLY:
2461		if (len < OF_SWITCH_FEATURES_LEN)
2462			goto invalid;
2463		if (ndo->ndo_vflag < 1)
2464			goto next_message;
2465		return of10_features_reply_print(ndo, cp, ep, len);
2466
2467	/* OpenFlow header and variable-size data. */
2468	case OFPT_HELLO: /* [OF10] Section 5.5.1 */
2469	case OFPT_ECHO_REQUEST: /* [OF10] Section 5.5.2 */
2470	case OFPT_ECHO_REPLY: /* [OF10] Section 5.5.3 */
2471		if (ndo->ndo_vflag < 1)
2472			goto next_message;
2473		return of10_data_print(ndo, cp, ep, len - OF_HEADER_LEN);
2474
2475	/* OpenFlow header, fixed-size message body and variable-size data. */
2476	case OFPT_ERROR:
2477		if (len < OF_ERROR_MSG_LEN)
2478			goto invalid;
2479		if (ndo->ndo_vflag < 1)
2480			goto next_message;
2481		return of10_error_print(ndo, cp, ep, len);
2482	case OFPT_VENDOR:
2483	  /* [OF10] Section 5.5.4 */
2484		if (len < OF_VENDOR_HEADER_LEN)
2485			goto invalid;
2486		if (ndo->ndo_vflag < 1)
2487			goto next_message;
2488		return of10_vendor_message_print(ndo, cp, ep, len - OF_HEADER_LEN);
2489	case OFPT_PACKET_IN:
2490		/* 2 mock octets count in OF_PACKET_IN_LEN but not in len */
2491		if (len < OF_PACKET_IN_LEN - 2)
2492			goto invalid;
2493		if (ndo->ndo_vflag < 1)
2494			goto next_message;
2495		return of10_packet_in_print(ndo, cp, ep, len);
2496
2497	/* a. OpenFlow header. */
2498	/* b. OpenFlow header and one of the fixed-size message bodies. */
2499	/* c. OpenFlow header, fixed-size message body and variable-size data. */
2500	case OFPT_STATS_REQUEST:
2501		if (len < OF_STATS_REQUEST_LEN)
2502			goto invalid;
2503		if (ndo->ndo_vflag < 1)
2504			goto next_message;
2505		return of10_stats_request_print(ndo, cp, ep, len);
2506
2507	/* a. OpenFlow header and fixed-size message body. */
2508	/* b. OpenFlow header and n * fixed-size data units. */
2509	/* c. OpenFlow header and n * variable-size data units. */
2510	/* d. OpenFlow header, fixed-size message body and variable-size data. */
2511	case OFPT_STATS_REPLY:
2512		if (len < OF_STATS_REPLY_LEN)
2513			goto invalid;
2514		if (ndo->ndo_vflag < 1)
2515			goto next_message;
2516		return of10_stats_reply_print(ndo, cp, ep, len);
2517
2518	/* OpenFlow header and n * variable-size data units and variable-size data. */
2519	case OFPT_PACKET_OUT:
2520		if (len < OF_PACKET_OUT_LEN)
2521			goto invalid;
2522		if (ndo->ndo_vflag < 1)
2523			goto next_message;
2524		return of10_packet_out_print(ndo, cp, ep, len);
2525
2526	/* OpenFlow header, fixed-size message body and n * variable-size data units. */
2527	case OFPT_FLOW_MOD:
2528		if (len < OF_FLOW_MOD_LEN)
2529			goto invalid;
2530		if (ndo->ndo_vflag < 1)
2531			goto next_message;
2532		return of10_flow_mod_print(ndo, cp, ep, len);
2533
2534	/* OpenFlow header, fixed-size message body and n * variable-size data units. */
2535	case OFPT_QUEUE_GET_CONFIG_REPLY: /* [OF10] Section 5.3.4 */
2536		if (len < OF_QUEUE_GET_CONFIG_REPLY_LEN)
2537			goto invalid;
2538		if (ndo->ndo_vflag < 1)
2539			goto next_message;
2540		/* port */
2541		ND_TCHECK2(*cp, 2);
2542		ND_PRINT((ndo, "\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_16BITS(cp))));
2543		cp += 2;
2544		/* pad */
2545		ND_TCHECK2(*cp, 6);
2546		cp += 6;
2547		/* queues */
2548		return of10_queues_print(ndo, cp, ep, len - OF_QUEUE_GET_CONFIG_REPLY_LEN);
2549	} /* switch (type) */
2550	goto next_message;
2551
2552invalid: /* skip the message body */
2553	ND_PRINT((ndo, "%s", istr));
2554next_message:
2555	ND_TCHECK2(*cp0, len0 - OF_HEADER_LEN);
2556	return cp0 + len0 - OF_HEADER_LEN;
2557trunc:
2558	ND_PRINT((ndo, "%s", tstr));
2559	return ep;
2560}
2561