2 * Routines for NetWare's IPX
3 * Gilbert Ramirez <gram@xiexie.org>
5 * $Id: packet-ipx.c,v 1.62 2000/06/15 03:48:40 gram 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>
41 #include "packet-ipx.h"
42 #include "packet-nbipx.h"
45 #include "packet-snmp.h"
47 /* The information in this module (IPX, SPX, NCP) comes from:
48 NetWare LAN Analysis, Second Edition
49 Laura A. Chappell and Dan E. Hakes
51 Novell Press, San Jose.
54 And from the ncpfs source code by Volker Lendecke
58 static int proto_ipx = -1;
59 static int hf_ipx_checksum = -1;
60 static int hf_ipx_len = -1;
61 static int hf_ipx_hops = -1;
62 static int hf_ipx_packet_type = -1;
63 static int hf_ipx_dnet = -1;
64 static int hf_ipx_dnode = -1;
65 static int hf_ipx_dsocket = -1;
66 static int hf_ipx_snet = -1;
67 static int hf_ipx_snode = -1;
68 static int hf_ipx_ssocket = -1;
70 static gint ett_ipx = -1;
72 static dissector_table_t ipx_type_dissector_table;
73 static dissector_table_t ipx_socket_dissector_table;
75 static int proto_spx = -1;
76 static int hf_spx_connection_control = -1;
77 static int hf_spx_datastream_type = -1;
78 static int hf_spx_src_id = -1;
79 static int hf_spx_dst_id = -1;
80 static int hf_spx_seq_nr = -1;
81 static int hf_spx_ack_nr = -1;
82 static int hf_spx_all_nr = -1;
84 static gint ett_spx = -1;
86 static int proto_ipxrip = -1;
87 static int hf_ipxrip_request = -1;
88 static int hf_ipxrip_response = -1;
90 static gint ett_ipxrip = -1;
92 static int proto_sap = -1;
93 static int hf_sap_request = -1;
94 static int hf_sap_response = -1;
96 static gint ett_ipxsap = -1;
97 static gint ett_ipxsap_server = -1;
99 static gint ett_ipxmsg = -1;
100 static int proto_ipxmsg = -1;
101 static int hf_msg_conn = -1;
102 static int hf_msg_sigchar = -1;
105 dissect_spx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
108 dissect_ipxrip(const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
111 dissect_ipxsap(const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
114 dissect_ipxmsg(const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
116 #define UDP_PORT_IPX 213 /* RFC 1234 */
118 #define IPX_HEADER_LEN 30 /* It's *always* 30 bytes */
120 /* ================================================================= */
122 /* ================================================================= */
123 static const value_string ipx_socket_vals[] = {
124 { IPX_SOCKET_PING_CISCO, "CISCO PING" },
125 { IPX_SOCKET_NCP, "NCP" },
126 { IPX_SOCKET_SAP, "SAP" },
127 { IPX_SOCKET_IPXRIP, "RIP" },
128 { IPX_SOCKET_NETBIOS, "NetBIOS" },
129 { IPX_SOCKET_DIAGNOSTIC, "Diagnostic" },
130 { IPX_SOCKET_SERIALIZATION, "Serialization" },
131 { IPX_SOCKET_NWLINK_SMB_NAMEQUERY, "NWLink SMB Name Query" },
132 { IPX_SOCKET_NWLINK_SMB_DGRAM, "NWLink SMB Datagram" },
133 { IPX_SOCKET_NWLINK_SMB_BROWSE, "NWLink SMB Browse" },
134 { IPX_SOCKET_ATTACHMATE_GW, "Attachmate Gateway" },
135 { IPX_SOCKET_IPX_MESSAGE, "IPX Message" },
136 { IPX_SOCKET_SNMP_AGENT, "SNMP Agent" },
137 { IPX_SOCKET_SNMP_SINK, "SNMP Sink" },
138 { IPX_SOCKET_PING_NOVELL, "Novell PING" },
139 { IPX_SOCKET_UDP_TUNNEL, "UDP Tunnel" },
140 { IPX_SOCKET_TCP_TUNNEL, "TCP Tunnel" },
141 { IPX_SOCKET_TCP_TUNNEL, "TCP Tunnel" },
142 { IPX_SOCKET_ADSM, "ADSM" },
143 { IPX_SOCKET_EIGRP, "Cisco EIGRP for IPX" },
144 { IPX_SOCKET_WIDE_AREA_ROUTER, "Wide Area Router" },
149 socket_text(guint16 socket)
153 p = match_strval(socket, ipx_socket_vals);
162 static const value_string ipx_packet_type_vals[] = {
163 { IPX_PACKET_TYPE_IPX, "IPX" },
164 { IPX_PACKET_TYPE_RIP, "RIP" },
165 { IPX_PACKET_TYPE_ECHO, "Echo" },
166 { IPX_PACKET_TYPE_ERROR, "Error" },
167 { IPX_PACKET_TYPE_PEP, "PEP" }, /* Packet Exchange Packet */
168 { IPX_PACKET_TYPE_SPX, "SPX" },
169 { 16, "Experimental Protocol" },
170 { IPX_PACKET_TYPE_NCP, "NCP" },
171 { 18, "Experimental Protocol" },
172 { 19, "Experimental Protocol" },
173 { IPX_PACKET_TYPE_WANBCAST, "NetBIOS Broadcast" },
174 { 21, "Experimental Protocol" },
175 { 22, "Experimental Protocol" },
176 { 23, "Experimental Protocol" },
177 { 24, "Experimental Protocol" },
178 { 25, "Experimental Protocol" },
179 { 26, "Experimental Protocol" },
180 { 27, "Experimental Protocol" },
181 { 28, "Experimental Protocol" },
182 { 29, "Experimental Protocol" },
183 { 30, "Experimental Protocol" },
184 { 31, "Experimental Protocol" },
188 static const value_string ipxmsg_sigchar_vals[] = {
189 { '?', "Poll inactive station" },
194 ipxnet_to_string(const guint8 *ad)
196 guint32 addr = pntohl(ad);
197 return ipxnet_to_str_punct(addr, ' ');
200 /* We use a different representation of hardware addresses
201 * than ether_to_str(); we don't put punctuation between the hex
206 ipx_addr_to_str(guint32 net, const guint8 *ad)
208 static gchar str[3][8+1+MAXNAMELEN+1]; /* 8 digits, 1 period, NAME, 1 null */
212 if (cur == &str[0][0]) {
214 } else if (cur == &str[1][0]) {
220 name = get_ether_name_if_known(ad);
223 sprintf(cur, "%s.%s", get_ipxnet_name(net), name);
226 sprintf(cur, "%s.%s", get_ipxnet_name(net), ether_to_str_punct(ad, '\0'));
232 ipxnet_to_str_punct(const guint32 ad, char punct)
234 static gchar str[3][12];
239 static const gchar hex_digits[16] = "0123456789ABCDEF";
240 static const guint32 octet_mask[4] =
241 { 0xff000000 , 0x00ff0000, 0x0000ff00, 0x000000ff };
243 if (cur == &str[0][0]) {
245 } else if (cur == &str[1][0]) {
254 octet = (ad & octet_mask[i]) >> ((3 - i) * 8);
255 *--p = hex_digits[octet&0xF];
257 *--p = hex_digits[octet&0xF];
268 capture_ipx(const u_char *pd, int offset, packet_counts *ld)
275 dissect_ipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
279 dissect_ipx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
281 packet_info *pinfo = π
282 tvbuff_t *tvb = tvb_create_from_top(offset);
285 const guint8 *this_pd;
286 int this_offset, len;
287 const guint8 *next_pd;
290 proto_tree *ipx_tree;
293 guint8 *src_net_node, *dst_net_node;
295 guint8 ipx_type, ipx_hops;
297 int reported_length, available_length;
299 guint16 ipx_dsocket, ipx_ssocket;
302 pinfo->current_proto = "IPX";
304 /* Calculate here for use in pinfo and in tree */
305 ipx_dsocket = tvb_get_ntohs(tvb, 16);
306 ipx_ssocket = tvb_get_ntohs(tvb, 28);
307 ipx_type = tvb_get_guint8(tvb, 5);
308 ipx_length = tvb_get_ntohs(tvb, 2);
310 /* Set the payload and captured-payload lengths to the minima of
311 (the IPX length plus the length of the headers above it) and
312 the frame lengths. XXX - remove once all dissectors use tvbuffs */
313 tvb_compat(tvb, &this_pd, &this_offset);
314 len = ipx_length + this_offset;
317 if (pi.captured_len > len)
318 pi.captured_len = len;
320 src_net_node = tvb_get_ptr(tvb, 18, 10);
321 dst_net_node = tvb_get_ptr(tvb, 6, 10);
323 SET_ADDRESS(&pi.net_src, AT_IPX, 10, src_net_node);
324 SET_ADDRESS(&pi.src, AT_IPX, 10, src_net_node);
325 SET_ADDRESS(&pi.net_dst, AT_IPX, 10, dst_net_node);
326 SET_ADDRESS(&pi.dst, AT_IPX, 10, dst_net_node);
328 if (check_col(pinfo->fd, COL_PROTOCOL))
329 col_add_str(pinfo->fd, COL_PROTOCOL, "IPX");
330 if (check_col(pinfo->fd, COL_INFO))
331 col_add_fstr(pinfo->fd, COL_INFO, "%s (0x%04X)",
332 socket_text(ipx_dsocket), ipx_dsocket);
336 ti = proto_tree_add_item(tree, proto_ipx, tvb, 0, IPX_HEADER_LEN, FALSE);
337 ipx_tree = proto_item_add_subtree(ti, ett_ipx);
339 proto_tree_add_item(ipx_tree, hf_ipx_checksum, tvb, 0, 2, FALSE);
340 proto_tree_add_uint_format(ipx_tree, hf_ipx_len, tvb, 2, 2, ipx_length,
341 "Length: %d bytes", ipx_length);
342 ipx_hops = tvb_get_guint8(tvb, 4);
343 proto_tree_add_uint_format(ipx_tree, hf_ipx_hops, tvb, 4, 1, ipx_hops,
344 "Transport Control: %d hops", ipx_hops);
345 proto_tree_add_uint(ipx_tree, hf_ipx_packet_type, tvb, 5, 1, ipx_type);
348 proto_tree_add_item(ipx_tree, hf_ipx_dnet, tvb, 6, 4, FALSE);
349 proto_tree_add_item(ipx_tree, hf_ipx_dnode, tvb, 10, 6, FALSE);
350 proto_tree_add_uint_format(ipx_tree, hf_ipx_dsocket, tvb, 16, 2,
351 ipx_dsocket, "Destination Socket: %s (0x%04X)",
352 socket_text(ipx_dsocket), ipx_dsocket);
355 proto_tree_add_item(ipx_tree, hf_ipx_snet, tvb, 18, 4, FALSE);
356 proto_tree_add_item(ipx_tree, hf_ipx_snode, tvb, 22, 6, FALSE);
357 proto_tree_add_uint_format(ipx_tree, hf_ipx_ssocket, tvb, 28, 2,
358 ipx_ssocket, "Source Socket: %s (0x%04X)", socket_text(ipx_ssocket),
362 /* Make the next tvbuff */
363 reported_length = ipx_length - IPX_HEADER_LEN;
364 available_length = tvb_length(tvb) - IPX_HEADER_LEN;
365 next_tvb = tvb_new_subset(tvb, IPX_HEADER_LEN,
366 MIN(available_length, reported_length),
369 tvb_compat(next_tvb, &next_pd, &next_offset);
371 if (dissector_try_port(ipx_type_dissector_table, ipx_type, next_pd,
372 next_offset, pinfo->fd, tree))
376 case IPX_PACKET_TYPE_WANBCAST:
377 case IPX_PACKET_TYPE_PEP:
378 if (ipx_dsocket == IPX_SOCKET_NETBIOS) {
379 dissect_nbipx(next_pd, next_offset, pinfo->fd, tree);
382 /* else fall through */
384 case 0: /* IPX, fall through to default */
385 /* XXX - should type 0's be dissected as NBIPX
386 if they're aimed at the NetBIOS socket? */
390 if (dissector_try_port(ipx_socket_dissector_table, ipx_dsocket, next_pd,
391 next_offset, pinfo->fd, tree))
393 if (dissector_try_port(ipx_socket_dissector_table, ipx_ssocket, next_pd,
394 next_offset, pinfo->fd, tree))
396 dissect_data_tvb(next_tvb, pinfo, tree);
400 /* ================================================================= */
402 /* ================================================================= */
404 spx_conn_ctrl(guint8 ctrl)
408 static const value_string conn_vals[] = {
409 { 0x10, "End-of-Message" },
410 { 0x20, "Attention" },
411 { 0x40, "Acknowledgment Required"},
412 { 0x80, "System Packet"},
416 p = match_strval(ctrl, conn_vals);
427 spx_datastream(guint8 type)
431 return "End-of-Connection";
433 return "End-of-Connection Acknowledgment";
435 return "Client-Defined";
439 #define SPX_HEADER_LEN 12
443 dissect_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
447 dissect_spx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
449 packet_info *pinfo = π
450 tvbuff_t *tvb = tvb_create_from_top(offset);
452 proto_tree *spx_tree;
457 guint8 datastream_type;
459 pinfo->current_proto = "SPX";
460 if (check_col(pinfo->fd, COL_PROTOCOL))
461 col_add_str(pinfo->fd, COL_PROTOCOL, "SPX");
462 if (check_col(pinfo->fd, COL_INFO))
463 col_add_str(pinfo->fd, COL_INFO, "SPX");
466 ti = proto_tree_add_item(tree, proto_spx, tvb, 0, SPX_HEADER_LEN, FALSE);
467 spx_tree = proto_item_add_subtree(ti, ett_spx);
469 conn_ctrl = tvb_get_guint8(tvb, 0);
470 proto_tree_add_uint_format(spx_tree, hf_spx_connection_control, tvb,
472 "Connection Control: %s (0x%02X)",
473 spx_conn_ctrl(conn_ctrl), conn_ctrl);
475 datastream_type = tvb_get_guint8(tvb, 1);
476 proto_tree_add_uint_format(spx_tree, hf_spx_datastream_type, tvb,
477 1, 1, datastream_type,
478 "Datastream Type: %s (0x%02X)",
479 spx_datastream(datastream_type), datastream_type);
481 proto_tree_add_item(spx_tree, hf_spx_src_id, tvb, 2, 2, FALSE);
482 proto_tree_add_item(spx_tree, hf_spx_dst_id, tvb, 4, 2, FALSE);
483 proto_tree_add_item(spx_tree, hf_spx_seq_nr, tvb, 6, 2, FALSE);
484 proto_tree_add_item(spx_tree, hf_spx_ack_nr, tvb, 8, 2, FALSE);
485 proto_tree_add_item(spx_tree, hf_spx_all_nr, tvb, 10, 2, FALSE);
487 next_tvb = tvb_new_subset(tvb, SPX_HEADER_LEN, -1, -1);
488 dissect_data_tvb(next_tvb, pinfo, tree);
492 /* ================================================================= */
494 /* ================================================================= */
497 dissect_ipxmsg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
501 dissect_ipxmsg(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
503 packet_info *pinfo = π
504 tvbuff_t *tvb = tvb_create_from_top(offset);
506 proto_tree *msg_tree;
508 guint8 conn_number, sig_char;
510 pinfo->current_proto = "IPX MSG";
512 if (check_col(pinfo->fd, COL_PROTOCOL))
513 col_add_str(pinfo->fd, COL_PROTOCOL, "IPX MSG");
515 conn_number = tvb_get_guint8(tvb, 0);
516 sig_char = tvb_get_guint8(tvb, 1);
518 if (check_col(pinfo->fd, COL_PROTOCOL)) {
519 col_add_fstr(pinfo->fd, COL_INFO,
521 val_to_str(sig_char, ipxmsg_sigchar_vals, "Unknown Signature Char"), conn_number);
525 ti = proto_tree_add_item(tree, proto_ipxmsg, tvb, 0, tvb_length(tvb), FALSE);
526 msg_tree = proto_item_add_subtree(ti, ett_ipxmsg);
528 proto_tree_add_uint(msg_tree, hf_msg_conn, tvb, 0, 1, conn_number);
529 proto_tree_add_uint(msg_tree, hf_msg_sigchar, tvb, 1, 1, sig_char);
534 /* ================================================================= */
536 /* ================================================================= */
539 dissect_ipxrip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
543 dissect_ipxrip(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
545 packet_info *pinfo = π
546 tvbuff_t *tvb = tvb_create_from_top(offset);
548 proto_tree *rip_tree;
551 struct ipx_rt_def route;
553 int available_length;
555 char *rip_type[3] = { "Request", "Response", "Unknown" };
557 pinfo->current_proto = "IPX RIP";
558 if (check_col(pinfo->fd, COL_PROTOCOL))
559 col_add_str(pinfo->fd, COL_PROTOCOL, "IPX RIP");
561 operation = tvb_get_ntohs(tvb, 0) - 1;
563 if (check_col(pinfo->fd, COL_PROTOCOL)) {
564 /* rip_types 0 and 1 are valid, anything else becomes 2 or "Unknown" */
565 col_add_str(pinfo->fd, COL_INFO, rip_type[MIN(operation, 2)]);
569 ti = proto_tree_add_item(tree, proto_ipxrip, tvb, 0, tvb_length(tvb), FALSE);
570 rip_tree = proto_item_add_subtree(ti, ett_ipxrip);
573 proto_tree_add_text(rip_tree, tvb, 0, 2,
574 "RIP packet type: %s", rip_type[operation]);
576 if (operation == 0) {
577 proto_tree_add_boolean_hidden(rip_tree,
581 proto_tree_add_boolean_hidden(rip_tree,
588 proto_tree_add_text(rip_tree, tvb, 0, 2, "Unknown RIP packet type");
591 available_length = tvb_length(tvb);
592 for (cursor = 2; cursor < available_length; cursor += 8) {
593 memcpy(&route.network, tvb_get_ptr(tvb, cursor, 4), 4);
594 route.hops = tvb_get_ntohs(tvb, cursor+4);
595 route.ticks = tvb_get_ntohs(tvb, cursor+6);
597 if (operation == IPX_RIP_REQUEST - 1) {
598 proto_tree_add_text(rip_tree, tvb, cursor, 8,
599 "Route Vector: %s, %d hop%s, %d tick%s",
600 ipxnet_to_string((guint8*)&route.network),
601 route.hops, route.hops == 1 ? "" : "s",
602 route.ticks, route.ticks == 1 ? "" : "s");
605 proto_tree_add_text(rip_tree, tvb, cursor, 8,
606 "Route Vector: %s, %d hop%s, %d tick%s (%d ms)",
607 ipxnet_to_string((guint8*)&route.network),
608 route.hops, route.hops == 1 ? "" : "s",
609 route.ticks, route.ticks == 1 ? "" : "s",
610 route.ticks * 1000 / 18);
618 /* ================================================================= */
620 /* ================================================================= */
622 server_type(guint16 type)
626 /* some of these are from ncpfs, others are from the book */
627 static const value_string server_vals[] = {
629 { 0x0002, "User Group" },
630 { 0x0003, "Print Queue" },
631 { 0x0004, "File server" },
632 { 0x0005, "Job server" },
633 { 0x0007, "Print server" },
634 { 0x0008, "Archive server" },
635 { 0x0009, "Archive server" },
636 { 0x000a, "Job queue" },
637 { 0x000b, "Administration" },
638 { 0x0021, "NAS SNA gateway" },
639 { 0x0024, "Remote bridge" },
640 { 0x0026, "Bridge server" },
641 { 0x0027, "TCP/IP gateway" },
642 { 0x002d, "Time Synchronization VAP" },
643 { 0x002e, "Archive Server Dynamic SAP" },
644 { 0x0047, "Advertising print server" },
645 { 0x004b, "Btrieve VAP 5.0" },
646 { 0x004c, "SQL VAP" },
647 { 0x0050, "Btrieve VAP" },
648 { 0x0053, "Print Queue VAP" },
649 { 0x007a, "TES NetWare for VMS" },
650 { 0x0098, "NetWare access server" },
651 { 0x009a, "Named Pipes server" },
652 { 0x009e, "Portable NetWare Unix" },
653 { 0x0107, "NetWare 386" },
654 { 0x0111, "Test server" },
655 { 0x0133, "NetWare Name Service" },
656 { 0x0166, "NetWare management" },
657 { 0x023f, "SMS Testing and Development" },
658 { 0x026a, "NetWare management" },
659 { 0x026b, "Time synchronization" },
660 { 0x027b, "NetWare Management Agent" },
661 { 0x0278, "NetWare Directory server" },
662 { 0x030c, "HP LaserJet / Quick Silver" },
663 { 0x0355, "Arcada Software" },
664 { 0x0361, "NETINELO" },
665 { 0x037e, "Powerchute UPS Monitoring" },
666 { 0x03e1, "UnixWare Application Server" },
667 { 0x044c, "Archive" },
668 { 0x055d, "Attachmate SNA gateway" },
669 { 0x0610, "Adaptec SCSI Management" },
670 { 0x0640, "NT Server-RPC/GW for NW/Win95 User Level Sec" },
671 { 0x064e, "NT Server-IIS" },
672 { 0x0810, "ELAN License Server Demo" },
673 { 0x8002, "Intel NetPort Print Server" },
675 /* For any unidentified ones, I found a really big list of them at: */
676 /* http://www.inpnet.org/cnpweb/saplist.txt */
677 /* http://www.isi.edu/in-notes/iana/assignments/novell-sap-numbers */
682 p = match_strval(type, server_vals);
693 dissect_ipxsap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
697 dissect_ipxsap(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
699 packet_info *pinfo = π
700 tvbuff_t *tvb = tvb_create_from_top(offset);
703 proto_tree *sap_tree, *s_tree;
706 struct sap_query query;
707 struct sap_server_ident server;
709 char *sap_type[4] = { "General Query", "General Response",
710 "Nearest Query", "Nearest Response" };
712 pinfo->current_proto = "IPX SAP";
713 if (check_col(pinfo->fd, COL_PROTOCOL))
714 col_add_str(pinfo->fd, COL_PROTOCOL, "IPX SAP");
716 query.query_type = tvb_get_ntohs(tvb, 0);
717 query.server_type = tvb_get_ntohs(tvb, 2);
719 if (check_col(pinfo->fd, COL_INFO)) {
720 if (query.query_type >= 1 && query.query_type <= 4) {
721 col_add_str(pinfo->fd, COL_INFO, sap_type[query.query_type - 1]);
724 col_add_str(pinfo->fd, COL_INFO, "Unknown Packet Type");
729 ti = proto_tree_add_item(tree, proto_sap, tvb, 0, tvb_length(tvb), FALSE);
730 sap_tree = proto_item_add_subtree(ti, ett_ipxsap);
732 if (query.query_type >= 1 && query.query_type <= 4) {
733 proto_tree_add_text(sap_tree, tvb, 0, 2, sap_type[query.query_type - 1]);
734 if ((query.query_type - 1) % 2) {
735 proto_tree_add_boolean_hidden(sap_tree,
739 proto_tree_add_boolean_hidden(sap_tree,
745 proto_tree_add_text(sap_tree, tvb, 0, 2,
746 "Unknown SAP Packet Type %d", query.query_type);
749 if (query.query_type == IPX_SAP_GENERAL_RESPONSE ||
750 query.query_type == IPX_SAP_NEAREST_RESPONSE) { /* responses */
752 int available_length = tvb_length(tvb);
753 for (cursor = 2; (cursor + 64) <= available_length; cursor += 64) {
754 server.server_type = tvb_get_ntohs(tvb, cursor);
755 memcpy(server.server_name, tvb_get_ptr(tvb, cursor+2, 48), 48);
756 memcpy(&server.server_network, tvb_get_ptr(tvb, cursor+50, 4), 4);
757 memcpy(&server.server_node, tvb_get_ptr(tvb, cursor+54, 6), 6);
758 server.server_port = tvb_get_ntohs(tvb, cursor+60);
759 server.intermediate_network = tvb_get_ntohs(tvb, cursor+62);
761 ti = proto_tree_add_text(sap_tree, tvb, cursor+2, 48,
762 "Server Name: %s", server.server_name);
763 s_tree = proto_item_add_subtree(ti, ett_ipxsap_server);
765 proto_tree_add_text(s_tree, tvb, cursor, 2, "Server Type: %s (0x%04X)",
766 server_type(server.server_type), server.server_type);
767 proto_tree_add_text(s_tree, tvb, cursor+50, 4, "Network: %s",
768 ipxnet_to_string((guint8*)tvb_get_ptr(tvb, cursor+50, 4)));
769 proto_tree_add_text(s_tree, tvb, cursor+54, 6, "Node: %s",
770 ether_to_str((guint8*)tvb_get_ptr(tvb, cursor+54, 6)));
771 proto_tree_add_text(s_tree, tvb, cursor+60, 2, "Socket: %s (0x%04X)",
772 socket_text(server.server_port), server.server_port);
773 proto_tree_add_text(s_tree, tvb, cursor+62, 2,
774 "Intermediate Networks: %d",
775 server.intermediate_network);
779 proto_tree_add_text(sap_tree, tvb, 2, 2, "Server Type: %s (0x%04X)",
780 server_type(query.server_type), query.server_type);
786 proto_register_ipx(void)
788 static hf_register_info hf_ipx[] = {
790 { "Checksum", "ipx.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
794 { "Length", "ipx.len", FT_UINT16, BASE_DEC, NULL, 0x0,
798 { "Transport Control (Hops)", "ipx.hops", FT_UINT8, BASE_DEC, NULL, 0x0,
801 { &hf_ipx_packet_type,
802 { "Packet Type", "ipx.packet_type", FT_UINT8, BASE_HEX, VALS(ipx_packet_type_vals),
807 { "Destination Network","ipx.dst.net", FT_IPXNET, BASE_NONE, NULL, 0x0,
811 { "Destination Node", "ipx.dst.node", FT_ETHER, BASE_NONE, NULL, 0x0,
815 { "Destination Socket", "ipx.dst.socket", FT_UINT16, BASE_HEX, NULL, 0x0,
819 { "Source Network","ipx.src.net", FT_IPXNET, BASE_NONE, NULL, 0x0,
823 { "Source Node", "ipx.src.node", FT_ETHER, BASE_NONE, NULL, 0x0,
827 { "Source Socket", "ipx.src.socket", FT_UINT16, BASE_HEX, NULL, 0x0,
831 static hf_register_info hf_spx[] = {
832 { &hf_spx_connection_control,
833 { "Connection Control", "spx.ctl",
834 FT_UINT8, BASE_HEX, NULL, 0x0,
837 { &hf_spx_datastream_type,
838 { "Datastream type", "spx.type",
839 FT_UINT8, BASE_HEX, NULL, 0x0,
843 { "Source Connection ID", "spx.src",
844 FT_UINT16, BASE_DEC, NULL, 0x0,
848 { "Destination Connection ID", "spx.dst",
849 FT_UINT16, BASE_DEC, NULL, 0x0,
853 { "Sequence Number", "spx.seq",
854 FT_UINT16, BASE_DEC, NULL, 0x0,
858 { "Acknowledgment Number", "spx.ack",
859 FT_UINT16, BASE_DEC, NULL, 0x0,
863 { "Allocation Number", "spx.alloc",
864 FT_UINT16, BASE_DEC, NULL, 0x0,
868 static hf_register_info hf_ipxrip[] = {
869 { &hf_ipxrip_request,
870 { "Request", "ipxrip.request",
871 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
872 "TRUE if IPX RIP request" }},
874 { &hf_ipxrip_response,
875 { "Response", "ipxrip.response",
876 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
877 "TRUE if IPX RIP response" }}
880 static hf_register_info hf_sap[] = {
882 { "Request", "ipxsap.request",
883 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
884 "TRUE if SAP request" }},
887 { "Response", "ipxsap.response",
888 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
889 "TRUE if SAP response" }}
892 static hf_register_info hf_ipxmsg[] = {
894 { "Connection Number", "ipxmsg.conn",
895 FT_UINT8, BASE_NONE, NULL, 0x0,
896 "Connection Number" }},
899 { "Signature Char", "ipxmsg.sigchar",
900 FT_UINT8, BASE_NONE, VALS(ipxmsg_sigchar_vals), 0x0,
904 static gint *ett[] = {
913 proto_ipx = proto_register_protocol ("Internetwork Packet eXchange", "ipx");
914 proto_register_field_array(proto_ipx, hf_ipx, array_length(hf_ipx));
916 proto_spx = proto_register_protocol ("Sequenced Packet eXchange", "spx");
917 proto_register_field_array(proto_spx, hf_spx, array_length(hf_spx));
919 proto_ipxrip = proto_register_protocol ("IPX Routing Information Protocol", "ipxrip");
920 proto_register_field_array(proto_ipxrip, hf_ipxrip, array_length(hf_ipxrip));
922 proto_ipxmsg = proto_register_protocol ("IPX Message", "ipxmsg");
923 proto_register_field_array(proto_ipxmsg, hf_ipxmsg, array_length(hf_ipxmsg));
925 proto_sap = proto_register_protocol ("Service Advertisement Protocol", "ipxsap");
926 proto_register_field_array(proto_sap, hf_sap, array_length(hf_sap));
928 proto_register_subtree_array(ett, array_length(ett));
930 ipx_type_dissector_table = register_dissector_table("ipx.packet_type");
931 ipx_socket_dissector_table = register_dissector_table("ipx.socket");
935 proto_reg_handoff_ipx(void)
937 dissector_add("udp.port", UDP_PORT_IPX, dissect_ipx);
938 dissector_add("ethertype", ETHERTYPE_IPX, dissect_ipx);
939 dissector_add("ppp.protocol", PPP_IPX, dissect_ipx);
940 dissector_add("llc.dsap", SAP_NETWARE, dissect_ipx);
941 dissector_add("ipx.packet_type", IPX_PACKET_TYPE_SPX, dissect_spx);
942 dissector_add("ipx.socket", IPX_SOCKET_SAP, dissect_ipxsap);
943 dissector_add("ipx.socket", IPX_SOCKET_IPXRIP, dissect_ipxrip);
944 dissector_add("ipx.socket", IPX_SOCKET_IPX_MESSAGE, dissect_ipxmsg);