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