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