xref: /minix3/external/bsd/tcpdump/dist/print-ahcp.c (revision b636d99d91c3d54204248f643c14627405d4afd1)
1*b636d99dSDavid van Moolenbroek /*
2*b636d99dSDavid van Moolenbroek  * This module implements decoding of AHCP (Ad Hoc Configuration Protocol) based
3*b636d99dSDavid van Moolenbroek  * on draft-chroboczek-ahcp-00 and source code of ahcpd-0.53.
4*b636d99dSDavid van Moolenbroek  *
5*b636d99dSDavid van Moolenbroek  *
6*b636d99dSDavid van Moolenbroek  * Copyright (c) 2013 The TCPDUMP project
7*b636d99dSDavid van Moolenbroek  * All rights reserved.
8*b636d99dSDavid van Moolenbroek  *
9*b636d99dSDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
10*b636d99dSDavid van Moolenbroek  * modification, are permitted provided that the following conditions
11*b636d99dSDavid van Moolenbroek  * are met:
12*b636d99dSDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
13*b636d99dSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
14*b636d99dSDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
15*b636d99dSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
16*b636d99dSDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
17*b636d99dSDavid van Moolenbroek  *
18*b636d99dSDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19*b636d99dSDavid van Moolenbroek  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20*b636d99dSDavid van Moolenbroek  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21*b636d99dSDavid van Moolenbroek  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22*b636d99dSDavid van Moolenbroek  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23*b636d99dSDavid van Moolenbroek  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24*b636d99dSDavid van Moolenbroek  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25*b636d99dSDavid van Moolenbroek  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26*b636d99dSDavid van Moolenbroek  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*b636d99dSDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28*b636d99dSDavid van Moolenbroek  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*b636d99dSDavid van Moolenbroek  * POSSIBILITY OF SUCH DAMAGE.
30*b636d99dSDavid van Moolenbroek  */
31*b636d99dSDavid van Moolenbroek 
32*b636d99dSDavid van Moolenbroek #include <sys/cdefs.h>
33*b636d99dSDavid van Moolenbroek #ifndef lint
34*b636d99dSDavid van Moolenbroek __RCSID("$NetBSD: print-ahcp.c,v 1.3 2015/03/31 21:59:35 christos Exp $");
35*b636d99dSDavid van Moolenbroek #endif
36*b636d99dSDavid van Moolenbroek 
37*b636d99dSDavid van Moolenbroek #define NETDISSECT_REWORKED
38*b636d99dSDavid van Moolenbroek #ifdef HAVE_CONFIG_H
39*b636d99dSDavid van Moolenbroek #include "config.h"
40*b636d99dSDavid van Moolenbroek #endif
41*b636d99dSDavid van Moolenbroek 
42*b636d99dSDavid van Moolenbroek #include <tcpdump-stdinc.h>
43*b636d99dSDavid van Moolenbroek 
44*b636d99dSDavid van Moolenbroek #include "interface.h"
45*b636d99dSDavid van Moolenbroek #include "extract.h"
46*b636d99dSDavid van Moolenbroek #include "addrtoname.h"
47*b636d99dSDavid van Moolenbroek 
48*b636d99dSDavid van Moolenbroek static const char tstr[] = " [|ahcp]";
49*b636d99dSDavid van Moolenbroek static const char cstr[] = "(corrupt)";
50*b636d99dSDavid van Moolenbroek 
51*b636d99dSDavid van Moolenbroek #define AHCP_MAGIC_NUMBER 43
52*b636d99dSDavid van Moolenbroek #define AHCP_VERSION_1 1
53*b636d99dSDavid van Moolenbroek #define AHCP1_HEADER_FIX_LEN 24
54*b636d99dSDavid van Moolenbroek #define AHCP1_BODY_MIN_LEN 4
55*b636d99dSDavid van Moolenbroek 
56*b636d99dSDavid van Moolenbroek #define AHCP1_MSG_DISCOVER 0
57*b636d99dSDavid van Moolenbroek #define AHCP1_MSG_OFFER    1
58*b636d99dSDavid van Moolenbroek #define AHCP1_MSG_REQUEST  2
59*b636d99dSDavid van Moolenbroek #define AHCP1_MSG_ACK      3
60*b636d99dSDavid van Moolenbroek #define AHCP1_MSG_NACK     4
61*b636d99dSDavid van Moolenbroek #define AHCP1_MSG_RELEASE  5
62*b636d99dSDavid van Moolenbroek 
63*b636d99dSDavid van Moolenbroek static const struct tok ahcp1_msg_str[] = {
64*b636d99dSDavid van Moolenbroek 	{ AHCP1_MSG_DISCOVER, "Discover" },
65*b636d99dSDavid van Moolenbroek 	{ AHCP1_MSG_OFFER,    "Offer"    },
66*b636d99dSDavid van Moolenbroek 	{ AHCP1_MSG_REQUEST,  "Request"  },
67*b636d99dSDavid van Moolenbroek 	{ AHCP1_MSG_ACK,      "Ack"      },
68*b636d99dSDavid van Moolenbroek 	{ AHCP1_MSG_NACK,     "Nack"     },
69*b636d99dSDavid van Moolenbroek 	{ AHCP1_MSG_RELEASE,  "Release"  },
70*b636d99dSDavid van Moolenbroek 	{ 0, NULL }
71*b636d99dSDavid van Moolenbroek };
72*b636d99dSDavid van Moolenbroek 
73*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_PAD                     0
74*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_MANDATORY               1
75*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_ORIGIN_TIME             2
76*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_EXPIRES                 3
77*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_MY_IPV6_ADDRESS         4
78*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_MY_IPV4_ADDRESS         5
79*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_IPV6_PREFIX             6
80*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_IPV4_PREFIX             7
81*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_IPV6_ADDRESS            8
82*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_IPV4_ADDRESS            9
83*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_IPV6_PREFIX_DELEGATION 10
84*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_IPV4_PREFIX_DELEGATION 11
85*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_NAME_SERVER            12
86*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_NTP_SERVER             13
87*b636d99dSDavid van Moolenbroek #define AHCP1_OPT_MAX                    13
88*b636d99dSDavid van Moolenbroek 
89*b636d99dSDavid van Moolenbroek static const struct tok ahcp1_opt_str[] = {
90*b636d99dSDavid van Moolenbroek 	{ AHCP1_OPT_PAD,                    "Pad"                    },
91*b636d99dSDavid van Moolenbroek 	{ AHCP1_OPT_MANDATORY,              "Mandatory"              },
92*b636d99dSDavid van Moolenbroek 	{ AHCP1_OPT_ORIGIN_TIME,            "Origin Time"            },
93*b636d99dSDavid van Moolenbroek 	{ AHCP1_OPT_EXPIRES,                "Expires"                },
94*b636d99dSDavid van Moolenbroek 	{ AHCP1_OPT_MY_IPV6_ADDRESS,        "My-IPv6-Address"        },
95*b636d99dSDavid van Moolenbroek 	{ AHCP1_OPT_MY_IPV4_ADDRESS,        "My-IPv4-Address"        },
96*b636d99dSDavid van Moolenbroek 	{ AHCP1_OPT_IPV6_PREFIX,            "IPv6 Prefix"            },
97*b636d99dSDavid van Moolenbroek 	{ AHCP1_OPT_IPV4_PREFIX,            "IPv4 Prefix"            },
98*b636d99dSDavid van Moolenbroek 	{ AHCP1_OPT_IPV6_ADDRESS,           "IPv6 Address"           },
99*b636d99dSDavid van Moolenbroek 	{ AHCP1_OPT_IPV4_ADDRESS,           "IPv4 Address"           },
100*b636d99dSDavid van Moolenbroek 	{ AHCP1_OPT_IPV6_PREFIX_DELEGATION, "IPv6 Prefix Delegation" },
101*b636d99dSDavid van Moolenbroek 	{ AHCP1_OPT_IPV4_PREFIX_DELEGATION, "IPv4 Prefix Delegation" },
102*b636d99dSDavid van Moolenbroek 	{ AHCP1_OPT_NAME_SERVER,            "Name Server"            },
103*b636d99dSDavid van Moolenbroek 	{ AHCP1_OPT_NTP_SERVER,             "NTP Server"             },
104*b636d99dSDavid van Moolenbroek 	{ 0, NULL }
105*b636d99dSDavid van Moolenbroek };
106*b636d99dSDavid van Moolenbroek 
107*b636d99dSDavid van Moolenbroek static int
ahcp_time_print(netdissect_options * ndo,const u_char * cp,const u_char * ep)108*b636d99dSDavid van Moolenbroek ahcp_time_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
109*b636d99dSDavid van Moolenbroek {
110*b636d99dSDavid van Moolenbroek 	time_t t;
111*b636d99dSDavid van Moolenbroek 	struct tm *tm;
112*b636d99dSDavid van Moolenbroek 	char buf[BUFSIZE];
113*b636d99dSDavid van Moolenbroek 
114*b636d99dSDavid van Moolenbroek 	if (cp + 4 != ep)
115*b636d99dSDavid van Moolenbroek 		goto corrupt;
116*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 4);
117*b636d99dSDavid van Moolenbroek 	t = EXTRACT_32BITS(cp);
118*b636d99dSDavid van Moolenbroek 	if (NULL == (tm = gmtime(&t)))
119*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, ": gmtime() error"));
120*b636d99dSDavid van Moolenbroek 	else if (0 == strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm))
121*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, ": strftime() error"));
122*b636d99dSDavid van Moolenbroek 	else
123*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, ": %s UTC", buf));
124*b636d99dSDavid van Moolenbroek 	return 0;
125*b636d99dSDavid van Moolenbroek 
126*b636d99dSDavid van Moolenbroek corrupt:
127*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ": %s", cstr));
128*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
129*b636d99dSDavid van Moolenbroek 	return 0;
130*b636d99dSDavid van Moolenbroek trunc:
131*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
132*b636d99dSDavid van Moolenbroek 	return -1;
133*b636d99dSDavid van Moolenbroek }
134*b636d99dSDavid van Moolenbroek 
135*b636d99dSDavid van Moolenbroek static int
ahcp_seconds_print(netdissect_options * ndo,const u_char * cp,const u_char * ep)136*b636d99dSDavid van Moolenbroek ahcp_seconds_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
137*b636d99dSDavid van Moolenbroek {
138*b636d99dSDavid van Moolenbroek 	if (cp + 4 != ep)
139*b636d99dSDavid van Moolenbroek 		goto corrupt;
140*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 4);
141*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ": %us", EXTRACT_32BITS(cp)));
142*b636d99dSDavid van Moolenbroek 	return 0;
143*b636d99dSDavid van Moolenbroek 
144*b636d99dSDavid van Moolenbroek corrupt:
145*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ": %s", cstr));
146*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
147*b636d99dSDavid van Moolenbroek 	return 0;
148*b636d99dSDavid van Moolenbroek trunc:
149*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
150*b636d99dSDavid van Moolenbroek 	return -1;
151*b636d99dSDavid van Moolenbroek }
152*b636d99dSDavid van Moolenbroek 
153*b636d99dSDavid van Moolenbroek static int
ahcp_ipv6_addresses_print(netdissect_options * ndo,const u_char * cp,const u_char * ep)154*b636d99dSDavid van Moolenbroek ahcp_ipv6_addresses_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
155*b636d99dSDavid van Moolenbroek {
156*b636d99dSDavid van Moolenbroek 	const char *sep = ": ";
157*b636d99dSDavid van Moolenbroek 
158*b636d99dSDavid van Moolenbroek 	while (cp < ep) {
159*b636d99dSDavid van Moolenbroek 		if (cp + 16 > ep)
160*b636d99dSDavid van Moolenbroek 			goto corrupt;
161*b636d99dSDavid van Moolenbroek 		ND_TCHECK2(*cp, 16);
162*b636d99dSDavid van Moolenbroek #ifdef INET6
163*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "%s%s", sep, ip6addr_string(ndo, cp)));
164*b636d99dSDavid van Moolenbroek #else
165*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "%s(compiled w/o IPv6)", sep));
166*b636d99dSDavid van Moolenbroek #endif /* INET6 */
167*b636d99dSDavid van Moolenbroek 		cp += 16;
168*b636d99dSDavid van Moolenbroek 		sep = ", ";
169*b636d99dSDavid van Moolenbroek 	}
170*b636d99dSDavid van Moolenbroek 	return 0;
171*b636d99dSDavid van Moolenbroek 
172*b636d99dSDavid van Moolenbroek corrupt:
173*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ": %s", cstr));
174*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
175*b636d99dSDavid van Moolenbroek 	return 0;
176*b636d99dSDavid van Moolenbroek trunc:
177*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
178*b636d99dSDavid van Moolenbroek 	return -1;
179*b636d99dSDavid van Moolenbroek }
180*b636d99dSDavid van Moolenbroek 
181*b636d99dSDavid van Moolenbroek static int
ahcp_ipv4_addresses_print(netdissect_options * ndo,const u_char * cp,const u_char * ep)182*b636d99dSDavid van Moolenbroek ahcp_ipv4_addresses_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
183*b636d99dSDavid van Moolenbroek {
184*b636d99dSDavid van Moolenbroek 	const char *sep = ": ";
185*b636d99dSDavid van Moolenbroek 
186*b636d99dSDavid van Moolenbroek 	while (cp < ep) {
187*b636d99dSDavid van Moolenbroek 		if (cp + 4 > ep)
188*b636d99dSDavid van Moolenbroek 			goto corrupt;
189*b636d99dSDavid van Moolenbroek 		ND_TCHECK2(*cp, 4);
190*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "%s%s", sep, ipaddr_string(ndo, cp)));
191*b636d99dSDavid van Moolenbroek 		cp += 4;
192*b636d99dSDavid van Moolenbroek 		sep = ", ";
193*b636d99dSDavid van Moolenbroek 	}
194*b636d99dSDavid van Moolenbroek 	return 0;
195*b636d99dSDavid van Moolenbroek 
196*b636d99dSDavid van Moolenbroek corrupt:
197*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ": %s", cstr));
198*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
199*b636d99dSDavid van Moolenbroek 	return 0;
200*b636d99dSDavid van Moolenbroek trunc:
201*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
202*b636d99dSDavid van Moolenbroek 	return -1;
203*b636d99dSDavid van Moolenbroek }
204*b636d99dSDavid van Moolenbroek 
205*b636d99dSDavid van Moolenbroek static int
ahcp_ipv6_prefixes_print(netdissect_options * ndo,const u_char * cp,const u_char * ep)206*b636d99dSDavid van Moolenbroek ahcp_ipv6_prefixes_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
207*b636d99dSDavid van Moolenbroek {
208*b636d99dSDavid van Moolenbroek 	const char *sep = ": ";
209*b636d99dSDavid van Moolenbroek 
210*b636d99dSDavid van Moolenbroek 	while (cp < ep) {
211*b636d99dSDavid van Moolenbroek 		if (cp + 17 > ep)
212*b636d99dSDavid van Moolenbroek 			goto corrupt;
213*b636d99dSDavid van Moolenbroek 		ND_TCHECK2(*cp, 17);
214*b636d99dSDavid van Moolenbroek #ifdef INET6
215*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "%s%s/%u", sep, ip6addr_string(ndo, cp), *(cp + 16)));
216*b636d99dSDavid van Moolenbroek #else
217*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "%s(compiled w/o IPv6)/%u", sep, *(cp + 16)));
218*b636d99dSDavid van Moolenbroek #endif /* INET6 */
219*b636d99dSDavid van Moolenbroek 		cp += 17;
220*b636d99dSDavid van Moolenbroek 		sep = ", ";
221*b636d99dSDavid van Moolenbroek 	}
222*b636d99dSDavid van Moolenbroek 	return 0;
223*b636d99dSDavid van Moolenbroek 
224*b636d99dSDavid van Moolenbroek corrupt:
225*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ": %s", cstr));
226*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
227*b636d99dSDavid van Moolenbroek 	return 0;
228*b636d99dSDavid van Moolenbroek trunc:
229*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
230*b636d99dSDavid van Moolenbroek 	return -1;
231*b636d99dSDavid van Moolenbroek }
232*b636d99dSDavid van Moolenbroek 
233*b636d99dSDavid van Moolenbroek static int
ahcp_ipv4_prefixes_print(netdissect_options * ndo,const u_char * cp,const u_char * ep)234*b636d99dSDavid van Moolenbroek ahcp_ipv4_prefixes_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
235*b636d99dSDavid van Moolenbroek {
236*b636d99dSDavid van Moolenbroek 	const char *sep = ": ";
237*b636d99dSDavid van Moolenbroek 
238*b636d99dSDavid van Moolenbroek 	while (cp < ep) {
239*b636d99dSDavid van Moolenbroek 		if (cp + 5 > ep)
240*b636d99dSDavid van Moolenbroek 			goto corrupt;
241*b636d99dSDavid van Moolenbroek 		ND_TCHECK2(*cp, 5);
242*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "%s%s/%u", sep, ipaddr_string(ndo, cp), *(cp + 4)));
243*b636d99dSDavid van Moolenbroek 		cp += 5;
244*b636d99dSDavid van Moolenbroek 		sep = ", ";
245*b636d99dSDavid van Moolenbroek 	}
246*b636d99dSDavid van Moolenbroek 	return 0;
247*b636d99dSDavid van Moolenbroek 
248*b636d99dSDavid van Moolenbroek corrupt:
249*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, ": %s", cstr));
250*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
251*b636d99dSDavid van Moolenbroek 	return 0;
252*b636d99dSDavid van Moolenbroek trunc:
253*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
254*b636d99dSDavid van Moolenbroek 	return -1;
255*b636d99dSDavid van Moolenbroek }
256*b636d99dSDavid van Moolenbroek 
257*b636d99dSDavid van Moolenbroek /* Data decoders signal truncated data with -1. */
258*b636d99dSDavid van Moolenbroek static int
259*b636d99dSDavid van Moolenbroek (* const data_decoders[AHCP1_OPT_MAX + 1])(netdissect_options *, const u_char *, const u_char *) = {
260*b636d99dSDavid van Moolenbroek 	/* [AHCP1_OPT_PAD]                    = */  NULL,
261*b636d99dSDavid van Moolenbroek 	/* [AHCP1_OPT_MANDATORY]              = */  NULL,
262*b636d99dSDavid van Moolenbroek 	/* [AHCP1_OPT_ORIGIN_TIME]            = */  ahcp_time_print,
263*b636d99dSDavid van Moolenbroek 	/* [AHCP1_OPT_EXPIRES]                = */  ahcp_seconds_print,
264*b636d99dSDavid van Moolenbroek 	/* [AHCP1_OPT_MY_IPV6_ADDRESS]        = */  ahcp_ipv6_addresses_print,
265*b636d99dSDavid van Moolenbroek 	/* [AHCP1_OPT_MY_IPV4_ADDRESS]        = */  ahcp_ipv4_addresses_print,
266*b636d99dSDavid van Moolenbroek 	/* [AHCP1_OPT_IPV6_PREFIX]            = */  ahcp_ipv6_prefixes_print,
267*b636d99dSDavid van Moolenbroek 	/* [AHCP1_OPT_IPV4_PREFIX]            = */  NULL,
268*b636d99dSDavid van Moolenbroek 	/* [AHCP1_OPT_IPV6_ADDRESS]           = */  ahcp_ipv6_addresses_print,
269*b636d99dSDavid van Moolenbroek 	/* [AHCP1_OPT_IPV4_ADDRESS]           = */  ahcp_ipv4_addresses_print,
270*b636d99dSDavid van Moolenbroek 	/* [AHCP1_OPT_IPV6_PREFIX_DELEGATION] = */  ahcp_ipv6_prefixes_print,
271*b636d99dSDavid van Moolenbroek 	/* [AHCP1_OPT_IPV4_PREFIX_DELEGATION] = */  ahcp_ipv4_prefixes_print,
272*b636d99dSDavid van Moolenbroek 	/* [AHCP1_OPT_NAME_SERVER]            = */  ahcp_ipv6_addresses_print,
273*b636d99dSDavid van Moolenbroek 	/* [AHCP1_OPT_NTP_SERVER]             = */  ahcp_ipv6_addresses_print,
274*b636d99dSDavid van Moolenbroek };
275*b636d99dSDavid van Moolenbroek 
276*b636d99dSDavid van Moolenbroek static void
ahcp1_options_print(netdissect_options * ndo,const u_char * cp,const u_char * ep)277*b636d99dSDavid van Moolenbroek ahcp1_options_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
278*b636d99dSDavid van Moolenbroek {
279*b636d99dSDavid van Moolenbroek 	uint8_t option_no, option_len;
280*b636d99dSDavid van Moolenbroek 
281*b636d99dSDavid van Moolenbroek 	while (cp < ep) {
282*b636d99dSDavid van Moolenbroek 		/* Option no */
283*b636d99dSDavid van Moolenbroek 		ND_TCHECK2(*cp, 1);
284*b636d99dSDavid van Moolenbroek 		option_no = *cp;
285*b636d99dSDavid van Moolenbroek 		cp += 1;
286*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "\n\t %s", tok2str(ahcp1_opt_str, "Unknown-%u", option_no)));
287*b636d99dSDavid van Moolenbroek 		if (option_no == AHCP1_OPT_PAD || option_no == AHCP1_OPT_MANDATORY)
288*b636d99dSDavid van Moolenbroek 			continue;
289*b636d99dSDavid van Moolenbroek 		/* Length */
290*b636d99dSDavid van Moolenbroek 		if (cp + 1 > ep)
291*b636d99dSDavid van Moolenbroek 			goto corrupt;
292*b636d99dSDavid van Moolenbroek 		ND_TCHECK2(*cp, 1);
293*b636d99dSDavid van Moolenbroek 		option_len = *cp;
294*b636d99dSDavid van Moolenbroek 		cp += 1;
295*b636d99dSDavid van Moolenbroek 		if (cp + option_len > ep)
296*b636d99dSDavid van Moolenbroek 			goto corrupt;
297*b636d99dSDavid van Moolenbroek 		/* Value */
298*b636d99dSDavid van Moolenbroek 		if (option_no <= AHCP1_OPT_MAX && data_decoders[option_no] != NULL) {
299*b636d99dSDavid van Moolenbroek 			if (data_decoders[option_no](ndo, cp, cp + option_len) < 0)
300*b636d99dSDavid van Moolenbroek 				break; /* truncated and already marked up */
301*b636d99dSDavid van Moolenbroek 		} else {
302*b636d99dSDavid van Moolenbroek 			ND_PRINT((ndo, " (Length %u)", option_len));
303*b636d99dSDavid van Moolenbroek 			ND_TCHECK2(*cp, option_len);
304*b636d99dSDavid van Moolenbroek 		}
305*b636d99dSDavid van Moolenbroek 		cp += option_len;
306*b636d99dSDavid van Moolenbroek 	}
307*b636d99dSDavid van Moolenbroek 	return;
308*b636d99dSDavid van Moolenbroek 
309*b636d99dSDavid van Moolenbroek corrupt:
310*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, " %s", cstr));
311*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
312*b636d99dSDavid van Moolenbroek 	return;
313*b636d99dSDavid van Moolenbroek trunc:
314*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
315*b636d99dSDavid van Moolenbroek }
316*b636d99dSDavid van Moolenbroek 
317*b636d99dSDavid van Moolenbroek static void
ahcp1_body_print(netdissect_options * ndo,const u_char * cp,const u_char * ep)318*b636d99dSDavid van Moolenbroek ahcp1_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
319*b636d99dSDavid van Moolenbroek {
320*b636d99dSDavid van Moolenbroek 	uint8_t type, mbz;
321*b636d99dSDavid van Moolenbroek 	uint16_t body_len;
322*b636d99dSDavid van Moolenbroek 
323*b636d99dSDavid van Moolenbroek 	if (cp + AHCP1_BODY_MIN_LEN > ep)
324*b636d99dSDavid van Moolenbroek 		goto corrupt;
325*b636d99dSDavid van Moolenbroek 	/* Type */
326*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
327*b636d99dSDavid van Moolenbroek 	type = *cp;
328*b636d99dSDavid van Moolenbroek 	cp += 1;
329*b636d99dSDavid van Moolenbroek 	/* MBZ */
330*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
331*b636d99dSDavid van Moolenbroek 	mbz = *cp;
332*b636d99dSDavid van Moolenbroek 	cp += 1;
333*b636d99dSDavid van Moolenbroek 	/* Length */
334*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 2);
335*b636d99dSDavid van Moolenbroek 	body_len = EXTRACT_16BITS(cp);
336*b636d99dSDavid van Moolenbroek 	cp += 2;
337*b636d99dSDavid van Moolenbroek 
338*b636d99dSDavid van Moolenbroek 	if (ndo->ndo_vflag) {
339*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "\n\t%s", tok2str(ahcp1_msg_str, "Unknown-%u", type)));
340*b636d99dSDavid van Moolenbroek 		if (mbz != 0)
341*b636d99dSDavid van Moolenbroek 			ND_PRINT((ndo, ", MBZ %u", mbz));
342*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, ", Length %u", body_len));
343*b636d99dSDavid van Moolenbroek 	}
344*b636d99dSDavid van Moolenbroek 	if (cp + body_len > ep)
345*b636d99dSDavid van Moolenbroek 		goto corrupt;
346*b636d99dSDavid van Moolenbroek 
347*b636d99dSDavid van Moolenbroek 	/* Options */
348*b636d99dSDavid van Moolenbroek 	if (ndo->ndo_vflag >= 2)
349*b636d99dSDavid van Moolenbroek 		ahcp1_options_print(ndo, cp, cp + body_len); /* not ep (ignore extra data) */
350*b636d99dSDavid van Moolenbroek 	else
351*b636d99dSDavid van Moolenbroek 		ND_TCHECK2(*cp, body_len);
352*b636d99dSDavid van Moolenbroek 	return;
353*b636d99dSDavid van Moolenbroek 
354*b636d99dSDavid van Moolenbroek corrupt:
355*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, " %s", cstr));
356*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
357*b636d99dSDavid van Moolenbroek 	return;
358*b636d99dSDavid van Moolenbroek trunc:
359*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
360*b636d99dSDavid van Moolenbroek }
361*b636d99dSDavid van Moolenbroek 
362*b636d99dSDavid van Moolenbroek void
ahcp_print(netdissect_options * ndo,const u_char * cp,const u_int len)363*b636d99dSDavid van Moolenbroek ahcp_print(netdissect_options *ndo, const u_char *cp, const u_int len)
364*b636d99dSDavid van Moolenbroek {
365*b636d99dSDavid van Moolenbroek 	const u_char *ep = cp + len;
366*b636d99dSDavid van Moolenbroek 	uint8_t version;
367*b636d99dSDavid van Moolenbroek 
368*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "AHCP"));
369*b636d99dSDavid van Moolenbroek 	if (len < 2)
370*b636d99dSDavid van Moolenbroek 		goto corrupt;
371*b636d99dSDavid van Moolenbroek 	/* Magic */
372*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
373*b636d99dSDavid van Moolenbroek 	if (*cp != AHCP_MAGIC_NUMBER)
374*b636d99dSDavid van Moolenbroek 		goto corrupt;
375*b636d99dSDavid van Moolenbroek 	cp += 1;
376*b636d99dSDavid van Moolenbroek 	/* Version */
377*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, 1);
378*b636d99dSDavid van Moolenbroek 	version = *cp;
379*b636d99dSDavid van Moolenbroek 	cp += 1;
380*b636d99dSDavid van Moolenbroek 	switch (version) {
381*b636d99dSDavid van Moolenbroek 		case AHCP_VERSION_1: {
382*b636d99dSDavid van Moolenbroek 			ND_PRINT((ndo, " Version 1"));
383*b636d99dSDavid van Moolenbroek 			if (len < AHCP1_HEADER_FIX_LEN)
384*b636d99dSDavid van Moolenbroek 				goto corrupt;
385*b636d99dSDavid van Moolenbroek 			if (!ndo->ndo_vflag) {
386*b636d99dSDavid van Moolenbroek 				ND_TCHECK2(*cp, AHCP1_HEADER_FIX_LEN - 2);
387*b636d99dSDavid van Moolenbroek 				cp += AHCP1_HEADER_FIX_LEN - 2;
388*b636d99dSDavid van Moolenbroek 			} else {
389*b636d99dSDavid van Moolenbroek 				/* Hopcount */
390*b636d99dSDavid van Moolenbroek 				ND_TCHECK2(*cp, 1);
391*b636d99dSDavid van Moolenbroek 				ND_PRINT((ndo, "\n\tHopcount %u", *cp));
392*b636d99dSDavid van Moolenbroek 				cp += 1;
393*b636d99dSDavid van Moolenbroek 				/* Original Hopcount */
394*b636d99dSDavid van Moolenbroek 				ND_TCHECK2(*cp, 1);
395*b636d99dSDavid van Moolenbroek 				ND_PRINT((ndo, ", Original Hopcount %u", *cp));
396*b636d99dSDavid van Moolenbroek 				cp += 1;
397*b636d99dSDavid van Moolenbroek 				/* Nonce */
398*b636d99dSDavid van Moolenbroek 				ND_TCHECK2(*cp, 4);
399*b636d99dSDavid van Moolenbroek 				ND_PRINT((ndo, ", Nonce 0x%08x", EXTRACT_32BITS(cp)));
400*b636d99dSDavid van Moolenbroek 				cp += 4;
401*b636d99dSDavid van Moolenbroek 				/* Source Id */
402*b636d99dSDavid van Moolenbroek 				ND_TCHECK2(*cp, 8);
403*b636d99dSDavid van Moolenbroek 				ND_PRINT((ndo, ", Source Id %s", linkaddr_string(ndo, cp, 0, 8)));
404*b636d99dSDavid van Moolenbroek 				cp += 8;
405*b636d99dSDavid van Moolenbroek 				/* Destination Id */
406*b636d99dSDavid van Moolenbroek 				ND_TCHECK2(*cp, 8);
407*b636d99dSDavid van Moolenbroek 				ND_PRINT((ndo, ", Destination Id %s", linkaddr_string(ndo, cp, 0, 8)));
408*b636d99dSDavid van Moolenbroek 				cp += 8;
409*b636d99dSDavid van Moolenbroek 			}
410*b636d99dSDavid van Moolenbroek 			/* Body */
411*b636d99dSDavid van Moolenbroek 			ahcp1_body_print(ndo, cp, ep);
412*b636d99dSDavid van Moolenbroek 			break;
413*b636d99dSDavid van Moolenbroek 		}
414*b636d99dSDavid van Moolenbroek 		default:
415*b636d99dSDavid van Moolenbroek 			ND_PRINT((ndo, " Version %u (unknown)", version));
416*b636d99dSDavid van Moolenbroek 			break;
417*b636d99dSDavid van Moolenbroek 	}
418*b636d99dSDavid van Moolenbroek 	return;
419*b636d99dSDavid van Moolenbroek 
420*b636d99dSDavid van Moolenbroek corrupt:
421*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, " %s", cstr));
422*b636d99dSDavid van Moolenbroek 	ND_TCHECK2(*cp, ep - cp);
423*b636d99dSDavid van Moolenbroek 	return;
424*b636d99dSDavid van Moolenbroek trunc:
425*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s", tstr));
426*b636d99dSDavid van Moolenbroek }
427