Commit | Line | Data |
---|---|---|
c8cf0f94 PA |
1 | /* |
2 | * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 | |
3 | * The Regents of the University of California. All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that: (1) source code distributions | |
7 | * retain the above copyright notice and this paragraph in its entirety, (2) | |
8 | * distributions including binary code include the above copyright notice and | |
9 | * this paragraph in its entirety in the documentation or other materials | |
10 | * provided with the distribution, and (3) all advertising materials mentioning | |
11 | * features or use of this software display the following acknowledgement: | |
12 | * ``This product includes software developed by the University of California, | |
13 | * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of | |
14 | * the University nor the names of its contributors may be used to endorse | |
15 | * or promote products derived from this software without specific prior | |
16 | * written permission. | |
17 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED | |
18 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF | |
19 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
c8cf0f94 PA |
20 | */ |
21 | ||
411677ae | 22 | /* \summary: AppleTalk printer */ |
c8cf0f94 PA |
23 | |
24 | #ifdef HAVE_CONFIG_H | |
ed775ee7 | 25 | #include <config.h> |
c8cf0f94 PA |
26 | #endif |
27 | ||
ed775ee7 | 28 | #include "netdissect-stdinc.h" |
c8cf0f94 PA |
29 | |
30 | #include <stdio.h> | |
c8cf0f94 | 31 | #include <string.h> |
c8cf0f94 | 32 | |
411677ae | 33 | #include "netdissect.h" |
c8cf0f94 PA |
34 | #include "addrtoname.h" |
35 | #include "ethertype.h" | |
411677ae | 36 | #include "extract.h" |
c8cf0f94 PA |
37 | #include "appletalk.h" |
38 | ||
411677ae AL |
39 | |
40 | static const struct tok type2str[] = { | |
c8cf0f94 PA |
41 | { ddpRTMP, "rtmp" }, |
42 | { ddpRTMPrequest, "rtmpReq" }, | |
43 | { ddpECHO, "echo" }, | |
44 | { ddpIP, "IP" }, | |
45 | { ddpARP, "ARP" }, | |
46 | { ddpKLAP, "KLAP" }, | |
47 | { 0, NULL } | |
48 | }; | |
49 | ||
50 | struct aarp { | |
ed775ee7 AHJ |
51 | nd_uint16_t htype, ptype; |
52 | nd_uint8_t halen, palen; | |
53 | nd_uint16_t op; | |
54 | nd_mac_addr hsaddr; | |
411677ae | 55 | uint8_t psaddr[4]; |
ed775ee7 | 56 | nd_mac_addr hdaddr; |
411677ae | 57 | uint8_t pdaddr[4]; |
c8cf0f94 PA |
58 | }; |
59 | ||
411677ae AL |
60 | static void atp_print(netdissect_options *, const struct atATP *, u_int); |
61 | static void atp_bitmap_print(netdissect_options *, u_char); | |
62 | static void nbp_print(netdissect_options *, const struct atNBP *, u_int, u_short, u_char, u_char); | |
63 | static const struct atNBPtuple *nbp_tuple_print(netdissect_options *ndo, const struct atNBPtuple *, | |
c8cf0f94 PA |
64 | const u_char *, |
65 | u_short, u_char, u_char); | |
411677ae | 66 | static const struct atNBPtuple *nbp_name_print(netdissect_options *, const struct atNBPtuple *, |
c8cf0f94 | 67 | const u_char *); |
411677ae | 68 | static const char *ataddr_string(netdissect_options *, u_short, u_char); |
ed775ee7 AHJ |
69 | static void ddp_print(netdissect_options *, const u_char *, u_int, u_int, u_short, u_char, u_char); |
70 | static const char *ddpskt_string(netdissect_options *, u_int); | |
c8cf0f94 PA |
71 | |
72 | /* | |
73 | * Print LLAP packets received on a physical LocalTalk interface. | |
74 | */ | |
ed775ee7 | 75 | void |
411677ae AL |
76 | ltalk_if_print(netdissect_options *ndo, |
77 | const struct pcap_pkthdr *h, const u_char *p) | |
c8cf0f94 | 78 | { |
411677ae AL |
79 | u_int hdrlen; |
80 | ||
ed775ee7 | 81 | ndo->ndo_protocol = "ltalk"; |
411677ae AL |
82 | hdrlen = llap_print(ndo, p, h->len); |
83 | if (hdrlen == 0) { | |
84 | /* Cut short by the snapshot length. */ | |
ed775ee7 AHJ |
85 | ndo->ndo_ll_hdr_len += h->caplen; |
86 | return; | |
411677ae | 87 | } |
ed775ee7 | 88 | ndo->ndo_ll_hdr_len += hdrlen; |
c8cf0f94 PA |
89 | } |
90 | ||
91 | /* | |
92 | * Print AppleTalk LLAP packets. | |
93 | */ | |
94 | u_int | |
411677ae | 95 | llap_print(netdissect_options *ndo, |
ed775ee7 | 96 | const u_char *bp, u_int length) |
c8cf0f94 | 97 | { |
ed775ee7 AHJ |
98 | const struct LAP *lp; |
99 | const struct atDDP *dp; | |
100 | const struct atShortDDP *sdp; | |
c8cf0f94 PA |
101 | u_short snet; |
102 | u_int hdrlen; | |
103 | ||
ed775ee7 | 104 | ndo->ndo_protocol = "llap"; |
27bfbee1 | 105 | if (length < sizeof(*lp)) { |
ed775ee7 | 106 | ND_PRINT(" [|llap %u]", length); |
27bfbee1 PA |
107 | return (length); |
108 | } | |
ed775ee7 AHJ |
109 | if (!ND_TTEST_LEN(bp, sizeof(*lp))) { |
110 | nd_print_trunc(ndo); | |
411677ae AL |
111 | return (0); /* cut short by the snapshot length */ |
112 | } | |
c8cf0f94 PA |
113 | lp = (const struct LAP *)bp; |
114 | bp += sizeof(*lp); | |
115 | length -= sizeof(*lp); | |
116 | hdrlen = sizeof(*lp); | |
ed775ee7 | 117 | switch (GET_U_1(lp->type)) { |
c8cf0f94 PA |
118 | |
119 | case lapShortDDP: | |
120 | if (length < ddpSSize) { | |
ed775ee7 | 121 | ND_PRINT(" [|sddp %u]", length); |
c8cf0f94 PA |
122 | return (length); |
123 | } | |
ed775ee7 AHJ |
124 | if (!ND_TTEST_LEN(bp, ddpSSize)) { |
125 | ND_PRINT(" [|sddp]"); | |
411677ae AL |
126 | return (0); /* cut short by the snapshot length */ |
127 | } | |
c8cf0f94 | 128 | sdp = (const struct atShortDDP *)bp; |
ed775ee7 AHJ |
129 | ND_PRINT("%s.%s", |
130 | ataddr_string(ndo, 0, GET_U_1(lp->src)), | |
131 | ddpskt_string(ndo, GET_U_1(sdp->srcSkt))); | |
132 | ND_PRINT(" > %s.%s:", | |
133 | ataddr_string(ndo, 0, GET_U_1(lp->dst)), | |
134 | ddpskt_string(ndo, GET_U_1(sdp->dstSkt))); | |
c8cf0f94 PA |
135 | bp += ddpSSize; |
136 | length -= ddpSSize; | |
137 | hdrlen += ddpSSize; | |
ed775ee7 AHJ |
138 | ddp_print(ndo, bp, length, GET_U_1(sdp->type), 0, |
139 | GET_U_1(lp->src), GET_U_1(sdp->srcSkt)); | |
c8cf0f94 PA |
140 | break; |
141 | ||
142 | case lapDDP: | |
143 | if (length < ddpSize) { | |
ed775ee7 | 144 | ND_PRINT(" [|ddp %u]", length); |
c8cf0f94 PA |
145 | return (length); |
146 | } | |
ed775ee7 AHJ |
147 | if (!ND_TTEST_LEN(bp, ddpSize)) { |
148 | ND_PRINT(" [|ddp]"); | |
411677ae AL |
149 | return (0); /* cut short by the snapshot length */ |
150 | } | |
c8cf0f94 | 151 | dp = (const struct atDDP *)bp; |
ed775ee7 AHJ |
152 | snet = GET_BE_U_2(dp->srcNet); |
153 | ND_PRINT("%s.%s", | |
154 | ataddr_string(ndo, snet, GET_U_1(dp->srcNode)), | |
155 | ddpskt_string(ndo, GET_U_1(dp->srcSkt))); | |
156 | ND_PRINT(" > %s.%s:", | |
157 | ataddr_string(ndo, GET_BE_U_2(dp->dstNet), GET_U_1(dp->dstNode)), | |
158 | ddpskt_string(ndo, GET_U_1(dp->dstSkt))); | |
c8cf0f94 PA |
159 | bp += ddpSize; |
160 | length -= ddpSize; | |
161 | hdrlen += ddpSize; | |
ed775ee7 AHJ |
162 | ddp_print(ndo, bp, length, GET_U_1(dp->type), snet, |
163 | GET_U_1(dp->srcNode), GET_U_1(dp->srcSkt)); | |
c8cf0f94 PA |
164 | break; |
165 | ||
166 | #ifdef notdef | |
167 | case lapKLAP: | |
168 | klap_print(bp, length); | |
169 | break; | |
170 | #endif | |
171 | ||
172 | default: | |
ed775ee7 AHJ |
173 | ND_PRINT("%u > %u at-lap#%u %u", |
174 | GET_U_1(lp->src), GET_U_1(lp->dst), GET_U_1(lp->type), | |
175 | length); | |
c8cf0f94 PA |
176 | break; |
177 | } | |
178 | return (hdrlen); | |
179 | } | |
180 | ||
181 | /* | |
182 | * Print EtherTalk/TokenTalk packets (or FDDITalk, or whatever it's called | |
183 | * when it runs over FDDI; yes, I've seen FDDI captures with AppleTalk | |
184 | * packets in them). | |
185 | */ | |
186 | void | |
411677ae | 187 | atalk_print(netdissect_options *ndo, |
ed775ee7 | 188 | const u_char *bp, u_int length) |
c8cf0f94 | 189 | { |
ed775ee7 | 190 | const struct atDDP *dp; |
c8cf0f94 PA |
191 | u_short snet; |
192 | ||
ed775ee7 | 193 | ndo->ndo_protocol = "atalk"; |
411677ae | 194 | if(!ndo->ndo_eflag) |
ed775ee7 | 195 | ND_PRINT("AT "); |
c8cf0f94 PA |
196 | |
197 | if (length < ddpSize) { | |
ed775ee7 | 198 | ND_PRINT(" [|ddp %u]", length); |
411677ae AL |
199 | return; |
200 | } | |
ed775ee7 AHJ |
201 | if (!ND_TTEST_LEN(bp, ddpSize)) { |
202 | ND_PRINT(" [|ddp]"); | |
c8cf0f94 PA |
203 | return; |
204 | } | |
205 | dp = (const struct atDDP *)bp; | |
ed775ee7 AHJ |
206 | snet = GET_BE_U_2(dp->srcNet); |
207 | ND_PRINT("%s.%s", ataddr_string(ndo, snet, GET_U_1(dp->srcNode)), | |
208 | ddpskt_string(ndo, GET_U_1(dp->srcSkt))); | |
209 | ND_PRINT(" > %s.%s: ", | |
210 | ataddr_string(ndo, GET_BE_U_2(dp->dstNet), GET_U_1(dp->dstNode)), | |
211 | ddpskt_string(ndo, GET_U_1(dp->dstSkt))); | |
c8cf0f94 PA |
212 | bp += ddpSize; |
213 | length -= ddpSize; | |
ed775ee7 AHJ |
214 | ddp_print(ndo, bp, length, GET_U_1(dp->type), snet, |
215 | GET_U_1(dp->srcNode), GET_U_1(dp->srcSkt)); | |
c8cf0f94 PA |
216 | } |
217 | ||
218 | /* XXX should probably pass in the snap header and do checks like arp_print() */ | |
219 | void | |
411677ae | 220 | aarp_print(netdissect_options *ndo, |
ed775ee7 | 221 | const u_char *bp, u_int length) |
c8cf0f94 | 222 | { |
ed775ee7 | 223 | const struct aarp *ap; |
c8cf0f94 | 224 | |
411677ae | 225 | #define AT(member) ataddr_string(ndo, (ap->member[1]<<8)|ap->member[2],ap->member[3]) |
c8cf0f94 | 226 | |
ed775ee7 AHJ |
227 | ndo->ndo_protocol = "aarp"; |
228 | ND_PRINT("aarp "); | |
c8cf0f94 | 229 | ap = (const struct aarp *)bp; |
ed775ee7 | 230 | if (!ND_TTEST_SIZE(ap)) { |
411677ae | 231 | /* Just bail if we don't have the whole chunk. */ |
ed775ee7 | 232 | nd_print_trunc(ndo); |
411677ae AL |
233 | return; |
234 | } | |
235 | if (length < sizeof(*ap)) { | |
ed775ee7 | 236 | ND_PRINT(" [|aarp %u]", length); |
411677ae AL |
237 | return; |
238 | } | |
ed775ee7 AHJ |
239 | if (GET_BE_U_2(ap->htype) == 1 && |
240 | GET_BE_U_2(ap->ptype) == ETHERTYPE_ATALK && | |
241 | GET_U_1(ap->halen) == MAC_ADDR_LEN && GET_U_1(ap->palen) == 4) | |
242 | switch (GET_BE_U_2(ap->op)) { | |
c8cf0f94 PA |
243 | |
244 | case 1: /* request */ | |
ed775ee7 | 245 | ND_PRINT("who-has %s tell %s", AT(pdaddr), AT(psaddr)); |
c8cf0f94 PA |
246 | return; |
247 | ||
248 | case 2: /* response */ | |
ed775ee7 | 249 | ND_PRINT("reply %s is-at %s", AT(psaddr), GET_ETHERADDR_STRING(ap->hsaddr)); |
c8cf0f94 PA |
250 | return; |
251 | ||
252 | case 3: /* probe (oy!) */ | |
ed775ee7 | 253 | ND_PRINT("probe %s tell %s", AT(pdaddr), AT(psaddr)); |
c8cf0f94 PA |
254 | return; |
255 | } | |
ed775ee7 AHJ |
256 | ND_PRINT("len %u op %u htype %u ptype %#x halen %u palen %u", |
257 | length, GET_BE_U_2(ap->op), GET_BE_U_2(ap->htype), | |
258 | GET_BE_U_2(ap->ptype), GET_U_1(ap->halen), GET_U_1(ap->palen)); | |
c8cf0f94 PA |
259 | } |
260 | ||
261 | /* | |
262 | * Print AppleTalk Datagram Delivery Protocol packets. | |
263 | */ | |
264 | static void | |
411677ae | 265 | ddp_print(netdissect_options *ndo, |
ed775ee7 AHJ |
266 | const u_char *bp, u_int length, u_int t, |
267 | u_short snet, u_char snode, u_char skt) | |
c8cf0f94 PA |
268 | { |
269 | ||
270 | switch (t) { | |
271 | ||
272 | case ddpNBP: | |
411677ae | 273 | nbp_print(ndo, (const struct atNBP *)bp, length, snet, snode, skt); |
c8cf0f94 PA |
274 | break; |
275 | ||
276 | case ddpATP: | |
411677ae | 277 | atp_print(ndo, (const struct atATP *)bp, length); |
c8cf0f94 PA |
278 | break; |
279 | ||
280 | case ddpEIGRP: | |
411677ae | 281 | eigrp_print(ndo, bp, length); |
c8cf0f94 PA |
282 | break; |
283 | ||
284 | default: | |
ed775ee7 | 285 | ND_PRINT(" at-%s %u", tok2str(type2str, NULL, t), length); |
c8cf0f94 PA |
286 | break; |
287 | } | |
288 | } | |
289 | ||
290 | static void | |
411677ae | 291 | atp_print(netdissect_options *ndo, |
ed775ee7 | 292 | const struct atATP *ap, u_int length) |
c8cf0f94 | 293 | { |
ed775ee7 | 294 | uint8_t control; |
411677ae | 295 | uint32_t data; |
c8cf0f94 | 296 | |
411677ae | 297 | if ((const u_char *)(ap + 1) > ndo->ndo_snapend) { |
c8cf0f94 | 298 | /* Just bail if we don't have the whole chunk. */ |
ed775ee7 | 299 | nd_print_trunc(ndo); |
c8cf0f94 PA |
300 | return; |
301 | } | |
27bfbee1 | 302 | if (length < sizeof(*ap)) { |
ed775ee7 | 303 | ND_PRINT(" [|atp %u]", length); |
27bfbee1 PA |
304 | return; |
305 | } | |
c8cf0f94 | 306 | length -= sizeof(*ap); |
ed775ee7 AHJ |
307 | control = GET_U_1(ap->control); |
308 | switch (control & 0xc0) { | |
c8cf0f94 PA |
309 | |
310 | case atpReqCode: | |
ed775ee7 AHJ |
311 | ND_PRINT(" atp-req%s %u", |
312 | control & atpXO? " " : "*", | |
313 | GET_BE_U_2(ap->transID)); | |
c8cf0f94 | 314 | |
ed775ee7 | 315 | atp_bitmap_print(ndo, GET_U_1(ap->bitmap)); |
c8cf0f94 PA |
316 | |
317 | if (length != 0) | |
ed775ee7 | 318 | ND_PRINT(" [len=%u]", length); |
c8cf0f94 | 319 | |
ed775ee7 | 320 | switch (control & (atpEOM|atpSTS)) { |
c8cf0f94 | 321 | case atpEOM: |
ed775ee7 | 322 | ND_PRINT(" [EOM]"); |
c8cf0f94 PA |
323 | break; |
324 | case atpSTS: | |
ed775ee7 | 325 | ND_PRINT(" [STS]"); |
c8cf0f94 PA |
326 | break; |
327 | case atpEOM|atpSTS: | |
ed775ee7 | 328 | ND_PRINT(" [EOM,STS]"); |
c8cf0f94 PA |
329 | break; |
330 | } | |
331 | break; | |
332 | ||
333 | case atpRspCode: | |
ed775ee7 AHJ |
334 | ND_PRINT(" atp-resp%s%u:%u (%u)", |
335 | control & atpEOM? "*" : " ", | |
336 | GET_BE_U_2(ap->transID), GET_U_1(ap->bitmap), | |
337 | length); | |
338 | switch (control & (atpXO|atpSTS)) { | |
c8cf0f94 | 339 | case atpXO: |
ed775ee7 | 340 | ND_PRINT(" [XO]"); |
c8cf0f94 PA |
341 | break; |
342 | case atpSTS: | |
ed775ee7 | 343 | ND_PRINT(" [STS]"); |
c8cf0f94 PA |
344 | break; |
345 | case atpXO|atpSTS: | |
ed775ee7 | 346 | ND_PRINT(" [XO,STS]"); |
c8cf0f94 PA |
347 | break; |
348 | } | |
349 | break; | |
350 | ||
351 | case atpRelCode: | |
ed775ee7 | 352 | ND_PRINT(" atp-rel %u", GET_BE_U_2(ap->transID)); |
c8cf0f94 | 353 | |
ed775ee7 | 354 | atp_bitmap_print(ndo, GET_U_1(ap->bitmap)); |
c8cf0f94 PA |
355 | |
356 | /* length should be zero */ | |
357 | if (length) | |
ed775ee7 | 358 | ND_PRINT(" [len=%u]", length); |
c8cf0f94 PA |
359 | |
360 | /* there shouldn't be any control flags */ | |
ed775ee7 AHJ |
361 | if (control & (atpXO|atpEOM|atpSTS)) { |
362 | char c = '['; | |
363 | if (control & atpXO) { | |
364 | ND_PRINT("%cXO", c); | |
c8cf0f94 PA |
365 | c = ','; |
366 | } | |
ed775ee7 AHJ |
367 | if (control & atpEOM) { |
368 | ND_PRINT("%cEOM", c); | |
c8cf0f94 PA |
369 | c = ','; |
370 | } | |
ed775ee7 AHJ |
371 | if (control & atpSTS) { |
372 | ND_PRINT("%cSTS", c); | |
c8cf0f94 | 373 | } |
ed775ee7 | 374 | ND_PRINT("]"); |
c8cf0f94 PA |
375 | } |
376 | break; | |
377 | ||
378 | default: | |
ed775ee7 AHJ |
379 | ND_PRINT(" atp-0x%x %u (%u)", control, |
380 | GET_BE_U_2(ap->transID), length); | |
c8cf0f94 PA |
381 | break; |
382 | } | |
ed775ee7 | 383 | data = GET_BE_U_4(ap->userData); |
c8cf0f94 | 384 | if (data != 0) |
ed775ee7 | 385 | ND_PRINT(" 0x%x", data); |
c8cf0f94 PA |
386 | } |
387 | ||
388 | static void | |
411677ae | 389 | atp_bitmap_print(netdissect_options *ndo, |
ed775ee7 | 390 | u_char bm) |
c8cf0f94 | 391 | { |
ed775ee7 | 392 | u_int i; |
c8cf0f94 PA |
393 | |
394 | /* | |
395 | * The '& 0xff' below is needed for compilers that want to sign | |
396 | * extend a u_char, which is the case with the Ultrix compiler. | |
397 | * (gcc is smart enough to eliminate it, at least on the Sparc). | |
398 | */ | |
399 | if ((bm + 1) & (bm & 0xff)) { | |
ed775ee7 | 400 | char c = '<'; |
c8cf0f94 PA |
401 | for (i = 0; bm; ++i) { |
402 | if (bm & 1) { | |
ed775ee7 | 403 | ND_PRINT("%c%u", c, i); |
c8cf0f94 PA |
404 | c = ','; |
405 | } | |
406 | bm >>= 1; | |
407 | } | |
ed775ee7 | 408 | ND_PRINT(">"); |
c8cf0f94 PA |
409 | } else { |
410 | for (i = 0; bm; ++i) | |
411 | bm >>= 1; | |
412 | if (i > 1) | |
ed775ee7 | 413 | ND_PRINT("<0-%u>", i - 1); |
c8cf0f94 | 414 | else |
ed775ee7 | 415 | ND_PRINT("<0>"); |
c8cf0f94 PA |
416 | } |
417 | } | |
418 | ||
419 | static void | |
411677ae | 420 | nbp_print(netdissect_options *ndo, |
ed775ee7 AHJ |
421 | const struct atNBP *np, u_int length, u_short snet, |
422 | u_char snode, u_char skt) | |
c8cf0f94 | 423 | { |
ed775ee7 | 424 | const struct atNBPtuple *tp = |
411677ae | 425 | (const struct atNBPtuple *)((const u_char *)np + nbpHeaderSize); |
ed775ee7 AHJ |
426 | uint8_t control; |
427 | u_int i; | |
c8cf0f94 PA |
428 | const u_char *ep; |
429 | ||
430 | if (length < nbpHeaderSize) { | |
ed775ee7 | 431 | ND_PRINT(" truncated-nbp %u", length); |
c8cf0f94 PA |
432 | return; |
433 | } | |
434 | ||
435 | length -= nbpHeaderSize; | |
436 | if (length < 8) { | |
437 | /* must be room for at least one tuple */ | |
ed775ee7 | 438 | ND_PRINT(" truncated-nbp %u", length + nbpHeaderSize); |
c8cf0f94 PA |
439 | return; |
440 | } | |
441 | /* ep points to end of available data */ | |
411677ae | 442 | ep = ndo->ndo_snapend; |
c8cf0f94 | 443 | if ((const u_char *)tp > ep) { |
ed775ee7 | 444 | nd_print_trunc(ndo); |
c8cf0f94 PA |
445 | return; |
446 | } | |
ed775ee7 AHJ |
447 | control = GET_U_1(np->control); |
448 | switch (i = (control & 0xf0)) { | |
c8cf0f94 PA |
449 | |
450 | case nbpBrRq: | |
451 | case nbpLkUp: | |
ed775ee7 AHJ |
452 | ND_PRINT(i == nbpLkUp? " nbp-lkup %u:":" nbp-brRq %u:", |
453 | GET_U_1(np->id)); | |
c8cf0f94 | 454 | if ((const u_char *)(tp + 1) > ep) { |
ed775ee7 | 455 | nd_print_trunc(ndo); |
c8cf0f94 PA |
456 | return; |
457 | } | |
411677ae | 458 | (void)nbp_name_print(ndo, tp, ep); |
c8cf0f94 PA |
459 | /* |
460 | * look for anomalies: the spec says there can only | |
461 | * be one tuple, the address must match the source | |
462 | * address and the enumerator should be zero. | |
463 | */ | |
ed775ee7 AHJ |
464 | if ((control & 0xf) != 1) |
465 | ND_PRINT(" [ntup=%u]", control & 0xf); | |
466 | if (GET_U_1(tp->enumerator)) | |
467 | ND_PRINT(" [enum=%u]", GET_U_1(tp->enumerator)); | |
468 | if (GET_BE_U_2(tp->net) != snet || | |
469 | GET_U_1(tp->node) != snode || | |
470 | GET_U_1(tp->skt) != skt) | |
471 | ND_PRINT(" [addr=%s.%u]", | |
472 | ataddr_string(ndo, GET_BE_U_2(tp->net), | |
473 | GET_U_1(tp->node)), | |
474 | GET_U_1(tp->skt)); | |
c8cf0f94 PA |
475 | break; |
476 | ||
477 | case nbpLkUpReply: | |
ed775ee7 | 478 | ND_PRINT(" nbp-reply %u:", GET_U_1(np->id)); |
c8cf0f94 PA |
479 | |
480 | /* print each of the tuples in the reply */ | |
ed775ee7 | 481 | for (i = control & 0xf; i != 0 && tp; i--) |
411677ae | 482 | tp = nbp_tuple_print(ndo, tp, ep, snet, snode, skt); |
c8cf0f94 PA |
483 | break; |
484 | ||
485 | default: | |
ed775ee7 AHJ |
486 | ND_PRINT(" nbp-0x%x %u (%u)", control, GET_U_1(np->id), |
487 | length); | |
c8cf0f94 PA |
488 | break; |
489 | } | |
490 | } | |
491 | ||
492 | /* print a counted string */ | |
ed775ee7 | 493 | static const u_char * |
411677ae | 494 | print_cstring(netdissect_options *ndo, |
ed775ee7 | 495 | const u_char *cp, const u_char *ep) |
c8cf0f94 | 496 | { |
ed775ee7 | 497 | u_int length; |
c8cf0f94 | 498 | |
ed775ee7 AHJ |
499 | if (cp >= ep) { |
500 | nd_print_trunc(ndo); | |
c8cf0f94 PA |
501 | return (0); |
502 | } | |
ed775ee7 AHJ |
503 | length = GET_U_1(cp); |
504 | cp++; | |
c8cf0f94 PA |
505 | |
506 | /* Spec says string can be at most 32 bytes long */ | |
507 | if (length > 32) { | |
ed775ee7 | 508 | ND_PRINT("[len=%u]", length); |
c8cf0f94 PA |
509 | return (0); |
510 | } | |
ed775ee7 AHJ |
511 | while (length != 0) { |
512 | if (cp >= ep) { | |
513 | nd_print_trunc(ndo); | |
c8cf0f94 PA |
514 | return (0); |
515 | } | |
ed775ee7 AHJ |
516 | fn_print_char(ndo, GET_U_1(cp)); |
517 | cp++; | |
518 | length--; | |
c8cf0f94 PA |
519 | } |
520 | return (cp); | |
521 | } | |
522 | ||
523 | static const struct atNBPtuple * | |
411677ae | 524 | nbp_tuple_print(netdissect_options *ndo, |
ed775ee7 AHJ |
525 | const struct atNBPtuple *tp, const u_char *ep, |
526 | u_short snet, u_char snode, u_char skt) | |
c8cf0f94 | 527 | { |
ed775ee7 | 528 | const struct atNBPtuple *tpn; |
c8cf0f94 PA |
529 | |
530 | if ((const u_char *)(tp + 1) > ep) { | |
ed775ee7 | 531 | nd_print_trunc(ndo); |
c8cf0f94 PA |
532 | return 0; |
533 | } | |
411677ae | 534 | tpn = nbp_name_print(ndo, tp, ep); |
c8cf0f94 PA |
535 | |
536 | /* if the enumerator isn't 1, print it */ | |
ed775ee7 AHJ |
537 | if (GET_U_1(tp->enumerator) != 1) |
538 | ND_PRINT("(%u)", GET_U_1(tp->enumerator)); | |
c8cf0f94 PA |
539 | |
540 | /* if the socket doesn't match the src socket, print it */ | |
ed775ee7 AHJ |
541 | if (GET_U_1(tp->skt) != skt) |
542 | ND_PRINT(" %u", GET_U_1(tp->skt)); | |
c8cf0f94 PA |
543 | |
544 | /* if the address doesn't match the src address, it's an anomaly */ | |
ed775ee7 AHJ |
545 | if (GET_BE_U_2(tp->net) != snet || |
546 | GET_U_1(tp->node) != snode) | |
547 | ND_PRINT(" [addr=%s]", | |
548 | ataddr_string(ndo, GET_BE_U_2(tp->net), GET_U_1(tp->node))); | |
c8cf0f94 PA |
549 | |
550 | return (tpn); | |
551 | } | |
552 | ||
553 | static const struct atNBPtuple * | |
411677ae | 554 | nbp_name_print(netdissect_options *ndo, |
ed775ee7 | 555 | const struct atNBPtuple *tp, const u_char *ep) |
c8cf0f94 | 556 | { |
ed775ee7 | 557 | const u_char *cp = (const u_char *)tp + nbpTupleSize; |
c8cf0f94 | 558 | |
ed775ee7 | 559 | ND_PRINT(" "); |
c8cf0f94 PA |
560 | |
561 | /* Object */ | |
ed775ee7 | 562 | ND_PRINT("\""); |
411677ae | 563 | if ((cp = print_cstring(ndo, cp, ep)) != NULL) { |
c8cf0f94 | 564 | /* Type */ |
ed775ee7 | 565 | ND_PRINT(":"); |
411677ae | 566 | if ((cp = print_cstring(ndo, cp, ep)) != NULL) { |
c8cf0f94 | 567 | /* Zone */ |
ed775ee7 | 568 | ND_PRINT("@"); |
411677ae | 569 | if ((cp = print_cstring(ndo, cp, ep)) != NULL) |
ed775ee7 | 570 | ND_PRINT("\""); |
c8cf0f94 PA |
571 | } |
572 | } | |
573 | return ((const struct atNBPtuple *)cp); | |
574 | } | |
575 | ||
576 | ||
577 | #define HASHNAMESIZE 4096 | |
578 | ||
579 | struct hnamemem { | |
ed775ee7 | 580 | u_int addr; |
c8cf0f94 PA |
581 | char *name; |
582 | struct hnamemem *nxt; | |
583 | }; | |
584 | ||
585 | static struct hnamemem hnametable[HASHNAMESIZE]; | |
586 | ||
587 | static const char * | |
411677ae AL |
588 | ataddr_string(netdissect_options *ndo, |
589 | u_short atnet, u_char athost) | |
c8cf0f94 | 590 | { |
ed775ee7 AHJ |
591 | struct hnamemem *tp, *tp2; |
592 | u_int i = (atnet << 8) | athost; | |
411677ae | 593 | char nambuf[256+1]; |
c8cf0f94 PA |
594 | static int first = 1; |
595 | FILE *fp; | |
596 | ||
597 | /* | |
ed775ee7 | 598 | * Are we doing address to name resolution? |
c8cf0f94 | 599 | */ |
ed775ee7 AHJ |
600 | if (!ndo->ndo_nflag) { |
601 | /* | |
602 | * Yes. Have we tried to open and read an AppleTalk | |
603 | * number to name map file? | |
604 | */ | |
605 | if (!first) { | |
606 | /* | |
607 | * No; try to do so. | |
608 | */ | |
609 | first = 0; | |
610 | fp = fopen("/etc/atalk.names", "r"); | |
611 | if (fp != NULL) { | |
612 | char line[256]; | |
613 | u_int i1, i2; | |
614 | ||
615 | while (fgets(line, sizeof(line), fp)) { | |
616 | if (line[0] == '\n' || line[0] == 0 || | |
617 | line[0] == '#') | |
618 | continue; | |
619 | if (sscanf(line, "%u.%u %256s", &i1, | |
620 | &i2, nambuf) == 3) | |
621 | /* got a hostname. */ | |
622 | i2 |= (i1 << 8); | |
623 | else if (sscanf(line, "%u %256s", &i1, | |
624 | nambuf) == 2) | |
625 | /* got a net name */ | |
626 | i2 = (i1 << 8) | 255; | |
627 | else | |
628 | continue; | |
629 | ||
630 | for (tp = &hnametable[i2 & (HASHNAMESIZE-1)]; | |
631 | tp->nxt; tp = tp->nxt) | |
632 | ; | |
633 | tp->addr = i2; | |
634 | tp->nxt = newhnamemem(ndo); | |
635 | tp->name = strdup(nambuf); | |
636 | if (tp->name == NULL) | |
637 | (*ndo->ndo_error)(ndo, | |
638 | S_ERR_ND_MEM_ALLOC, | |
639 | "%s: strdup(nambuf)", __func__); | |
640 | } | |
641 | fclose(fp); | |
642 | } | |
c8cf0f94 | 643 | } |
c8cf0f94 PA |
644 | } |
645 | ||
ed775ee7 AHJ |
646 | /* |
647 | * Now try to look up the address in the table. | |
648 | */ | |
c8cf0f94 PA |
649 | for (tp = &hnametable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) |
650 | if (tp->addr == i) | |
651 | return (tp->name); | |
652 | ||
653 | /* didn't have the node name -- see if we've got the net name */ | |
654 | i |= 255; | |
655 | for (tp2 = &hnametable[i & (HASHNAMESIZE-1)]; tp2->nxt; tp2 = tp2->nxt) | |
656 | if (tp2->addr == i) { | |
657 | tp->addr = (atnet << 8) | athost; | |
411677ae | 658 | tp->nxt = newhnamemem(ndo); |
ed775ee7 | 659 | (void)snprintf(nambuf, sizeof(nambuf), "%s.%u", |
c8cf0f94 PA |
660 | tp2->name, athost); |
661 | tp->name = strdup(nambuf); | |
411677ae | 662 | if (tp->name == NULL) |
ed775ee7 AHJ |
663 | (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, |
664 | "%s: strdup(nambuf)", __func__); | |
c8cf0f94 PA |
665 | return (tp->name); |
666 | } | |
667 | ||
668 | tp->addr = (atnet << 8) | athost; | |
411677ae | 669 | tp->nxt = newhnamemem(ndo); |
c8cf0f94 | 670 | if (athost != 255) |
ed775ee7 | 671 | (void)snprintf(nambuf, sizeof(nambuf), "%u.%u", atnet, athost); |
c8cf0f94 | 672 | else |
ed775ee7 | 673 | (void)snprintf(nambuf, sizeof(nambuf), "%u", atnet); |
c8cf0f94 | 674 | tp->name = strdup(nambuf); |
411677ae | 675 | if (tp->name == NULL) |
ed775ee7 AHJ |
676 | (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, |
677 | "%s: strdup(nambuf)", __func__); | |
c8cf0f94 PA |
678 | |
679 | return (tp->name); | |
680 | } | |
681 | ||
411677ae | 682 | static const struct tok skt2str[] = { |
c8cf0f94 PA |
683 | { rtmpSkt, "rtmp" }, /* routing table maintenance */ |
684 | { nbpSkt, "nis" }, /* name info socket */ | |
685 | { echoSkt, "echo" }, /* AppleTalk echo protocol */ | |
686 | { zipSkt, "zip" }, /* zone info protocol */ | |
687 | { 0, NULL } | |
688 | }; | |
689 | ||
690 | static const char * | |
411677ae | 691 | ddpskt_string(netdissect_options *ndo, |
ed775ee7 | 692 | u_int skt) |
c8cf0f94 PA |
693 | { |
694 | static char buf[8]; | |
695 | ||
411677ae | 696 | if (ndo->ndo_nflag) { |
ed775ee7 | 697 | (void)snprintf(buf, sizeof(buf), "%u", skt); |
c8cf0f94 PA |
698 | return (buf); |
699 | } | |
ed775ee7 | 700 | return (tok2str(skt2str, "%u", skt)); |
c8cf0f94 | 701 | } |