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