Set the svn:eol-style property on all text files to "native", so that
[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  * NDPS support added by Greg Morris (gmorris@novell.com)
5  *
6  * Portions Copyright (c) 2000-2002 by Gilbert Ramirez.
7  * Portions Copyright (c) Novell, Inc. 2002-2003
8  *
9  * $Id$
10  *
11  * Ethereal - Network traffic analyzer
12  * By Gerald Combs <gerald@ethereal.com>
13  * Copyright 1998 Gerald Combs
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <glib.h>
37 #include <epan/packet.h>
38 #include "packet-ipx.h"
39 #include <epan/resolv.h>
40 #include "etypes.h"
41 #include "ppptypes.h"
42 #include "llcsaps.h"
43 #include "aftypes.h"
44 #include "arcnet_pids.h"
45 #include <epan/conversation.h>
46 #include "tap.h"
47
48 static int ipx_tap = -1;
49
50 #define SPX_PACKET_INIT_COUNT   200
51
52 /* The information in this module (IPX, SPX, NCP) comes from:
53         NetWare LAN Analysis, Second Edition
54         Laura A. Chappell and Dan E. Hakes
55         (c) 1994 Novell, Inc.
56         Novell Press, San Jose.
57         ISBN: 0-7821-1362-1
58
59   And from the ncpfs source code by Volker Lendecke
60
61 */
62
63 static int proto_ipx = -1;
64 static int hf_ipx_checksum = -1;
65 static int hf_ipx_len = -1;
66 static int hf_ipx_src = -1;
67 static int hf_ipx_dst = -1;
68 static int hf_ipx_addr = -1;
69 static int hf_ipx_hops = -1;
70 static int hf_ipx_packet_type = -1;
71 static int hf_ipx_dnet = -1;
72 static int hf_ipx_dnode = -1;
73 static int hf_ipx_dsocket = -1;
74 static int hf_ipx_snet = -1;
75 static int hf_ipx_snode = -1;
76 static int hf_ipx_ssocket = -1;
77 static int hf_ipx_net = -1;
78 static int hf_ipx_node = -1;
79 static int hf_ipx_socket = -1;
80
81 static gint ett_ipx = -1;
82
83 static dissector_table_t ipx_type_dissector_table;
84 static dissector_table_t ipx_socket_dissector_table;
85 static dissector_table_t spx_socket_dissector_table;
86
87 static int proto_spx = -1;
88 static int hf_spx_connection_control = -1;
89 static int hf_spx_connection_control_sys = -1;
90 static int hf_spx_connection_control_send_ack = -1;
91 static int hf_spx_connection_control_attn = -1;
92 static int hf_spx_connection_control_eom = -1;
93 static int hf_spx_datastream_type = -1;
94 static int hf_spx_src_id = -1;
95 static int hf_spx_dst_id = -1;
96 static int hf_spx_seq_nr = -1;
97 static int hf_spx_ack_nr = -1;
98 static int hf_spx_all_nr = -1;
99 static int hf_spx_rexmt_frame = -1;
100
101 static gint ett_spx = -1;
102 static gint ett_spx_connctrl = -1;
103
104 static int proto_ipxrip = -1;
105 static int hf_ipxrip_request = -1;
106 static int hf_ipxrip_response = -1;
107
108 static gint ett_ipxrip = -1;
109
110 static int proto_serialization = -1;
111
112 static gint ett_serialization = -1;
113
114 static int proto_sap = -1;
115 static int hf_sap_request = -1;
116 static int hf_sap_response = -1;
117
118 static gint ett_ipxsap = -1;
119 static gint ett_ipxsap_server = -1;
120
121 static gint ett_ipxmsg = -1;
122 static int proto_ipxmsg = -1;
123 static int hf_msg_conn = -1;
124 static int hf_msg_sigchar = -1;
125
126 static dissector_handle_t data_handle;
127
128 static void
129 dissect_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
130
131 static void
132 dissect_ipxrip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
133
134 static void
135 dissect_serialization(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
136
137 static void
138 dissect_ipxsap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
139
140 static void
141 dissect_ipxmsg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
142
143 #define UDP_PORT_IPX    213             /* RFC 1234 */
144
145 #define IPX_HEADER_LEN  30              /* It's *always* 30 bytes */
146
147 /* ================================================================= */
148 /* IPX                                                               */
149 /* ================================================================= */
150 const value_string ipx_socket_vals[] = {
151         { IPX_SOCKET_PING_CISCO,                "CISCO PING" },
152         { IPX_SOCKET_NCP,                       "NCP" },
153         { IPX_SOCKET_SAP,                       "SAP" },
154         { IPX_SOCKET_IPXRIP,                    "RIP" },
155         { IPX_SOCKET_NETBIOS,                   "NetBIOS" },
156         { IPX_SOCKET_DIAGNOSTIC,                "Diagnostic" },
157         { IPX_SOCKET_SERIALIZATION,             "Serialization" },
158         { IPX_SOCKET_NWLINK_SMB_SERVER,         "NWLink SMB Server" },
159         { IPX_SOCKET_NWLINK_SMB_NAMEQUERY,      "NWLink SMB Name Query" },
160         { IPX_SOCKET_NWLINK_SMB_REDIR,          "NWLink SMB Redirector" },
161         { IPX_SOCKET_NWLINK_SMB_MAILSLOT,       "NWLink SMB Mailslot Datagram" },
162         { IPX_SOCKET_NWLINK_SMB_MESSENGER,      "NWLink SMB Messenger" },
163         { IPX_SOCKET_NWLINK_SMB_BROWSE,         "NWLink SMB Browse" },
164         { IPX_SOCKET_ATTACHMATE_GW,             "Attachmate Gateway" },
165         { IPX_SOCKET_IPX_MESSAGE,               "IPX Message" },
166         { IPX_SOCKET_IPX_MESSAGE1,              "IPX Message" },
167         { IPX_SOCKET_SNMP_AGENT,                "SNMP Agent" },
168         { IPX_SOCKET_SNMP_SINK,                 "SNMP Sink" },
169         { IPX_SOCKET_PING_NOVELL,               "Novell PING" },
170         { IPX_SOCKET_UDP_TUNNEL,                "UDP Tunnel" },
171         { IPX_SOCKET_TCP_TUNNEL,                "TCP Tunnel" },
172         { IPX_SOCKET_TCP_TUNNEL,                "TCP Tunnel" },
173         { IPX_SOCKET_ADSM,                      "ADSM" },
174         { IPX_SOCKET_EIGRP,                     "Cisco EIGRP for IPX" },
175         { IPX_SOCKET_NLSP,                      "NetWare Link Services Protocol" },
176         { IPX_SOCKET_IPXWAN,                    "IPX WAN" },
177         { SPX_SOCKET_PA,                        "NDPS Printer Agent/PSM" },
178         { SPX_SOCKET_BROKER,                    "NDPS Broker" },
179         { SPX_SOCKET_SRS,                       "NDPS Service Registry Service" },
180         { SPX_SOCKET_ENS,                       "NDPS Event Notification Service" },
181         { SPX_SOCKET_RMS,                       "NDPS Remote Management Service" },
182         { SPX_SOCKET_NOTIFY_LISTENER,           "NDPS Notify Listener" },
183         { 0xE885,                               "NT Server-RPC/GW" },
184         { 0x400C,                               "HP LaserJet/QuickSilver" },
185         { 0x907B,                               "SMS Testing and Development" },
186         { 0x8F83,                               "Powerchute UPS Monitoring" },
187         { 0x4006,                               "NetWare Directory Server" },
188         { 0x8104,                               "NetWare 386" },
189         { 0x0000,                               NULL }
190 };
191
192 static const char*
193 socket_text(guint16 socket)
194 {
195         return val_to_str(socket, ipx_socket_vals, "Unknown");
196 }
197
198 static const value_string ipx_packet_type_vals[] = {
199         { IPX_PACKET_TYPE_IPX,          "IPX" },
200         { IPX_PACKET_TYPE_RIP,          "RIP" },
201         { IPX_PACKET_TYPE_ECHO,         "Echo" },
202         { IPX_PACKET_TYPE_ERROR,        "Error" },
203         { IPX_PACKET_TYPE_PEP,          "PEP" }, /* Packet Exchange Packet */
204         { IPX_PACKET_TYPE_SPX,          "SPX" },
205         { 16,                           "Experimental Protocol" },
206         { IPX_PACKET_TYPE_NCP,          "NCP" },
207         { 18,                           "Experimental Protocol" },
208         { 19,                           "Experimental Protocol" },
209         { IPX_PACKET_TYPE_WANBCAST,     "NetBIOS Broadcast" },
210         { 21,                           "Experimental Protocol" },
211         { 22,                           "Experimental Protocol" },
212         { 23,                           "Experimental Protocol" },
213         { 24,                           "Experimental Protocol" },
214         { 25,                           "Experimental Protocol" },
215         { 26,                           "Experimental Protocol" },
216         { 27,                           "Experimental Protocol" },
217         { 28,                           "Experimental Protocol" },
218         { 29,                           "Experimental Protocol" },
219         { 30,                           "Experimental Protocol" },
220         { 31,                           "Experimental Protocol" },
221         { 0,                            NULL }
222 };
223
224 static const value_string ipxmsg_sigchar_vals[] = {
225         { '?', "Poll inactive station" },
226         { 'Y', "Station is still using the connection" },
227         { '!', "Broadcast message waiting" },
228         { 0, NULL }
229 };
230
231 void
232 capture_ipx(packet_counts *ld)
233 {
234         ld->ipx++;
235 }
236
237 static void
238 dissect_ipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
239 {
240         tvbuff_t        *next_tvb;
241
242         proto_tree      *ipx_tree = NULL;
243         proto_item      *ti = NULL;
244
245         const guint8    *src_net_node, *dst_net_node;
246
247         guint8          ipx_hops;
248         char            *str;
249         guint16         first_socket, second_socket;
250         guint32         ipx_snet, ipx_dnet;
251         const guint8    *ipx_snode, *ipx_dnode;
252         static ipxhdr_t ipxh_arr[4];
253         static int ipx_current=0;
254         ipxhdr_t *ipxh;
255         
256         ipx_current++;
257         if(ipx_current==4){
258                 ipx_current=0;
259         }
260         ipxh=&ipxh_arr[ipx_current];
261
262
263         if (check_col(pinfo->cinfo, COL_PROTOCOL))
264                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPX");
265         if (check_col(pinfo->cinfo, COL_INFO))
266                 col_clear(pinfo->cinfo, COL_INFO);
267
268         /* Calculate here for use in pinfo and in tree */
269         ipxh->ipx_dsocket = tvb_get_ntohs(tvb, 16);
270         ipxh->ipx_ssocket = tvb_get_ntohs(tvb, 28);
271         ipxh->ipx_type    = tvb_get_guint8(tvb, 5);
272         ipxh->ipx_length  = tvb_get_ntohs(tvb, 2);
273
274         pinfo->ptype = PT_IPX;
275         pinfo->srcport = ipxh->ipx_ssocket;
276         pinfo->destport = ipxh->ipx_dsocket;
277
278         /* Adjust the tvbuff length to include only the IPX datagram. */
279         set_actual_length(tvb, ipxh->ipx_length);
280
281         src_net_node = tvb_get_ptr(tvb, 18, 10);
282         dst_net_node = tvb_get_ptr(tvb, 6,  10);
283
284         SET_ADDRESS(&pinfo->net_src,    AT_IPX, 10, src_net_node);
285         SET_ADDRESS(&pinfo->src,        AT_IPX, 10, src_net_node);
286         SET_ADDRESS(&ipxh->ipx_src,     AT_IPX, 10, src_net_node);
287         SET_ADDRESS(&pinfo->net_dst,    AT_IPX, 10, dst_net_node);
288         SET_ADDRESS(&pinfo->dst,        AT_IPX, 10, dst_net_node);
289         SET_ADDRESS(&ipxh->ipx_dst,     AT_IPX, 10, dst_net_node);
290
291         if (check_col(pinfo->cinfo, COL_INFO))
292                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s (0x%04x)",
293                                 socket_text(ipxh->ipx_dsocket), ipxh->ipx_dsocket);
294
295         if (tree) {
296
297                 ti = proto_tree_add_item(tree, proto_ipx, tvb, 0, IPX_HEADER_LEN, FALSE);
298                 ipx_tree = proto_item_add_subtree(ti, ett_ipx);
299         }
300
301         str=address_to_str(&pinfo->net_src);
302         proto_tree_add_string_hidden(ipx_tree, hf_ipx_src, tvb, 0, 0, str);
303         proto_tree_add_string_hidden(ipx_tree, hf_ipx_addr, tvb, 0, 0, str);
304         str=address_to_str(&pinfo->net_dst);
305         proto_tree_add_string_hidden(ipx_tree, hf_ipx_dst, tvb, 0, 0, str);
306         proto_tree_add_string_hidden(ipx_tree, hf_ipx_addr, tvb, 0, 0, str);
307
308         proto_tree_add_item(ipx_tree, hf_ipx_checksum, tvb, 0, 2, FALSE);
309         proto_tree_add_uint_format(ipx_tree, hf_ipx_len, tvb, 2, 2, ipxh->ipx_length,
310                 "Length: %d bytes", ipxh->ipx_length);
311         ipx_hops = tvb_get_guint8(tvb, 4);
312         proto_tree_add_uint_format(ipx_tree, hf_ipx_hops, tvb, 4, 1, ipx_hops,
313                 "Transport Control: %d hops", ipx_hops);
314         proto_tree_add_uint(ipx_tree, hf_ipx_packet_type, tvb, 5, 1, ipxh->ipx_type);
315
316         /* Destination */
317         ipx_dnet = tvb_get_ntohl(tvb, 6);
318         proto_tree_add_ipxnet(ipx_tree, hf_ipx_dnet, tvb, 6, 4,
319                 ipx_dnet);
320         proto_tree_add_ipxnet_hidden(ipx_tree, hf_ipx_net, tvb, 6, 4,
321                 ipx_dnet);
322         ipx_dnode = tvb_get_ptr(tvb, 10,  6);
323         proto_tree_add_ether(ipx_tree, hf_ipx_dnode, tvb, 10, 6,
324                 ipx_dnode);
325         proto_tree_add_ether_hidden(ipx_tree, hf_ipx_node, tvb, 10, 6,
326                 ipx_dnode);
327         proto_tree_add_uint(ipx_tree, hf_ipx_dsocket, tvb, 16, 2,
328                 ipxh->ipx_dsocket);
329         proto_tree_add_uint_hidden(ipx_tree, hf_ipx_socket, tvb, 16, 2,
330                 ipxh->ipx_dsocket);
331
332         /* Source */
333         ipx_snet = tvb_get_ntohl(tvb, 18);
334         proto_tree_add_ipxnet(ipx_tree, hf_ipx_snet, tvb, 18, 4,
335                 ipx_snet);
336         proto_tree_add_ipxnet_hidden(ipx_tree, hf_ipx_net, tvb, 18, 4,
337                 ipx_snet);
338         ipx_snode = tvb_get_ptr(tvb, 22, 6);
339         proto_tree_add_ether(ipx_tree, hf_ipx_snode, tvb, 22, 6,
340                 ipx_snode);
341         proto_tree_add_ether_hidden(ipx_tree, hf_ipx_node, tvb, 22, 6,
342                 ipx_snode);
343         proto_tree_add_uint(ipx_tree, hf_ipx_ssocket, tvb, 28, 2,
344                 ipxh->ipx_ssocket);
345         proto_tree_add_uint_hidden(ipx_tree, hf_ipx_socket, tvb, 28, 2,
346                 ipxh->ipx_ssocket);
347
348         /* Make the next tvbuff */
349         next_tvb = tvb_new_subset(tvb, IPX_HEADER_LEN, -1, -1);
350
351         /*
352          * Let the subdissector know what type of IPX packet this is.
353          */
354         pinfo->ipxptype = ipxh->ipx_type;
355
356         /*
357          * Check the socket numbers before we check the packet type;
358          * we've seen non-NCP packets with a type of NCP and a
359          * destination socket of IPX_SOCKET_IPX_MESSAGE, and SAP
360          * packets with a type of NCP and a destination socket of
361          * IPX_SOCKET_SAP.
362          *
363          * We've seen NCP packets with a type of NCP, a source socket of
364          * IPX_SOCKET_NCP, and a destination socket of IPX_SOCKET_IPX_MESSAGE,
365          * and we've seen NCP packets with a type of NCP, a source socket of
366          * IPX_SOCKET_IPX_MESSAGE, and a destination socket of
367          * IPX_SOCKET_NCP, so testing the destination socket first doesn't
368          * always give the right answer.  We've also seen SAP packets with
369          * a source socket of IPX_SOCKET_SAP and a destination socket of
370          * IPX_SOCKET_IPX_MESSAGE.
371          *
372          * Unfortunately, we've also seen packets with a source socket
373          * of IPX_SOCKET_NWLINK_SMB_SERVER and a destination socket
374          * of IPX_SOCKET_NWLINK_SMB_NAMEQUERY that were NMPI packets,
375          * not SMB packets, so testing the lower-valued socket first
376          * also doesn't always give the right answer.
377          *
378          * So we start out assuming we should test the lower-numbered
379          * socket number first, but, if the higher-numbered socket is
380          * IPX_SOCKET_NWLINK_SMB_NAMEQUERY, we assume that it's a
381          * NMPI query, and test only that socket.
382          */
383         if (ipxh->ipx_ssocket > ipxh->ipx_dsocket) {
384                 first_socket = ipxh->ipx_dsocket;
385                 second_socket = ipxh->ipx_ssocket;
386         } else {
387                 first_socket = ipxh->ipx_ssocket;
388                 second_socket = ipxh->ipx_dsocket;
389         }
390
391         tap_queue_packet(ipx_tap, pinfo, ipxh);
392
393         if (second_socket != IPX_SOCKET_NWLINK_SMB_NAMEQUERY) {
394                 if (dissector_try_port(ipx_socket_dissector_table, first_socket,
395                     next_tvb, pinfo, tree))
396                         return;
397         }
398         if (dissector_try_port(ipx_socket_dissector_table, second_socket,
399             next_tvb, pinfo, tree))
400                 return;
401
402         /*
403          * Neither of them are known; try the packet type, which will
404          * at least let us, for example, dissect SPX packets as SPX.
405          */
406         if (dissector_try_port(ipx_type_dissector_table, ipxh->ipx_type, next_tvb,
407             pinfo, tree))
408                 return;
409
410         call_dissector(data_handle,next_tvb, pinfo, tree);
411 }
412 /* ================================================================= */
413 /* SPX Hash Functions                                                */
414 /* ================================================================= */
415
416 typedef struct {
417         conversation_t  *conversation;
418         guint32         spx_src;
419         guint16         spx_seq;
420 } spx_hash_key;
421
422 typedef struct {
423         guint16             spx_ack;
424         guint16             spx_all;
425         guint32             num;
426 } spx_hash_value;
427
428 /*
429  * Structure attached to retransmitted SPX frames; it contains the
430  * frame number of the original transmission.
431  */
432 typedef struct {
433         guint32             num;
434 } spx_rexmit_info;
435
436 static GHashTable *spx_hash = NULL;
437 static GMemChunk *spx_hash_keys = NULL;
438 static GMemChunk *spx_hash_values = NULL;
439 static GMemChunk *spx_rexmit_infos = NULL;
440
441 /* Hash Functions */
442 gint
443 spx_equal(gconstpointer v, gconstpointer v2)
444 {
445         const spx_hash_key      *val1 = (const spx_hash_key*)v;
446         const spx_hash_key      *val2 = (const spx_hash_key*)v2;
447
448         if (val1->conversation == val2->conversation &&
449             val1->spx_src == val2->spx_src &&
450             val1->spx_seq == val2->spx_seq) {
451                 return 1;
452         }
453         return 0;
454 }
455
456 guint
457 spx_hash_func(gconstpointer v)
458 {
459         const spx_hash_key      *spx_key = (const spx_hash_key*)v;
460         return GPOINTER_TO_UINT(spx_key->conversation) + spx_key->spx_src;
461 }
462
463 /* Initializes the hash table and the mem_chunk area each time a new
464  * file is loaded or re-loaded in ethereal */
465 static void
466 spx_init_protocol(void)
467 {
468
469         if (spx_hash)
470                 g_hash_table_destroy(spx_hash);
471         if (spx_hash_keys)
472                 g_mem_chunk_destroy(spx_hash_keys);
473         if (spx_hash_values)
474                 g_mem_chunk_destroy(spx_hash_values);
475         if (spx_rexmit_infos)
476                 g_mem_chunk_destroy(spx_rexmit_infos);
477
478         spx_hash = g_hash_table_new(spx_hash_func, spx_equal);
479         spx_hash_keys = g_mem_chunk_new("spx_hash_keys",
480                         sizeof(spx_hash_key),
481                         SPX_PACKET_INIT_COUNT * sizeof(spx_hash_key),
482                         G_ALLOC_ONLY);
483         spx_hash_values = g_mem_chunk_new("spx_hash_values",
484                         sizeof(spx_hash_value),
485                         SPX_PACKET_INIT_COUNT * sizeof(spx_hash_value),
486                         G_ALLOC_ONLY);
487         spx_rexmit_infos = g_mem_chunk_new("spx_rexmit_infos",
488                         sizeof(spx_rexmit_infos),
489                         SPX_PACKET_INIT_COUNT * sizeof(spx_rexmit_infos),
490                         G_ALLOC_ONLY);
491 }
492
493 /* After the sequential run, we don't need the spx hash table, or
494  * the keys and values, anymore; the lookups have already been done
495  * and the relevant info saved as SPX private data with the frame
496  * if the frame was a retransmission. */
497 static void
498 spx_postseq_cleanup(void)
499 {
500         if (spx_hash) {
501                 /* Destroy the hash, but don't clean up request_condition data. */
502                 g_hash_table_destroy(spx_hash);
503                 spx_hash = NULL;
504         }
505         if (spx_hash_keys) {
506                 g_mem_chunk_destroy(spx_hash_keys);
507                 spx_hash_keys = NULL;
508         }
509         if (spx_hash_values) {
510                 g_mem_chunk_destroy(spx_hash_values);
511                 spx_hash_values = NULL;
512         }
513         /* Don't free the spx_rexmit_infos, as they're
514          * needed during random-access processing of the proto_tree.*/
515 }
516
517 spx_hash_value*
518 spx_hash_insert(conversation_t *conversation, guint32 spx_src, guint16 spx_seq)
519 {
520         spx_hash_key            *key;
521         spx_hash_value          *value;
522
523         /* Now remember the packet, so we can find it if we later. */
524         key = g_mem_chunk_alloc(spx_hash_keys);
525         key->conversation = conversation;
526         key->spx_src = spx_src;
527         key->spx_seq = spx_seq;
528
529         value = g_mem_chunk_alloc(spx_hash_values);
530         value->spx_ack = 0;
531         value->spx_all = 0;
532         value->num = 0;
533
534         g_hash_table_insert(spx_hash, key, value);
535
536         return value;
537 }
538
539 /* Returns the spx_hash_value*, or NULL if not found. */
540 spx_hash_value*
541 spx_hash_lookup(conversation_t *conversation, guint32 spx_src, guint32 spx_seq)
542 {
543         spx_hash_key            key;
544
545         key.conversation = conversation;
546         key.spx_src = spx_src;
547         key.spx_seq = spx_seq;
548
549         return g_hash_table_lookup(spx_hash, &key);
550 }
551
552 /* ================================================================= */
553 /* SPX                                                               */
554 /* ================================================================= */
555
556 #define SPX_SYS_PACKET  0x80
557 #define SPX_SEND_ACK    0x40
558 #define SPX_ATTN        0x20
559 #define SPX_EOM         0x10
560
561 static const char*
562 spx_conn_ctrl(guint8 ctrl)
563 {
564         const char *p;
565
566         static const value_string conn_vals[] = {
567                 { 0x00,                        "Data, No Ack Required" },
568                 { SPX_EOM,                     "End-of-Message" },
569                 { SPX_ATTN,                    "Attention" },
570                 { SPX_SEND_ACK,                "Acknowledgment Required"},
571                 { SPX_SEND_ACK|SPX_EOM,        "Send Ack: End Message"},
572                 { SPX_SYS_PACKET,              "System Packet"},
573                 { SPX_SYS_PACKET|SPX_SEND_ACK, "System Packet: Send Ack"},
574                 { 0x00,                        NULL }
575         };
576
577         p = match_strval((ctrl & 0xf0), conn_vals );
578
579         if (p) {
580                 return p;
581         }
582         else {
583                 return "Unknown";
584         }
585 }
586
587 static const char*
588 spx_datastream(guint8 type)
589 {
590         switch (type) {
591                 case 0xfe:
592                         return "End-of-Connection";
593                 case 0xff:
594                         return "End-of-Connection Acknowledgment";
595                 default:
596                         return NULL;
597         }
598 }
599
600 #define SPX_HEADER_LEN  12
601
602 static void
603 dissect_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
604 {
605         proto_tree      *spx_tree = NULL;
606         proto_item      *ti;
607         tvbuff_t        *next_tvb;
608         guint8          conn_ctrl;
609         proto_tree      *cc_tree;
610         guint8          datastream_type;
611         const char      *datastream_type_string;
612         guint16         spx_seq;
613         const char      *spx_msg_string;
614         guint16         low_socket, high_socket;
615         guint32         src;
616         conversation_t  *conversation;
617         spx_hash_value  *pkt_value;
618         spx_rexmit_info *spx_rexmit_info;
619         spx_info        spx_info;
620
621         if (check_col(pinfo->cinfo, COL_PROTOCOL))
622                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SPX");
623         if (check_col(pinfo->cinfo, COL_INFO))
624                 col_set_str(pinfo->cinfo, COL_INFO, "SPX");
625
626         if (tree) {
627                 ti = proto_tree_add_item(tree, proto_spx, tvb, 0, SPX_HEADER_LEN, FALSE);
628                 spx_tree = proto_item_add_subtree(ti, ett_spx);
629         }
630
631         conn_ctrl = tvb_get_guint8(tvb, 0);
632         spx_msg_string = spx_conn_ctrl(conn_ctrl);
633         if (check_col(pinfo->cinfo, COL_INFO))
634                 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", spx_msg_string);
635         if (tree) {
636                 ti = proto_tree_add_uint_format(spx_tree, hf_spx_connection_control, tvb,
637                                                 0, 1, conn_ctrl,
638                                                 "Connection Control: %s (0x%02X)",
639                                                 spx_msg_string, conn_ctrl);
640                 cc_tree = proto_item_add_subtree(ti, ett_spx_connctrl);
641                 proto_tree_add_boolean(cc_tree, hf_spx_connection_control_sys, tvb,
642                                        0, 1, conn_ctrl);
643                 proto_tree_add_boolean(cc_tree, hf_spx_connection_control_send_ack, tvb,
644                                        0, 1, conn_ctrl);
645                 proto_tree_add_boolean(cc_tree, hf_spx_connection_control_attn, tvb,
646                                        0, 1, conn_ctrl);
647                 proto_tree_add_boolean(cc_tree, hf_spx_connection_control_eom, tvb,
648                                        0, 1, conn_ctrl);
649         }
650
651         datastream_type = tvb_get_guint8(tvb, 1);
652         datastream_type_string = spx_datastream(datastream_type);
653         if (datastream_type_string != NULL) {
654                 if (check_col(pinfo->cinfo, COL_INFO))
655                         col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)",
656                             datastream_type_string);
657         }
658         if (tree) {
659                 if (datastream_type_string != NULL) {
660                         proto_tree_add_uint_format(spx_tree, hf_spx_datastream_type, tvb,
661                                                    1, 1, datastream_type,
662                                                    "Datastream Type: %s (0x%02X)",
663                                                    datastream_type_string,
664                                                    datastream_type);
665                 } else {
666                         proto_tree_add_uint_format(spx_tree, hf_spx_datastream_type, tvb,
667                                                    1, 1, datastream_type,
668                                                    "Datastream Type: 0x%02X",
669                                                    datastream_type);
670                 }
671                 proto_tree_add_item(spx_tree, hf_spx_src_id, tvb,  2, 2, FALSE);
672                 proto_tree_add_item(spx_tree, hf_spx_dst_id, tvb,  4, 2, FALSE);
673         }
674         spx_seq = tvb_get_ntohs(tvb, 6);
675         if (tree) {
676                 proto_tree_add_uint(spx_tree, hf_spx_seq_nr, tvb,  6, 2, spx_seq);
677                 proto_tree_add_item(spx_tree, hf_spx_ack_nr, tvb,  8, 2, FALSE);
678                 proto_tree_add_item(spx_tree, hf_spx_all_nr, tvb, 10, 2, FALSE);
679         }
680
681         /*
682          * SPX is Connection Oriented and Delivery Guaranteed.
683          * On the first pass, we need to flag retransmissions by the SPX
684          * protocol, so that subdissectors know whether a packet was
685          * retransmitted.
686          *
687          * We start out by creating a conversation for this direction of the
688          * IPX session; we use "pinfo->srcport" twice, so that we have
689          * separate conversations for the two directions.
690          *
691          * XXX - that might not work correctly if there's more than one
692          * SPX session using that source port; can that happen?  If so,
693          * we should probably use the direction, as well as the conversation,
694          * as part of the hash key; if we do that, we can probably just
695          * use PT_IPX as the port type, and possibly get rid of PT_NCP.
696          *
697          * According to
698          *
699          *      http://developer.novell.com/research/appnotes/1995/december/03/apv.htm
700          *
701          * the sequence number is not incremented for system packets, so
702          * presumably that means there is no notion of a system packet
703          * being retransmitted; that document also says that system
704          * packets are used as "I'm still here" keepalives and as
705          * acknowledgements (presumably meaning ACK-only packets), which
706          * suggests that they might not be ACKed and thus might not
707          * be retransmitted.
708          */
709         if (conn_ctrl & SPX_SYS_PACKET) {
710                 /*
711                  * It's a system packet, so it isn't a retransmission.
712                  */
713                 spx_rexmit_info = NULL;
714         } else {
715                 /*
716                  * Not a system packet - check for retransmissions.
717                  */
718                 if (!pinfo->fd->flags.visited) {
719                         conversation = find_conversation(&pinfo->src,
720                             &pinfo->dst, PT_NCP, pinfo->srcport,
721                             pinfo->srcport, 0);
722                         if (conversation == NULL) {
723                                 /*
724                                  * It's not part of any conversation - create
725                                  * a new one.
726                                  */
727                                 conversation = conversation_new(&pinfo->src,
728                                     &pinfo->dst, PT_NCP, pinfo->srcport,
729                                     pinfo->srcport, 0);
730                         }
731
732                         /*
733                          * Now we'll hash the SPX header and use the result
734                          * of that, plus the conversation, as a hash key to
735                          * identify this packet.
736                          *
737                          * If we don't find it in the hash table, it's not a
738                          * retransmission, otherwise it is.  If we don't find
739                          * it, we enter it into the hash table, with the
740                          * frame number.
741                          * If we do, we attach to this frame a structure giving
742                          * the frame number of the original transmission, so
743                          * that we, and subdissectors, know it's a
744                          * retransmission.
745                          */
746                         src = tvb_get_ntohs(tvb, 0)+tvb_get_ntohs(tvb, 2)+tvb_get_ntohs(tvb, 4)+tvb_get_ntohs(tvb, 6)+tvb_get_ntohs(tvb, 8);
747                         pkt_value = spx_hash_lookup(conversation, src, spx_seq);
748                         if (pkt_value == NULL) {
749                                 /*
750                                  * Not found in the hash table.
751                                  * Enter it into the hash table.
752                                  */
753                                 pkt_value = spx_hash_insert(conversation, src,
754                                     spx_seq);
755                                 pkt_value->spx_ack = tvb_get_ntohs(tvb, 8);
756                                 pkt_value->spx_all = tvb_get_ntohs(tvb, 10);
757                                 pkt_value->num = pinfo->fd->num;
758
759                                 /*
760                                  * This is not a retransmission, so we shouldn't
761                                  * have any retransmission indicator.
762                                  */
763                                 spx_rexmit_info = NULL;
764                         } else {
765                                 /*
766                                  * Found in the hash table.  Mark this frame as
767                                  * a retransmission.
768                                  */
769                                 spx_rexmit_info = g_mem_chunk_alloc(spx_rexmit_infos);
770                                 spx_rexmit_info->num = pkt_value->num;
771                                 p_add_proto_data(pinfo->fd, proto_spx,
772                                     spx_rexmit_info);
773                         }
774                 } else {
775                         /*
776                          * Do we have per-packet SPX data for this frame?
777                          * If so, it's a retransmission, and the per-packet
778                          * data indicates which frame had the original
779                          * transmission.
780                          */
781                         spx_rexmit_info = p_get_proto_data(pinfo->fd,
782                             proto_spx);
783                 }
784         }
785
786         /*
787          * It's a retransmission if we have a retransmission indicator.
788          * Flag this as a retransmission, but don't pass it to the
789          * subdissector.
790          */
791         if (spx_rexmit_info != NULL) {
792                 if (check_col(pinfo->cinfo, COL_INFO)) {
793                         col_add_fstr(pinfo->cinfo, COL_INFO,
794                             "[Retransmission] Original Packet %u",
795                             spx_rexmit_info->num);
796                 }
797                 if (tree) {
798                         proto_tree_add_uint_format(spx_tree, hf_spx_rexmt_frame,
799                             tvb, 0, 0, spx_rexmit_info->num,
800                             "This is a retransmission of frame %u",
801                             spx_rexmit_info->num);
802                         if (tvb_length_remaining(tvb, SPX_HEADER_LEN) > 0) {
803                                 proto_tree_add_text(spx_tree, tvb,
804                                     SPX_HEADER_LEN, -1,
805                                     "Retransmitted data");
806                         }
807                 }
808                 return;
809         }
810
811         if (tvb_reported_length_remaining(tvb, SPX_HEADER_LEN) > 0) {
812                 /*
813                  * Call subdissectors based on the IPX socket numbers; a
814                  * subdissector might have registered with our IPX socket
815                  * dissector table rather than the IPX dissector's socket
816                  * dissector table.
817                  *
818                  * Assume the lower-numbered socket number is more likely
819                  * to be the right one, along the lines of what we do for
820                  * TCP and UDP.  We've seen NCP packets with a type of NCP,
821                  * a source socket of IPX_SOCKET_NCP, and a destination
822                  * socket of IPX_SOCKET_IPX_MESSAGE, and we've seen NCP
823                  * packets with a type of NCP, a source socket of
824                  * IPX_SOCKET_IPX_MESSAGE, and a destination socket of
825                  * IPX_SOCKET_NCP.
826                  */
827                 if (pinfo->srcport > pinfo->destport) {
828                         low_socket = pinfo->destport;
829                         high_socket = pinfo->srcport;
830                 } else {
831                         low_socket = pinfo->srcport;
832                         high_socket = pinfo->destport;
833                 }
834
835                 /*
836                  * Pass information to subdissectors.
837                  */
838                 spx_info.eom = conn_ctrl & SPX_EOM;
839                 spx_info.datastream_type = datastream_type;
840                 pinfo->private_data = &spx_info;
841
842                 next_tvb = tvb_new_subset(tvb, SPX_HEADER_LEN, -1, -1);
843                 if (dissector_try_port(spx_socket_dissector_table, low_socket,
844                     next_tvb, pinfo, tree))
845                         return;
846                 if (dissector_try_port(spx_socket_dissector_table, high_socket,
847                     next_tvb, pinfo, tree))
848                         return;
849                 call_dissector(data_handle, next_tvb, pinfo, tree);
850         }
851 }
852
853 /* ================================================================= */
854 /* IPX Message                                                       */
855 /* ================================================================= */
856 static void
857 dissect_ipxmsg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
858 {
859         proto_tree      *msg_tree;
860         proto_item      *ti;
861         guint8          conn_number, sig_char;
862
863         if (check_col(pinfo->cinfo, COL_PROTOCOL))
864                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPX MSG");
865         if (check_col(pinfo->cinfo, COL_INFO))
866                 col_clear(pinfo->cinfo, COL_INFO);
867
868         conn_number = tvb_get_guint8(tvb, 0);
869         sig_char = tvb_get_guint8(tvb, 1);
870
871         if (check_col(pinfo->cinfo, COL_INFO)) {
872                 col_add_fstr(pinfo->cinfo, COL_INFO,
873                         "%s, Connection %d",
874                         val_to_str(sig_char, ipxmsg_sigchar_vals, "Unknown Signature Char"), conn_number);
875         }
876
877         if (tree) {
878                 ti = proto_tree_add_item(tree, proto_ipxmsg, tvb, 0, -1, FALSE);
879                 msg_tree = proto_item_add_subtree(ti, ett_ipxmsg);
880
881                 proto_tree_add_uint(msg_tree, hf_msg_conn, tvb, 0, 1, conn_number);
882                 proto_tree_add_uint(msg_tree, hf_msg_sigchar, tvb, 1, 1, sig_char);
883         }
884 }
885
886
887 /* ================================================================= */
888 /* IPX RIP                                                           */
889 /* ================================================================= */
890 static void
891 dissect_ipxrip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
892 {
893         proto_tree      *rip_tree;
894         proto_item      *ti;
895         guint16         operation;
896         struct ipx_rt_def route;
897         int             cursor;
898         int             available_length;
899
900         static char     *rip_type[3] = { "Request", "Response", "Unknown" };
901
902         if (check_col(pinfo->cinfo, COL_PROTOCOL))
903                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPX RIP");
904         if (check_col(pinfo->cinfo, COL_INFO))
905                 col_clear(pinfo->cinfo, COL_INFO);
906
907         operation = tvb_get_ntohs(tvb, 0) - 1;
908
909         if (check_col(pinfo->cinfo, COL_INFO)) {
910                 /* rip_types 0 and 1 are valid, anything else becomes 2 or "Unknown" */
911                 col_set_str(pinfo->cinfo, COL_INFO, rip_type[MIN(operation, 2)]);
912         }
913
914         if (tree) {
915                 ti = proto_tree_add_item(tree, proto_ipxrip, tvb, 0, -1, FALSE);
916                 rip_tree = proto_item_add_subtree(ti, ett_ipxrip);
917
918                 if (operation < 2) {
919                         proto_tree_add_text(rip_tree, tvb, 0, 2,
920                         "RIP packet type: %s", rip_type[operation]);
921
922                         if (operation == 0) {
923                           proto_tree_add_boolean_hidden(rip_tree,
924                                                      hf_ipxrip_request,
925                                                      tvb, 0, 2, 1);
926                         } else {
927                           proto_tree_add_boolean_hidden(rip_tree,
928                                                      hf_ipxrip_response,
929                                                      tvb, 0, 2, 1);
930                         }
931
932                 }
933                 else {
934                         proto_tree_add_text(rip_tree, tvb, 0, 2, "Unknown RIP packet type");
935                 }
936
937                 available_length = tvb_reported_length(tvb);
938                 for (cursor =  2; cursor < available_length; cursor += 8) {
939                         tvb_memcpy(tvb, (guint8 *)&route.network, cursor, 4);
940                         route.hops = tvb_get_ntohs(tvb, cursor+4);
941                         route.ticks = tvb_get_ntohs(tvb, cursor+6);
942
943                         if (operation == IPX_RIP_REQUEST - 1) {
944                                 proto_tree_add_text(rip_tree, tvb, cursor,      8,
945                                         "Route Vector: %s, %d hop%s, %d tick%s",
946                                         ipxnet_to_string((guint8*)&route.network),
947                                         route.hops,  route.hops  == 1 ? "" : "s",
948                                         route.ticks, route.ticks == 1 ? "" : "s");
949                         }
950                         else {
951                                 proto_tree_add_text(rip_tree, tvb, cursor,      8,
952                                         "Route Vector: %s, %d hop%s, %d tick%s (%d ms)",
953                                         ipxnet_to_string((guint8*)&route.network),
954                                         route.hops,  route.hops  == 1 ? "" : "s",
955                                         route.ticks, route.ticks == 1 ? "" : "s",
956                                         route.ticks * 1000 / 18);
957                         }
958                 }
959         }
960 }
961
962 /* ================================================================= */
963 /* IPX Serialization                                                 */
964 /* ================================================================= */
965 static void
966 dissect_serialization(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
967 {
968         proto_tree      *ser_tree = NULL;
969         proto_item      *ti;
970
971         if (check_col(pinfo->cinfo, COL_PROTOCOL))
972                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NW_SERIAL");
973         if (check_col(pinfo->cinfo, COL_INFO))
974                 col_clear(pinfo->cinfo, COL_INFO);
975
976         if (tree) {
977                 ti = proto_tree_add_item(tree, proto_serialization, tvb, 0, -1,
978                     FALSE);
979                 ser_tree = proto_item_add_subtree(ti, ett_serialization);
980         }
981
982         if (check_col(pinfo->cinfo, COL_INFO)) {
983                 col_add_fstr(pinfo->cinfo, COL_INFO, "Serial number %s",
984                     tvb_bytes_to_str(tvb, 0, 6));
985         }
986
987         if (tree) {
988                 proto_tree_add_text(ser_tree, tvb, 0, 6,
989                       "Serial number: %s", tvb_bytes_to_str(tvb, 0, 6));
990         }
991 }
992
993 /*
994  * Some of these are from ncpfs, others are from the book,
995  * others are from the page at
996  *
997  *      http://www.iana.org/assignments/novell-sap-numbers
998  *
999  * and some from the page at
1000  *
1001  *      http://www.rware.demon.co.uk/ipxsap.htm
1002  *
1003  * (see also the page at
1004  *
1005  *      http://developer.novell.com/research/appnotes/1998/february/03/06.htm
1006  *
1007  * which has a huge list - but many of the entries list only the
1008  * organization owning the SAP type, not what the type is for).
1009  */
1010 const value_string server_vals[] = {
1011         { 0x0000,       "Unknown" },
1012         { 0x0001,       "User" },
1013         { 0x0002,       "User Group" },
1014         { 0x0003,       "Print Queue or Print Group" },
1015         { 0x0004,       "File Server (SLIST source)" },
1016         { 0x0005,       "Job Server" },
1017         { 0x0006,       "Gateway" },
1018         { 0x0007,       "Print Server or Silent Print Server" },
1019         { 0x0008,       "Archive Queue" },
1020         { 0x0009,       "Archive Server" },
1021         { 0x000a,       "Job Queue" },
1022         { 0x000b,       "Administration" },
1023         { 0x000F,       "Novell TI-RPC" },
1024         { 0x0017,       "Diagnostics" },
1025         { 0x0020,       "NetBIOS" },
1026         { 0x0021,       "NAS SNA Gateway" },
1027         { 0x0023,       "NACS Async Gateway or Asynchronous Gateway" },
1028         { 0x0024,       "Remote Bridge or Routing Service" },
1029         { 0x0026,       "Bridge Server or Asynchronous Bridge Server" },
1030         { 0x0027,       "TCP/IP Gateway Server" },
1031         { 0x0028,       "Point to Point (Eicon) X.25 Bridge Server" },
1032         { 0x0029,       "Eicon 3270 Gateway" },
1033         { 0x002a,       "CHI Corp" },
1034         { 0x002c,       "PC Chalkboard" },
1035         { 0x002d,       "Time Synchronization Server or Asynchronous Timer" },
1036         { 0x002e,       "ARCserve 5.0 / Palindrome Backup Director 4.x (PDB4)" },
1037         { 0x0045,       "DI3270 Gateway" },
1038         { 0x0047,       "Advertising Print Server" },
1039         { 0x004a,       "NetBlazer Modems" },
1040         { 0x004b,       "Btrieve VAP/NLM 5.0" },
1041         { 0x004c,       "NetWare SQL VAP/NLM Server" },
1042         { 0x004d,       "Xtree Network Version/NetWare XTree" },
1043         { 0x0050,       "Btrieve VAP 4.11" },
1044         { 0x0052,       "QuickLink (Cubix)" },
1045         { 0x0053,       "Print Queue User" },
1046         { 0x0058,       "Multipoint X.25 Eicon Router" },
1047         { 0x0060,       "STLB/NLM" },
1048         { 0x0064,       "ARCserve" },
1049         { 0x0066,       "ARCserve 3.0" },
1050         { 0x0072,       "WAN Copy Utility" },
1051         { 0x007a,       "TES-NetWare for VMS" },
1052         { 0x0092,       "WATCOM Debugger or Emerald Tape Backup Server" },
1053         { 0x0095,       "DDA OBGYN" },
1054         { 0x0098,       "NetWare Access Server (Asynchronous gateway)" },
1055         { 0x009a,       "NetWare for VMS II or Named Pipe Server" },
1056         { 0x009b,       "NetWare Access Server" },
1057         { 0x009e,       "Portable NetWare Server or SunLink NVT" },
1058         { 0x00a1,       "Powerchute APC UPS NLM" },
1059         { 0x00aa,       "LAWserve" },
1060         { 0x00ac,       "Compaq IDA Status Monitor" },
1061         { 0x0100,       "PIPE STAIL" },
1062         { 0x0102,       "LAN Protect Bindery" },
1063         { 0x0103,       "Oracle DataBase Server" },
1064         { 0x0107,       "NetWare 386 or RSPX Remote Console" },
1065         { 0x010f,       "Novell SNA Gateway" },
1066         { 0x0111,       "Test Server" },
1067         { 0x0112,       "Print Server (HP)" },
1068         { 0x0114,       "CSA MUX (f/Communications Executive)" },
1069         { 0x0115,       "CSA LCA (f/Communications Executive)" },
1070         { 0x0116,       "CSA CM (f/Communications Executive)" },
1071         { 0x0117,       "CSA SMA (f/Communications Executive)" },
1072         { 0x0118,       "CSA DBA (f/Communications Executive)" },
1073         { 0x0119,       "CSA NMA (f/Communications Executive)" },
1074         { 0x011a,       "CSA SSA (f/Communications Executive)" },
1075         { 0x011b,       "CSA STATUS (f/Communications Executive)" },
1076         { 0x011e,       "CSA APPC (f/Communications Executive)" },
1077         { 0x0126,       "SNA TEST SSA Profile" },
1078         { 0x012a,       "CSA TRACE (f/Communications Executive)" },
1079         { 0x012b,       "NetWare for SAA" },
1080         { 0x012e,       "IKARUS virus scan utility" },
1081         { 0x0130,       "Communications Executive" },
1082         { 0x0133,       "NNS Domain Server or NetWare Naming Services Domain" },
1083         { 0x0135,       "NetWare Naming Services Profile" },
1084         { 0x0137,       "NetWare 386 Print Queue or NNS Print Queue" },
1085         { 0x0141,       "LAN Spool Server (Vap, Intel)" },
1086         { 0x0152,       "IRMALAN Gateway" },
1087         { 0x0154,       "Named Pipe Server" },
1088         { 0x0166,       "NetWare Management" },
1089         { 0x0168,       "Intel PICKIT Comm Server or Intel CAS Talk Server" },
1090         { 0x0173,       "Compaq" },
1091         { 0x0174,       "Compaq SNMP Agent" },
1092         { 0x0175,       "Compaq" },
1093         { 0x0180,       "XTree Server or XTree Tools" },
1094         { 0x018A,       "NASI services broadcast server (Novell)" },
1095         { 0x01b0,       "GARP Gateway (net research)" },
1096         { 0x01b1,       "Binfview (Lan Support Group)" },
1097         { 0x01bf,       "Intel LanDesk Manager" },
1098         { 0x01ca,       "AXTEC" },
1099         { 0x01cb,       "Shiva NetModem/E" },
1100         { 0x01cc,       "Shiva LanRover/E" },
1101         { 0x01cd,       "Shiva LanRover/T" },
1102         { 0x01ce,       "Shiva Universal" },
1103         { 0x01d8,       "Castelle FAXPress Server" },
1104         { 0x01da,       "Castelle LANPress Print Server" },
1105         { 0x01dc,       "Castelle FAX/Xerox 7033 Fax Server/Excel Lan Fax" },
1106         { 0x01f0,       "LEGATO" },
1107         { 0x01f5,       "LEGATO" },
1108         { 0x0233,       "NMS Agent or NetWare Management Agent" },
1109         { 0x0237,       "NMS IPX Discovery or LANtern Read/Write Channel" },
1110         { 0x0238,       "NMS IP Discovery or LANtern Trap/Alarm Channel" },
1111         { 0x023a,       "LANtern" },
1112         { 0x023c,       "MAVERICK" },
1113         { 0x023f,       "SMS Testing and Development" },
1114         { 0x024e,       "NetWare Connect" },
1115         { 0x024f,       "NASI server broadcast (Cisco)" },
1116         { 0x026a,       "Network Management (NMS) Service Console" },
1117         { 0x026b,       "Time Synchronization Server (NetWare 4.x)" },
1118         { 0x0278,       "Directory Server (NetWare 4.x)" },
1119         { 0x027b,       "NetWare Management Agent" },
1120         { 0x0280,       "Novell File and Printer Sharing Service for PC" },
1121         { 0x0304,       "Novell SAA Gateway" },
1122         { 0x0308,       "COM or VERMED 1" },
1123         { 0x030a,       "Galacticomm's Worldgroup Server" },
1124         { 0x030c,       "Intel Netport 2 or HP JetDirect or HP Quicksilver" },
1125         { 0x0320,       "Attachmate Gateway" },
1126         { 0x0327,       "Microsoft Diagnostics" },
1127         { 0x0328,       "WATCOM SQL server" },
1128         { 0x0335,       "MultiTech Systems Multisynch Comm Server" },
1129         { 0x0343,       "Xylogics Remote Access Server or LAN Modem" },
1130         { 0x0355,       "Arcada Backup Exec" },
1131         { 0x0358,       "MSLCD1" },
1132         { 0x0361,       "NETINELO" },
1133         { 0x037e,       "Powerchute UPS Monitoring" },
1134         { 0x037f,       "ViruSafe Notify" },
1135         { 0x0386,       "HP Bridge" },
1136         { 0x0387,       "HP Hub" },
1137         { 0x0394,       "NetWare SAA Gateway" },
1138         { 0x039b,       "Lotus Notes" },
1139         { 0x03b7,       "Certus Anti Virus NLM" },
1140         { 0x03c4,       "ARCserve 4.0 (Cheyenne)" },
1141         { 0x03c7,       "LANspool 3.5 (Intel)" },
1142         { 0x03d7,       "Lexmark printer server (type 4033-011)" },
1143         { 0x03d8,       "Lexmark XLE printer server (type 4033-301)" },
1144         { 0x03dd,       "Banyan ENS for NetWare Client NLM" },
1145         { 0x03de,       "Gupta Sequel Base Server or NetWare SQL" },
1146         { 0x03e1,       "Univel Unixware" },
1147         { 0x03e4,       "Univel Unixware" },
1148         { 0x03fc,       "Intel Netport" },
1149         { 0x03fd,       "Intel Print Server Queue" },
1150         { 0x040A,       "ipnServer" },
1151         { 0x040D,       "LVERRMAN" },
1152         { 0x040E,       "LVLIC" },
1153         { 0x0414,       "NET Silicon (DPI)/Kyocera" },
1154         { 0x0429,       "Site Lock Virus (Brightworks)" },
1155         { 0x0432,       "UFHELP R" },
1156         { 0x0433,       "Synoptics 281x Advanced SNMP Agent" },
1157         { 0x0444,       "Microsoft NT SNA Server" },
1158         { 0x0448,       "Oracle" },
1159         { 0x044c,       "ARCserve 5.01" },
1160         { 0x0457,       "Canon GP55 Running on a Canon GP55 network printer" },
1161         { 0x045a,       "QMS Printers" },
1162         { 0x045b,       "Dell SCSI Array (DSA) Monitor" },
1163         { 0x0491,       "NetBlazer Modems" },
1164         { 0x04ac,       "On-Time Scheduler NLM" },
1165         { 0x04b0,       "CD-Net (Meridian)" },
1166         { 0x0513,       "Emulex NQA" },
1167         { 0x0520,       "Site Lock Checks" },
1168         { 0x0529,       "Site Lock Checks (Brightworks)" },
1169         { 0x052d,       "Citrix OS/2 App Server" },
1170         { 0x0535,       "Tektronix" },
1171         { 0x0536,       "Milan" },
1172         { 0x055d,       "Attachmate SNA gateway" },
1173         { 0x056b,       "IBM 8235 modem server" },
1174         { 0x056c,       "Shiva LanRover/E PLUS" },
1175         { 0x056d,       "Shiva LanRover/T PLUS" },
1176         { 0x0580,       "McAfee's NetShield anti-virus" },
1177         { 0x05B8,       "NLM to workstation communication (Revelation Software)" },
1178         { 0x05BA,       "Compatible Systems Routers" },
1179         { 0x05BE,       "Cheyenne Hierarchical Storage Manager" },
1180         { 0x0606,       "JCWatermark Imaging" },
1181         { 0x060c,       "AXIS Network Printer" },
1182         { 0x0610,       "Adaptec SCSI Management" },
1183         { 0x0621,       "IBM AntiVirus NLM" },
1184         { 0x0640,       "Microsoft Gateway Services for NetWare" },
1185 /*      { 0x0640,       "NT Server-RPC/GW for NW/Win95 User Level Sec" }, */
1186         { 0x064e,       "Microsoft Internet Information Server" },
1187         { 0x067b,       "Microsoft Win95/98 File and Print Sharing for NetWare" },
1188         { 0x067c,       "Microsoft Win95/98 File and Print Sharing for NetWare" },
1189         { 0x076C,       "Xerox" },
1190         { 0x079b,       "Shiva LanRover/E 115" },
1191         { 0x079c,       "Shiva LanRover/T 115" },
1192         { 0x07B4,       "Cubix WorldDesk" },
1193         { 0x07c2,       "Quarterdeck IWare Connect V2.x NLM" },
1194         { 0x07c1,       "Quarterdeck IWare Connect V3.x NLM" },
1195         { 0x0810,       "ELAN License Server Demo" },
1196         { 0x0824,       "Shiva LanRover Access Switch/E" },
1197         { 0x086a,       "ISSC collector NLMs" },
1198         { 0x087f,       "ISSC DAS agent for AIX" },
1199         { 0x0880,       "Intel Netport PRO" },
1200         { 0x0881,       "Intel Netport PRO" },
1201         { 0x0b29,       "Site Lock" },
1202         { 0x0c29,       "Site Lock Applications" },
1203         { 0x0c2c,       "Licensing Server" },
1204         { 0x2101,       "Performance Technology Instant Internet" },
1205         { 0x2380,       "LAI Site Lock" },
1206         { 0x238c,       "Meeting Maker" },
1207         { 0x4808,       "Site Lock Server or Site Lock Metering VAP/NLM" },
1208         { 0x5555,       "Site Lock User" },
1209         { 0x6312,       "Tapeware" },
1210         { 0x6f00,       "Rabbit Gateway (3270)" },
1211         { 0x7703,       "MODEM" },
1212         { 0x8002,       "NetPort Printers (Intel) or LANport" },
1213         { 0x8003,       "SEH InterCon Printserver" },
1214         { 0x8008,       "WordPerfect Network Version" },
1215         { 0x85BE,       "Cisco Enhanced Interior Routing Protocol (EIGRP)" },
1216         { 0x8888,       "WordPerfect Network Version or Quick Network Management" },
1217         { 0x9000,       "McAfee's NetShield anti-virus" },
1218         { 0x9604,       "CSA-NT_MON" },
1219         { 0xb6a8,       "Ocean Isle Reachout Remote Control" },
1220         { 0xf11f,       "Site Lock Metering VAP/NLM" },
1221         { 0xf1ff,       "Site Lock" },
1222         { 0xf503,       "Microsoft SQL Server" },
1223         { 0xf905,       "IBM Time and Place/2 application" },
1224         { 0xfbfb,       "TopCall III fax server" },
1225         { 0xffff,       "Any Service or Wildcard" },
1226         { 0x0000,       NULL }
1227 };
1228
1229 static void
1230 dissect_ipxsap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1231 {
1232         proto_tree      *sap_tree, *s_tree;
1233         proto_item      *ti;
1234         int             cursor;
1235         struct sap_query query;
1236         guint16         server_type;
1237         char            server_name[48];
1238         guint16         server_port;
1239         guint16         intermediate_network;
1240
1241         static char     *sap_type[4] = { "General Query", "General Response",
1242                 "Nearest Query", "Nearest Response" };
1243
1244         if (check_col(pinfo->cinfo, COL_PROTOCOL))
1245                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPX SAP");
1246         if (check_col(pinfo->cinfo, COL_INFO))
1247                 col_clear(pinfo->cinfo, COL_INFO);
1248
1249         query.query_type = tvb_get_ntohs(tvb, 0);
1250         query.server_type = tvb_get_ntohs(tvb, 2);
1251
1252         if (check_col(pinfo->cinfo, COL_INFO)) {
1253                 if (query.query_type >= 1 && query.query_type <= 4) {
1254                         col_set_str(pinfo->cinfo, COL_INFO, sap_type[query.query_type - 1]);
1255                 }
1256                 else {
1257                         col_set_str(pinfo->cinfo, COL_INFO, "Unknown Packet Type");
1258                 }
1259         }
1260
1261         if (tree) {
1262                 ti = proto_tree_add_item(tree, proto_sap, tvb, 0, -1, FALSE);
1263                 sap_tree = proto_item_add_subtree(ti, ett_ipxsap);
1264
1265                 if (query.query_type >= 1 && query.query_type <= 4) {
1266                         proto_tree_add_text(sap_tree, tvb, 0, 2, sap_type[query.query_type - 1]);
1267                         if ((query.query_type - 1) % 2) {
1268                           proto_tree_add_boolean_hidden(sap_tree,
1269                                                      hf_sap_response,
1270                                                      tvb, 0, 2, 1);
1271                         } else {
1272                           proto_tree_add_boolean_hidden(sap_tree,
1273                                                      hf_sap_request,
1274                                                      tvb, 0, 2, 1);
1275                         }
1276                 }
1277                 else {
1278                         proto_tree_add_text(sap_tree, tvb, 0, 2,
1279                                         "Unknown SAP Packet Type %d", query.query_type);
1280                 }
1281
1282                 if (query.query_type == IPX_SAP_GENERAL_RESPONSE ||
1283                                 query.query_type == IPX_SAP_NEAREST_RESPONSE) { /* responses */
1284
1285                         int available_length = tvb_reported_length(tvb);
1286                         for (cursor =  2; (cursor + 64) <= available_length; cursor += 64) {
1287                                 server_type = tvb_get_ntohs(tvb, cursor);
1288                                 tvb_memcpy(tvb, (guint8 *)server_name,
1289                                     cursor+2, 48);
1290
1291                                 ti = proto_tree_add_text(sap_tree, tvb, cursor+2, 48,
1292                                         "Server Name: %.48s", server_name);
1293                                 s_tree = proto_item_add_subtree(ti, ett_ipxsap_server);
1294
1295                                 proto_tree_add_text(s_tree, tvb, cursor, 2, "Server Type: %s (0x%04X)",
1296                                     val_to_str(server_type, server_vals, "Unknown"),
1297                                     server_type);
1298                                 proto_tree_add_text(s_tree, tvb, cursor+50, 4, "Network: %s",
1299                                                 ipxnet_to_string(tvb_get_ptr(tvb, cursor+50, 4)));
1300                                 proto_tree_add_text(s_tree, tvb, cursor+54, 6, "Node: %s",
1301                                                 ether_to_str(tvb_get_ptr(tvb, cursor+54, 6)));
1302                                 server_port = tvb_get_ntohs(tvb, cursor+60);
1303                                 proto_tree_add_text(s_tree, tvb, cursor+60, 2, "Socket: %s (0x%04x)",
1304                                                 socket_text(server_port),
1305                                                 server_port);
1306                                 intermediate_network = tvb_get_ntohs(tvb, cursor+62);
1307                                 proto_tree_add_text(s_tree, tvb, cursor+62, 2,
1308                                                 "Intermediate Networks: %d",
1309                                                 intermediate_network);
1310                         }
1311                 }
1312                 else {  /* queries */
1313                         proto_tree_add_text(sap_tree, tvb, 2, 2, "Server Type: %s (0x%04X)",
1314                                 val_to_str(query.server_type, server_vals, "Unknown"),
1315                                 query.server_type);
1316                 }
1317         }
1318 }
1319
1320 void
1321 proto_register_ipx(void)
1322 {
1323         static hf_register_info hf_ipx[] = {
1324                 { &hf_ipx_checksum,
1325                 { "Checksum",           "ipx.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1326                         "", HFILL }},
1327
1328                 { &hf_ipx_src,
1329                 { "Source Address",     "ipx.src", FT_STRING, BASE_DEC, NULL, 0x0,
1330                   "Source IPX Address  \"network.node\"", HFILL }},
1331
1332                 { &hf_ipx_dst,
1333                 { "Destination Address",        "ipx.dst", FT_STRING, BASE_DEC, NULL, 0x0,
1334                   "Destination IPX Address  \"network.node\"", HFILL }},
1335                 { &hf_ipx_addr,
1336                 { "Src/Dst Address",    "ipx.addr", FT_STRING, BASE_DEC, NULL, 0x0,
1337                   "Source or Destination IPX Address  \"network.node\"", HFILL }},
1338
1339                 { &hf_ipx_len,
1340                 { "Length",             "ipx.len", FT_UINT16, BASE_DEC, NULL, 0x0,
1341                         "", HFILL }},
1342
1343                 { &hf_ipx_hops,
1344                 { "Transport Control (Hops)", "ipx.hops", FT_UINT8, BASE_DEC, NULL, 0x0,
1345                         "", HFILL }},
1346
1347                 { &hf_ipx_packet_type,
1348                 { "Packet Type",        "ipx.packet_type", FT_UINT8, BASE_HEX, VALS(ipx_packet_type_vals),
1349                         0x0,
1350                         "", HFILL }},
1351
1352                 { &hf_ipx_dnet,
1353                 { "Destination Network","ipx.dst.net", FT_IPXNET, BASE_NONE, NULL, 0x0,
1354                         "", HFILL }},
1355
1356                 { &hf_ipx_dnode,
1357                 { "Destination Node",   "ipx.dst.node", FT_ETHER, BASE_NONE, NULL, 0x0,
1358                         "", HFILL }},
1359
1360                 { &hf_ipx_dsocket,
1361                 { "Destination Socket", "ipx.dst.socket", FT_UINT16, BASE_HEX,
1362                         VALS(ipx_socket_vals), 0x0,
1363                         "", HFILL }},
1364
1365                 { &hf_ipx_snet,
1366                 { "Source Network","ipx.src.net", FT_IPXNET, BASE_NONE, NULL, 0x0,
1367                         "", HFILL }},
1368
1369                 { &hf_ipx_snode,
1370                 { "Source Node",        "ipx.src.node", FT_ETHER, BASE_NONE, NULL, 0x0,
1371                         "", HFILL }},
1372
1373                 { &hf_ipx_ssocket,
1374                 { "Source Socket",      "ipx.src.socket", FT_UINT16, BASE_HEX,
1375                         VALS(ipx_socket_vals), 0x0,
1376                         "", HFILL }},
1377
1378                 { &hf_ipx_net,
1379                 { "Source or Destination Network","ipx.net", FT_IPXNET, BASE_NONE, NULL, 0x0,
1380                         "", HFILL }},
1381
1382                 { &hf_ipx_node,
1383                 { "Source or Destination Node", "ipx.node", FT_ETHER, BASE_NONE, NULL, 0x0,
1384                         "", HFILL }},
1385         
1386                 { &hf_ipx_socket,
1387                 { "Source or Destination Socket", "ipx.socket", FT_UINT16, BASE_HEX,
1388                         VALS(ipx_socket_vals), 0x0,
1389                         "", HFILL }},
1390         };
1391
1392         static hf_register_info hf_spx[] = {
1393                 { &hf_spx_connection_control,
1394                 { "Connection Control",         "spx.ctl",
1395                   FT_UINT8,     BASE_HEX,       NULL,   0x0,
1396                   "", HFILL }},
1397
1398                 { &hf_spx_connection_control_sys,
1399                 { "System Packet",              "spx.ctl.sys",
1400                   FT_BOOLEAN,   8,      NULL,   SPX_SYS_PACKET,
1401                   "", HFILL }},
1402
1403                 { &hf_spx_connection_control_send_ack,
1404                 { "Send Ack",           "spx.ctl.send_ack",
1405                   FT_BOOLEAN,   8,      NULL,   SPX_SEND_ACK,
1406                   "", HFILL }},
1407
1408                 { &hf_spx_connection_control_attn,
1409                 { "Attention",          "spx.ctl.attn",
1410                   FT_BOOLEAN,   8,      NULL,   SPX_ATTN,
1411                   "", HFILL }},
1412
1413                 { &hf_spx_connection_control_eom,
1414                 { "End of Message",     "spx.ctl.eom",
1415                   FT_BOOLEAN,   8,      NULL,   SPX_EOM,
1416                   "", HFILL }},
1417
1418                 { &hf_spx_datastream_type,
1419                 { "Datastream type",            "spx.type",
1420                   FT_UINT8,     BASE_HEX,       NULL,   0x0,
1421                   "", HFILL }},
1422
1423                 { &hf_spx_src_id,
1424                 { "Source Connection ID",       "spx.src",
1425                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
1426                   "", HFILL }},
1427
1428                 { &hf_spx_dst_id,
1429                 { "Destination Connection ID",  "spx.dst",
1430                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
1431                   "", HFILL }},
1432
1433                 { &hf_spx_seq_nr,
1434                 { "Sequence Number",            "spx.seq",
1435                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
1436                   "", HFILL }},
1437
1438                 { &hf_spx_ack_nr,
1439                 { "Acknowledgment Number",      "spx.ack",
1440                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
1441                   "", HFILL }},
1442
1443                 { &hf_spx_all_nr,
1444                 { "Allocation Number",          "spx.alloc",
1445                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
1446                   "", HFILL }},
1447
1448                 { &hf_spx_rexmt_frame,
1449                 { "Retransmitted Frame Number", "spx.rexmt_frame",
1450                   FT_FRAMENUM,  BASE_NONE,      NULL,   0x0,
1451                   "", HFILL }},
1452         };
1453
1454         static hf_register_info hf_ipxrip[] = {
1455                 { &hf_ipxrip_request,
1456                 { "Request",                    "ipxrip.request",
1457                   FT_BOOLEAN,   BASE_NONE,      NULL,   0x0,
1458                   "TRUE if IPX RIP request", HFILL }},
1459
1460                 { &hf_ipxrip_response,
1461                 { "Response",                   "ipxrip.response",
1462                   FT_BOOLEAN,   BASE_NONE,      NULL,   0x0,
1463                   "TRUE if IPX RIP response", HFILL }}
1464         };
1465
1466         static hf_register_info hf_sap[] = {
1467                 { &hf_sap_request,
1468                 { "Request",                    "ipxsap.request",
1469                   FT_BOOLEAN,   BASE_NONE,      NULL,   0x0,
1470                   "TRUE if SAP request", HFILL }},
1471
1472                 { &hf_sap_response,
1473                 { "Response",                   "ipxsap.response",
1474                   FT_BOOLEAN,   BASE_NONE,      NULL,   0x0,
1475                   "TRUE if SAP response", HFILL }}
1476         };
1477
1478         static hf_register_info hf_ipxmsg[] = {
1479                 { &hf_msg_conn,
1480                 { "Connection Number",                  "ipxmsg.conn",
1481                   FT_UINT8,     BASE_DEC,       NULL,   0x0,
1482                   "Connection Number", HFILL }},
1483
1484                 { &hf_msg_sigchar,
1485                 { "Signature Char",                     "ipxmsg.sigchar",
1486                   FT_UINT8,     BASE_DEC,       VALS(ipxmsg_sigchar_vals),      0x0,
1487                   "Signature Char", HFILL }}
1488         };
1489
1490         static gint *ett[] = {
1491                 &ett_ipx,
1492                 &ett_spx,
1493                 &ett_spx_connctrl,
1494                 &ett_ipxmsg,
1495                 &ett_ipxrip,
1496                 &ett_serialization,
1497                 &ett_ipxsap,
1498                 &ett_ipxsap_server,
1499         };
1500
1501         proto_ipx = proto_register_protocol("Internetwork Packet eXchange",
1502             "IPX", "ipx");
1503         proto_register_field_array(proto_ipx, hf_ipx, array_length(hf_ipx));
1504
1505         register_dissector("ipx", dissect_ipx, proto_ipx);
1506
1507         proto_spx = proto_register_protocol("Sequenced Packet eXchange",
1508             "SPX", "spx");
1509         proto_register_field_array(proto_spx, hf_spx, array_length(hf_spx));
1510
1511         proto_ipxrip = proto_register_protocol("IPX Routing Information Protocol",
1512             "IPX RIP", "ipxrip");
1513         proto_register_field_array(proto_ipxrip, hf_ipxrip, array_length(hf_ipxrip));
1514
1515         proto_serialization = proto_register_protocol("NetWare Serialization Protocol",
1516             "NW_SERIAL", "nw_serial");
1517
1518         proto_ipxmsg = proto_register_protocol("IPX Message", "IPX MSG",
1519             "ipxmsg");
1520         proto_register_field_array(proto_ipxmsg, hf_ipxmsg, array_length(hf_ipxmsg));
1521
1522         proto_sap = proto_register_protocol("Service Advertisement Protocol",
1523             "IPX SAP", "ipxsap");
1524         register_dissector("ipxsap", dissect_ipxsap, proto_sap);
1525
1526         proto_register_field_array(proto_sap, hf_sap, array_length(hf_sap));
1527
1528         proto_register_subtree_array(ett, array_length(ett));
1529
1530         ipx_type_dissector_table = register_dissector_table("ipx.packet_type",
1531             "IPX packet type", FT_UINT8, BASE_HEX);
1532         ipx_socket_dissector_table = register_dissector_table("ipx.socket",
1533             "IPX socket", FT_UINT16, BASE_HEX);
1534         spx_socket_dissector_table = register_dissector_table("spx.socket",
1535             "SPX socket", FT_UINT16, BASE_HEX);
1536         
1537         register_init_routine(&spx_init_protocol);
1538         register_postseq_cleanup_routine(&spx_postseq_cleanup);
1539         ipx_tap=register_tap("ipx");
1540 }
1541
1542 void
1543 proto_reg_handoff_ipx(void)
1544 {
1545         dissector_handle_t ipx_handle, spx_handle;
1546         dissector_handle_t ipxsap_handle, ipxrip_handle;
1547         dissector_handle_t serialization_handle, ipxmsg_handle;
1548
1549         ipx_handle = find_dissector("ipx");
1550         dissector_add("udp.port", UDP_PORT_IPX, ipx_handle);
1551         dissector_add("ethertype", ETHERTYPE_IPX, ipx_handle);
1552         dissector_add("chdlctype", ETHERTYPE_IPX, ipx_handle);
1553         dissector_add("ppp.protocol", PPP_IPX, ipx_handle);
1554         dissector_add("llc.dsap", SAP_NETWARE1, ipx_handle);
1555         dissector_add("llc.dsap", SAP_NETWARE2, ipx_handle);
1556         dissector_add("null.type", BSD_AF_IPX, ipx_handle);
1557         dissector_add("gre.proto", ETHERTYPE_IPX, ipx_handle);
1558         dissector_add("arcnet.protocol_id", ARCNET_PROTO_IPX, ipx_handle);
1559         dissector_add("arcnet.protocol_id", ARCNET_PROTO_NOVELL_EC, ipx_handle);
1560
1561         spx_handle = create_dissector_handle(dissect_spx, proto_spx);
1562         dissector_add("ipx.packet_type", IPX_PACKET_TYPE_SPX, spx_handle);
1563
1564         ipxsap_handle = find_dissector("ipxsap");
1565         dissector_add("ipx.socket", IPX_SOCKET_SAP, ipxsap_handle);
1566
1567         ipxrip_handle = create_dissector_handle(dissect_ipxrip, proto_ipxrip);
1568         dissector_add("ipx.socket", IPX_SOCKET_IPXRIP, ipxrip_handle);
1569
1570         serialization_handle = create_dissector_handle(dissect_serialization,
1571             proto_serialization);
1572         dissector_add("ipx.socket", IPX_SOCKET_SERIALIZATION,
1573             serialization_handle);
1574
1575         ipxmsg_handle = create_dissector_handle(dissect_ipxmsg, proto_ipxmsg);
1576         dissector_add("ipx.socket", IPX_SOCKET_IPX_MESSAGE, ipxmsg_handle);
1577         dissector_add("ipx.socket", IPX_SOCKET_IPX_MESSAGE1, ipxmsg_handle);
1578
1579         data_handle = find_dissector("data");
1580 }