Get rid of some trailing blanks in strings.
[obnox/wireshark/wip.git] / packet-ipx.c
1 /* packet-ipx.c
2  * Routines for NetWare's IPX
3  * Gilbert Ramirez <gram@alumni.rice.edu>
4  *
5  * $Id: packet-ipx.c,v 1.116 2002/10/19 01:17:13 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <glib.h>
33 #include <epan/packet.h>
34 #include "packet-ipx.h"
35 #include <epan/resolv.h>
36 #include "etypes.h"
37 #include "ppptypes.h"
38 #include "llcsaps.h"
39 #include "aftypes.h"
40 #include "arcnet_pids.h"
41
42 /* The information in this module (IPX, SPX, NCP) comes from:
43         NetWare LAN Analysis, Second Edition
44         Laura A. Chappell and Dan E. Hakes
45         (c) 1994 Novell, Inc.
46         Novell Press, San Jose.
47         ISBN: 0-7821-1362-1
48
49   And from the ncpfs source code by Volker Lendecke
50
51 */
52
53 static int proto_ipx = -1;
54 static int hf_ipx_checksum = -1;
55 static int hf_ipx_len = -1;
56 static int hf_ipx_hops = -1;
57 static int hf_ipx_packet_type = -1;
58 static int hf_ipx_dnet = -1;
59 static int hf_ipx_dnode = -1;
60 static int hf_ipx_dsocket = -1;
61 static int hf_ipx_snet = -1;
62 static int hf_ipx_snode = -1;
63 static int hf_ipx_ssocket = -1;
64
65 static gint ett_ipx = -1;
66
67 static dissector_table_t ipx_type_dissector_table;
68 static dissector_table_t ipx_socket_dissector_table;
69 static dissector_table_t spx_socket_dissector_table;
70
71 static int proto_spx = -1;
72 static int hf_spx_connection_control = -1;
73 static int hf_spx_datastream_type = -1;
74 static int hf_spx_src_id = -1;
75 static int hf_spx_dst_id = -1;
76 static int hf_spx_seq_nr = -1;
77 static int hf_spx_ack_nr = -1;
78 static int hf_spx_all_nr = -1;
79
80 static gint ett_spx = -1;
81
82 static int proto_ipxrip = -1;
83 static int hf_ipxrip_request = -1;
84 static int hf_ipxrip_response = -1;
85
86 static gint ett_ipxrip = -1;
87
88 static int proto_sap = -1;
89 static int hf_sap_request = -1;
90 static int hf_sap_response = -1;
91
92 static gint ett_ipxsap = -1;
93 static gint ett_ipxsap_server = -1;
94
95 static gint ett_ipxmsg = -1;
96 static int proto_ipxmsg = -1;
97 static int hf_msg_conn = -1;
98 static int hf_msg_sigchar = -1;
99
100 static dissector_handle_t data_handle;
101
102 static void
103 dissect_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
104
105 static void
106 dissect_ipxrip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
107
108 static void
109 dissect_ipxsap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
110
111 static void
112 dissect_ipxmsg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
113
114 #define UDP_PORT_IPX    213             /* RFC 1234 */
115
116 #define IPX_HEADER_LEN  30              /* It's *always* 30 bytes */
117
118 /* ================================================================= */
119 /* IPX                                                               */
120 /* ================================================================= */
121 static const value_string ipx_socket_vals[] = {
122         { IPX_SOCKET_PING_CISCO,                "CISCO PING" },
123         { IPX_SOCKET_NCP,                       "NCP" },
124         { IPX_SOCKET_SAP,                       "SAP" },
125         { IPX_SOCKET_IPXRIP,                    "RIP" },
126         { IPX_SOCKET_NETBIOS,                   "NetBIOS" },
127         { IPX_SOCKET_DIAGNOSTIC,                "Diagnostic" },
128         { IPX_SOCKET_SERIALIZATION,             "Serialization" },
129         { IPX_SOCKET_NWLINK_SMB_SERVER,         "NWLink SMB Server" },
130         { IPX_SOCKET_NWLINK_SMB_NAMEQUERY,      "NWLink SMB Name Query" },
131         { IPX_SOCKET_NWLINK_SMB_REDIR,          "NWLink SMB Redirector" },
132         { IPX_SOCKET_NWLINK_SMB_MAILSLOT,       "NWLink SMB Mailslot Datagram" },
133         { IPX_SOCKET_NWLINK_SMB_MESSENGER,      "NWLink SMB Messenger" },
134         { IPX_SOCKET_NWLINK_SMB_BROWSE,         "NWLink SMB Browse" },
135         { IPX_SOCKET_ATTACHMATE_GW,             "Attachmate Gateway" },
136         { IPX_SOCKET_IPX_MESSAGE,               "IPX Message" },
137         { IPX_SOCKET_IPX_MESSAGE1,              "IPX Message" },
138         { IPX_SOCKET_SNMP_AGENT,                "SNMP Agent" },
139         { IPX_SOCKET_SNMP_SINK,                 "SNMP Sink" },
140         { IPX_SOCKET_PING_NOVELL,               "Novell PING" },
141         { IPX_SOCKET_UDP_TUNNEL,                "UDP Tunnel" },
142         { IPX_SOCKET_TCP_TUNNEL,                "TCP Tunnel" },
143         { IPX_SOCKET_TCP_TUNNEL,                "TCP Tunnel" },
144         { IPX_SOCKET_ADSM,                      "ADSM" },
145         { IPX_SOCKET_EIGRP,                     "Cisco EIGRP for IPX" },
146         { IPX_SOCKET_WIDE_AREA_ROUTER,          "Wide Area Router" },
147         { SPX_SOCKET_PA,                        "NDPS Printer Agent/PSM" },
148         { SPX_SOCKET_BROKER,                    "NDPS Broker" },
149         { SPX_SOCKET_SRS,                       "NDPS Service Registry Service" },
150         { SPX_SOCKET_ENS,                       "NDPS Event Notification Service" },
151         { SPX_SOCKET_RMS,                       "NDPS Remote Management Service" },
152         { SPX_SOCKET_NOTIFY_LISTENER,           "NDPS Notify Listener" },
153         { 0xE885,                               "NT Server-RPC/GW" },
154         { 0x400C,                               "HP LaserJet/QuickSilver" },
155         { 0x907B,                               "SMS Testing and Development" },
156         { 0x8F83,                               "Powerchute UPS Monitoring" },
157         { 0x4006,                               "NetWare Directory Server" },
158         { 0x8104,                               "NetWare 386" },
159         { 0x0000,                               NULL }
160 };
161
162 static const char*
163 socket_text(guint16 socket)
164 {
165         return val_to_str(socket, ipx_socket_vals, "Unknown");
166 }
167
168 static const value_string ipx_packet_type_vals[] = {
169         { IPX_PACKET_TYPE_IPX,          "IPX" },
170         { IPX_PACKET_TYPE_RIP,          "RIP" },
171         { IPX_PACKET_TYPE_ECHO,         "Echo" },
172         { IPX_PACKET_TYPE_ERROR,        "Error" },
173         { IPX_PACKET_TYPE_PEP,          "PEP" }, /* Packet Exchange Packet */
174         { IPX_PACKET_TYPE_SPX,          "SPX" },
175         { 16,                           "Experimental Protocol" },
176         { IPX_PACKET_TYPE_NCP,          "NCP" },
177         { 18,                           "Experimental Protocol" },
178         { 19,                           "Experimental Protocol" },
179         { IPX_PACKET_TYPE_WANBCAST,     "NetBIOS Broadcast" },
180         { 21,                           "Experimental Protocol" },
181         { 22,                           "Experimental Protocol" },
182         { 23,                           "Experimental Protocol" },
183         { 24,                           "Experimental Protocol" },
184         { 25,                           "Experimental Protocol" },
185         { 26,                           "Experimental Protocol" },
186         { 27,                           "Experimental Protocol" },
187         { 28,                           "Experimental Protocol" },
188         { 29,                           "Experimental Protocol" },
189         { 30,                           "Experimental Protocol" },
190         { 31,                           "Experimental Protocol" },
191         { 0,                            NULL }
192 };
193
194 static const value_string ipxmsg_sigchar_vals[] = {
195         { '?', "Poll inactive station" },
196         { 'Y', "Station is still using the connection" },
197         { '!', "Broadcast message waiting" },
198         { 0, NULL }
199 };
200
201
202 void
203 capture_ipx(packet_counts *ld)
204 {
205         ld->ipx++;
206 }
207
208 static void
209 dissect_ipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
210 {
211         tvbuff_t        *next_tvb;
212
213         proto_tree      *ipx_tree;
214         proto_item      *ti;
215
216         const guint8    *src_net_node, *dst_net_node;
217
218         guint8          ipx_type, ipx_hops;
219         guint16         ipx_length;
220
221         guint16         ipx_dsocket, ipx_ssocket;
222         guint16         low_socket, high_socket;
223
224         if (check_col(pinfo->cinfo, COL_PROTOCOL))
225                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPX");
226         if (check_col(pinfo->cinfo, COL_INFO))
227                 col_clear(pinfo->cinfo, COL_INFO);
228
229         /* Calculate here for use in pinfo and in tree */
230         ipx_dsocket     = tvb_get_ntohs(tvb, 16);
231         ipx_ssocket     = tvb_get_ntohs(tvb, 28);
232         ipx_type        = tvb_get_guint8(tvb, 5);
233         ipx_length      = tvb_get_ntohs(tvb, 2);
234
235         pinfo->ptype = PT_IPX;
236         pinfo->srcport = ipx_ssocket;
237         pinfo->destport = ipx_dsocket;
238
239         /* Adjust the tvbuff length to include only the IPX datagram. */
240         set_actual_length(tvb, ipx_length);
241
242         src_net_node = tvb_get_ptr(tvb, 18, 10);
243         dst_net_node = tvb_get_ptr(tvb, 6,  10);
244
245         SET_ADDRESS(&pinfo->net_src,    AT_IPX, 10, src_net_node);
246         SET_ADDRESS(&pinfo->src,        AT_IPX, 10, src_net_node);
247         SET_ADDRESS(&pinfo->net_dst,    AT_IPX, 10, dst_net_node);
248         SET_ADDRESS(&pinfo->dst,        AT_IPX, 10, dst_net_node);
249
250         if (check_col(pinfo->cinfo, COL_INFO))
251                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s (0x%04x)",
252                                 socket_text(ipx_dsocket), ipx_dsocket);
253
254         if (tree) {
255
256                 ti = proto_tree_add_item(tree, proto_ipx, tvb, 0, IPX_HEADER_LEN, FALSE);
257                 ipx_tree = proto_item_add_subtree(ti, ett_ipx);
258
259                 proto_tree_add_item(ipx_tree, hf_ipx_checksum, tvb, 0, 2, FALSE);
260                 proto_tree_add_uint_format(ipx_tree, hf_ipx_len, tvb, 2, 2, ipx_length,
261                         "Length: %d bytes", ipx_length);
262                 ipx_hops = tvb_get_guint8(tvb, 4);
263                 proto_tree_add_uint_format(ipx_tree, hf_ipx_hops, tvb, 4, 1, ipx_hops,
264                         "Transport Control: %d hops", ipx_hops);
265                 proto_tree_add_uint(ipx_tree, hf_ipx_packet_type, tvb, 5, 1, ipx_type);
266
267                 /* Destination */
268                 proto_tree_add_item(ipx_tree, hf_ipx_dnet, tvb, 6, 4, FALSE);
269                 proto_tree_add_item(ipx_tree, hf_ipx_dnode, tvb, 10, 6, FALSE);
270                 proto_tree_add_uint(ipx_tree, hf_ipx_dsocket, tvb, 16, 2,
271                         ipx_dsocket);
272
273                 /* Source */
274                 proto_tree_add_item(ipx_tree, hf_ipx_snet, tvb, 18, 4, FALSE);
275                 proto_tree_add_item(ipx_tree, hf_ipx_snode, tvb, 22, 6, FALSE);
276                 proto_tree_add_uint(ipx_tree, hf_ipx_ssocket, tvb, 28, 2,
277                         ipx_ssocket);
278         }
279
280         /* Make the next tvbuff */
281         next_tvb = tvb_new_subset(tvb, IPX_HEADER_LEN, -1, -1);
282
283         /*
284          * Let the subdissector know what type of IPX packet this is.
285          */
286         pinfo->ipxptype = ipx_type;
287
288         /*
289          * Check the socket numbers before we check the packet type;
290          * we've seen non-NCP packets with a type of NCP and a
291          * destination socket of IPX_SOCKET_IPX_MESSAGE, and SAP
292          * packets with a type of NCP and a destination socket of
293          * IPX_SOCKET_SAP.
294          *
295          * Assume the lower-numbered socket number is more likely
296          * to be the right one, along the lines of what we do for
297          * TCP and UDP.  We've seen NCP packets with a type of NCP,
298          * a source socket of IPX_SOCKET_NCP, and a destination
299          * socket of IPX_SOCKET_IPX_MESSAGE, and we've seen NCP
300          * packets with a type of NCP, a source socket of
301          * IPX_SOCKET_IPX_MESSAGE, and a destination socket of
302          * IPX_SOCKET_NCP.
303          */
304         if (ipx_ssocket > ipx_dsocket) {
305                 low_socket = ipx_dsocket;
306                 high_socket = ipx_ssocket;
307         } else {
308                 low_socket = ipx_ssocket;
309                 high_socket = ipx_dsocket;
310         }
311         if (dissector_try_port(ipx_socket_dissector_table, low_socket,
312             next_tvb, pinfo, tree))
313                 return;
314         if (dissector_try_port(ipx_socket_dissector_table, high_socket,
315             next_tvb, pinfo, tree))
316                 return;
317
318         /*
319          * Neither of them are known; try the packet type, which will
320          * at least let us, for example, dissect SPX packets as SPX.
321          */
322         if (dissector_try_port(ipx_type_dissector_table, ipx_type, next_tvb,
323             pinfo, tree))
324                 return;
325
326         call_dissector(data_handle,next_tvb, pinfo, tree);
327 }
328
329
330 /* ================================================================= */
331 /* SPX                                                               */
332 /* ================================================================= */
333 static const char*
334 spx_conn_ctrl(guint8 ctrl)
335 {
336         const char *p;
337
338         static const value_string conn_vals[] = {
339                 { 0x10, "End-of-Message" },
340                 { 0x20, "Attention" },
341                 { 0x40, "Acknowledgment Required"},
342                 { 0x50, "Send Ack: End Message"},
343                 { 0x80, "System Packet"},
344                 { 0xc0, "System Packet: Send Ack"},
345                 { 0x00, NULL }
346         };
347
348         p = match_strval((ctrl & 0xf0), conn_vals );
349
350         if (p) {
351                 return p;
352         }
353         else {
354                 return "Unknown";
355         }
356 }
357
358 static const char*
359 spx_datastream(guint8 type)
360 {
361         switch (type) {
362                 case 0xfe:
363                         return "End-of-Connection";
364                 case 0xff:
365                         return "End-of-Connection Acknowledgment";
366                 default:
367                         return "Client-Defined";
368         }
369 }
370
371 #define SPX_HEADER_LEN  12
372
373 static void
374 dissect_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
375 {
376         proto_tree      *spx_tree = NULL;
377         proto_item      *ti;
378         tvbuff_t        *next_tvb;
379
380         guint8          conn_ctrl;
381         guint8          datastream_type;
382         const char      *spx_msg_string;
383         guint16         low_socket, high_socket;
384
385         if (check_col(pinfo->cinfo, COL_PROTOCOL))
386                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SPX");
387         if (check_col(pinfo->cinfo, COL_INFO))
388                 col_set_str(pinfo->cinfo, COL_INFO, "SPX");
389
390         if (tree) {
391                 ti = proto_tree_add_item(tree, proto_spx, tvb, 0, SPX_HEADER_LEN, FALSE);
392                 spx_tree = proto_item_add_subtree(ti, ett_spx);
393         }
394
395         conn_ctrl = tvb_get_guint8(tvb, 0);
396         spx_msg_string = spx_conn_ctrl(conn_ctrl);
397         if (check_col(pinfo->cinfo, COL_INFO))
398                 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", spx_msg_string);
399         if (tree) {
400                 proto_tree_add_uint_format(spx_tree, hf_spx_connection_control, tvb,
401                                            0, 1, conn_ctrl,
402                                            "Connection Control: %s (0x%02X)",
403                                            spx_msg_string, conn_ctrl);
404
405                 datastream_type = tvb_get_guint8(tvb, 1);
406                 proto_tree_add_uint_format(spx_tree, hf_spx_datastream_type, tvb,
407                                            1, 1, datastream_type,
408                                            "Datastream Type: %s (0x%02X)",
409                                            spx_datastream(datastream_type), datastream_type);
410
411                 proto_tree_add_item(spx_tree, hf_spx_src_id, tvb,  2, 2, FALSE);
412                 proto_tree_add_item(spx_tree, hf_spx_dst_id, tvb,  4, 2, FALSE);
413                 proto_tree_add_item(spx_tree, hf_spx_seq_nr, tvb,  6, 2, FALSE);
414                 proto_tree_add_item(spx_tree, hf_spx_ack_nr, tvb,  8, 2, FALSE);
415                 proto_tree_add_item(spx_tree, hf_spx_all_nr, tvb, 10, 2, FALSE);
416         }
417
418         if (tvb_reported_length_remaining(tvb, SPX_HEADER_LEN) > 0) {
419                 /*
420                  * Call subdissectors based on the IPX socket numbers; a
421                  * subdissector might have registered with our IPX socket
422                  * dissector table rather than the IPX dissector's socket
423                  * dissector table.
424                  *
425                  * Assume the lower-numbered socket number is more likely
426                  * to be the right one, along the lines of what we do for
427                  * TCP and UDP.  We've seen NCP packets with a type of NCP,
428                  * a source socket of IPX_SOCKET_NCP, and a destination
429                  * socket of IPX_SOCKET_IPX_MESSAGE, and we've seen NCP
430                  * packets with a type of NCP, a source socket of
431                  * IPX_SOCKET_IPX_MESSAGE, and a destination socket of
432                  * IPX_SOCKET_NCP.
433                  */
434                 if (pinfo->srcport > pinfo->destport) {
435                         low_socket = pinfo->destport;
436                         high_socket = pinfo->srcport;
437                 } else {
438                         low_socket = pinfo->srcport;
439                         high_socket = pinfo->destport;
440                 }
441
442                 next_tvb = tvb_new_subset(tvb, SPX_HEADER_LEN, -1, -1);
443                 if (dissector_try_port(spx_socket_dissector_table, low_socket,
444                     next_tvb, pinfo, tree))
445                         return;
446                 if (dissector_try_port(spx_socket_dissector_table, high_socket,
447                     next_tvb, pinfo, tree))
448                         return;
449                 call_dissector(data_handle, next_tvb, pinfo, tree);
450         }
451 }
452
453 /* ================================================================= */
454 /* IPX Message                                                       */
455 /* ================================================================= */
456 static void
457 dissect_ipxmsg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
458 {
459         proto_tree      *msg_tree;
460         proto_item      *ti;
461         guint8          conn_number, sig_char;
462
463         if (check_col(pinfo->cinfo, COL_PROTOCOL))
464                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPX MSG");
465         if (check_col(pinfo->cinfo, COL_INFO))
466                 col_clear(pinfo->cinfo, COL_INFO);
467
468         conn_number = tvb_get_guint8(tvb, 0);
469         sig_char = tvb_get_guint8(tvb, 1);
470
471         if (check_col(pinfo->cinfo, COL_INFO)) {
472                 col_add_fstr(pinfo->cinfo, COL_INFO,
473                         "%s, Connection %d",
474                         val_to_str(sig_char, ipxmsg_sigchar_vals, "Unknown Signature Char"), conn_number);
475         }
476
477         if (tree) {
478                 ti = proto_tree_add_item(tree, proto_ipxmsg, tvb, 0, -1, FALSE);
479                 msg_tree = proto_item_add_subtree(ti, ett_ipxmsg);
480
481                 proto_tree_add_uint(msg_tree, hf_msg_conn, tvb, 0, 1, conn_number);
482                 proto_tree_add_uint(msg_tree, hf_msg_sigchar, tvb, 1, 1, sig_char);
483         }
484 }
485
486
487 /* ================================================================= */
488 /* IPX RIP                                                           */
489 /* ================================================================= */
490 static void
491 dissect_ipxrip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
492 {
493         proto_tree      *rip_tree;
494         proto_item      *ti;
495         guint16         operation;
496         struct ipx_rt_def route;
497         int             cursor;
498         int             available_length;
499
500         static char     *rip_type[3] = { "Request", "Response", "Unknown" };
501
502         if (check_col(pinfo->cinfo, COL_PROTOCOL))
503                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPX RIP");
504         if (check_col(pinfo->cinfo, COL_INFO))
505                 col_clear(pinfo->cinfo, COL_INFO);
506
507         operation = tvb_get_ntohs(tvb, 0) - 1;
508
509         if (check_col(pinfo->cinfo, COL_INFO)) {
510                 /* rip_types 0 and 1 are valid, anything else becomes 2 or "Unknown" */
511                 col_set_str(pinfo->cinfo, COL_INFO, rip_type[MIN(operation, 2)]);
512         }
513
514         if (tree) {
515                 ti = proto_tree_add_item(tree, proto_ipxrip, tvb, 0, -1, FALSE);
516                 rip_tree = proto_item_add_subtree(ti, ett_ipxrip);
517
518                 if (operation < 2) {
519                         proto_tree_add_text(rip_tree, tvb, 0, 2,
520                         "RIP packet type: %s", rip_type[operation]);
521
522                         if (operation == 0) {
523                           proto_tree_add_boolean_hidden(rip_tree,
524                                                      hf_ipxrip_request,
525                                                      tvb, 0, 2, 1);
526                         } else {
527                           proto_tree_add_boolean_hidden(rip_tree,
528                                                      hf_ipxrip_response,
529                                                      tvb, 0, 2, 1);
530                         }
531
532                 }
533                 else {
534                         proto_tree_add_text(rip_tree, tvb, 0, 2, "Unknown RIP packet type");
535                 }
536
537                 available_length = tvb_reported_length(tvb);
538                 for (cursor =  2; cursor < available_length; cursor += 8) {
539                         tvb_memcpy(tvb, (guint8 *)&route.network, cursor, 4);
540                         route.hops = tvb_get_ntohs(tvb, cursor+4);
541                         route.ticks = tvb_get_ntohs(tvb, cursor+6);
542
543                         if (operation == IPX_RIP_REQUEST - 1) {
544                                 proto_tree_add_text(rip_tree, tvb, cursor,      8,
545                                         "Route Vector: %s, %d hop%s, %d tick%s",
546                                         ipxnet_to_string((guint8*)&route.network),
547                                         route.hops,  route.hops  == 1 ? "" : "s",
548                                         route.ticks, route.ticks == 1 ? "" : "s");
549                         }
550                         else {
551                                 proto_tree_add_text(rip_tree, tvb, cursor,      8,
552                                         "Route Vector: %s, %d hop%s, %d tick%s (%d ms)",
553                                         ipxnet_to_string((guint8*)&route.network),
554                                         route.hops,  route.hops  == 1 ? "" : "s",
555                                         route.ticks, route.ticks == 1 ? "" : "s",
556                                         route.ticks * 1000 / 18);
557                         }
558                 }
559         }
560 }
561
562
563
564 /* ================================================================= */
565 /* SAP                                                                   */
566 /* ================================================================= */
567 static const char*
568 server_type(guint16 type)
569 {
570         const char *p;
571
572         /*
573          * Some of these are from ncpfs, others are from the book,
574          * others are from the page at
575          *
576          *      http://www.iana.org/assignments/novell-sap-numbers
577          *
578          * and some from the page at
579          *
580          *      http://www.rware.demon.co.uk/ipxsap.htm
581          *
582          * (see also the page at
583          *
584          *      http://developer.novell.com/research/appnotes/1998/february/03/06.htm
585          *
586          * which has a huge list - but many of the entries list only the
587          * organization owning the SAP type, not what the type is for).
588          */
589         static const value_string server_vals[] = {
590                 { 0x0000,       "Unknown" },
591                 { 0x0001,       "User" },
592                 { 0x0002,       "User Group" },
593                 { 0x0003,       "Print Queue or Print Group" },
594                 { 0x0004,       "File Server (SLIST source)" },
595                 { 0x0005,       "Job Server" },
596                 { 0x0006,       "Gateway" },
597                 { 0x0007,       "Print Server or Silent Print Server" },
598                 { 0x0008,       "Archive Queue" },
599                 { 0x0009,       "Archive Server" },
600                 { 0x000a,       "Job Queue" },
601                 { 0x000b,       "Administration" },
602                 { 0x000F,       "Novell TI-RPC" },
603                 { 0x0017,       "Diagnostics" },
604                 { 0x0020,       "NetBIOS" },
605                 { 0x0021,       "NAS SNA Gateway" },
606                 { 0x0023,       "NACS Async Gateway or Asynchronous Gateway" },
607                 { 0x0024,       "Remote Bridge or Routing Service" },
608                 { 0x0026,       "Bridge Server or Asynchronous Bridge Server" },
609                 { 0x0027,       "TCP/IP Gateway Server" },
610                 { 0x0028,       "Point to Point (Eicon) X.25 Bridge Server" },
611                 { 0x0029,       "Eicon 3270 Gateway" },
612                 { 0x002a,       "CHI Corp" },
613                 { 0x002c,       "PC Chalkboard" },
614                 { 0x002d,       "Time Synchronization Server or Asynchronous Timer" },
615                 { 0x002e,       "ARCserve 5.0 / Palindrome Backup Director 4.x (PDB4)" },
616                 { 0x0045,       "DI3270 Gateway" },
617                 { 0x0047,       "Advertising Print Server" },
618                 { 0x004a,       "NetBlazer Modems" },
619                 { 0x004b,       "Btrieve VAP/NLM 5.0" },
620                 { 0x004c,       "NetWare SQL VAP/NLM Server" },
621                 { 0x004d,       "Xtree Network Version/NetWare XTree" },
622                 { 0x0050,       "Btrieve VAP 4.11" },
623                 { 0x0052,       "QuickLink (Cubix)" },
624                 { 0x0053,       "Print Queue User" },
625                 { 0x0058,       "Multipoint X.25 Eicon Router" },
626                 { 0x0060,       "STLB/NLM" },
627                 { 0x0064,       "ARCserve" },
628                 { 0x0066,       "ARCserve 3.0" },
629                 { 0x0072,       "WAN Copy Utility" },
630                 { 0x007a,       "TES-NetWare for VMS" },
631                 { 0x0092,       "WATCOM Debugger or Emerald Tape Backup Server" },
632                 { 0x0095,       "DDA OBGYN" },
633                 { 0x0098,       "NetWare Access Server (Asynchronous gateway)" },
634                 { 0x009a,       "NetWare for VMS II or Named Pipe Server" },
635                 { 0x009b,       "NetWare Access Server" },
636                 { 0x009e,       "Portable NetWare Server or SunLink NVT" },
637                 { 0x00a1,       "Powerchute APC UPS NLM" },
638                 { 0x00aa,       "LAWserve" },
639                 { 0x00ac,       "Compaq IDA Status Monitor" },
640                 { 0x0100,       "PIPE STAIL" },
641                 { 0x0102,       "LAN Protect Bindery" },
642                 { 0x0103,       "Oracle DataBase Server" },
643                 { 0x0107,       "NetWare 386 or RSPX Remote Console" },
644                 { 0x010f,       "Novell SNA Gateway" },
645                 { 0x0111,       "Test Server" },
646                 { 0x0112,       "Print Server (HP)" },
647                 { 0x0114,       "CSA MUX (f/Communications Executive)" },
648                 { 0x0115,       "CSA LCA (f/Communications Executive)" },
649                 { 0x0116,       "CSA CM (f/Communications Executive)" },
650                 { 0x0117,       "CSA SMA (f/Communications Executive)" },
651                 { 0x0118,       "CSA DBA (f/Communications Executive)" },
652                 { 0x0119,       "CSA NMA (f/Communications Executive)" },
653                 { 0x011a,       "CSA SSA (f/Communications Executive)" },
654                 { 0x011b,       "CSA STATUS (f/Communications Executive)" },
655                 { 0x011e,       "CSA APPC (f/Communications Executive)" },
656                 { 0x0126,       "SNA TEST SSA Profile" },
657                 { 0x012a,       "CSA TRACE (f/Communications Executive)" },
658                 { 0x012b,       "NetWare for SAA" },
659                 { 0x012e,       "IKARUS virus scan utility" },
660                 { 0x0130,       "Communications Executive" },
661                 { 0x0133,       "NNS Domain Server or NetWare Naming Services Domain" },
662                 { 0x0135,       "NetWare Naming Services Profile" },
663                 { 0x0137,       "NetWare 386 Print Queue or NNS Print Queue" },
664                 { 0x0141,       "LAN Spool Server (Vap, Intel)" },
665                 { 0x0152,       "IRMALAN Gateway" },
666                 { 0x0154,       "Named Pipe Server" },
667                 { 0x0166,       "NetWare Management" },
668                 { 0x0168,       "Intel PICKIT Comm Server or Intel CAS Talk Server" },
669                 { 0x0173,       "Compaq" },
670                 { 0x0174,       "Compaq SNMP Agent" },
671                 { 0x0175,       "Compaq" },
672                 { 0x0180,       "XTree Server or XTree Tools" },
673                 { 0x018A,       "NASI services broadcast server (Novell)" },
674                 { 0x01b0,       "GARP Gateway (net research)" },
675                 { 0x01b1,       "Binfview (Lan Support Group)" },
676                 { 0x01bf,       "Intel LanDesk Manager" },
677                 { 0x01ca,       "AXTEC" },
678                 { 0x01cb,       "Shiva NetModem/E" },
679                 { 0x01cc,       "Shiva LanRover/E" },
680                 { 0x01cd,       "Shiva LanRover/T" },
681                 { 0x01ce,       "Shiva Universal" },
682                 { 0x01d8,       "Castelle FAXPress Server" },
683                 { 0x01da,       "Castelle LANPress Print Server" },
684                 { 0x01dc,       "Castelle FAX/Xerox 7033 Fax Server/Excel Lan Fax" },
685                 { 0x01f0,       "LEGATO" },
686                 { 0x01f5,       "LEGATO" },
687                 { 0x0233,       "NMS Agent or NetWare Management Agent" },
688                 { 0x0237,       "NMS IPX Discovery or LANtern Read/Write Channel" },
689                 { 0x0238,       "NMS IP Discovery or LANtern Trap/Alarm Channel" },
690                 { 0x023a,       "LANtern" },
691                 { 0x023c,       "MAVERICK" },
692                 { 0x023f,       "SMS Testing and Development" },
693                 { 0x024e,       "NetWare Connect" },
694                 { 0x024f,       "NASI server broadcast (Cisco)" },
695                 { 0x026a,       "Network Management (NMS) Service Console" },
696                 { 0x026b,       "Time Synchronization Server (NetWare 4.x)" },
697                 { 0x0278,       "Directory Server (NetWare 4.x)" },
698                 { 0x027b,       "NetWare Management Agent" },
699                 { 0x0280,       "Novell File and Printer Sharing Service for PC" },
700                 { 0x0304,       "Novell SAA Gateway" },
701                 { 0x0308,       "COM or VERMED 1" },
702                 { 0x030a,       "Galacticomm's Worldgroup Server" },
703                 { 0x030c,       "Intel Netport 2 or HP JetDirect or HP Quicksilver" },
704                 { 0x0320,       "Attachmate Gateway" },
705                 { 0x0327,       "Microsoft Diagnostics" },
706                 { 0x0328,       "WATCOM SQL server" },
707                 { 0x0335,       "MultiTech Systems Multisynch Comm Server" },
708                 { 0x0343,       "Xylogics Remote Access Server or LAN Modem" },
709                 { 0x0355,       "Arcada Backup Exec" },
710                 { 0x0358,       "MSLCD1" },
711                 { 0x0361,       "NETINELO" },
712                 { 0x037e,       "Powerchute UPS Monitoring" },
713                 { 0x037f,       "ViruSafe Notify" },
714                 { 0x0386,       "HP Bridge" },
715                 { 0x0387,       "HP Hub" },
716                 { 0x0394,       "NetWare SAA Gateway" },
717                 { 0x039b,       "Lotus Notes" },
718                 { 0x03b7,       "Certus Anti Virus NLM" },
719                 { 0x03c4,       "ARCserve 4.0 (Cheyenne)" },
720                 { 0x03c7,       "LANspool 3.5 (Intel)" },
721                 { 0x03d7,       "Lexmark printer server (type 4033-011)" },
722                 { 0x03d8,       "Lexmark XLE printer server (type 4033-301)" },
723                 { 0x03dd,       "Banyan ENS for NetWare Client NLM" },
724                 { 0x03de,       "Gupta Sequel Base Server or NetWare SQL" },
725                 { 0x03e1,       "Univel Unixware" },
726                 { 0x03e4,       "Univel Unixware" },
727                 { 0x03fc,       "Intel Netport" },
728                 { 0x03fd,       "Intel Print Server Queue" },
729                 { 0x040A,       "ipnServer" },
730                 { 0x040D,       "LVERRMAN" },
731                 { 0x040E,       "LVLIC" },
732                 { 0x0414,       "NET Silicon (DPI)/Kyocera" },
733                 { 0x0429,       "Site Lock Virus (Brightworks)" },
734                 { 0x0432,       "UFHELP R" },
735                 { 0x0433,       "Synoptics 281x Advanced SNMP Agent" },
736                 { 0x0444,       "Microsoft NT SNA Server" },
737                 { 0x0448,       "Oracle" },
738                 { 0x044c,       "ARCserve 5.01" },
739                 { 0x0457,       "Canon GP55 Running on a Canon GP55 network printer" },
740                 { 0x045a,       "QMS Printers" },
741                 { 0x045b,       "Dell SCSI Array (DSA) Monitor" },
742                 { 0x0491,       "NetBlazer Modems" },
743                 { 0x04ac,       "On-Time Scheduler NLM" },
744                 { 0x04b0,       "CD-Net (Meridian)" },
745                 { 0x0513,       "Emulex NQA" },
746                 { 0x0520,       "Site Lock Checks" },
747                 { 0x0529,       "Site Lock Checks (Brightworks)" },
748                 { 0x052d,       "Citrix OS/2 App Server" },
749                 { 0x0535,       "Tektronix" },
750                 { 0x0536,       "Milan" },
751                 { 0x055d,       "Attachmate SNA gateway" },
752                 { 0x056b,       "IBM 8235 modem server" },
753                 { 0x056c,       "Shiva LanRover/E PLUS" },
754                 { 0x056d,       "Shiva LanRover/T PLUS" },
755                 { 0x0580,       "McAfee's NetShield anti-virus" },
756                 { 0x05B8,       "NLM to workstation communication (Revelation Software)" },
757                 { 0x05BA,       "Compatible Systems Routers" },
758                 { 0x05BE,       "Cheyenne Hierarchical Storage Manager" },
759                 { 0x0606,       "JCWatermark Imaging" },
760                 { 0x060c,       "AXIS Network Printer" },
761                 { 0x0610,       "Adaptec SCSI Management" },
762                 { 0x0621,       "IBM AntiVirus NLM" },
763                 { 0x0640,       "Microsoft Gateway Services for NetWare" },
764 /*              { 0x0640,       "NT Server-RPC/GW for NW/Win95 User Level Sec" }, */
765                 { 0x064e,       "Microsoft Internet Information Server" },
766                 { 0x067b,       "Microsoft Win95/98 File and Print Sharing for NetWare" },
767                 { 0x067c,       "Microsoft Win95/98 File and Print Sharing for NetWare" },
768                 { 0x076C,       "Xerox" },
769                 { 0x079b,       "Shiva LanRover/E 115" },
770                 { 0x079c,       "Shiva LanRover/T 115" },
771                 { 0x07B4,       "Cubix WorldDesk" },
772                 { 0x07c2,       "Quarterdeck IWare Connect V2.x NLM" },
773                 { 0x07c1,       "Quarterdeck IWare Connect V3.x NLM" },
774                 { 0x0810,       "ELAN License Server Demo" },
775                 { 0x0824,       "Shiva LanRover Access Switch/E" },
776                 { 0x086a,       "ISSC collector NLMs" },
777                 { 0x087f,       "ISSC DAS agent for AIX" },
778                 { 0x0880,       "Intel Netport PRO" },
779                 { 0x0881,       "Intel Netport PRO" },
780                 { 0x0b29,       "Site Lock" },
781                 { 0x0c29,       "Site Lock Applications" },
782                 { 0x0c2c,       "Licensing Server" },
783                 { 0x2101,       "Performance Technology Instant Internet" },
784                 { 0x2380,       "LAI Site Lock" },
785                 { 0x238c,       "Meeting Maker" },
786                 { 0x4808,       "Site Lock Server or Site Lock Metering VAP/NLM" },
787                 { 0x5555,       "Site Lock User" },
788                 { 0x6312,       "Tapeware" },
789                 { 0x6f00,       "Rabbit Gateway (3270)" },
790                 { 0x7703,       "MODEM" },
791                 { 0x8002,       "NetPort Printers (Intel) or LANport" },
792                 { 0x8003,       "SEH InterCon Printserver" },
793                 { 0x8008,       "WordPerfect Network Version" },
794                 { 0x85BE,       "Cisco Enhanced Interior Routing Protocol (EIGRP)" },
795                 { 0x8888,       "WordPerfect Network Version or Quick Network Management" },
796                 { 0x9000,       "McAfee's NetShield anti-virus" },
797                 { 0x9604,       "CSA-NT_MON" },
798                 { 0xb6a8,       "Ocean Isle Reachout Remote Control" },
799                 { 0xf11f,       "Site Lock Metering VAP/NLM" },
800                 { 0xf1ff,       "Site Lock" },
801                 { 0xf503,       "Microsoft SQL Server" },
802                 { 0xf905,       "IBM Time and Place/2 application" },
803                 { 0xfbfb,       "TopCall III fax server" },
804                 { 0xffff,       "Any Service or Wildcard" },
805                 { 0x0000,       NULL }
806         };
807
808         p = match_strval(type, server_vals);
809         if (p) {
810                 return p;
811         }
812         else {
813                 return "Unknown";
814         }
815 }
816
817 static void
818 dissect_ipxsap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
819 {
820         proto_tree      *sap_tree, *s_tree;
821         proto_item      *ti;
822         int             cursor;
823         struct sap_query query;
824         struct sap_server_ident server;
825
826         static char     *sap_type[4] = { "General Query", "General Response",
827                 "Nearest Query", "Nearest Response" };
828
829         if (check_col(pinfo->cinfo, COL_PROTOCOL))
830                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPX SAP");
831         if (check_col(pinfo->cinfo, COL_INFO))
832                 col_clear(pinfo->cinfo, COL_INFO);
833
834         query.query_type = tvb_get_ntohs(tvb, 0);
835         query.server_type = tvb_get_ntohs(tvb, 2);
836
837         if (check_col(pinfo->cinfo, COL_INFO)) {
838                 if (query.query_type >= 1 && query.query_type <= 4) {
839                         col_set_str(pinfo->cinfo, COL_INFO, sap_type[query.query_type - 1]);
840                 }
841                 else {
842                         col_set_str(pinfo->cinfo, COL_INFO, "Unknown Packet Type");
843                 }
844         }
845
846         if (tree) {
847                 ti = proto_tree_add_item(tree, proto_sap, tvb, 0, -1, FALSE);
848                 sap_tree = proto_item_add_subtree(ti, ett_ipxsap);
849
850                 if (query.query_type >= 1 && query.query_type <= 4) {
851                         proto_tree_add_text(sap_tree, tvb, 0, 2, sap_type[query.query_type - 1]);
852                         if ((query.query_type - 1) % 2) {
853                           proto_tree_add_boolean_hidden(sap_tree,
854                                                      hf_sap_response,
855                                                      tvb, 0, 2, 1);
856                         } else {
857                           proto_tree_add_boolean_hidden(sap_tree,
858                                                      hf_sap_request,
859                                                      tvb, 0, 2, 1);
860                         }
861                 }
862                 else {
863                         proto_tree_add_text(sap_tree, tvb, 0, 2,
864                                         "Unknown SAP Packet Type %d", query.query_type);
865                 }
866
867                 if (query.query_type == IPX_SAP_GENERAL_RESPONSE ||
868                                 query.query_type == IPX_SAP_NEAREST_RESPONSE) { /* responses */
869
870                         int available_length = tvb_reported_length(tvb);
871                         for (cursor =  2; (cursor + 64) <= available_length; cursor += 64) {
872                                 server.server_type = tvb_get_ntohs(tvb, cursor);
873                                 tvb_memcpy(tvb, (guint8 *)server.server_name,
874                                     cursor+2, 48);
875                                 tvb_memcpy(tvb, (guint8 *)&server.server_network,
876                                     cursor+50, 4);
877                                 tvb_memcpy(tvb, (guint8 *)&server.server_node,
878                                     cursor+54, 6);
879                                 server.server_port = tvb_get_ntohs(tvb, cursor+60);
880                                 server.intermediate_network = tvb_get_ntohs(tvb, cursor+62);
881
882                                 ti = proto_tree_add_text(sap_tree, tvb, cursor+2, 48,
883                                         "Server Name: %s", server.server_name);
884                                 s_tree = proto_item_add_subtree(ti, ett_ipxsap_server);
885
886                                 proto_tree_add_text(s_tree, tvb, cursor, 2, "Server Type: %s (0x%04X)",
887                                                 server_type(server.server_type), server.server_type);
888                                 proto_tree_add_text(s_tree, tvb, cursor+50, 4, "Network: %s",
889                                                 ipxnet_to_string((guint8*)tvb_get_ptr(tvb, cursor+50, 4)));
890                                 proto_tree_add_text(s_tree, tvb, cursor+54, 6, "Node: %s",
891                                                 ether_to_str((guint8*)tvb_get_ptr(tvb, cursor+54, 6)));
892                                 proto_tree_add_text(s_tree, tvb, cursor+60, 2, "Socket: %s (0x%04x)",
893                                                 socket_text(server.server_port), server.server_port);
894                                 proto_tree_add_text(s_tree, tvb, cursor+62, 2,
895                                                 "Intermediate Networks: %d",
896                                                 server.intermediate_network);
897                         }
898                 }
899                 else {  /* queries */
900                         proto_tree_add_text(sap_tree, tvb, 2, 2, "Server Type: %s (0x%04X)",
901                                         server_type(query.server_type), query.server_type);
902                 }
903         }
904 }
905
906 void
907 proto_register_ipx(void)
908 {
909         static hf_register_info hf_ipx[] = {
910                 { &hf_ipx_checksum,
911                 { "Checksum",           "ipx.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
912                         "", HFILL }},
913
914                 { &hf_ipx_len,
915                 { "Length",             "ipx.len", FT_UINT16, BASE_DEC, NULL, 0x0,
916                         "", HFILL }},
917
918                 { &hf_ipx_hops,
919                 { "Transport Control (Hops)", "ipx.hops", FT_UINT8, BASE_DEC, NULL, 0x0,
920                         "", HFILL }},
921
922                 { &hf_ipx_packet_type,
923                 { "Packet Type",        "ipx.packet_type", FT_UINT8, BASE_HEX, VALS(ipx_packet_type_vals),
924                         0x0,
925                         "", HFILL }},
926
927                 { &hf_ipx_dnet,
928                 { "Destination Network","ipx.dst.net", FT_IPXNET, BASE_NONE, NULL, 0x0,
929                         "", HFILL }},
930
931                 { &hf_ipx_dnode,
932                 { "Destination Node",   "ipx.dst.node", FT_ETHER, BASE_NONE, NULL, 0x0,
933                         "", HFILL }},
934
935                 { &hf_ipx_dsocket,
936                 { "Destination Socket", "ipx.dst.socket", FT_UINT16, BASE_HEX,
937                         VALS(ipx_socket_vals), 0x0,
938                         "", HFILL }},
939
940                 { &hf_ipx_snet,
941                 { "Source Network","ipx.src.net", FT_IPXNET, BASE_NONE, NULL, 0x0,
942                         "", HFILL }},
943
944                 { &hf_ipx_snode,
945                 { "Source Node",        "ipx.src.node", FT_ETHER, BASE_NONE, NULL, 0x0,
946                         "", HFILL }},
947
948                 { &hf_ipx_ssocket,
949                 { "Source Socket",      "ipx.src.socket", FT_UINT16, BASE_HEX,
950                         VALS(ipx_socket_vals), 0x0,
951                         "", HFILL }},
952         };
953
954         static hf_register_info hf_spx[] = {
955                 { &hf_spx_connection_control,
956                 { "Connection Control",         "spx.ctl",
957                   FT_UINT8,     BASE_HEX,       NULL,   0x0,
958                   "", HFILL }},
959
960                 { &hf_spx_datastream_type,
961                 { "Datastream type",            "spx.type",
962                   FT_UINT8,     BASE_HEX,       NULL,   0x0,
963                   "", HFILL }},
964
965                 { &hf_spx_src_id,
966                 { "Source Connection ID",       "spx.src",
967                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
968                   "", HFILL }},
969
970                 { &hf_spx_dst_id,
971                 { "Destination Connection ID",  "spx.dst",
972                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
973                   "", HFILL }},
974
975                 { &hf_spx_seq_nr,
976                 { "Sequence Number",            "spx.seq",
977                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
978                   "", HFILL }},
979
980                 { &hf_spx_ack_nr,
981                 { "Acknowledgment Number",      "spx.ack",
982                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
983                   "", HFILL }},
984
985                 { &hf_spx_all_nr,
986                 { "Allocation Number",          "spx.alloc",
987                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
988                   "", HFILL }}    };
989
990         static hf_register_info hf_ipxrip[] = {
991                 { &hf_ipxrip_request,
992                 { "Request",                    "ipxrip.request",
993                   FT_BOOLEAN,   BASE_NONE,      NULL,   0x0,
994                   "TRUE if IPX RIP request", HFILL }},
995
996                 { &hf_ipxrip_response,
997                 { "Response",                   "ipxrip.response",
998                   FT_BOOLEAN,   BASE_NONE,      NULL,   0x0,
999                   "TRUE if IPX RIP response", HFILL }}
1000         };
1001
1002         static hf_register_info hf_sap[] = {
1003                 { &hf_sap_request,
1004                 { "Request",                    "ipxsap.request",
1005                   FT_BOOLEAN,   BASE_NONE,      NULL,   0x0,
1006                   "TRUE if SAP request", HFILL }},
1007
1008                 { &hf_sap_response,
1009                 { "Response",                   "ipxsap.response",
1010                   FT_BOOLEAN,   BASE_NONE,      NULL,   0x0,
1011                   "TRUE if SAP response", HFILL }}
1012         };
1013
1014         static hf_register_info hf_ipxmsg[] = {
1015                 { &hf_msg_conn,
1016                 { "Connection Number",                  "ipxmsg.conn",
1017                   FT_UINT8,     BASE_DEC,       NULL,   0x0,
1018                   "Connection Number", HFILL }},
1019
1020                 { &hf_msg_sigchar,
1021                 { "Signature Char",                     "ipxmsg.sigchar",
1022                   FT_UINT8,     BASE_DEC,       VALS(ipxmsg_sigchar_vals),      0x0,
1023                   "Signature Char", HFILL }}
1024         };
1025
1026         static gint *ett[] = {
1027                 &ett_ipx,
1028                 &ett_spx,
1029                 &ett_ipxmsg,
1030                 &ett_ipxrip,
1031                 &ett_ipxsap,
1032                 &ett_ipxsap_server,
1033         };
1034
1035         proto_ipx = proto_register_protocol("Internetwork Packet eXchange",
1036             "IPX", "ipx");
1037         proto_register_field_array(proto_ipx, hf_ipx, array_length(hf_ipx));
1038
1039         register_dissector("ipx", dissect_ipx, proto_ipx);
1040
1041         proto_spx = proto_register_protocol("Sequenced Packet eXchange",
1042             "SPX", "spx");
1043         proto_register_field_array(proto_spx, hf_spx, array_length(hf_spx));
1044
1045         proto_ipxrip = proto_register_protocol("IPX Routing Information Protocol",
1046             "IPX RIP", "ipxrip");
1047         proto_register_field_array(proto_ipxrip, hf_ipxrip, array_length(hf_ipxrip));
1048
1049         proto_ipxmsg = proto_register_protocol("IPX Message", "IPX MSG",
1050             "ipxmsg");
1051         proto_register_field_array(proto_ipxmsg, hf_ipxmsg, array_length(hf_ipxmsg));
1052
1053         proto_sap = proto_register_protocol("Service Advertisement Protocol",
1054             "IPX SAP", "ipxsap");
1055         register_dissector("ipxsap", dissect_ipxsap, proto_sap);
1056
1057         proto_register_field_array(proto_sap, hf_sap, array_length(hf_sap));
1058
1059         proto_register_subtree_array(ett, array_length(ett));
1060
1061         ipx_type_dissector_table = register_dissector_table("ipx.packet_type",
1062             "IPX packet type", FT_UINT8, BASE_HEX);
1063         ipx_socket_dissector_table = register_dissector_table("ipx.socket",
1064             "IPX socket", FT_UINT16, BASE_HEX);
1065         spx_socket_dissector_table = register_dissector_table("spx.socket",
1066             "SPX socket", FT_UINT16, BASE_HEX);
1067 }
1068
1069 void
1070 proto_reg_handoff_ipx(void)
1071 {
1072         dissector_handle_t ipx_handle, spx_handle;
1073         dissector_handle_t ipxsap_handle, ipxrip_handle;
1074         dissector_handle_t ipxmsg_handle;
1075
1076         ipx_handle = find_dissector("ipx");
1077         dissector_add("udp.port", UDP_PORT_IPX, ipx_handle);
1078         dissector_add("ethertype", ETHERTYPE_IPX, ipx_handle);
1079         dissector_add("chdlctype", ETHERTYPE_IPX, ipx_handle);
1080         dissector_add("ppp.protocol", PPP_IPX, ipx_handle);
1081         dissector_add("llc.dsap", SAP_NETWARE, ipx_handle);
1082         dissector_add("null.type", BSD_AF_IPX, ipx_handle);
1083         dissector_add("gre.proto", ETHERTYPE_IPX, ipx_handle);
1084         dissector_add("arcnet.protocol_id", ARCNET_PROTO_IPX, ipx_handle);
1085
1086         spx_handle = create_dissector_handle(dissect_spx, proto_spx);
1087         dissector_add("ipx.packet_type", IPX_PACKET_TYPE_SPX, spx_handle);
1088
1089         ipxsap_handle = find_dissector("ipxsap");
1090         dissector_add("ipx.socket", IPX_SOCKET_SAP, ipxsap_handle);
1091
1092         ipxrip_handle = create_dissector_handle(dissect_ipxrip, proto_ipxrip);
1093         dissector_add("ipx.socket", IPX_SOCKET_IPXRIP, ipxrip_handle);
1094
1095         ipxmsg_handle = create_dissector_handle(dissect_ipxmsg, proto_ipxmsg);
1096         dissector_add("ipx.socket", IPX_SOCKET_IPX_MESSAGE, ipxmsg_handle);
1097         dissector_add("ipx.socket", IPX_SOCKET_IPX_MESSAGE1, ipxmsg_handle);
1098
1099         data_handle = find_dissector("data");
1100 }