Boolean fields are just like other fields - if you use the field name
[obnox/wireshark/wip.git] / packet-ipx.c
1 /* packet-ipx.c
2  * Routines for NetWare's IPX
3  * Gilbert Ramirez <gram@xiexie.org>
4  *
5  * $Id: packet-ipx.c,v 1.77 2001/01/22 00:20:29 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <glib.h>
38 #include "etypes.h"
39 #include "ppptypes.h"
40 #include "llcsaps.h"
41 #include "aftypes.h"
42 #include "packet.h"
43 #include "packet-ipx.h"
44 #include "resolv.h"
45
46 #include "packet-snmp.h"
47
48 /* The information in this module (IPX, SPX, NCP) comes from:
49         NetWare LAN Analysis, Second Edition
50         Laura A. Chappell and Dan E. Hakes
51         (c) 1994 Novell, Inc.
52         Novell Press, San Jose.
53         ISBN: 0-7821-1362-1
54
55   And from the ncpfs source code by Volker Lendecke
56
57 */
58         
59 static int proto_ipx = -1;
60 static int hf_ipx_checksum = -1;
61 static int hf_ipx_len = -1;
62 static int hf_ipx_hops = -1;
63 static int hf_ipx_packet_type = -1;
64 static int hf_ipx_dnet = -1;
65 static int hf_ipx_dnode = -1;
66 static int hf_ipx_dsocket = -1;
67 static int hf_ipx_snet = -1;
68 static int hf_ipx_snode = -1;
69 static int hf_ipx_ssocket = -1;
70
71 static gint ett_ipx = -1;
72
73 static dissector_table_t ipx_type_dissector_table;
74 static dissector_table_t ipx_socket_dissector_table;
75
76 static dissector_handle_t nbipx_handle;
77
78 static int proto_spx = -1;
79 static int hf_spx_connection_control = -1;
80 static int hf_spx_datastream_type = -1;
81 static int hf_spx_src_id = -1;
82 static int hf_spx_dst_id = -1;
83 static int hf_spx_seq_nr = -1;
84 static int hf_spx_ack_nr = -1;
85 static int hf_spx_all_nr = -1;
86
87 static gint ett_spx = -1;
88
89 static int proto_ipxrip = -1;
90 static int hf_ipxrip_request = -1;
91 static int hf_ipxrip_response = -1;
92
93 static gint ett_ipxrip = -1;
94
95 static int proto_sap = -1;
96 static int hf_sap_request = -1;
97 static int hf_sap_response = -1;
98
99 static gint ett_ipxsap = -1;
100 static gint ett_ipxsap_server = -1;
101
102 static gint ett_ipxmsg = -1;
103 static int proto_ipxmsg = -1;
104 static int hf_msg_conn = -1;
105 static int hf_msg_sigchar = -1;
106
107 static void
108 dissect_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
109
110 static void
111 dissect_ipxrip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
112
113 static void
114 dissect_ipxsap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
115
116 static void
117 dissect_ipxmsg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
118
119 #define UDP_PORT_IPX    213             /* RFC 1234 */
120
121 #define IPX_HEADER_LEN  30              /* It's *always* 30 bytes */
122
123 /* ================================================================= */
124 /* IPX                                                               */
125 /* ================================================================= */
126 static const value_string ipx_socket_vals[] = {
127         { IPX_SOCKET_PING_CISCO,                "CISCO PING" },
128         { IPX_SOCKET_NCP,                       "NCP" },
129         { IPX_SOCKET_SAP,                       "SAP" },
130         { IPX_SOCKET_IPXRIP,                    "RIP" },
131         { IPX_SOCKET_NETBIOS,                   "NetBIOS" },
132         { IPX_SOCKET_DIAGNOSTIC,                "Diagnostic" },
133         { IPX_SOCKET_SERIALIZATION,             "Serialization" },
134         { IPX_SOCKET_NWLINK_SMB_NAMEQUERY,      "NWLink SMB Name Query" },
135         { IPX_SOCKET_NWLINK_SMB_DGRAM,          "NWLink SMB Datagram" },
136         { IPX_SOCKET_NWLINK_SMB_BROWSE,         "NWLink SMB Browse" },
137         { IPX_SOCKET_ATTACHMATE_GW,             "Attachmate Gateway" },
138         { IPX_SOCKET_IPX_MESSAGE,               "IPX Message" },
139         { IPX_SOCKET_SNMP_AGENT,                "SNMP Agent" },
140         { IPX_SOCKET_SNMP_SINK,                 "SNMP Sink" },
141         { IPX_SOCKET_PING_NOVELL,               "Novell PING" },
142         { IPX_SOCKET_UDP_TUNNEL,                "UDP Tunnel" },
143         { IPX_SOCKET_TCP_TUNNEL,                "TCP Tunnel" },
144         { IPX_SOCKET_TCP_TUNNEL,                "TCP Tunnel" },
145         { IPX_SOCKET_ADSM,                      "ADSM" },
146         { IPX_SOCKET_EIGRP,                     "Cisco EIGRP for IPX" },
147         { IPX_SOCKET_WIDE_AREA_ROUTER,          "Wide Area Router" },
148         { 0x0000,                               NULL }
149 };
150
151 static const char*
152 socket_text(guint16 socket)
153 {
154         const char      *p;
155
156         p = match_strval(socket, ipx_socket_vals);
157         if (p) {
158                 return p;
159         }
160         else {
161                 return "Unknown";
162         }
163 }
164
165 static const value_string ipx_packet_type_vals[] = {
166         { IPX_PACKET_TYPE_IPX,          "IPX" },
167         { IPX_PACKET_TYPE_RIP,          "RIP" },
168         { IPX_PACKET_TYPE_ECHO,         "Echo" },
169         { IPX_PACKET_TYPE_ERROR,        "Error" },
170         { IPX_PACKET_TYPE_PEP,          "PEP" }, /* Packet Exchange Packet */
171         { IPX_PACKET_TYPE_SPX,          "SPX" },
172         { 16,                           "Experimental Protocol" },
173         { IPX_PACKET_TYPE_NCP,          "NCP" },
174         { 18,                           "Experimental Protocol" },
175         { 19,                           "Experimental Protocol" },
176         { IPX_PACKET_TYPE_WANBCAST,     "NetBIOS Broadcast" },
177         { 21,                           "Experimental Protocol" },
178         { 22,                           "Experimental Protocol" },
179         { 23,                           "Experimental Protocol" },
180         { 24,                           "Experimental Protocol" },
181         { 25,                           "Experimental Protocol" },
182         { 26,                           "Experimental Protocol" },
183         { 27,                           "Experimental Protocol" },
184         { 28,                           "Experimental Protocol" },
185         { 29,                           "Experimental Protocol" },
186         { 30,                           "Experimental Protocol" },
187         { 31,                           "Experimental Protocol" },
188         { 0,                            NULL }
189 };
190
191 static const value_string ipxmsg_sigchar_vals[] = {
192         { '?', "Poll inactive station" },
193         { 0, NULL }
194 };
195
196 gchar*
197 ipxnet_to_string(const guint8 *ad)
198 {
199         guint32 addr = pntohl(ad);
200         return ipxnet_to_str_punct(addr, ' ');
201 }
202
203 /* We use a different representation of hardware addresses
204  * than ether_to_str(); we don't put punctuation between the hex
205  * digits.
206  */
207
208 gchar*
209 ipx_addr_to_str(guint32 net, const guint8 *ad)
210 {
211         static gchar    str[3][8+1+MAXNAMELEN+1]; /* 8 digits, 1 period, NAME, 1 null */
212         static gchar    *cur;
213         char            *name;
214
215         if (cur == &str[0][0]) {
216                 cur = &str[1][0];
217         } else if (cur == &str[1][0]) {
218                 cur = &str[2][0];
219         } else {
220                 cur = &str[0][0];
221         }
222
223         name = get_ether_name_if_known(ad);
224
225         if (name) {
226                 sprintf(cur, "%s.%s", get_ipxnet_name(net), name);
227         }
228         else {
229                 sprintf(cur, "%s.%s", get_ipxnet_name(net), ether_to_str_punct(ad, '\0'));
230         }
231         return cur;
232 }
233
234 gchar *
235 ipxnet_to_str_punct(const guint32 ad, char punct)
236 {
237   static gchar  str[3][12];
238   static gchar *cur;
239   gchar        *p;
240   int          i;
241   guint32      octet;
242   static const gchar hex_digits[16] = "0123456789ABCDEF";
243   static const guint32  octet_mask[4] =
244           { 0xff000000 , 0x00ff0000, 0x0000ff00, 0x000000ff };
245
246   if (cur == &str[0][0]) {
247     cur = &str[1][0];
248   } else if (cur == &str[1][0]) {  
249     cur = &str[2][0];
250   } else {  
251     cur = &str[0][0];
252   }
253   p = &cur[12];
254   *--p = '\0';
255   i = 3;
256   for (;;) {
257     octet = (ad & octet_mask[i]) >> ((3 - i) * 8);
258     *--p = hex_digits[octet&0xF];
259     octet >>= 4;
260     *--p = hex_digits[octet&0xF];
261     if (i == 0)
262       break;
263     if (punct)
264       *--p = punct;
265     i--;
266   }
267   return p;
268 }
269
270 void
271 capture_ipx(const u_char *pd, int offset, packet_counts *ld)
272 {
273         ld->ipx++;
274 }
275
276 static void
277 dissect_ipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
278 {
279         tvbuff_t        *next_tvb;
280         const guint8    *this_pd;
281         int             this_offset, len;
282
283         proto_tree      *ipx_tree;
284         proto_item      *ti;
285
286         guint8          *src_net_node, *dst_net_node;
287
288         guint8          ipx_type, ipx_hops;
289         guint16         ipx_length;
290         int             reported_length, available_length;
291
292         guint16         ipx_dsocket, ipx_ssocket;
293
294         if (check_col(pinfo->fd, COL_PROTOCOL))
295                 col_set_str(pinfo->fd, COL_PROTOCOL, "IPX");
296         if (check_col(pinfo->fd, COL_INFO))
297                 col_clear(pinfo->fd, COL_INFO);
298
299         /* Calculate here for use in pinfo and in tree */
300         ipx_dsocket     = tvb_get_ntohs(tvb, 16);
301         ipx_ssocket     = tvb_get_ntohs(tvb, 28);
302         ipx_type        = tvb_get_guint8(tvb, 5);
303         ipx_length      = tvb_get_ntohs(tvb, 2);
304
305         /* Set the payload and captured-payload lengths to the minima of
306            (the IPX length plus the length of the headers above it) and
307            the frame lengths. XXX - remove once all dissectors use tvbuffs */
308         tvb_compat(tvb, &this_pd, &this_offset);
309         len = ipx_length + this_offset;
310         if (pi.len > len)
311                 pi.len = len;
312         if (pi.captured_len > len)
313                 pi.captured_len = len;
314
315         src_net_node = tvb_get_ptr(tvb, 18, 10);
316         dst_net_node = tvb_get_ptr(tvb, 6,  10);
317
318         SET_ADDRESS(&pi.net_src,        AT_IPX, 10, src_net_node);
319         SET_ADDRESS(&pi.src,            AT_IPX, 10, src_net_node);
320         SET_ADDRESS(&pi.net_dst,        AT_IPX, 10, dst_net_node);
321         SET_ADDRESS(&pi.dst,            AT_IPX, 10, dst_net_node);
322
323         if (check_col(pinfo->fd, COL_INFO))
324                 col_add_fstr(pinfo->fd, COL_INFO, "%s (0x%04X)",
325                                 socket_text(ipx_dsocket), ipx_dsocket);
326
327         if (tree) {
328
329                 ti = proto_tree_add_item(tree, proto_ipx, tvb, 0, IPX_HEADER_LEN, FALSE);
330                 ipx_tree = proto_item_add_subtree(ti, ett_ipx);
331
332                 proto_tree_add_item(ipx_tree, hf_ipx_checksum, tvb, 0, 2, FALSE);
333                 proto_tree_add_uint_format(ipx_tree, hf_ipx_len, tvb, 2, 2, ipx_length,
334                         "Length: %d bytes", ipx_length);
335                 ipx_hops = tvb_get_guint8(tvb, 4);
336                 proto_tree_add_uint_format(ipx_tree, hf_ipx_hops, tvb, 4, 1, ipx_hops,
337                         "Transport Control: %d hops", ipx_hops);
338                 proto_tree_add_uint(ipx_tree, hf_ipx_packet_type, tvb, 5, 1, ipx_type);
339
340                 /* Destination */
341                 proto_tree_add_item(ipx_tree, hf_ipx_dnet, tvb, 6, 4, FALSE);
342                 proto_tree_add_item(ipx_tree, hf_ipx_dnode, tvb, 10, 6, FALSE);
343                 proto_tree_add_uint_format(ipx_tree, hf_ipx_dsocket, tvb, 16, 2,
344                         ipx_dsocket, "Destination Socket: %s (0x%04X)",
345                         socket_text(ipx_dsocket), ipx_dsocket);
346
347                 /* Source */
348                 proto_tree_add_item(ipx_tree, hf_ipx_snet, tvb, 18, 4, FALSE);
349                 proto_tree_add_item(ipx_tree, hf_ipx_snode, tvb, 22, 6, FALSE);
350                 proto_tree_add_uint_format(ipx_tree, hf_ipx_ssocket, tvb, 28, 2,
351                         ipx_ssocket, "Source Socket: %s (0x%04X)", socket_text(ipx_ssocket),
352                         ipx_ssocket);
353         }
354
355         /* Make the next tvbuff */
356         reported_length = ipx_length - IPX_HEADER_LEN;
357         available_length = tvb_length(tvb) - IPX_HEADER_LEN;
358         next_tvb = tvb_new_subset(tvb, IPX_HEADER_LEN,
359                         MIN(available_length, reported_length),
360                         reported_length);
361
362         if (dissector_try_port(ipx_type_dissector_table, ipx_type, next_tvb,
363             pinfo, tree))
364                 return;
365
366         switch (ipx_type) {
367                 case IPX_PACKET_TYPE_WANBCAST:
368                 case IPX_PACKET_TYPE_PEP:
369                         if (ipx_dsocket == IPX_SOCKET_NETBIOS) {
370                                 call_dissector(nbipx_handle, next_tvb, pinfo,
371                                     tree);
372                                 return;
373                         }
374                         /* else fall through */
375
376                 case 0: /* IPX, fall through to default */
377                         /* XXX - should type 0's be dissected as NBIPX
378                            if they're aimed at the NetBIOS socket? */
379                         break;
380         }
381
382         if (dissector_try_port(ipx_socket_dissector_table, ipx_dsocket,
383             next_tvb, pinfo, tree))
384                 return;
385         if (dissector_try_port(ipx_socket_dissector_table, ipx_ssocket,
386             next_tvb, pinfo, tree))
387                 return;
388         dissect_data(next_tvb, 0, pinfo, tree);
389 }
390
391
392 /* ================================================================= */
393 /* SPX                                                               */
394 /* ================================================================= */
395 static const char*
396 spx_conn_ctrl(guint8 ctrl)
397 {
398         const char *p;
399
400         static const value_string conn_vals[] = {
401                 { 0x10, "End-of-Message" },
402                 { 0x20, "Attention" },
403                 { 0x40, "Acknowledgment Required"},
404                 { 0x80, "System Packet"},
405                 { 0x00, NULL }
406         };
407
408         p = match_strval(ctrl, conn_vals);
409
410         if (p) {
411                 return p;
412         }
413         else {
414                 return "Unknown";
415         }
416 }
417
418 static const char*
419 spx_datastream(guint8 type)
420 {
421         switch (type) {
422                 case 0xfe:
423                         return "End-of-Connection";
424                 case 0xff:
425                         return "End-of-Connection Acknowledgment";
426                 default:
427                         return "Client-Defined";
428         }
429 }
430
431 #define SPX_HEADER_LEN  12
432
433 static void
434 dissect_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
435 {
436         proto_tree      *spx_tree;
437         proto_item      *ti;
438         tvbuff_t        *next_tvb;
439
440         guint8          conn_ctrl;
441         guint8          datastream_type;
442
443         if (check_col(pinfo->fd, COL_PROTOCOL))
444                 col_set_str(pinfo->fd, COL_PROTOCOL, "SPX");
445         if (check_col(pinfo->fd, COL_INFO))
446                 col_set_str(pinfo->fd, COL_INFO, "SPX");
447
448         if (tree) {
449                 ti = proto_tree_add_item(tree, proto_spx, tvb, 0, SPX_HEADER_LEN, FALSE);
450                 spx_tree = proto_item_add_subtree(ti, ett_spx);
451
452                 conn_ctrl = tvb_get_guint8(tvb, 0);
453                 proto_tree_add_uint_format(spx_tree, hf_spx_connection_control, tvb,
454                                            0, 1, conn_ctrl,
455                                            "Connection Control: %s (0x%02X)",
456                                            spx_conn_ctrl(conn_ctrl), conn_ctrl);
457
458                 datastream_type = tvb_get_guint8(tvb, 1);
459                 proto_tree_add_uint_format(spx_tree, hf_spx_datastream_type, tvb,
460                                            1, 1, datastream_type,
461                                            "Datastream Type: %s (0x%02X)",
462                                            spx_datastream(datastream_type), datastream_type);
463
464                 proto_tree_add_item(spx_tree, hf_spx_src_id, tvb,  2, 2, FALSE);
465                 proto_tree_add_item(spx_tree, hf_spx_dst_id, tvb,  4, 2, FALSE);
466                 proto_tree_add_item(spx_tree, hf_spx_seq_nr, tvb,  6, 2, FALSE);
467                 proto_tree_add_item(spx_tree, hf_spx_ack_nr, tvb,  8, 2, FALSE);
468                 proto_tree_add_item(spx_tree, hf_spx_all_nr, tvb, 10, 2, FALSE);
469
470                 next_tvb = tvb_new_subset(tvb, SPX_HEADER_LEN, -1, -1);
471                 dissect_data(next_tvb, 0, pinfo, tree);
472         }
473 }
474
475 /* ================================================================= */
476 /* IPX Message                                                       */
477 /* ================================================================= */
478 static void
479 dissect_ipxmsg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
480 {
481         proto_tree      *msg_tree;
482         proto_item      *ti;
483         guint8          conn_number, sig_char;
484
485         if (check_col(pinfo->fd, COL_PROTOCOL))
486                 col_set_str(pinfo->fd, COL_PROTOCOL, "IPX MSG");
487         if (check_col(pinfo->fd, COL_INFO))
488                 col_clear(pinfo->fd, COL_INFO);
489
490         conn_number = tvb_get_guint8(tvb, 0);
491         sig_char = tvb_get_guint8(tvb, 1);
492
493         if (check_col(pinfo->fd, COL_INFO)) {
494                 col_add_fstr(pinfo->fd, COL_INFO, 
495                         "%s, Connection %d", 
496                         val_to_str(sig_char, ipxmsg_sigchar_vals, "Unknown Signature Char"), conn_number);
497         }
498
499         if (tree) {
500                 ti = proto_tree_add_item(tree, proto_ipxmsg, tvb, 0, tvb_length(tvb), FALSE);
501                 msg_tree = proto_item_add_subtree(ti, ett_ipxmsg);
502
503                 proto_tree_add_uint(msg_tree, hf_msg_conn, tvb, 0, 1, conn_number);
504                 proto_tree_add_uint(msg_tree, hf_msg_sigchar, tvb, 1, 1, sig_char);
505         }
506 }
507
508
509 /* ================================================================= */
510 /* IPX RIP                                                           */
511 /* ================================================================= */
512 static void
513 dissect_ipxrip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
514 {
515         proto_tree      *rip_tree;
516         proto_item      *ti;
517         guint16         operation;
518         struct ipx_rt_def route;
519         int             cursor;
520         int             available_length;
521
522         char            *rip_type[3] = { "Request", "Response", "Unknown" };
523
524         if (check_col(pinfo->fd, COL_PROTOCOL))
525                 col_set_str(pinfo->fd, COL_PROTOCOL, "IPX RIP");
526         if (check_col(pinfo->fd, COL_INFO))
527                 col_clear(pinfo->fd, COL_INFO);
528
529         operation = tvb_get_ntohs(tvb, 0) - 1;
530
531         if (check_col(pinfo->fd, COL_INFO)) {
532                 /* rip_types 0 and 1 are valid, anything else becomes 2 or "Unknown" */
533                 col_add_str(pinfo->fd, COL_INFO, rip_type[MIN(operation, 2)]);
534         }
535
536         if (tree) {
537                 ti = proto_tree_add_item(tree, proto_ipxrip, tvb, 0, tvb_length(tvb), FALSE);
538                 rip_tree = proto_item_add_subtree(ti, ett_ipxrip);
539
540                 if (operation < 2) {
541                         proto_tree_add_text(rip_tree, tvb, 0, 2,
542                         "RIP packet type: %s", rip_type[operation]);
543
544                         if (operation == 0) {
545                           proto_tree_add_boolean_hidden(rip_tree, 
546                                                      hf_ipxrip_request, 
547                                                      tvb, 0, 2, 1);
548                         } else {
549                           proto_tree_add_boolean_hidden(rip_tree, 
550                                                      hf_ipxrip_response, 
551                                                      tvb, 0, 2, 1);
552                         }
553
554                 }
555                 else {
556                         proto_tree_add_text(rip_tree, tvb, 0, 2, "Unknown RIP packet type");
557                 }
558
559                 available_length = tvb_length(tvb);
560                 for (cursor =  2; cursor < available_length; cursor += 8) {
561                         memcpy(&route.network, tvb_get_ptr(tvb, cursor, 4), 4);
562                         route.hops = tvb_get_ntohs(tvb, cursor+4);
563                         route.ticks = tvb_get_ntohs(tvb, cursor+6);
564
565                         if (operation == IPX_RIP_REQUEST - 1) {
566                                 proto_tree_add_text(rip_tree, tvb, cursor,      8,
567                                         "Route Vector: %s, %d hop%s, %d tick%s",
568                                         ipxnet_to_string((guint8*)&route.network),
569                                         route.hops,  route.hops  == 1 ? "" : "s",
570                                         route.ticks, route.ticks == 1 ? "" : "s");
571                         }
572                         else {
573                                 proto_tree_add_text(rip_tree, tvb, cursor,      8,
574                                         "Route Vector: %s, %d hop%s, %d tick%s (%d ms)",
575                                         ipxnet_to_string((guint8*)&route.network),
576                                         route.hops,  route.hops  == 1 ? "" : "s",
577                                         route.ticks, route.ticks == 1 ? "" : "s",
578                                         route.ticks * 1000 / 18);
579                         }
580                 }
581         }
582 }
583
584
585
586 /* ================================================================= */
587 /* SAP                                                                   */
588 /* ================================================================= */
589 static const char*
590 server_type(guint16 type)
591 {
592         const char *p;
593
594         /* some of these are from ncpfs, others are from the book */
595         static const value_string server_vals[] = {
596                 { 0x0001,       "User" },
597                 { 0x0002,       "User Group" },
598                 { 0x0003,       "Print Queue" },
599                 { 0x0004,       "File server" },
600                 { 0x0005,       "Job server" },
601                 { 0x0007,       "Print server" },
602                 { 0x0008,       "Archive server" },
603                 { 0x0009,       "Archive server" },
604                 { 0x000a,       "Job queue" },
605                 { 0x000b,       "Administration" },
606                 { 0x0021,       "NAS SNA gateway" },
607                 { 0x0024,       "Remote bridge" },
608                 { 0x0026,       "Bridge server" },
609                 { 0x0027,       "TCP/IP gateway" },
610                 { 0x002d,       "Time Synchronization VAP" },
611                 { 0x002e,       "Archive Server Dynamic SAP" },
612                 { 0x0047,       "Advertising print server" },
613                 { 0x004b,       "Btrieve VAP 5.0" },
614                 { 0x004c,       "SQL VAP" },
615                 { 0x0050,       "Btrieve VAP" },
616                 { 0x0053,       "Print Queue VAP" },
617                 { 0x007a,       "TES NetWare for VMS" },
618                 { 0x0098,       "NetWare access server" },
619                 { 0x009a,       "Named Pipes server" },
620                 { 0x009e,       "Portable NetWare Unix" },
621                 { 0x0107,       "NetWare 386" },
622                 { 0x0111,       "Test server" },
623                 { 0x0133,       "NetWare Name Service" },
624                 { 0x0166,       "NetWare management" },
625                 { 0x023f,       "SMS Testing and Development" },
626                 { 0x026a,       "NetWare management" },
627                 { 0x026b,       "Time synchronization" },
628                 { 0x027b,       "NetWare Management Agent" },
629                 { 0x0278,       "NetWare Directory server" },
630                 { 0x030c,       "HP LaserJet / Quick Silver" },
631                 { 0x0355,       "Arcada Software" },
632                 { 0x0361,       "NETINELO" },
633                 { 0x037e,       "Powerchute UPS Monitoring" },
634                 { 0x03e1,       "UnixWare Application Server" },
635                 { 0x044c,       "Archive" },
636                 { 0x055d,       "Attachmate SNA gateway" },
637                 { 0x0610,       "Adaptec SCSI Management" },
638                 { 0x0640,       "NT Server-RPC/GW for NW/Win95 User Level Sec" },
639                 { 0x064e,       "NT Server-IIS" },
640                 { 0x0810,       "ELAN License Server Demo" },
641                 { 0x8002,       "Intel NetPort Print Server" },
642
643 /* For any unidentified ones, I found a really big list of them at: */
644 /*    http://www.inpnet.org/cnpweb/saplist.txt */
645 /*    http://www.isi.edu/in-notes/iana/assignments/novell-sap-numbers */
646
647                 { 0x0000,       NULL }
648         };
649
650         p = match_strval(type, server_vals);
651         if (p) {
652                 return p;
653         }
654         else {
655                 return "Unknown";
656         }
657 }
658
659 static void
660 dissect_ipxsap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
661 {
662         proto_tree      *sap_tree, *s_tree;
663         proto_item      *ti;
664         int             cursor;
665         struct sap_query query;
666         struct sap_server_ident server;
667
668         char            *sap_type[4] = { "General Query", "General Response",
669                 "Nearest Query", "Nearest Response" };
670
671         if (check_col(pinfo->fd, COL_PROTOCOL))
672                 col_set_str(pinfo->fd, COL_PROTOCOL, "IPX SAP");
673         if (check_col(pinfo->fd, COL_INFO))
674                 col_clear(pinfo->fd, COL_INFO);
675
676         query.query_type = tvb_get_ntohs(tvb, 0);
677         query.server_type = tvb_get_ntohs(tvb, 2);
678
679         if (check_col(pinfo->fd, COL_INFO)) {
680                 if (query.query_type >= 1 && query.query_type <= 4) {
681                         col_add_str(pinfo->fd, COL_INFO, sap_type[query.query_type - 1]);
682                 }
683                 else {
684                         col_set_str(pinfo->fd, COL_INFO, "Unknown Packet Type");
685                 }
686         }
687
688         if (tree) {
689                 ti = proto_tree_add_item(tree, proto_sap, tvb, 0, tvb_length(tvb), FALSE);
690                 sap_tree = proto_item_add_subtree(ti, ett_ipxsap);
691
692                 if (query.query_type >= 1 && query.query_type <= 4) {
693                         proto_tree_add_text(sap_tree, tvb, 0, 2, sap_type[query.query_type - 1]);
694                         if ((query.query_type - 1) % 2) {
695                           proto_tree_add_boolean_hidden(sap_tree, 
696                                                      hf_sap_response, 
697                                                      tvb, 0, 2, 1);
698                         } else {
699                           proto_tree_add_boolean_hidden(sap_tree, 
700                                                      hf_sap_request, 
701                                                      tvb, 0, 2, 1);
702                         }
703                 }
704                 else {
705                         proto_tree_add_text(sap_tree, tvb, 0, 2,
706                                         "Unknown SAP Packet Type %d", query.query_type);
707                 }
708
709                 if (query.query_type == IPX_SAP_GENERAL_RESPONSE ||
710                                 query.query_type == IPX_SAP_NEAREST_RESPONSE) { /* responses */
711
712                         int available_length = tvb_length(tvb);
713                         for (cursor =  2; (cursor + 64) <= available_length; cursor += 64) {
714                                 server.server_type = tvb_get_ntohs(tvb, cursor);
715                                 memcpy(server.server_name, tvb_get_ptr(tvb, cursor+2, 48), 48);
716                                 memcpy(&server.server_network, tvb_get_ptr(tvb, cursor+50, 4), 4);
717                                 memcpy(&server.server_node, tvb_get_ptr(tvb, cursor+54, 6), 6);
718                                 server.server_port = tvb_get_ntohs(tvb, cursor+60);
719                                 server.intermediate_network = tvb_get_ntohs(tvb, cursor+62);
720
721                                 ti = proto_tree_add_text(sap_tree, tvb, cursor+2, 48,
722                                         "Server Name: %s", server.server_name);
723                                 s_tree = proto_item_add_subtree(ti, ett_ipxsap_server);
724
725                                 proto_tree_add_text(s_tree, tvb, cursor, 2, "Server Type: %s (0x%04X)",
726                                                 server_type(server.server_type), server.server_type);
727                                 proto_tree_add_text(s_tree, tvb, cursor+50, 4, "Network: %s",
728                                                 ipxnet_to_string((guint8*)tvb_get_ptr(tvb, cursor+50, 4)));
729                                 proto_tree_add_text(s_tree, tvb, cursor+54, 6, "Node: %s",
730                                                 ether_to_str((guint8*)tvb_get_ptr(tvb, cursor+54, 6)));
731                                 proto_tree_add_text(s_tree, tvb, cursor+60, 2, "Socket: %s (0x%04X)",
732                                                 socket_text(server.server_port), server.server_port);
733                                 proto_tree_add_text(s_tree, tvb, cursor+62, 2,
734                                                 "Intermediate Networks: %d",
735                                                 server.intermediate_network);
736                         }
737                 }
738                 else {  /* queries */
739                         proto_tree_add_text(sap_tree, tvb, 2, 2, "Server Type: %s (0x%04X)",
740                                         server_type(query.server_type), query.server_type);
741                 }
742         }
743 }
744
745 void
746 proto_register_ipx(void)
747 {
748         static hf_register_info hf_ipx[] = {
749                 { &hf_ipx_checksum,
750                 { "Checksum",           "ipx.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
751                         "" }},
752
753                 { &hf_ipx_len,
754                 { "Length",             "ipx.len", FT_UINT16, BASE_DEC, NULL, 0x0,
755                         "" }},
756
757                 { &hf_ipx_hops,
758                 { "Transport Control (Hops)", "ipx.hops", FT_UINT8, BASE_DEC, NULL, 0x0,
759                         "" }},
760
761                 { &hf_ipx_packet_type,
762                 { "Packet Type",        "ipx.packet_type", FT_UINT8, BASE_HEX, VALS(ipx_packet_type_vals),
763                         0x0,
764                         "" }},
765
766                 { &hf_ipx_dnet,
767                 { "Destination Network","ipx.dst.net", FT_IPXNET, BASE_NONE, NULL, 0x0,
768                         "" }},
769
770                 { &hf_ipx_dnode,
771                 { "Destination Node",   "ipx.dst.node", FT_ETHER, BASE_NONE, NULL, 0x0,
772                         "" }},
773
774                 { &hf_ipx_dsocket,
775                 { "Destination Socket", "ipx.dst.socket", FT_UINT16, BASE_HEX, NULL, 0x0,
776                         "" }},
777
778                 { &hf_ipx_snet,
779                 { "Source Network","ipx.src.net", FT_IPXNET, BASE_NONE, NULL, 0x0,
780                         "" }},
781
782                 { &hf_ipx_snode,
783                 { "Source Node",        "ipx.src.node", FT_ETHER, BASE_NONE, NULL, 0x0,
784                         "" }},
785
786                 { &hf_ipx_ssocket,
787                 { "Source Socket",      "ipx.src.socket", FT_UINT16, BASE_HEX, NULL, 0x0,
788                         "" }},
789         };
790
791         static hf_register_info hf_spx[] = {
792                 { &hf_spx_connection_control,
793                 { "Connection Control",         "spx.ctl", 
794                   FT_UINT8,     BASE_HEX,       NULL,   0x0,
795                   "" }},
796
797                 { &hf_spx_datastream_type,
798                 { "Datastream type",            "spx.type", 
799                   FT_UINT8,     BASE_HEX,       NULL,   0x0,
800                   "" }},
801
802                 { &hf_spx_src_id,
803                 { "Source Connection ID",       "spx.src", 
804                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
805                   "" }},
806
807                 { &hf_spx_dst_id,
808                 { "Destination Connection ID",  "spx.dst", 
809                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
810                   "" }},
811
812                 { &hf_spx_seq_nr,
813                 { "Sequence Number",            "spx.seq", 
814                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
815                   "" }},
816
817                 { &hf_spx_ack_nr,
818                 { "Acknowledgment Number",      "spx.ack", 
819                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
820                   "" }},
821
822                 { &hf_spx_all_nr,
823                 { "Allocation Number",          "spx.alloc", 
824                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
825                   "" }}
826         };
827
828         static hf_register_info hf_ipxrip[] = {
829                 { &hf_ipxrip_request,
830                 { "Request",                    "ipxrip.request", 
831                   FT_BOOLEAN,   BASE_NONE,      NULL,   0x0,
832                   "TRUE if IPX RIP request" }},
833
834                 { &hf_ipxrip_response,
835                 { "Response",                   "ipxrip.response", 
836                   FT_BOOLEAN,   BASE_NONE,      NULL,   0x0,
837                   "TRUE if IPX RIP response" }}
838         };
839
840         static hf_register_info hf_sap[] = {
841                 { &hf_sap_request,
842                 { "Request",                    "ipxsap.request", 
843                   FT_BOOLEAN,   BASE_NONE,      NULL,   0x0,
844                   "TRUE if SAP request" }},
845
846                 { &hf_sap_response,
847                 { "Response",                   "ipxsap.response", 
848                   FT_BOOLEAN,   BASE_NONE,      NULL,   0x0,
849                   "TRUE if SAP response" }}
850         };
851
852         static hf_register_info hf_ipxmsg[] = {
853                 { &hf_msg_conn,
854                 { "Connection Number",                  "ipxmsg.conn", 
855                   FT_UINT8,     BASE_NONE,      NULL,   0x0,
856                   "Connection Number" }},
857
858                 { &hf_msg_sigchar,
859                 { "Signature Char",                     "ipxmsg.sigchar", 
860                   FT_UINT8,     BASE_NONE,      VALS(ipxmsg_sigchar_vals),      0x0,
861                   "Signature Char" }}
862         };
863
864         static gint *ett[] = {
865                 &ett_ipx,
866                 &ett_spx,
867                 &ett_ipxmsg,
868                 &ett_ipxrip,
869                 &ett_ipxsap,
870                 &ett_ipxsap_server,
871         };
872
873         proto_ipx = proto_register_protocol("Internetwork Packet eXchange",
874             "IPX", "ipx");
875         proto_register_field_array(proto_ipx, hf_ipx, array_length(hf_ipx));
876
877         register_dissector("ipx", dissect_ipx, proto_ipx);
878
879         proto_spx = proto_register_protocol("Sequenced Packet eXchange",
880             "SPX", "spx");
881         proto_register_field_array(proto_spx, hf_spx, array_length(hf_spx));
882
883         proto_ipxrip = proto_register_protocol("IPX Routing Information Protocol",
884             "IPX RIP", "ipxrip");
885         proto_register_field_array(proto_ipxrip, hf_ipxrip, array_length(hf_ipxrip));
886
887         proto_ipxmsg = proto_register_protocol("IPX Message", "IPX MSG",
888             "ipxmsg");
889         proto_register_field_array(proto_ipxmsg, hf_ipxmsg, array_length(hf_ipxmsg));
890
891         proto_sap = proto_register_protocol("Service Advertisement Protocol",
892             "IPX SAP", "ipxsap");
893         proto_register_field_array(proto_sap, hf_sap, array_length(hf_sap));
894
895         proto_register_subtree_array(ett, array_length(ett));
896
897         ipx_type_dissector_table = register_dissector_table("ipx.packet_type");
898         ipx_socket_dissector_table = register_dissector_table("ipx.socket");
899 }
900
901 void
902 proto_reg_handoff_ipx(void)
903 {
904         /*
905          * Get handle for the NBIPX dissector.
906          */
907         nbipx_handle = find_dissector("nbipx");
908
909         dissector_add("udp.port", UDP_PORT_IPX, dissect_ipx, proto_ipx);
910         dissector_add("ethertype", ETHERTYPE_IPX, dissect_ipx, proto_ipx);
911         dissector_add("fr.cisco", ETHERTYPE_IPX, dissect_ipx, proto_ipx);
912         dissector_add("ppp.protocol", PPP_IPX, dissect_ipx, proto_ipx);
913         dissector_add("llc.dsap", SAP_NETWARE, dissect_ipx, proto_ipx);
914         dissector_add("null.type", BSD_AF_IPX, dissect_ipx, proto_ipx);
915         dissector_add("gre.proto", ETHERTYPE_IPX, dissect_ipx, proto_ipx);
916         dissector_add("ipx.packet_type", IPX_PACKET_TYPE_SPX, dissect_spx,
917             proto_spx);
918         dissector_add("ipx.socket", IPX_SOCKET_SAP, dissect_ipxsap,
919             proto_sap);
920         dissector_add("ipx.socket", IPX_SOCKET_IPXRIP, dissect_ipxrip,
921             proto_ipxrip);
922         dissector_add("ipx.socket", IPX_SOCKET_IPX_MESSAGE, dissect_ipxmsg,
923             proto_ipxmsg);
924 }