X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/3a7639e545c0543bcec19c4321dd3ba397fbe6fa..2e63bc0ec11f2b041ee53e2ed986c9d50f135700:/print-openflow.c diff --git a/print-openflow.c b/print-openflow.c index 687b16d6..3b85dd7a 100644 --- a/print-openflow.c +++ b/print-openflow.c @@ -33,17 +33,16 @@ /* \summary: version-independent OpenFlow printer */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif -#include +#include "netdissect-stdinc.h" #include "netdissect.h" #include "extract.h" #include "openflow.h" #include "oui.h" -static const char tstr[] = " [|openflow]"; #define OF_VER_1_0 0x01 @@ -70,73 +69,90 @@ static void of_header_print(netdissect_options *ndo, const uint8_t version, const uint8_t type, const uint16_t length, const uint32_t xid) { - ND_PRINT((ndo, "\n\tversion unknown (0x%02x), type 0x%02x, length %u, xid 0x%08x", - version, type, length, xid)); -} - -/* Print a single OpenFlow message. */ -static const u_char * -of_header_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) -{ - uint8_t version, type; - uint16_t length; - uint32_t xid; - - if (ep < cp + OF_HEADER_LEN) - goto invalid; - /* version */ - ND_TCHECK_1(cp); - version = EXTRACT_U_1(cp); - cp += 1; - /* type */ - ND_TCHECK_1(cp); - type = EXTRACT_U_1(cp); - cp += 1; - /* length */ - ND_TCHECK_2(cp); - length = EXTRACT_BE_U_2(cp); - cp += 2; - /* xid */ - ND_TCHECK_4(cp); - xid = EXTRACT_BE_U_4(cp); - cp += 4; - /* Message length includes the header length and a message always includes - * the basic header. A message length underrun fails decoding of the rest of - * the current packet. At the same time, try decoding as much of the current - * message as possible even when it does not end within the current TCP - * segment. */ - if (length < OF_HEADER_LEN) { - of_header_print(ndo, version, type, length, xid); - goto invalid; - } - /* Decode known protocol versions further without printing the header (the - * type decoding is version-specific. */ - switch (version) { - case OF_VER_1_0: - return of10_header_body_print(ndo, cp, ep, type, length, xid); - default: - of_header_print(ndo, version, type, length, xid); - ND_TCHECK2(*cp, length - OF_HEADER_LEN); - return cp + length - OF_HEADER_LEN; /* done with current message */ - } - -invalid: /* fail current packet */ - ND_PRINT((ndo, "%s", istr)); - ND_TCHECK2(*cp, ep - cp); - return ep; -trunc: - ND_PRINT((ndo, "%s", tstr)); - return ep; + ND_PRINT("\n\tversion unknown (0x%02x), type 0x%02x, length %u, xid 0x%08x", + version, type, length, xid); } /* Print a TCP segment worth of OpenFlow messages presuming the segment begins * on a message boundary. */ void -openflow_print(netdissect_options *ndo, const u_char *cp, const u_int len) +openflow_print(netdissect_options *ndo, const u_char *cp, u_int len) { - const u_char *ep = cp + len; + ndo->ndo_protocol = "openflow"; + ND_PRINT(": OpenFlow"); + while (len) { + /* Print a single OpenFlow message. */ + uint8_t version, type; + uint16_t length; + uint32_t xid; - ND_PRINT((ndo, ": OpenFlow")); - while (cp < ep) - cp = of_header_body_print(ndo, cp, ep); + if (len < OF_HEADER_FIXLEN) + goto invalid; + /* version */ + version = GET_U_1(cp); + OF_FWD(1); + /* type */ + type = GET_U_1(cp); + OF_FWD(1); + /* length */ + length = GET_BE_U_2(cp); + OF_FWD(2); + /* xid */ + xid = GET_BE_U_4(cp); + OF_FWD(4); + /* + * When a TCP packet can contain several protocol messages, + * and at the same time a protocol message can span several + * TCP packets, decoding an incomplete message at the end of + * a TCP packet requires attention to detail in this loop. + * + * Message length includes the header length and a message + * always includes the basic header. A message length underrun + * fails decoding of the rest of the current packet. At the + * same time, try decoding as much of the current message as + * possible even when it does not end within the current TCP + * segment. + * + * Specifically, to try to process the message body in this + * iteration do NOT require the header "length" to be small + * enough for the full declared OpenFlow message to fit into + * the remainder of the declared TCP segment, same as the full + * declared TCP segment is not required to fit into the + * captured packet buffer. + * + * But DO require the same at the end of this iteration to + * decrement "len" and to proceed to the next iteration. + * (Ideally the declared TCP payload end will be at or after + * the captured packet buffer end, but stay safe even when + * that's somehow not the case.) + */ + if (length < OF_HEADER_FIXLEN) { + of_header_print(ndo, version, type, length, xid); + goto invalid; + } + /* + * Decode known protocol versions further without printing the + * header (the type decoding is version-specific). + */ + switch (version) { + case OF_VER_1_0: + of10_header_body_print(ndo, cp, type, + length - OF_HEADER_FIXLEN, xid); + break; + default: + of_header_print(ndo, version, type, length, xid); + ND_TCHECK_LEN(cp, length - OF_HEADER_FIXLEN); + } + if (length - OF_HEADER_FIXLEN > len) + break; + OF_FWD(length - OF_HEADER_FIXLEN); + } /* while (len) */ + return; + +invalid: /* fail the current packet */ + nd_print_invalid(ndo); + ND_TCHECK_LEN(cp, len); + return; +trunc: + nd_trunc(ndo); }