2 * Routines for NetWare's IPX
3 * Gilbert Ramirez <gram@verdict.uthscsa.edu>
5 * $Id: packet-ipx.c,v 1.18 1999/03/23 03:14:39 gram Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@unicom.net>
9 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
38 #include "packet-ipx.h"
39 #include "packet-ncp.h"
41 /* The information in this module (IPX, SPX, NCP) comes from:
42 NetWare LAN Analysis, Second Edition
43 Laura A. Chappell and Dan E. Hakes
45 Novell Press, San Jose.
48 And from the ncpfs source code by Volker Lendecke
53 dissect_spx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
56 dissect_ipxrip(const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
59 dissect_sap(const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
63 void (*func) (const u_char *, int, frame_data *, proto_tree *);
77 /* ================================================================= */
79 /* ================================================================= */
80 static struct port_info ports[] = {
81 { 0x0451, dissect_ncp, "NCP" },
82 { 0x0452, dissect_sap, "SAP" },
83 { 0x0453, dissect_ipxrip, "RIP" },
84 { 0x0455, NULL, "NetBIOS" },
85 { 0x0456, NULL, "Diagnostic" },
86 { 0x0457, NULL, "Serialization" },
87 { 0x0551, NULL, "NWLink SMB Name Query" },
88 { 0x0553, dissect_nwlink_dg,"NWLink SMB Datagram" },
89 { 0x055d, NULL, "Attachmate Gateway" },
90 { 0x4001, NULL, "IPX Message" },
91 { 0x0000, NULL, NULL }
95 port_text(guint16 port) {
98 while (ports[i].text != NULL) {
99 if (ports[i].port == port) {
100 return ports[i].text;
108 port_func(guint16 port) {
111 while (ports[i].text != NULL) {
112 if (ports[i].port == port) {
113 return ports[i].func;
121 ipx_packet_type(u_char val)
129 else if (val == 17) {
132 else if (val == 20) {
133 return "NetBIOS Broadcast";
135 else if (val >= 16 && val <= 31) {
136 return "Experimental Protocol";
144 ipxnet_to_string(const guint8 *ad)
146 static gchar str[3][12];
149 if (cur == &str[0][0]) {
151 } else if (cur == &str[1][0]) {
157 sprintf(cur, "%02X %02X %02X %02X", ad[0], ad[1], ad[2], ad[3]);
162 ipx_addr_to_str(guint32 net, const guint8 *ad)
164 static gchar str[3][22];
167 if (cur == &str[0][0]) {
169 } else if (cur == &str[1][0]) {
175 sprintf(cur, "%X.%02x%02x%02x%02x%02x%02x", net,
176 ad[0], ad[1], ad[2], ad[3], ad[4], ad[5]);
181 dissect_ipx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
183 proto_tree *ipx_tree;
185 guint8 ipx_type, ipx_hops;
186 guint16 ipx_checksum, ipx_length;
187 guint8 *ipx_snode, *ipx_dnode, *ipx_snet, *ipx_dnet;
189 gchar *str_dnet, *str_snet;
190 guint16 ipx_dsocket, ipx_ssocket;
191 void (*dissect) (const u_char *, int, frame_data *, proto_tree *);
193 /* Calculate here for use in pinfo and in tree */
194 ipx_dnet = (guint8*)&pd[offset+6];
195 ipx_snet = (guint8*)&pd[offset+18];
196 str_dnet = ipxnet_to_string(ipx_dnet);
197 str_snet = ipxnet_to_string(ipx_snet);
198 ipx_dsocket = pntohs(&pd[offset+16]);
199 ipx_ssocket = pntohs(&pd[offset+28]);
200 ipx_dnode = (guint8*)&pd[offset+10];
201 ipx_snode = (guint8*)&pd[offset+22];
202 ipx_type = pd[offset+5];
204 if (check_col(fd, COL_RES_DL_DST))
205 col_add_str(fd, COL_RES_DL_DST,
206 ipx_addr_to_str(pntohl(ipx_dnet), ipx_dnode));
207 if (check_col(fd, COL_RES_DL_SRC))
208 col_add_str(fd, COL_RES_DL_SRC,
209 ipx_addr_to_str(pntohl(ipx_snet), ipx_snode));
211 if (check_col(fd, COL_PROTOCOL))
212 col_add_str(fd, COL_PROTOCOL, "IPX");
213 if (check_col(fd, COL_INFO))
214 col_add_fstr(fd, COL_INFO, "%s (0x%04X)", port_text(ipx_dsocket),
218 ipx_checksum = pntohs(&pd[offset]);
219 ipx_length = pntohs(&pd[offset+2]);
220 ipx_hops = pd[offset+4];
222 ti = proto_tree_add_item(tree, offset, 30,
223 "Internetwork Packet Exchange");
224 ipx_tree = proto_tree_new();
225 proto_item_add_subtree(ti, ipx_tree, ETT_IPX);
226 proto_tree_add_item(ipx_tree, offset, 2, "Checksum: 0x%04x",
228 proto_tree_add_item(ipx_tree, offset+2, 2, "Length: %d bytes",
230 proto_tree_add_item(ipx_tree, offset+4, 1, "Transport Control: %d hops",
232 proto_tree_add_item(ipx_tree, offset+5, 1, "Packet Type: %s",
233 ipx_packet_type(ipx_type));
234 proto_tree_add_item(ipx_tree, offset+6, 4, "Destination Network: %s",
236 proto_tree_add_item(ipx_tree, offset+10, 6, "Destination Node: %s",
237 ether_to_str(ipx_dnode));
238 proto_tree_add_item(ipx_tree, offset+16, 2,
239 "Destination Socket: %s (0x%04X)", port_text(ipx_dsocket),
241 proto_tree_add_item(ipx_tree, offset+18, 4, "Source Network: %s",
243 proto_tree_add_item(ipx_tree, offset+22, 6, "Source Node: %s",
244 ether_to_str(ipx_snode));
245 proto_tree_add_item(ipx_tree, offset+28, 2,
246 "Source Socket: %s (0x%04X)", port_text(ipx_ssocket), ipx_ssocket);
252 dissect_spx(pd, offset, fd, tree);
256 if (pntohl(ipx_dnode) == 0 && pntohs(ipx_dnode + 4) == 1)
257 nw_server_address = pntohl(ipx_dnet);
258 else if (pntohl(ipx_snode) == 0 && pntohs(ipx_snode + 4) == 1)
259 nw_server_address = pntohl(ipx_snet);
261 nw_server_address = 0;
263 dissect_ncp(pd, offset, fd, tree);
266 case 20: /* NetBIOS */
267 if (ipx_dsocket == 0x0455) {
268 dissect_nbipx_ns(pd, offset, fd, tree);
271 /* else fall through */
273 case 0: /* IPX, fall through to default */
275 dissect = port_func(ipx_dsocket);
277 dissect(pd, offset, fd, tree);
280 dissect = port_func(ipx_ssocket);
282 dissect(pd, offset, fd, tree);
285 dissect_data(pd, offset, fd, tree);
293 /* ================================================================= */
295 /* ================================================================= */
297 spx_conn_ctrl(u_char ctrl)
301 static struct conn_info conns[] = {
302 { 0x10, "End-of-Message" },
303 { 0x20, "Attention" },
304 { 0x40, "Acknowledgment Required"},
305 { 0x80, "System Packet"}
308 while (conns[i].text != NULL) {
309 if (conns[i].ctrl == ctrl) {
310 return conns[i].text;
318 spx_datastream(u_char type)
322 return "End-of-Connection";
324 return "End-of-Connection Acknowledgment";
326 return "Client-Defined";
331 dissect_spx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
333 proto_tree *spx_tree;
336 if (check_col(fd, COL_PROTOCOL))
337 col_add_str(fd, COL_PROTOCOL, "SPX");
338 if (check_col(fd, COL_INFO))
339 col_add_str(fd, COL_INFO, "SPX");
342 ti = proto_tree_add_item(tree, offset, 12, "Sequenced Packet Exchange");
343 spx_tree = proto_tree_new();
344 proto_item_add_subtree(ti, spx_tree, ETT_SPX);
346 proto_tree_add_item(spx_tree, offset, 1,
347 "Connection Control: %s (0x%02X)",
348 spx_conn_ctrl(pd[offset]), pd[offset]);
350 proto_tree_add_item(spx_tree, offset+1, 1,
351 "Datastream Type: %s (0x%02X)",
352 spx_datastream(pd[offset+1]), pd[offset+1]);
354 proto_tree_add_item(spx_tree, offset+2, 2,
355 "Source Connection ID: %d", pntohs( &pd[offset+2] ) );
357 proto_tree_add_item(spx_tree, offset+4, 2,
358 "Destination Connection ID: %d", pntohs( &pd[offset+4] ) );
360 proto_tree_add_item(spx_tree, offset+6, 2,
361 "Sequence Number: %d", pntohs( &pd[offset+6] ) );
363 proto_tree_add_item(spx_tree, offset+8, 2,
364 "Acknowledgment Number: %d", pntohs( &pd[offset+8] ) );
366 proto_tree_add_item(spx_tree, offset+10, 2,
367 "Allocation Number: %d", pntohs( &pd[offset+10] ) );
370 dissect_data(pd, offset, fd, tree);
374 /* ================================================================= */
376 /* ================================================================= */
378 dissect_ipxrip(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
380 proto_tree *rip_tree;
383 struct ipx_rt_def route;
386 char *rip_type[2] = { "Request", "Response" };
388 operation = pntohs(&pd[offset]) - 1;
390 if (check_col(fd, COL_PROTOCOL))
391 col_add_str(fd, COL_PROTOCOL, "IPX RIP");
392 if (check_col(fd, COL_PROTOCOL)) {
394 col_add_str(fd, COL_INFO, rip_type[operation]);
397 col_add_str(fd, COL_INFO, "Unknown Packet Type");
402 ti = proto_tree_add_item(tree, offset, END_OF_FRAME,
403 "IPX Routing Information Protocol");
404 rip_tree = proto_tree_new();
405 proto_item_add_subtree(ti, rip_tree, ETT_IPXRIP);
408 proto_tree_add_item(rip_tree, offset, 2,
409 "RIP packet type: %s", rip_type[operation]);
412 proto_tree_add_item(rip_tree, offset, 2, "Unknown RIP packet type");
415 for (cursor = offset + 2; cursor < fd->cap_len; cursor += 8) {
416 memcpy(&route.network, &pd[cursor], 4);
417 route.hops = pntohs(&pd[cursor+4]);
418 route.ticks = pntohs(&pd[cursor+6]);
420 if (operation == IPX_RIP_REQUEST - 1) {
421 proto_tree_add_item(rip_tree, cursor, 8,
422 "Route Vector: %s, %d hop%s, %d tick%s",
423 ipxnet_to_string((guint8*)&route.network),
424 route.hops, route.hops == 1 ? "" : "s",
425 route.ticks, route.ticks == 1 ? "" : "s");
428 proto_tree_add_item(rip_tree, cursor, 8,
429 "Route Vector: %s, %d hop%s, %d tick%s (%d ms)",
430 ipxnet_to_string((guint8*)&route.network),
431 route.hops, route.hops == 1 ? "" : "s",
432 route.ticks, route.ticks == 1 ? "" : "s",
433 route.ticks * 1000 / 18);
441 /* ================================================================= */
443 /* ================================================================= */
445 server_type(guint16 type)
449 /* some of these are from ncpfs, others are from the book */
450 static struct server_info servers[] = {
452 { 0x0002, "User Group" },
453 { 0x0003, "Print Queue" },
454 { 0x0004, "File server" },
455 { 0x0005, "Job server" },
456 { 0x0007, "Print server" },
457 { 0x0008, "Archive server" },
458 { 0x0009, "Archive server" },
459 { 0x000a, "Job queue" },
460 { 0x000b, "Administration" },
461 { 0x0021, "NAS SNA gateway" },
462 { 0x0024, "Remote bridge" },
463 { 0x0026, "Bridge server" },
464 { 0x0027, "TCP/IP gateway" },
465 { 0x002d, "Time Synchronization VAP" },
466 { 0x002e, "Archive Server Dynamic SAP" },
467 { 0x0047, "Advertising print server" },
468 { 0x004b, "Btrieve VAP 5.0" },
469 { 0x004c, "SQL VAP" },
470 { 0x0050, "Btrieve VAP" },
471 { 0x0053, "Print Queue VAP" },
472 { 0x007a, "TES NetWare for VMS" },
473 { 0x0098, "NetWare access server" },
474 { 0x009a, "Named Pipes server" },
475 { 0x009e, "Portable NetWare Unix" },
476 { 0x0107, "NetWare 386" },
477 { 0x0111, "Test server" },
478 { 0x0133, "NetWare Name Service" },
479 { 0x0166, "NetWare management" },
480 { 0x026a, "NetWare management" },
481 { 0x026b, "Time synchronization" },
482 { 0x0278, "NetWare Directory server" },
483 { 0x055d, "Attachmate SNA gateway" },
487 while (servers[i].text != NULL) {
488 if (servers[i].type == type) {
489 return servers[i].text;
497 dissect_sap(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
499 proto_tree *sap_tree, *s_tree;
502 struct sap_query query;
503 struct sap_server_ident server;
505 char *sap_type[4] = { "General Query", "General Response",
506 "Nearest Query", "Nearest Response" };
508 query.query_type = pntohs(&pd[offset]);
509 query.server_type = pntohs(&pd[offset+2]);
511 if (check_col(fd, COL_PROTOCOL))
512 col_add_str(fd, COL_PROTOCOL, "SAP");
513 if (check_col(fd, COL_INFO)) {
514 if (query.query_type < 4) {
515 col_add_str(fd, COL_INFO, sap_type[query.query_type - 1]);
518 col_add_str(fd, COL_INFO, "Unknown Packet Type");
523 ti = proto_tree_add_item(tree, offset, END_OF_FRAME,
524 "Service Advertising Protocol");
525 sap_tree = proto_tree_new();
526 proto_item_add_subtree(ti, sap_tree, ETT_IPXSAP);
528 if (query.query_type < 4) {
529 proto_tree_add_item(sap_tree, offset, 2, sap_type[query.query_type - 1]);
532 proto_tree_add_item(sap_tree, offset, 2,
533 "Unknown SAP Packet Type %d", query.query_type);
536 if (query.query_type == IPX_SAP_GENERAL_RESPONSE ||
537 query.query_type == IPX_SAP_NEAREST_RESPONSE) { /* responses */
539 for (cursor = offset + 2; (cursor + 64) <= fd->cap_len; cursor += 64) {
540 server.server_type = pntohs(&pd[cursor]);
541 memcpy(server.server_name, &pd[cursor+2], 48);
542 memcpy(&server.server_network, &pd[cursor+50], 4);
543 memcpy(&server.server_node, &pd[cursor+54], 6);
544 server.server_port = pntohs(&pd[cursor+60]);
545 server.intermediate_network = pntohs(&pd[cursor+62]);
547 ti = proto_tree_add_item(sap_tree, cursor+2, 48,
548 "Server Name: %s", server.server_name);
549 s_tree = proto_tree_new();
550 proto_item_add_subtree(ti, s_tree, ETT_IPXSAP_SERVER);
552 proto_tree_add_item(s_tree, cursor, 2, "Server Type: %s (0x%04X)",
553 server_type(server.server_type), server.server_type);
554 proto_tree_add_item(s_tree, cursor+50, 4, "Network: %s",
555 ipxnet_to_string((guint8*)&pd[cursor+50]));
556 proto_tree_add_item(s_tree, cursor+54, 6, "Node: %s",
557 ether_to_str((guint8*)&pd[cursor+54]));
558 proto_tree_add_item(s_tree, cursor+60, 2, "Socket: %s (0x%04X)",
559 port_text(server.server_port), server.server_port);
560 proto_tree_add_item(s_tree, cursor+62, 2,
561 "Intermediate Networks: %d",
562 server.intermediate_network);
566 proto_tree_add_item(sap_tree, offset+2, 2, "Server Type: %s (0x%04X)",
567 server_type(query.server_type), query.server_type);