xref: /netbsd-src/external/bsd/tcpdump/dist/print-ipx.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
1 /*
2  * Copyright (c) 1994, 1995, 1996
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.
20  *
21  * Contributed by Brad Parker (brad@fcr.com).
22  */
23 
24 /* \summary: Novell IPX printer */
25 
26 #include <sys/cdefs.h>
27 #ifndef lint
28 __RCSID("$NetBSD: print-ipx.c,v 1.8 2024/09/02 16:15:31 christos Exp $");
29 #endif
30 
31 #include <config.h>
32 
33 #include "netdissect-stdinc.h"
34 
35 #include <stdio.h>
36 
37 #define ND_LONGJMP_FROM_TCHECK
38 #include "netdissect.h"
39 #include "addrtoname.h"
40 #include "extract.h"
41 
42 /* well-known sockets */
43 #define	IPX_SKT_NCP		0x0451
44 #define	IPX_SKT_SAP		0x0452
45 #define	IPX_SKT_RIP		0x0453
46 #define	IPX_SKT_NETBIOS		0x0455
47 #define	IPX_SKT_DIAGNOSTICS	0x0456
48 #define	IPX_SKT_NWLINK_DGM	0x0553	/* NWLink datagram, may contain SMB */
49 #define	IPX_SKT_EIGRP		0x85be	/* Cisco EIGRP over IPX */
50 
51 /* IPX transport header */
52 struct ipxHdr {
53     nd_uint16_t	cksum;		/* Checksum */
54     nd_uint16_t	length;		/* Length, in bytes, including header */
55     nd_uint8_t	tCtl;		/* Transport Control (i.e. hop count) */
56     nd_uint8_t	pType;		/* Packet Type (i.e. level 2 protocol) */
57     nd_uint32_t	dstNet;		/* destination net */
58     nd_mac_addr	dstNode;	/* destination node */
59     nd_uint16_t	dstSkt;		/* destination socket */
60     nd_uint32_t	srcNet;		/* source net */
61     nd_mac_addr	srcNode;	/* source node */
62     nd_uint16_t	srcSkt;		/* source socket */
63 };
64 
65 #define ipxSize	30
66 
67 static const char *ipxaddr_string(netdissect_options *, uint32_t, const u_char *);
68 static void ipx_decode(netdissect_options *, const struct ipxHdr *, const u_char *, u_int);
69 static void ipx_sap_print(netdissect_options *, const u_char *, u_int);
70 static void ipx_rip_print(netdissect_options *, const u_char *, u_int);
71 
72 /*
73  * Print IPX datagram packets.
74  */
75 void
76 ipx_print(netdissect_options *ndo, const u_char *p, u_int length)
77 {
78 	const struct ipxHdr *ipx = (const struct ipxHdr *)p;
79 
80 	ndo->ndo_protocol = "ipx";
81 	if (!ndo->ndo_eflag)
82 		ND_PRINT("IPX ");
83 
84 	ND_PRINT("%s.%04x > ",
85 		     ipxaddr_string(ndo, GET_BE_U_4(ipx->srcNet), ipx->srcNode),
86 		     GET_BE_U_2(ipx->srcSkt));
87 
88 	ND_PRINT("%s.%04x: ",
89 		     ipxaddr_string(ndo, GET_BE_U_4(ipx->dstNet), ipx->dstNode),
90 		     GET_BE_U_2(ipx->dstSkt));
91 
92 	/* take length from ipx header */
93 	length = GET_BE_U_2(ipx->length);
94 
95 	if (length < ipxSize) {
96 		ND_PRINT("[length %u < %u]", length, ipxSize);
97 		nd_print_invalid(ndo);
98 		return;
99 	}
100 	ipx_decode(ndo, ipx, p + ipxSize, length - ipxSize);
101 }
102 
103 static const char *
104 ipxaddr_string(netdissect_options *ndo, uint32_t net, const u_char *node)
105 {
106     static char line[256];
107 
108     snprintf(line, sizeof(line), "%08x.%02x:%02x:%02x:%02x:%02x:%02x",
109 	    net, GET_U_1(node), GET_U_1(node + 1),
110 	    GET_U_1(node + 2), GET_U_1(node + 3),
111 	    GET_U_1(node + 4), GET_U_1(node + 5));
112 
113     return line;
114 }
115 
116 static void
117 ipx_decode(netdissect_options *ndo, const struct ipxHdr *ipx, const u_char *datap, u_int length)
118 {
119     u_short dstSkt;
120 
121     dstSkt = GET_BE_U_2(ipx->dstSkt);
122     switch (dstSkt) {
123       case IPX_SKT_NCP:
124 	ND_PRINT("ipx-ncp %u", length);
125 	break;
126       case IPX_SKT_SAP:
127 	ipx_sap_print(ndo, datap, length);
128 	break;
129       case IPX_SKT_RIP:
130 	ipx_rip_print(ndo, datap, length);
131 	break;
132       case IPX_SKT_NETBIOS:
133 	ND_PRINT("ipx-netbios %u", length);
134 #ifdef ENABLE_SMB
135 	ipx_netbios_print(ndo, datap, length);
136 #endif
137 	break;
138       case IPX_SKT_DIAGNOSTICS:
139 	ND_PRINT("ipx-diags %u", length);
140 	break;
141       case IPX_SKT_NWLINK_DGM:
142 	ND_PRINT("ipx-nwlink-dgm %u", length);
143 #ifdef ENABLE_SMB
144 	ipx_netbios_print(ndo, datap, length);
145 #endif
146 	break;
147       case IPX_SKT_EIGRP:
148 	eigrp_print(ndo, datap, length);
149 	break;
150       default:
151 	ND_PRINT("ipx-#%x %u", dstSkt, length);
152 	break;
153     }
154 }
155 
156 static void
157 ipx_sap_print(netdissect_options *ndo, const u_char *ipx, u_int length)
158 {
159     int command, i;
160 
161     command = GET_BE_U_2(ipx);
162     ND_ICHECK_U(length, <, 2);
163     ipx += 2;
164     length -= 2;
165 
166     switch (command) {
167       case 1:
168       case 3:
169 	if (command == 1)
170 	    ND_PRINT("ipx-sap-req");
171 	else
172 	    ND_PRINT("ipx-sap-nearest-req");
173 
174 	ND_PRINT(" %s", ipxsap_string(ndo, htons(GET_BE_U_2(ipx))));
175 	break;
176 
177       case 2:
178       case 4:
179 	if (command == 2)
180 	    ND_PRINT("ipx-sap-resp");
181 	else
182 	    ND_PRINT("ipx-sap-nearest-resp");
183 
184 	for (i = 0; i < 8 && length != 0; i++) {
185 	    ND_TCHECK_2(ipx);
186 	    if (length < 2)
187 		goto invalid;
188 	    ND_PRINT(" %s '", ipxsap_string(ndo, htons(GET_BE_U_2(ipx))));
189 	    ipx += 2;
190 	    length -= 2;
191 	    if (length < 48) {
192 		ND_PRINT("'");
193 		goto invalid;
194 	    }
195 	    nd_printjnp(ndo, ipx, 48);
196 	    ND_PRINT("'");
197 	    ipx += 48;
198 	    length -= 48;
199 	    /*
200 	     * 10 bytes of IPX address.
201 	     */
202 	    ND_TCHECK_LEN(ipx, 10);
203 	    if (length < 10)
204 		goto invalid;
205 	    ND_PRINT(" addr %s",
206 		ipxaddr_string(ndo, GET_BE_U_4(ipx), ipx + 4));
207 	    ipx += 10;
208 	    length -= 10;
209 	    /*
210 	     * 2 bytes of socket and 2 bytes of number of intermediate
211 	     * networks.
212 	     */
213 	    ND_TCHECK_4(ipx);
214 	    if (length < 4)
215 		goto invalid;
216 	    ipx += 4;
217 	    length -= 4;
218 	}
219 	break;
220       default:
221 	ND_PRINT("ipx-sap-?%x", command);
222 	break;
223     }
224     return;
225 
226 invalid:
227     nd_print_invalid(ndo);
228 }
229 
230 static void
231 ipx_rip_print(netdissect_options *ndo, const u_char *ipx, u_int length)
232 {
233     int command, i;
234 
235     command = GET_BE_U_2(ipx);
236     ND_ICHECK_U(length, <, 2);
237     ipx += 2;
238     length -= 2;
239 
240     switch (command) {
241       case 1:
242 	ND_PRINT("ipx-rip-req");
243 	if (length != 0) {
244 	    if (length < 8)
245 		goto invalid;
246 	    ND_PRINT(" %08x/%u.%u", GET_BE_U_4(ipx),
247 			 GET_BE_U_2(ipx + 4), GET_BE_U_2(ipx + 6));
248 	}
249 	break;
250       case 2:
251 	ND_PRINT("ipx-rip-resp");
252 	for (i = 0; i < 50 && length != 0; i++) {
253 	    if (length < 8)
254 		goto invalid;
255 	    ND_PRINT(" %08x/%u.%u", GET_BE_U_4(ipx),
256 			 GET_BE_U_2(ipx + 4), GET_BE_U_2(ipx + 6));
257 
258 	    ipx += 8;
259 	    length -= 8;
260 	}
261 	break;
262       default:
263 	ND_PRINT("ipx-rip-?%x", command);
264 	break;
265     }
266     return;
267 
268 invalid:
269     nd_print_invalid(ndo);
270 }
271