Bug Summary

File:src/usr.sbin/tcpdump/print-gre.c
Warning:line 325, column 2
Value stored to 'l' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name print-gre.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/tcpdump/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/tcpdump/../../sbin/pfctl -I /usr/src/usr.sbin/tcpdump/../hostapd -I /usr/src/usr.sbin/tcpdump/../../lib/libpcap -D CSLIP -D PPP -D HAVE_FDDI -D ETHER_SERVICE -D HAVE_ETHER_NTOHOST -D INET6 -I /usr/src/usr.sbin/tcpdump/../../sbin/pfctl -D FAKE_PF_KERNEL -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/tcpdump/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/tcpdump/print-gre.c
1/* $OpenBSD: print-gre.c,v 1.34 2020/08/17 07:09:25 dlg Exp $ */
2
3/*
4 * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * tcpdump filter for GRE - Generic Routing Encapsulation
31 * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE)
32 */
33
34#include <sys/time.h>
35#include <sys/uio.h>
36#include <sys/socket.h>
37
38#include <netinet/in.h>
39#include <netinet/ip.h>
40#include <arpa/inet.h>
41
42#include <net/ethertypes.h>
43
44#include <stdio.h>
45#include <string.h>
46
47#include "interface.h"
48#include "addrtoname.h"
49#include "extract.h"
50
51#define GRE_CP0x8000 0x8000 /* checksum present */
52#define GRE_RP0x4000 0x4000 /* routing present */
53#define GRE_KP0x2000 0x2000 /* key present */
54#define GRE_SP0x1000 0x1000 /* sequence# present */
55#define GRE_sP0x0800 0x0800 /* source routing */
56#define GRE_RECRS0x0700 0x0700 /* recursion count */
57#define GRE_AP0x0080 0x0080 /* acknowledgment# present */
58#define GRE_VERS0x0007 0x0007 /* protocol version */
59
60/* source route entry types */
61#define GRESRE_IP0x0800 0x0800 /* IP */
62#define GRESRE_ASN0xfffe 0xfffe /* ASN */
63
64#define NVGRE_VSID_MASK0xffffff00U 0xffffff00U
65#define NVGRE_VSID_SHIFT8 8
66#define NVGRE_FLOWID_MASK0x000000ffU 0x000000ffU
67#define NVGRE_FLOWID_SHIFT0 0
68
69#define GRE_WCCP0x883e 0x883e
70#define ERSPAN_II0x88be 0x88be
71#define ERSPAN_III0x22eb 0x22eb
72
73struct wccp_redirect {
74 uint8_t flags;
75#define WCCP_D(1 << 7) (1 << 7)
76#define WCCP_A(1 << 6) (1 << 6)
77 uint8_t ServiceId;
78 uint8_t AltBucket;
79 uint8_t PriBucket;
80};
81
82void gre_print_0(const u_char *, u_int);
83void gre_print_1(const u_char *, u_int);
84void gre_print_pptp(const u_char *, u_int, uint16_t);
85void gre_print_eoip(const u_char *, u_int, uint16_t);
86void gre_print_erspan(uint16_t, const u_char *, u_int);
87void gre_print_erspan3(const u_char *, u_int);
88void gre_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int);
89void gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int);
90void gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int);
91
92void
93gre_print(const u_char *p, u_int length)
94{
95 uint16_t vers;
96 int l;
97
98 l = snapend - p;
99
100 if (l < sizeof(vers)) {
101 printf("[|gre]");
102 return;
103 }
104 vers = EXTRACT_16BITS(p)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | (u_int16_t
)*((const u_int8_t *)(p) + 1))
& GRE_VERS0x0007;
105
106 switch (vers) {
107 case 0:
108 gre_print_0(p, length);
109 break;
110 case 1:
111 gre_print_1(p, length);
112 break;
113 default:
114 printf("gre-unknown-version=%u", vers);
115 break;
116 }
117}
118
119void
120gre_print_0(const u_char *p, u_int length)
121{
122 uint16_t flags, proto;
123 u_int l;
124
125 l = snapend - p;
126
127 flags = EXTRACT_16BITS(p)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | (u_int16_t
)*((const u_int8_t *)(p) + 1))
;
128 p += sizeof(flags);
129 l -= sizeof(flags);
130 length -= sizeof(flags);
131
132 printf("gre");
133
134 if (vflag) {
135 printf(" [%s%s%s%s%s]",
136 (flags & GRE_CP0x8000) ? "C" : "",
137 (flags & GRE_RP0x4000) ? "R" : "",
138 (flags & GRE_KP0x2000) ? "K" : "",
139 (flags & GRE_SP0x1000) ? "S" : "",
140 (flags & GRE_sP0x0800) ? "s" : "");
141 }
142
143 if (l < sizeof(proto))
144 goto trunc;
145 proto = EXTRACT_16BITS(p)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | (u_int16_t
)*((const u_int8_t *)(p) + 1))
;
146 p += sizeof(proto);
147 l -= sizeof(proto);
148 length -= sizeof(proto);
149
150 if (vflag)
151 printf(" %04x", proto);
152
153 if ((flags & GRE_CP0x8000) | (flags & GRE_RP0x4000)) {
154 if (l < 2)
155 goto trunc;
156 if ((flags & GRE_CP0x8000) && vflag)
157 printf(" sum 0x%x", EXTRACT_16BITS(p)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | (u_int16_t
)*((const u_int8_t *)(p) + 1))
);
158 p += 2;
159 l -= 2;
160 length -= 2;
161
162 if (l < 2)
163 goto trunc;
164 if (flags & GRE_RP0x4000)
165 printf(" off 0x%x", EXTRACT_16BITS(p)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | (u_int16_t
)*((const u_int8_t *)(p) + 1))
);
166 p += 2;
167 l -= 2;
168 length -= 2;
169 }
170
171 if (flags & GRE_KP0x2000) {
172 uint32_t key, vsid;
173
174 if (l < sizeof(key))
175 goto trunc;
176 key = EXTRACT_32BITS(p)((u_int32_t)*((const u_int8_t *)(p) + 0) << 24 | (u_int32_t
)*((const u_int8_t *)(p) + 1) << 16 | (u_int32_t)*((const
u_int8_t *)(p) + 2) << 8 | (u_int32_t)*((const u_int8_t
*)(p) + 3))
;
177 p += sizeof(key);
178 l -= sizeof(key);
179 length -= sizeof(key);
180
181 /* maybe NVGRE, or key entropy? */
182 vsid = (key & NVGRE_VSID_MASK0xffffff00U) >> NVGRE_VSID_SHIFT8;
183 printf(" key=%u|%u+%02x", key, vsid,
184 (key & NVGRE_FLOWID_MASK0x000000ffU) >> NVGRE_FLOWID_SHIFT0);
185 }
186
187 if (flags & GRE_SP0x1000) {
188 if (l < 4)
189 goto trunc;
190 printf(" seq %u", EXTRACT_32BITS(p)((u_int32_t)*((const u_int8_t *)(p) + 0) << 24 | (u_int32_t
)*((const u_int8_t *)(p) + 1) << 16 | (u_int32_t)*((const
u_int8_t *)(p) + 2) << 8 | (u_int32_t)*((const u_int8_t
*)(p) + 3))
);
191 p += 4;
192 l -= 4;
193 length -= 4;
194 }
195
196 if (flags & GRE_RP0x4000) {
197 for (;;) {
198 u_int16_t af;
199 u_int8_t sreoff;
200 u_int8_t srelen;
201
202 if (l < 4)
203 goto trunc;
204 af = EXTRACT_16BITS(p)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | (u_int16_t
)*((const u_int8_t *)(p) + 1))
;
205 sreoff = *(p + 2);
206 srelen = *(p + 3);
207 p += 4;
208 l -= 4;
209 length -= 4;
210
211 if (af == 0 && srelen == 0)
212 break;
213
214 gre_sre_print(af, sreoff, srelen, p, l);
215
216 if (l < srelen)
217 goto trunc;
218 p += srelen;
219 l -= srelen;
220 length -= srelen;
221 }
222 }
223
224 printf(" ");
225
226 switch (packettype) {
227 case PT_ERSPAN13:
228 gre_print_erspan(flags, p, length);
229 return;
230 default:
231 break;
232 }
233
234 switch (proto) {
235 case 0:
236 printf("keep-alive");
237 break;
238 case GRE_WCCP0x883e: {
239 printf("wccp ");
240
241 if (l == 0)
242 return;
243
244 if (*p >> 4 != 4) {
245 struct wccp_redirect *wccp;
246
247 if (l < sizeof(*wccp)) {
248 printf("[|wccp]");
249 return;
250 }
251
252 wccp = (struct wccp_redirect *)p;
253
254 printf("D:%c A:%c SId:%u Alt:%u Pri:%u",
255 (wccp->flags & WCCP_D(1 << 7)) ? '1' : '0',
256 (wccp->flags & WCCP_A(1 << 6)) ? '1' : '0',
257 wccp->ServiceId, wccp->AltBucket, wccp->PriBucket);
258
259 p += sizeof(*wccp);
260 l -= sizeof(*wccp);
261
262 printf(": ");
263 }
264
265 /* FALLTHROUGH */
266 }
267 case ETHERTYPE_IP0x0800:
268 ip_print(p, length);
269 break;
270 case ETHERTYPE_IPV60x86DD:
271 ip6_print(p, length);
272 break;
273 case ETHERTYPE_MPLS0x8847:
274 case ETHERTYPE_MPLS_MCAST0x8848:
275 mpls_print(p, length);
276 break;
277 case ETHERTYPE_TRANSETHER0x6558:
278 ether_tryprint(p, length, 0);
279 break;
280#ifndef ETHERTYPE_NSH0x894f
281#define ETHERTYPE_NSH0x894f 0x894f
282#endif
283 case ETHERTYPE_NSH0x894f:
284 nsh_print(p, length);
285 break;
286 case ERSPAN_II0x88be:
287 gre_print_erspan(flags, p, length);
288 break;
289 case 0x2000:
290 cdp_print(p, length, l, 0);
291 break;
292#ifndef ETHERTYPE_NHRP0x2001
293#define ETHERTYPE_NHRP0x2001 0x2001
294#endif
295 case ETHERTYPE_NHRP0x2001:
296 nhrp_print(p, length);
297 break;
298 default:
299 printf("unknown-proto-%04x", proto);
300 }
301 return;
302
303trunc:
304 printf("[|gre]");
305}
306
307void
308gre_print_1(const u_char *p, u_int length)
309{
310 uint16_t flags, proto;
311 int l;
312
313 l = snapend - p;
314
315 flags = EXTRACT_16BITS(p)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | (u_int16_t
)*((const u_int8_t *)(p) + 1))
;
316 p += sizeof(flags);
317 l -= sizeof(flags);
318 length -= sizeof(flags);
319
320 if (l < sizeof(proto))
321 goto trunc;
322
323 proto = EXTRACT_16BITS(p)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | (u_int16_t
)*((const u_int8_t *)(p) + 1))
;
324 p += sizeof(proto);
325 l -= sizeof(proto);
Value stored to 'l' is never read
326 length -= sizeof(proto);
327
328 switch (proto) {
329 case ETHERTYPE_PPP0x880B:
330 gre_print_pptp(p, length, flags);
331 break;
332 case 0x6400:
333 /* MikroTik RouterBoard Ethernet over IP (EoIP) */
334 gre_print_eoip(p, length, flags);
335 break;
336 default:
337 printf("unknown-gre1-proto-%04x", proto);
338 break;
339 }
340
341 return;
342
343trunc:
344 printf("[|gre1]");
345}
346
347void
348gre_print_pptp(const u_char *p, u_int length, uint16_t flags)
349{
350 uint16_t len;
351 int l;
352
353 l = snapend - p;
354
355 printf("pptp");
356
357 if (vflag) {
358 printf(" [%s%s%s%s%s%s]",
359 (flags & GRE_CP0x8000) ? "C" : "",
360 (flags & GRE_RP0x4000) ? "R" : "",
361 (flags & GRE_KP0x2000) ? "K" : "",
362 (flags & GRE_SP0x1000) ? "S" : "",
363 (flags & GRE_sP0x0800) ? "s" : "",
364 (flags & GRE_AP0x0080) ? "A" : "");
365 }
366
367 if (flags & GRE_CP0x8000) {
368 printf(" cpset!");
369 return;
370 }
371 if (flags & GRE_RP0x4000) {
372 printf(" rpset!");
373 return;
374 }
375 if ((flags & GRE_KP0x2000) == 0) {
376 printf(" kpunset!");
377 return;
378 }
379 if (flags & GRE_sP0x0800) {
380 printf(" spset!");
381 return;
382 }
383
384 /* GRE_KP */
385 if (l < sizeof(len))
386 goto trunc;
387 len = EXTRACT_16BITS(p)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | (u_int16_t
)*((const u_int8_t *)(p) + 1))
;
388 p += sizeof(len);
389 l -= sizeof(len);
390 length -= sizeof(len);
391
392 if (vflag)
393 printf(" len %u", EXTRACT_16BITS(p)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | (u_int16_t
)*((const u_int8_t *)(p) + 1))
);
394
395 if (l < 2)
396 goto trunc;
397 printf(" callid %u", EXTRACT_16BITS(p)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | (u_int16_t
)*((const u_int8_t *)(p) + 1))
);
398 p += 2;
399 l -= 2;
400 length -= 2;
401
402 if (flags & GRE_SP0x1000) {
403 if (l < 4)
404 goto trunc;
405 printf(" seq %u", EXTRACT_32BITS(p)((u_int32_t)*((const u_int8_t *)(p) + 0) << 24 | (u_int32_t
)*((const u_int8_t *)(p) + 1) << 16 | (u_int32_t)*((const
u_int8_t *)(p) + 2) << 8 | (u_int32_t)*((const u_int8_t
*)(p) + 3))
);
406 p += 4;
407 l -= 4;
408 length -= 4;
409 }
410
411 if (flags & GRE_AP0x0080) {
412 if (l < 4)
413 goto trunc;
414 printf(" ack %u", EXTRACT_32BITS(p)((u_int32_t)*((const u_int8_t *)(p) + 0) << 24 | (u_int32_t
)*((const u_int8_t *)(p) + 1) << 16 | (u_int32_t)*((const
u_int8_t *)(p) + 2) << 8 | (u_int32_t)*((const u_int8_t
*)(p) + 3))
);
415 p += 4;
416 l -= 4;
417 length -= 4;
418 }
419
420 if ((flags & GRE_SP0x1000) == 0)
421 return;
422
423 if (length < len) {
424 printf(" truncated-pptp - %d bytes missing!",
425 len - length);
426 len = length;
427 }
428
429 printf(": ");
430
431 ppp_hdlc_print(p, len);
432 return;
433
434trunc:
435 printf("[|pptp]");
436}
437
438void
439gre_print_eoip(const u_char *p, u_int length, uint16_t flags)
440{
441 uint16_t len, id;
442 int l;
443
444 l = snapend - p;
445
446 printf("eoip");
447
448 flags &= ~GRE_VERS0x0007;
449 if (flags != GRE_KP0x2000) {
450 printf(" unknown-eoip-flags-%04x!", flags);
451 return;
452 }
453
454 if (l < sizeof(len))
455 goto trunc;
456
457 len = EXTRACT_16BITS(p)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | (u_int16_t
)*((const u_int8_t *)(p) + 1))
;
458 p += sizeof(len);
459 l -= sizeof(len);
460 length -= sizeof(len);
461
462 if (l < sizeof(id))
463 goto trunc;
464
465 id = EXTRACT_LE_16BITS(p)((u_int16_t)*((const u_int8_t *)(p) + 1) << 8 | (u_int16_t
)*((const u_int8_t *)(p) + 0))
;
466 p += sizeof(id);
467 l -= sizeof(id);
468 length -= sizeof(id);
469
470 if (vflag)
471 printf(" len=%u tunnel-id=%u", len, id);
472 else
473 printf(" %u", id);
474
475 if (length < len) {
476 printf(" truncated-eoip - %d bytes missing!",
477 len - length);
478 len = length;
479 }
480
481 printf(": ");
482
483 if (len == 0)
484 printf("keepalive");
485 else
486 ether_tryprint(p, len, 0);
487
488 return;
489
490trunc:
491 printf("[|eoip]");
492}
493
494#define ERSPAN2_VER_SHIFT28 28
495#define ERSPAN2_VER_MASK(0xfU << 28) (0xfU << ERSPAN2_VER_SHIFT28)
496#define ERSPAN2_VER(0x1U << 28) (0x1U << ERSPAN2_VER_SHIFT28)
497#define ERSPAN2_VLAN_SHIFT16 16
498#define ERSPAN2_VLAN_MASK(0xfffU << 16) (0xfffU << ERSPAN2_VLAN_SHIFT16)
499#define ERSPAN2_COS_SHIFT13 13
500#define ERSPAN2_COS_MASK(0x7U << 13) (0x7U << ERSPAN2_COS_SHIFT13)
501#define ERSPAN2_EN_SHIFT11 11
502#define ERSPAN2_EN_MASK(0x3U << 11) (0x3U << ERSPAN2_EN_SHIFT11)
503#define ERSPAN2_EN_NONE(0x0U << 11) (0x0U << ERSPAN2_EN_SHIFT11)
504#define ERSPAN2_EN_ISL(0x1U << 11) (0x1U << ERSPAN2_EN_SHIFT11)
505#define ERSPAN2_EN_DOT1Q(0x2U << 11) (0x2U << ERSPAN2_EN_SHIFT11)
506#define ERSPAN2_EN_VLAN(0x3U << 11) (0x3U << ERSPAN2_EN_SHIFT11)
507#define ERSPAN2_T_SHIFT10 10
508#define ERSPAN2_T_MASK(0x1U << 10) (0x1U << ERSPAN2_T_SHIFT10)
509#define ERSPAN2_SID_SHIFT0 0
510#define ERSPAN2_SID_MASK(0x3ffU << 0) (0x3ffU << ERSPAN2_SID_SHIFT0)
511
512#define ERSPAN2_INDEX_SHIFT0 0
513#define ERSPAN2_INDEX_MASK(0xfffffU << 0) (0xfffffU << ERSPAN2_INDEX_SHIFT0)
514
515void
516gre_print_erspan(uint16_t flags, const u_char *bp, u_int len)
517{
518 uint32_t hdr, ver, vlan, cos, en, sid, index;
519 u_int l;
520
521 printf("erspan");
522
523 if (!(flags & GRE_SP0x1000)) {
524 printf(" I: ");
525 ether_tryprint(bp, len, 0);
526 return;
527 }
528
529 l = snapend - bp;
530 if (l < sizeof(hdr))
531 goto trunc;
532
533 hdr = EXTRACT_32BITS(bp)((u_int32_t)*((const u_int8_t *)(bp) + 0) << 24 | (u_int32_t
)*((const u_int8_t *)(bp) + 1) << 16 | (u_int32_t)*((const
u_int8_t *)(bp) + 2) << 8 | (u_int32_t)*((const u_int8_t
*)(bp) + 3))
;
534 bp += sizeof(hdr);
535 l -= sizeof(hdr);
536 len -= sizeof(hdr);
537
538 ver = hdr & ERSPAN2_VER_MASK(0xfU << 28);
539 if (ver != ERSPAN2_VER(0x1U << 28)) {
540 ver >>= ERSPAN2_VER_SHIFT28;
541 printf(" erspan-unknown-version-%x", ver);
542 return;
543 }
544
545 if (vflag)
546 printf(" II");
547
548 sid = (hdr & ERSPAN2_SID_MASK(0x3ffU << 0)) >> ERSPAN2_SID_SHIFT0;
549 printf(" session %u", sid);
550
551 en = hdr & ERSPAN2_EN_MASK(0x3U << 11);
552 vlan = (hdr & ERSPAN2_VLAN_MASK(0xfffU << 16)) >> ERSPAN2_VLAN_SHIFT16;
553 switch (en) {
554 case ERSPAN2_EN_NONE(0x0U << 11):
555 break;
556 case ERSPAN2_EN_ISL(0x1U << 11):
557 printf(" isl %u", vlan);
558 break;
559 case ERSPAN2_EN_DOT1Q(0x2U << 11):
560 printf(" vlan %u", vlan);
561 break;
562 case ERSPAN2_EN_VLAN(0x3U << 11):
563 printf(" vlan payload");
564 break;
565 }
566
567 if (vflag) {
568 cos = (hdr & ERSPAN2_COS_MASK(0x7U << 13)) >> ERSPAN2_COS_SHIFT13;
569 printf(" cos %u", cos);
570
571 if (hdr & ERSPAN2_T_MASK(0x1U << 10))
572 printf(" truncated");
573 }
574
575 if (l < sizeof(hdr))
576 goto trunc;
577
578 hdr = EXTRACT_32BITS(bp)((u_int32_t)*((const u_int8_t *)(bp) + 0) << 24 | (u_int32_t
)*((const u_int8_t *)(bp) + 1) << 16 | (u_int32_t)*((const
u_int8_t *)(bp) + 2) << 8 | (u_int32_t)*((const u_int8_t
*)(bp) + 3))
;
579 bp += sizeof(hdr);
580 l -= sizeof(hdr);
581 len -= sizeof(hdr);
582
583 if (vflag) {
584 index = (hdr & ERSPAN2_INDEX_MASK(0xfffffU << 0)) >> ERSPAN2_INDEX_SHIFT0;
585 printf(" index %u", index);
586 }
587
588 printf(": ");
589 ether_tryprint(bp, len, 0);
590 return;
591
592trunc:
593 printf(" [|erspan]");
594}
595
596void
597gre_sre_print(u_int16_t af, u_int8_t sreoff, u_int8_t srelen,
598 const u_char *bp, u_int len)
599{
600 switch (af) {
601 case GRESRE_IP0x0800:
602 printf(" (rtaf=ip");
603 gre_sre_ip_print(sreoff, srelen, bp, len);
604 printf(")");
605 break;
606 case GRESRE_ASN0xfffe:
607 printf(" (rtaf=asn");
608 gre_sre_asn_print(sreoff, srelen, bp, len);
609 printf(")");
610 break;
611 default:
612 printf(" (rtaf=0x%x)", af);
613 }
614}
615void
616gre_sre_ip_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
617{
618 struct in_addr a;
619 const u_char *up = bp;
620
621 if (sreoff & 3) {
622 printf(" badoffset=%u", sreoff);
623 return;
624 }
625 if (srelen & 3) {
626 printf(" badlength=%u", srelen);
627 return;
628 }
629 if (sreoff >= srelen) {
630 printf(" badoff/len=%u/%u", sreoff, srelen);
631 return;
632 }
633
634 for (;;) {
635 if (len < 4 || srelen == 0)
636 return;
637
638 memcpy(&a, bp, sizeof(a));
639 printf(" %s%s",
640 ((bp - up) == sreoff) ? "*" : "",
641 inet_ntoa(a));
642
643 bp += 4;
644 len -= 4;
645 srelen -= 4;
646 }
647}
648
649void
650gre_sre_asn_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
651{
652 const u_char *up = bp;
653
654 if (sreoff & 1) {
655 printf(" badoffset=%u", sreoff);
656 return;
657 }
658 if (srelen & 1) {
659 printf(" badlength=%u", srelen);
660 return;
661 }
662 if (sreoff >= srelen) {
663 printf(" badoff/len=%u/%u", sreoff, srelen);
664 return;
665 }
666
667 for (;;) {
668 if (len < 2 || srelen == 0)
669 return;
670
671 printf(" %s%x",
672 ((bp - up) == sreoff) ? "*" : "",
673 EXTRACT_16BITS(bp)((u_int16_t)*((const u_int8_t *)(bp) + 0) << 8 | (u_int16_t
)*((const u_int8_t *)(bp) + 1))
);
674
675 bp += 2;
676 len -= 2;
677 srelen -= 2;
678 }
679}
680
681/*
682 * - RFC 7348 Virtual eXtensible Local Area Network (VXLAN)
683 * - draft-ietf-nvo3-vxlan-gpe-08 Generic Protocol Extension for VXLAN
684 */
685
686struct vxlan_header {
687 uint16_t flags;
688#define VXLAN_VER0x3000 0x3000 /* GPE */
689#define VXLAN_VER_00x0000 0x0000
690#define VXLAN_I0x0800 0x0800 /* Instance Bit */
691#define VXLAN_P0x0400 0x0400 /* GPE Next Protocol */
692#define VXLAN_B0x0200 0x0200 /* GPE BUM Traffic */
693#define VXLAN_O0x0100 0x0100 /* GPE OAM Flag */
694 uint8_t reserved;
695 uint8_t next_proto; /* GPE */
696#define VXLAN_PROTO_RESERVED0x00 0x00
697#define VXLAN_PROTO_IPV40x01 0x01
698#define VXLAN_PROTO_IPV60x02 0x02
699#define VXLAN_PROTO_ETHERNET0x03 0x03
700#define VXLAN_PROTO_NSH0x04 0x04
701#define VXLAN_PROTO_MPLS0x05 0x05
702#define VXLAN_PROTO_VBNG0x07 0x07
703#define VXLAN_PROTO_GBP0x80 0x80
704#define VXLAN_PROTO_IOAM0x82 0x82
705 uint32_t vni;
706#define VXLAN_VNI_SHIFT8 8
707#define VXLAN_VNI_MASK(0xffffffU << 8) (0xffffffU << VXLAN_VNI_SHIFT8)
708#define VXLAN_VNI_RESERVED(~(0xffffffU << 8)) (~VXLAN_VNI_MASK(0xffffffU << 8))
709};
710
711void
712vxlan_print(const u_char *p, u_int length)
713{
714 const struct vxlan_header *vh;
715 uint16_t flags, ver;
716 uint8_t proto = VXLAN_PROTO_ETHERNET0x03;
717 int l = snapend - p;
718
719 printf("VXLAN");
720
721 if (l < sizeof(*vh))
722 goto trunc;
723 if (length < sizeof(*vh)) {
724 printf(" ip truncated");
725 return;
726 }
727
728 vh = (const struct vxlan_header *)p;
729
730 p += sizeof(*vh);
731 length -= sizeof(*vh);
732
733 flags = ntohs(vh->flags)(__uint16_t)(__builtin_constant_p(vh->flags) ? (__uint16_t
)(((__uint16_t)(vh->flags) & 0xffU) << 8 | ((__uint16_t
)(vh->flags) & 0xff00U) >> 8) : __swap16md(vh->
flags))
;
734 ver = flags & VXLAN_VER0x3000;
735 if (ver != VXLAN_VER_00x0000) {
736 printf(" unknown version %u", ver >> 12);
737 return;
738 }
739
740 if (flags & VXLAN_I0x0800) {
741 uint32_t vni = (htonl(vh->vni)(__uint32_t)(__builtin_constant_p(vh->vni) ? (__uint32_t)(
((__uint32_t)(vh->vni) & 0xff) << 24 | ((__uint32_t
)(vh->vni) & 0xff00) << 8 | ((__uint32_t)(vh->
vni) & 0xff0000) >> 8 | ((__uint32_t)(vh->vni) &
0xff000000) >> 24) : __swap32md(vh->vni))
& VXLAN_VNI_MASK(0xffffffU << 8)) >>
742 VXLAN_VNI_SHIFT8;
743 printf(" vni %u", vni);
744 }
745
746 if (flags & VXLAN_P0x0400)
747 proto = vh->next_proto;
748
749 if (flags & VXLAN_B0x0200)
750 printf(" BUM");
751
752 if (flags & VXLAN_O0x0100) {
753 printf(" OAM (proto 0x%x, len %u)", proto, length);
754 return;
755 }
756
757 printf(": ");
758
759 switch (proto) {
760 case VXLAN_PROTO_RESERVED0x00:
761 printf("Reserved");
762 break;
763 case VXLAN_PROTO_IPV40x01:
764 ip_print(p, length);
765 break;
766 case VXLAN_PROTO_IPV60x02:
767 ip6_print(p, length);
768 break;
769 case VXLAN_PROTO_ETHERNET0x03:
770 ether_tryprint(p, length, 0);
771 break;
772 case VXLAN_PROTO_NSH0x04:
773 nsh_print(p, length);
774 break;
775 case VXLAN_PROTO_MPLS0x05:
776 mpls_print(p, length);
777 break;
778
779 default:
780 printf("Unassigned proto 0x%x", proto);
781 break;
782 }
783
784 return;
785trunc:
786 printf(" [|vxlan]");
787}
788
789/*
790 * Geneve: Generic Network Virtualization Encapsulation
791 * draft-ietf-nvo3-geneve-16
792 */
793
794struct geneve_header {
795 uint16_t flags;
796#define GENEVE_VER_SHIFT14 14
797#define GENEVE_VER_MASK(0x3U << 14) (0x3U << GENEVE_VER_SHIFT14)
798#define GENEVE_VER_0(0x0U << 14) (0x0U << GENEVE_VER_SHIFT14)
799#define GENEVE_OPT_LEN_SHIFT8 8
800#define GENEVE_OPT_LEN_MASK(0x3fU << 8) (0x3fU << GENEVE_OPT_LEN_SHIFT8)
801#define GENEVE_OPT_LEN_UNITS4 4
802#define GENEVE_O0x0080 0x0080 /* Control packet */
803#define GENEVE_C0x0040 0x0040 /* Critical options present */
804 uint16_t protocol;
805 uint32_t vni;
806#define GENEVE_VNI_SHIFT8 8
807#define GENEVE_VNI_MASK(0xffffffU << 8) (0xffffffU << GENEVE_VNI_SHIFT8)
808#define GENEVE_VNI_RESERVED(~(0xffffffU << 8)) (~GENEVE_VNI_MASK(0xffffffU << 8))
809};
810
811struct geneve_option {
812 uint16_t class;
813 uint8_t type;
814 uint8_t flags;
815#define GENEVE_OPTION_LENGTH_SHIFT0 0
816#define GENEVE_OPTION_LENGTH_MASK(0x1fU << 0) (0x1fU << GENEVE_OPTION_LENGTH_SHIFT0)
817};
818
819static void
820geneve_options_print(const u_char *p, u_int l)
821{
822 if (l == 0)
823 return;
824
825 do {
826 struct geneve_option *go;
827 unsigned int len, i;
828
829 if (l < sizeof(*go))
830 goto trunc;
831
832 go = (struct geneve_option *)p;
833 p += sizeof(*go);
834 l -= sizeof(*go);
835
836 printf("\n\toption class %u type %u", ntohs(go->class)(__uint16_t)(__builtin_constant_p(go->class) ? (__uint16_t
)(((__uint16_t)(go->class) & 0xffU) << 8 | ((__uint16_t
)(go->class) & 0xff00U) >> 8) : __swap16md(go->
class))
,
837 go->type);
838
839 len = (go->flags & GENEVE_OPTION_LENGTH_MASK(0x1fU << 0)) >>
840 GENEVE_OPTION_LENGTH_SHIFT0;
841 if (len > 0) {
842 printf(":");
843 for (i = 0; i < len; i++) {
844 uint32_t w;
845
846 if (l < sizeof(w))
847 goto trunc;
848
849 w = EXTRACT_32BITS(p)((u_int32_t)*((const u_int8_t *)(p) + 0) << 24 | (u_int32_t
)*((const u_int8_t *)(p) + 1) << 16 | (u_int32_t)*((const
u_int8_t *)(p) + 2) << 8 | (u_int32_t)*((const u_int8_t
*)(p) + 3))
;
850 p += sizeof(w);
851 l -= sizeof(w);
852
853 printf(" %08x", w);
854 }
855 }
856 } while (l > 0);
857
858 return;
859trunc:
860 printf("[|geneve option]");
861}
862
863void
864geneve_print(const u_char *p, u_int length)
865{
866 const struct geneve_header *gh;
867 uint16_t flags, ver, optlen, proto;
868 uint32_t vni;
869 int l = snapend - p;
870
871 printf("geneve");
872
873 if (l < sizeof(*gh))
874 goto trunc;
875 if (length < sizeof(*gh)) {
876 printf(" ip truncated");
877 return;
878 }
879
880 gh = (const struct geneve_header *)p;
881
882 p += sizeof(*gh);
883 l -= sizeof(*gh);
884 length -= sizeof(*gh);
885
886 flags = ntohs(gh->flags)(__uint16_t)(__builtin_constant_p(gh->flags) ? (__uint16_t
)(((__uint16_t)(gh->flags) & 0xffU) << 8 | ((__uint16_t
)(gh->flags) & 0xff00U) >> 8) : __swap16md(gh->
flags))
;
887 ver = flags & GENEVE_VER_MASK(0x3U << 14);
888 if (ver != GENEVE_VER_0(0x0U << 14)) {
889 printf(" unknown version %u", ver >> GENEVE_VER_SHIFT14);
890 return;
891 }
892
893 vni = (htonl(gh->vni)(__uint32_t)(__builtin_constant_p(gh->vni) ? (__uint32_t)(
((__uint32_t)(gh->vni) & 0xff) << 24 | ((__uint32_t
)(gh->vni) & 0xff00) << 8 | ((__uint32_t)(gh->
vni) & 0xff0000) >> 8 | ((__uint32_t)(gh->vni) &
0xff000000) >> 24) : __swap32md(gh->vni))
& GENEVE_VNI_MASK(0xffffffU << 8)) >> GENEVE_VNI_SHIFT8;
894 printf(" vni %u", vni);
895
896 if (flags & GENEVE_O0x0080)
897 printf(" Control");
898
899 if (flags & GENEVE_C0x0040)
900 printf(" Critical");
901
902 optlen = (flags & GENEVE_OPT_LEN_MASK(0x3fU << 8)) >> GENEVE_OPT_LEN_SHIFT8;
903 optlen *= GENEVE_OPT_LEN_UNITS4;
904
905 if (l < optlen)
906 goto trunc;
907 if (length < optlen) {
908 printf(" ip truncated");
909 return;
910 }
911
912 if (optlen > 0)
913 geneve_options_print(p, optlen);
914
915 p += optlen;
916 length -= optlen;
917
918 printf("\n ");
919
920 proto = ntohs(gh->protocol)(__uint16_t)(__builtin_constant_p(gh->protocol) ? (__uint16_t
)(((__uint16_t)(gh->protocol) & 0xffU) << 8 | ((
__uint16_t)(gh->protocol) & 0xff00U) >> 8) : __swap16md
(gh->protocol))
;
921 switch (proto) {
922 case ETHERTYPE_IP0x0800:
923 ip_print(p, length);
924 break;
925 case ETHERTYPE_IPV60x86DD:
926 ip6_print(p, length);
927 break;
928 case ETHERTYPE_MPLS0x8847:
929 case ETHERTYPE_MPLS_MCAST0x8848:
930 mpls_print(p, length);
931 break;
932 case ETHERTYPE_TRANSETHER0x6558:
933 ether_tryprint(p, length, 0);
934 break;
935
936 default:
937 printf("geneve-protocol-0x%x", proto);
938 break;
939 }
940
941 return;
942trunc:
943 printf(" [|geneve]");
944}