]> The Tcpdump Group git mirrors - tcpdump/blob - print-gre.c
IGMP: Remove all remaining ND_TCHECK*() cases.
[tcpdump] / print-gre.c
1 /* $OpenBSD: print-gre.c,v 1.6 2002/10/30 03:04:04 fgsch 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 /* \summary: Generic Routing Encapsulation (GRE) printer */
30
31 /*
32 * netdissect printer for GRE - Generic Routing Encapsulation
33 * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE)
34 */
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include "netdissect-stdinc.h"
41
42 #include <string.h>
43
44 #include "netdissect.h"
45 #include "addrtostr.h"
46 #include "extract.h"
47 #include "ethertype.h"
48
49
50 #define GRE_CP 0x8000 /* checksum present */
51 #define GRE_RP 0x4000 /* routing present */
52 #define GRE_KP 0x2000 /* key present */
53 #define GRE_SP 0x1000 /* sequence# present */
54 #define GRE_sP 0x0800 /* source routing */
55 #define GRE_RECRS 0x0700 /* recursion count */
56 #define GRE_AP 0x0080 /* acknowledgment# present */
57
58 static const struct tok gre_flag_values[] = {
59 { GRE_CP, "checksum present"},
60 { GRE_RP, "routing present"},
61 { GRE_KP, "key present"},
62 { GRE_SP, "sequence# present"},
63 { GRE_sP, "source routing present"},
64 { GRE_RECRS, "recursion count"},
65 { GRE_AP, "ack present"},
66 { 0, NULL }
67 };
68
69 #define GRE_VERS_MASK 0x0007 /* protocol version */
70
71 /* source route entry types */
72 #define GRESRE_IP 0x0800 /* IP */
73 #define GRESRE_ASN 0xfffe /* ASN */
74
75 static void gre_print_0(netdissect_options *, const u_char *, u_int);
76 static void gre_print_1(netdissect_options *, const u_char *, u_int);
77 static int gre_sre_print(netdissect_options *, uint16_t, uint8_t, uint8_t, const u_char *, u_int);
78 static int gre_sre_ip_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int);
79 static int gre_sre_asn_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int);
80
81 void
82 gre_print(netdissect_options *ndo, const u_char *bp, u_int length)
83 {
84 u_int len = length, vers;
85
86 ndo->ndo_protocol = "gre";
87 ND_TCHECK_2(bp);
88 if (len < 2)
89 goto trunc;
90 vers = GET_BE_U_2(bp) & GRE_VERS_MASK;
91 ND_PRINT("GREv%u",vers);
92
93 switch(vers) {
94 case 0:
95 gre_print_0(ndo, bp, len);
96 break;
97 case 1:
98 gre_print_1(ndo, bp, len);
99 break;
100 default:
101 ND_PRINT(" ERROR: unknown-version");
102 break;
103 }
104 return;
105
106 trunc:
107 nd_print_trunc(ndo);
108 }
109
110 static void
111 gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length)
112 {
113 u_int len = length;
114 uint16_t flags, prot;
115
116 /* 16 bits ND_TCHECKed in gre_print() */
117 flags = GET_BE_U_2(bp);
118 if (ndo->ndo_vflag)
119 ND_PRINT(", Flags [%s]",
120 bittok2str(gre_flag_values,"none",flags));
121
122 len -= 2;
123 bp += 2;
124
125 ND_TCHECK_2(bp);
126 if (len < 2)
127 goto trunc;
128 prot = GET_BE_U_2(bp);
129 len -= 2;
130 bp += 2;
131
132 if ((flags & GRE_CP) | (flags & GRE_RP)) {
133 ND_TCHECK_2(bp);
134 if (len < 2)
135 goto trunc;
136 if (ndo->ndo_vflag)
137 ND_PRINT(", sum 0x%x", GET_BE_U_2(bp));
138 bp += 2;
139 len -= 2;
140
141 ND_TCHECK_2(bp);
142 if (len < 2)
143 goto trunc;
144 ND_PRINT(", off 0x%x", GET_BE_U_2(bp));
145 bp += 2;
146 len -= 2;
147 }
148
149 if (flags & GRE_KP) {
150 ND_TCHECK_4(bp);
151 if (len < 4)
152 goto trunc;
153 ND_PRINT(", key=0x%x", GET_BE_U_4(bp));
154 bp += 4;
155 len -= 4;
156 }
157
158 if (flags & GRE_SP) {
159 ND_TCHECK_4(bp);
160 if (len < 4)
161 goto trunc;
162 ND_PRINT(", seq %u", GET_BE_U_4(bp));
163 bp += 4;
164 len -= 4;
165 }
166
167 if (flags & GRE_RP) {
168 for (;;) {
169 uint16_t af;
170 uint8_t sreoff;
171 uint8_t srelen;
172
173 ND_TCHECK_4(bp);
174 if (len < 4)
175 goto trunc;
176 af = GET_BE_U_2(bp);
177 sreoff = GET_U_1(bp + 2);
178 srelen = GET_U_1(bp + 3);
179 bp += 4;
180 len -= 4;
181
182 if (af == 0 && srelen == 0)
183 break;
184
185 if (!gre_sre_print(ndo, af, sreoff, srelen, bp, len))
186 goto trunc;
187
188 if (len < srelen)
189 goto trunc;
190 bp += srelen;
191 len -= srelen;
192 }
193 }
194
195 if (ndo->ndo_eflag)
196 ND_PRINT(", proto %s (0x%04x)",
197 tok2str(ethertype_values,"unknown",prot), prot);
198
199 ND_PRINT(", length %u",length);
200
201 if (ndo->ndo_vflag < 1)
202 ND_PRINT(": "); /* put in a colon as protocol demarc */
203 else
204 ND_PRINT("\n\t"); /* if verbose go multiline */
205
206 switch (prot) {
207 case ETHERTYPE_IP:
208 ip_print(ndo, bp, len);
209 break;
210 case ETHERTYPE_IPV6:
211 ip6_print(ndo, bp, len);
212 break;
213 case ETHERTYPE_MPLS:
214 mpls_print(ndo, bp, len);
215 break;
216 case ETHERTYPE_IPX:
217 ipx_print(ndo, bp, len);
218 break;
219 case ETHERTYPE_ATALK:
220 atalk_print(ndo, bp, len);
221 break;
222 case ETHERTYPE_GRE_ISO:
223 isoclns_print(ndo, bp, len);
224 break;
225 case ETHERTYPE_TEB:
226 ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
227 break;
228 default:
229 ND_PRINT("gre-proto-0x%x", prot);
230 }
231 return;
232
233 trunc:
234 nd_print_trunc(ndo);
235 }
236
237 static void
238 gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length)
239 {
240 u_int len = length;
241 uint16_t flags, prot;
242
243 /* 16 bits ND_TCHECKed in gre_print() */
244 flags = GET_BE_U_2(bp);
245 len -= 2;
246 bp += 2;
247
248 if (ndo->ndo_vflag)
249 ND_PRINT(", Flags [%s]",
250 bittok2str(gre_flag_values,"none",flags));
251
252 ND_TCHECK_2(bp);
253 if (len < 2)
254 goto trunc;
255 prot = GET_BE_U_2(bp);
256 len -= 2;
257 bp += 2;
258
259
260 if (flags & GRE_KP) {
261 uint32_t k;
262
263 ND_TCHECK_4(bp);
264 if (len < 4)
265 goto trunc;
266 k = GET_BE_U_4(bp);
267 ND_PRINT(", call %u", k & 0xffff);
268 len -= 4;
269 bp += 4;
270 }
271
272 if (flags & GRE_SP) {
273 ND_TCHECK_4(bp);
274 if (len < 4)
275 goto trunc;
276 ND_PRINT(", seq %u", GET_BE_U_4(bp));
277 bp += 4;
278 len -= 4;
279 }
280
281 if (flags & GRE_AP) {
282 ND_TCHECK_4(bp);
283 if (len < 4)
284 goto trunc;
285 ND_PRINT(", ack %u", GET_BE_U_4(bp));
286 bp += 4;
287 len -= 4;
288 }
289
290 if ((flags & GRE_SP) == 0)
291 ND_PRINT(", no-payload");
292
293 if (ndo->ndo_eflag)
294 ND_PRINT(", proto %s (0x%04x)",
295 tok2str(ethertype_values,"unknown",prot), prot);
296
297 ND_PRINT(", length %u",length);
298
299 if ((flags & GRE_SP) == 0)
300 return;
301
302 if (ndo->ndo_vflag < 1)
303 ND_PRINT(": "); /* put in a colon as protocol demarc */
304 else
305 ND_PRINT("\n\t"); /* if verbose go multiline */
306
307 switch (prot) {
308 case ETHERTYPE_PPP:
309 ppp_print(ndo, bp, len);
310 break;
311 default:
312 ND_PRINT("gre-proto-0x%x", prot);
313 break;
314 }
315 return;
316
317 trunc:
318 nd_print_trunc(ndo);
319 }
320
321 static int
322 gre_sre_print(netdissect_options *ndo, uint16_t af, uint8_t sreoff,
323 uint8_t srelen, const u_char *bp, u_int len)
324 {
325 int ret;
326
327 switch (af) {
328 case GRESRE_IP:
329 ND_PRINT(", (rtaf=ip");
330 ret = gre_sre_ip_print(ndo, sreoff, srelen, bp, len);
331 ND_PRINT(")");
332 break;
333 case GRESRE_ASN:
334 ND_PRINT(", (rtaf=asn");
335 ret = gre_sre_asn_print(ndo, sreoff, srelen, bp, len);
336 ND_PRINT(")");
337 break;
338 default:
339 ND_PRINT(", (rtaf=0x%x)", af);
340 ret = 1;
341 }
342 return (ret);
343 }
344
345 static int
346 gre_sre_ip_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
347 const u_char *bp, u_int len)
348 {
349 const u_char *up = bp;
350 char buf[INET_ADDRSTRLEN];
351
352 if (sreoff & 3) {
353 ND_PRINT(", badoffset=%u", sreoff);
354 return (1);
355 }
356 if (srelen & 3) {
357 ND_PRINT(", badlength=%u", srelen);
358 return (1);
359 }
360 if (sreoff >= srelen) {
361 ND_PRINT(", badoff/len=%u/%u", sreoff, srelen);
362 return (1);
363 }
364
365 while (srelen != 0) {
366 ND_TCHECK_4(bp);
367 if (len < 4)
368 return (0);
369
370 addrtostr(bp, buf, sizeof(buf));
371 ND_PRINT(" %s%s",
372 ((bp - up) == sreoff) ? "*" : "", buf);
373
374 bp += 4;
375 len -= 4;
376 srelen -= 4;
377 }
378 return (1);
379 trunc:
380 return 0;
381 }
382
383 static int
384 gre_sre_asn_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
385 const u_char *bp, u_int len)
386 {
387 const u_char *up = bp;
388
389 if (sreoff & 1) {
390 ND_PRINT(", badoffset=%u", sreoff);
391 return (1);
392 }
393 if (srelen & 1) {
394 ND_PRINT(", badlength=%u", srelen);
395 return (1);
396 }
397 if (sreoff >= srelen) {
398 ND_PRINT(", badoff/len=%u/%u", sreoff, srelen);
399 return (1);
400 }
401
402 while (srelen != 0) {
403 ND_TCHECK_2(bp);
404 if (len < 2)
405 return (0);
406
407 ND_PRINT(" %s%x",
408 ((bp - up) == sreoff) ? "*" : "", GET_BE_U_2(bp));
409
410 bp += 2;
411 len -= 2;
412 srelen -= 2;
413 }
414 return (1);
415 trunc:
416 return 0;
417 }