73d23040a14f25ba8340a13179eb0ef29dd0b427
[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.4 1999/09/02 23:17:56 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 #include "packet.h"
42 #include "packet-dns.h"
43 #include "packet-netbios.h"
44 #include "util.h"
45
46 /* Netbios command numbers */
47 #define NB_ADD_GROUP            0x00
48 #define NB_ADD_NAME             0x01
49 #define NB_DATAGRAM             0x08
50 #define NB_NAME_QUERY           0x0a
51 #define NB_NAME_RESP            0x0e
52 #define NB_DATA_ACK             0x14
53 #define NB_DATA_ONLY_LAST       0x16
54 #define NB_SESSION_CONFIRM      0x17    
55 #define NB_SESSION_INIT         0x19    
56 #define NB_KEEP_ALIVE           0x1f
57
58
59 /* Offsets of fields in the NetBIOS header. */
60 #define NB_LENGTH               0
61 #define NB_DELIMITER            2
62 #define NB_COMMAND              4
63 #define NB_FLAGS                5
64 #define NB_DATA1                5
65 #define NB_RESYNC               6
66 #define NB_DATA2                6
67 #define NB_CALL_NAME_TYPE       7
68 #define NB_XMIT_CORL            8
69 #define NB_RESP_CORL            10
70 #define NB_RMT_SES              12
71 #define NB_LOCAL_SES            13
72 #define NB_RECVER_NAME          12
73 #define NB_SENDER_NAME          28
74
75
76
77
78 static int proto_netbios = -1;
79
80 /* a number to bit image table */
81
82 static char *bit_field_str[] = {
83         "000",
84         "001",
85         "010",
86         "011",
87         "100",
88         "101",
89         "110",
90         "111"};
91         
92
93 /* the strings for the station type, used by get_netbios_name function */
94
95 char *name_type_str[] = {
96         "Workstation/Redirector",       /* 0x00 */
97         "Browser",                      /* 0x01 */
98         "Unknown",
99         "Messenger service/Main name",  /* 0x03 */
100         "Unknown",
101         "Forwarded name",               /* 0x05 */
102         "RAS Server service",           /* 0x06 */
103         "Unknown",
104         "Unknown",
105         "Unknown",
106         "Unknown",
107         "Unknown",
108         "Unknown",
109         "Unknown",
110         "Unknown",
111         "Unknown",
112         "Unknown",                      /* 0x10 */
113         "Unknown",
114         "Unknown",
115         "Unknown",
116         "Unknown",
117         "Unknown",
118         "Unknown",
119         "Unknown",
120         "Unknown",
121         "Unknown",
122         "Unknown",
123         "PDC Domain name",              /* 0x1b */
124         "BDC Domain name",              /* 0x1c */
125         "Master Browser backup",        /* 0x1d */
126         "Browser Election Service",     /* 0x1e */
127         "Net DDE Service",              /* 0x1f */
128         "Server service",               /* 0x20 */
129         "RAS client service",           /* 0x21 */
130         "Unknown",      /* need 'Unknown' as last entry (for limiting stuff) */
131 };
132
133 static int nb_name_type_max = (sizeof name_type_str / sizeof name_type_str[0]) - 1;
134
135 /* the strings for the command types  */
136
137 char *CommandName[] = {
138                 "Add Group Query",      /* 0x00 */
139                 "Add Name Query",       /* 0x01 */
140                 "Unknown",
141                 "Unknown",
142                 "Unknown",
143                 "Unknown",
144                 "Unknown",
145                 "Unknown",
146                 "Datagram",             /* 0x08 */
147                 "Unknown",
148                 "Name Query",           /* 0x0A */
149                 "Unknown",
150                 "Unknown",
151                 "Unknown",
152                 "Name Recognized",      /* 0x0E */
153                 "Unknown",
154                 "Unknown",
155                 "Unknown",
156                 "Unknown",
157                 "Unknown",
158                 "Data Ack",             /* 0x14 */
159                 "Unknown",
160                 "Data Only Last",       /* 0x16 */
161                 "Session Confirm",      /* 0x17 */
162                 "Unknown",
163                 "Session Initialize",   /* 0x19 */
164                 "Unknown",
165                 "Unknown",
166                 "Unknown",
167                 "Unknown",
168                 "Unknown",
169                 "Session Alive",        /* 0x1f */
170         };
171
172 void capture_netbios(const u_char *pd, int offset, guint32 cap_len,
173         packet_counts *ld)
174 {
175         ld->netbios++;
176 }
177
178
179 static guint get_netbios_name(const u_char *data_ptr, int offset, char *name_ret)
180
181 {/*  Extract the name string and name type.  Return the name string in  */
182  /* name_ret and return the name_type. */
183
184         int i;
185         char  name_type = *(data_ptr + offset + 15);
186         const char *name_ptr = data_ptr + offset;
187
188         for( i = 0; i <16; ++i){
189                 if ( 0x20 == (*name_ret++ = *name_ptr++))       /* exit if space */
190                         break;
191         }
192
193         *name_ret = 0;
194         return (guint)name_type;
195 }
196
197
198 void netbios_add_name( char* label, const u_char *pd, int offset,
199     int nb_offset, proto_tree *tree)
200
201 {/* add a name field display tree. Display the name and station type in sub-tree */
202  /* NOTE: offset = offset to start of netbios header    */
203  /*       nb_offset = offset inside of netbios header   */
204  
205         proto_tree *field_tree;
206         proto_item *tf;
207         char  name_str[ 17];
208         int   name_type;
209
210                                         /* decode the name field */
211         name_type = get_netbios_name( pd, nb_offset, name_str);
212
213         if ( nb_name_type_max < name_type)      /* limit type value */
214                 name_type = nb_name_type_max;
215         
216         tf = proto_tree_add_text( tree, offset + nb_offset, 16,
217                 "%s: %s (%s)", label, name_str, name_type_str[name_type]);
218
219         field_tree = proto_item_add_subtree( tf, ETT_NETB_NAME);
220         
221         proto_tree_add_text( field_tree, offset + nb_offset, 15, "%s",
222             name_str);
223         proto_tree_add_text( field_tree, offset + nb_offset + 15, 1,
224             "0x%0x (%s)", name_type, name_type_str[ name_type]);
225 }
226
227
228 static void netbios_add_flags( const u_char *pd, proto_tree *tree, int offset)
229
230 {
231
232         proto_tree *field_tree;
233         proto_item *tf;
234         guint flags = *(pd + offset);
235                                         /* decode the flag field */
236
237
238         tf = proto_tree_add_text( tree, offset, 1,
239                         "Flags: 0x%02x", flags);
240         field_tree = proto_item_add_subtree(tf, ETT_NETB_FLAGS);
241
242         proto_tree_add_text( field_tree, offset, 1, "%s%s",
243                 decode_boolean_bitfield(flags, 0x80,
244                         8, "No", ""), " NO.ACK indicator");
245
246         proto_tree_add_text(field_tree, offset, 1,
247                  ".... %s. = Largest Frame Size = %d", 
248                 bit_field_str[(flags & 0x0e) >> 1], ((flags & 0x0e) >> 1));
249
250         proto_tree_add_text(field_tree, offset, 1, "%s",
251                 decode_boolean_bitfield( flags, 0x01,
252                         8, "Version 2.0 or higher", "Pre version 2.0"));
253 }
254
255
256 static void netbios_add_ses_confirm_flags( const u_char *pd, proto_tree *tree,
257         int offset)
258
259 {
260         proto_tree *field_tree;
261         proto_item *tf;
262         guint flags = *(pd + offset);
263                                         /* decode the flag field */
264
265
266         tf = proto_tree_add_text( tree, offset, 1,
267                         "Flags: 0x%02x", flags);
268         field_tree = proto_item_add_subtree( tf, ETT_NETB_FLAGS);
269
270         proto_tree_add_text(field_tree, offset, 1, "%s%s",
271                         decode_boolean_bitfield(flags, 0x80,
272                                 8, "No", ""), " NO.ACK indicator");
273
274         proto_tree_add_text(field_tree, offset, 1, "%s",
275                         decode_boolean_bitfield(flags, 0x01,
276                                 8, "Pre version 2.0", "Version 2.0 or higher"));
277 }
278
279
280 static void netbios_data_only_flags( const u_char *pd, proto_tree *tree,
281     int offset)
282
283 {
284         proto_tree *field_tree;
285         proto_item *tf;
286         guint flags = *(pd + offset);
287                                         /* decode the flag field for data_only packet*/
288
289
290         tf = proto_tree_add_text( tree, offset, 1,
291                         "Flags: 0x%02x", flags);
292         field_tree = proto_item_add_subtree(tf, ETT_NETB_FLAGS);
293
294         proto_tree_add_text(field_tree, offset, 1, "%s%s",
295                         decode_boolean_bitfield(flags, 0x08,
296                                 8, "", "No "), "Acknowledge_Included");
297         proto_tree_add_text(field_tree, offset, 1, "%s%s",
298                         decode_boolean_bitfield(flags, 0x04,
299                                 8, "", "No "), "Ack_with_data_allowed");
300
301         proto_tree_add_text(field_tree, offset, 1, "%s%s",
302                         decode_boolean_bitfield(flags, 0x02,
303                                 8, "", "No "), "NO.ACK indicator");
304 }
305
306
307 /************************************************************************/
308 /*                                                                      */
309 /*  The routines to display the netbios field values in the tree        */
310 /*                                                                      */
311 /************************************************************************/
312
313
314 static void nb_xmit_corrl(const u_char *data_ptr, int offset, proto_tree *tree)
315
316 {/* display the transmit correlator */
317
318         proto_tree_add_text( tree, offset + NB_XMIT_CORL, 2,
319             "Transmit Correlator: 0x%04x", pletohs( data_ptr + NB_XMIT_CORL));
320 }
321
322
323 static void nb_resp_corrl(const u_char *data_ptr, int offset, proto_tree *tree)
324
325 {/* display the response correlator */
326
327         proto_tree_add_text( tree, offset + NB_RESP_CORL, 2,
328             "Response Correlator: 0x%04x", pletohs( data_ptr + NB_RESP_CORL));
329 }
330
331
332 static void nb_call_name_type(const u_char *data_ptr, int offset,
333     proto_tree *tree)
334
335 {/* display the call name type */
336
337         int name_type_value = MIN(*(data_ptr + NB_CALL_NAME_TYPE),
338                 nb_name_type_max);
339         
340         proto_tree_add_text( tree, offset + NB_CALL_NAME_TYPE, 1,
341             "Caller's Name Type.: 0x%02x (%s)",
342             *(data_ptr + NB_CALL_NAME_TYPE),
343             name_type_str[ name_type_value]);
344 }
345
346
347 static void nb_local_session(const u_char *data_ptr, int offset,
348     proto_tree *tree)
349
350 {/* add the local session to tree */
351                         
352         proto_tree_add_text( tree, offset +NB_LOCAL_SES, 1,
353             "Local Session No.: 0x%02d", *(data_ptr + NB_LOCAL_SES));
354 }
355
356
357 static void nb_remote_session(const u_char *data_ptr, int offset,
358     proto_tree *tree)
359
360 {/* add the remote session to tree */
361                         
362         proto_tree_add_text( tree, offset +NB_RMT_SES, 1,
363             "Remote Session No.: 0x%02d", *(data_ptr + NB_RMT_SES));
364 }
365
366
367 static void nb_data1( char *label, const u_char *data_ptr, int offset,
368     proto_tree *tree)
369
370 {/* add the DATA1 to tree with format string = label */
371
372         proto_tree_add_text( tree, offset + NB_DATA1, 1, label,
373             *(data_ptr + NB_DATA1));
374 }
375
376
377 static void nb_data2( char *label, int len, const u_char *data_ptr, int offset,
378     proto_tree *tree)
379
380 {/* add the DATA2 to tree with format string = label and length of len */
381
382         int value = (len == 1 ? *(data_ptr + NB_DATA2)
383                         : pletohs( data_ptr + NB_DATA2));
384         
385         proto_tree_add_text( tree, offset +NB_DATA2, len, label, value);
386 }
387
388 /************************************************************************/
389 /*                                                                      */
390 /*  The routines called by the top level to handle individual commands  */
391 /*                                                                      */
392 /************************************************************************/
393
394 static void  dissect_netb_unknown(const u_char *data_ptr, int offset,
395     frame_data *fd, proto_tree *tree)
396
397 {/* Handle any unknow commands, do nothing */
398
399 //$$    dissect_data( data_ptr, offset + NB_COMMAND + 1, fd, tree);
400 }
401
402
403 static void  dissect_netb_add_group(const u_char *data_ptr, int offset,
404     frame_data *fd, proto_tree *tree)
405
406 {/* Handle the ADD GROUP command */
407
408         nb_resp_corrl( data_ptr, offset, tree); 
409
410         netbios_add_name( "Group to add", data_ptr, 
411                             offset, NB_SENDER_NAME, tree);
412 }
413
414
415 static void  dissect_netb_add_name(const u_char *data_ptr, int offset, 
416     frame_data *fd, proto_tree *tree)
417
418 {/* Handle the ADD NAME command */
419
420         nb_resp_corrl( data_ptr, offset, tree); 
421
422         netbios_add_name( "Name to add", data_ptr, 
423                             offset, NB_SENDER_NAME, tree);
424 }
425
426
427 static void  dissect_netb_name_query(const u_char *data_ptr, int offset,
428     frame_data *fd, proto_tree *tree)
429
430 {/* Handle the NAME QUERY command */
431
432         nb_data2( "Local Session No.: 0x%02x", 1, data_ptr, offset, tree); 
433         nb_call_name_type( data_ptr, offset, tree); 
434         netbios_add_name( "Query Name", data_ptr, offset, NB_RECVER_NAME, tree);
435         netbios_add_name( "Sender's Name", data_ptr, offset, NB_SENDER_NAME,
436             tree);
437 }
438
439
440 static void  dissect_netb_name_resp(const u_char *data_ptr, int offset,
441     frame_data *fd, proto_tree *tree)
442
443 {/* Handle the NAME RESPONSE command */
444
445         nb_data2( "Local Session No.: 0x%02x", 1, data_ptr, offset, tree); 
446
447         nb_call_name_type( data_ptr, offset, tree); 
448         nb_xmit_corrl( data_ptr, offset, tree); 
449         nb_resp_corrl( data_ptr, offset, tree);
450         netbios_add_name( "Receiver's Name", data_ptr, offset, NB_RECVER_NAME,
451             tree);
452         netbios_add_name( "Sender's Name", data_ptr, offset, NB_SENDER_NAME,
453             tree);
454 }
455
456 static void  dissect_netb_session_init(const u_char *data_ptr, int offset,
457     frame_data *fd, proto_tree *tree)
458
459 {/* Handle the SESSION INITIATE command */
460
461         netbios_add_flags( data_ptr, tree, offset + NB_FLAGS);
462
463         nb_data2( "Max data recv size: %d", 2, data_ptr, offset, tree); 
464         nb_resp_corrl( data_ptr, offset, tree);
465         nb_xmit_corrl( data_ptr, offset, tree); 
466         nb_remote_session( data_ptr, offset, tree); 
467         nb_local_session( data_ptr, offset, tree); 
468 }
469
470
471 static void  dissect_netb_session_confirm(const u_char *data_ptr, int offset,
472     frame_data *fd, proto_tree *tree)
473
474 {/* Handle the SESSION CONFIRM command */
475
476         netbios_add_ses_confirm_flags( data_ptr, tree, offset + NB_FLAGS);
477
478         nb_data2( "Max data recv size: %d", 2, data_ptr, offset, tree); 
479         nb_resp_corrl( data_ptr, offset, tree);
480         nb_xmit_corrl( data_ptr, offset, tree); 
481         nb_remote_session( data_ptr, offset, tree); 
482         nb_local_session( data_ptr, offset, tree); 
483 }
484
485
486 static void  dissect_netb_data_only_last(const u_char *data_ptr, int offset,
487     frame_data *fd, proto_tree *tree)
488
489 {/* Handle the DATA ONLY LAST command */
490
491         netbios_data_only_flags( data_ptr, tree, offset + NB_FLAGS);
492
493         nb_data2( "Re-sync indicator: %d", 2, data_ptr, offset, tree); 
494         nb_resp_corrl( data_ptr, offset, tree);
495         nb_remote_session( data_ptr, offset, tree); 
496         nb_local_session( data_ptr, offset, tree); 
497
498 }
499
500
501 static void  dissect_netb_datagram(const u_char *data_ptr, int offset,
502     frame_data *fd, proto_tree *tree)
503
504 {/* Handle the DATAGRAM command */
505
506         nb_data1( "Data1: 0x%02x", data_ptr, offset, tree); 
507         nb_data2( "Data2: 0x%04x", 2, data_ptr, offset, tree); 
508         nb_xmit_corrl( data_ptr, offset, tree);
509         nb_resp_corrl( data_ptr, offset, tree);
510         netbios_add_name( "Receiver's Name", data_ptr, offset, NB_RECVER_NAME,
511             tree);
512         netbios_add_name( "Sender's Name", data_ptr, offset, NB_SENDER_NAME,
513             tree);
514
515 }
516
517 static void  dissect_netb_data_ack(const u_char *data_ptr, int offset,
518     frame_data *fd, proto_tree *tree)
519
520 {/* Handle the DATA ACK command */
521
522         netbios_data_only_flags( data_ptr, tree, offset + NB_FLAGS);
523
524
525         nb_xmit_corrl( data_ptr, offset, tree);
526         nb_remote_session( data_ptr, offset, tree); 
527         nb_local_session( data_ptr, offset, tree); 
528
529 }
530
531
532 /************************************************************************/
533 /*                                                                      */
534 /*  The table routines called by the top level to handle commands       */
535 /*                                                                      */
536 /************************************************************************/
537
538
539 void (*dissect_netb[])(const u_char *, int, frame_data *, proto_tree *) = {
540
541   dissect_netb_add_group,       /* add_group    0x00 */
542   dissect_netb_add_name,        /* add_name     0x01 */
543   dissect_netb_unknown,         /* unknown      0x02 */
544   dissect_netb_unknown,         /* unknown      0x03 */
545   dissect_netb_unknown,         /* unknown      0x04 */
546   dissect_netb_unknown,         /* unknown      0x05 */
547   dissect_netb_unknown,         /* unknown      0x06 */
548   dissect_netb_unknown,         /* unknown      0x07 */
549   dissect_netb_datagram,        /* Datagram     0x08 */
550   dissect_netb_unknown,         /* unknown      0x09 */
551   dissect_netb_name_query,      /* Name Query   0x0A */
552   dissect_netb_unknown,         /* unknown      0x0B */
553   dissect_netb_unknown,         /* unknown      0x0C */
554   dissect_netb_unknown,         /* unknown      0x0D */
555   dissect_netb_name_resp,       /* Name Resp    0x0E */
556   dissect_netb_unknown,         /* unknown      0x0F */
557   dissect_netb_unknown,         /* unknown      0x10 */
558   dissect_netb_unknown,         /* unknown      0x11 */
559   dissect_netb_unknown,         /* unknown      0x12 */
560   dissect_netb_unknown,         /* unknown      0x13 */
561   dissect_netb_data_ack,        /* Data Ack     0x14 */
562   dissect_netb_unknown,         /* unknown      0x15 */
563   dissect_netb_data_only_last,  /* Data Only Last 0x16 */
564   dissect_netb_session_confirm, /* Session Confirm 0x17 */
565   dissect_netb_unknown,         /* unknown      0x18 */
566   dissect_netb_session_init,    /* Session Initialize 0x19      */
567   dissect_netb_unknown,         /* unknown      0x1A */
568   dissect_netb_unknown,         /* unknown      0x1B */
569   dissect_netb_unknown,         /* unknown      0x1C */
570   dissect_netb_unknown,         /* unknown      0x1D */
571   dissect_netb_unknown,         /* unknown      0x1E */
572
573   dissect_netb_unknown,         /* Session Alive        0x1f (nothing to do) */
574 };
575
576
577 void dissect_netbios(const u_char *pd, int offset, frame_data *fd,
578     proto_tree *tree)
579
580 {
581         const u_char            *nb_data_ptr;
582         proto_tree              *netb_tree;
583         proto_item              *ti;
584         guint16                 hdr_len, command;
585         char                    name[17];
586
587         nb_data_ptr = &pd[offset];
588
589 /* Find NetBIOS marker EFFF, this is done because I have seen an extra LLC */
590 /* byte on our network. This only checks for one extra LLC byte. */
591
592         if (( *(nb_data_ptr + 2) != 0xff) || ( *(nb_data_ptr + 3) != 0xef)){
593
594                 ++nb_data_ptr;          /** marker not found shift one byte */
595                 ++offset;
596                 if (( *(nb_data_ptr + 2) != 0xff)
597                     || ( *(nb_data_ptr + 3) != 0xef)){
598                         if (check_col(fd, COL_PROTOCOL))
599                                 col_add_str(fd, COL_PROTOCOL, "NetBIOS");       
600         
601                         if (check_col(fd, COL_INFO))    /* print bad packet */
602                                 col_add_str(fd, COL_INFO, "Bad packet");
603
604                         if (tree) {
605                                 ti = proto_tree_add_item(tree, proto_netbios,
606                                         offset, END_OF_FRAME, NULL);
607                                 netb_tree = proto_item_add_subtree(ti, ETT_NETB);
608                                 
609                                 proto_tree_add_text( netb_tree, offset,
610                                     END_OF_FRAME, "Data (%u bytes)", 
611                                     END_OF_FRAME); 
612                         }       
613                         return;
614                 }
615         }
616         
617         /* To do: check for runts, errs, etc. */
618
619         hdr_len = pletohs( nb_data_ptr + NB_LENGTH);
620         command = *(nb_data_ptr + NB_COMMAND);
621
622         
623         if ( command == NB_NAME_QUERY ) {
624                 get_netbios_name( pd, offset + 12, name);
625         }               
626
627         if ( command == NB_NAME_RESP ){
628                 get_netbios_name( pd, offset + 28, name);
629         }               
630         
631
632         if (check_col(fd, COL_PROTOCOL))
633                 col_add_str(fd, COL_PROTOCOL, "NetBIOS");
634
635         if (check_col(fd, COL_INFO)) {                  /* print command name */
636                 if ( command == NB_NAME_QUERY)
637                         col_add_fstr(fd, COL_INFO, "%s for %s",
638                             CommandName[ command], name);
639
640                 else if ( command == NB_NAME_RESP)
641                         col_add_fstr(fd, COL_INFO, "%s - %s",
642                             CommandName[ command], name);
643
644                 else
645                         col_add_fstr(fd, COL_INFO, "%s", CommandName[ command]);
646         }
647
648
649         if (tree) {
650                 ti = proto_tree_add_item(tree, proto_netbios, offset, END_OF_FRAME, NULL);
651
652                 netb_tree = proto_item_add_subtree(ti, ETT_NETB);
653
654                 proto_tree_add_text(netb_tree, offset, 2,
655                                 "Header Length: %d", hdr_len);
656
657                 proto_tree_add_text(netb_tree, offset + 2, 2,
658                                 "Delimiter: EFFF (NetBIOS)");
659
660                 proto_tree_add_text(netb_tree, offset + NB_COMMAND, 1,
661                     "Command: 0x%02x (%s)", command, CommandName[ command]);
662
663                                                 /* if command in table range */
664                 if ( command < sizeof( dissect_netb)/ sizeof(void *))
665
666                                                 /* branch to handle commands */
667                         (dissect_netb[ command])( nb_data_ptr, offset, fd,
668                                 netb_tree);             
669         }
670
671                                                         /* Test for SMB data */
672         if ( (END_OF_FRAME) > ( hdr_len + 4)){          /* if enough data */
673
674                 nb_data_ptr += hdr_len;                 /* move past header */
675
676                 if (( *nb_data_ptr == 0xff) &&          /* if SMB marker */
677                     ( *(nb_data_ptr + 1) == 'S') &&
678                     ( *(nb_data_ptr + 2) == 'M') &&
679                     ( *(nb_data_ptr + 3) == 'B'))
680                                                         /* decode SMB */
681                         dissect_smb(pd, offset + hdr_len, fd, tree, 
682                                 END_OF_FRAME - hdr_len);
683         }
684
685 /*$$$$ somewhere around here need to check for frame padding */
686
687 }
688
689
690 void proto_register_netbios(void)
691 {
692
693         proto_netbios = proto_register_protocol("NetBIOS", "netbios");
694 }