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