xref: /netbsd-src/external/bsd/tcpdump/dist/print-openflow.c (revision c47fd3787da4fb1e7c8847e4e4885998d8a9eb06)
1026d7285Schristos /*
2026d7285Schristos  * This module implements printing of the very basic (version-independent)
3026d7285Schristos  * OpenFlow header and iteration over OpenFlow messages. It is intended for
4026d7285Schristos  * dispatching of version-specific OpenFlow message decoding.
5026d7285Schristos  *
6026d7285Schristos  *
7026d7285Schristos  * Copyright (c) 2013 The TCPDUMP project
8026d7285Schristos  * All rights reserved.
9026d7285Schristos  *
10026d7285Schristos  * Redistribution and use in source and binary forms, with or without
11026d7285Schristos  * modification, are permitted provided that the following conditions
12026d7285Schristos  * are met:
13026d7285Schristos  * 1. Redistributions of source code must retain the above copyright
14026d7285Schristos  *    notice, this list of conditions and the following disclaimer.
15026d7285Schristos  * 2. Redistributions in binary form must reproduce the above copyright
16026d7285Schristos  *    notice, this list of conditions and the following disclaimer in the
17026d7285Schristos  *    documentation and/or other materials provided with the distribution.
18026d7285Schristos  *
19026d7285Schristos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20026d7285Schristos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21026d7285Schristos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22026d7285Schristos  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23026d7285Schristos  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24026d7285Schristos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25026d7285Schristos  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26026d7285Schristos  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27026d7285Schristos  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28026d7285Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29026d7285Schristos  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30026d7285Schristos  * POSSIBILITY OF SUCH DAMAGE.
31026d7285Schristos  */
32026d7285Schristos 
33*c47fd378Schristos #define NETDISSECT_REWORKED
34026d7285Schristos #ifdef HAVE_CONFIG_H
35026d7285Schristos #include "config.h"
36026d7285Schristos #endif
37026d7285Schristos 
38026d7285Schristos #include <tcpdump-stdinc.h>
39026d7285Schristos 
40026d7285Schristos #include "interface.h"
41026d7285Schristos #include "extract.h"
42026d7285Schristos #include "openflow.h"
43026d7285Schristos 
44*c47fd378Schristos static const char tstr[] = " [|openflow]";
45*c47fd378Schristos static const char cstr[] = " (corrupt)";
46*c47fd378Schristos 
47026d7285Schristos #define OF_VER_1_0    0x01
48026d7285Schristos 
49026d7285Schristos static void
50*c47fd378Schristos of_header_print(netdissect_options *ndo, const uint8_t version, const uint8_t type,
51026d7285Schristos                       const uint16_t length, const uint32_t xid) {
52*c47fd378Schristos 	ND_PRINT((ndo, "\n\tversion unknown (0x%02x), type 0x%02x, length %u, xid 0x%08x",
53*c47fd378Schristos 	       version, type, length, xid));
54026d7285Schristos }
55026d7285Schristos 
56026d7285Schristos /* Print a single OpenFlow message. */
57026d7285Schristos static const u_char *
58*c47fd378Schristos of_header_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) {
59026d7285Schristos 	uint8_t version, type;
60026d7285Schristos 	uint16_t length;
61026d7285Schristos 	uint32_t xid;
62026d7285Schristos 
63026d7285Schristos 	if (ep < cp + OF_HEADER_LEN)
64026d7285Schristos 		goto corrupt;
65026d7285Schristos 	/* version */
66*c47fd378Schristos 	ND_TCHECK2(*cp, 1);
67026d7285Schristos 	version = *cp;
68026d7285Schristos 	cp += 1;
69026d7285Schristos 	/* type */
70*c47fd378Schristos 	ND_TCHECK2(*cp, 1);
71026d7285Schristos 	type = *cp;
72026d7285Schristos 	cp += 1;
73026d7285Schristos 	/* length */
74*c47fd378Schristos 	ND_TCHECK2(*cp, 2);
75026d7285Schristos 	length = EXTRACT_16BITS(cp);
76026d7285Schristos 	cp += 2;
77026d7285Schristos 	/* xid */
78*c47fd378Schristos 	ND_TCHECK2(*cp, 4);
79026d7285Schristos 	xid = EXTRACT_32BITS(cp);
80026d7285Schristos 	cp += 4;
81026d7285Schristos 	/* Message length includes the header length and a message always includes
82026d7285Schristos 	 * the basic header. A message length underrun fails decoding of the rest of
83026d7285Schristos 	 * the current packet. At the same time, try decoding as much of the current
84026d7285Schristos 	 * message as possible even when it does not end within the current TCP
85026d7285Schristos 	 * segment. */
86026d7285Schristos 	if (length < OF_HEADER_LEN) {
87*c47fd378Schristos 		of_header_print(ndo, version, type, length, xid);
88026d7285Schristos 		goto corrupt;
89026d7285Schristos 	}
90026d7285Schristos 	/* Decode known protocol versions further without printing the header (the
91026d7285Schristos 	 * type decoding is version-specific. */
92026d7285Schristos 	switch (version) {
93026d7285Schristos 	case OF_VER_1_0:
94*c47fd378Schristos 		return of10_header_body_print(ndo, cp, ep, type, length, xid);
95026d7285Schristos 	default:
96*c47fd378Schristos 		of_header_print(ndo, version, type, length, xid);
97*c47fd378Schristos 		ND_TCHECK2(*cp, length - OF_HEADER_LEN);
98026d7285Schristos 		return cp + length - OF_HEADER_LEN; /* done with current message */
99026d7285Schristos 	}
100026d7285Schristos 
101026d7285Schristos corrupt: /* fail current packet */
102*c47fd378Schristos 	ND_PRINT((ndo, "%s", cstr));
103*c47fd378Schristos 	ND_TCHECK2(*cp, ep - cp);
104026d7285Schristos 	return ep;
105026d7285Schristos trunc:
106*c47fd378Schristos 	ND_PRINT((ndo, "%s", tstr));
107026d7285Schristos 	return ep;
108026d7285Schristos }
109026d7285Schristos 
110026d7285Schristos /* Print a TCP segment worth of OpenFlow messages presuming the segment begins
111026d7285Schristos  * on a message boundary. */
112026d7285Schristos void
113*c47fd378Schristos openflow_print(netdissect_options *ndo, const u_char *cp, const u_int len) {
114026d7285Schristos 	const u_char *ep = cp + len;
115026d7285Schristos 
116*c47fd378Schristos 	ND_PRINT((ndo, ": OpenFlow"));
117026d7285Schristos 	while (cp < ep)
118*c47fd378Schristos 		cp = of_header_body_print(ndo, cp, ep);
119026d7285Schristos }
120