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 33c47fd378Schristos #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" 43*3d25ea14Schristos #include "oui.h" 44026d7285Schristos 45c47fd378Schristos static const char tstr[] = " [|openflow]"; 46c47fd378Schristos static const char cstr[] = " (corrupt)"; 47c47fd378Schristos 48026d7285Schristos #define OF_VER_1_0 0x01 49026d7285Schristos 50*3d25ea14Schristos const struct tok onf_exp_str[] = { 51*3d25ea14Schristos { ONF_EXP_ONF, "ONF Extensions" }, 52*3d25ea14Schristos { ONF_EXP_BUTE, "Budapest University of Technology and Economics" }, 53*3d25ea14Schristos { ONF_EXP_NOVIFLOW, "NoviFlow" }, 54*3d25ea14Schristos { ONF_EXP_L3, "L3+ Extensions, Vendor Neutral" }, 55*3d25ea14Schristos { ONF_EXP_L4L7, "L4-L7 Extensions" }, 56*3d25ea14Schristos { ONF_EXP_WMOB, "Wireless and Mobility Extensions" }, 57*3d25ea14Schristos { ONF_EXP_FABS, "Forwarding Abstractions Extensions" }, 58*3d25ea14Schristos { ONF_EXP_OTRANS, "Optical Transport Extensions" }, 59*3d25ea14Schristos { 0, NULL } 60*3d25ea14Schristos }; 61*3d25ea14Schristos 62*3d25ea14Schristos const char * 63*3d25ea14Schristos of_vendor_name(const uint32_t vendor) 64*3d25ea14Schristos { 65*3d25ea14Schristos const struct tok *table = (vendor & 0xff000000) == 0 ? oui_values : onf_exp_str; 66*3d25ea14Schristos return tok2str(table, "unknown", vendor); 67*3d25ea14Schristos } 68*3d25ea14Schristos 69026d7285Schristos static void 70c47fd378Schristos of_header_print(netdissect_options *ndo, const uint8_t version, const uint8_t type, 71*3d25ea14Schristos const uint16_t length, const uint32_t xid) 72*3d25ea14Schristos { 73c47fd378Schristos ND_PRINT((ndo, "\n\tversion unknown (0x%02x), type 0x%02x, length %u, xid 0x%08x", 74c47fd378Schristos version, type, length, xid)); 75026d7285Schristos } 76026d7285Schristos 77026d7285Schristos /* Print a single OpenFlow message. */ 78026d7285Schristos static const u_char * 79*3d25ea14Schristos of_header_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) 80*3d25ea14Schristos { 81026d7285Schristos uint8_t version, type; 82026d7285Schristos uint16_t length; 83026d7285Schristos uint32_t xid; 84026d7285Schristos 85026d7285Schristos if (ep < cp + OF_HEADER_LEN) 86026d7285Schristos goto corrupt; 87026d7285Schristos /* version */ 88c47fd378Schristos ND_TCHECK2(*cp, 1); 89026d7285Schristos version = *cp; 90026d7285Schristos cp += 1; 91026d7285Schristos /* type */ 92c47fd378Schristos ND_TCHECK2(*cp, 1); 93026d7285Schristos type = *cp; 94026d7285Schristos cp += 1; 95026d7285Schristos /* length */ 96c47fd378Schristos ND_TCHECK2(*cp, 2); 97026d7285Schristos length = EXTRACT_16BITS(cp); 98026d7285Schristos cp += 2; 99026d7285Schristos /* xid */ 100c47fd378Schristos ND_TCHECK2(*cp, 4); 101026d7285Schristos xid = EXTRACT_32BITS(cp); 102026d7285Schristos cp += 4; 103026d7285Schristos /* Message length includes the header length and a message always includes 104026d7285Schristos * the basic header. A message length underrun fails decoding of the rest of 105026d7285Schristos * the current packet. At the same time, try decoding as much of the current 106026d7285Schristos * message as possible even when it does not end within the current TCP 107026d7285Schristos * segment. */ 108026d7285Schristos if (length < OF_HEADER_LEN) { 109c47fd378Schristos of_header_print(ndo, version, type, length, xid); 110026d7285Schristos goto corrupt; 111026d7285Schristos } 112026d7285Schristos /* Decode known protocol versions further without printing the header (the 113026d7285Schristos * type decoding is version-specific. */ 114026d7285Schristos switch (version) { 115026d7285Schristos case OF_VER_1_0: 116c47fd378Schristos return of10_header_body_print(ndo, cp, ep, type, length, xid); 117026d7285Schristos default: 118c47fd378Schristos of_header_print(ndo, version, type, length, xid); 119c47fd378Schristos ND_TCHECK2(*cp, length - OF_HEADER_LEN); 120026d7285Schristos return cp + length - OF_HEADER_LEN; /* done with current message */ 121026d7285Schristos } 122026d7285Schristos 123026d7285Schristos corrupt: /* fail current packet */ 124c47fd378Schristos ND_PRINT((ndo, "%s", cstr)); 125c47fd378Schristos ND_TCHECK2(*cp, ep - cp); 126026d7285Schristos return ep; 127026d7285Schristos trunc: 128c47fd378Schristos ND_PRINT((ndo, "%s", tstr)); 129026d7285Schristos return ep; 130026d7285Schristos } 131026d7285Schristos 132026d7285Schristos /* Print a TCP segment worth of OpenFlow messages presuming the segment begins 133026d7285Schristos * on a message boundary. */ 134026d7285Schristos void 135*3d25ea14Schristos openflow_print(netdissect_options *ndo, const u_char *cp, const u_int len) 136*3d25ea14Schristos { 137026d7285Schristos const u_char *ep = cp + len; 138026d7285Schristos 139c47fd378Schristos ND_PRINT((ndo, ": OpenFlow")); 140026d7285Schristos while (cp < ep) 141c47fd378Schristos cp = of_header_body_print(ndo, cp, ep); 142026d7285Schristos } 143