nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 malformed 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 | #define NETDISSECT_REWORKED |
||
60 | #ifdef HAVE_CONFIG_H |
||
61 | #include "config.h" |
||
62 | #endif |
||
63 | |||
64 | #include <tcpdump-stdinc.h> |
||
65 | |||
66 | #include "interface.h" |
||
67 | #include "extract.h" |
||
68 | #include "addrtoname.h" |
||
69 | #include "ether.h" |
||
70 | #include "ethertype.h" |
||
71 | #include "ipproto.h" |
||
72 | #include "oui.h" |
||
73 | #include "openflow.h" |
||
74 | |||
75 | static const char tstr[] = " [|openflow]"; |
||
76 | static const char cstr[] = " (corrupt)"; |
||
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 |
||
100 | static 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) |
||
133 | static 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) |
||
153 | static 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 |
||
173 | static 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) |
||
198 | static 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 |
||
220 | static 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) |
||
243 | static 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 |
||
275 | static 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 */ |
||
293 | static 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) |
||
323 | static 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 |
||
342 | static 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 |
||
354 | static 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 | |||
363 | static 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) |
||
371 | static 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 |
||
386 | static 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 | |||
397 | static const struct tok tableid_str[] = { |
||
398 | { 0xfe, "EMERG" }, |
||
399 | { 0xff, "ALL" }, |
||
400 | { 0, NULL } |
||
401 | }; |
||
402 | |||
403 | #define OFPQ_ALL 0xffffffff |
||
404 | static const struct tok ofpq_str[] = { |
||
405 | { OFPQ_ALL, "ALL" }, |
||
406 | { 0, NULL } |
||
407 | }; |
||
408 | |||
409 | #define OFPSF_REPLY_MORE 0x0001 |
||
410 | static 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 |
||
418 | static 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 |
||
427 | static 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 |
||
437 | static 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 |
||
450 | static 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 |
||
462 | static 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 |
||
477 | static 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 |
||
499 | static 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 |
||
518 | static 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 |
||
530 | static 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 |
||
539 | static 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 | |||
546 | static 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 | |||
636 | static 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 | |||
679 | static 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 | |||
686 | static const struct tok bsn_mirror_copy_stage_str[] = { |
||
687 | { 0, "INGRESS" }, |
||
688 | { 1, "EGRESS" }, |
||
689 | { 0, NULL }, |
||
690 | }; |
||
691 | |||
692 | static const struct tok bsn_onoff_str[] = { |
||
693 | { 0, "OFF" }, |
||
694 | { 1, "ON" }, |
||
695 | { 0, NULL }, |
||
696 | }; |
||
697 | |||
698 | static const char * |
||
699 | vlan_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 | |||
711 | static const char * |
||
712 | pcp_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 | |||
719 | static void |
||
720 | of10_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 | |||
737 | static const u_char * |
||
738 | of10_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 | |||
750 | trunc: |
||
751 | ND_PRINT((ndo, "%s", tstr)); |
||
752 | return ep; |
||
753 | } |
||
754 | |||
755 | static const u_char * |
||
756 | of10_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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 | |||
951 | corrupt: /* skip the undersized data */ |
||
952 | ND_PRINT((ndo, "%s", cstr)); |
||
953 | ND_TCHECK2(*cp0, len); |
||
954 | return cp0 + len; |
||
955 | trunc: |
||
956 | ND_PRINT((ndo, "%s", tstr)); |
||
957 | return ep; |
||
958 | } |
||
959 | |||
960 | static const u_char * |
||
961 | of10_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 corrupt; |
||
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 corrupt; |
||
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 | |||
1025 | corrupt: |
||
1026 | ND_PRINT((ndo, "%s", cstr)); |
||
1027 | ND_TCHECK2(*cp0, len); |
||
1028 | return cp0 + len; |
||
1029 | trunc: |
||
1030 | ND_PRINT((ndo, "%s", tstr)); |
||
1031 | return ep; |
||
1032 | } |
||
1033 | |||
1034 | static const u_char * |
||
1035 | of10_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 corrupt; |
||
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 | |||
1054 | corrupt: /* skip the undersized data */ |
||
1055 | ND_PRINT((ndo, "%s", cstr)); |
||
1056 | ND_TCHECK2(*cp, len); |
||
1057 | return cp + len; |
||
1058 | trunc: |
||
1059 | ND_PRINT((ndo, "%s", tstr)); |
||
1060 | return ep; |
||
1061 | } |
||
1062 | |||
1063 | static const u_char * |
||
1064 | of10_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 corrupt; |
||
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 | |||
1083 | corrupt: /* skip the undersized data */ |
||
1084 | ND_PRINT((ndo, "%s", cstr)); |
||
1085 | ND_TCHECK2(*cp, len); |
||
1086 | return cp + len; |
||
1087 | trunc: |
||
1088 | ND_PRINT((ndo, "%s", tstr)); |
||
1089 | return ep; |
||
1090 | } |
||
1091 | |||
1092 | /* Vendor ID is mandatory, data is optional. */ |
||
1093 | static const u_char * |
||
1094 | of10_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 corrupt; |
||
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 | |||
1109 | corrupt: /* skip the undersized data */ |
||
1110 | ND_PRINT((ndo, "%s", cstr)); |
||
1111 | ND_TCHECK2(*cp, len); |
||
1112 | return cp + len; |
||
1113 | trunc: |
||
1114 | ND_PRINT((ndo, "%s", tstr)); |
||
1115 | return ep; |
||
1116 | } |
||
1117 | |||
1118 | static const u_char * |
||
1119 | of10_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 | |||
1135 | trunc: |
||
1136 | ND_PRINT((ndo, "%s", tstr)); |
||
1137 | return ep; |
||
1138 | } |
||
1139 | |||
1140 | /* [OF10] Section 5.2.1 */ |
||
1141 | static const u_char * |
||
1142 | of10_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 corrupt; |
||
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; |
||
1201 | next_port: |
||
1202 | len -= OF_PHY_PORT_LEN; |
||
1203 | } /* while */ |
||
1204 | return cp; |
||
1205 | |||
1206 | corrupt: /* skip the undersized trailing data */ |
||
1207 | ND_PRINT((ndo, "%s", cstr)); |
||
1208 | ND_TCHECK2(*cp0, len0); |
||
1209 | return cp0 + len0; |
||
1210 | trunc: |
||
1211 | ND_PRINT((ndo, "%s", tstr)); |
||
1212 | return ep; |
||
1213 | } |
||
1214 | |||
1215 | /* [OF10] Section 5.2.2 */ |
||
1216 | static const u_char * |
||
1217 | of10_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 corrupt; |
||
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 corrupt; |
||
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 | } |
||
1277 | next_property: |
||
1278 | len -= plen; |
||
1279 | } /* while */ |
||
1280 | return cp; |
||
1281 | |||
1282 | corrupt: /* skip the rest of queue properties */ |
||
1283 | ND_PRINT((ndo, "%s", cstr)); |
||
1284 | ND_TCHECK2(*cp0, len0); |
||
1285 | return cp0 + len0; |
||
1286 | trunc: |
||
1287 | ND_PRINT((ndo, "%s", tstr)); |
||
1288 | return ep; |
||
1289 | } |
||
1290 | |||
1291 | /* ibid */ |
||
1292 | static const u_char * |
||
1293 | of10_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 corrupt; |
||
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 corrupt; |
||
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 */ |
||
1325 | next_queue: |
||
1326 | len -= desclen; |
||
1327 | } /* while */ |
||
1328 | return cp; |
||
1329 | |||
1330 | corrupt: /* skip the rest of queues */ |
||
1331 | ND_PRINT((ndo, "%s", cstr)); |
||
1332 | ND_TCHECK2(*cp0, len0); |
||
1333 | return cp0 + len0; |
||
1334 | trunc: |
||
1335 | ND_PRINT((ndo, "%s", tstr)); |
||
1336 | return ep; |
||
1337 | } |
||
1338 | |||
1339 | /* [OF10] Section 5.2.3 */ |
||
1340 | static const u_char * |
||
1341 | of10_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 | |||
1438 | trunc: |
||
1439 | ND_PRINT((ndo, "%s", tstr)); |
||
1440 | return ep; |
||
1441 | } |
||
1442 | |||
1443 | /* [OF10] Section 5.2.4 */ |
||
1444 | static const u_char * |
||
1445 | of10_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 corrupt; |
||
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 corrupt; |
||
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 */ |
||
1596 | next_action: |
||
1597 | len -= alen; |
||
1598 | } /* while */ |
||
1599 | return cp; |
||
1600 | |||
1601 | corrupt: /* skip the rest of actions */ |
||
1602 | ND_PRINT((ndo, "%s", cstr)); |
||
1603 | ND_TCHECK2(*cp0, len0); |
||
1604 | return cp0 + len0; |
||
1605 | trunc: |
||
1606 | ND_PRINT((ndo, "%s", tstr)); |
||
1607 | return ep; |
||
1608 | } |
||
1609 | |||
1610 | /* [OF10] Section 5.3.1 */ |
||
1611 | static const u_char * |
||
1612 | of10_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 | |||
1643 | trunc: |
||
1644 | ND_PRINT((ndo, "%s", tstr)); |
||
1645 | return ep; |
||
1646 | } |
||
1647 | |||
1648 | /* [OF10] Section 5.3.3 */ |
||
1649 | static const u_char * |
||
1650 | of10_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 | |||
1701 | trunc: |
||
1702 | ND_PRINT((ndo, "%s", tstr)); |
||
1703 | return ep; |
||
1704 | } |
||
1705 | |||
1706 | /* ibid */ |
||
1707 | static const u_char * |
||
1708 | of10_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 | |||
1738 | trunc: |
||
1739 | ND_PRINT((ndo, "%s", tstr)); |
||
1740 | return ep; |
||
1741 | } |
||
1742 | |||
1743 | /* [OF10] Section 5.3.5 */ |
||
1744 | static const u_char * |
||
1745 | of10_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 corrupt; |
||
1770 | return cp; |
||
1771 | case OFPST_FLOW: |
||
1772 | case OFPST_AGGREGATE: |
||
1773 | if (len != OF_FLOW_STATS_REQUEST_LEN) |
||
1774 | goto corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 | |||
1818 | corrupt: /* skip the message body */ |
||
1819 | ND_PRINT((ndo, "%s", cstr)); |
||
1820 | ND_TCHECK2(*cp0, len0); |
||
1821 | return cp0 + len0; |
||
1822 | trunc: |
||
1823 | ND_PRINT((ndo, "%s", tstr)); |
||
1824 | return ep; |
||
1825 | } |
||
1826 | |||
1827 | /* ibid */ |
||
1828 | static const u_char * |
||
1829 | of10_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 corrupt; |
||
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 | |||
1865 | corrupt: /* skip the message body */ |
||
1866 | ND_PRINT((ndo, "%s", cstr)); |
||
1867 | ND_TCHECK2(*cp, len); |
||
1868 | return cp + len; |
||
1869 | trunc: |
||
1870 | ND_PRINT((ndo, "%s", tstr)); |
||
1871 | return ep; |
||
1872 | } |
||
1873 | |||
1874 | /* ibid */ |
||
1875 | static const u_char * |
||
1876 | of10_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 corrupt; |
||
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 corrupt; |
||
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 | |||
1946 | corrupt: /* skip the rest of flow statistics entries */ |
||
1947 | ND_PRINT((ndo, "%s", cstr)); |
||
1948 | ND_TCHECK2(*cp0, len0); |
||
1949 | return cp0 + len0; |
||
1950 | trunc: |
||
1951 | ND_PRINT((ndo, "%s", tstr)); |
||
1952 | return ep; |
||
1953 | } |
||
1954 | |||
1955 | /* ibid */ |
||
1956 | static const u_char * |
||
1957 | of10_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 corrupt; |
||
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 | |||
1979 | corrupt: /* skip the message body */ |
||
1980 | ND_PRINT((ndo, "%s", cstr)); |
||
1981 | ND_TCHECK2(*cp, len); |
||
1982 | return cp + len; |
||
1983 | trunc: |
||
1984 | ND_PRINT((ndo, "%s", tstr)); |
||
1985 | return ep; |
||
1986 | } |
||
1987 | |||
1988 | /* ibid */ |
||
1989 | static const u_char * |
||
1990 | of10_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 corrupt; |
||
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 | |||
2038 | corrupt: /* skip the undersized trailing data */ |
||
2039 | ND_PRINT((ndo, "%s", cstr)); |
||
2040 | ND_TCHECK2(*cp0, len0); |
||
2041 | return cp0 + len0; |
||
2042 | trunc: |
||
2043 | ND_PRINT((ndo, "%s", tstr)); |
||
2044 | return ep; |
||
2045 | } |
||
2046 | |||
2047 | /* ibid */ |
||
2048 | static const u_char * |
||
2049 | of10_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 corrupt; |
||
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; |
||
2118 | next_port: |
||
2119 | len -= OF_PORT_STATS_LEN; |
||
2120 | } /* while */ |
||
2121 | return cp; |
||
2122 | |||
2123 | corrupt: /* skip the undersized trailing data */ |
||
2124 | ND_PRINT((ndo, "%s", cstr)); |
||
2125 | ND_TCHECK2(*cp0, len0); |
||
2126 | return cp0 + len0; |
||
2127 | trunc: |
||
2128 | ND_PRINT((ndo, "%s", tstr)); |
||
2129 | return ep; |
||
2130 | } |
||
2131 | |||
2132 | /* ibid */ |
||
2133 | static const u_char * |
||
2134 | of10_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 corrupt; |
||
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 | |||
2171 | corrupt: /* skip the undersized trailing data */ |
||
2172 | ND_PRINT((ndo, "%s", cstr)); |
||
2173 | ND_TCHECK2(*cp0, len0); |
||
2174 | return cp0 + len0; |
||
2175 | trunc: |
||
2176 | ND_PRINT((ndo, "%s", tstr)); |
||
2177 | return ep; |
||
2178 | } |
||
2179 | |||
2180 | /* ibid */ |
||
2181 | static const u_char * |
||
2182 | of10_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 | |||
2215 | trunc: |
||
2216 | ND_PRINT((ndo, "%s", tstr)); |
||
2217 | return ep; |
||
2218 | } |
||
2219 | |||
2220 | /* [OF10] Section 5.3.6 */ |
||
2221 | static const u_char * |
||
2222 | of10_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 corrupt; |
||
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 | |||
2249 | corrupt: /* skip the rest of the message body */ |
||
2250 | ND_PRINT((ndo, "%s", cstr)); |
||
2251 | ND_TCHECK2(*cp0, len0); |
||
2252 | return cp0 + len0; |
||
2253 | trunc: |
||
2254 | ND_PRINT((ndo, "%s", tstr)); |
||
2255 | return ep; |
||
2256 | } |
||
2257 | |||
2258 | /* [OF10] Section 5.4.1 */ |
||
2259 | static const u_char * |
||
2260 | of10_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 | |||
2286 | trunc: |
||
2287 | ND_PRINT((ndo, "%s", tstr)); |
||
2288 | return ep; |
||
2289 | } |
||
2290 | |||
2291 | /* [OF10] Section 5.4.2 */ |
||
2292 | static const u_char * |
||
2293 | of10_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 | |||
2340 | trunc: |
||
2341 | ND_PRINT((ndo, "%s", tstr)); |
||
2342 | return ep; |
||
2343 | } |
||
2344 | |||
2345 | /* [OF10] Section 5.4.4 */ |
||
2346 | static const u_char * |
||
2347 | of10_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 | |||
2373 | trunc: |
||
2374 | ND_PRINT((ndo, "%s", tstr)); |
||
2375 | return ep; |
||
2376 | } |
||
2377 | |||
2378 | const u_char * |
||
2379 | of10_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 | * corrupt, 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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 corrupt; |
||
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 | |||
2552 | corrupt: /* skip the message body */ |
||
2553 | ND_PRINT((ndo, "%s", cstr)); |
||
2554 | next_message: |
||
2555 | ND_TCHECK2(*cp0, len0 - OF_HEADER_LEN); |
||
2556 | return cp0 + len0 - OF_HEADER_LEN; |
||
2557 | trunc: |
||
2558 | ND_PRINT((ndo, "%s", tstr)); |
||
2559 | return ep; |
||
2560 | } |