Import tcpdump-4.3.0.
[dragonfly.git] / contrib / tcpdump / print-ip6opts.c
1 /*
2  * Copyright (C) 1998 WIDE Project.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the project nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #ifndef lint
35 static const char rcsid[] _U_ =
36      "@(#) $Header: /tcpdump/master/tcpdump/print-ip6opts.c,v 1.18 2005-04-20 22:18:50 guy Exp $";
37 #endif
38
39 #ifdef INET6
40 #include <tcpdump-stdinc.h>
41
42 #include <stdio.h>
43
44 #include "ip6.h"
45
46 #include "interface.h"
47 #include "addrtoname.h"
48 #include "extract.h"
49
50 /* items outside of rfc2292bis */
51 #ifndef IP6OPT_MINLEN
52 #define IP6OPT_MINLEN   2
53 #endif
54 #ifndef IP6OPT_RTALERT_LEN
55 #define IP6OPT_RTALERT_LEN      4
56 #endif
57 #ifndef IP6OPT_JUMBO_LEN
58 #define IP6OPT_JUMBO_LEN        6
59 #endif
60 #define IP6OPT_HOMEADDR_MINLEN 18
61 #define IP6OPT_BU_MINLEN       10
62 #define IP6OPT_BA_MINLEN       13
63 #define IP6OPT_BR_MINLEN        2
64 #define IP6SOPT_UI            0x2
65 #define IP6SOPT_UI_MINLEN       4
66 #define IP6SOPT_ALTCOA        0x3
67 #define IP6SOPT_ALTCOA_MINLEN  18
68 #define IP6SOPT_AUTH          0x4
69 #define IP6SOPT_AUTH_MINLEN     6
70
71 static void ip6_sopt_print(const u_char *, int);
72
73 static void
74 ip6_sopt_print(const u_char *bp, int len)
75 {
76     int i;
77     int optlen;
78
79     for (i = 0; i < len; i += optlen) {
80         if (bp[i] == IP6OPT_PAD1)
81             optlen = 1;
82         else {
83             if (i + 1 < len)
84                 optlen = bp[i + 1] + 2;
85             else
86                 goto trunc;
87         }
88         if (i + optlen > len)
89             goto trunc;
90
91         switch (bp[i]) {
92         case IP6OPT_PAD1:
93             printf(", pad1");
94             break;
95         case IP6OPT_PADN:
96             if (len - i < IP6OPT_MINLEN) {
97                 printf(", padn: trunc");
98                 goto trunc;
99             }
100             printf(", padn");
101             break;
102         case IP6SOPT_UI:
103              if (len - i < IP6SOPT_UI_MINLEN) {
104                 printf(", ui: trunc");
105                 goto trunc;
106             }
107             printf(", ui: 0x%04x ", EXTRACT_16BITS(&bp[i + 2]));
108             break;
109         case IP6SOPT_ALTCOA:
110              if (len - i < IP6SOPT_ALTCOA_MINLEN) {
111                 printf(", altcoa: trunc");
112                 goto trunc;
113             }
114             printf(", alt-CoA: %s", ip6addr_string(&bp[i+2]));
115             break;
116         case IP6SOPT_AUTH:
117              if (len - i < IP6SOPT_AUTH_MINLEN) {
118                 printf(", auth: trunc");
119                 goto trunc;
120             }
121             printf(", auth spi: 0x%08x", EXTRACT_32BITS(&bp[i + 2]));
122             break;
123         default:
124             if (len - i < IP6OPT_MINLEN) {
125                 printf(", sopt_type %d: trunc)", bp[i]);
126                 goto trunc;
127             }
128             printf(", sopt_type 0x%02x: len=%d", bp[i], bp[i + 1]);
129             break;
130         }
131     }
132     return;
133
134 trunc:
135     printf("[trunc] ");
136 }
137
138 void
139 ip6_opt_print(const u_char *bp, int len)
140 {
141     int i;
142     int optlen = 0;
143
144     if (len == 0)
145         return;
146     for (i = 0; i < len; i += optlen) {
147         if (bp[i] == IP6OPT_PAD1)
148             optlen = 1;
149         else {
150             if (i + 1 < len)
151                 optlen = bp[i + 1] + 2;
152             else
153                 goto trunc;
154         }
155         if (i + optlen > len)
156             goto trunc;
157
158         switch (bp[i]) {
159         case IP6OPT_PAD1:
160             printf("(pad1)");
161             break;
162         case IP6OPT_PADN:
163             if (len - i < IP6OPT_MINLEN) {
164                 printf("(padn: trunc)");
165                 goto trunc;
166             }
167             printf("(padn)");
168             break;
169         case IP6OPT_ROUTER_ALERT:
170             if (len - i < IP6OPT_RTALERT_LEN) {
171                 printf("(rtalert: trunc)");
172                 goto trunc;
173             }
174             if (bp[i + 1] != IP6OPT_RTALERT_LEN - 2) {
175                 printf("(rtalert: invalid len %d)", bp[i + 1]);
176                 goto trunc;
177             }
178             printf("(rtalert: 0x%04x) ", EXTRACT_16BITS(&bp[i + 2]));
179             break;
180         case IP6OPT_JUMBO:
181             if (len - i < IP6OPT_JUMBO_LEN) {
182                 printf("(jumbo: trunc)");
183                 goto trunc;
184             }
185             if (bp[i + 1] != IP6OPT_JUMBO_LEN - 2) {
186                 printf("(jumbo: invalid len %d)", bp[i + 1]);
187                 goto trunc;
188             }
189             printf("(jumbo: %u) ", EXTRACT_32BITS(&bp[i + 2]));
190             break;
191         case IP6OPT_HOME_ADDRESS:
192             if (len - i < IP6OPT_HOMEADDR_MINLEN) {
193                 printf("(homeaddr: trunc)");
194                 goto trunc;
195             }
196             if (bp[i + 1] < IP6OPT_HOMEADDR_MINLEN - 2) {
197                 printf("(homeaddr: invalid len %d)", bp[i + 1]);
198                 goto trunc;
199             }
200             printf("(homeaddr: %s", ip6addr_string(&bp[i + 2]));
201             if (bp[i + 1] > IP6OPT_HOMEADDR_MINLEN - 2) {
202                 ip6_sopt_print(&bp[i + IP6OPT_HOMEADDR_MINLEN],
203                     (optlen - IP6OPT_HOMEADDR_MINLEN));
204             }
205             printf(")");
206             break;
207         case IP6OPT_BINDING_UPDATE:
208             if (len - i < IP6OPT_BU_MINLEN) {
209                 printf("(bu: trunc)");
210                 goto trunc;
211             }
212             if (bp[i + 1] < IP6OPT_BU_MINLEN - 2) {
213                 printf("(bu: invalid len %d)", bp[i + 1]);
214                 goto trunc;
215             }
216             printf("(bu: ");
217             if (bp[i + 2] & 0x80)
218                     printf("A");
219             if (bp[i + 2] & 0x40)
220                     printf("H");
221             if (bp[i + 2] & 0x20)
222                     printf("S");
223             if (bp[i + 2] & 0x10)
224                     printf("D");
225             if ((bp[i + 2] & 0x0f) || bp[i + 3] || bp[i + 4])
226                     printf("res");
227             printf(", sequence: %u", bp[i + 5]);
228             printf(", lifetime: %u", EXTRACT_32BITS(&bp[i + 6]));
229
230             if (bp[i + 1] > IP6OPT_BU_MINLEN - 2) {
231                 ip6_sopt_print(&bp[i + IP6OPT_BU_MINLEN],
232                     (optlen - IP6OPT_BU_MINLEN));
233             }
234             printf(")");
235             break;
236         case IP6OPT_BINDING_ACK:
237             if (len - i < IP6OPT_BA_MINLEN) {
238                 printf("(ba: trunc)");
239                 goto trunc;
240             }
241             if (bp[i + 1] < IP6OPT_BA_MINLEN - 2) {
242                 printf("(ba: invalid len %d)", bp[i + 1]);
243                 goto trunc;
244             }
245             printf("(ba: ");
246             printf("status: %u", bp[i + 2]);
247             if (bp[i + 3])
248                     printf("res");
249             printf(", sequence: %u", bp[i + 4]);
250             printf(", lifetime: %u", EXTRACT_32BITS(&bp[i + 5]));
251             printf(", refresh: %u", EXTRACT_32BITS(&bp[i + 9]));
252
253             if (bp[i + 1] > IP6OPT_BA_MINLEN - 2) {
254                 ip6_sopt_print(&bp[i + IP6OPT_BA_MINLEN],
255                     (optlen - IP6OPT_BA_MINLEN));
256             }
257             printf(")");
258             break;
259         case IP6OPT_BINDING_REQ:
260             if (len - i < IP6OPT_BR_MINLEN) {
261                 printf("(br: trunc)");
262                 goto trunc;
263             }
264             printf("(br");
265             if (bp[i + 1] > IP6OPT_BR_MINLEN - 2) {
266                 ip6_sopt_print(&bp[i + IP6OPT_BR_MINLEN],
267                     (optlen - IP6OPT_BR_MINLEN));
268             }
269             printf(")");
270             break;
271         default:
272             if (len - i < IP6OPT_MINLEN) {
273                 printf("(type %d: trunc)", bp[i]);
274                 goto trunc;
275             }
276             printf("(opt_type 0x%02x: len=%d)", bp[i], bp[i + 1]);
277             break;
278         }
279     }
280     printf(" ");
281
282 #if 0
283 end:
284 #endif
285     return;
286
287 trunc:
288     printf("[trunc] ");
289 }
290
291 int
292 hbhopt_print(register const u_char *bp)
293 {
294     const struct ip6_hbh *dp = (struct ip6_hbh *)bp;
295     int hbhlen = 0;
296
297     TCHECK(dp->ip6h_len);
298     hbhlen = (int)((dp->ip6h_len + 1) << 3);
299     TCHECK2(*dp, hbhlen);
300     printf("HBH ");
301     if (vflag)
302         ip6_opt_print((const u_char *)dp + sizeof(*dp), hbhlen - sizeof(*dp));
303
304     return(hbhlen);
305
306   trunc:
307     fputs("[|HBH]", stdout);
308     return(-1);
309 }
310
311 int
312 dstopt_print(register const u_char *bp)
313 {
314     const struct ip6_dest *dp = (struct ip6_dest *)bp;
315     int dstoptlen = 0;
316
317     TCHECK(dp->ip6d_len);
318     dstoptlen = (int)((dp->ip6d_len + 1) << 3);
319     TCHECK2(*dp, dstoptlen);
320     printf("DSTOPT ");
321     if (vflag) {
322         ip6_opt_print((const u_char *)dp + sizeof(*dp),
323             dstoptlen - sizeof(*dp));
324     }
325
326     return(dstoptlen);
327
328   trunc:
329     fputs("[|DSTOPT]", stdout);
330     return(-1);
331 }
332 #endif /* INET6 */