2 * Routines for NetWare's IPX
3 * Gilbert Ramirez <gram@xiexie.org>
5 * $Id: packet-ipx.c,v 1.71 2000/12/03 09:18:20 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 CHECK_DISPLAY_AS_DATA(proto_ipx, tvb, pinfo, tree);
296 pinfo->current_proto = "IPX";
298 /* Calculate here for use in pinfo and in tree */
299 ipx_dsocket = tvb_get_ntohs(tvb, 16);
300 ipx_ssocket = tvb_get_ntohs(tvb, 28);
301 ipx_type = tvb_get_guint8(tvb, 5);
302 ipx_length = tvb_get_ntohs(tvb, 2);
304 /* Set the payload and captured-payload lengths to the minima of
305 (the IPX length plus the length of the headers above it) and
306 the frame lengths. XXX - remove once all dissectors use tvbuffs */
307 tvb_compat(tvb, &this_pd, &this_offset);
308 len = ipx_length + this_offset;
311 if (pi.captured_len > len)
312 pi.captured_len = len;
314 src_net_node = tvb_get_ptr(tvb, 18, 10);
315 dst_net_node = tvb_get_ptr(tvb, 6, 10);
317 SET_ADDRESS(&pi.net_src, AT_IPX, 10, src_net_node);
318 SET_ADDRESS(&pi.src, AT_IPX, 10, src_net_node);
319 SET_ADDRESS(&pi.net_dst, AT_IPX, 10, dst_net_node);
320 SET_ADDRESS(&pi.dst, AT_IPX, 10, dst_net_node);
322 if (check_col(pinfo->fd, COL_PROTOCOL))
323 col_set_str(pinfo->fd, COL_PROTOCOL, "IPX");
324 if (check_col(pinfo->fd, COL_INFO))
325 col_add_fstr(pinfo->fd, COL_INFO, "%s (0x%04X)",
326 socket_text(ipx_dsocket), ipx_dsocket);
330 ti = proto_tree_add_item(tree, proto_ipx, tvb, 0, IPX_HEADER_LEN, FALSE);
331 ipx_tree = proto_item_add_subtree(ti, ett_ipx);
333 proto_tree_add_item(ipx_tree, hf_ipx_checksum, tvb, 0, 2, FALSE);
334 proto_tree_add_uint_format(ipx_tree, hf_ipx_len, tvb, 2, 2, ipx_length,
335 "Length: %d bytes", ipx_length);
336 ipx_hops = tvb_get_guint8(tvb, 4);
337 proto_tree_add_uint_format(ipx_tree, hf_ipx_hops, tvb, 4, 1, ipx_hops,
338 "Transport Control: %d hops", ipx_hops);
339 proto_tree_add_uint(ipx_tree, hf_ipx_packet_type, tvb, 5, 1, ipx_type);
342 proto_tree_add_item(ipx_tree, hf_ipx_dnet, tvb, 6, 4, FALSE);
343 proto_tree_add_item(ipx_tree, hf_ipx_dnode, tvb, 10, 6, FALSE);
344 proto_tree_add_uint_format(ipx_tree, hf_ipx_dsocket, tvb, 16, 2,
345 ipx_dsocket, "Destination Socket: %s (0x%04X)",
346 socket_text(ipx_dsocket), ipx_dsocket);
349 proto_tree_add_item(ipx_tree, hf_ipx_snet, tvb, 18, 4, FALSE);
350 proto_tree_add_item(ipx_tree, hf_ipx_snode, tvb, 22, 6, FALSE);
351 proto_tree_add_uint_format(ipx_tree, hf_ipx_ssocket, tvb, 28, 2,
352 ipx_ssocket, "Source Socket: %s (0x%04X)", socket_text(ipx_ssocket),
356 /* Make the next tvbuff */
357 reported_length = ipx_length - IPX_HEADER_LEN;
358 available_length = tvb_length(tvb) - IPX_HEADER_LEN;
359 next_tvb = tvb_new_subset(tvb, IPX_HEADER_LEN,
360 MIN(available_length, reported_length),
363 if (dissector_try_port(ipx_type_dissector_table, ipx_type, next_tvb,
368 case IPX_PACKET_TYPE_WANBCAST:
369 case IPX_PACKET_TYPE_PEP:
370 if (ipx_dsocket == IPX_SOCKET_NETBIOS) {
371 call_dissector(nbipx_handle, next_tvb, pinfo,
375 /* else fall through */
377 case 0: /* IPX, fall through to default */
378 /* XXX - should type 0's be dissected as NBIPX
379 if they're aimed at the NetBIOS socket? */
383 if (dissector_try_port(ipx_socket_dissector_table, ipx_dsocket,
384 next_tvb, pinfo, tree))
386 if (dissector_try_port(ipx_socket_dissector_table, ipx_ssocket,
387 next_tvb, pinfo, tree))
389 dissect_data(next_tvb, 0, pinfo, tree);
393 /* ================================================================= */
395 /* ================================================================= */
397 spx_conn_ctrl(guint8 ctrl)
401 static const value_string conn_vals[] = {
402 { 0x10, "End-of-Message" },
403 { 0x20, "Attention" },
404 { 0x40, "Acknowledgment Required"},
405 { 0x80, "System Packet"},
409 p = match_strval(ctrl, conn_vals);
420 spx_datastream(guint8 type)
424 return "End-of-Connection";
426 return "End-of-Connection Acknowledgment";
428 return "Client-Defined";
432 #define SPX_HEADER_LEN 12
435 dissect_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
437 proto_tree *spx_tree;
442 guint8 datastream_type;
444 CHECK_DISPLAY_AS_DATA(proto_spx, tvb, pinfo, tree);
446 pinfo->current_proto = "SPX";
447 if (check_col(pinfo->fd, COL_PROTOCOL))
448 col_set_str(pinfo->fd, COL_PROTOCOL, "SPX");
449 if (check_col(pinfo->fd, COL_INFO))
450 col_set_str(pinfo->fd, COL_INFO, "SPX");
453 ti = proto_tree_add_item(tree, proto_spx, tvb, 0, SPX_HEADER_LEN, FALSE);
454 spx_tree = proto_item_add_subtree(ti, ett_spx);
456 conn_ctrl = tvb_get_guint8(tvb, 0);
457 proto_tree_add_uint_format(spx_tree, hf_spx_connection_control, tvb,
459 "Connection Control: %s (0x%02X)",
460 spx_conn_ctrl(conn_ctrl), conn_ctrl);
462 datastream_type = tvb_get_guint8(tvb, 1);
463 proto_tree_add_uint_format(spx_tree, hf_spx_datastream_type, tvb,
464 1, 1, datastream_type,
465 "Datastream Type: %s (0x%02X)",
466 spx_datastream(datastream_type), datastream_type);
468 proto_tree_add_item(spx_tree, hf_spx_src_id, tvb, 2, 2, FALSE);
469 proto_tree_add_item(spx_tree, hf_spx_dst_id, tvb, 4, 2, FALSE);
470 proto_tree_add_item(spx_tree, hf_spx_seq_nr, tvb, 6, 2, FALSE);
471 proto_tree_add_item(spx_tree, hf_spx_ack_nr, tvb, 8, 2, FALSE);
472 proto_tree_add_item(spx_tree, hf_spx_all_nr, tvb, 10, 2, FALSE);
474 next_tvb = tvb_new_subset(tvb, SPX_HEADER_LEN, -1, -1);
475 dissect_data(next_tvb, 0, pinfo, tree);
479 /* ================================================================= */
481 /* ================================================================= */
483 dissect_ipxmsg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
485 proto_tree *msg_tree;
487 guint8 conn_number, sig_char;
489 CHECK_DISPLAY_AS_DATA(proto_ipxmsg, tvb, pinfo, tree);
491 pinfo->current_proto = "IPX MSG";
493 if (check_col(pinfo->fd, COL_PROTOCOL))
494 col_set_str(pinfo->fd, COL_PROTOCOL, "IPX MSG");
496 conn_number = tvb_get_guint8(tvb, 0);
497 sig_char = tvb_get_guint8(tvb, 1);
499 if (check_col(pinfo->fd, COL_INFO)) {
500 col_add_fstr(pinfo->fd, COL_INFO,
502 val_to_str(sig_char, ipxmsg_sigchar_vals, "Unknown Signature Char"), conn_number);
506 ti = proto_tree_add_item(tree, proto_ipxmsg, tvb, 0, tvb_length(tvb), FALSE);
507 msg_tree = proto_item_add_subtree(ti, ett_ipxmsg);
509 proto_tree_add_uint(msg_tree, hf_msg_conn, tvb, 0, 1, conn_number);
510 proto_tree_add_uint(msg_tree, hf_msg_sigchar, tvb, 1, 1, sig_char);
515 /* ================================================================= */
517 /* ================================================================= */
519 dissect_ipxrip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
521 proto_tree *rip_tree;
524 struct ipx_rt_def route;
526 int available_length;
528 char *rip_type[3] = { "Request", "Response", "Unknown" };
530 CHECK_DISPLAY_AS_DATA(proto_ipxrip, tvb, pinfo, tree);
532 pinfo->current_proto = "IPX RIP";
533 if (check_col(pinfo->fd, COL_PROTOCOL))
534 col_set_str(pinfo->fd, COL_PROTOCOL, "IPX RIP");
536 operation = tvb_get_ntohs(tvb, 0) - 1;
538 if (check_col(pinfo->fd, COL_INFO)) {
539 /* rip_types 0 and 1 are valid, anything else becomes 2 or "Unknown" */
540 col_add_str(pinfo->fd, COL_INFO, rip_type[MIN(operation, 2)]);
544 ti = proto_tree_add_item(tree, proto_ipxrip, tvb, 0, tvb_length(tvb), FALSE);
545 rip_tree = proto_item_add_subtree(ti, ett_ipxrip);
548 proto_tree_add_text(rip_tree, tvb, 0, 2,
549 "RIP packet type: %s", rip_type[operation]);
551 if (operation == 0) {
552 proto_tree_add_boolean_hidden(rip_tree,
556 proto_tree_add_boolean_hidden(rip_tree,
563 proto_tree_add_text(rip_tree, tvb, 0, 2, "Unknown RIP packet type");
566 available_length = tvb_length(tvb);
567 for (cursor = 2; cursor < available_length; cursor += 8) {
568 memcpy(&route.network, tvb_get_ptr(tvb, cursor, 4), 4);
569 route.hops = tvb_get_ntohs(tvb, cursor+4);
570 route.ticks = tvb_get_ntohs(tvb, cursor+6);
572 if (operation == IPX_RIP_REQUEST - 1) {
573 proto_tree_add_text(rip_tree, tvb, cursor, 8,
574 "Route Vector: %s, %d hop%s, %d tick%s",
575 ipxnet_to_string((guint8*)&route.network),
576 route.hops, route.hops == 1 ? "" : "s",
577 route.ticks, route.ticks == 1 ? "" : "s");
580 proto_tree_add_text(rip_tree, tvb, cursor, 8,
581 "Route Vector: %s, %d hop%s, %d tick%s (%d ms)",
582 ipxnet_to_string((guint8*)&route.network),
583 route.hops, route.hops == 1 ? "" : "s",
584 route.ticks, route.ticks == 1 ? "" : "s",
585 route.ticks * 1000 / 18);
593 /* ================================================================= */
595 /* ================================================================= */
597 server_type(guint16 type)
601 /* some of these are from ncpfs, others are from the book */
602 static const value_string server_vals[] = {
604 { 0x0002, "User Group" },
605 { 0x0003, "Print Queue" },
606 { 0x0004, "File server" },
607 { 0x0005, "Job server" },
608 { 0x0007, "Print server" },
609 { 0x0008, "Archive server" },
610 { 0x0009, "Archive server" },
611 { 0x000a, "Job queue" },
612 { 0x000b, "Administration" },
613 { 0x0021, "NAS SNA gateway" },
614 { 0x0024, "Remote bridge" },
615 { 0x0026, "Bridge server" },
616 { 0x0027, "TCP/IP gateway" },
617 { 0x002d, "Time Synchronization VAP" },
618 { 0x002e, "Archive Server Dynamic SAP" },
619 { 0x0047, "Advertising print server" },
620 { 0x004b, "Btrieve VAP 5.0" },
621 { 0x004c, "SQL VAP" },
622 { 0x0050, "Btrieve VAP" },
623 { 0x0053, "Print Queue VAP" },
624 { 0x007a, "TES NetWare for VMS" },
625 { 0x0098, "NetWare access server" },
626 { 0x009a, "Named Pipes server" },
627 { 0x009e, "Portable NetWare Unix" },
628 { 0x0107, "NetWare 386" },
629 { 0x0111, "Test server" },
630 { 0x0133, "NetWare Name Service" },
631 { 0x0166, "NetWare management" },
632 { 0x023f, "SMS Testing and Development" },
633 { 0x026a, "NetWare management" },
634 { 0x026b, "Time synchronization" },
635 { 0x027b, "NetWare Management Agent" },
636 { 0x0278, "NetWare Directory server" },
637 { 0x030c, "HP LaserJet / Quick Silver" },
638 { 0x0355, "Arcada Software" },
639 { 0x0361, "NETINELO" },
640 { 0x037e, "Powerchute UPS Monitoring" },
641 { 0x03e1, "UnixWare Application Server" },
642 { 0x044c, "Archive" },
643 { 0x055d, "Attachmate SNA gateway" },
644 { 0x0610, "Adaptec SCSI Management" },
645 { 0x0640, "NT Server-RPC/GW for NW/Win95 User Level Sec" },
646 { 0x064e, "NT Server-IIS" },
647 { 0x0810, "ELAN License Server Demo" },
648 { 0x8002, "Intel NetPort Print Server" },
650 /* For any unidentified ones, I found a really big list of them at: */
651 /* http://www.inpnet.org/cnpweb/saplist.txt */
652 /* http://www.isi.edu/in-notes/iana/assignments/novell-sap-numbers */
657 p = match_strval(type, server_vals);
667 dissect_ipxsap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
669 proto_tree *sap_tree, *s_tree;
672 struct sap_query query;
673 struct sap_server_ident server;
675 char *sap_type[4] = { "General Query", "General Response",
676 "Nearest Query", "Nearest Response" };
678 CHECK_DISPLAY_AS_DATA(proto_sap, tvb, pinfo, tree);
680 pinfo->current_proto = "IPX SAP";
681 if (check_col(pinfo->fd, COL_PROTOCOL))
682 col_set_str(pinfo->fd, COL_PROTOCOL, "IPX SAP");
684 query.query_type = tvb_get_ntohs(tvb, 0);
685 query.server_type = tvb_get_ntohs(tvb, 2);
687 if (check_col(pinfo->fd, COL_INFO)) {
688 if (query.query_type >= 1 && query.query_type <= 4) {
689 col_add_str(pinfo->fd, COL_INFO, sap_type[query.query_type - 1]);
692 col_set_str(pinfo->fd, COL_INFO, "Unknown Packet Type");
697 ti = proto_tree_add_item(tree, proto_sap, tvb, 0, tvb_length(tvb), FALSE);
698 sap_tree = proto_item_add_subtree(ti, ett_ipxsap);
700 if (query.query_type >= 1 && query.query_type <= 4) {
701 proto_tree_add_text(sap_tree, tvb, 0, 2, sap_type[query.query_type - 1]);
702 if ((query.query_type - 1) % 2) {
703 proto_tree_add_boolean_hidden(sap_tree,
707 proto_tree_add_boolean_hidden(sap_tree,
713 proto_tree_add_text(sap_tree, tvb, 0, 2,
714 "Unknown SAP Packet Type %d", query.query_type);
717 if (query.query_type == IPX_SAP_GENERAL_RESPONSE ||
718 query.query_type == IPX_SAP_NEAREST_RESPONSE) { /* responses */
720 int available_length = tvb_length(tvb);
721 for (cursor = 2; (cursor + 64) <= available_length; cursor += 64) {
722 server.server_type = tvb_get_ntohs(tvb, cursor);
723 memcpy(server.server_name, tvb_get_ptr(tvb, cursor+2, 48), 48);
724 memcpy(&server.server_network, tvb_get_ptr(tvb, cursor+50, 4), 4);
725 memcpy(&server.server_node, tvb_get_ptr(tvb, cursor+54, 6), 6);
726 server.server_port = tvb_get_ntohs(tvb, cursor+60);
727 server.intermediate_network = tvb_get_ntohs(tvb, cursor+62);
729 ti = proto_tree_add_text(sap_tree, tvb, cursor+2, 48,
730 "Server Name: %s", server.server_name);
731 s_tree = proto_item_add_subtree(ti, ett_ipxsap_server);
733 proto_tree_add_text(s_tree, tvb, cursor, 2, "Server Type: %s (0x%04X)",
734 server_type(server.server_type), server.server_type);
735 proto_tree_add_text(s_tree, tvb, cursor+50, 4, "Network: %s",
736 ipxnet_to_string((guint8*)tvb_get_ptr(tvb, cursor+50, 4)));
737 proto_tree_add_text(s_tree, tvb, cursor+54, 6, "Node: %s",
738 ether_to_str((guint8*)tvb_get_ptr(tvb, cursor+54, 6)));
739 proto_tree_add_text(s_tree, tvb, cursor+60, 2, "Socket: %s (0x%04X)",
740 socket_text(server.server_port), server.server_port);
741 proto_tree_add_text(s_tree, tvb, cursor+62, 2,
742 "Intermediate Networks: %d",
743 server.intermediate_network);
747 proto_tree_add_text(sap_tree, tvb, 2, 2, "Server Type: %s (0x%04X)",
748 server_type(query.server_type), query.server_type);
754 proto_register_ipx(void)
756 static hf_register_info hf_ipx[] = {
758 { "Checksum", "ipx.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
762 { "Length", "ipx.len", FT_UINT16, BASE_DEC, NULL, 0x0,
766 { "Transport Control (Hops)", "ipx.hops", FT_UINT8, BASE_DEC, NULL, 0x0,
769 { &hf_ipx_packet_type,
770 { "Packet Type", "ipx.packet_type", FT_UINT8, BASE_HEX, VALS(ipx_packet_type_vals),
775 { "Destination Network","ipx.dst.net", FT_IPXNET, BASE_NONE, NULL, 0x0,
779 { "Destination Node", "ipx.dst.node", FT_ETHER, BASE_NONE, NULL, 0x0,
783 { "Destination Socket", "ipx.dst.socket", FT_UINT16, BASE_HEX, NULL, 0x0,
787 { "Source Network","ipx.src.net", FT_IPXNET, BASE_NONE, NULL, 0x0,
791 { "Source Node", "ipx.src.node", FT_ETHER, BASE_NONE, NULL, 0x0,
795 { "Source Socket", "ipx.src.socket", FT_UINT16, BASE_HEX, NULL, 0x0,
799 static hf_register_info hf_spx[] = {
800 { &hf_spx_connection_control,
801 { "Connection Control", "spx.ctl",
802 FT_UINT8, BASE_HEX, NULL, 0x0,
805 { &hf_spx_datastream_type,
806 { "Datastream type", "spx.type",
807 FT_UINT8, BASE_HEX, NULL, 0x0,
811 { "Source Connection ID", "spx.src",
812 FT_UINT16, BASE_DEC, NULL, 0x0,
816 { "Destination Connection ID", "spx.dst",
817 FT_UINT16, BASE_DEC, NULL, 0x0,
821 { "Sequence Number", "spx.seq",
822 FT_UINT16, BASE_DEC, NULL, 0x0,
826 { "Acknowledgment Number", "spx.ack",
827 FT_UINT16, BASE_DEC, NULL, 0x0,
831 { "Allocation Number", "spx.alloc",
832 FT_UINT16, BASE_DEC, NULL, 0x0,
836 static hf_register_info hf_ipxrip[] = {
837 { &hf_ipxrip_request,
838 { "Request", "ipxrip.request",
839 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
840 "TRUE if IPX RIP request" }},
842 { &hf_ipxrip_response,
843 { "Response", "ipxrip.response",
844 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
845 "TRUE if IPX RIP response" }}
848 static hf_register_info hf_sap[] = {
850 { "Request", "ipxsap.request",
851 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
852 "TRUE if SAP request" }},
855 { "Response", "ipxsap.response",
856 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
857 "TRUE if SAP response" }}
860 static hf_register_info hf_ipxmsg[] = {
862 { "Connection Number", "ipxmsg.conn",
863 FT_UINT8, BASE_NONE, NULL, 0x0,
864 "Connection Number" }},
867 { "Signature Char", "ipxmsg.sigchar",
868 FT_UINT8, BASE_NONE, VALS(ipxmsg_sigchar_vals), 0x0,
872 static gint *ett[] = {
881 proto_ipx = proto_register_protocol ("Internetwork Packet eXchange", "ipx");
882 proto_register_field_array(proto_ipx, hf_ipx, array_length(hf_ipx));
884 proto_spx = proto_register_protocol ("Sequenced Packet eXchange", "spx");
885 proto_register_field_array(proto_spx, hf_spx, array_length(hf_spx));
887 proto_ipxrip = proto_register_protocol ("IPX Routing Information Protocol", "ipxrip");
888 proto_register_field_array(proto_ipxrip, hf_ipxrip, array_length(hf_ipxrip));
890 proto_ipxmsg = proto_register_protocol ("IPX Message", "ipxmsg");
891 proto_register_field_array(proto_ipxmsg, hf_ipxmsg, array_length(hf_ipxmsg));
893 proto_sap = proto_register_protocol ("Service Advertisement Protocol", "ipxsap");
894 proto_register_field_array(proto_sap, hf_sap, array_length(hf_sap));
896 proto_register_subtree_array(ett, array_length(ett));
898 ipx_type_dissector_table = register_dissector_table("ipx.packet_type");
899 ipx_socket_dissector_table = register_dissector_table("ipx.socket");
903 proto_reg_handoff_ipx(void)
906 * Get handle for the NBIPX dissector.
908 nbipx_handle = find_dissector("nbipx");
910 dissector_add("udp.port", UDP_PORT_IPX, dissect_ipx);
911 dissector_add("ethertype", ETHERTYPE_IPX, dissect_ipx);
912 dissector_add("ppp.protocol", PPP_IPX, dissect_ipx);
913 dissector_add("llc.dsap", SAP_NETWARE, dissect_ipx);
914 dissector_add("null.type", BSD_AF_IPX, dissect_ipx);
915 dissector_add("ipx.packet_type", IPX_PACKET_TYPE_SPX, dissect_spx);
916 dissector_add("ipx.socket", IPX_SOCKET_SAP, dissect_ipxsap);
917 dissector_add("ipx.socket", IPX_SOCKET_IPXRIP, dissect_ipxrip);
918 dissector_add("ipx.socket", IPX_SOCKET_IPX_MESSAGE, dissect_ipxmsg);