Fix up the handling of NBIPX packets, and of Microsoft "direct hosting"
[obnox/wireshark/wip.git] / packet-nbipx.c
1 /* packet-nbipx.c
2  * Routines for NetBIOS over IPX packet disassembly
3  * Gilbert Ramirez <gram@xiexie.org>
4  *
5  * $Id: packet-nbipx.c,v 1.37 2001/02/27 07:28:47 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 <string.h>
36 #include <glib.h>
37 #include "packet.h"
38 #include "packet-ipx.h"
39 #include "packet-netbios.h"
40 #include "packet-smb.h"
41
42 static int proto_nbipx = -1;
43
44 static gint ett_nbipx = -1;
45 static gint ett_nbipx_conn_ctrl = -1;
46 static gint ett_nbipx_name_type_flags = -1;
47
48 static void dissect_conn_control(tvbuff_t *tvb, int offset, proto_tree *tree);
49 static void dissect_packet_type(tvbuff_t *tvb, int offset, guint8 packet_type,
50     proto_tree *tree);
51
52 /* There is no RFC or public specification of Netware or Microsoft
53  * NetBIOS over IPX packets. I have had to decode the protocol myself,
54  * so there are holes and perhaps errors in this code. (gram)
55  *
56  * A list of "NovelNetBIOS" packet types can be found at
57  *
58  *      http://www.protocols.com/pbook/novel.htm#NetBIOS
59  *
60  * and at least some of those packet types appear to match what's in
61  * some NBIPX packets.
62  *
63  * Note, however, that it appears that sometimes NBIPX packets have
64  * 8 IPX addresses at the beginning, and sometimes they don't.
65  *
66  * In the section on "NetBIOS Broadcasts", the document at
67  *
68  *      http://www.microsoft.com/technet/network/ipxrout.asp
69  *
70  * says that "the NetBIOS over IPX Broadcast header" contains 8 IPX
71  * network numbers in the "IPX WAN broadcast header", and that it's
72  * followed by a "Name Type Flags" byte (giving information about the
73  * name being registered, deregistered, or checked), a "Data Stream
74  * Type 2" byte giving the type of operation (NBIPX_FIND_NAME,
75  * NBIPX_NAME_RECOGNIZED, or NBIPX_CHECK_NAME - the latter is called
76  * "Add Name"), and a 16-byte NetBIOS name.
77  *
78  * It also says that "NetBIOS over IPX Broadcast packets" have a
79  * packet type of 0x14 (20, or IPX_PACKET_TYPE_WANBCAST) and a
80  * socket number of 0x455 (IPX_SOCKET_NETBIOS).
81  *
82  * However, there are also non-broadcast packets that *also* contain
83  * the 8 IPX network numbers; they appear to be replies to broadcast
84  * packets, and have a packet type of 0x4 (IPX_PACKET_TYPE_PEP).
85  *
86  * Other IPX_PACKET_TYPE_PEP packets to and from the IPX_SOCKET_NETBIOS
87  * socket, however, *don't* have the 8 IPX network numbers; there does
88  * not seem to be any obvious algorithm to determine whether the packet
89  * has the addresses or not.  Microsoft Knowledge Base article Q128335
90  * appears to show some code from the NBIPX implementation in NT that
91  * tries to determine the packet type - and it appears to use heuristics
92  * based on the packet length and on looking at what might be the NBIPX
93  * "Data Stream Type" byte depending on whether the packet has the 8
94  * IPX network numbers or not.
95  *
96  * So, for now, we treat *all* NBIPX packets as having a "Data Stream
97  * Type" byte, preceded by another byte of NBIPX information and
98  * followed by more NBIPX stuff, and assume that it's preceded by
99  * 8 IPX network numbers iff:
100  *
101  *      the packet is a WAN Broadcast packet
102  *
103  * or
104  *
105  *      the packet is the right size for one of those PEP name replies
106  *      (50 bytes) *and* has a name packet type as the Data Stream
107  *      Type byte at the offset where that byte would be if the packet
108  *      does have the 8 IPX network numbers at the beginning.
109  *
110  * The page at
111  *
112  *      http://ourworld.compuserve.com/homepages/TimothyDEvans/encap.htm
113  *
114  * indicates, under "NBIPX session packets", that "NBIPX session packets"
115  * have
116  *
117  *      1 byte of NBIPX connection control flag
118  *      1 byte of data stream type
119  *      2 bytes of source connection ID
120  *      2 bytes of destination connection ID
121  *      2 bytes of send sequence number
122  *      2 bytes of total data length
123  *      2 bytes of offset
124  *      2 bytes of data length
125  *      2 bytes of receive sequence number
126  *      2 bytes of "bytes received"
127  *
128  * followed by data.
129  *
130  * Packets with a data stream type of NBIPX_DIRECTED_DATAGRAM appear to
131  * have, following the data stream type, two NetBIOS names, the first
132  * of which is the receiver's NetBIOS name and the second of which is
133  * the sender's NetBIOS name.  The page at
134  *
135  *      http://support.microsoft.com/support/kb/articles/q203/0/51.asp
136  *
137  * speaks of type 4 (PEP) packets as being used for "SAP, NetBIOS sessions
138  * and directed datagrams" and type 20 (WAN Broadcast) as being used for
139  * "NetBIOS name resolution broadcasts" (but nothing about the non-broadcast
140  * type 4 name resolution stuff).
141  *
142  * We assume that this means that, once you get past the 8 IPX network
143  * numbers if present:
144  *
145  *      the first byte is a name type byte for the name packets
146  *      and a connection control flag for the other packets;
147  *
148  *      the second byte is a data stream type;
149  *
150  *      the rest of the bytes are:
151  *
152  *              the NetBIOS name being registered/deregistered/etc.,
153  *              for name packets;
154  *
155  *              the two NetBIOS names, followed by the NetBIOS
156  *              datagram, for NBIPX_DIRECTED_DATAGRAM packets;
157  *
158  *              the session packet header, possibly followed by
159  *              session data, for session packets.
160  *
161  * We don't know yet how to interpret NBIPX_STATUS_QUERY or
162  * NBIPX_STATUS_RESPONSE.
163  *
164  * For now, we treat the datagrams and session data as SMB stuff.
165  */
166 #define NBIPX_FIND_NAME         1
167 #define NBIPX_NAME_RECOGNIZED   2
168 #define NBIPX_CHECK_NAME        3
169 #define NBIPX_NAME_IN_USE       4
170 #define NBIPX_DEREGISTER_NAME   5
171 #define NBIPX_SESSION_DATA      6
172 #define NBIPX_SESSION_END       7
173 #define NBIPX_SESSION_END_ACK   8
174 #define NBIPX_STATUS_QUERY      9
175 #define NBIPX_STATUS_RESPONSE   10
176 #define NBIPX_DIRECTED_DATAGRAM 11
177
178 static const value_string nbipx_data_stream_type_vals[] = {
179         {NBIPX_FIND_NAME,               "Find name"},
180         {NBIPX_NAME_RECOGNIZED,         "Name recognized"},
181         {NBIPX_CHECK_NAME,              "Check name"},
182         {NBIPX_NAME_IN_USE,             "Name in use"},
183         {NBIPX_DEREGISTER_NAME,         "Deregister name"},
184         {NBIPX_SESSION_DATA,            "Session data"},
185         {NBIPX_SESSION_END,             "Session end"},
186         {NBIPX_SESSION_END_ACK,         "Session end ACK"},
187         {NBIPX_STATUS_QUERY,            "Status query"},
188         {NBIPX_STATUS_RESPONSE,         "Status response"},
189         {NBIPX_DIRECTED_DATAGRAM,       "Directed datagram"},
190         {0,                             NULL}
191 };
192
193 static void
194 add_routers(proto_tree *tree, tvbuff_t *tvb, int offset)
195 {
196         int             i;
197         int             rtr_offset;
198         guint32         router;
199
200         /* Eight routers are listed */
201         for (i = 0; i < 8; i++) {
202                 rtr_offset = offset + (i << 2);
203                 tvb_memcpy(tvb, (guint8 *)&router, rtr_offset, 4);
204                 if (router != 0) {
205                         proto_tree_add_text(tree, tvb, rtr_offset, 4,
206                             "IPX Network: %s",
207                             ipxnet_to_string((guint8*)&router));
208                 }
209         }
210 }
211
212 static void
213 dissect_nbipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
214 {
215         gboolean        has_routes;
216         proto_tree      *nbipx_tree = NULL;
217         proto_item      *ti = NULL;
218         int             offset = 0;
219         guint8          packet_type;
220         guint8          name_type_flag;
221         proto_tree      *name_type_flag_tree;
222         proto_item      *tf;
223         tvbuff_t        *next_tvb;
224         const guint8    *next_pd;
225         int             next_offset;
226         char            name[(NETBIOS_NAME_LEN - 1)*4 + 1];
227         int             name_type;
228         gboolean        has_payload;
229
230         if (check_col(pinfo->fd, COL_PROTOCOL))
231                 col_set_str(pinfo->fd, COL_PROTOCOL, "NBIPX");
232         if (check_col(pinfo->fd, COL_INFO))
233                 col_clear(pinfo->fd, COL_INFO);
234
235         if (pinfo->ipxptype == IPX_PACKET_TYPE_WANBCAST) {
236                 /*
237                  * This is a WAN Broadcast packet; we assume it will have
238                  * 8 IPX addresses at the beginning.
239                  */
240                 has_routes = TRUE;
241         } else {
242                 /*
243                  * This isn't a WAN Broadcast packet, but it still might
244                  * have the 8 addresses.
245                  *
246                  * If it's the right length for a name operation,
247                  * and, if we assume it has routes, the packet type
248                  * is a name operation, assume it has routes.
249                  *
250                  * NOTE: this will throw an exception if the byte that
251                  * would be the packet type byte if this has the 8
252                  * addresses isn't present; if that's the case, we don't
253                  * know how to interpret this packet, so we can't dissect
254                  * it anyway.
255                  */
256                 has_routes = FALSE;     /* start out assuming it doesn't */
257                 if (tvb_reported_length(tvb) == 50) {
258                         packet_type = tvb_get_guint8(tvb, offset + 32 + 1);
259                         switch (packet_type) {
260
261                         case NBIPX_FIND_NAME:
262                         case NBIPX_NAME_RECOGNIZED:
263                         case NBIPX_CHECK_NAME:
264                         case NBIPX_NAME_IN_USE:
265                         case NBIPX_DEREGISTER_NAME:
266                                 has_routes = TRUE;
267                                 break;
268                         }
269                 }
270         }
271
272         if (tree) {
273                 ti = proto_tree_add_item(tree, proto_nbipx, tvb, 0,
274                     0, FALSE);
275                 nbipx_tree = proto_item_add_subtree(ti, ett_nbipx);
276         }
277
278         if (has_routes) {
279                 if (tree)
280                         add_routers(nbipx_tree, tvb, 0);
281                 offset += 32;
282         }
283
284         packet_type = tvb_get_guint8(tvb, offset + 1);
285
286         switch (packet_type) {
287
288         case NBIPX_FIND_NAME:
289         case NBIPX_NAME_RECOGNIZED:
290         case NBIPX_CHECK_NAME:
291         case NBIPX_NAME_IN_USE:
292         case NBIPX_DEREGISTER_NAME:
293                 name_type_flag = tvb_get_guint8(tvb, offset);
294                 name_type = get_netbios_name(tvb, offset+2, name);
295                 if (check_col(pinfo->fd, COL_INFO)) {
296                         col_add_fstr(pinfo->fd, COL_INFO, "%s %s<%02x>",
297                                 val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown"),
298                                 name, name_type);
299                 }
300                 if (nbipx_tree) {
301                         tf = proto_tree_add_text(nbipx_tree, tvb, offset, 1,
302                                 "Name type flag: 0x%02x", name_type_flag);
303                         name_type_flag_tree = proto_item_add_subtree(tf,
304                                         ett_nbipx_name_type_flags);
305                         proto_tree_add_text(name_type_flag_tree, tvb, offset,
306                             1, "%s",
307                             decode_boolean_bitfield(name_type_flag, 0x80, 8,
308                               "Group name", "Unique name"));
309                         proto_tree_add_text(name_type_flag_tree, tvb, offset,
310                             1, "%s",
311                             decode_boolean_bitfield(name_type_flag, 0x40, 8,
312                               "Name in use", "Name not used"));
313                         proto_tree_add_text(name_type_flag_tree, tvb, offset,
314                             1, "%s",
315                             decode_boolean_bitfield(name_type_flag, 0x04, 8,
316                               "Name registered", "Name not registered"));
317                         proto_tree_add_text(name_type_flag_tree, tvb, offset,
318                             1, "%s",
319                             decode_boolean_bitfield(name_type_flag, 0x02, 8,
320                               "Name duplicated", "Name not duplicated"));
321                         proto_tree_add_text(name_type_flag_tree, tvb, offset,
322                             1, "%s",
323                             decode_boolean_bitfield(name_type_flag, 0x01, 8,
324                               "Name deregistered", "Name not deregistered"));
325                 }
326                 offset += 1;
327
328                 dissect_packet_type(tvb, offset, packet_type, nbipx_tree);
329                 offset += 1;
330
331                 if (nbipx_tree)
332                         netbios_add_name("Name", tvb, offset, nbipx_tree);
333                 offset += NETBIOS_NAME_LEN;
334
335                 /*
336                  * No payload to be interpreted by another protocol.
337                  */
338                 has_payload = FALSE;
339                 break;
340
341         case NBIPX_SESSION_DATA:
342         case NBIPX_SESSION_END:
343         case NBIPX_SESSION_END_ACK:
344                 if (check_col(pinfo->fd, COL_INFO)) {
345                         col_add_fstr(pinfo->fd, COL_INFO, "%s",
346                                 val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown"));
347                 }
348                 dissect_conn_control(tvb, offset, nbipx_tree);
349                 offset += 1;
350
351                 dissect_packet_type(tvb, offset, packet_type, nbipx_tree);
352                 offset += 1;
353
354                 if (nbipx_tree) {
355                         proto_tree_add_text(nbipx_tree, tvb, offset, 2,
356                             "Source connection ID: 0x%04X",
357                             tvb_get_letohs(tvb, offset));
358                 }
359                 offset += 2;
360
361                 if (nbipx_tree) {
362                         proto_tree_add_text(nbipx_tree, tvb, offset, 2,
363                             "Destination connection ID: 0x%04X",
364                             tvb_get_letohs(tvb, offset));
365                 }
366                 offset += 2;
367
368                 if (nbipx_tree) {
369                         proto_tree_add_text(nbipx_tree, tvb, offset, 2,
370                             "Send sequence number: %u",
371                             tvb_get_letohs(tvb, offset));
372                 }
373                 offset += 2;
374
375                 if (nbipx_tree) {
376                         proto_tree_add_text(nbipx_tree, tvb, offset, 2,
377                             "Total data length: %u",
378                             tvb_get_letohs(tvb, offset));
379                 }
380                 offset += 2;
381
382                 if (nbipx_tree) {
383                         proto_tree_add_text(nbipx_tree, tvb, offset, 2,
384                             "Offset: %u",
385                             tvb_get_letohs(tvb, offset));
386                 }
387                 offset += 2;
388
389                 if (nbipx_tree) {
390                         proto_tree_add_text(nbipx_tree, tvb, offset, 2,
391                             "Data length: %u",
392                             tvb_get_letohs(tvb, offset));
393                 }
394                 offset += 2;
395
396                 if (nbipx_tree) {
397                         proto_tree_add_text(nbipx_tree, tvb, offset, 2,
398                             "Receive sequence number: %u",
399                             tvb_get_letohs(tvb, offset));
400                 }
401                 offset += 2;
402
403                 if (nbipx_tree) {
404                         proto_tree_add_text(nbipx_tree, tvb, offset, 2,
405                             "Bytes received: %u",
406                             tvb_get_letohs(tvb, offset));
407                 }
408                 offset += 2;
409
410                 /*
411                  * We may have payload to dissect.
412                  */
413                 has_payload = TRUE;
414                 break;
415
416         case NBIPX_DIRECTED_DATAGRAM:
417                 if (check_col(pinfo->fd, COL_INFO)) {
418                         col_add_fstr(pinfo->fd, COL_INFO, "%s",
419                                 val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown"));
420                 }
421                 dissect_conn_control(tvb, offset, nbipx_tree);
422                 offset += 1;
423
424                 dissect_packet_type(tvb, offset, packet_type, nbipx_tree);
425                 offset += 1;
426
427                 if (nbipx_tree)
428                         netbios_add_name("Receiver's Name", tvb, offset,
429                             nbipx_tree);
430                 offset += NETBIOS_NAME_LEN;
431
432                 if (nbipx_tree)
433                         netbios_add_name("Sender's Name", tvb, offset,
434                             nbipx_tree);
435                 offset += NETBIOS_NAME_LEN;
436
437                 /*
438                  * We may have payload to dissect.
439                  */
440                 has_payload = TRUE;
441                 break;
442
443         default:
444                 if (check_col(pinfo->fd, COL_INFO)) {
445                         col_add_fstr(pinfo->fd, COL_INFO, "%s",
446                                 val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown"));
447                 }
448
449                 /*
450                  * We don't know what the first byte is.
451                  */
452                 offset += 1;
453
454                 /*
455                  * The second byte is a data stream type byte.
456                  */
457                 dissect_packet_type(tvb, offset, packet_type, nbipx_tree);
458                 offset += 1;
459
460                 /*
461                  * We don't know what the rest of the packet is.
462                  */
463                 has_payload = FALSE;
464         }
465
466         /*
467          * Set the length of the NBIPX tree item.
468          */
469         if (ti != NULL)
470                 proto_item_set_len(ti, offset);
471
472         if (has_payload && tvb_offset_exists(tvb, offset)) {
473                 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
474                 tvb_compat(next_tvb, &next_pd, &next_offset);
475                 dissect_smb(next_pd, next_offset, pinfo->fd, tree,
476                     tvb_length(next_tvb));
477         }
478 }
479
480 static void
481 dissect_conn_control(tvbuff_t *tvb, int offset, proto_tree *tree)
482 {
483         guint8          conn_control;
484         proto_item      *ti;
485         proto_tree      *cc_tree;
486
487         if (tree) {
488                 conn_control = tvb_get_guint8(tvb, offset);
489                 ti = proto_tree_add_text(tree, tvb, offset, 1,
490                     "Connection control: 0x%02x", conn_control);
491                 cc_tree = proto_item_add_subtree(ti, ett_nbipx_conn_ctrl);
492                 proto_tree_add_text(cc_tree, tvb, offset, 1, "%s",
493                       decode_boolean_bitfield(conn_control, 0x80, 8,
494                               "System packet", "Non-system packet"));
495                 proto_tree_add_text(cc_tree, tvb, offset, 1, "%s",
496                       decode_boolean_bitfield(conn_control, 0x40, 8,
497                               "Acknowledgement required",
498                               "Acknowledgement not required"));
499                 proto_tree_add_text(cc_tree, tvb, offset, 1, "%s",
500                       decode_boolean_bitfield(conn_control, 0x20, 8,
501                               "Attention", "No attention"));
502                 proto_tree_add_text(cc_tree, tvb, offset, 1, "%s",
503                       decode_boolean_bitfield(conn_control, 0x10, 8,
504                               "End of message", "No end of message"));
505                 proto_tree_add_text(cc_tree, tvb, offset, 1, "%s",
506                       decode_boolean_bitfield(conn_control, 0x08, 8,
507                               "Resend", "No resend"));
508         }
509 }
510
511 static void
512 dissect_packet_type(tvbuff_t *tvb, int offset, guint8 packet_type,
513     proto_tree *tree)
514 {
515         if (tree) {
516                 proto_tree_add_text(tree, tvb, offset, 1,
517                                 "Packet Type: %s (%02X)",
518                                 val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown"),
519                                 packet_type);
520         }
521 }
522
523 void
524 proto_register_nbipx(void)
525 {
526 /*        static hf_register_info hf[] = {
527                 { &variable,
528                 { "Name",           "nbipx.abbreviation", TYPE, VALS_POINTER }},
529         };*/
530         static gint *ett[] = {
531                 &ett_nbipx,
532                 &ett_nbipx_conn_ctrl,
533                 &ett_nbipx_name_type_flags,
534         };
535
536         proto_nbipx = proto_register_protocol("NetBIOS over IPX",
537             "NBIPX", "nbipx");
538  /*       proto_register_field_array(proto_nbipx, hf, array_length(hf));*/
539         proto_register_subtree_array(ett, array_length(ett));
540 }
541
542 void
543 proto_reg_handoff_nbipx(void)
544 {
545         dissector_add("ipx.socket", IPX_SOCKET_NETBIOS, dissect_nbipx,
546             proto_nbipx);
547 }
548
549 /*
550  * Microsoft appear to have something they call "direct hosting", where
551  * SMB - and, I infer, related stuff, such as name resolution - runs
552  * directly over IPX.  (In Windows 2000, they also run SMB directly over
553  * TCP, on port 445, and that also appears to be called "direct hosting".
554  * Ethereal handles SMB-over-TCP.)
555  *
556  * The document at
557  *
558  *      http://support.microsoft.com/support/kb/articles/q203/0/51.asp
559  *
560  * speaks of NMPI - the "Name Management Protocol on IPX" - as being
561  * "Microsoft's protocol for name management support when you use IPX
562  * without the NetBIOS interface," and says that "This process of routing
563  * the SMB protocol directly through IPX is known as Direct Hosting."
564  *
565  * It speaks of IPX socket 0x551 as being for NMPI; we define it as
566  * IPX_SOCKET_NWLINK_SMB_NAMEQUERY.
567  *
568  * We also define IPX_SOCKET_NWLINK_SMB_DGRAM as 0x0553 and define
569  * IPX_SOCKET_NWLINK_SMB_BROWSE as 0x0555 (with a "? not sure on this"
570  * comment after the latter one).
571  *
572  * We have seen at least some browser announcements on IPX socket 0x553;
573  * those are WAN broadcast packets, complete with 8 IPX network
574  * numbers, and with the header containing the usual two NetBIOS names
575  * that show up in NetBIOS datagrams.
576  *
577  * Network Monitor calls those packets NMPI packets, even though they're
578  * on socket 0x553, not socket 0x551, and contain SMB datagrams, not name
579  * resolution packets.
580  *
581  * At least some of this is discussed in the "SMBPUB.DOC" Word document
582  * stored in
583  *
584  *      ftp://ftp.microsoft.com/developr/drg/CIFS/smbpub.zip
585  *
586  * which can also be found in text form at
587  *
588  *      http://www.samba.org/samba/ftp/specs/smbpub.txt
589  *
590  * which says that for "connectionless IPX transport" the sockets that
591  * are used are:
592  *
593  *      SMB_SERVER_SOCKET (0x550) - SMB requests from clients
594  *      SMB_NAME_SOCKET (0x551) - name claims and name query messages
595  *      REDIR_SOCKET (0x552) - used by the redirector (client) for
596  *              sending SMB requests and receiving SMB replies
597  *      MAILSLOT_SOCKET (0x553) - used by the redirector and browser
598  *              for mailslot datagrams
599  *      MESSENGER_SOCKET (0x554) - used by the redirector to send
600  *              messages from client to client          
601  *
602  * Name claim/query packets, and mailslot datagrams, are:
603  *
604  *      8 IPX network addresses
605  *      1 byte of opcode
606  *      1 byte of name type
607  *      2 bytes of message ID
608  *      16 bytes of name being sought or claimed
609  *      16 bytes of requesting machine
610  *
611  * The opcode is one of:
612  *
613  *      INAME_CLAIM (0xf1) - server name claim message
614  *      INAME_DELETE (0xf2) - relinquish server name
615  *      INAME_QUERY (0xf3) - locate server name
616  *      INAME_FOUND (0xf4) - response to INAME_QUERY
617  *      IMSG_HANGUP (0xf5) - messenger hangup
618  *      IMSLOT_SEND (0xfc) - mailslot write
619  *      IMSLOT_FIND (0xfd) - find name for mailslot write
620  *      IMSLOT_NAME (0xfe) - response to IMSLOT_FIND
621  *
622  * The name type is one of:
623  *
624  *      INTYPE_MACHINE  1
625  *      INTYPE_WKGROUP  2
626  *      INTYPE_BROWSER  3
627  */
628 static int proto_nmpi = -1;
629
630 static gint ett_nmpi = -1;
631 static gint ett_nmpi_name_type_flags = -1;
632
633 /*
634  * Opcodes.
635  */
636 #define INAME_CLAIM     0xf1
637 #define INAME_DELETE    0xf2
638 #define INAME_QUERY     0xf3
639 #define INAME_FOUND     0xf4
640 #define IMSG_HANGUP     0xf5
641 #define IMSLOT_SEND     0xfc
642 #define IMSLOT_FIND     0xfd
643 #define IMSLOT_NAME     0xfe
644
645 static const value_string nmpi_opcode_vals[] = {
646         {INAME_CLAIM,   "Claim name"},
647         {INAME_DELETE,  "Delete name"},
648         {INAME_QUERY,   "Query name"},
649         {INAME_FOUND,   "Name found"},
650         {IMSG_HANGUP,   "Messenger hangup"},
651         {IMSLOT_SEND,   "Mailslot write"},
652         {IMSLOT_FIND,   "Find mailslot name"},
653         {IMSLOT_NAME,   "Mailslot name found"},
654         {0,             NULL}
655 };
656
657 /*
658  * Name types.
659  */
660 #define INTYPE_MACHINE          1
661 #define INTYPE_WORKGROUP        2
662 #define INTYPE_BROWSER          3
663
664 static const value_string nmpi_name_type_vals[] = {
665         {INTYPE_MACHINE,        "Machine"},
666         {INTYPE_WORKGROUP,      "Workgroup"},
667         {INTYPE_BROWSER,        "Browser"},
668         {0,                     NULL}
669 };
670
671 static void
672 dissect_nmpi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
673 {
674         proto_tree      *nmpi_tree = NULL;
675         proto_item      *ti;
676         int             offset = 0;
677         guint8          opcode;
678         guint8          nmpi_name_type;
679         char            name[(NETBIOS_NAME_LEN - 1)*4 + 1];
680         int             name_type;
681         char            node_name[(NETBIOS_NAME_LEN - 1)*4 + 1];
682         int             node_name_type = 0;
683         tvbuff_t        *next_tvb;
684         const guint8    *next_pd;
685         int             next_offset;
686
687         if (check_col(pinfo->fd, COL_PROTOCOL))
688                 col_set_str(pinfo->fd, COL_PROTOCOL, "NMPI");
689         if (check_col(pinfo->fd, COL_INFO))
690                 col_clear(pinfo->fd, COL_INFO);
691
692         if (tree) {
693                 ti = proto_tree_add_item(tree, proto_nmpi, tvb, offset, 68,
694                     FALSE);
695                 nmpi_tree = proto_item_add_subtree(ti, ett_nmpi);
696
697                 add_routers(nmpi_tree, tvb, offset);
698         }
699         offset += 32;
700
701         /*
702          * XXX - we don't use "node_name" or "node_name_type".
703          */
704         opcode = tvb_get_guint8(tvb, offset);
705         nmpi_name_type = tvb_get_guint8(tvb, offset+1);
706         name_type = get_netbios_name(tvb, offset+4, name);
707         node_name_type = get_netbios_name(tvb, offset+20, node_name);
708
709         if (check_col(pinfo->fd, COL_INFO)) {
710                 switch (opcode) {
711
712                 case INAME_CLAIM:
713                         col_add_fstr(pinfo->fd, COL_INFO, "Claim name %s<%02x>",
714                                         name, name_type);
715                         break;
716
717                 case INAME_DELETE:
718                         col_add_fstr(pinfo->fd, COL_INFO, "Delete name %s<%02x>",
719                                         name, name_type);
720                         break;
721
722                 case INAME_QUERY:
723                         col_add_fstr(pinfo->fd, COL_INFO, "Query name %s<%02x>",
724                                         name, name_type);
725                         break;
726
727                 case INAME_FOUND:
728                         col_add_fstr(pinfo->fd, COL_INFO, "Name %s<%02x> found",
729                                         name, name_type);
730                         break;
731
732                 case IMSG_HANGUP:
733                         col_add_fstr(pinfo->fd, COL_INFO,
734                             "Messenger hangup on %s<%02x>", name, name_type);
735                         break;
736
737                 case IMSLOT_SEND:
738                         col_add_fstr(pinfo->fd, COL_INFO,
739                             "Mailslot write to %s<%02x>", name, name_type);
740                         break;
741
742                 case IMSLOT_FIND:
743                         col_add_fstr(pinfo->fd, COL_INFO,
744                             "Find mailslot name %s<%02x>", name, name_type);
745                         break;
746
747                 case IMSLOT_NAME:
748                         col_add_fstr(pinfo->fd, COL_INFO,
749                             "Mailslot name %s<%02x> found", name, name_type);
750                         break;
751
752                 default:
753                         col_add_fstr(pinfo->fd, COL_INFO,
754                             "Unknown NMPI op 0x%02x: name %s<%02x>",
755                             opcode, name, name_type);
756                         break;
757                 }
758         }
759
760         if (tree) {
761                 proto_tree_add_text(nmpi_tree, tvb, offset, 1,
762                     "Opcode: %s (0x%02x)",
763                     val_to_str(opcode, nmpi_opcode_vals, "Unknown"),
764                     opcode);
765                 proto_tree_add_text(nmpi_tree, tvb, offset+1, 1,
766                     "Name Type: %s (0x%02x)",
767                     val_to_str(nmpi_name_type, nmpi_name_type_vals, "Unknown"),
768                     nmpi_name_type);
769                 proto_tree_add_text(nmpi_tree, tvb, offset+2, 2,
770                     "Message ID: 0x%04x",
771                     tvb_get_letohs(tvb, offset+2));
772                 netbios_add_name("Requested name", tvb, offset+4, nmpi_tree);
773                 netbios_add_name("Source name", tvb, offset+20, nmpi_tree);
774         }
775
776         offset += 1 + 1 + 2 + NETBIOS_NAME_LEN + NETBIOS_NAME_LEN;
777
778         if (opcode == IMSLOT_SEND && tvb_offset_exists(tvb, offset)) {
779                 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
780                 tvb_compat(next_tvb, &next_pd, &next_offset);
781                 dissect_smb(next_pd, next_offset, pinfo->fd, tree,
782                     tvb_length(next_tvb));
783         }
784 }
785
786 void
787 proto_register_nmpi(void)
788 {
789 /*        static hf_register_info hf[] = {
790                 { &variable,
791                 { "Name",           "nmpi.abbreviation", TYPE, VALS_POINTER }},
792         };*/
793         static gint *ett[] = {
794                 &ett_nmpi,
795                 &ett_nmpi_name_type_flags,
796         };
797
798         proto_nmpi = proto_register_protocol("Name Management Protocol over IPX",
799             "NMPI", "nmpi");
800  /*       proto_register_field_array(proto_nmpi, hf, array_length(hf));*/
801         proto_register_subtree_array(ett, array_length(ett));
802 }
803
804 void
805 proto_reg_handoff_nmpi(void)
806 {
807         dissector_add("ipx.socket", IPX_SOCKET_NWLINK_SMB_NAMEQUERY,
808             dissect_nmpi, proto_nmpi);
809         dissector_add("ipx.socket", IPX_SOCKET_NWLINK_SMB_MAILSLOT,
810             dissect_nmpi, proto_nmpi);
811 }