2 * Routines for NetBIOS protocol packet disassembly
3 * Jeff Foster <foste@woodward.com>
4 * Copyright 1999 Jeffrey C. Foster
6 * derived from the packet-nbns.c
8 * $Id: packet-netbios.c,v 1.4 1999/09/02 23:17:56 guy Exp $
10 * Ethereal - Network traffic analyzer
11 * By Gerald Combs <gerald@zing.org>
12 * Copyright 1998 Gerald Combs
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.
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.
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.
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
42 #include "packet-dns.h"
43 #include "packet-netbios.h"
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
59 /* Offsets of fields in the NetBIOS header. */
61 #define NB_DELIMITER 2
67 #define NB_CALL_NAME_TYPE 7
68 #define NB_XMIT_CORL 8
69 #define NB_RESP_CORL 10
71 #define NB_LOCAL_SES 13
72 #define NB_RECVER_NAME 12
73 #define NB_SENDER_NAME 28
78 static int proto_netbios = -1;
80 /* a number to bit image table */
82 static char *bit_field_str[] = {
93 /* the strings for the station type, used by get_netbios_name function */
95 char *name_type_str[] = {
96 "Workstation/Redirector", /* 0x00 */
99 "Messenger service/Main name", /* 0x03 */
101 "Forwarded name", /* 0x05 */
102 "RAS Server service", /* 0x06 */
112 "Unknown", /* 0x10 */
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) */
133 static int nb_name_type_max = (sizeof name_type_str / sizeof name_type_str[0]) - 1;
135 /* the strings for the command types */
137 char *CommandName[] = {
138 "Add Group Query", /* 0x00 */
139 "Add Name Query", /* 0x01 */
146 "Datagram", /* 0x08 */
148 "Name Query", /* 0x0A */
152 "Name Recognized", /* 0x0E */
158 "Data Ack", /* 0x14 */
160 "Data Only Last", /* 0x16 */
161 "Session Confirm", /* 0x17 */
163 "Session Initialize", /* 0x19 */
169 "Session Alive", /* 0x1f */
172 void capture_netbios(const u_char *pd, int offset, guint32 cap_len,
179 static guint get_netbios_name(const u_char *data_ptr, int offset, char *name_ret)
181 {/* Extract the name string and name type. Return the name string in */
182 /* name_ret and return the name_type. */
185 char name_type = *(data_ptr + offset + 15);
186 const char *name_ptr = data_ptr + offset;
188 for( i = 0; i <16; ++i){
189 if ( 0x20 == (*name_ret++ = *name_ptr++)) /* exit if space */
194 return (guint)name_type;
198 void netbios_add_name( char* label, const u_char *pd, int offset,
199 int nb_offset, proto_tree *tree)
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 */
205 proto_tree *field_tree;
210 /* decode the name field */
211 name_type = get_netbios_name( pd, nb_offset, name_str);
213 if ( nb_name_type_max < name_type) /* limit type value */
214 name_type = nb_name_type_max;
216 tf = proto_tree_add_text( tree, offset + nb_offset, 16,
217 "%s: %s (%s)", label, name_str, name_type_str[name_type]);
219 field_tree = proto_item_add_subtree( tf, ETT_NETB_NAME);
221 proto_tree_add_text( field_tree, offset + nb_offset, 15, "%s",
223 proto_tree_add_text( field_tree, offset + nb_offset + 15, 1,
224 "0x%0x (%s)", name_type, name_type_str[ name_type]);
228 static void netbios_add_flags( const u_char *pd, proto_tree *tree, int offset)
232 proto_tree *field_tree;
234 guint flags = *(pd + offset);
235 /* decode the flag field */
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);
242 proto_tree_add_text( field_tree, offset, 1, "%s%s",
243 decode_boolean_bitfield(flags, 0x80,
244 8, "No", ""), " NO.ACK indicator");
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));
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"));
256 static void netbios_add_ses_confirm_flags( const u_char *pd, proto_tree *tree,
260 proto_tree *field_tree;
262 guint flags = *(pd + offset);
263 /* decode the flag field */
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);
270 proto_tree_add_text(field_tree, offset, 1, "%s%s",
271 decode_boolean_bitfield(flags, 0x80,
272 8, "No", ""), " NO.ACK indicator");
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"));
280 static void netbios_data_only_flags( const u_char *pd, proto_tree *tree,
284 proto_tree *field_tree;
286 guint flags = *(pd + offset);
287 /* decode the flag field for data_only packet*/
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);
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");
301 proto_tree_add_text(field_tree, offset, 1, "%s%s",
302 decode_boolean_bitfield(flags, 0x02,
303 8, "", "No "), "NO.ACK indicator");
307 /************************************************************************/
309 /* The routines to display the netbios field values in the tree */
311 /************************************************************************/
314 static void nb_xmit_corrl(const u_char *data_ptr, int offset, proto_tree *tree)
316 {/* display the transmit correlator */
318 proto_tree_add_text( tree, offset + NB_XMIT_CORL, 2,
319 "Transmit Correlator: 0x%04x", pletohs( data_ptr + NB_XMIT_CORL));
323 static void nb_resp_corrl(const u_char *data_ptr, int offset, proto_tree *tree)
325 {/* display the response correlator */
327 proto_tree_add_text( tree, offset + NB_RESP_CORL, 2,
328 "Response Correlator: 0x%04x", pletohs( data_ptr + NB_RESP_CORL));
332 static void nb_call_name_type(const u_char *data_ptr, int offset,
335 {/* display the call name type */
337 int name_type_value = MIN(*(data_ptr + NB_CALL_NAME_TYPE),
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]);
347 static void nb_local_session(const u_char *data_ptr, int offset,
350 {/* add the local session to tree */
352 proto_tree_add_text( tree, offset +NB_LOCAL_SES, 1,
353 "Local Session No.: 0x%02d", *(data_ptr + NB_LOCAL_SES));
357 static void nb_remote_session(const u_char *data_ptr, int offset,
360 {/* add the remote session to tree */
362 proto_tree_add_text( tree, offset +NB_RMT_SES, 1,
363 "Remote Session No.: 0x%02d", *(data_ptr + NB_RMT_SES));
367 static void nb_data1( char *label, const u_char *data_ptr, int offset,
370 {/* add the DATA1 to tree with format string = label */
372 proto_tree_add_text( tree, offset + NB_DATA1, 1, label,
373 *(data_ptr + NB_DATA1));
377 static void nb_data2( char *label, int len, const u_char *data_ptr, int offset,
380 {/* add the DATA2 to tree with format string = label and length of len */
382 int value = (len == 1 ? *(data_ptr + NB_DATA2)
383 : pletohs( data_ptr + NB_DATA2));
385 proto_tree_add_text( tree, offset +NB_DATA2, len, label, value);
388 /************************************************************************/
390 /* The routines called by the top level to handle individual commands */
392 /************************************************************************/
394 static void dissect_netb_unknown(const u_char *data_ptr, int offset,
395 frame_data *fd, proto_tree *tree)
397 {/* Handle any unknow commands, do nothing */
399 //$$ dissect_data( data_ptr, offset + NB_COMMAND + 1, fd, tree);
403 static void dissect_netb_add_group(const u_char *data_ptr, int offset,
404 frame_data *fd, proto_tree *tree)
406 {/* Handle the ADD GROUP command */
408 nb_resp_corrl( data_ptr, offset, tree);
410 netbios_add_name( "Group to add", data_ptr,
411 offset, NB_SENDER_NAME, tree);
415 static void dissect_netb_add_name(const u_char *data_ptr, int offset,
416 frame_data *fd, proto_tree *tree)
418 {/* Handle the ADD NAME command */
420 nb_resp_corrl( data_ptr, offset, tree);
422 netbios_add_name( "Name to add", data_ptr,
423 offset, NB_SENDER_NAME, tree);
427 static void dissect_netb_name_query(const u_char *data_ptr, int offset,
428 frame_data *fd, proto_tree *tree)
430 {/* Handle the NAME QUERY command */
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,
440 static void dissect_netb_name_resp(const u_char *data_ptr, int offset,
441 frame_data *fd, proto_tree *tree)
443 {/* Handle the NAME RESPONSE command */
445 nb_data2( "Local Session No.: 0x%02x", 1, data_ptr, offset, tree);
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,
452 netbios_add_name( "Sender's Name", data_ptr, offset, NB_SENDER_NAME,
456 static void dissect_netb_session_init(const u_char *data_ptr, int offset,
457 frame_data *fd, proto_tree *tree)
459 {/* Handle the SESSION INITIATE command */
461 netbios_add_flags( data_ptr, tree, offset + NB_FLAGS);
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);
471 static void dissect_netb_session_confirm(const u_char *data_ptr, int offset,
472 frame_data *fd, proto_tree *tree)
474 {/* Handle the SESSION CONFIRM command */
476 netbios_add_ses_confirm_flags( data_ptr, tree, offset + NB_FLAGS);
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);
486 static void dissect_netb_data_only_last(const u_char *data_ptr, int offset,
487 frame_data *fd, proto_tree *tree)
489 {/* Handle the DATA ONLY LAST command */
491 netbios_data_only_flags( data_ptr, tree, offset + NB_FLAGS);
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);
501 static void dissect_netb_datagram(const u_char *data_ptr, int offset,
502 frame_data *fd, proto_tree *tree)
504 {/* Handle the DATAGRAM command */
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,
512 netbios_add_name( "Sender's Name", data_ptr, offset, NB_SENDER_NAME,
517 static void dissect_netb_data_ack(const u_char *data_ptr, int offset,
518 frame_data *fd, proto_tree *tree)
520 {/* Handle the DATA ACK command */
522 netbios_data_only_flags( data_ptr, tree, offset + NB_FLAGS);
525 nb_xmit_corrl( data_ptr, offset, tree);
526 nb_remote_session( data_ptr, offset, tree);
527 nb_local_session( data_ptr, offset, tree);
532 /************************************************************************/
534 /* The table routines called by the top level to handle commands */
536 /************************************************************************/
539 void (*dissect_netb[])(const u_char *, int, frame_data *, proto_tree *) = {
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 */
573 dissect_netb_unknown, /* Session Alive 0x1f (nothing to do) */
577 void dissect_netbios(const u_char *pd, int offset, frame_data *fd,
581 const u_char *nb_data_ptr;
582 proto_tree *netb_tree;
584 guint16 hdr_len, command;
587 nb_data_ptr = &pd[offset];
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. */
592 if (( *(nb_data_ptr + 2) != 0xff) || ( *(nb_data_ptr + 3) != 0xef)){
594 ++nb_data_ptr; /** marker not found shift one byte */
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");
601 if (check_col(fd, COL_INFO)) /* print bad packet */
602 col_add_str(fd, COL_INFO, "Bad packet");
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);
609 proto_tree_add_text( netb_tree, offset,
610 END_OF_FRAME, "Data (%u bytes)",
617 /* To do: check for runts, errs, etc. */
619 hdr_len = pletohs( nb_data_ptr + NB_LENGTH);
620 command = *(nb_data_ptr + NB_COMMAND);
623 if ( command == NB_NAME_QUERY ) {
624 get_netbios_name( pd, offset + 12, name);
627 if ( command == NB_NAME_RESP ){
628 get_netbios_name( pd, offset + 28, name);
632 if (check_col(fd, COL_PROTOCOL))
633 col_add_str(fd, COL_PROTOCOL, "NetBIOS");
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);
640 else if ( command == NB_NAME_RESP)
641 col_add_fstr(fd, COL_INFO, "%s - %s",
642 CommandName[ command], name);
645 col_add_fstr(fd, COL_INFO, "%s", CommandName[ command]);
650 ti = proto_tree_add_item(tree, proto_netbios, offset, END_OF_FRAME, NULL);
652 netb_tree = proto_item_add_subtree(ti, ETT_NETB);
654 proto_tree_add_text(netb_tree, offset, 2,
655 "Header Length: %d", hdr_len);
657 proto_tree_add_text(netb_tree, offset + 2, 2,
658 "Delimiter: EFFF (NetBIOS)");
660 proto_tree_add_text(netb_tree, offset + NB_COMMAND, 1,
661 "Command: 0x%02x (%s)", command, CommandName[ command]);
663 /* if command in table range */
664 if ( command < sizeof( dissect_netb)/ sizeof(void *))
666 /* branch to handle commands */
667 (dissect_netb[ command])( nb_data_ptr, offset, fd,
671 /* Test for SMB data */
672 if ( (END_OF_FRAME) > ( hdr_len + 4)){ /* if enough data */
674 nb_data_ptr += hdr_len; /* move past header */
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'))
681 dissect_smb(pd, offset + hdr_len, fd, tree,
682 END_OF_FRAME - hdr_len);
685 /*$$$$ somewhere around here need to check for frame padding */
690 void proto_register_netbios(void)
693 proto_netbios = proto_register_protocol("NetBIOS", "netbios");