10f74e101Schristos /* 20f74e101Schristos * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 30f74e101Schristos * The Regents of the University of California. All rights reserved. 40f74e101Schristos * 50f74e101Schristos * Redistribution and use in source and binary forms, with or without 60f74e101Schristos * modification, are permitted provided that: (1) source code distributions 70f74e101Schristos * retain the above copyright notice and this paragraph in its entirety, (2) 80f74e101Schristos * distributions including binary code include the above copyright notice and 90f74e101Schristos * this paragraph in its entirety in the documentation or other materials 100f74e101Schristos * provided with the distribution, and (3) all advertising materials mentioning 110f74e101Schristos * features or use of this software display the following acknowledgement: 120f74e101Schristos * ``This product includes software developed by the University of California, 130f74e101Schristos * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 140f74e101Schristos * the University nor the names of its contributors may be used to endorse 150f74e101Schristos * or promote products derived from this software without specific prior 160f74e101Schristos * written permission. 170f74e101Schristos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 180f74e101Schristos * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 190f74e101Schristos * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 200f74e101Schristos */ 210f74e101Schristos 22dc860a36Sspz /* \summary: AppleTalk printer */ 23dc860a36Sspz 2411b3aaa1Schristos #include <sys/cdefs.h> 250f74e101Schristos #ifndef lint 26*26ba0b50Schristos __RCSID("$NetBSD: print-atalk.c,v 1.9 2024/09/02 16:15:30 christos Exp $"); 270f74e101Schristos #endif 280f74e101Schristos 29c74ad251Schristos #include <config.h> 300f74e101Schristos 31c74ad251Schristos #include "netdissect-stdinc.h" 320f74e101Schristos 330f74e101Schristos #include <stdio.h> 340f74e101Schristos #include <string.h> 350f74e101Schristos 36fdccd7e4Schristos #include "netdissect.h" 370f74e101Schristos #include "addrtoname.h" 380f74e101Schristos #include "ethertype.h" 39fdccd7e4Schristos #include "extract.h" 400f74e101Schristos #include "appletalk.h" 410f74e101Schristos 42b3a00663Schristos 43870189d2Schristos static const struct tok type2str[] = { 440f74e101Schristos { ddpRTMP, "rtmp" }, 450f74e101Schristos { ddpRTMPrequest, "rtmpReq" }, 460f74e101Schristos { ddpECHO, "echo" }, 470f74e101Schristos { ddpIP, "IP" }, 480f74e101Schristos { ddpARP, "ARP" }, 490f74e101Schristos { ddpKLAP, "KLAP" }, 500f74e101Schristos { 0, NULL } 510f74e101Schristos }; 520f74e101Schristos 530f74e101Schristos struct aarp { 54c74ad251Schristos nd_uint16_t htype, ptype; 55c74ad251Schristos nd_uint8_t halen, palen; 56c74ad251Schristos nd_uint16_t op; 57c74ad251Schristos nd_mac_addr hsaddr; 58b3a00663Schristos uint8_t psaddr[4]; 59c74ad251Schristos nd_mac_addr hdaddr; 60b3a00663Schristos uint8_t pdaddr[4]; 610f74e101Schristos }; 620f74e101Schristos 63b3a00663Schristos static void atp_print(netdissect_options *, const struct atATP *, u_int); 64b3a00663Schristos static void atp_bitmap_print(netdissect_options *, u_char); 65b3a00663Schristos static void nbp_print(netdissect_options *, const struct atNBP *, u_int, u_short, u_char, u_char); 66b3a00663Schristos static const struct atNBPtuple *nbp_tuple_print(netdissect_options *ndo, const struct atNBPtuple *, 670f74e101Schristos const u_char *, 680f74e101Schristos u_short, u_char, u_char); 69b3a00663Schristos static const struct atNBPtuple *nbp_name_print(netdissect_options *, const struct atNBPtuple *, 700f74e101Schristos const u_char *); 71b3a00663Schristos static const char *ataddr_string(netdissect_options *, u_short, u_char); 72c74ad251Schristos static void ddp_print(netdissect_options *, const u_char *, u_int, u_int, u_short, u_char, u_char); 73c74ad251Schristos static const char *ddpskt_string(netdissect_options *, u_int); 740f74e101Schristos 750f74e101Schristos /* 760f74e101Schristos * Print LLAP packets received on a physical LocalTalk interface. 770f74e101Schristos */ 78c74ad251Schristos void 79b3a00663Schristos ltalk_if_print(netdissect_options *ndo, 80b3a00663Schristos const struct pcap_pkthdr *h, const u_char *p) 810f74e101Schristos { 82dc860a36Sspz u_int hdrlen; 83dc860a36Sspz 84c74ad251Schristos ndo->ndo_protocol = "ltalk"; 85dc860a36Sspz hdrlen = llap_print(ndo, p, h->len); 86dc860a36Sspz if (hdrlen == 0) { 87dc860a36Sspz /* Cut short by the snapshot length. */ 88c74ad251Schristos ndo->ndo_ll_hdr_len += h->caplen; 89c74ad251Schristos return; 90dc860a36Sspz } 91c74ad251Schristos ndo->ndo_ll_hdr_len += hdrlen; 920f74e101Schristos } 930f74e101Schristos 940f74e101Schristos /* 950f74e101Schristos * Print AppleTalk LLAP packets. 960f74e101Schristos */ 970f74e101Schristos u_int 98b3a00663Schristos llap_print(netdissect_options *ndo, 99c74ad251Schristos const u_char *bp, u_int length) 1000f74e101Schristos { 101c74ad251Schristos const struct LAP *lp; 102c74ad251Schristos const struct atDDP *dp; 103c74ad251Schristos const struct atShortDDP *sdp; 1040f74e101Schristos u_short snet; 1050f74e101Schristos u_int hdrlen; 1060f74e101Schristos 107c74ad251Schristos ndo->ndo_protocol = "llap"; 1080e9868baSchristos if (length < sizeof(*lp)) { 109c74ad251Schristos ND_PRINT(" [|llap %u]", length); 1100e9868baSchristos return (length); 1110e9868baSchristos } 112c74ad251Schristos if (!ND_TTEST_LEN(bp, sizeof(*lp))) { 113c74ad251Schristos nd_print_trunc(ndo); 114dc860a36Sspz return (0); /* cut short by the snapshot length */ 115dc860a36Sspz } 1160f74e101Schristos lp = (const struct LAP *)bp; 1170f74e101Schristos bp += sizeof(*lp); 1180f74e101Schristos length -= sizeof(*lp); 1190f74e101Schristos hdrlen = sizeof(*lp); 120c74ad251Schristos switch (GET_U_1(lp->type)) { 1210f74e101Schristos 1220f74e101Schristos case lapShortDDP: 1230f74e101Schristos if (length < ddpSSize) { 124c74ad251Schristos ND_PRINT(" [|sddp %u]", length); 1250f74e101Schristos return (length); 1260f74e101Schristos } 127c74ad251Schristos if (!ND_TTEST_LEN(bp, ddpSSize)) { 128c74ad251Schristos ND_PRINT(" [|sddp]"); 129dc860a36Sspz return (0); /* cut short by the snapshot length */ 130dc860a36Sspz } 1310f74e101Schristos sdp = (const struct atShortDDP *)bp; 132c74ad251Schristos ND_PRINT("%s.%s", 133c74ad251Schristos ataddr_string(ndo, 0, GET_U_1(lp->src)), 134c74ad251Schristos ddpskt_string(ndo, GET_U_1(sdp->srcSkt))); 135c74ad251Schristos ND_PRINT(" > %s.%s:", 136c74ad251Schristos ataddr_string(ndo, 0, GET_U_1(lp->dst)), 137c74ad251Schristos ddpskt_string(ndo, GET_U_1(sdp->dstSkt))); 1380f74e101Schristos bp += ddpSSize; 1390f74e101Schristos length -= ddpSSize; 1400f74e101Schristos hdrlen += ddpSSize; 141c74ad251Schristos ddp_print(ndo, bp, length, GET_U_1(sdp->type), 0, 142c74ad251Schristos GET_U_1(lp->src), GET_U_1(sdp->srcSkt)); 1430f74e101Schristos break; 1440f74e101Schristos 1450f74e101Schristos case lapDDP: 1460f74e101Schristos if (length < ddpSize) { 147c74ad251Schristos ND_PRINT(" [|ddp %u]", length); 1480f74e101Schristos return (length); 1490f74e101Schristos } 150c74ad251Schristos if (!ND_TTEST_LEN(bp, ddpSize)) { 151c74ad251Schristos ND_PRINT(" [|ddp]"); 152dc860a36Sspz return (0); /* cut short by the snapshot length */ 153dc860a36Sspz } 1540f74e101Schristos dp = (const struct atDDP *)bp; 155c74ad251Schristos snet = GET_BE_U_2(dp->srcNet); 156c74ad251Schristos ND_PRINT("%s.%s", 157c74ad251Schristos ataddr_string(ndo, snet, GET_U_1(dp->srcNode)), 158c74ad251Schristos ddpskt_string(ndo, GET_U_1(dp->srcSkt))); 159c74ad251Schristos ND_PRINT(" > %s.%s:", 160c74ad251Schristos ataddr_string(ndo, GET_BE_U_2(dp->dstNet), GET_U_1(dp->dstNode)), 161c74ad251Schristos ddpskt_string(ndo, GET_U_1(dp->dstSkt))); 1620f74e101Schristos bp += ddpSize; 1630f74e101Schristos length -= ddpSize; 1640f74e101Schristos hdrlen += ddpSize; 165c74ad251Schristos ddp_print(ndo, bp, length, GET_U_1(dp->type), snet, 166c74ad251Schristos GET_U_1(dp->srcNode), GET_U_1(dp->srcSkt)); 1670f74e101Schristos break; 1680f74e101Schristos 1690f74e101Schristos #ifdef notdef 1700f74e101Schristos case lapKLAP: 1710f74e101Schristos klap_print(bp, length); 1720f74e101Schristos break; 1730f74e101Schristos #endif 1740f74e101Schristos 1750f74e101Schristos default: 176c74ad251Schristos ND_PRINT("%u > %u at-lap#%u %u", 177c74ad251Schristos GET_U_1(lp->src), GET_U_1(lp->dst), GET_U_1(lp->type), 178c74ad251Schristos length); 1790f74e101Schristos break; 1800f74e101Schristos } 1810f74e101Schristos return (hdrlen); 1820f74e101Schristos } 1830f74e101Schristos 1840f74e101Schristos /* 1850f74e101Schristos * Print EtherTalk/TokenTalk packets (or FDDITalk, or whatever it's called 1860f74e101Schristos * when it runs over FDDI; yes, I've seen FDDI captures with AppleTalk 1870f74e101Schristos * packets in them). 1880f74e101Schristos */ 1890f74e101Schristos void 190b3a00663Schristos atalk_print(netdissect_options *ndo, 191c74ad251Schristos const u_char *bp, u_int length) 1920f74e101Schristos { 193c74ad251Schristos const struct atDDP *dp; 1940f74e101Schristos u_short snet; 1950f74e101Schristos 196c74ad251Schristos ndo->ndo_protocol = "atalk"; 197b3a00663Schristos if(!ndo->ndo_eflag) 198c74ad251Schristos ND_PRINT("AT "); 1990f74e101Schristos 2000f74e101Schristos if (length < ddpSize) { 201c74ad251Schristos ND_PRINT(" [|ddp %u]", length); 2020f74e101Schristos return; 2030f74e101Schristos } 204c74ad251Schristos if (!ND_TTEST_LEN(bp, ddpSize)) { 205c74ad251Schristos ND_PRINT(" [|ddp]"); 206dc860a36Sspz return; 207dc860a36Sspz } 2080f74e101Schristos dp = (const struct atDDP *)bp; 209c74ad251Schristos snet = GET_BE_U_2(dp->srcNet); 210c74ad251Schristos ND_PRINT("%s.%s", ataddr_string(ndo, snet, GET_U_1(dp->srcNode)), 211c74ad251Schristos ddpskt_string(ndo, GET_U_1(dp->srcSkt))); 212c74ad251Schristos ND_PRINT(" > %s.%s: ", 213c74ad251Schristos ataddr_string(ndo, GET_BE_U_2(dp->dstNet), GET_U_1(dp->dstNode)), 214c74ad251Schristos ddpskt_string(ndo, GET_U_1(dp->dstSkt))); 2150f74e101Schristos bp += ddpSize; 2160f74e101Schristos length -= ddpSize; 217c74ad251Schristos ddp_print(ndo, bp, length, GET_U_1(dp->type), snet, 218c74ad251Schristos GET_U_1(dp->srcNode), GET_U_1(dp->srcSkt)); 2190f74e101Schristos } 2200f74e101Schristos 2210f74e101Schristos /* XXX should probably pass in the snap header and do checks like arp_print() */ 2220f74e101Schristos void 223b3a00663Schristos aarp_print(netdissect_options *ndo, 224c74ad251Schristos const u_char *bp, u_int length) 2250f74e101Schristos { 226c74ad251Schristos const struct aarp *ap; 2270f74e101Schristos 228b3a00663Schristos #define AT(member) ataddr_string(ndo, (ap->member[1]<<8)|ap->member[2],ap->member[3]) 2290f74e101Schristos 230c74ad251Schristos ndo->ndo_protocol = "aarp"; 231c74ad251Schristos ND_PRINT("aarp "); 2320f74e101Schristos ap = (const struct aarp *)bp; 233c74ad251Schristos if (!ND_TTEST_SIZE(ap)) { 234dc860a36Sspz /* Just bail if we don't have the whole chunk. */ 235c74ad251Schristos nd_print_trunc(ndo); 236dc860a36Sspz return; 237dc860a36Sspz } 238dc860a36Sspz if (length < sizeof(*ap)) { 239c74ad251Schristos ND_PRINT(" [|aarp %u]", length); 240dc860a36Sspz return; 241dc860a36Sspz } 242c74ad251Schristos if (GET_BE_U_2(ap->htype) == 1 && 243c74ad251Schristos GET_BE_U_2(ap->ptype) == ETHERTYPE_ATALK && 244c74ad251Schristos GET_U_1(ap->halen) == MAC_ADDR_LEN && GET_U_1(ap->palen) == 4) 245c74ad251Schristos switch (GET_BE_U_2(ap->op)) { 2460f74e101Schristos 2470f74e101Schristos case 1: /* request */ 248c74ad251Schristos ND_PRINT("who-has %s tell %s", AT(pdaddr), AT(psaddr)); 2490f74e101Schristos return; 2500f74e101Schristos 2510f74e101Schristos case 2: /* response */ 252c74ad251Schristos ND_PRINT("reply %s is-at %s", AT(psaddr), GET_ETHERADDR_STRING(ap->hsaddr)); 2530f74e101Schristos return; 2540f74e101Schristos 2550f74e101Schristos case 3: /* probe (oy!) */ 256c74ad251Schristos ND_PRINT("probe %s tell %s", AT(pdaddr), AT(psaddr)); 2570f74e101Schristos return; 2580f74e101Schristos } 259c74ad251Schristos ND_PRINT("len %u op %u htype %u ptype %#x halen %u palen %u", 260c74ad251Schristos length, GET_BE_U_2(ap->op), GET_BE_U_2(ap->htype), 261c74ad251Schristos GET_BE_U_2(ap->ptype), GET_U_1(ap->halen), GET_U_1(ap->palen)); 2620f74e101Schristos } 2630f74e101Schristos 2640f74e101Schristos /* 2650f74e101Schristos * Print AppleTalk Datagram Delivery Protocol packets. 2660f74e101Schristos */ 2670f74e101Schristos static void 268b3a00663Schristos ddp_print(netdissect_options *ndo, 269c74ad251Schristos const u_char *bp, u_int length, u_int t, 270c74ad251Schristos u_short snet, u_char snode, u_char skt) 2710f74e101Schristos { 2720f74e101Schristos 2730f74e101Schristos switch (t) { 2740f74e101Schristos 2750f74e101Schristos case ddpNBP: 276b3a00663Schristos nbp_print(ndo, (const struct atNBP *)bp, length, snet, snode, skt); 2770f74e101Schristos break; 2780f74e101Schristos 2790f74e101Schristos case ddpATP: 280b3a00663Schristos atp_print(ndo, (const struct atATP *)bp, length); 2810f74e101Schristos break; 2820f74e101Schristos 2830f74e101Schristos case ddpEIGRP: 284b3a00663Schristos eigrp_print(ndo, bp, length); 2850f74e101Schristos break; 2860f74e101Schristos 2870f74e101Schristos default: 288c74ad251Schristos ND_PRINT(" at-%s %u", tok2str(type2str, NULL, t), length); 2890f74e101Schristos break; 2900f74e101Schristos } 2910f74e101Schristos } 2920f74e101Schristos 2930f74e101Schristos static void 294b3a00663Schristos atp_print(netdissect_options *ndo, 295c74ad251Schristos const struct atATP *ap, u_int length) 2960f74e101Schristos { 297c74ad251Schristos uint8_t control; 298b3a00663Schristos uint32_t data; 2990f74e101Schristos 300b3a00663Schristos if ((const u_char *)(ap + 1) > ndo->ndo_snapend) { 3010f74e101Schristos /* Just bail if we don't have the whole chunk. */ 302c74ad251Schristos nd_print_trunc(ndo); 3030f74e101Schristos return; 3040f74e101Schristos } 3050e9868baSchristos if (length < sizeof(*ap)) { 306c74ad251Schristos ND_PRINT(" [|atp %u]", length); 3070e9868baSchristos return; 3080e9868baSchristos } 3090f74e101Schristos length -= sizeof(*ap); 310c74ad251Schristos control = GET_U_1(ap->control); 311c74ad251Schristos switch (control & 0xc0) { 3120f74e101Schristos 3130f74e101Schristos case atpReqCode: 314c74ad251Schristos ND_PRINT(" atp-req%s %u", 315c74ad251Schristos control & atpXO? " " : "*", 316c74ad251Schristos GET_BE_U_2(ap->transID)); 3170f74e101Schristos 318c74ad251Schristos atp_bitmap_print(ndo, GET_U_1(ap->bitmap)); 3190f74e101Schristos 3200f74e101Schristos if (length != 0) 321c74ad251Schristos ND_PRINT(" [len=%u]", length); 3220f74e101Schristos 323c74ad251Schristos switch (control & (atpEOM|atpSTS)) { 3240f74e101Schristos case atpEOM: 325c74ad251Schristos ND_PRINT(" [EOM]"); 3260f74e101Schristos break; 3270f74e101Schristos case atpSTS: 328c74ad251Schristos ND_PRINT(" [STS]"); 3290f74e101Schristos break; 3300f74e101Schristos case atpEOM|atpSTS: 331c74ad251Schristos ND_PRINT(" [EOM,STS]"); 3320f74e101Schristos break; 3330f74e101Schristos } 3340f74e101Schristos break; 3350f74e101Schristos 3360f74e101Schristos case atpRspCode: 337c74ad251Schristos ND_PRINT(" atp-resp%s%u:%u (%u)", 338c74ad251Schristos control & atpEOM? "*" : " ", 339c74ad251Schristos GET_BE_U_2(ap->transID), GET_U_1(ap->bitmap), 340c74ad251Schristos length); 341c74ad251Schristos switch (control & (atpXO|atpSTS)) { 3420f74e101Schristos case atpXO: 343c74ad251Schristos ND_PRINT(" [XO]"); 3440f74e101Schristos break; 3450f74e101Schristos case atpSTS: 346c74ad251Schristos ND_PRINT(" [STS]"); 3470f74e101Schristos break; 3480f74e101Schristos case atpXO|atpSTS: 349c74ad251Schristos ND_PRINT(" [XO,STS]"); 3500f74e101Schristos break; 3510f74e101Schristos } 3520f74e101Schristos break; 3530f74e101Schristos 3540f74e101Schristos case atpRelCode: 355c74ad251Schristos ND_PRINT(" atp-rel %u", GET_BE_U_2(ap->transID)); 3560f74e101Schristos 357c74ad251Schristos atp_bitmap_print(ndo, GET_U_1(ap->bitmap)); 3580f74e101Schristos 3590f74e101Schristos /* length should be zero */ 3600f74e101Schristos if (length) 361c74ad251Schristos ND_PRINT(" [len=%u]", length); 3620f74e101Schristos 3630f74e101Schristos /* there shouldn't be any control flags */ 364c74ad251Schristos if (control & (atpXO|atpEOM|atpSTS)) { 365c74ad251Schristos char c = '['; 366c74ad251Schristos if (control & atpXO) { 367c74ad251Schristos ND_PRINT("%cXO", c); 3680f74e101Schristos c = ','; 3690f74e101Schristos } 370c74ad251Schristos if (control & atpEOM) { 371c74ad251Schristos ND_PRINT("%cEOM", c); 3720f74e101Schristos c = ','; 3730f74e101Schristos } 374c74ad251Schristos if (control & atpSTS) { 375c74ad251Schristos ND_PRINT("%cSTS", c); 3760f74e101Schristos } 377c74ad251Schristos ND_PRINT("]"); 3780f74e101Schristos } 3790f74e101Schristos break; 3800f74e101Schristos 3810f74e101Schristos default: 382c74ad251Schristos ND_PRINT(" atp-0x%x %u (%u)", control, 383c74ad251Schristos GET_BE_U_2(ap->transID), length); 3840f74e101Schristos break; 3850f74e101Schristos } 386c74ad251Schristos data = GET_BE_U_4(ap->userData); 3870f74e101Schristos if (data != 0) 388c74ad251Schristos ND_PRINT(" 0x%x", data); 3890f74e101Schristos } 3900f74e101Schristos 3910f74e101Schristos static void 392b3a00663Schristos atp_bitmap_print(netdissect_options *ndo, 393c74ad251Schristos u_char bm) 3940f74e101Schristos { 395c74ad251Schristos u_int i; 3960f74e101Schristos 3970f74e101Schristos /* 3980f74e101Schristos * The '& 0xff' below is needed for compilers that want to sign 3990f74e101Schristos * extend a u_char, which is the case with the Ultrix compiler. 4000f74e101Schristos * (gcc is smart enough to eliminate it, at least on the Sparc). 4010f74e101Schristos */ 4020f74e101Schristos if ((bm + 1) & (bm & 0xff)) { 403c74ad251Schristos char c = '<'; 4040f74e101Schristos for (i = 0; bm; ++i) { 4050f74e101Schristos if (bm & 1) { 406c74ad251Schristos ND_PRINT("%c%u", c, i); 4070f74e101Schristos c = ','; 4080f74e101Schristos } 4090f74e101Schristos bm >>= 1; 4100f74e101Schristos } 411c74ad251Schristos ND_PRINT(">"); 4120f74e101Schristos } else { 4130f74e101Schristos for (i = 0; bm; ++i) 4140f74e101Schristos bm >>= 1; 4150f74e101Schristos if (i > 1) 416c74ad251Schristos ND_PRINT("<0-%u>", i - 1); 4170f74e101Schristos else 418c74ad251Schristos ND_PRINT("<0>"); 4190f74e101Schristos } 4200f74e101Schristos } 4210f74e101Schristos 4220f74e101Schristos static void 423b3a00663Schristos nbp_print(netdissect_options *ndo, 424c74ad251Schristos const struct atNBP *np, u_int length, u_short snet, 425c74ad251Schristos u_char snode, u_char skt) 4260f74e101Schristos { 427c74ad251Schristos const struct atNBPtuple *tp = 428fdccd7e4Schristos (const struct atNBPtuple *)((const u_char *)np + nbpHeaderSize); 429c74ad251Schristos uint8_t control; 430c74ad251Schristos u_int i; 4310f74e101Schristos const u_char *ep; 4320f74e101Schristos 4330f74e101Schristos if (length < nbpHeaderSize) { 434c74ad251Schristos ND_PRINT(" truncated-nbp %u", length); 4350f74e101Schristos return; 4360f74e101Schristos } 4370f74e101Schristos 4380f74e101Schristos length -= nbpHeaderSize; 4390f74e101Schristos if (length < 8) { 4400f74e101Schristos /* must be room for at least one tuple */ 441c74ad251Schristos ND_PRINT(" truncated-nbp %u", length + nbpHeaderSize); 4420f74e101Schristos return; 4430f74e101Schristos } 4440f74e101Schristos /* ep points to end of available data */ 445b3a00663Schristos ep = ndo->ndo_snapend; 4460f74e101Schristos if ((const u_char *)tp > ep) { 447c74ad251Schristos nd_print_trunc(ndo); 4480f74e101Schristos return; 4490f74e101Schristos } 450c74ad251Schristos control = GET_U_1(np->control); 451c74ad251Schristos switch (i = (control & 0xf0)) { 4520f74e101Schristos 4530f74e101Schristos case nbpBrRq: 4540f74e101Schristos case nbpLkUp: 455c74ad251Schristos ND_PRINT(i == nbpLkUp? " nbp-lkup %u:":" nbp-brRq %u:", 456c74ad251Schristos GET_U_1(np->id)); 4570f74e101Schristos if ((const u_char *)(tp + 1) > ep) { 458c74ad251Schristos nd_print_trunc(ndo); 4590f74e101Schristos return; 4600f74e101Schristos } 461b3a00663Schristos (void)nbp_name_print(ndo, tp, ep); 4620f74e101Schristos /* 4630f74e101Schristos * look for anomalies: the spec says there can only 4640f74e101Schristos * be one tuple, the address must match the source 4650f74e101Schristos * address and the enumerator should be zero. 4660f74e101Schristos */ 467c74ad251Schristos if ((control & 0xf) != 1) 468c74ad251Schristos ND_PRINT(" [ntup=%u]", control & 0xf); 469c74ad251Schristos if (GET_U_1(tp->enumerator)) 470c74ad251Schristos ND_PRINT(" [enum=%u]", GET_U_1(tp->enumerator)); 471c74ad251Schristos if (GET_BE_U_2(tp->net) != snet || 472c74ad251Schristos GET_U_1(tp->node) != snode || 473c74ad251Schristos GET_U_1(tp->skt) != skt) 474c74ad251Schristos ND_PRINT(" [addr=%s.%u]", 475c74ad251Schristos ataddr_string(ndo, GET_BE_U_2(tp->net), 476c74ad251Schristos GET_U_1(tp->node)), 477c74ad251Schristos GET_U_1(tp->skt)); 4780f74e101Schristos break; 4790f74e101Schristos 4800f74e101Schristos case nbpLkUpReply: 481c74ad251Schristos ND_PRINT(" nbp-reply %u:", GET_U_1(np->id)); 4820f74e101Schristos 4830f74e101Schristos /* print each of the tuples in the reply */ 484c74ad251Schristos for (i = control & 0xf; i != 0 && tp; i--) 485b3a00663Schristos tp = nbp_tuple_print(ndo, tp, ep, snet, snode, skt); 4860f74e101Schristos break; 4870f74e101Schristos 4880f74e101Schristos default: 489c74ad251Schristos ND_PRINT(" nbp-0x%x %u (%u)", control, GET_U_1(np->id), 490c74ad251Schristos length); 4910f74e101Schristos break; 4920f74e101Schristos } 4930f74e101Schristos } 4940f74e101Schristos 4950f74e101Schristos /* print a counted string */ 496c74ad251Schristos static const u_char * 497b3a00663Schristos print_cstring(netdissect_options *ndo, 498c74ad251Schristos const u_char *cp, const u_char *ep) 4990f74e101Schristos { 500c74ad251Schristos u_int length; 5010f74e101Schristos 502c74ad251Schristos if (cp >= ep) { 503c74ad251Schristos nd_print_trunc(ndo); 5040f74e101Schristos return (0); 5050f74e101Schristos } 506c74ad251Schristos length = GET_U_1(cp); 507c74ad251Schristos cp++; 5080f74e101Schristos 5090f74e101Schristos /* Spec says string can be at most 32 bytes long */ 5100f74e101Schristos if (length > 32) { 511c74ad251Schristos ND_PRINT("[len=%u]", length); 5120f74e101Schristos return (0); 5130f74e101Schristos } 514c74ad251Schristos while (length != 0) { 515c74ad251Schristos if (cp >= ep) { 516c74ad251Schristos nd_print_trunc(ndo); 5170f74e101Schristos return (0); 5180f74e101Schristos } 519c74ad251Schristos fn_print_char(ndo, GET_U_1(cp)); 520c74ad251Schristos cp++; 521c74ad251Schristos length--; 5220f74e101Schristos } 5230f74e101Schristos return (cp); 5240f74e101Schristos } 5250f74e101Schristos 5260f74e101Schristos static const struct atNBPtuple * 527b3a00663Schristos nbp_tuple_print(netdissect_options *ndo, 528c74ad251Schristos const struct atNBPtuple *tp, const u_char *ep, 529c74ad251Schristos u_short snet, u_char snode, u_char skt) 5300f74e101Schristos { 531c74ad251Schristos const struct atNBPtuple *tpn; 5320f74e101Schristos 5330f74e101Schristos if ((const u_char *)(tp + 1) > ep) { 534c74ad251Schristos nd_print_trunc(ndo); 5350f74e101Schristos return 0; 5360f74e101Schristos } 537b3a00663Schristos tpn = nbp_name_print(ndo, tp, ep); 5380f74e101Schristos 5390f74e101Schristos /* if the enumerator isn't 1, print it */ 540c74ad251Schristos if (GET_U_1(tp->enumerator) != 1) 541c74ad251Schristos ND_PRINT("(%u)", GET_U_1(tp->enumerator)); 5420f74e101Schristos 5430f74e101Schristos /* if the socket doesn't match the src socket, print it */ 544c74ad251Schristos if (GET_U_1(tp->skt) != skt) 545c74ad251Schristos ND_PRINT(" %u", GET_U_1(tp->skt)); 5460f74e101Schristos 5470f74e101Schristos /* if the address doesn't match the src address, it's an anomaly */ 548c74ad251Schristos if (GET_BE_U_2(tp->net) != snet || 549c74ad251Schristos GET_U_1(tp->node) != snode) 550c74ad251Schristos ND_PRINT(" [addr=%s]", 551c74ad251Schristos ataddr_string(ndo, GET_BE_U_2(tp->net), GET_U_1(tp->node))); 5520f74e101Schristos 5530f74e101Schristos return (tpn); 5540f74e101Schristos } 5550f74e101Schristos 5560f74e101Schristos static const struct atNBPtuple * 557b3a00663Schristos nbp_name_print(netdissect_options *ndo, 558c74ad251Schristos const struct atNBPtuple *tp, const u_char *ep) 5590f74e101Schristos { 560c74ad251Schristos const u_char *cp = (const u_char *)tp + nbpTupleSize; 5610f74e101Schristos 562c74ad251Schristos ND_PRINT(" "); 5630f74e101Schristos 5640f74e101Schristos /* Object */ 565c74ad251Schristos ND_PRINT("\""); 566b3a00663Schristos if ((cp = print_cstring(ndo, cp, ep)) != NULL) { 5670f74e101Schristos /* Type */ 568c74ad251Schristos ND_PRINT(":"); 569b3a00663Schristos if ((cp = print_cstring(ndo, cp, ep)) != NULL) { 5700f74e101Schristos /* Zone */ 571c74ad251Schristos ND_PRINT("@"); 572b3a00663Schristos if ((cp = print_cstring(ndo, cp, ep)) != NULL) 573c74ad251Schristos ND_PRINT("\""); 5740f74e101Schristos } 5750f74e101Schristos } 5760f74e101Schristos return ((const struct atNBPtuple *)cp); 5770f74e101Schristos } 5780f74e101Schristos 5790f74e101Schristos 5800f74e101Schristos #define HASHNAMESIZE 4096 5810f74e101Schristos 5820f74e101Schristos struct hnamemem { 583c74ad251Schristos u_int addr; 5840f74e101Schristos char *name; 5850f74e101Schristos struct hnamemem *nxt; 5860f74e101Schristos }; 5870f74e101Schristos 5880f74e101Schristos static struct hnamemem hnametable[HASHNAMESIZE]; 5890f74e101Schristos 5900f74e101Schristos static const char * 591b3a00663Schristos ataddr_string(netdissect_options *ndo, 592b3a00663Schristos u_short atnet, u_char athost) 5930f74e101Schristos { 594c74ad251Schristos struct hnamemem *tp, *tp2; 595c74ad251Schristos u_int i = (atnet << 8) | athost; 596870189d2Schristos char nambuf[256+1]; 5970f74e101Schristos static int first = 1; 5980f74e101Schristos FILE *fp; 5990f74e101Schristos 6000f74e101Schristos /* 601c74ad251Schristos * Are we doing address to name resolution? 6020f74e101Schristos */ 603c74ad251Schristos if (!ndo->ndo_nflag) { 604c74ad251Schristos /* 605c74ad251Schristos * Yes. Have we tried to open and read an AppleTalk 606c74ad251Schristos * number to name map file? 607c74ad251Schristos */ 608c74ad251Schristos if (!first) { 609c74ad251Schristos /* 610c74ad251Schristos * No; try to do so. 611c74ad251Schristos */ 612c74ad251Schristos first = 0; 613c74ad251Schristos fp = fopen("/etc/atalk.names", "r"); 614c74ad251Schristos if (fp != NULL) { 6150f74e101Schristos char line[256]; 616c74ad251Schristos u_int i1, i2; 6170f74e101Schristos 6180f74e101Schristos while (fgets(line, sizeof(line), fp)) { 619c74ad251Schristos if (line[0] == '\n' || line[0] == 0 || 620c74ad251Schristos line[0] == '#') 6210f74e101Schristos continue; 622c74ad251Schristos if (sscanf(line, "%u.%u %256s", &i1, 623c74ad251Schristos &i2, nambuf) == 3) 6240f74e101Schristos /* got a hostname. */ 6250e9868baSchristos i2 |= (i1 << 8); 626c74ad251Schristos else if (sscanf(line, "%u %256s", &i1, 627c74ad251Schristos nambuf) == 2) 6280f74e101Schristos /* got a net name */ 6290e9868baSchristos i2 = (i1 << 8) | 255; 6300f74e101Schristos else 6310f74e101Schristos continue; 6320f74e101Schristos 6330e9868baSchristos for (tp = &hnametable[i2 & (HASHNAMESIZE-1)]; 6340f74e101Schristos tp->nxt; tp = tp->nxt) 6350f74e101Schristos ; 6360e9868baSchristos tp->addr = i2; 637fdccd7e4Schristos tp->nxt = newhnamemem(ndo); 6380f74e101Schristos tp->name = strdup(nambuf); 639fdccd7e4Schristos if (tp->name == NULL) 640fdccd7e4Schristos (*ndo->ndo_error)(ndo, 641c74ad251Schristos S_ERR_ND_MEM_ALLOC, 642c74ad251Schristos "%s: strdup(nambuf)", __func__); 6430f74e101Schristos } 6440f74e101Schristos fclose(fp); 6450f74e101Schristos } 646c74ad251Schristos } 647c74ad251Schristos } 6480f74e101Schristos 649c74ad251Schristos /* 650c74ad251Schristos * Now try to look up the address in the table. 651c74ad251Schristos */ 6520f74e101Schristos for (tp = &hnametable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) 6530f74e101Schristos if (tp->addr == i) 6540f74e101Schristos return (tp->name); 6550f74e101Schristos 6560f74e101Schristos /* didn't have the node name -- see if we've got the net name */ 6570f74e101Schristos i |= 255; 6580f74e101Schristos for (tp2 = &hnametable[i & (HASHNAMESIZE-1)]; tp2->nxt; tp2 = tp2->nxt) 6590f74e101Schristos if (tp2->addr == i) { 6600f74e101Schristos tp->addr = (atnet << 8) | athost; 661fdccd7e4Schristos tp->nxt = newhnamemem(ndo); 662c74ad251Schristos (void)snprintf(nambuf, sizeof(nambuf), "%s.%u", 6630f74e101Schristos tp2->name, athost); 6640f74e101Schristos tp->name = strdup(nambuf); 665fdccd7e4Schristos if (tp->name == NULL) 666c74ad251Schristos (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, 667c74ad251Schristos "%s: strdup(nambuf)", __func__); 6680f74e101Schristos return (tp->name); 6690f74e101Schristos } 6700f74e101Schristos 6710f74e101Schristos tp->addr = (atnet << 8) | athost; 672fdccd7e4Schristos tp->nxt = newhnamemem(ndo); 6730f74e101Schristos if (athost != 255) 674c74ad251Schristos (void)snprintf(nambuf, sizeof(nambuf), "%u.%u", atnet, athost); 6750f74e101Schristos else 676c74ad251Schristos (void)snprintf(nambuf, sizeof(nambuf), "%u", atnet); 6770f74e101Schristos tp->name = strdup(nambuf); 678fdccd7e4Schristos if (tp->name == NULL) 679c74ad251Schristos (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, 680c74ad251Schristos "%s: strdup(nambuf)", __func__); 6810f74e101Schristos 6820f74e101Schristos return (tp->name); 6830f74e101Schristos } 6840f74e101Schristos 685870189d2Schristos static const struct tok skt2str[] = { 6860f74e101Schristos { rtmpSkt, "rtmp" }, /* routing table maintenance */ 6870f74e101Schristos { nbpSkt, "nis" }, /* name info socket */ 6880f74e101Schristos { echoSkt, "echo" }, /* AppleTalk echo protocol */ 6890f74e101Schristos { zipSkt, "zip" }, /* zone info protocol */ 6900f74e101Schristos { 0, NULL } 6910f74e101Schristos }; 6920f74e101Schristos 6930f74e101Schristos static const char * 694b3a00663Schristos ddpskt_string(netdissect_options *ndo, 695c74ad251Schristos u_int skt) 6960f74e101Schristos { 6970f74e101Schristos static char buf[8]; 6980f74e101Schristos 699b3a00663Schristos if (ndo->ndo_nflag) { 700c74ad251Schristos (void)snprintf(buf, sizeof(buf), "%u", skt); 7010f74e101Schristos return (buf); 7020f74e101Schristos } 703c74ad251Schristos return (tok2str(skt2str, "%u", skt)); 7040f74e101Schristos } 705