2 * Routines for NetWare's IPX
3 * Gilbert Ramirez <gram@verdict.uthscsa.edu>
5 * $Id: packet-ipx.c,v 1.21 1999/07/07 22:51:45 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, int max_data);
56 dissect_ipxrip(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int
60 dissect_sap(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int
65 void (*func) (const u_char *, int, frame_data *, proto_tree *, int);
79 /* ================================================================= */
81 /* ================================================================= */
82 static struct port_info ports[] = {
83 { 0x0451, dissect_ncp, "NCP" },
84 { 0x0452, dissect_sap, "SAP" },
85 { 0x0453, dissect_ipxrip, "RIP" },
86 { 0x0455, NULL, "NetBIOS" },
87 { 0x0456, NULL, "Diagnostic" },
88 { 0x0457, NULL, "Serialization" },
89 { 0x0551, NULL, "NWLink SMB Name Query" },
90 { 0x0553, dissect_nwlink_dg, "NWLink SMB Datagram" },
91 { 0x055d, NULL, "Attachmate Gateway" },
92 { 0x4001, NULL, "IPX Message" },
93 { 0x0000, NULL, NULL }
97 port_text(guint16 port) {
100 while (ports[i].text != NULL) {
101 if (ports[i].port == port) {
102 return ports[i].text;
110 port_func(guint16 port) {
113 while (ports[i].text != NULL) {
114 if (ports[i].port == port) {
115 return ports[i].func;
123 ipx_packet_type(u_char val)
131 else if (val == 17) {
134 else if (val == 20) {
135 return "NetBIOS Broadcast";
137 else if (val >= 16 && val <= 31) {
138 return "Experimental Protocol";
146 ipxnet_to_string(const guint8 *ad)
148 static gchar str[3][12];
151 if (cur == &str[0][0]) {
153 } else if (cur == &str[1][0]) {
159 sprintf(cur, "%02X %02X %02X %02X", ad[0], ad[1], ad[2], ad[3]);
164 ipx_addr_to_str(guint32 net, const guint8 *ad)
166 static gchar str[3][22];
169 if (cur == &str[0][0]) {
171 } else if (cur == &str[1][0]) {
177 sprintf(cur, "%X.%02x%02x%02x%02x%02x%02x", net,
178 ad[0], ad[1], ad[2], ad[3], ad[4], ad[5]);
183 dissect_ipx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
185 proto_tree *ipx_tree;
187 guint8 ipx_type, ipx_hops;
188 guint16 ipx_checksum, ipx_length;
189 guint8 *ipx_snode, *ipx_dnode, *ipx_snet, *ipx_dnet;
191 gchar *str_dnet, *str_snet;
192 guint16 ipx_dsocket, ipx_ssocket;
193 void (*dissect) (const u_char *, int, frame_data *, proto_tree *, int);
196 /* Calculate here for use in pinfo and in tree */
197 ipx_dnet = (guint8*)&pd[offset+6];
198 ipx_snet = (guint8*)&pd[offset+18];
199 str_dnet = ipxnet_to_string(ipx_dnet);
200 str_snet = ipxnet_to_string(ipx_snet);
201 ipx_dsocket = pntohs(&pd[offset+16]);
202 ipx_ssocket = pntohs(&pd[offset+28]);
203 ipx_dnode = (guint8*)&pd[offset+10];
204 ipx_snode = (guint8*)&pd[offset+22];
205 ipx_type = pd[offset+5];
206 ipx_length = pntohs(&pd[offset+2]);
207 max_data = ipx_length - 30;
209 if (check_col(fd, COL_RES_DL_DST))
210 col_add_str(fd, COL_RES_DL_DST,
211 ipx_addr_to_str(pntohl(ipx_dnet), ipx_dnode));
212 if (check_col(fd, COL_RES_DL_SRC))
213 col_add_str(fd, COL_RES_DL_SRC,
214 ipx_addr_to_str(pntohl(ipx_snet), ipx_snode));
216 if (check_col(fd, COL_PROTOCOL))
217 col_add_str(fd, COL_PROTOCOL, "IPX");
218 if (check_col(fd, COL_INFO))
219 col_add_fstr(fd, COL_INFO, "%s (0x%04X)", port_text(ipx_dsocket),
223 ipx_checksum = pntohs(&pd[offset]);
224 ipx_hops = pd[offset+4];
226 ti = proto_tree_add_text(tree, offset, 30,
227 "Internetwork Packet Exchange");
228 ipx_tree = proto_item_add_subtree(ti, ETT_IPX);
229 proto_tree_add_text(ipx_tree, offset, 2, "Checksum: 0x%04x",
231 proto_tree_add_text(ipx_tree, offset+2, 2, "Length: %d bytes",
233 proto_tree_add_text(ipx_tree, offset+4, 1, "Transport Control: %d hops",
235 proto_tree_add_text(ipx_tree, offset+5, 1, "Packet Type: %s",
236 ipx_packet_type(ipx_type));
237 proto_tree_add_text(ipx_tree, offset+6, 4, "Destination Network: %s",
239 proto_tree_add_text(ipx_tree, offset+10, 6, "Destination Node: %s",
240 ether_to_str(ipx_dnode));
241 proto_tree_add_text(ipx_tree, offset+16, 2,
242 "Destination Socket: %s (0x%04X)", port_text(ipx_dsocket),
244 proto_tree_add_text(ipx_tree, offset+18, 4, "Source Network: %s",
246 proto_tree_add_text(ipx_tree, offset+22, 6, "Source Node: %s",
247 ether_to_str(ipx_snode));
248 proto_tree_add_text(ipx_tree, offset+28, 2,
249 "Source Socket: %s (0x%04X)", port_text(ipx_ssocket), ipx_ssocket);
255 dissect_spx(pd, offset, fd, tree, max_data);
259 /* Is the destination node 00:00:00:00:00:01 ? */
260 if (pntohl(ipx_dnode) == 0 && pntohs(ipx_dnode + 4) == 1)
261 nw_server_address = pntohl(ipx_dnet);
263 /* Is the source node 00:00:00:00:00:01 ? */
264 else if (pntohl(ipx_snode) == 0 && pntohs(ipx_snode + 4) == 1)
265 nw_server_address = pntohl(ipx_snet);
267 nw_server_address = 0;
269 dissect_ncp(pd, offset, fd, tree, max_data);
272 case 20: /* NetBIOS */
273 if (ipx_dsocket == 0x0455) {
274 dissect_nbipx_ns(pd, offset, fd, tree, max_data);
277 /* else fall through */
279 case 0: /* IPX, fall through to default */
281 dissect = port_func(ipx_dsocket);
283 dissect(pd, offset, fd, tree, max_data);
286 dissect = port_func(ipx_ssocket);
288 dissect(pd, offset, fd, tree, max_data);
291 dissect_data(pd, offset, fd, tree);
299 /* ================================================================= */
301 /* ================================================================= */
303 spx_conn_ctrl(u_char ctrl)
307 static struct conn_info conns[] = {
308 { 0x10, "End-of-Message" },
309 { 0x20, "Attention" },
310 { 0x40, "Acknowledgment Required"},
311 { 0x80, "System Packet"}
314 while (conns[i].text != NULL) {
315 if (conns[i].ctrl == ctrl) {
316 return conns[i].text;
324 spx_datastream(u_char type)
328 return "End-of-Connection";
330 return "End-of-Connection Acknowledgment";
332 return "Client-Defined";
337 dissect_spx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int
340 proto_tree *spx_tree;
343 if (check_col(fd, COL_PROTOCOL))
344 col_add_str(fd, COL_PROTOCOL, "SPX");
345 if (check_col(fd, COL_INFO))
346 col_add_str(fd, COL_INFO, "SPX");
349 ti = proto_tree_add_text(tree, offset, 12, "Sequenced Packet Exchange");
350 spx_tree = proto_item_add_subtree(ti, ETT_SPX);
352 proto_tree_add_text(spx_tree, offset, 1,
353 "Connection Control: %s (0x%02X)",
354 spx_conn_ctrl(pd[offset]), pd[offset]);
356 proto_tree_add_text(spx_tree, offset+1, 1,
357 "Datastream Type: %s (0x%02X)",
358 spx_datastream(pd[offset+1]), pd[offset+1]);
360 proto_tree_add_text(spx_tree, offset+2, 2,
361 "Source Connection ID: %d", pntohs( &pd[offset+2] ) );
363 proto_tree_add_text(spx_tree, offset+4, 2,
364 "Destination Connection ID: %d", pntohs( &pd[offset+4] ) );
366 proto_tree_add_text(spx_tree, offset+6, 2,
367 "Sequence Number: %d", pntohs( &pd[offset+6] ) );
369 proto_tree_add_text(spx_tree, offset+8, 2,
370 "Acknowledgment Number: %d", pntohs( &pd[offset+8] ) );
372 proto_tree_add_text(spx_tree, offset+10, 2,
373 "Allocation Number: %d", pntohs( &pd[offset+10] ) );
376 dissect_data(pd, offset, fd, tree);
380 /* ================================================================= */
382 /* ================================================================= */
384 dissect_ipxrip(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
387 proto_tree *rip_tree;
390 struct ipx_rt_def route;
393 char *rip_type[2] = { "Request", "Response" };
395 operation = pntohs(&pd[offset]) - 1;
397 if (check_col(fd, COL_PROTOCOL))
398 col_add_str(fd, COL_PROTOCOL, "IPX RIP");
399 if (check_col(fd, COL_PROTOCOL)) {
401 col_add_str(fd, COL_INFO, rip_type[operation]);
404 col_add_str(fd, COL_INFO, "Unknown Packet Type");
409 ti = proto_tree_add_text(tree, offset, END_OF_FRAME,
410 "IPX Routing Information Protocol");
411 rip_tree = proto_item_add_subtree(ti, ETT_IPXRIP);
414 proto_tree_add_text(rip_tree, offset, 2,
415 "RIP packet type: %s", rip_type[operation]);
418 proto_tree_add_text(rip_tree, offset, 2, "Unknown RIP packet type");
421 for (cursor = offset + 2; cursor < fd->cap_len; cursor += 8) {
422 memcpy(&route.network, &pd[cursor], 4);
423 route.hops = pntohs(&pd[cursor+4]);
424 route.ticks = pntohs(&pd[cursor+6]);
426 if (operation == IPX_RIP_REQUEST - 1) {
427 proto_tree_add_text(rip_tree, cursor, 8,
428 "Route Vector: %s, %d hop%s, %d tick%s",
429 ipxnet_to_string((guint8*)&route.network),
430 route.hops, route.hops == 1 ? "" : "s",
431 route.ticks, route.ticks == 1 ? "" : "s");
434 proto_tree_add_text(rip_tree, cursor, 8,
435 "Route Vector: %s, %d hop%s, %d tick%s (%d ms)",
436 ipxnet_to_string((guint8*)&route.network),
437 route.hops, route.hops == 1 ? "" : "s",
438 route.ticks, route.ticks == 1 ? "" : "s",
439 route.ticks * 1000 / 18);
447 /* ================================================================= */
449 /* ================================================================= */
451 server_type(guint16 type)
455 /* some of these are from ncpfs, others are from the book */
456 static struct server_info servers[] = {
458 { 0x0002, "User Group" },
459 { 0x0003, "Print Queue" },
460 { 0x0004, "File server" },
461 { 0x0005, "Job server" },
462 { 0x0007, "Print server" },
463 { 0x0008, "Archive server" },
464 { 0x0009, "Archive server" },
465 { 0x000a, "Job queue" },
466 { 0x000b, "Administration" },
467 { 0x0021, "NAS SNA gateway" },
468 { 0x0024, "Remote bridge" },
469 { 0x0026, "Bridge server" },
470 { 0x0027, "TCP/IP gateway" },
471 { 0x002d, "Time Synchronization VAP" },
472 { 0x002e, "Archive Server Dynamic SAP" },
473 { 0x0047, "Advertising print server" },
474 { 0x004b, "Btrieve VAP 5.0" },
475 { 0x004c, "SQL VAP" },
476 { 0x0050, "Btrieve VAP" },
477 { 0x0053, "Print Queue VAP" },
478 { 0x007a, "TES NetWare for VMS" },
479 { 0x0098, "NetWare access server" },
480 { 0x009a, "Named Pipes server" },
481 { 0x009e, "Portable NetWare Unix" },
482 { 0x0107, "NetWare 386" },
483 { 0x0111, "Test server" },
484 { 0x0133, "NetWare Name Service" },
485 { 0x0166, "NetWare management" },
486 { 0x026a, "NetWare management" },
487 { 0x026b, "Time synchronization" },
488 { 0x0278, "NetWare Directory server" },
489 { 0x055d, "Attachmate SNA gateway" },
493 while (servers[i].text != NULL) {
494 if (servers[i].type == type) {
495 return servers[i].text;
503 dissect_sap(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
506 proto_tree *sap_tree, *s_tree;
509 struct sap_query query;
510 struct sap_server_ident server;
512 char *sap_type[4] = { "General Query", "General Response",
513 "Nearest Query", "Nearest Response" };
515 query.query_type = pntohs(&pd[offset]);
516 query.server_type = pntohs(&pd[offset+2]);
518 if (check_col(fd, COL_PROTOCOL))
519 col_add_str(fd, COL_PROTOCOL, "SAP");
520 if (check_col(fd, COL_INFO)) {
521 if (query.query_type < 4) {
522 col_add_str(fd, COL_INFO, sap_type[query.query_type - 1]);
525 col_add_str(fd, COL_INFO, "Unknown Packet Type");
530 ti = proto_tree_add_text(tree, offset, END_OF_FRAME,
531 "Service Advertising Protocol");
532 sap_tree = proto_item_add_subtree(ti, ETT_IPXSAP);
534 if (query.query_type < 4) {
535 proto_tree_add_text(sap_tree, offset, 2, sap_type[query.query_type - 1]);
538 proto_tree_add_text(sap_tree, offset, 2,
539 "Unknown SAP Packet Type %d", query.query_type);
542 if (query.query_type == IPX_SAP_GENERAL_RESPONSE ||
543 query.query_type == IPX_SAP_NEAREST_RESPONSE) { /* responses */
545 for (cursor = offset + 2; (cursor + 64) <= fd->cap_len; cursor += 64) {
546 server.server_type = pntohs(&pd[cursor]);
547 memcpy(server.server_name, &pd[cursor+2], 48);
548 memcpy(&server.server_network, &pd[cursor+50], 4);
549 memcpy(&server.server_node, &pd[cursor+54], 6);
550 server.server_port = pntohs(&pd[cursor+60]);
551 server.intermediate_network = pntohs(&pd[cursor+62]);
553 ti = proto_tree_add_text(sap_tree, cursor+2, 48,
554 "Server Name: %s", server.server_name);
555 s_tree = proto_item_add_subtree(ti, ETT_IPXSAP_SERVER);
557 proto_tree_add_text(s_tree, cursor, 2, "Server Type: %s (0x%04X)",
558 server_type(server.server_type), server.server_type);
559 proto_tree_add_text(s_tree, cursor+50, 4, "Network: %s",
560 ipxnet_to_string((guint8*)&pd[cursor+50]));
561 proto_tree_add_text(s_tree, cursor+54, 6, "Node: %s",
562 ether_to_str((guint8*)&pd[cursor+54]));
563 proto_tree_add_text(s_tree, cursor+60, 2, "Socket: %s (0x%04X)",
564 port_text(server.server_port), server.server_port);
565 proto_tree_add_text(s_tree, cursor+62, 2,
566 "Intermediate Networks: %d",
567 server.intermediate_network);
571 proto_tree_add_text(sap_tree, offset+2, 2, "Server Type: %s (0x%04X)",
572 server_type(query.server_type), query.server_type);