Fix some "proto_tree_add_text()" calls.
[obnox/wireshark/wip.git] / packet-netbios.c
1 /* packet-netbios.c
2  * Routines for NetBIOS protocol packet disassembly
3  * Jeff Foster <foste@woodward.com>            
4  * Copyright 1999 Jeffrey C. Foster
5  * 
6  * derived from the packet-nbns.c
7  *
8  * $Id: packet-netbios.c,v 1.17 2000/03/07 05:20:54 guy Exp $
9  *
10  * Ethereal - Network traffic analyzer
11  * By Gerald Combs <gerald@zing.org>
12  * Copyright 1998 Gerald Combs
13  *
14  * 
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  * 
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  * 
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
36 #endif
37
38 #include <stdio.h>
39 #include <string.h>
40 #include <glib.h>
41
42 #include "packet.h"
43 #include "packet-netbios.h"
44 #include "packet-smb.h"
45
46 /* Netbios command numbers */
47 #define NB_ADD_GROUP            0x00
48 #define NB_ADD_NAME             0x01
49 #define NB_NAME_IN_CONFLICT     0x02
50 #define NB_STATUS_QUERY         0x03
51 #define NB_TERMINATE_TRACE_R    0x07
52 #define NB_DATAGRAM             0x08
53 #define NB_DATAGRAM_BCAST       0x09
54 #define NB_NAME_QUERY           0x0a
55 #define NB_ADD_NAME_RESP        0x0d
56 #define NB_NAME_RESP            0x0e
57 #define NB_STATUS_RESP          0x0f
58 #define NB_TERMINATE_TRACE_LR   0x13
59 #define NB_DATA_ACK             0x14
60 #define NB_DATA_FIRST_MIDDLE    0x15
61 #define NB_DATA_ONLY_LAST       0x16
62 #define NB_SESSION_CONFIRM      0x17
63 #define NB_SESSION_END          0x18
64 #define NB_SESSION_INIT         0x19
65 #define NB_NO_RECEIVE           0x1a
66 #define NB_RECEIVE_OUTSTANDING  0x1b
67 #define NB_RECEIVE_CONTINUE     0x1c
68 #define NB_KEEP_ALIVE           0x1f
69
70 /* Offsets of fields in the NetBIOS header. */
71 #define NB_LENGTH               0
72 #define NB_DELIMITER            2
73 #define NB_COMMAND              4
74 #define NB_FLAGS                5
75 #define NB_DATA1                5
76 #define NB_RESYNC               6
77 #define NB_DATA2                6
78 #define NB_CALL_NAME_TYPE       7
79 #define NB_XMIT_CORL            8
80 #define NB_RESP_CORL            10
81 #define NB_RMT_SES              12
82 #define NB_LOCAL_SES            13
83 #define NB_RECVER_NAME          12
84 #define NB_SENDER_NAME          28
85
86 static int proto_netbios = -1;
87
88 static gint ett_netb = -1;
89 static gint ett_netb_name = -1;
90 static gint ett_netb_flags = -1;
91 static gint ett_netb_status = -1;
92
93 /* The strings for the station type, used by get_netbios_name function;
94    many of them came from the file "NetBIOS.txt" in the Zip archive at
95
96         http://www.net3group.com/ftp/browser.zip
97  */
98
99 static const value_string name_type_vals[] = {
100         {0x00,  "Workstation/Redirector"},
101         {0x01,  "Browser"},
102         {0x02,  "Workstation/Redirector"}, 
103                 /* not sure what 0x02 is, I'm seeing alot of them however */
104                 /* i'm seeing them with workstation/redirection host 
105                         announcements */
106         {0x03,  "Messenger service/Main name"},
107         {0x05,  "Forwarded name"},
108         {0x06,  "RAS Server service"},
109         {0x1b,  "Domain Master Browser"},
110         {0x1c,  "Domain Controllers"},
111         {0x1d,  "Local Master Browser"},
112         {0x1e,  "Browser Election Service"},
113         {0x1f,  "Net DDE Service"},
114         {0x20,  "Server service"},
115         {0x21,  "RAS client service"},
116         {0x22,  "Exchange Interchange (MSMail Connector)"},
117         {0x23,  "Exchange Store"},
118         {0x24,  "Exchange Directory"},
119         {0x2b,  "Lotus Notes Server service"},
120         {0x30,  "Modem sharing server service"},
121         {0x31,  "Modem sharing client service"},
122         {0x43,  "SMS Clients Remote Control"},
123         {0x44,  "SMS Administrators Remote Control Tool"},
124         {0x45,  "SMS Clients Remote Chat"},
125         {0x46,  "SMS Clients Remote Transfer"},
126         {0x4c,  "DEC Pathworks TCP/IP Service on Windows NT"},
127         {0x52,  "DEC Pathworks TCP/IP Service on Windows NT"},
128         {0x6a,  "Microsoft Exchange IMC"},
129         {0x87,  "Microsoft Exchange MTA"},
130         {0xbe,  "Network Monitor Agent"},
131         {0xbf,  "Network Monitor Analyzer"},
132         {0x00,  NULL}
133 };
134
135 /* See
136    
137         http://www.s390.ibm.com/bookmgr-cgi/bookmgr.cmd/BOOKS/BK8P7001/CCONTENTS
138
139    and
140
141         http://ourworld.compuserve.com/homepages/TimothyDEvans/contents.htm
142
143    for information about the NetBIOS Frame Protocol (which is what this
144    module dissects). */
145
146 /* the strings for the command types  */
147
148 static char *CommandName[] = {
149         "Add Group Name Query", /* 0x00 */
150         "Add Name Query",       /* 0x01 */
151         "Name In Conflict",     /* 0x02 */
152         "Status Query",         /* 0x03 */
153         "Unknown",
154         "Unknown",
155         "Unknown",
156         "Terminate Trace",      /* 0x07 */
157         "Datagram",             /* 0x08 */
158         "Broadcast Datagram",   /* 0x09 */
159         "Name Query",           /* 0x0A */
160         "Unknown",
161         "Unknown",
162         "Add Name Response",    /* 0x0D */
163         "Name Recognized",      /* 0x0E */
164         "Status Response",      /* 0x0F */
165         "Unknown",
166         "Unknown",
167         "Unknown",
168         "Terminate Trace",      /* 0x13 */
169         "Data Ack",             /* 0x14 */
170         "Data First Middle",    /* 0x15 */
171         "Data Only Last",       /* 0x16 */
172         "Session Confirm",      /* 0x17 */
173         "Session End",          /* 0x18 */
174         "Session Initialize",   /* 0x19 */
175         "No Receive",           /* 0x1a */
176         "Receive Outstanding",  /* 0x1b */
177         "Receive Continue",     /* 0x1c */
178         "Unknown",
179         "Unknown",
180         "Session Alive",        /* 0x1f */
181 };
182
183 void capture_netbios(const u_char *pd, int offset, packet_counts *ld)
184 {
185         ld->netbios++;
186 }
187
188
189 int
190 process_netbios_name(const u_char *name_ptr, char *name_ret)
191 {
192         int i;
193         int name_type = *(name_ptr + NETBIOS_NAME_LEN - 1);
194         u_char name_char;
195         static const char hex_digits[16] = "0123456789abcdef";
196
197         for (i = 0; i < NETBIOS_NAME_LEN - 1; i++) {
198                 name_char = *name_ptr++;
199                 if (name_char >= ' ' && name_char <= '~')
200                         *name_ret++ = name_char;
201                 else {
202                         /* It's not printable; show it as <XX>, where
203                            XX is the value in hex. */
204                         *name_ret++ = '<';
205                         *name_ret++ = hex_digits[(name_char >> 4)];
206                         *name_ret++ = hex_digits[(name_char & 0x0F)];
207                         *name_ret++ = '>';
208                 }
209         }
210         *name_ret = '\0';
211         return name_type;
212 }
213
214 int get_netbios_name(const u_char *pd, int offset, char *name_ret)
215
216 {/*  Extract the name string and name type.  Return the name string in  */
217  /* name_ret and return the name_type. */
218         if (!BYTES_ARE_IN_FRAME(offset, NETBIOS_NAME_LEN)) {
219                 /*
220                  * Name goes past end of captured data in packet.
221                  */
222                 return -1;
223         }
224         return process_netbios_name(&pd[offset], name_ret);
225 }
226
227 /*
228  * Get a string describing the type of a NetBIOS name.
229  */
230 char *
231 netbios_name_type_descr(int name_type)
232 {
233         return val_to_str(name_type, name_type_vals, "Unknown");
234 }
235
236 gboolean netbios_add_name(char* label, const u_char *pd, int offset,
237     proto_tree *tree)
238
239 {/* add a name field display tree. Display the name and station type in sub-tree */
240  
241         proto_tree *field_tree;
242         proto_item *tf;
243         char  name_str[(NETBIOS_NAME_LEN - 1)*4 + 1];
244         int   name_type;
245         char  *name_type_str;
246
247                                         /* decode the name field */
248         name_type = get_netbios_name(pd, offset, name_str);
249         if (name_type < 0) {
250                 /*
251                  * Name goes past end of captured data in packet.
252                  */
253                 return FALSE;
254         }
255
256         name_type_str = netbios_name_type_descr(name_type);
257         tf = proto_tree_add_text( tree, offset, NETBIOS_NAME_LEN,
258                 "%s: %s<%02x> (%s)", label, name_str, name_type, name_type_str);
259
260         field_tree = proto_item_add_subtree( tf, ett_netb_name);
261         
262         proto_tree_add_text( field_tree, offset, 15, "%s",
263             name_str);
264         proto_tree_add_text( field_tree, offset + 15, 1,
265             "0x%02x (%s)", name_type, name_type_str);
266         return TRUE;
267 }
268
269
270 static void netbios_data_first_middle_flags(const u_char *pd, proto_tree *tree,
271     int offset)
272
273 {
274         proto_tree *field_tree;
275         proto_item *tf;
276         guint flags = pd[offset];
277                 /* decode the flag field for Data First Middle packet*/
278
279         tf = proto_tree_add_text(tree, offset, 1,
280                         "Flags: 0x%02x", flags);
281         field_tree = proto_item_add_subtree(tf, ett_netb_flags);
282
283         proto_tree_add_text(field_tree, offset, 1, "%s",
284             decode_boolean_bitfield(flags, 0x08, 8,
285                 "Acknowledge_included", "No Acknowledge_included"));
286
287         proto_tree_add_text(field_tree, offset, 1, "%s",
288             decode_boolean_bitfield(flags, 0x02, 8,
289                 "No acknowledgement expected", "Acknowledgement expected"));
290
291         proto_tree_add_text(field_tree, offset, 1, "%s",
292             decode_boolean_bitfield(flags, 0x01, 8,
293                 "RECEIVE_CONTINUE requested", "RECEIVE_CONTINUE not requested"));
294 }
295
296
297 static void netbios_data_only_flags(const u_char *pd, proto_tree *tree,
298     int offset)
299 {
300         proto_tree *field_tree;
301         proto_item *tf;
302         guint flags = pd[offset];
303                 /* decode the flag field for Data Only Last packet*/
304
305         tf = proto_tree_add_text(tree, offset, 1,
306                         "Flags: 0x%02x", flags);
307         field_tree = proto_item_add_subtree(tf, ett_netb_flags);
308
309         proto_tree_add_text(field_tree, offset, 1, "%s",
310             decode_boolean_bitfield(flags, 0x08, 8,
311                 "ACKNOWLEDGE_INCLUDED", "No ACKNOWLEDGE_INCLUDED"));
312
313         proto_tree_add_text(field_tree, offset, 1, "%s",
314             decode_boolean_bitfield(flags, 0x04, 8,
315                 "ACKNOWLEDGE_WITH_DATA_ALLOWED", "No ACKNOWLEDGE_WITH_DATA_ALLOWED"));
316
317         proto_tree_add_text(field_tree, offset, 1, "%s",
318             decode_boolean_bitfield(flags, 0x02, 8,
319                 "No acknowledgement expected", "Acknowledgement expected"));
320 }
321
322
323 static void netbios_add_ses_confirm_flags(const u_char *pd, proto_tree *tree,
324         int offset)
325 {
326         proto_tree *field_tree;
327         proto_item *tf;
328         guint flags = pd[offset];
329                 /* decode the flag field for Session Confirm packet */
330
331         tf = proto_tree_add_text(tree, offset, 1,
332                         "Flags: 0x%02x", flags);
333         field_tree = proto_item_add_subtree( tf, ett_netb_flags);
334
335         proto_tree_add_text(field_tree, offset, 1, "%s",
336             decode_boolean_bitfield(flags, 0x80, 8,
337                 "Can handle SEND.NO.ACK", "Can't handle SEND.NO.ACK"));
338
339         proto_tree_add_text(field_tree, offset, 1, "%s",
340             decode_boolean_bitfield(flags, 0x01, 8,
341                 "NetBIOS 2.00 or higher", "NetBIOS 1.xx"));
342 }
343
344
345 static void netbios_add_session_init_flags(const u_char *pd, proto_tree *tree,
346         int offset)
347 {
348         proto_tree *field_tree;
349         proto_item *tf;
350         guint flags = pd[offset];
351                 /* decode the flag field for Session Init packet */
352
353         tf = proto_tree_add_text(tree, offset, 1,
354                         "Flags: 0x%02x", flags);
355         field_tree = proto_item_add_subtree(tf, ett_netb_flags);
356
357         proto_tree_add_text(field_tree, offset, 1, "%s",
358             decode_boolean_bitfield(flags, 0x80, 8,
359                 "Can handle SEND.NO.ACK", "Can't handle SEND.NO.ACK"));
360
361         proto_tree_add_text(field_tree, offset, 1, "%s",
362             decode_numeric_bitfield(flags, 0x0E, 8,
363                 "Largest frame value = %u"));
364
365         proto_tree_add_text(field_tree, offset, 1, "%s",
366             decode_boolean_bitfield(flags, 0x01, 8,
367                 "NetBIOS 2.00 or higher", "NetBIOS 1.xx"));
368 }
369
370
371 static void netbios_no_receive_flags(const u_char *pd, proto_tree *tree,
372     int offset)
373
374 {
375         proto_tree *field_tree;
376         proto_item *tf;
377         guint flags = pd[offset];
378                 /* decode the flag field for No Receive packet*/
379
380         tf = proto_tree_add_text(tree, offset, 1,
381                         "Flags: 0x%02x", flags);
382
383         if (flags & 0x02) {
384                 field_tree = proto_item_add_subtree(tf, ett_netb_flags);
385                 proto_tree_add_text(field_tree, offset, 1, "%s",
386                     decode_boolean_bitfield(flags, 0x02, 8,
387                         "SEND.NO.ACK data not received", NULL));
388         }
389 }
390
391
392 /************************************************************************/
393 /*                                                                      */
394 /*  The routines to display the netbios field values in the tree        */
395 /*                                                                      */
396 /************************************************************************/
397
398
399 static void nb_xmit_corrl(const u_char *pd, int offset, proto_tree *tree)
400
401 {/* display the transmit correlator */
402
403         proto_tree_add_text( tree, offset + NB_XMIT_CORL, 2,
404             "Transmit Correlator: 0x%04x", pletohs(&pd[offset + NB_XMIT_CORL]));
405 }
406
407
408 static void nb_resp_corrl(const u_char *pd, int offset, proto_tree *tree)
409
410 {/* display the response correlator */
411
412         proto_tree_add_text( tree, offset + NB_RESP_CORL, 2,
413             "Response Correlator: 0x%04x", pletohs(&pd[offset + NB_RESP_CORL]));
414 }
415
416
417 static void nb_call_name_type(const u_char *pd, int offset,
418     proto_tree *tree)
419
420 {/* display the call name type */
421
422         int name_type_value = pd[offset + NB_CALL_NAME_TYPE];
423         
424         switch (name_type_value) {
425
426         case 0x00:
427                 proto_tree_add_text( tree, offset + NB_CALL_NAME_TYPE, 1,
428                     "Caller's Name Type: Unique name");
429                 break;
430
431         case 0x01:
432                 proto_tree_add_text( tree, offset + NB_CALL_NAME_TYPE, 1,
433                     "Caller's Name Type: Group name");
434                 break;
435
436         default:
437                 proto_tree_add_text( tree, offset + NB_CALL_NAME_TYPE, 1,
438                     "Caller's Name Type: 0x%02x (should be 0 or 1)",
439                     name_type_value);
440                 break;
441         }
442 }
443
444
445 static void nb_local_session(const u_char *pd, int offset,
446     proto_tree *tree)
447
448 {/* add the local session to tree */
449                         
450         proto_tree_add_text(tree, offset + NB_LOCAL_SES, 1,
451             "Local Session No.: 0x%02x", pd[offset + NB_LOCAL_SES]);
452 }
453
454
455 static void nb_remote_session(const u_char *pd, int offset,
456     proto_tree *tree)
457
458 {/* add the remote session to tree */
459                         
460         proto_tree_add_text(tree, offset + NB_RMT_SES, 1,
461             "Remote Session No.: 0x%02x", pd[offset + NB_RMT_SES]);
462 }
463
464
465 static void nb_data2(char *label, int len, const u_char *pd, int offset,
466     proto_tree *tree)
467
468 {/* add the DATA2 to tree with format string = label and length of len */
469
470         int value = (len == 1 ? pd[offset + NB_DATA2]
471                         : pletohs(&pd[offset + NB_DATA2]));
472         
473         proto_tree_add_text(tree, offset + NB_DATA2, len, label, value);
474 }
475
476 static void nb_resync_indicator(const u_char *pd, int offset,
477     proto_tree *tree)
478 {
479         guint16 resync_indicator = pletohs(&pd[offset + NB_DATA2]);
480
481         switch (resync_indicator) {
482
483         case 0x0000:
484                 proto_tree_add_text(tree, offset + NB_DATA2, 2,
485                     "Re-sync indicator: Not first Data First Middle following Receive Outstanding");
486                 break;
487
488         case 0x0001:
489                 proto_tree_add_text(tree, offset + NB_DATA2, 2,
490                     "Re-sync indicator: First Data First Middle following Receive Outstanding");
491                 break;
492
493         default:
494                 proto_tree_add_text(tree, offset + NB_DATA2, 2,
495                     "Re-sync indicator: 0x%04x", resync_indicator);
496                 break;
497         }
498 }
499
500 /************************************************************************/
501 /*                                                                      */
502 /*  The routines called by the top level to handle individual commands  */
503 /*                                                                      */
504 /************************************************************************/
505
506 static void  dissect_netb_unknown(const u_char *data_ptr, int offset,
507     frame_data *fd, proto_tree *tree)
508
509 {/* Handle any unknow commands, do nothing */
510
511 /*      dissect_data( data_ptr, offset + NB_COMMAND + 1, fd, tree); */
512 }
513
514
515 static void  dissect_netb_add_group_name(const u_char *pd, int offset,
516     frame_data *fd, proto_tree *tree)
517
518 {/* Handle the ADD GROUP NAME QUERY command */
519
520         nb_resp_corrl(pd, offset, tree); 
521
522         netbios_add_name("Group name to add", pd, offset + NB_SENDER_NAME,
523             tree);
524 }
525
526
527 static void  dissect_netb_add_name(const u_char *pd, int offset, 
528     frame_data *fd, proto_tree *tree)
529
530 {/* Handle the ADD NAME QUERY command */
531
532         nb_resp_corrl(pd, offset, tree); 
533
534         netbios_add_name("Name to add", pd, offset + NB_SENDER_NAME, tree);
535 }
536
537
538 static void  dissect_netb_name_in_conflict(const u_char *pd, int offset,
539     frame_data *fd, proto_tree *tree)
540
541 {/* Handle the NAME IN CONFLICT command */
542
543         if (!netbios_add_name("Name In Conflict", pd, offset + NB_RECVER_NAME,
544             tree))
545                 return;
546         netbios_add_name("Sender's Name", pd, offset + NB_SENDER_NAME,
547             tree);
548 }
549
550
551 static void  dissect_netb_status_query(const u_char *pd, int offset,
552     frame_data *fd, proto_tree *tree)
553
554 {/* Handle the STATUS QUERY command */
555         guint8 status_request = pd[offset + NB_DATA1];
556
557         switch (status_request) {
558
559         case 0:
560                 proto_tree_add_text(tree, offset + NB_DATA1, 1,
561                     "Status request: NetBIOS 1.x or 2.0");
562                 break;
563
564         case 1:
565                 proto_tree_add_text(tree, offset + NB_DATA1, 1,
566                     "Status request: NetBIOS 2.1, initial status request");
567                 break;
568
569         default:
570                 proto_tree_add_text(tree, offset + NB_DATA1, 1,
571                     "Status request: NetBIOS 2.1, %u names received so far",
572                     status_request);
573                 break;
574         }
575         nb_data2("Length of status buffer: %u", 2, pd, offset, tree);
576         nb_resp_corrl(pd, offset, tree); 
577         if (!netbios_add_name("Receiver's Name", pd, offset + NB_RECVER_NAME,
578             tree))
579                 return;
580         netbios_add_name("Sender's Name", pd, offset + NB_SENDER_NAME,
581             tree);
582 }
583
584
585 static u_char zeroes[10];
586
587 static void  dissect_netb_datagram(const u_char *pd, int offset,
588     frame_data *fd, proto_tree *tree)
589
590 {/* Handle the DATAGRAM command */
591
592         if (!netbios_add_name("Receiver's Name", pd, offset + NB_RECVER_NAME,
593             tree))
594                 return;
595         /* Weird.  In some datagrams, this is 10 octets of 0, followed
596            by a MAC address.... */
597         if (memcmp(&pd[offset + NB_SENDER_NAME], zeroes, 10) == 0) {
598                 proto_tree_add_text( tree, offset + NB_SENDER_NAME + 10, 6,
599                     "Sender's MAC Address: %s",
600                     ether_to_str(&pd[offset + NB_SENDER_NAME + 10]));
601         } else {
602                 netbios_add_name("Sender's Name", pd, offset + NB_SENDER_NAME,
603                     tree);
604         }
605 }
606
607
608 static void  dissect_netb_datagram_bcast(const u_char *pd, int offset,
609     frame_data *fd, proto_tree *tree)
610
611 {/* Handle the DATAGRAM BROADCAST command */
612
613         /* We assume the same weirdness can happen here.... */
614         if (memcmp(&pd[offset + NB_SENDER_NAME], zeroes, 10) == 0) {
615                 proto_tree_add_text( tree, offset + NB_SENDER_NAME + 10, 6,
616                     "Sender's Node Address: %s",
617                     ether_to_str(&pd[offset + NB_SENDER_NAME + 10]));
618         } else {
619                 netbios_add_name("Sender's Name", pd, offset + NB_SENDER_NAME,
620                     tree);
621         }
622 }
623
624
625 static void  dissect_netb_name_query(const u_char *pd, int offset,
626     frame_data *fd, proto_tree *tree)
627
628 {/* Handle the NAME QUERY command */
629         guint8 local_session_number = pd[offset + NB_DATA2];
630
631         if (local_session_number == 0) {
632                 proto_tree_add_text( tree, offset + NB_DATA2, 1,
633                     "Local Session No.: 0 (FIND.NAME request)");
634         } else {
635                 proto_tree_add_text( tree, offset + NB_DATA2, 1,
636                     "Local Session No.: 0x%02x", local_session_number);
637         }
638         nb_call_name_type(pd, offset, tree);
639         nb_resp_corrl(pd, offset, tree);
640         if (!netbios_add_name("Query Name", pd, offset + NB_RECVER_NAME, tree))
641                 return;
642         if (local_session_number != 0) {
643                 netbios_add_name("Sender's Name", pd, offset + NB_SENDER_NAME,
644                     tree);
645         }
646 }
647
648
649 static void  dissect_netb_add_name_resp(const u_char *pd, int offset,
650     frame_data *fd, proto_tree *tree)
651
652 {/* Handle the ADD NAME RESPONSE command */
653         guint8 status = pd[offset + NB_DATA1];
654         guint16 name_type = pletohs(&pd[offset + NB_DATA2]);
655
656         switch (status) {
657
658         case 0:
659                 proto_tree_add_text( tree, offset + NB_DATA1, 1,
660                     "Status: Add name not in process");
661                 break;
662
663         case 1:
664                 proto_tree_add_text( tree, offset + NB_DATA1, 1,
665                     "Status: Add name in process");
666                 break;
667
668         default:
669                 proto_tree_add_text( tree, offset + NB_DATA1, 1,
670                     "Status: 0x%02x (should be 0 or 1)", status);
671                 break;
672         }
673
674         switch (name_type) {
675
676         case 0:
677                 proto_tree_add_text( tree, offset + NB_DATA2, 2,
678                     "Name type: Unique name");
679                 break;
680
681         case 1:
682                 proto_tree_add_text( tree, offset + NB_DATA2, 2,
683                     "Name type: Group name");
684                 break;
685
686         default:
687                 proto_tree_add_text( tree, offset + NB_DATA2, 2,
688                     "Name type: 0x%04x (should be 0 or 1)", name_type);
689                 break;
690         }
691
692         nb_xmit_corrl(pd, offset, tree); 
693         if (!netbios_add_name("Name to be added", pd, offset + NB_RECVER_NAME,
694             tree))
695                 return;
696         netbios_add_name("Name to be added", pd, offset + NB_SENDER_NAME,
697             tree);
698 }
699
700
701 static void  dissect_netb_name_resp(const u_char *pd, int offset,
702     frame_data *fd, proto_tree *tree)
703
704 {/* Handle the NAME RECOGNIZED command */
705         guint8 local_session_number = pd[offset + NB_DATA2];
706
707         switch (local_session_number) {
708
709         case 0x00:
710                 proto_tree_add_text( tree, offset + NB_DATA2, 1,
711                     "State of name: No LISTEN pending, or FIND.NAME response");
712                 break;
713
714         case 0xFF:
715                 proto_tree_add_text( tree, offset + NB_DATA2, 1,
716                     "State of name: LISTEN pending, but insufficient resources to establish session");
717                 break;
718
719         default:
720                 proto_tree_add_text( tree, offset + NB_DATA2, 1,
721                     "Local Session No.: 0x%02x", local_session_number);
722                 break;
723         }
724         nb_call_name_type(pd, offset, tree);
725         nb_xmit_corrl(pd, offset, tree);
726         if (local_session_number != 0x00 && local_session_number != 0xFF)
727                 nb_resp_corrl(pd, offset, tree);
728         if (!netbios_add_name("Receiver's Name", pd, offset + NB_RECVER_NAME,
729             tree))
730                 return;
731         if (local_session_number != 0x00 && local_session_number != 0xFF) {
732                 netbios_add_name("Sender's Name", pd, offset + NB_SENDER_NAME,
733                     tree);
734         }
735 }
736
737
738 static void  dissect_netb_status_resp(const u_char *pd, int offset,
739     frame_data *fd, proto_tree *tree)
740
741 {/* Handle the STATUS RESPONSE command */
742         guint8 status_response = pd[offset + NB_DATA1];
743         proto_item *td2;
744         proto_tree *data2_tree;
745         guint16 data2;
746
747         nb_call_name_type(pd, offset, tree);
748         if (status_response == 0) {
749                 proto_tree_add_text(tree, offset + NB_DATA1, 1,
750                     "Status response: NetBIOS 1.x or 2.0");
751         } else {
752                 proto_tree_add_text(tree, offset + NB_DATA1, 1,
753                     "Status response: NetBIOS 2.1, %u names sent so far",
754                     status_response);
755         }
756         data2 = pletohs(&pd[offset + NB_DATA2]);
757         td2 = proto_tree_add_text(tree, offset + NB_DATA2, 2, "Status: 0x%04x",
758             data2);
759         data2_tree = proto_item_add_subtree(td2, ett_netb_status);
760         if (data2 & 0x8000) {
761                 proto_tree_add_text(data2_tree, offset, 2, "%s",
762                     decode_boolean_bitfield(data2, 0x8000, 8*2,
763                         "Data length exceeds maximum frame size", NULL));
764         }
765         if (data2 & 0x4000) {
766                 proto_tree_add_text(data2_tree, offset, 2, "%s",
767                     decode_boolean_bitfield(data2, 0x4000, 8*2,
768                         "Data length exceeds user's buffer", NULL));
769         }
770         proto_tree_add_text(data2_tree, offset, 2, "%s",
771             decode_numeric_bitfield(data2, 0x3FFF, 2*8,
772                         "Status data length = %u"));
773         nb_xmit_corrl(pd, offset, tree); 
774         if (!netbios_add_name("Receiver's Name", pd, offset + NB_RECVER_NAME,
775             tree))
776                 return;
777         netbios_add_name("Sender's Name", pd, offset + NB_SENDER_NAME,
778             tree);
779 }
780
781
782 static void  dissect_netb_data_ack(const u_char *pd, int offset,
783     frame_data *fd, proto_tree *tree)
784
785 {/* Handle the DATA ACK command */
786
787         nb_xmit_corrl(pd, offset, tree);
788         nb_remote_session(pd, offset, tree);
789         nb_local_session(pd, offset, tree);
790 }
791
792
793 static void  dissect_netb_data_first_middle(const u_char *pd, int offset,
794     frame_data *fd, proto_tree *tree)
795
796 {/* Handle the DATA FIRST MIDDLE command */
797
798         netbios_data_first_middle_flags(pd, tree, offset + NB_FLAGS);
799
800         nb_resync_indicator(pd, offset, tree);
801         nb_xmit_corrl(pd, offset, tree);
802         nb_resp_corrl(pd, offset, tree);
803         nb_remote_session(pd, offset, tree);
804         nb_local_session(pd, offset, tree);
805 }
806
807
808 static void  dissect_netb_data_only_last(const u_char *pd, int offset,
809     frame_data *fd, proto_tree *tree)
810
811 {/* Handle the DATA ONLY LAST command */
812
813         netbios_data_only_flags(pd, tree, offset + NB_FLAGS);
814
815         nb_resync_indicator(pd, offset, tree);
816         nb_xmit_corrl(pd, offset, tree);
817         nb_resp_corrl(pd, offset, tree);
818         nb_remote_session(pd, offset, tree);
819         nb_local_session(pd, offset, tree);
820 }
821
822
823 static void  dissect_netb_session_confirm(const u_char *pd, int offset,
824     frame_data *fd, proto_tree *tree)
825
826 {/* Handle the SESSION CONFIRM command */
827
828         netbios_add_ses_confirm_flags(pd, tree, offset + NB_FLAGS);
829
830         nb_data2("Max data recv size: %u", 2, pd, offset, tree);
831         nb_xmit_corrl(pd, offset, tree);
832         nb_resp_corrl(pd, offset, tree);
833         nb_remote_session(pd, offset, tree);
834         nb_local_session(pd, offset, tree);
835 }
836
837
838 static void  dissect_netb_session_end(const u_char *pd, int offset,
839     frame_data *fd, proto_tree *tree)
840
841 {/* Handle the SESSION END command */
842         guint16 termination_indicator = pletohs(&pd[offset + NB_DATA2]);
843
844         switch (termination_indicator) {
845
846         case 0x0000:
847                 proto_tree_add_text( tree, offset + NB_DATA2, 2,
848                     "Termination indicator: Normal session end");
849                 break;
850
851         case 0x0001:
852                 proto_tree_add_text( tree, offset + NB_DATA2, 2,
853                     "Termination indicator: Abormal session end");
854                 break;
855
856         default:
857                 proto_tree_add_text( tree, offset + NB_DATA2, 2,
858                     "Termination indicator: 0x%04x (should be 0x0000 or 0x0001)",
859                     termination_indicator);
860                 break;
861         }
862
863         nb_remote_session(pd, offset, tree);
864         nb_local_session(pd, offset, tree);
865 }
866
867
868 static void  dissect_netb_session_init(const u_char *pd, int offset,
869     frame_data *fd, proto_tree *tree)
870
871 {/* Handle the SESSION INITIALIZE command */
872
873         netbios_add_session_init_flags(pd, tree, offset + NB_FLAGS);
874
875         nb_data2("Max data recv size: %u", 2, pd, offset, tree);
876         nb_resp_corrl(pd, offset, tree);
877         nb_xmit_corrl(pd, offset, tree);
878         nb_remote_session(pd, offset, tree);
879         nb_local_session(pd, offset, tree);
880 }
881
882
883 static void  dissect_netb_no_receive(const u_char *pd, int offset,
884     frame_data *fd, proto_tree *tree)
885
886 {/* Handle the NO RECEIVE command */
887
888         netbios_no_receive_flags(pd, tree, offset + NB_FLAGS);
889
890         nb_data2("Number of data bytes accepted: %u", 2, pd, offset, tree);
891         nb_remote_session(pd, offset, tree);
892         nb_local_session(pd, offset, tree);
893 }
894
895
896 static void  dissect_netb_receive_outstanding(const u_char *pd, int offset,
897     frame_data *fd, proto_tree *tree)
898
899 {/* Handle the RECEIVE OUTSTANDING command */
900
901         nb_data2("Number of data bytes accepted: %u", 2, pd, offset, tree);
902         nb_remote_session(pd, offset, tree);
903         nb_local_session(pd, offset, tree);
904 }
905
906
907 static void  dissect_netb_receive_continue(const u_char *pd, int offset,
908     frame_data *fd, proto_tree *tree)
909
910 {/* Handle the RECEIVE CONTINUE command */
911
912         nb_xmit_corrl(pd, offset, tree);
913         nb_remote_session(pd, offset, tree);
914         nb_local_session(pd, offset, tree);
915 }
916
917
918 /************************************************************************/
919 /*                                                                      */
920 /*  The table routines called by the top level to handle commands       */
921 /*                                                                      */
922 /************************************************************************/
923
924
925 void (*dissect_netb[])(const u_char *, int, frame_data *, proto_tree *) = {
926
927   dissect_netb_add_group_name,  /* Add Group Name       0x00 */
928   dissect_netb_add_name,        /* Add Name             0x01 */
929   dissect_netb_name_in_conflict,/* Name In Conflict     0x02 */
930   dissect_netb_status_query,    /* Status Query         0x03 */
931   dissect_netb_unknown,         /* unknown              0x04 */
932   dissect_netb_unknown,         /* unknown              0x05 */
933   dissect_netb_unknown,         /* unknown              0x06 */
934   dissect_netb_unknown,         /* Terminate Trace      0x07 */
935   dissect_netb_datagram,        /* Datagram             0x08 */
936   dissect_netb_datagram_bcast,  /* Datagram Broadcast   0x09 */
937   dissect_netb_name_query,      /* Name Query           0x0A */
938   dissect_netb_unknown,         /* unknown              0x0B */
939   dissect_netb_unknown,         /* unknown              0x0C */
940   dissect_netb_add_name_resp,   /* Add Name Response    0x0D */
941   dissect_netb_name_resp,       /* Name Recognized      0x0E */
942   dissect_netb_status_resp,     /* Status Response      0x0F */
943   dissect_netb_unknown,         /* unknown              0x10 */
944   dissect_netb_unknown,         /* unknown              0x11 */
945   dissect_netb_unknown,         /* unknown              0x12 */
946   dissect_netb_unknown,         /* Terminate Trace      0x13 */
947   dissect_netb_data_ack,        /* Data Ack             0x14 */
948   dissect_netb_data_first_middle,/* Data First Middle   0x15 */
949   dissect_netb_data_only_last,  /* Data Only Last       0x16 */
950   dissect_netb_session_confirm, /* Session Confirm      0x17 */
951   dissect_netb_session_end,     /* Session End          0x18 */
952   dissect_netb_session_init,    /* Session Initialize   0x19 */
953   dissect_netb_no_receive,      /* No Receive           0x1A */
954   dissect_netb_receive_outstanding,/* Receive Outstanding 0x1B */
955   dissect_netb_receive_continue,/* Receive Continue     0x1C */
956   dissect_netb_unknown,         /* unknown              0x1D */
957   dissect_netb_unknown,         /* unknown              0x1E */
958
959   dissect_netb_unknown,         /* Session Alive        0x1f (nothing to do) */
960 };
961
962
963 void dissect_netbios(const u_char *pd, int offset, frame_data *fd,
964     proto_tree *tree)
965
966 {
967         proto_tree              *netb_tree;
968         proto_item              *ti;
969         guint16                 hdr_len, command;
970         char                    name[(NETBIOS_NAME_LEN - 1)*4 + 1];
971         int                     name_type;
972
973 /* Find NetBIOS marker EFFF, this is done because I have seen an extra LLC */
974 /* byte on our network. This only checks for one extra LLC byte. */
975
976         if (( pd[offset + 2] != 0xff) || ( pd[offset + 3] != 0xef)){
977                 ++offset;
978                 if (( pd[offset + 2] != 0xff)
979                     || ( pd[offset + 3] != 0xef)){
980                         if (check_col(fd, COL_PROTOCOL))
981                                 col_add_str(fd, COL_PROTOCOL, "NetBIOS");       
982         
983                         if (check_col(fd, COL_INFO))    /* print bad packet */
984                                 col_add_str(fd, COL_INFO, "Bad packet");
985
986                         if (tree) {
987                                 ti = proto_tree_add_item(tree, proto_netbios,
988                                         offset, END_OF_FRAME, NULL);
989                                 netb_tree = proto_item_add_subtree(ti, ett_netb);
990                                 
991                                 proto_tree_add_text( netb_tree, offset,
992                                     END_OF_FRAME, "Data (%u bytes)", 
993                                     END_OF_FRAME); 
994                         }       
995                         return;
996                 }
997         }
998         
999         /* To do: check for runts, errs, etc. */
1000
1001         hdr_len = pletohs(&pd[offset + NB_LENGTH]);
1002         command = pd[offset + NB_COMMAND];
1003         
1004         if (check_col(fd, COL_PROTOCOL))
1005                 col_add_str(fd, COL_PROTOCOL, "NetBIOS");
1006
1007         if (check_col(fd, COL_INFO)) {                  /* print command name */
1008                 switch ( command ) {
1009                 case NB_NAME_QUERY:
1010                         name_type = get_netbios_name( pd, offset + 12, name);
1011                         col_add_fstr(fd, COL_INFO, "%s for %s<%02x>",
1012                             CommandName[ command], name, name_type);
1013                         break;
1014
1015                 case NB_NAME_RESP:
1016                         name_type = get_netbios_name( pd, offset + 28, name);
1017                         col_add_fstr(fd, COL_INFO, "%s - %s<%02x>",
1018                             CommandName[ command], name, name_type);
1019                         break;
1020
1021                 default:
1022                         if ( command < sizeof( dissect_netb)/ sizeof(void *))
1023                                 col_add_fstr(fd, COL_INFO, "%s", CommandName[ command]);
1024                         else
1025                                 col_add_fstr(fd, COL_INFO, "Unknown");
1026                         break;
1027                 }
1028         }
1029
1030
1031         if (tree) {
1032                 ti = proto_tree_add_item(tree, proto_netbios, offset, END_OF_FRAME, NULL);
1033
1034                 netb_tree = proto_item_add_subtree(ti, ett_netb);
1035
1036                 proto_tree_add_text(netb_tree, offset, 2,
1037                                 "Header Length: %d", hdr_len);
1038
1039                 proto_tree_add_text(netb_tree, offset + 2, 2,
1040                                 "Delimiter: EFFF (NetBIOS)");
1041
1042                 proto_tree_add_text(netb_tree, offset + NB_COMMAND, 1,
1043                     "Command: 0x%02x (%s)", command, CommandName[ command]);
1044
1045                                                 /* if command in table range */
1046                 if ( command < sizeof( dissect_netb)/ sizeof(void *))
1047
1048                                                 /* branch to handle commands */
1049                         (dissect_netb[ command])( pd, offset, fd,
1050                                 netb_tree);             
1051         }
1052
1053                                                         /* Test for SMB data */
1054         if ( (END_OF_FRAME) > ( hdr_len + 4)){          /* if enough data */
1055
1056                 offset += hdr_len;                      /* move past header */
1057
1058                 if (( pd[offset + 0] == 0xff) &&        /* if SMB marker */
1059                     ( pd[offset + 1] == 'S') &&
1060                     ( pd[offset + 2] == 'M') &&
1061                     ( pd[offset + 3] == 'B'))
1062                                                         /* decode SMB */
1063                         dissect_smb(pd, offset, fd, tree, 
1064                                 END_OF_FRAME - hdr_len);
1065         }
1066
1067 /*$$$$ somewhere around here need to check for frame padding */
1068
1069 }
1070
1071
1072 void proto_register_netbios(void)
1073 {
1074         static gint *ett[] = {
1075                 &ett_netb,
1076                 &ett_netb_name,
1077                 &ett_netb_flags,
1078                 &ett_netb_status,
1079         };
1080
1081         proto_netbios = proto_register_protocol("NetBIOS", "netbios");
1082         proto_register_subtree_array(ett, array_length(ett));
1083 }