8d347e84f6003c0f04d9b88dfaf4caf6ac4af8f1
[obnox/wireshark/wip.git] / packet-nbipx.c
1 /* packet-nbipx.c
2  * Routines for NetBIOS over IPX packet disassembly
3  * Gilbert Ramirez <gram@verdict.uthscsa.edu>
4  *
5  * $Id: packet-nbipx.c,v 1.11 1999/09/02 23:17:56 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 <glib.h>
36 #include "packet.h"
37 #include "packet-ipx.h" /* for ipxnet_to_string() */
38 #include "packet-netbios.h"
39
40 static int proto_nbipx = -1;
41
42 enum nbipx_protocol {
43         NETBIOS_NETWARE,
44         NETBIOS_NWLINK
45 };
46
47 static void
48 nbipx_ns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
49                 enum nbipx_protocol nbipx, int max_data);
50 static void
51 dissect_nbipx_dg(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
52                 int max_data);
53
54 /* There is no RFC or public specification of Netware or Microsoft
55  * NetBIOS over IPX packets. I have had to decode the protocol myself,
56  * so there are holes and perhaps errors in this code. (gram)
57  *
58  * A list of "NovelNetBIOS" packet types can be found at
59  *
60  *      http://www.protocols.com/pbook/novel.htm#NetBIOS
61  *
62  * and at least some of those packet types appear to match what's in
63  * some NBIPX packets.
64  *
65  * Note, however, that the offset of the packet type in an NBIPX packet
66  * *DEPENDS ON THE PACKET TYPE*; "Find name" and "Name recognized" have
67  * it at one offset, "Directed datagram" has it at another.  Does the
68  * NBIPX code base it on the length, or what?  Non-broadcast directed
69  * datagram packets have an IPX type of "IPX", just as "Find name" and
70  * "Name recognized" do....  For now, we base it on the length.
71  */
72 #define NBIPX_FIND_NAME         1
73 #define NBIPX_NAME_RECOGNIZED   2
74 #define NBIPX_CHECK_NAME        3
75 #define NBIPX_NAME_IN_USE       4
76 #define NBIPX_DEREGISTER_NAME   5
77 #define NBIPX_SESSION_DATA      6
78 #define NBIPX_SESSION_END       7
79 #define NBIPX_SESSION_END_ACK   8
80 #define NBIPX_STATUS_QUERY      9
81 #define NBIPX_STATUS_RESPONSE   10
82 #define NBIPX_DIRECTED_DATAGRAM 11
83
84 static const value_string nbipx_data_stream_type_vals[] = {
85         {NBIPX_FIND_NAME,               "Find name"},
86         {NBIPX_NAME_RECOGNIZED,         "Name recognized"},
87         {NBIPX_CHECK_NAME,              "Check name"},
88         {NBIPX_NAME_IN_USE,             "Name in use"},
89         {NBIPX_DEREGISTER_NAME,         "Deregister name"},
90         {NBIPX_SESSION_DATA,            "Session data"},
91         {NBIPX_SESSION_END,             "Session end"},
92         {NBIPX_SESSION_END_ACK,         "Session end ACK"},
93         {NBIPX_STATUS_QUERY,            "Status query"},
94         {NBIPX_STATUS_RESPONSE,         "Status response"},
95         {NBIPX_DIRECTED_DATAGRAM,       "Directed datagram"},
96         {0,                             NULL}
97 };
98
99 #define NWLINK_NAME_QUERY       1
100 #define NWLINK_SMB              2
101 #define NWLINK_NETBIOS_DATAGRAM 3
102
103 static const value_string nwlink_data_stream_type_vals[] = {
104         {NWLINK_NAME_QUERY,             "Name query"},
105         {NWLINK_SMB,                    "SMB"},
106         {NWLINK_NETBIOS_DATAGRAM,       "NetBIOS datagram"},
107         {0,                             NULL}
108 };
109
110 struct nbipx_ns_header {
111         /* Netware & NT NetBIOS over IPX */
112         guint32         router[8];
113         guint8          name_type;
114         guint8          packet_type;
115
116         char            name[17];
117
118         /* NT NetBIOS over IPX */
119         guint16         junk;
120         char            node_name[17];
121         
122 };
123
124
125 /* NetWare */
126 void
127 dissect_nbipx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
128 {
129         int     max_data = pi.captured_len - offset;
130
131         /*
132          * As said above, we look at the length of the packet to decide
133          * whether to treat it as a name-service packet or a datagram
134          * (the packet type would tell us, but it's at a *DIFFERENT
135          * LOCATION* in different types of packet...).
136          */
137         if (END_OF_FRAME == 50)
138                 nbipx_ns(pd, offset, fd, tree, NETBIOS_NETWARE, max_data);
139         else
140                 dissect_nbipx_dg(pd, offset, fd, tree, max_data);
141 }
142
143 void
144 dissect_nwlink_dg(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
145 {
146         int     max_data = pi.captured_len - offset;
147
148         nbipx_ns(pd, offset, fd, tree, NETBIOS_NWLINK, max_data);
149 }
150
151
152 static void
153 nbipx_ns(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
154                 enum nbipx_protocol nbipx, int max_data)
155 {
156         proto_tree                      *nbipx_tree;
157         proto_item                      *ti;
158         struct nbipx_ns_header  header;
159         int                                     i, rtr_offset;
160         int                                     name_offset;
161
162         if (nbipx == NETBIOS_NETWARE) {
163                 name_offset = 34;
164         }
165         else {
166                 name_offset = 36;
167         }
168
169
170         header.name_type = pd[offset+32];
171         header.packet_type = pd[offset+33];
172         memcpy(header.name, &pd[offset+name_offset], 16);
173         header.name[16] = 0; /* null-terminate the string */
174
175         if (nbipx == NETBIOS_NWLINK) {
176                 memcpy(header.node_name, &pd[offset+52], 16);
177                 header.node_name[17] = 0; /* null-terminate the string */
178         }
179
180         if (check_col(fd, COL_PROTOCOL)) {
181                 if (nbipx == NETBIOS_NETWARE) {
182                         col_add_str(fd, COL_PROTOCOL, "NBIPX");
183                 }
184                 else {
185                         col_add_str(fd, COL_PROTOCOL, "NWLink");
186                 }
187         }
188
189         if (check_col(fd, COL_INFO)) {
190                 if (nbipx == NETBIOS_NETWARE) {
191                         switch (header.packet_type) {
192                         case NBIPX_FIND_NAME:
193                         case NBIPX_NAME_RECOGNIZED:
194                         case NBIPX_CHECK_NAME:
195                         case NBIPX_NAME_IN_USE:
196                         case NBIPX_DEREGISTER_NAME:
197                                 col_add_fstr(fd, COL_INFO, "%s %s",
198                                         val_to_str(header.packet_type, nbipx_data_stream_type_vals, "Unknown"),
199                                         header.name);
200                                 break;
201
202                         default:
203                                 col_add_fstr(fd, COL_INFO, "%s",
204                                         val_to_str(header.packet_type, nbipx_data_stream_type_vals, "Unknown"));
205                                 break;
206                         }
207                 }
208                 else {
209                         switch (header.packet_type) {
210                         case NWLINK_NAME_QUERY:
211                                 col_add_fstr(fd, COL_INFO, "Name Query for %s", header.name);
212                                 break;
213
214                         case NWLINK_SMB:
215                                 /* Session? */
216                                 col_add_fstr(fd, COL_INFO, "SMB over NBIPX");
217                                 break;
218
219                         case NWLINK_NETBIOS_DATAGRAM:
220                                 /* Datagram? (Where did we see this?) */
221                                 col_add_fstr(fd, COL_INFO, "NetBIOS datagram over NBIPX");
222                                 break;
223                                 
224                         default:
225                                 col_add_str(fd, COL_INFO, "NetBIOS over IPX (NWLink)");
226                                 break;
227                         }
228                 }
229         }
230
231         if (tree) {
232                 ti = proto_tree_add_item(tree, proto_nbipx, offset, 68, NULL);
233                 nbipx_tree = proto_item_add_subtree(ti, ETT_NBIPX);
234
235                 if (nbipx == NETBIOS_NETWARE) {
236                         proto_tree_add_text(nbipx_tree, offset+33, 1,
237                                 "Packet Type: %s (%02X)",
238                                 val_to_str(header.packet_type, nbipx_data_stream_type_vals, "Unknown"),
239                                 header.packet_type);
240                 } else {
241                         proto_tree_add_text(nbipx_tree, offset+33, 1,
242                                 "Packet Type: %s (%02X)",
243                                 val_to_str(header.packet_type, nwlink_data_stream_type_vals, "Unknown"),
244                                 header.packet_type);
245                 }
246
247                 /* Eight routers are listed */
248                 for (i = 0; i < 8; i++) {
249                         rtr_offset = offset + (i << 2);
250                         memcpy(&header.router[i], &pd[rtr_offset], 4);
251                         if (header.router[i] != 0) {
252                                 proto_tree_add_text(nbipx_tree, rtr_offset, 4, "IPX Network: %s",
253                                                 ipxnet_to_string((guint8*)&header.router[i]));
254                         }
255                 }
256
257                 proto_tree_add_text(nbipx_tree, offset+32, 1, "Name Type: %02X",
258                                 header.name_type);
259
260                 if (nbipx == NETBIOS_NETWARE) {
261                         netbios_add_name("Name", &pd[offset], offset,
262                                         name_offset, nbipx_tree);
263                 }
264                 else {
265                         netbios_add_name("Group name", &pd[offset], offset,
266                                         name_offset, nbipx_tree);
267                         netbios_add_name("Node name", &pd[offset], offset,
268                                         52, nbipx_tree);
269                 }
270         }
271
272         if (nbipx == NETBIOS_NWLINK) {
273                 switch (header.packet_type) {
274                         case NWLINK_SMB:
275                         case NWLINK_NETBIOS_DATAGRAM:
276                                 dissect_smb(pd, offset + 68, fd, tree, max_data - 68);
277                                 break;
278                                 
279                         default:
280                                 dissect_data(pd, offset + 68, fd, tree);
281                                 break;
282                 }
283         }
284 }
285
286 static void
287 dissect_nbipx_dg(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
288                 int max_data)
289 {
290         proto_tree                      *nbipx_tree;
291         proto_item                      *ti;
292
293         if (check_col(fd, COL_PROTOCOL))
294                 col_add_str(fd, COL_PROTOCOL, "NetBIOS");
295
296         if (check_col(fd, COL_INFO))
297                 col_add_fstr(fd, COL_INFO, "NetBIOS datagram over NBIPX");
298
299         if (tree) {
300                 ti = proto_tree_add_item(tree, proto_nbipx, offset, 68, NULL);
301                 nbipx_tree = proto_item_add_subtree(ti, ETT_NBIPX);
302
303                 proto_tree_add_text(nbipx_tree, offset+1, 1,
304                                 "Packet Type: %s (%02X)",
305                                 val_to_str(pd[offset+1], nbipx_data_stream_type_vals, "Unknown"),
306                                 pd[offset+1]);
307                 proto_tree_add_text(nbipx_tree, offset, 1,
308                     "Connection control: 0x%02x", pd[offset]);
309                 netbios_add_name("Receiver's Name", &pd[offset],
310                     offset, 2, nbipx_tree);
311                 netbios_add_name("Sender's Name", &pd[offset],
312                     offset, 2+16, nbipx_tree);
313
314                 dissect_smb(pd, offset+2+16+16, fd, tree, max_data - 2+16+16);
315         }
316 }
317
318 void
319 proto_register_nbipx(void)
320 {
321 /*        static hf_register_info hf[] = {
322                 { &variable,
323                 { "Name",           "nbipx.abbreviation", TYPE, VALS_POINTER }},
324         };*/
325
326         proto_nbipx = proto_register_protocol("NetBIOS over IPX", "nbipx");
327  /*       proto_register_field_array(proto_nbipx, hf, array_length(hf));*/
328 }