File: | src/usr.sbin/tcpdump/print-gre.c |
Warning: | line 260, column 4 Value stored to 'l' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
73 | struct 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 | |
82 | void gre_print_0(const u_char *, u_int); |
83 | void gre_print_1(const u_char *, u_int); |
84 | void gre_print_pptp(const u_char *, u_int, uint16_t); |
85 | void gre_print_eoip(const u_char *, u_int, uint16_t); |
86 | void gre_print_erspan(uint16_t, const u_char *, u_int); |
87 | void gre_print_erspan3(const u_char *, u_int); |
88 | void gre_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int); |
89 | void gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int); |
90 | void gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int); |
91 | |
92 | void |
93 | gre_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 | |
119 | void |
120 | gre_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); |
Value stored to 'l' is never read | |
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 | |
303 | trunc: |
304 | printf("[|gre]"); |
305 | } |
306 | |
307 | void |
308 | gre_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); |
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 | |
343 | trunc: |
344 | printf("[|gre1]"); |
345 | } |
346 | |
347 | void |
348 | gre_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 | |
434 | trunc: |
435 | printf("[|pptp]"); |
436 | } |
437 | |
438 | void |
439 | gre_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 | |
490 | trunc: |
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 | |
515 | void |
516 | gre_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 | |
592 | trunc: |
593 | printf(" [|erspan]"); |
594 | } |
595 | |
596 | void |
597 | gre_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 | } |
615 | void |
616 | gre_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 | |
649 | void |
650 | gre_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 | |
686 | struct 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 | |
711 | void |
712 | vxlan_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; |
785 | trunc: |
786 | printf(" [|vxlan]"); |
787 | } |
788 | |
789 | /* |
790 | * Geneve: Generic Network Virtualization Encapsulation |
791 | * draft-ietf-nvo3-geneve-16 |
792 | */ |
793 | |
794 | struct 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 | |
811 | struct 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 | |
819 | static void |
820 | geneve_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; |
859 | trunc: |
860 | printf("[|geneve option]"); |
861 | } |
862 | |
863 | void |
864 | geneve_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; |
942 | trunc: |
943 | printf(" [|geneve]"); |
944 | } |