1285191Spkelsey/*
2285191Spkelsey * Copyright (c) 2014 VMware, Inc. All Rights Reserved.
3285191Spkelsey *
4285191Spkelsey * Jesse Gross <jesse@nicira.com>
5285191Spkelsey *
6285191Spkelsey * Redistribution and use in source and binary forms, with or without
7285191Spkelsey * modification, are permitted provided that: (1) source code
8285191Spkelsey * distributions retain the above copyright notice and this paragraph
9285191Spkelsey * in its entirety, and (2) distributions including binary code include
10285191Spkelsey * the above copyright notice and this paragraph in its entirety in
11285191Spkelsey * the documentation or other materials provided with the distribution.
12285191Spkelsey * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
13285191Spkelsey * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
14285191Spkelsey * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
15285191Spkelsey * FOR A PARTICULAR PURPOSE.
16285191Spkelsey */
17285191Spkelsey
18285191Spkelsey#define NETDISSECT_REWORKED
19285191Spkelsey#ifdef HAVE_CONFIG_H
20285191Spkelsey#include "config.h"
21285191Spkelsey#endif
22285191Spkelsey
23285191Spkelsey#include <tcpdump-stdinc.h>
24285191Spkelsey
25285191Spkelsey#include "interface.h"
26285191Spkelsey#include "extract.h"
27285191Spkelsey#include "ethertype.h"
28285191Spkelsey
29285191Spkelsey/*
30285191Spkelsey * Geneve header, draft-gross-geneve-02
31285191Spkelsey *
32285191Spkelsey *    0                   1                   2                   3
33285191Spkelsey *    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
34285191Spkelsey *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35285191Spkelsey *    |Ver|  Opt Len  |O|C|    Rsvd.  |          Protocol Type        |
36285191Spkelsey *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37285191Spkelsey *    |        Virtual Network Identifier (VNI)       |    Reserved   |
38285191Spkelsey *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39285191Spkelsey *    |                    Variable Length Options                    |
40285191Spkelsey *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41285191Spkelsey *
42285191Spkelsey * Options:
43285191Spkelsey *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44285191Spkelsey *    |          Option Class         |      Type     |R|R|R| Length  |
45285191Spkelsey *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46285191Spkelsey *    |                      Variable Option Data                     |
47285191Spkelsey *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48285191Spkelsey */
49285191Spkelsey
50285191Spkelsey#define VER_SHIFT 6
51285191Spkelsey#define HDR_OPTS_LEN_MASK 0x3F
52285191Spkelsey
53285191Spkelsey#define FLAG_OAM      (1 << 7)
54285191Spkelsey#define FLAG_CRITICAL (1 << 6)
55285191Spkelsey#define FLAG_R1       (1 << 5)
56285191Spkelsey#define FLAG_R2       (1 << 4)
57285191Spkelsey#define FLAG_R3       (1 << 3)
58285191Spkelsey#define FLAG_R4       (1 << 2)
59285191Spkelsey#define FLAG_R5       (1 << 1)
60285191Spkelsey#define FLAG_R6       (1 << 0)
61285191Spkelsey
62285191Spkelsey#define OPT_TYPE_CRITICAL (1 << 7)
63285191Spkelsey#define OPT_LEN_MASK 0x1F
64285191Spkelsey
65285191Spkelseystatic const struct tok geneve_flag_values[] = {
66285191Spkelsey        { FLAG_OAM, "O" },
67285191Spkelsey        { FLAG_CRITICAL, "C" },
68285191Spkelsey        { FLAG_R1, "R1" },
69285191Spkelsey        { FLAG_R2, "R2" },
70285191Spkelsey        { FLAG_R3, "R3" },
71285191Spkelsey        { FLAG_R4, "R4" },
72285191Spkelsey        { FLAG_R5, "R5" },
73285191Spkelsey        { FLAG_R6, "R6" },
74285191Spkelsey        { 0, NULL }
75285191Spkelsey};
76285191Spkelsey
77285191Spkelseystatic const char *
78285191Spkelseyformat_opt_class(uint16_t opt_class)
79285191Spkelsey{
80285191Spkelsey    if (opt_class <= 0xff)
81285191Spkelsey        return "Standard";
82285191Spkelsey    else if (opt_class == 0xffff)
83285191Spkelsey        return "Experimental";
84285191Spkelsey    else
85285191Spkelsey        return "Unknown";
86285191Spkelsey}
87285191Spkelsey
88285191Spkelseystatic void
89285191Spkelseygeneve_opts_print(netdissect_options *ndo, const u_char *bp, u_int len)
90285191Spkelsey{
91285191Spkelsey    const char *sep = "";
92285191Spkelsey
93285191Spkelsey    while (len > 0) {
94285191Spkelsey        uint16_t opt_class;
95285191Spkelsey        uint8_t opt_type;
96285191Spkelsey        uint8_t opt_len;
97285191Spkelsey
98285191Spkelsey        ND_PRINT((ndo, "%s", sep));
99285191Spkelsey        sep = ", ";
100285191Spkelsey
101285191Spkelsey        opt_class = EXTRACT_16BITS(bp);
102285191Spkelsey        opt_type = *(bp + 2);
103285191Spkelsey        opt_len = 4 + ((*(bp + 3) & OPT_LEN_MASK) * 4);
104285191Spkelsey
105285191Spkelsey        ND_PRINT((ndo, "class %s (0x%x) type 0x%x%s len %u",
106285191Spkelsey                  format_opt_class(opt_class), opt_class, opt_type,
107285191Spkelsey                  opt_type & OPT_TYPE_CRITICAL ? "(C)" : "", opt_len));
108285191Spkelsey
109285191Spkelsey        if (opt_len > len) {
110285191Spkelsey            ND_PRINT((ndo, " [bad length]"));
111285191Spkelsey            return;
112285191Spkelsey        }
113285191Spkelsey
114285191Spkelsey        if (ndo->ndo_vflag > 1 && opt_len > 4) {
115285191Spkelsey            uint32_t *print_data = (uint32_t *)(bp + 4);
116285191Spkelsey            int i;
117285191Spkelsey
118285191Spkelsey            ND_PRINT((ndo, " data"));
119285191Spkelsey
120285191Spkelsey            for (i = 4; i < opt_len; i += 4) {
121285191Spkelsey                ND_PRINT((ndo, " %08x", EXTRACT_32BITS(print_data)));
122285191Spkelsey                print_data++;
123285191Spkelsey            }
124285191Spkelsey        }
125285191Spkelsey
126285191Spkelsey        bp += opt_len;
127285191Spkelsey        len -= opt_len;
128285191Spkelsey    }
129285191Spkelsey}
130285191Spkelsey
131285191Spkelseyvoid
132285191Spkelseygeneve_print(netdissect_options *ndo, const u_char *bp, u_int len)
133285191Spkelsey{
134285191Spkelsey    uint8_t ver_opt;
135285191Spkelsey    uint version;
136285191Spkelsey    uint8_t flags;
137285191Spkelsey    uint16_t prot;
138285191Spkelsey    uint32_t vni;
139285191Spkelsey    uint8_t reserved;
140285191Spkelsey    u_int opts_len;
141285191Spkelsey
142285191Spkelsey    ND_PRINT((ndo, "Geneve"));
143285191Spkelsey
144285191Spkelsey    ND_TCHECK2(*bp, 8);
145285191Spkelsey
146285191Spkelsey    ver_opt = *bp;
147285191Spkelsey    bp += 1;
148285191Spkelsey    len -= 1;
149285191Spkelsey
150285191Spkelsey    version = ver_opt >> VER_SHIFT;
151285191Spkelsey    if (version != 0) {
152285191Spkelsey        ND_PRINT((ndo, " ERROR: unknown-version %u", version));
153285191Spkelsey        return;
154285191Spkelsey    }
155285191Spkelsey
156285191Spkelsey    flags = *bp;
157285191Spkelsey    bp += 1;
158285191Spkelsey    len -= 1;
159285191Spkelsey
160285191Spkelsey    prot = EXTRACT_16BITS(bp);
161285191Spkelsey    bp += 2;
162285191Spkelsey    len -= 2;
163285191Spkelsey
164285191Spkelsey    vni = EXTRACT_24BITS(bp);
165285191Spkelsey    bp += 3;
166285191Spkelsey    len -= 3;
167285191Spkelsey
168285191Spkelsey    reserved = *bp;
169285191Spkelsey    bp += 1;
170285191Spkelsey    len -= 1;
171285191Spkelsey
172285191Spkelsey    ND_PRINT((ndo, ", Flags [%s]",
173285191Spkelsey              bittok2str_nosep(geneve_flag_values, "none", flags)));
174285191Spkelsey    ND_PRINT((ndo, ", vni 0x%x", vni));
175285191Spkelsey
176285191Spkelsey    if (reserved)
177285191Spkelsey        ND_PRINT((ndo, ", rsvd 0x%x", reserved));
178285191Spkelsey
179285191Spkelsey    if (ndo->ndo_eflag)
180285191Spkelsey        ND_PRINT((ndo, ", proto %s (0x%04x)",
181285191Spkelsey                  tok2str(ethertype_values, "unknown", prot), prot));
182285191Spkelsey
183285191Spkelsey    opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4;
184285191Spkelsey
185285191Spkelsey    if (len < opts_len) {
186285191Spkelsey        ND_PRINT((ndo, " truncated-geneve - %u bytes missing",
187285191Spkelsey                  len - opts_len));
188285191Spkelsey        return;
189285191Spkelsey    }
190285191Spkelsey
191285191Spkelsey    ND_TCHECK2(*bp, opts_len);
192285191Spkelsey
193285191Spkelsey    if (opts_len > 0) {
194285191Spkelsey        ND_PRINT((ndo, ", options ["));
195285191Spkelsey
196285191Spkelsey        if (ndo->ndo_vflag)
197285191Spkelsey            geneve_opts_print(ndo, bp, opts_len);
198285191Spkelsey        else
199285191Spkelsey            ND_PRINT((ndo, "%u bytes", opts_len));
200285191Spkelsey
201285191Spkelsey        ND_PRINT((ndo, "]"));
202285191Spkelsey    }
203285191Spkelsey
204285191Spkelsey    bp += opts_len;
205285191Spkelsey    len -= opts_len;
206285191Spkelsey
207285191Spkelsey    if (ndo->ndo_vflag < 1)
208285191Spkelsey        ND_PRINT((ndo, ": "));
209285191Spkelsey    else
210285191Spkelsey        ND_PRINT((ndo, "\n\t"));
211285191Spkelsey
212285191Spkelsey    if (ethertype_print(ndo, prot, bp, len, len) == 0) {
213285191Spkelsey        if (prot == ETHERTYPE_TEB)
214285191Spkelsey            ether_print(ndo, bp, len, len, NULL, NULL);
215285191Spkelsey        else
216285191Spkelsey            ND_PRINT((ndo, "geneve-proto-0x%x", prot));
217285191Spkelsey    }
218285191Spkelsey
219285191Spkelsey    return;
220285191Spkelsey
221285191Spkelseytrunc:
222285191Spkelsey    ND_PRINT((ndo, " [|geneve]"));
223285191Spkelsey}
224