2 * Routines for NetWare's IPX
3 * Gilbert Ramirez <gram@xiexie.org>
5 * $Id: packet-ipx.c,v 1.77 2001/01/22 00:20:29 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@zing.org>
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>
43 #include "packet-ipx.h"
46 #include "packet-snmp.h"
48 /* The information in this module (IPX, SPX, NCP) comes from:
49 NetWare LAN Analysis, Second Edition
50 Laura A. Chappell and Dan E. Hakes
52 Novell Press, San Jose.
55 And from the ncpfs source code by Volker Lendecke
59 static int proto_ipx = -1;
60 static int hf_ipx_checksum = -1;
61 static int hf_ipx_len = -1;
62 static int hf_ipx_hops = -1;
63 static int hf_ipx_packet_type = -1;
64 static int hf_ipx_dnet = -1;
65 static int hf_ipx_dnode = -1;
66 static int hf_ipx_dsocket = -1;
67 static int hf_ipx_snet = -1;
68 static int hf_ipx_snode = -1;
69 static int hf_ipx_ssocket = -1;
71 static gint ett_ipx = -1;
73 static dissector_table_t ipx_type_dissector_table;
74 static dissector_table_t ipx_socket_dissector_table;
76 static dissector_handle_t nbipx_handle;
78 static int proto_spx = -1;
79 static int hf_spx_connection_control = -1;
80 static int hf_spx_datastream_type = -1;
81 static int hf_spx_src_id = -1;
82 static int hf_spx_dst_id = -1;
83 static int hf_spx_seq_nr = -1;
84 static int hf_spx_ack_nr = -1;
85 static int hf_spx_all_nr = -1;
87 static gint ett_spx = -1;
89 static int proto_ipxrip = -1;
90 static int hf_ipxrip_request = -1;
91 static int hf_ipxrip_response = -1;
93 static gint ett_ipxrip = -1;
95 static int proto_sap = -1;
96 static int hf_sap_request = -1;
97 static int hf_sap_response = -1;
99 static gint ett_ipxsap = -1;
100 static gint ett_ipxsap_server = -1;
102 static gint ett_ipxmsg = -1;
103 static int proto_ipxmsg = -1;
104 static int hf_msg_conn = -1;
105 static int hf_msg_sigchar = -1;
108 dissect_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
111 dissect_ipxrip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
114 dissect_ipxsap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
117 dissect_ipxmsg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
119 #define UDP_PORT_IPX 213 /* RFC 1234 */
121 #define IPX_HEADER_LEN 30 /* It's *always* 30 bytes */
123 /* ================================================================= */
125 /* ================================================================= */
126 static const value_string ipx_socket_vals[] = {
127 { IPX_SOCKET_PING_CISCO, "CISCO PING" },
128 { IPX_SOCKET_NCP, "NCP" },
129 { IPX_SOCKET_SAP, "SAP" },
130 { IPX_SOCKET_IPXRIP, "RIP" },
131 { IPX_SOCKET_NETBIOS, "NetBIOS" },
132 { IPX_SOCKET_DIAGNOSTIC, "Diagnostic" },
133 { IPX_SOCKET_SERIALIZATION, "Serialization" },
134 { IPX_SOCKET_NWLINK_SMB_NAMEQUERY, "NWLink SMB Name Query" },
135 { IPX_SOCKET_NWLINK_SMB_DGRAM, "NWLink SMB Datagram" },
136 { IPX_SOCKET_NWLINK_SMB_BROWSE, "NWLink SMB Browse" },
137 { IPX_SOCKET_ATTACHMATE_GW, "Attachmate Gateway" },
138 { IPX_SOCKET_IPX_MESSAGE, "IPX Message" },
139 { IPX_SOCKET_SNMP_AGENT, "SNMP Agent" },
140 { IPX_SOCKET_SNMP_SINK, "SNMP Sink" },
141 { IPX_SOCKET_PING_NOVELL, "Novell PING" },
142 { IPX_SOCKET_UDP_TUNNEL, "UDP Tunnel" },
143 { IPX_SOCKET_TCP_TUNNEL, "TCP Tunnel" },
144 { IPX_SOCKET_TCP_TUNNEL, "TCP Tunnel" },
145 { IPX_SOCKET_ADSM, "ADSM" },
146 { IPX_SOCKET_EIGRP, "Cisco EIGRP for IPX" },
147 { IPX_SOCKET_WIDE_AREA_ROUTER, "Wide Area Router" },
152 socket_text(guint16 socket)
156 p = match_strval(socket, ipx_socket_vals);
165 static const value_string ipx_packet_type_vals[] = {
166 { IPX_PACKET_TYPE_IPX, "IPX" },
167 { IPX_PACKET_TYPE_RIP, "RIP" },
168 { IPX_PACKET_TYPE_ECHO, "Echo" },
169 { IPX_PACKET_TYPE_ERROR, "Error" },
170 { IPX_PACKET_TYPE_PEP, "PEP" }, /* Packet Exchange Packet */
171 { IPX_PACKET_TYPE_SPX, "SPX" },
172 { 16, "Experimental Protocol" },
173 { IPX_PACKET_TYPE_NCP, "NCP" },
174 { 18, "Experimental Protocol" },
175 { 19, "Experimental Protocol" },
176 { IPX_PACKET_TYPE_WANBCAST, "NetBIOS Broadcast" },
177 { 21, "Experimental Protocol" },
178 { 22, "Experimental Protocol" },
179 { 23, "Experimental Protocol" },
180 { 24, "Experimental Protocol" },
181 { 25, "Experimental Protocol" },
182 { 26, "Experimental Protocol" },
183 { 27, "Experimental Protocol" },
184 { 28, "Experimental Protocol" },
185 { 29, "Experimental Protocol" },
186 { 30, "Experimental Protocol" },
187 { 31, "Experimental Protocol" },
191 static const value_string ipxmsg_sigchar_vals[] = {
192 { '?', "Poll inactive station" },
197 ipxnet_to_string(const guint8 *ad)
199 guint32 addr = pntohl(ad);
200 return ipxnet_to_str_punct(addr, ' ');
203 /* We use a different representation of hardware addresses
204 * than ether_to_str(); we don't put punctuation between the hex
209 ipx_addr_to_str(guint32 net, const guint8 *ad)
211 static gchar str[3][8+1+MAXNAMELEN+1]; /* 8 digits, 1 period, NAME, 1 null */
215 if (cur == &str[0][0]) {
217 } else if (cur == &str[1][0]) {
223 name = get_ether_name_if_known(ad);
226 sprintf(cur, "%s.%s", get_ipxnet_name(net), name);
229 sprintf(cur, "%s.%s", get_ipxnet_name(net), ether_to_str_punct(ad, '\0'));
235 ipxnet_to_str_punct(const guint32 ad, char punct)
237 static gchar str[3][12];
242 static const gchar hex_digits[16] = "0123456789ABCDEF";
243 static const guint32 octet_mask[4] =
244 { 0xff000000 , 0x00ff0000, 0x0000ff00, 0x000000ff };
246 if (cur == &str[0][0]) {
248 } else if (cur == &str[1][0]) {
257 octet = (ad & octet_mask[i]) >> ((3 - i) * 8);
258 *--p = hex_digits[octet&0xF];
260 *--p = hex_digits[octet&0xF];
271 capture_ipx(const u_char *pd, int offset, packet_counts *ld)
277 dissect_ipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
280 const guint8 *this_pd;
281 int this_offset, len;
283 proto_tree *ipx_tree;
286 guint8 *src_net_node, *dst_net_node;
288 guint8 ipx_type, ipx_hops;
290 int reported_length, available_length;
292 guint16 ipx_dsocket, ipx_ssocket;
294 if (check_col(pinfo->fd, COL_PROTOCOL))
295 col_set_str(pinfo->fd, COL_PROTOCOL, "IPX");
296 if (check_col(pinfo->fd, COL_INFO))
297 col_clear(pinfo->fd, COL_INFO);
299 /* Calculate here for use in pinfo and in tree */
300 ipx_dsocket = tvb_get_ntohs(tvb, 16);
301 ipx_ssocket = tvb_get_ntohs(tvb, 28);
302 ipx_type = tvb_get_guint8(tvb, 5);
303 ipx_length = tvb_get_ntohs(tvb, 2);
305 /* Set the payload and captured-payload lengths to the minima of
306 (the IPX length plus the length of the headers above it) and
307 the frame lengths. XXX - remove once all dissectors use tvbuffs */
308 tvb_compat(tvb, &this_pd, &this_offset);
309 len = ipx_length + this_offset;
312 if (pi.captured_len > len)
313 pi.captured_len = len;
315 src_net_node = tvb_get_ptr(tvb, 18, 10);
316 dst_net_node = tvb_get_ptr(tvb, 6, 10);
318 SET_ADDRESS(&pi.net_src, AT_IPX, 10, src_net_node);
319 SET_ADDRESS(&pi.src, AT_IPX, 10, src_net_node);
320 SET_ADDRESS(&pi.net_dst, AT_IPX, 10, dst_net_node);
321 SET_ADDRESS(&pi.dst, AT_IPX, 10, dst_net_node);
323 if (check_col(pinfo->fd, COL_INFO))
324 col_add_fstr(pinfo->fd, COL_INFO, "%s (0x%04X)",
325 socket_text(ipx_dsocket), ipx_dsocket);
329 ti = proto_tree_add_item(tree, proto_ipx, tvb, 0, IPX_HEADER_LEN, FALSE);
330 ipx_tree = proto_item_add_subtree(ti, ett_ipx);
332 proto_tree_add_item(ipx_tree, hf_ipx_checksum, tvb, 0, 2, FALSE);
333 proto_tree_add_uint_format(ipx_tree, hf_ipx_len, tvb, 2, 2, ipx_length,
334 "Length: %d bytes", ipx_length);
335 ipx_hops = tvb_get_guint8(tvb, 4);
336 proto_tree_add_uint_format(ipx_tree, hf_ipx_hops, tvb, 4, 1, ipx_hops,
337 "Transport Control: %d hops", ipx_hops);
338 proto_tree_add_uint(ipx_tree, hf_ipx_packet_type, tvb, 5, 1, ipx_type);
341 proto_tree_add_item(ipx_tree, hf_ipx_dnet, tvb, 6, 4, FALSE);
342 proto_tree_add_item(ipx_tree, hf_ipx_dnode, tvb, 10, 6, FALSE);
343 proto_tree_add_uint_format(ipx_tree, hf_ipx_dsocket, tvb, 16, 2,
344 ipx_dsocket, "Destination Socket: %s (0x%04X)",
345 socket_text(ipx_dsocket), ipx_dsocket);
348 proto_tree_add_item(ipx_tree, hf_ipx_snet, tvb, 18, 4, FALSE);
349 proto_tree_add_item(ipx_tree, hf_ipx_snode, tvb, 22, 6, FALSE);
350 proto_tree_add_uint_format(ipx_tree, hf_ipx_ssocket, tvb, 28, 2,
351 ipx_ssocket, "Source Socket: %s (0x%04X)", socket_text(ipx_ssocket),
355 /* Make the next tvbuff */
356 reported_length = ipx_length - IPX_HEADER_LEN;
357 available_length = tvb_length(tvb) - IPX_HEADER_LEN;
358 next_tvb = tvb_new_subset(tvb, IPX_HEADER_LEN,
359 MIN(available_length, reported_length),
362 if (dissector_try_port(ipx_type_dissector_table, ipx_type, next_tvb,
367 case IPX_PACKET_TYPE_WANBCAST:
368 case IPX_PACKET_TYPE_PEP:
369 if (ipx_dsocket == IPX_SOCKET_NETBIOS) {
370 call_dissector(nbipx_handle, next_tvb, pinfo,
374 /* else fall through */
376 case 0: /* IPX, fall through to default */
377 /* XXX - should type 0's be dissected as NBIPX
378 if they're aimed at the NetBIOS socket? */
382 if (dissector_try_port(ipx_socket_dissector_table, ipx_dsocket,
383 next_tvb, pinfo, tree))
385 if (dissector_try_port(ipx_socket_dissector_table, ipx_ssocket,
386 next_tvb, pinfo, tree))
388 dissect_data(next_tvb, 0, pinfo, tree);
392 /* ================================================================= */
394 /* ================================================================= */
396 spx_conn_ctrl(guint8 ctrl)
400 static const value_string conn_vals[] = {
401 { 0x10, "End-of-Message" },
402 { 0x20, "Attention" },
403 { 0x40, "Acknowledgment Required"},
404 { 0x80, "System Packet"},
408 p = match_strval(ctrl, conn_vals);
419 spx_datastream(guint8 type)
423 return "End-of-Connection";
425 return "End-of-Connection Acknowledgment";
427 return "Client-Defined";
431 #define SPX_HEADER_LEN 12
434 dissect_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
436 proto_tree *spx_tree;
441 guint8 datastream_type;
443 if (check_col(pinfo->fd, COL_PROTOCOL))
444 col_set_str(pinfo->fd, COL_PROTOCOL, "SPX");
445 if (check_col(pinfo->fd, COL_INFO))
446 col_set_str(pinfo->fd, COL_INFO, "SPX");
449 ti = proto_tree_add_item(tree, proto_spx, tvb, 0, SPX_HEADER_LEN, FALSE);
450 spx_tree = proto_item_add_subtree(ti, ett_spx);
452 conn_ctrl = tvb_get_guint8(tvb, 0);
453 proto_tree_add_uint_format(spx_tree, hf_spx_connection_control, tvb,
455 "Connection Control: %s (0x%02X)",
456 spx_conn_ctrl(conn_ctrl), conn_ctrl);
458 datastream_type = tvb_get_guint8(tvb, 1);
459 proto_tree_add_uint_format(spx_tree, hf_spx_datastream_type, tvb,
460 1, 1, datastream_type,
461 "Datastream Type: %s (0x%02X)",
462 spx_datastream(datastream_type), datastream_type);
464 proto_tree_add_item(spx_tree, hf_spx_src_id, tvb, 2, 2, FALSE);
465 proto_tree_add_item(spx_tree, hf_spx_dst_id, tvb, 4, 2, FALSE);
466 proto_tree_add_item(spx_tree, hf_spx_seq_nr, tvb, 6, 2, FALSE);
467 proto_tree_add_item(spx_tree, hf_spx_ack_nr, tvb, 8, 2, FALSE);
468 proto_tree_add_item(spx_tree, hf_spx_all_nr, tvb, 10, 2, FALSE);
470 next_tvb = tvb_new_subset(tvb, SPX_HEADER_LEN, -1, -1);
471 dissect_data(next_tvb, 0, pinfo, tree);
475 /* ================================================================= */
477 /* ================================================================= */
479 dissect_ipxmsg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
481 proto_tree *msg_tree;
483 guint8 conn_number, sig_char;
485 if (check_col(pinfo->fd, COL_PROTOCOL))
486 col_set_str(pinfo->fd, COL_PROTOCOL, "IPX MSG");
487 if (check_col(pinfo->fd, COL_INFO))
488 col_clear(pinfo->fd, COL_INFO);
490 conn_number = tvb_get_guint8(tvb, 0);
491 sig_char = tvb_get_guint8(tvb, 1);
493 if (check_col(pinfo->fd, COL_INFO)) {
494 col_add_fstr(pinfo->fd, COL_INFO,
496 val_to_str(sig_char, ipxmsg_sigchar_vals, "Unknown Signature Char"), conn_number);
500 ti = proto_tree_add_item(tree, proto_ipxmsg, tvb, 0, tvb_length(tvb), FALSE);
501 msg_tree = proto_item_add_subtree(ti, ett_ipxmsg);
503 proto_tree_add_uint(msg_tree, hf_msg_conn, tvb, 0, 1, conn_number);
504 proto_tree_add_uint(msg_tree, hf_msg_sigchar, tvb, 1, 1, sig_char);
509 /* ================================================================= */
511 /* ================================================================= */
513 dissect_ipxrip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
515 proto_tree *rip_tree;
518 struct ipx_rt_def route;
520 int available_length;
522 char *rip_type[3] = { "Request", "Response", "Unknown" };
524 if (check_col(pinfo->fd, COL_PROTOCOL))
525 col_set_str(pinfo->fd, COL_PROTOCOL, "IPX RIP");
526 if (check_col(pinfo->fd, COL_INFO))
527 col_clear(pinfo->fd, COL_INFO);
529 operation = tvb_get_ntohs(tvb, 0) - 1;
531 if (check_col(pinfo->fd, COL_INFO)) {
532 /* rip_types 0 and 1 are valid, anything else becomes 2 or "Unknown" */
533 col_add_str(pinfo->fd, COL_INFO, rip_type[MIN(operation, 2)]);
537 ti = proto_tree_add_item(tree, proto_ipxrip, tvb, 0, tvb_length(tvb), FALSE);
538 rip_tree = proto_item_add_subtree(ti, ett_ipxrip);
541 proto_tree_add_text(rip_tree, tvb, 0, 2,
542 "RIP packet type: %s", rip_type[operation]);
544 if (operation == 0) {
545 proto_tree_add_boolean_hidden(rip_tree,
549 proto_tree_add_boolean_hidden(rip_tree,
556 proto_tree_add_text(rip_tree, tvb, 0, 2, "Unknown RIP packet type");
559 available_length = tvb_length(tvb);
560 for (cursor = 2; cursor < available_length; cursor += 8) {
561 memcpy(&route.network, tvb_get_ptr(tvb, cursor, 4), 4);
562 route.hops = tvb_get_ntohs(tvb, cursor+4);
563 route.ticks = tvb_get_ntohs(tvb, cursor+6);
565 if (operation == IPX_RIP_REQUEST - 1) {
566 proto_tree_add_text(rip_tree, tvb, cursor, 8,
567 "Route Vector: %s, %d hop%s, %d tick%s",
568 ipxnet_to_string((guint8*)&route.network),
569 route.hops, route.hops == 1 ? "" : "s",
570 route.ticks, route.ticks == 1 ? "" : "s");
573 proto_tree_add_text(rip_tree, tvb, cursor, 8,
574 "Route Vector: %s, %d hop%s, %d tick%s (%d ms)",
575 ipxnet_to_string((guint8*)&route.network),
576 route.hops, route.hops == 1 ? "" : "s",
577 route.ticks, route.ticks == 1 ? "" : "s",
578 route.ticks * 1000 / 18);
586 /* ================================================================= */
588 /* ================================================================= */
590 server_type(guint16 type)
594 /* some of these are from ncpfs, others are from the book */
595 static const value_string server_vals[] = {
597 { 0x0002, "User Group" },
598 { 0x0003, "Print Queue" },
599 { 0x0004, "File server" },
600 { 0x0005, "Job server" },
601 { 0x0007, "Print server" },
602 { 0x0008, "Archive server" },
603 { 0x0009, "Archive server" },
604 { 0x000a, "Job queue" },
605 { 0x000b, "Administration" },
606 { 0x0021, "NAS SNA gateway" },
607 { 0x0024, "Remote bridge" },
608 { 0x0026, "Bridge server" },
609 { 0x0027, "TCP/IP gateway" },
610 { 0x002d, "Time Synchronization VAP" },
611 { 0x002e, "Archive Server Dynamic SAP" },
612 { 0x0047, "Advertising print server" },
613 { 0x004b, "Btrieve VAP 5.0" },
614 { 0x004c, "SQL VAP" },
615 { 0x0050, "Btrieve VAP" },
616 { 0x0053, "Print Queue VAP" },
617 { 0x007a, "TES NetWare for VMS" },
618 { 0x0098, "NetWare access server" },
619 { 0x009a, "Named Pipes server" },
620 { 0x009e, "Portable NetWare Unix" },
621 { 0x0107, "NetWare 386" },
622 { 0x0111, "Test server" },
623 { 0x0133, "NetWare Name Service" },
624 { 0x0166, "NetWare management" },
625 { 0x023f, "SMS Testing and Development" },
626 { 0x026a, "NetWare management" },
627 { 0x026b, "Time synchronization" },
628 { 0x027b, "NetWare Management Agent" },
629 { 0x0278, "NetWare Directory server" },
630 { 0x030c, "HP LaserJet / Quick Silver" },
631 { 0x0355, "Arcada Software" },
632 { 0x0361, "NETINELO" },
633 { 0x037e, "Powerchute UPS Monitoring" },
634 { 0x03e1, "UnixWare Application Server" },
635 { 0x044c, "Archive" },
636 { 0x055d, "Attachmate SNA gateway" },
637 { 0x0610, "Adaptec SCSI Management" },
638 { 0x0640, "NT Server-RPC/GW for NW/Win95 User Level Sec" },
639 { 0x064e, "NT Server-IIS" },
640 { 0x0810, "ELAN License Server Demo" },
641 { 0x8002, "Intel NetPort Print Server" },
643 /* For any unidentified ones, I found a really big list of them at: */
644 /* http://www.inpnet.org/cnpweb/saplist.txt */
645 /* http://www.isi.edu/in-notes/iana/assignments/novell-sap-numbers */
650 p = match_strval(type, server_vals);
660 dissect_ipxsap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
662 proto_tree *sap_tree, *s_tree;
665 struct sap_query query;
666 struct sap_server_ident server;
668 char *sap_type[4] = { "General Query", "General Response",
669 "Nearest Query", "Nearest Response" };
671 if (check_col(pinfo->fd, COL_PROTOCOL))
672 col_set_str(pinfo->fd, COL_PROTOCOL, "IPX SAP");
673 if (check_col(pinfo->fd, COL_INFO))
674 col_clear(pinfo->fd, COL_INFO);
676 query.query_type = tvb_get_ntohs(tvb, 0);
677 query.server_type = tvb_get_ntohs(tvb, 2);
679 if (check_col(pinfo->fd, COL_INFO)) {
680 if (query.query_type >= 1 && query.query_type <= 4) {
681 col_add_str(pinfo->fd, COL_INFO, sap_type[query.query_type - 1]);
684 col_set_str(pinfo->fd, COL_INFO, "Unknown Packet Type");
689 ti = proto_tree_add_item(tree, proto_sap, tvb, 0, tvb_length(tvb), FALSE);
690 sap_tree = proto_item_add_subtree(ti, ett_ipxsap);
692 if (query.query_type >= 1 && query.query_type <= 4) {
693 proto_tree_add_text(sap_tree, tvb, 0, 2, sap_type[query.query_type - 1]);
694 if ((query.query_type - 1) % 2) {
695 proto_tree_add_boolean_hidden(sap_tree,
699 proto_tree_add_boolean_hidden(sap_tree,
705 proto_tree_add_text(sap_tree, tvb, 0, 2,
706 "Unknown SAP Packet Type %d", query.query_type);
709 if (query.query_type == IPX_SAP_GENERAL_RESPONSE ||
710 query.query_type == IPX_SAP_NEAREST_RESPONSE) { /* responses */
712 int available_length = tvb_length(tvb);
713 for (cursor = 2; (cursor + 64) <= available_length; cursor += 64) {
714 server.server_type = tvb_get_ntohs(tvb, cursor);
715 memcpy(server.server_name, tvb_get_ptr(tvb, cursor+2, 48), 48);
716 memcpy(&server.server_network, tvb_get_ptr(tvb, cursor+50, 4), 4);
717 memcpy(&server.server_node, tvb_get_ptr(tvb, cursor+54, 6), 6);
718 server.server_port = tvb_get_ntohs(tvb, cursor+60);
719 server.intermediate_network = tvb_get_ntohs(tvb, cursor+62);
721 ti = proto_tree_add_text(sap_tree, tvb, cursor+2, 48,
722 "Server Name: %s", server.server_name);
723 s_tree = proto_item_add_subtree(ti, ett_ipxsap_server);
725 proto_tree_add_text(s_tree, tvb, cursor, 2, "Server Type: %s (0x%04X)",
726 server_type(server.server_type), server.server_type);
727 proto_tree_add_text(s_tree, tvb, cursor+50, 4, "Network: %s",
728 ipxnet_to_string((guint8*)tvb_get_ptr(tvb, cursor+50, 4)));
729 proto_tree_add_text(s_tree, tvb, cursor+54, 6, "Node: %s",
730 ether_to_str((guint8*)tvb_get_ptr(tvb, cursor+54, 6)));
731 proto_tree_add_text(s_tree, tvb, cursor+60, 2, "Socket: %s (0x%04X)",
732 socket_text(server.server_port), server.server_port);
733 proto_tree_add_text(s_tree, tvb, cursor+62, 2,
734 "Intermediate Networks: %d",
735 server.intermediate_network);
739 proto_tree_add_text(sap_tree, tvb, 2, 2, "Server Type: %s (0x%04X)",
740 server_type(query.server_type), query.server_type);
746 proto_register_ipx(void)
748 static hf_register_info hf_ipx[] = {
750 { "Checksum", "ipx.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
754 { "Length", "ipx.len", FT_UINT16, BASE_DEC, NULL, 0x0,
758 { "Transport Control (Hops)", "ipx.hops", FT_UINT8, BASE_DEC, NULL, 0x0,
761 { &hf_ipx_packet_type,
762 { "Packet Type", "ipx.packet_type", FT_UINT8, BASE_HEX, VALS(ipx_packet_type_vals),
767 { "Destination Network","ipx.dst.net", FT_IPXNET, BASE_NONE, NULL, 0x0,
771 { "Destination Node", "ipx.dst.node", FT_ETHER, BASE_NONE, NULL, 0x0,
775 { "Destination Socket", "ipx.dst.socket", FT_UINT16, BASE_HEX, NULL, 0x0,
779 { "Source Network","ipx.src.net", FT_IPXNET, BASE_NONE, NULL, 0x0,
783 { "Source Node", "ipx.src.node", FT_ETHER, BASE_NONE, NULL, 0x0,
787 { "Source Socket", "ipx.src.socket", FT_UINT16, BASE_HEX, NULL, 0x0,
791 static hf_register_info hf_spx[] = {
792 { &hf_spx_connection_control,
793 { "Connection Control", "spx.ctl",
794 FT_UINT8, BASE_HEX, NULL, 0x0,
797 { &hf_spx_datastream_type,
798 { "Datastream type", "spx.type",
799 FT_UINT8, BASE_HEX, NULL, 0x0,
803 { "Source Connection ID", "spx.src",
804 FT_UINT16, BASE_DEC, NULL, 0x0,
808 { "Destination Connection ID", "spx.dst",
809 FT_UINT16, BASE_DEC, NULL, 0x0,
813 { "Sequence Number", "spx.seq",
814 FT_UINT16, BASE_DEC, NULL, 0x0,
818 { "Acknowledgment Number", "spx.ack",
819 FT_UINT16, BASE_DEC, NULL, 0x0,
823 { "Allocation Number", "spx.alloc",
824 FT_UINT16, BASE_DEC, NULL, 0x0,
828 static hf_register_info hf_ipxrip[] = {
829 { &hf_ipxrip_request,
830 { "Request", "ipxrip.request",
831 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
832 "TRUE if IPX RIP request" }},
834 { &hf_ipxrip_response,
835 { "Response", "ipxrip.response",
836 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
837 "TRUE if IPX RIP response" }}
840 static hf_register_info hf_sap[] = {
842 { "Request", "ipxsap.request",
843 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
844 "TRUE if SAP request" }},
847 { "Response", "ipxsap.response",
848 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
849 "TRUE if SAP response" }}
852 static hf_register_info hf_ipxmsg[] = {
854 { "Connection Number", "ipxmsg.conn",
855 FT_UINT8, BASE_NONE, NULL, 0x0,
856 "Connection Number" }},
859 { "Signature Char", "ipxmsg.sigchar",
860 FT_UINT8, BASE_NONE, VALS(ipxmsg_sigchar_vals), 0x0,
864 static gint *ett[] = {
873 proto_ipx = proto_register_protocol("Internetwork Packet eXchange",
875 proto_register_field_array(proto_ipx, hf_ipx, array_length(hf_ipx));
877 register_dissector("ipx", dissect_ipx, proto_ipx);
879 proto_spx = proto_register_protocol("Sequenced Packet eXchange",
881 proto_register_field_array(proto_spx, hf_spx, array_length(hf_spx));
883 proto_ipxrip = proto_register_protocol("IPX Routing Information Protocol",
884 "IPX RIP", "ipxrip");
885 proto_register_field_array(proto_ipxrip, hf_ipxrip, array_length(hf_ipxrip));
887 proto_ipxmsg = proto_register_protocol("IPX Message", "IPX MSG",
889 proto_register_field_array(proto_ipxmsg, hf_ipxmsg, array_length(hf_ipxmsg));
891 proto_sap = proto_register_protocol("Service Advertisement Protocol",
892 "IPX SAP", "ipxsap");
893 proto_register_field_array(proto_sap, hf_sap, array_length(hf_sap));
895 proto_register_subtree_array(ett, array_length(ett));
897 ipx_type_dissector_table = register_dissector_table("ipx.packet_type");
898 ipx_socket_dissector_table = register_dissector_table("ipx.socket");
902 proto_reg_handoff_ipx(void)
905 * Get handle for the NBIPX dissector.
907 nbipx_handle = find_dissector("nbipx");
909 dissector_add("udp.port", UDP_PORT_IPX, dissect_ipx, proto_ipx);
910 dissector_add("ethertype", ETHERTYPE_IPX, dissect_ipx, proto_ipx);
911 dissector_add("fr.cisco", ETHERTYPE_IPX, dissect_ipx, proto_ipx);
912 dissector_add("ppp.protocol", PPP_IPX, dissect_ipx, proto_ipx);
913 dissector_add("llc.dsap", SAP_NETWARE, dissect_ipx, proto_ipx);
914 dissector_add("null.type", BSD_AF_IPX, dissect_ipx, proto_ipx);
915 dissector_add("gre.proto", ETHERTYPE_IPX, dissect_ipx, proto_ipx);
916 dissector_add("ipx.packet_type", IPX_PACKET_TYPE_SPX, dissect_spx,
918 dissector_add("ipx.socket", IPX_SOCKET_SAP, dissect_ipxsap,
920 dissector_add("ipx.socket", IPX_SOCKET_IPXRIP, dissect_ipxrip,
922 dissector_add("ipx.socket", IPX_SOCKET_IPX_MESSAGE, dissect_ipxmsg,