2 * Routines for NetWare's IPX
3 * Gilbert Ramirez <gram@verdict.uthscsa.edu>
5 * $Id: packet-ipx.c,v 1.13 1998/11/17 04:28:55 gerald 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.
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
41 #include "packet-ipx.h"
43 /* The information in this module (IPX, SPX, NCP) comes from:
44 NetWare LAN Analysis, Second Edition
45 Laura A. Chappell and Dan E. Hakes
47 Novell Press, San Jose.
50 And from the ncpfs source code by Volker Lendecke
55 dissect_spx(const u_char *pd, int offset, frame_data *fd, GtkTree *tree);
58 dissect_ipxrip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree);
61 dissect_sap(const u_char *pd, int offset, frame_data *fd, GtkTree *tree);
65 void (*func) (const u_char *, int, frame_data *, GtkTree *);
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 dissect_ipx(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
166 GtkWidget *ipx_tree, *ti;
170 guint16 dsocket, ssocket;
171 void (*dissect) (const u_char *, int, frame_data *, GtkTree *);
173 /* Calculate here for use in pinfo and in tree */
174 dnet = ipxnet_to_string((guint8*)&pd[offset+6]);
175 snet = ipxnet_to_string((guint8*)&pd[offset+18]);
176 dsocket = pntohs(&pd[offset+16]);
178 if (check_col(fd, COL_PROTOCOL))
179 col_add_str(fd, COL_PROTOCOL, "IPX");
180 if (check_col(fd, COL_INFO))
181 col_add_fstr(fd, COL_INFO, "%s (0x%04X)", port_text(dsocket), dsocket);
183 ipx_type = pd[offset+5];
186 ti = add_item_to_tree(GTK_WIDGET(tree), offset, 30,
187 "Internetwork Packet Exchange");
188 ipx_tree = gtk_tree_new();
189 add_subtree(ti, ipx_tree, ETT_IPX);
190 add_item_to_tree(ipx_tree, offset, 2, "Checksum: 0x%04X",
191 (pd[offset] << 8) | pd[offset+1]);
192 add_item_to_tree(ipx_tree, offset+2, 2, "Length: %d bytes",
193 (pd[offset+2] << 8) | pd[offset+3]);
194 add_item_to_tree(ipx_tree, offset+4, 1, "Transport Control: %d hops",
196 add_item_to_tree(ipx_tree, offset+5, 1, "Packet Type: %s",
197 ipx_packet_type(ipx_type));
198 add_item_to_tree(ipx_tree, offset+6, 4, "Destination Network: %s",
200 add_item_to_tree(ipx_tree, offset+10, 6, "Destination Node: %s",
201 ether_to_str((guint8*)&pd[offset+10]));
202 /*dsocket = ntohs(*((guint16*)&pd[offset+16]));*/
203 add_item_to_tree(ipx_tree, offset+16, 2,
204 "Destination Socket: %s (0x%04X)", port_text(dsocket), dsocket);
205 add_item_to_tree(ipx_tree, offset+18, 4, "Source Network: %s",
207 add_item_to_tree(ipx_tree, offset+22, 6, "Source Node: %s",
208 ether_to_str((guint8*)&pd[offset+22]));
209 ssocket = pntohs(&pd[offset+28]);
210 add_item_to_tree(ipx_tree, offset+28, 2,
211 "Source Socket: %s (0x%04X)", port_text(ssocket), ssocket);
217 dissect_spx(pd, offset, fd, tree);
221 dissect_ncp(pd, offset, fd, tree);
224 case 20: /* NetBIOS */
225 if (dsocket == 0x0455) {
226 dissect_nbipx_ns(pd, offset, fd, tree);
229 /* else fall through */
231 case 0: /* IPX, fall through to default */
233 dissect = port_func(dsocket);
235 dissect(pd, offset, fd, tree);
238 dissect_data(pd, offset, fd, tree);
245 /* ================================================================= */
247 /* ================================================================= */
249 spx_conn_ctrl(u_char ctrl)
253 static struct conn_info conns[] = {
254 { 0x10, "End-of-Message" },
255 { 0x20, "Attention" },
256 { 0x40, "Acknowledgment Required"},
257 { 0x80, "System Packet"}
260 while (conns[i].text != NULL) {
261 if (conns[i].ctrl == ctrl) {
262 return conns[i].text;
270 datastream(u_char type)
274 return "End-of-Connection";
276 return "End-of-Connection Acknowledgment";
278 return "Client-Defined";
283 dissect_spx(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
285 GtkWidget *spx_tree, *ti;
287 if (check_col(fd, COL_PROTOCOL))
288 col_add_str(fd, COL_PROTOCOL, "SPX");
289 if (check_col(fd, COL_INFO))
290 col_add_str(fd, COL_INFO, "SPX");
293 ti = add_item_to_tree(GTK_WIDGET(tree), offset, 12,
294 "Sequenced Packet Exchange");
295 spx_tree = gtk_tree_new();
296 add_subtree(ti, spx_tree, ETT_SPX);
298 add_item_to_tree(spx_tree, offset, 1,
299 "Connection Control: %s (0x%02X)",
300 spx_conn_ctrl(pd[offset]), pd[offset]);
302 add_item_to_tree(spx_tree, offset+1, 1,
303 "Datastream Type: %s (0x%02X)",
304 datastream(pd[offset+1]), pd[offset+1]);
306 add_item_to_tree(spx_tree, offset+2, 2,
307 "Source Connection ID: %d", pntohs( &pd[offset+2] ) );
309 add_item_to_tree(spx_tree, offset+4, 2,
310 "Destination Connection ID: %d", pntohs( &pd[offset+4] ) );
312 add_item_to_tree(spx_tree, offset+6, 2,
313 "Sequence Number: %d", pntohs( &pd[offset+6] ) );
315 add_item_to_tree(spx_tree, offset+8, 2,
316 "Acknowledgment Number: %d", pntohs( &pd[offset+8] ) );
318 add_item_to_tree(spx_tree, offset+10, 2,
319 "Allocation Number: %d", pntohs( &pd[offset+10] ) );
322 dissect_data(pd, offset, fd, tree);
326 /* ================================================================= */
328 /* ================================================================= */
330 dissect_ipxrip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
332 GtkWidget *rip_tree, *ti;
334 struct ipx_rt_def route;
337 char *rip_type[2] = { "Request", "Response" };
339 operation = pntohs(&pd[offset]) - 1;
341 if (check_col(fd, COL_PROTOCOL))
342 col_add_str(fd, COL_PROTOCOL, "IPX RIP");
343 if (check_col(fd, COL_PROTOCOL)) {
345 col_add_str(fd, COL_INFO, rip_type[operation]);
348 col_add_str(fd, COL_INFO, "Unknown Packet Type");
353 ti = add_item_to_tree(GTK_WIDGET(tree), offset, END_OF_FRAME,
354 "IPX Routing Information Protocol");
355 rip_tree = gtk_tree_new();
356 add_subtree(ti, rip_tree, ETT_IPXRIP);
359 add_item_to_tree(rip_tree, offset, 2,
360 "RIP packet type: %s", rip_type[operation]);
363 add_item_to_tree(rip_tree, offset, 2, "Unknown RIP packet type");
366 for (cursor = offset + 2; cursor < fd->cap_len; cursor += 8) {
367 memcpy(&route.network, &pd[cursor], 4);
368 route.hops = pntohs(&pd[cursor+4]);
369 route.ticks = pntohs(&pd[cursor+6]);
371 if (operation == IPX_RIP_REQUEST - 1) {
372 add_item_to_tree(rip_tree, cursor, 8,
373 "Route Vector: %s, %d hop%s, %d tick%s",
374 ipxnet_to_string((guint8*)&route.network),
375 route.hops, route.hops == 1 ? "" : "s",
376 route.ticks, route.ticks == 1 ? "" : "s");
379 add_item_to_tree(rip_tree, cursor, 8,
380 "Route Vector: %s, %d hop%s, %d tick%s (%d ms)",
381 ipxnet_to_string((guint8*)&route.network),
382 route.hops, route.hops == 1 ? "" : "s",
383 route.ticks, route.ticks == 1 ? "" : "s",
384 route.ticks * 1000 / 18);
392 /* ================================================================= */
394 /* ================================================================= */
396 server_type(guint16 type)
400 /* some of these are from ncpfs, others are from the book */
401 static struct server_info servers[] = {
403 { 0x0002, "User Group" },
404 { 0x0003, "Print Queue" },
405 { 0x0004, "File server" },
406 { 0x0005, "Job server" },
407 { 0x0007, "Print server" },
408 { 0x0008, "Archive server" },
409 { 0x0009, "Archive server" },
410 { 0x000a, "Job queue" },
411 { 0x000b, "Administration" },
412 { 0x0021, "NAS SNA gateway" },
413 { 0x0024, "Remote bridge" },
414 { 0x0026, "Bridge server" },
415 { 0x0027, "TCP/IP gateway" },
416 { 0x002d, "Time Synchronization VAP" },
417 { 0x002e, "Archive Server Dynamic SAP" },
418 { 0x0047, "Advertising print server" },
419 { 0x004b, "Btrieve VAP 5.0" },
420 { 0x004c, "SQL VAP" },
421 { 0x0050, "Btrieve VAP" },
422 { 0x0053, "Print Queue VAP" },
423 { 0x007a, "TES NetWare for VMS" },
424 { 0x0098, "NetWare access server" },
425 { 0x009a, "Named Pipes server" },
426 { 0x009e, "Portable NetWare Unix" },
427 { 0x0107, "NetWare 386" },
428 { 0x0111, "Test server" },
429 { 0x0133, "NetWare Name Service" },
430 { 0x0166, "NetWare management" },
431 { 0x026a, "NetWare management" },
432 { 0x026b, "Time synchronization" },
433 { 0x0278, "NetWare Directory server" },
434 { 0x055d, "Attachmate SNA gateway" },
438 while (servers[i].text != NULL) {
439 if (servers[i].type == type) {
440 return servers[i].text;
448 dissect_sap(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
450 GtkWidget *sap_tree, *s_tree, *ti;
452 struct sap_query query;
453 struct sap_server_ident server;
455 char *sap_type[4] = { "General Query", "General Response",
456 "Nearest Query", "Nearest Response" };
458 query.query_type = pntohs(&pd[offset]);
459 query.server_type = pntohs(&pd[offset+2]);
461 if (check_col(fd, COL_PROTOCOL))
462 col_add_str(fd, COL_PROTOCOL, "SAP");
463 if (check_col(fd, COL_INFO)) {
464 if (query.query_type < 4) {
465 col_add_str(fd, COL_INFO, sap_type[query.query_type - 1]);
468 col_add_str(fd, COL_INFO, "Unknown Packet Type");
473 ti = add_item_to_tree(GTK_WIDGET(tree), offset, END_OF_FRAME,
474 "Service Advertising Protocol");
475 sap_tree = gtk_tree_new();
476 add_subtree(ti, sap_tree, ETT_IPXSAP);
478 if (query.query_type < 4) {
479 add_item_to_tree(sap_tree, offset, 2, sap_type[query.query_type - 1]);
482 add_item_to_tree(sap_tree, offset, 2,
483 "Unknown SAP Packet Type %d", query.query_type);
486 if (query.query_type == IPX_SAP_GENERAL_RESPONSE ||
487 query.query_type == IPX_SAP_NEAREST_RESPONSE) { /* responses */
489 for (cursor = offset + 2; cursor < fd->cap_len; cursor += 64) {
490 server.server_type = pntohs(&pd[cursor]);
491 memcpy(server.server_name, &pd[cursor+2], 48);
492 memcpy(&server.server_network, &pd[cursor+50], 4);
493 memcpy(&server.server_node, &pd[cursor+54], 6);
494 server.server_port = pntohs(&pd[cursor+60]);
495 server.intermediate_network = pntohs(&pd[cursor+62]);
497 ti = add_item_to_tree(GTK_WIDGET(sap_tree), cursor+2, 48,
498 "Server Name: %s", server.server_name);
499 s_tree = gtk_tree_new();
500 add_subtree(ti, s_tree, ETT_IPXSAP_SERVER);
502 add_item_to_tree(s_tree, cursor, 2, "Server Type: %s (0x%04X)",
503 server_type(server.server_type), server.server_type);
504 add_item_to_tree(s_tree, cursor+50, 4, "Network: %s",
505 ipxnet_to_string((guint8*)&pd[cursor+50]));
506 add_item_to_tree(s_tree, cursor+54, 6, "Node: %s",
507 ether_to_str((guint8*)&pd[cursor+54]));
508 add_item_to_tree(s_tree, cursor+60, 2, "Socket: %s (0x%04X)",
509 port_text(server.server_port), server.server_port);
510 add_item_to_tree(s_tree, cursor+62, 2,
511 "Intermediate Networks: %d",
512 server.intermediate_network);
516 add_item_to_tree(sap_tree, offset+2, 2, "Server Type: %s (0x%04X)",
517 server_type(query.server_type), query.server_type);