Removed all references to gtk objects from packet*.[ch] files. They now
[obnox/wireshark/wip.git] / packet-ipx.c
1 /* packet-ipx.c
2  * Routines for NetWare's IPX
3  * Gilbert Ramirez <gram@verdict.uthscsa.edu>
4  *
5  * $Id: packet-ipx.c,v 1.18 1999/03/23 03:14:39 gram Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@unicom.net>
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 <glib.h>
37 #include "packet.h"
38 #include "packet-ipx.h"
39 #include "packet-ncp.h"
40
41 /* The information in this module (IPX, SPX, NCP) comes from:
42         NetWare LAN Analysis, Second Edition
43         Laura A. Chappell and Dan E. Hakes
44         (c) 1994 Novell, Inc.
45         Novell Press, San Jose.
46         ISBN: 0-7821-1362-1
47
48   And from the ncpfs source code by Volker Lendecke
49
50 */
51
52 static void
53 dissect_spx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
54
55 static void
56 dissect_ipxrip(const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
57
58 static void
59 dissect_sap(const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
60
61 struct port_info {
62         guint16 port;
63         void    (*func) (const u_char *, int, frame_data *, proto_tree *);
64         char    *text;
65 };
66
67 struct conn_info {
68         guint8  ctrl;
69         char    *text;
70 };
71
72 struct server_info {
73         guint16 type;
74         char    *text;
75 };
76
77 /* ================================================================= */
78 /* IPX                                                               */
79 /* ================================================================= */
80 static struct port_info ports[] = {
81         { 0x0451, dissect_ncp,          "NCP" },
82         { 0x0452, dissect_sap,          "SAP" },
83         { 0x0453, dissect_ipxrip,       "RIP" },
84         { 0x0455, NULL,                         "NetBIOS" },
85         { 0x0456, NULL,                         "Diagnostic" },
86         { 0x0457, NULL,                         "Serialization" },
87         { 0x0551, NULL,                         "NWLink SMB Name Query" },
88         { 0x0553, dissect_nwlink_dg,"NWLink SMB Datagram" },
89         { 0x055d, NULL,                         "Attachmate Gateway" },
90         { 0x4001, NULL,                         "IPX Message" },
91         { 0x0000, NULL,                         NULL }
92 };
93
94 static char*
95 port_text(guint16 port) {
96         int i=0;
97
98         while (ports[i].text != NULL) {
99                 if (ports[i].port == port) {
100                         return ports[i].text;
101                 }
102                 i++;
103         }
104         return "Unknown";
105 }
106
107 static void*
108 port_func(guint16 port) {
109         int i=0;
110
111         while (ports[i].text != NULL) {
112                 if (ports[i].port == port) {
113                         return ports[i].func;
114                 }
115                 i++;
116         }
117         return NULL;
118 }
119
120 char *
121 ipx_packet_type(u_char val)
122 {
123         if (val == 0) {
124                 return "IPX";
125         }
126         else if (val == 5) {
127                 return "SPX";
128         }
129         else if (val == 17) {
130                 return "NCP";
131         }
132         else if (val == 20) {
133                 return "NetBIOS Broadcast";
134         }
135         else if (val >= 16 && val <= 31) {
136                 return "Experimental Protocol";
137         }
138         else {
139                 return "Unknown";
140         }
141 }
142
143 gchar*
144 ipxnet_to_string(const guint8 *ad)
145 {
146         static gchar    str[3][12];
147         static gchar    *cur;
148
149         if (cur == &str[0][0]) {
150                 cur = &str[1][0];
151         } else if (cur == &str[1][0]) {
152                 cur = &str[2][0];
153         } else {
154                 cur = &str[0][0];
155         }
156
157         sprintf(cur, "%02X %02X %02X %02X", ad[0], ad[1], ad[2], ad[3]);
158         return cur;
159 }
160
161 gchar*
162 ipx_addr_to_str(guint32 net, const guint8 *ad)
163 {
164         static gchar    str[3][22];
165         static gchar    *cur;
166
167         if (cur == &str[0][0]) {
168                 cur = &str[1][0];
169         } else if (cur == &str[1][0]) {
170                 cur = &str[2][0];
171         } else {
172                 cur = &str[0][0];
173         }
174
175         sprintf(cur, "%X.%02x%02x%02x%02x%02x%02x", net, 
176                 ad[0], ad[1], ad[2], ad[3], ad[4], ad[5]);
177         return cur;
178 }
179
180 void
181 dissect_ipx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
182
183         proto_tree      *ipx_tree;
184         proto_item      *ti;
185         guint8          ipx_type, ipx_hops;
186         guint16         ipx_checksum, ipx_length;
187         guint8          *ipx_snode, *ipx_dnode, *ipx_snet, *ipx_dnet;
188
189         gchar           *str_dnet, *str_snet;
190         guint16         ipx_dsocket, ipx_ssocket;
191         void            (*dissect) (const u_char *, int, frame_data *, proto_tree *);
192
193         /* Calculate here for use in pinfo and in tree */
194         ipx_dnet = (guint8*)&pd[offset+6];
195         ipx_snet = (guint8*)&pd[offset+18];
196         str_dnet = ipxnet_to_string(ipx_dnet);
197         str_snet = ipxnet_to_string(ipx_snet);
198         ipx_dsocket = pntohs(&pd[offset+16]);
199         ipx_ssocket = pntohs(&pd[offset+28]);
200         ipx_dnode = (guint8*)&pd[offset+10];
201         ipx_snode = (guint8*)&pd[offset+22];
202         ipx_type = pd[offset+5];
203
204         if (check_col(fd, COL_RES_DL_DST))
205                 col_add_str(fd, COL_RES_DL_DST,
206                                 ipx_addr_to_str(pntohl(ipx_dnet), ipx_dnode));
207         if (check_col(fd, COL_RES_DL_SRC))
208                 col_add_str(fd, COL_RES_DL_SRC,
209                                 ipx_addr_to_str(pntohl(ipx_snet), ipx_snode));
210
211         if (check_col(fd, COL_PROTOCOL))
212                 col_add_str(fd, COL_PROTOCOL, "IPX");
213         if (check_col(fd, COL_INFO))
214                 col_add_fstr(fd, COL_INFO, "%s (0x%04X)", port_text(ipx_dsocket),
215                                 ipx_dsocket);
216
217         if (tree) {
218                 ipx_checksum = pntohs(&pd[offset]);
219                 ipx_length = pntohs(&pd[offset+2]);
220                 ipx_hops = pd[offset+4];
221
222                 ti = proto_tree_add_item(tree, offset, 30,
223                         "Internetwork Packet Exchange");
224                 ipx_tree = proto_tree_new();
225                 proto_item_add_subtree(ti, ipx_tree, ETT_IPX);
226                 proto_tree_add_item(ipx_tree, offset,      2, "Checksum: 0x%04x",
227                                 ipx_checksum);
228                 proto_tree_add_item(ipx_tree, offset+2,    2, "Length: %d bytes",
229                                 ipx_length);
230                 proto_tree_add_item(ipx_tree, offset+4,    1, "Transport Control: %d hops",
231                                 ipx_hops);
232                 proto_tree_add_item(ipx_tree, offset+5,    1, "Packet Type: %s",
233                         ipx_packet_type(ipx_type));
234                 proto_tree_add_item(ipx_tree, offset+6,    4, "Destination Network: %s",
235                         str_dnet);
236                 proto_tree_add_item(ipx_tree, offset+10,   6, "Destination Node: %s",
237                         ether_to_str(ipx_dnode));
238                 proto_tree_add_item(ipx_tree, offset+16,   2,
239                         "Destination Socket: %s (0x%04X)", port_text(ipx_dsocket),
240                         ipx_dsocket);
241                 proto_tree_add_item(ipx_tree, offset+18,   4, "Source Network: %s",
242                         str_snet);
243                 proto_tree_add_item(ipx_tree, offset+22,   6, "Source Node: %s",
244                         ether_to_str(ipx_snode));
245                 proto_tree_add_item(ipx_tree, offset+28,   2,
246                         "Source Socket: %s (0x%04X)", port_text(ipx_ssocket), ipx_ssocket);
247         }
248         offset += 30;
249
250         switch (ipx_type) {
251                 case 5: /* SPX */
252                         dissect_spx(pd, offset, fd, tree);
253                         break;
254
255                 case 17: /* NCP */
256                         if (pntohl(ipx_dnode) == 0 && pntohs(ipx_dnode + 4) == 1)
257                                 nw_server_address = pntohl(ipx_dnet);
258                         else if (pntohl(ipx_snode) == 0 && pntohs(ipx_snode + 4) == 1)
259                                 nw_server_address = pntohl(ipx_snet);
260                         else
261                                 nw_server_address = 0;
262
263                         dissect_ncp(pd, offset, fd, tree);
264                         break;
265
266                 case 20: /* NetBIOS */
267                         if (ipx_dsocket == 0x0455) {
268                                 dissect_nbipx_ns(pd, offset, fd, tree);
269                                 break;
270                         }
271                         /* else fall through */
272
273                 case 0: /* IPX, fall through to default */
274                 default:
275                         dissect = port_func(ipx_dsocket);
276                         if (dissect) {
277                                 dissect(pd, offset, fd, tree);
278                         }
279                         else {
280                                 dissect = port_func(ipx_ssocket);
281                                 if (dissect) {
282                                         dissect(pd, offset, fd, tree);
283                                 }
284                                 else {
285                                         dissect_data(pd, offset, fd, tree);
286                                 }
287                         }
288                         break;
289         }
290 }
291
292
293 /* ================================================================= */
294 /* SPX                                                               */
295 /* ================================================================= */
296 static char*
297 spx_conn_ctrl(u_char ctrl)
298 {
299         int i=0;
300
301         static struct conn_info conns[] = {
302                 { 0x10, "End-of-Message" },
303                 { 0x20, "Attention" },
304                 { 0x40, "Acknowledgment Required"},
305                 { 0x80, "System Packet"}
306         };
307
308         while (conns[i].text != NULL) {
309                 if (conns[i].ctrl == ctrl) {
310                         return conns[i].text;
311                 }
312                 i++;
313         }
314         return "Unknown";
315 }
316
317 static char*
318 spx_datastream(u_char type)
319 {
320         switch (type) {
321                 case 0xfe:
322                         return "End-of-Connection";
323                 case 0xff:
324                         return "End-of-Connection Acknowledgment";
325                 default:
326                         return "Client-Defined";
327         }
328 }
329
330 static void
331 dissect_spx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
332
333         proto_tree      *spx_tree;
334         proto_item      *ti;
335
336         if (check_col(fd, COL_PROTOCOL))
337                 col_add_str(fd, COL_PROTOCOL, "SPX");
338         if (check_col(fd, COL_INFO))
339                 col_add_str(fd, COL_INFO, "SPX");
340
341         if (tree) {
342                 ti = proto_tree_add_item(tree, offset, 12, "Sequenced Packet Exchange");
343                 spx_tree = proto_tree_new();
344                 proto_item_add_subtree(ti, spx_tree, ETT_SPX);
345
346                 proto_tree_add_item(spx_tree, offset,      1,
347                         "Connection Control: %s (0x%02X)",
348                         spx_conn_ctrl(pd[offset]), pd[offset]);
349
350                 proto_tree_add_item(spx_tree, offset+1,     1,
351                         "Datastream Type: %s (0x%02X)",
352                         spx_datastream(pd[offset+1]), pd[offset+1]);
353
354                 proto_tree_add_item(spx_tree, offset+2,     2,
355                         "Source Connection ID: %d", pntohs( &pd[offset+2] ) );
356
357                 proto_tree_add_item(spx_tree, offset+4,     2,
358                         "Destination Connection ID: %d", pntohs( &pd[offset+4] ) );
359
360                 proto_tree_add_item(spx_tree, offset+6,     2,
361                         "Sequence Number: %d", pntohs( &pd[offset+6] ) );
362
363                 proto_tree_add_item(spx_tree, offset+8,     2,
364                         "Acknowledgment Number: %d", pntohs( &pd[offset+8] ) );
365
366                 proto_tree_add_item(spx_tree, offset+10,     2,
367                         "Allocation Number: %d", pntohs( &pd[offset+10] ) );
368
369                 offset += 12;
370                 dissect_data(pd, offset, fd, tree);
371         }
372 }
373
374 /* ================================================================= */
375 /* IPX RIP                                                           */
376 /* ================================================================= */
377 static void
378 dissect_ipxrip(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
379
380         proto_tree      *rip_tree;
381         proto_item      *ti;
382         guint16         operation;
383         struct ipx_rt_def route;
384         int                     cursor;
385
386         char            *rip_type[2] = { "Request", "Response" };
387
388         operation = pntohs(&pd[offset]) - 1;
389
390         if (check_col(fd, COL_PROTOCOL))
391          col_add_str(fd, COL_PROTOCOL, "IPX RIP");
392         if (check_col(fd, COL_PROTOCOL)) {
393          if (operation < 2) {
394                  col_add_str(fd, COL_INFO, rip_type[operation]);
395          }
396          else {
397                  col_add_str(fd, COL_INFO, "Unknown Packet Type");
398          }
399         }
400
401         if (tree) {
402                 ti = proto_tree_add_item(tree, offset, END_OF_FRAME,
403                         "IPX Routing Information Protocol");
404                 rip_tree = proto_tree_new();
405                 proto_item_add_subtree(ti, rip_tree, ETT_IPXRIP);
406
407                 if (operation < 2) {
408                         proto_tree_add_item(rip_tree, offset, 2,
409                         "RIP packet type: %s", rip_type[operation]);
410                 }
411                 else {
412                         proto_tree_add_item(rip_tree, offset, 2, "Unknown RIP packet type");
413                 }
414
415                 for (cursor = offset + 2; cursor < fd->cap_len; cursor += 8) {
416                         memcpy(&route.network, &pd[cursor], 4);
417                         route.hops = pntohs(&pd[cursor+4]);
418                         route.ticks = pntohs(&pd[cursor+6]);
419
420                         if (operation == IPX_RIP_REQUEST - 1) {
421                                 proto_tree_add_item(rip_tree, cursor,      8,
422                                         "Route Vector: %s, %d hop%s, %d tick%s",
423                                         ipxnet_to_string((guint8*)&route.network),
424                                         route.hops,  route.hops  == 1 ? "" : "s",
425                                         route.ticks, route.ticks == 1 ? "" : "s");
426                         }
427                         else {
428                                 proto_tree_add_item(rip_tree, cursor,      8,
429                                         "Route Vector: %s, %d hop%s, %d tick%s (%d ms)",
430                                         ipxnet_to_string((guint8*)&route.network),
431                                         route.hops,  route.hops  == 1 ? "" : "s",
432                                         route.ticks, route.ticks == 1 ? "" : "s",
433                                         route.ticks * 1000 / 18);
434                         }
435                 }
436         }
437 }
438
439
440
441 /* ================================================================= */
442 /* SAP                                                                                                                           */
443 /* ================================================================= */
444 static char*
445 server_type(guint16 type)
446 {
447         int i=0;
448
449         /* some of these are from ncpfs, others are from the book */
450         static struct server_info       servers[] = {
451                 { 0x0001,       "User" },
452                 { 0x0002,       "User Group" },
453                 { 0x0003,       "Print Queue" },
454                 { 0x0004,       "File server" },
455                 { 0x0005,       "Job server" },
456                 { 0x0007,       "Print server" },
457                 { 0x0008,       "Archive server" },
458                 { 0x0009,       "Archive server" },
459                 { 0x000a,       "Job queue" },
460                 { 0x000b,       "Administration" },
461                 { 0x0021,       "NAS SNA gateway" },
462                 { 0x0024,       "Remote bridge" },
463                 { 0x0026,       "Bridge server" },
464                 { 0x0027,       "TCP/IP gateway" },
465                 { 0x002d,       "Time Synchronization VAP" },
466                 { 0x002e,       "Archive Server Dynamic SAP" },
467                 { 0x0047,       "Advertising print server" },
468                 { 0x004b,       "Btrieve VAP 5.0" },
469                 { 0x004c,       "SQL VAP" },
470                 { 0x0050,       "Btrieve VAP" },
471                 { 0x0053,       "Print Queue VAP" },
472                 { 0x007a,       "TES NetWare for VMS" },
473                 { 0x0098,       "NetWare access server" },
474                 { 0x009a,       "Named Pipes server" },
475                 { 0x009e,       "Portable NetWare Unix" },
476                 { 0x0107,       "NetWare 386" },
477                 { 0x0111,       "Test server" },
478                 { 0x0133,       "NetWare Name Service" },
479                 { 0x0166,       "NetWare management" },
480                 { 0x026a,       "NetWare management" },
481                 { 0x026b,       "Time synchronization" },
482                 { 0x0278,       "NetWare Directory server" },
483                 { 0x055d,       "Attachmate SNA gateway" },
484                 { 0x0000,       NULL }
485         };
486
487         while (servers[i].text != NULL) {
488                 if (servers[i].type == type) {
489                         return servers[i].text;
490                 }
491                 i++;
492         }
493         return "Unknown";
494 }
495
496 static void
497 dissect_sap(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
498
499         proto_tree      *sap_tree, *s_tree;
500         proto_item      *ti;
501         int                     cursor;
502         struct sap_query query;
503         struct sap_server_ident server;
504
505         char            *sap_type[4] = { "General Query", "General Response",
506                 "Nearest Query", "Nearest Response" };
507
508         query.query_type = pntohs(&pd[offset]);
509         query.server_type = pntohs(&pd[offset+2]);
510
511         if (check_col(fd, COL_PROTOCOL))
512                 col_add_str(fd, COL_PROTOCOL, "SAP");
513         if (check_col(fd, COL_INFO)) {
514                 if (query.query_type < 4) {
515                         col_add_str(fd, COL_INFO, sap_type[query.query_type - 1]);
516                 }
517                 else {
518                         col_add_str(fd, COL_INFO, "Unknown Packet Type");
519                 }
520         }
521
522         if (tree) {
523                 ti = proto_tree_add_item(tree, offset, END_OF_FRAME,
524                         "Service Advertising Protocol");
525                 sap_tree = proto_tree_new();
526                 proto_item_add_subtree(ti, sap_tree, ETT_IPXSAP);
527
528                 if (query.query_type < 4) {
529                         proto_tree_add_item(sap_tree, offset, 2, sap_type[query.query_type - 1]);
530                 }
531                 else {
532                         proto_tree_add_item(sap_tree, offset, 2,
533                                         "Unknown SAP Packet Type %d", query.query_type);
534                 }
535
536                 if (query.query_type == IPX_SAP_GENERAL_RESPONSE ||
537                                 query.query_type == IPX_SAP_NEAREST_RESPONSE) { /* responses */
538
539                         for (cursor = offset + 2; (cursor + 64) <= fd->cap_len; cursor += 64) {
540                                 server.server_type = pntohs(&pd[cursor]);
541                                 memcpy(server.server_name, &pd[cursor+2], 48);
542                                 memcpy(&server.server_network, &pd[cursor+50], 4);
543                                 memcpy(&server.server_node, &pd[cursor+54], 6);
544                                 server.server_port = pntohs(&pd[cursor+60]);
545                                 server.intermediate_network = pntohs(&pd[cursor+62]);
546
547                                 ti = proto_tree_add_item(sap_tree, cursor+2, 48,
548                                         "Server Name: %s", server.server_name);
549                                 s_tree = proto_tree_new();
550                                 proto_item_add_subtree(ti, s_tree, ETT_IPXSAP_SERVER);
551
552                                 proto_tree_add_item(s_tree, cursor, 2, "Server Type: %s (0x%04X)",
553                                                 server_type(server.server_type), server.server_type);
554                                 proto_tree_add_item(s_tree, cursor+50, 4, "Network: %s",
555                                                 ipxnet_to_string((guint8*)&pd[cursor+50]));
556                                 proto_tree_add_item(s_tree, cursor+54, 6, "Node: %s",
557                                                 ether_to_str((guint8*)&pd[cursor+54]));
558                                 proto_tree_add_item(s_tree, cursor+60, 2, "Socket: %s (0x%04X)",
559                                                 port_text(server.server_port), server.server_port);
560                                 proto_tree_add_item(s_tree, cursor+62, 2,
561                                                 "Intermediate Networks: %d",
562                                                 server.intermediate_network);
563                         }
564                 }
565                 else {  /* queries */
566                         proto_tree_add_item(sap_tree, offset+2, 2, "Server Type: %s (0x%04X)",
567                                         server_type(query.server_type), query.server_type);
568                 }
569         }
570 }
571