1*b636d99dSDavid van Moolenbroek /*
2*b636d99dSDavid van Moolenbroek * This module implements printing of the very basic (version-independent)
3*b636d99dSDavid van Moolenbroek * OpenFlow header and iteration over OpenFlow messages. It is intended for
4*b636d99dSDavid van Moolenbroek * dispatching of version-specific OpenFlow message decoding.
5*b636d99dSDavid van Moolenbroek *
6*b636d99dSDavid van Moolenbroek *
7*b636d99dSDavid van Moolenbroek * Copyright (c) 2013 The TCPDUMP project
8*b636d99dSDavid van Moolenbroek * All rights reserved.
9*b636d99dSDavid van Moolenbroek *
10*b636d99dSDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
11*b636d99dSDavid van Moolenbroek * modification, are permitted provided that the following conditions
12*b636d99dSDavid van Moolenbroek * are met:
13*b636d99dSDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
14*b636d99dSDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
15*b636d99dSDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright
16*b636d99dSDavid van Moolenbroek * notice, this list of conditions and the following disclaimer in the
17*b636d99dSDavid van Moolenbroek * documentation and/or other materials provided with the distribution.
18*b636d99dSDavid van Moolenbroek *
19*b636d99dSDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*b636d99dSDavid van Moolenbroek * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*b636d99dSDavid van Moolenbroek * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22*b636d99dSDavid van Moolenbroek * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23*b636d99dSDavid van Moolenbroek * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24*b636d99dSDavid van Moolenbroek * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25*b636d99dSDavid van Moolenbroek * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26*b636d99dSDavid van Moolenbroek * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27*b636d99dSDavid van Moolenbroek * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28*b636d99dSDavid van Moolenbroek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29*b636d99dSDavid van Moolenbroek * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30*b636d99dSDavid van Moolenbroek * POSSIBILITY OF SUCH DAMAGE.
31*b636d99dSDavid van Moolenbroek */
32*b636d99dSDavid van Moolenbroek
33*b636d99dSDavid van Moolenbroek #define NETDISSECT_REWORKED
34*b636d99dSDavid van Moolenbroek #ifdef HAVE_CONFIG_H
35*b636d99dSDavid van Moolenbroek #include "config.h"
36*b636d99dSDavid van Moolenbroek #endif
37*b636d99dSDavid van Moolenbroek
38*b636d99dSDavid van Moolenbroek #include <tcpdump-stdinc.h>
39*b636d99dSDavid van Moolenbroek
40*b636d99dSDavid van Moolenbroek #include "interface.h"
41*b636d99dSDavid van Moolenbroek #include "extract.h"
42*b636d99dSDavid van Moolenbroek #include "openflow.h"
43*b636d99dSDavid van Moolenbroek #include "oui.h"
44*b636d99dSDavid van Moolenbroek
45*b636d99dSDavid van Moolenbroek static const char tstr[] = " [|openflow]";
46*b636d99dSDavid van Moolenbroek static const char cstr[] = " (corrupt)";
47*b636d99dSDavid van Moolenbroek
48*b636d99dSDavid van Moolenbroek #define OF_VER_1_0 0x01
49*b636d99dSDavid van Moolenbroek
50*b636d99dSDavid van Moolenbroek const struct tok onf_exp_str[] = {
51*b636d99dSDavid van Moolenbroek { ONF_EXP_ONF, "ONF Extensions" },
52*b636d99dSDavid van Moolenbroek { ONF_EXP_BUTE, "Budapest University of Technology and Economics" },
53*b636d99dSDavid van Moolenbroek { ONF_EXP_NOVIFLOW, "NoviFlow" },
54*b636d99dSDavid van Moolenbroek { ONF_EXP_L3, "L3+ Extensions, Vendor Neutral" },
55*b636d99dSDavid van Moolenbroek { ONF_EXP_L4L7, "L4-L7 Extensions" },
56*b636d99dSDavid van Moolenbroek { ONF_EXP_WMOB, "Wireless and Mobility Extensions" },
57*b636d99dSDavid van Moolenbroek { ONF_EXP_FABS, "Forwarding Abstractions Extensions" },
58*b636d99dSDavid van Moolenbroek { ONF_EXP_OTRANS, "Optical Transport Extensions" },
59*b636d99dSDavid van Moolenbroek { 0, NULL }
60*b636d99dSDavid van Moolenbroek };
61*b636d99dSDavid van Moolenbroek
62*b636d99dSDavid van Moolenbroek const char *
of_vendor_name(const uint32_t vendor)63*b636d99dSDavid van Moolenbroek of_vendor_name(const uint32_t vendor)
64*b636d99dSDavid van Moolenbroek {
65*b636d99dSDavid van Moolenbroek const struct tok *table = (vendor & 0xff000000) == 0 ? oui_values : onf_exp_str;
66*b636d99dSDavid van Moolenbroek return tok2str(table, "unknown", vendor);
67*b636d99dSDavid van Moolenbroek }
68*b636d99dSDavid van Moolenbroek
69*b636d99dSDavid van Moolenbroek static void
of_header_print(netdissect_options * ndo,const uint8_t version,const uint8_t type,const uint16_t length,const uint32_t xid)70*b636d99dSDavid van Moolenbroek of_header_print(netdissect_options *ndo, const uint8_t version, const uint8_t type,
71*b636d99dSDavid van Moolenbroek const uint16_t length, const uint32_t xid)
72*b636d99dSDavid van Moolenbroek {
73*b636d99dSDavid van Moolenbroek ND_PRINT((ndo, "\n\tversion unknown (0x%02x), type 0x%02x, length %u, xid 0x%08x",
74*b636d99dSDavid van Moolenbroek version, type, length, xid));
75*b636d99dSDavid van Moolenbroek }
76*b636d99dSDavid van Moolenbroek
77*b636d99dSDavid van Moolenbroek /* Print a single OpenFlow message. */
78*b636d99dSDavid van Moolenbroek static const u_char *
of_header_body_print(netdissect_options * ndo,const u_char * cp,const u_char * ep)79*b636d99dSDavid van Moolenbroek of_header_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
80*b636d99dSDavid van Moolenbroek {
81*b636d99dSDavid van Moolenbroek uint8_t version, type;
82*b636d99dSDavid van Moolenbroek uint16_t length;
83*b636d99dSDavid van Moolenbroek uint32_t xid;
84*b636d99dSDavid van Moolenbroek
85*b636d99dSDavid van Moolenbroek if (ep < cp + OF_HEADER_LEN)
86*b636d99dSDavid van Moolenbroek goto corrupt;
87*b636d99dSDavid van Moolenbroek /* version */
88*b636d99dSDavid van Moolenbroek ND_TCHECK2(*cp, 1);
89*b636d99dSDavid van Moolenbroek version = *cp;
90*b636d99dSDavid van Moolenbroek cp += 1;
91*b636d99dSDavid van Moolenbroek /* type */
92*b636d99dSDavid van Moolenbroek ND_TCHECK2(*cp, 1);
93*b636d99dSDavid van Moolenbroek type = *cp;
94*b636d99dSDavid van Moolenbroek cp += 1;
95*b636d99dSDavid van Moolenbroek /* length */
96*b636d99dSDavid van Moolenbroek ND_TCHECK2(*cp, 2);
97*b636d99dSDavid van Moolenbroek length = EXTRACT_16BITS(cp);
98*b636d99dSDavid van Moolenbroek cp += 2;
99*b636d99dSDavid van Moolenbroek /* xid */
100*b636d99dSDavid van Moolenbroek ND_TCHECK2(*cp, 4);
101*b636d99dSDavid van Moolenbroek xid = EXTRACT_32BITS(cp);
102*b636d99dSDavid van Moolenbroek cp += 4;
103*b636d99dSDavid van Moolenbroek /* Message length includes the header length and a message always includes
104*b636d99dSDavid van Moolenbroek * the basic header. A message length underrun fails decoding of the rest of
105*b636d99dSDavid van Moolenbroek * the current packet. At the same time, try decoding as much of the current
106*b636d99dSDavid van Moolenbroek * message as possible even when it does not end within the current TCP
107*b636d99dSDavid van Moolenbroek * segment. */
108*b636d99dSDavid van Moolenbroek if (length < OF_HEADER_LEN) {
109*b636d99dSDavid van Moolenbroek of_header_print(ndo, version, type, length, xid);
110*b636d99dSDavid van Moolenbroek goto corrupt;
111*b636d99dSDavid van Moolenbroek }
112*b636d99dSDavid van Moolenbroek /* Decode known protocol versions further without printing the header (the
113*b636d99dSDavid van Moolenbroek * type decoding is version-specific. */
114*b636d99dSDavid van Moolenbroek switch (version) {
115*b636d99dSDavid van Moolenbroek case OF_VER_1_0:
116*b636d99dSDavid van Moolenbroek return of10_header_body_print(ndo, cp, ep, type, length, xid);
117*b636d99dSDavid van Moolenbroek default:
118*b636d99dSDavid van Moolenbroek of_header_print(ndo, version, type, length, xid);
119*b636d99dSDavid van Moolenbroek ND_TCHECK2(*cp, length - OF_HEADER_LEN);
120*b636d99dSDavid van Moolenbroek return cp + length - OF_HEADER_LEN; /* done with current message */
121*b636d99dSDavid van Moolenbroek }
122*b636d99dSDavid van Moolenbroek
123*b636d99dSDavid van Moolenbroek corrupt: /* fail current packet */
124*b636d99dSDavid van Moolenbroek ND_PRINT((ndo, "%s", cstr));
125*b636d99dSDavid van Moolenbroek ND_TCHECK2(*cp, ep - cp);
126*b636d99dSDavid van Moolenbroek return ep;
127*b636d99dSDavid van Moolenbroek trunc:
128*b636d99dSDavid van Moolenbroek ND_PRINT((ndo, "%s", tstr));
129*b636d99dSDavid van Moolenbroek return ep;
130*b636d99dSDavid van Moolenbroek }
131*b636d99dSDavid van Moolenbroek
132*b636d99dSDavid van Moolenbroek /* Print a TCP segment worth of OpenFlow messages presuming the segment begins
133*b636d99dSDavid van Moolenbroek * on a message boundary. */
134*b636d99dSDavid van Moolenbroek void
openflow_print(netdissect_options * ndo,const u_char * cp,const u_int len)135*b636d99dSDavid van Moolenbroek openflow_print(netdissect_options *ndo, const u_char *cp, const u_int len)
136*b636d99dSDavid van Moolenbroek {
137*b636d99dSDavid van Moolenbroek const u_char *ep = cp + len;
138*b636d99dSDavid van Moolenbroek
139*b636d99dSDavid van Moolenbroek ND_PRINT((ndo, ": OpenFlow"));
140*b636d99dSDavid van Moolenbroek while (cp < ep)
141*b636d99dSDavid van Moolenbroek cp = of_header_body_print(ndo, cp, ep);
142*b636d99dSDavid van Moolenbroek }
143