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.9 1999/11/15 21:33:57 nneul 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-netbios.h"
45 /* Netbios command numbers */
46 #define NB_ADD_GROUP 0x00
47 #define NB_ADD_NAME 0x01
48 #define NB_NAME_IN_CONFLICT 0x02
49 #define NB_STATUS_QUERY 0x03
50 #define NB_TERMINATE_TRACE_R 0x07
51 #define NB_DATAGRAM 0x08
52 #define NB_DATAGRAM_BCAST 0x09
53 #define NB_NAME_QUERY 0x0a
54 #define NB_ADD_NAME_RESP 0x0d
55 #define NB_NAME_RESP 0x0e
56 #define NB_STATUS_RESP 0x0f
57 #define NB_TERMINATE_TRACE_LR 0x13
58 #define NB_DATA_ACK 0x14
59 #define NB_DATA_FIRST_MIDDLE 0x15
60 #define NB_DATA_ONLY_LAST 0x16
61 #define NB_SESSION_CONFIRM 0x17
62 #define NB_SESSION_END 0x18
63 #define NB_SESSION_INIT 0x19
64 #define NB_NO_RECEIVE 0x1a
65 #define NB_RECEIVE_OUTSTANDING 0x1b
66 #define NB_RECEIVE_CONTINUE 0x1c
67 #define NB_KEEP_ALIVE 0x1f
69 /* Offsets of fields in the NetBIOS header. */
71 #define NB_DELIMITER 2
77 #define NB_CALL_NAME_TYPE 7
78 #define NB_XMIT_CORL 8
79 #define NB_RESP_CORL 10
81 #define NB_LOCAL_SES 13
82 #define NB_RECVER_NAME 12
83 #define NB_SENDER_NAME 28
85 static int proto_netbios = -1;
87 /* The strings for the station type, used by get_netbios_name function;
88 many of them came from the file "NetBIOS.txt" in the Zip archive at
90 http://www.net3group.com/ftp/browser.zip
93 static const value_string name_type_vals[] = {
94 {0x00, "Workstation/Redirector"},
96 {0x02, "Workstation/Redirector"},
97 /* not sure what 0x02 is, I'm seeing alot of them however */
98 /* i'm seeing them with workstation/redirection host
100 {0x03, "Messenger service/Main name"},
101 {0x05, "Forwarded name"},
102 {0x06, "RAS Server service"},
103 {0x1b, "PDC Domain name"},
104 {0x1c, "BDC Domain name"},
105 {0x1d, "Master Browser backup"},
106 {0x1e, "Browser Election Service"},
107 {0x1f, "Net DDE Service"},
108 {0x20, "Server service"},
109 {0x21, "RAS client service"},
110 {0x22, "Exchange Interchange (MSMail Connector)"},
111 {0x23, "Exchange Store"},
112 {0x24, "Exchange Directory"},
113 {0x2b, "Lotus Notes Server service"},
114 {0x30, "Modem sharing server service"},
115 {0x31, "Modem sharing client service"},
116 {0x43, "SMS Clients Remote Control"},
117 {0x44, "SMS Administrators Remote Control Tool"},
118 {0x45, "SMS Clients Remote Chat"},
119 {0x46, "SMS Clients Remote Transfer"},
120 {0x4c, "DEC Pathworks TCP/IP Service on Windows NT"},
121 {0x52, "DEC Pathworks TCP/IP Service on Windows NT"},
122 {0x6a, "Microsoft Exchange IMC"},
123 {0x87, "Microsoft Exchange MTA"},
124 {0xbe, "Network Monitor Agent"},
125 {0xbf, "Network Monitor Analyzer"},
131 http://www.s390.ibm.com/bookmgr-cgi/bookmgr.cmd/BOOKS/BK8P7001/CCONTENTS
135 http://ourworld.compuserve.com/homepages/TimothyDEvans/contents.htm
137 for information about the NetBIOS Frame Protocol (which is what this
140 /* the strings for the command types */
142 static char *CommandName[] = {
143 "Add Group Name Query", /* 0x00 */
144 "Add Name Query", /* 0x01 */
145 "Name In Conflict", /* 0x02 */
146 "Status Query", /* 0x03 */
150 "Terminate Trace", /* 0x07 */
151 "Datagram", /* 0x08 */
152 "Broadcast Datagram", /* 0x09 */
153 "Name Query", /* 0x0A */
156 "Add Name Response", /* 0x0D */
157 "Name Recognized", /* 0x0E */
158 "Status Response", /* 0x0F */
162 "Terminate Trace", /* 0x13 */
163 "Data Ack", /* 0x14 */
164 "Data First Middle", /* 0x15 */
165 "Data Only Last", /* 0x16 */
166 "Session Confirm", /* 0x17 */
167 "Session End", /* 0x18 */
168 "Session Initialize", /* 0x19 */
169 "No Receive", /* 0x1a */
170 "Receive Outstanding", /* 0x1b */
171 "Receive Continue", /* 0x1c */
174 "Session Alive", /* 0x1f */
177 void capture_netbios(const u_char *pd, int offset, guint32 cap_len,
185 process_netbios_name(const u_char *name_ptr, char *name_ret)
188 int name_type = *(name_ptr + NETBIOS_NAME_LEN - 1);
190 static const char hex_digits[16] = "0123456780abcdef";
192 for (i = 0; i < NETBIOS_NAME_LEN - 1; i++) {
193 name_char = *name_ptr++;
194 if (name_char >= ' ' && name_char <= '~')
195 *name_ret++ = name_char;
197 /* It's not printable; show it as <XX>, where
198 XX is the value in hex. */
200 *name_ret++ = hex_digits[(name_char >> 4)];
201 *name_ret++ = hex_digits[(name_char & 0x0F)];
209 guint get_netbios_name(const u_char *data_ptr, int offset, char *name_ret)
211 {/* Extract the name string and name type. Return the name string in */
212 /* name_ret and return the name_type. */
213 return process_netbios_name(data_ptr + offset, name_ret);
217 * Get a string describing the type of a NetBIOS name.
220 netbios_name_type_descr(int name_type)
222 return val_to_str(name_type, name_type_vals, "Unknown");
225 void netbios_add_name( char* label, const u_char *pd, int offset,
226 int nb_offset, proto_tree *tree)
228 {/* add a name field display tree. Display the name and station type in sub-tree */
229 /* NOTE: offset = offset to start of netbios header */
230 /* nb_offset = offset inside of netbios header */
232 proto_tree *field_tree;
234 char name_str[(NETBIOS_NAME_LEN - 1)*4 + 1];
238 /* decode the name field */
239 name_type = get_netbios_name( pd, nb_offset, name_str);
241 name_type_str = netbios_name_type_descr(name_type);
242 tf = proto_tree_add_text( tree, offset + nb_offset, NETBIOS_NAME_LEN,
243 "%s: %s<%02x> (%s)", label, name_str, name_type, name_type_str);
245 field_tree = proto_item_add_subtree( tf, ETT_NETB_NAME);
247 proto_tree_add_text( field_tree, offset + nb_offset, 15, "%s",
249 proto_tree_add_text( field_tree, offset + nb_offset + 15, 1,
250 "0x%02x (%s)", name_type, name_type_str);
254 static void netbios_data_first_middle_flags( const u_char *pd, proto_tree *tree,
258 proto_tree *field_tree;
260 guint flags = *(pd + offset);
261 /* decode the flag field for Data First Middle packet*/
263 tf = proto_tree_add_text( tree, offset, 1,
264 "Flags: 0x%02x", flags);
265 field_tree = proto_item_add_subtree(tf, ETT_NETB_FLAGS);
267 proto_tree_add_text(field_tree, offset, 1, "%s",
268 decode_boolean_bitfield(flags, 0x08, 8,
269 "Acknowledge_included", "No Acknowledge_included"));
271 proto_tree_add_text(field_tree, offset, 1, "%s",
272 decode_boolean_bitfield(flags, 0x02, 8,
273 "No acknowledgement expected", "Acknowledgement expected"));
275 proto_tree_add_text(field_tree, offset, 1, "%s",
276 decode_boolean_bitfield(flags, 0x01, 8,
277 "RECEIVE_CONTINUE requested", "RECEIVE_CONTINUE not requested"));
281 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 Last packet*/
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);
293 proto_tree_add_text(field_tree, offset, 1, "%s",
294 decode_boolean_bitfield(flags, 0x08, 8,
295 "ACKNOWLEDGE_INCLUDED", "No ACKNOWLEDGE_INCLUDED"));
297 proto_tree_add_text(field_tree, offset, 1, "%s",
298 decode_boolean_bitfield(flags, 0x04, 8,
299 "ACKNOWLEDGE_WITH_DATA_ALLOWED", "No ACKNOWLEDGE_WITH_DATA_ALLOWED"));
301 proto_tree_add_text(field_tree, offset, 1, "%s",
302 decode_boolean_bitfield(flags, 0x02, 8,
303 "No acknowledgement expected", "Acknowledgement expected"));
307 static void netbios_add_ses_confirm_flags( const u_char *pd, proto_tree *tree,
310 proto_tree *field_tree;
312 guint flags = *(pd + offset);
313 /* decode the flag field for Session Confirm packet */
315 tf = proto_tree_add_text( tree, offset, 1,
316 "Flags: 0x%02x", flags);
317 field_tree = proto_item_add_subtree( tf, ETT_NETB_FLAGS);
319 proto_tree_add_text(field_tree, offset, 1, "%s",
320 decode_boolean_bitfield(flags, 0x80, 8,
321 "Can handle SEND.NO.ACK", "Can't handle SEND.NO.ACK"));
323 proto_tree_add_text(field_tree, offset, 1, "%s",
324 decode_boolean_bitfield(flags, 0x01, 8,
325 "NetBIOS 2.00 or higher", "NetBIOS 1.xx"));
329 static void netbios_add_session_init_flags( const u_char *pd, proto_tree *tree,
332 proto_tree *field_tree;
334 guint flags = *(pd + offset);
335 /* decode the flag field for Session Init packet */
337 tf = proto_tree_add_text( tree, offset, 1,
338 "Flags: 0x%02x", flags);
339 field_tree = proto_item_add_subtree(tf, ETT_NETB_FLAGS);
341 proto_tree_add_text(field_tree, offset, 1, "%s",
342 decode_boolean_bitfield(flags, 0x80, 8,
343 "Can handle SEND.NO.ACK", "Can't handle SEND.NO.ACK"));
345 proto_tree_add_text(field_tree, offset, 1, "%s",
346 decode_numeric_bitfield(flags, 0x0E, 8,
347 "Largest frame value = %u"));
349 proto_tree_add_text(field_tree, offset, 1, "%s",
350 decode_boolean_bitfield(flags, 0x01, 8,
351 "NetBIOS 2.00 or higher", "NetBIOS 1.xx"));
355 static void netbios_no_receive_flags( const u_char *pd, proto_tree *tree,
359 proto_tree *field_tree;
361 guint flags = *(pd + offset);
362 /* decode the flag field for No Receive packet*/
364 tf = proto_tree_add_text( tree, offset, 1,
365 "Flags: 0x%02x", flags);
368 field_tree = proto_item_add_subtree(tf, ETT_NETB_FLAGS);
369 proto_tree_add_text(field_tree, offset, 1, "%s",
370 decode_boolean_bitfield(flags, 0x02, 8,
371 "SEND.NO.ACK data not received", NULL));
376 /************************************************************************/
378 /* The routines to display the netbios field values in the tree */
380 /************************************************************************/
383 static void nb_xmit_corrl(const u_char *data_ptr, int offset, proto_tree *tree)
385 {/* display the transmit correlator */
387 proto_tree_add_text( tree, offset + NB_XMIT_CORL, 2,
388 "Transmit Correlator: 0x%04x", pletohs( data_ptr + NB_XMIT_CORL));
392 static void nb_resp_corrl(const u_char *data_ptr, int offset, proto_tree *tree)
394 {/* display the response correlator */
396 proto_tree_add_text( tree, offset + NB_RESP_CORL, 2,
397 "Response Correlator: 0x%04x", pletohs( data_ptr + NB_RESP_CORL));
401 static void nb_call_name_type(const u_char *data_ptr, int offset,
404 {/* display the call name type */
406 int name_type_value = *(data_ptr + NB_CALL_NAME_TYPE);
408 switch (name_type_value) {
411 proto_tree_add_text( tree, offset + NB_CALL_NAME_TYPE, 1,
412 "Caller's Name Type: Unique name");
416 proto_tree_add_text( tree, offset + NB_CALL_NAME_TYPE, 1,
417 "Caller's Name Type: Group name");
421 proto_tree_add_text( tree, offset + NB_CALL_NAME_TYPE, 1,
422 "Caller's Name Type: 0x%02x (should be 0 or 1)",
429 static void nb_local_session(const u_char *data_ptr, int offset,
432 {/* add the local session to tree */
434 proto_tree_add_text( tree, offset +NB_LOCAL_SES, 1,
435 "Local Session No.: 0x%02x", *(data_ptr + NB_LOCAL_SES));
439 static void nb_remote_session(const u_char *data_ptr, int offset,
442 {/* add the remote session to tree */
444 proto_tree_add_text( tree, offset +NB_RMT_SES, 1,
445 "Remote Session No.: 0x%02x", *(data_ptr + NB_RMT_SES));
449 static void nb_data2( char *label, int len, const u_char *data_ptr, int offset,
452 {/* add the DATA2 to tree with format string = label and length of len */
454 int value = (len == 1 ? *(data_ptr + NB_DATA2)
455 : pletohs( data_ptr + NB_DATA2));
457 proto_tree_add_text( tree, offset +NB_DATA2, len, label, value);
460 static void nb_resync_indicator(const u_char *data_ptr, int offset,
463 guint16 resync_indicator = pletohs(data_ptr + NB_DATA2);
465 switch (resync_indicator) {
468 proto_tree_add_text(tree, offset + NB_DATA2, 2,
469 "Re-sync indicator: Not first Data First Middle following Receive Outstanding");
473 proto_tree_add_text(tree, offset + NB_DATA2, 2,
474 "Re-sync indicator: First Data First Middle following Receive Outstanding");
478 proto_tree_add_text(tree, offset + NB_DATA2, 2,
479 "Re-sync indicator: 0x%04x", resync_indicator);
484 /************************************************************************/
486 /* The routines called by the top level to handle individual commands */
488 /************************************************************************/
490 static void dissect_netb_unknown(const u_char *data_ptr, int offset,
491 frame_data *fd, proto_tree *tree)
493 {/* Handle any unknow commands, do nothing */
495 /* dissect_data( data_ptr, offset + NB_COMMAND + 1, fd, tree); */
499 static void dissect_netb_add_group_name(const u_char *data_ptr, int offset,
500 frame_data *fd, proto_tree *tree)
502 {/* Handle the ADD GROUP NAME QUERY command */
504 nb_resp_corrl( data_ptr, offset, tree);
506 netbios_add_name( "Group name to add", data_ptr,
507 offset, NB_SENDER_NAME, tree);
511 static void dissect_netb_add_name(const u_char *data_ptr, int offset,
512 frame_data *fd, proto_tree *tree)
514 {/* Handle the ADD NAME QUERY command */
516 nb_resp_corrl( data_ptr, offset, tree);
518 netbios_add_name( "Name to add", data_ptr,
519 offset, NB_SENDER_NAME, tree);
523 static void dissect_netb_name_in_conflict(const u_char *data_ptr, int offset,
524 frame_data *fd, proto_tree *tree)
526 {/* Handle the NAME IN CONFLICT command */
528 netbios_add_name( "Name In Conflict", data_ptr, offset, NB_RECVER_NAME, tree);
529 netbios_add_name( "Sender's Name", data_ptr, offset, NB_SENDER_NAME,
534 static void dissect_netb_status_query(const u_char *data_ptr, int offset,
535 frame_data *fd, proto_tree *tree)
537 {/* Handle the STATUS QUERY command */
538 guint8 status_request = *(data_ptr + NB_DATA1);
540 switch (status_request) {
543 proto_tree_add_text(tree, offset + NB_DATA1, 1,
544 "Status request: NetBIOS 1.x or 2.0");
548 proto_tree_add_text(tree, offset + NB_DATA1, 1,
549 "Status request: NetBIOS 2.1, initial status request");
553 proto_tree_add_text(tree, offset + NB_DATA1, 1,
554 "Status request: NetBIOS 2.1, %u names received so far",
558 nb_data2( "Length of status buffer: %u", 2, data_ptr, offset, tree);
559 nb_resp_corrl( data_ptr, offset, tree);
560 netbios_add_name( "Receiver's Name", data_ptr, offset, NB_RECVER_NAME,
562 netbios_add_name( "Sender's Name", data_ptr, offset, NB_SENDER_NAME,
567 static u_char zeroes[10];
569 static void dissect_netb_datagram(const u_char *data_ptr, int offset,
570 frame_data *fd, proto_tree *tree)
572 {/* Handle the DATAGRAM command */
574 netbios_add_name( "Receiver's Name", data_ptr, offset, NB_RECVER_NAME,
576 /* Weird. In some datagrams, this is 10 octets of 0, followed
577 by a MAC address.... */
578 if (memcmp(data_ptr + NB_SENDER_NAME, zeroes, 10) == 0) {
579 proto_tree_add_text( tree, offset + NB_SENDER_NAME + 10, 6,
580 "Sender's MAC Address: %s",
581 ether_to_str(data_ptr + NB_SENDER_NAME + 10));
583 netbios_add_name( "Sender's Name", data_ptr, offset,
584 NB_SENDER_NAME, tree);
589 static void dissect_netb_datagram_bcast(const u_char *data_ptr, int offset,
590 frame_data *fd, proto_tree *tree)
592 {/* Handle the DATAGRAM BROADCAST command */
594 /* We assume the same weirdness can happen here.... */
595 if (memcmp(data_ptr + NB_SENDER_NAME, zeroes, 10) == 0) {
596 proto_tree_add_text( tree, offset + NB_SENDER_NAME + 10, 6,
597 "Sender's Node Address: %s",
598 ether_to_str(data_ptr + NB_SENDER_NAME + 10));
600 netbios_add_name( "Sender's Name", data_ptr, offset,
601 NB_SENDER_NAME, tree);
606 static void dissect_netb_name_query(const u_char *data_ptr, int offset,
607 frame_data *fd, proto_tree *tree)
609 {/* Handle the NAME QUERY command */
610 guint8 local_session_number = *(data_ptr + NB_DATA2);
612 if (local_session_number == 0) {
613 proto_tree_add_text( tree, offset + NB_DATA2, 1,
614 "Local Session No.: 0 (FIND.NAME request)");
616 proto_tree_add_text( tree, offset + NB_DATA2, 1,
617 "Local Session No.: 0x%02x", local_session_number);
619 nb_call_name_type( data_ptr, offset, tree);
620 nb_resp_corrl( data_ptr, offset, tree);
621 netbios_add_name( "Query Name", data_ptr, offset, NB_RECVER_NAME, tree);
622 if (local_session_number != 0) {
623 netbios_add_name( "Sender's Name", data_ptr, offset,
624 NB_SENDER_NAME, tree);
629 static void dissect_netb_add_name_resp(const u_char *data_ptr, int offset,
630 frame_data *fd, proto_tree *tree)
632 {/* Handle the ADD NAME RESPONSE command */
633 guint8 status = *(data_ptr + NB_DATA1);
634 guint16 name_type = pletohs(data_ptr + NB_DATA2);
639 proto_tree_add_text( tree, offset + NB_DATA1, 1,
640 "Status: Add name not in process");
644 proto_tree_add_text( tree, offset + NB_DATA1, 1,
645 "Status: Add name in process");
649 proto_tree_add_text( tree, offset + NB_DATA1, 1,
650 "Status: 0x%02x (should be 0 or 1)", status);
657 proto_tree_add_text( tree, offset + NB_DATA2, 2,
658 "Name type: Unique name");
662 proto_tree_add_text( tree, offset + NB_DATA2, 2,
663 "Name type: Group name");
667 proto_tree_add_text( tree, offset + NB_DATA2, 2,
668 "Name type: 0x%04x (should be 0 or 1)", name_type);
672 nb_xmit_corrl( data_ptr, offset, tree);
673 netbios_add_name( "Name to be added", data_ptr, offset, NB_RECVER_NAME,
675 netbios_add_name( "Name to be added", data_ptr, offset, NB_SENDER_NAME,
680 static void dissect_netb_name_resp(const u_char *data_ptr, int offset,
681 frame_data *fd, proto_tree *tree)
683 {/* Handle the NAME RECOGNIZED command */
684 guint8 local_session_number = *(data_ptr + NB_DATA2);
686 switch (local_session_number) {
689 proto_tree_add_text( tree, offset + NB_DATA2, 1,
690 "State of name: No LISTEN pending, or FIND.NAME response");
694 proto_tree_add_text( tree, offset + NB_DATA2, 1,
695 "State of name: LISTEN pending, but insufficient resources to establish session");
699 proto_tree_add_text( tree, offset + NB_DATA2, 1,
700 "Local Session No.: 0x%02x", local_session_number);
703 nb_call_name_type( data_ptr, offset, tree);
704 nb_xmit_corrl( data_ptr, offset, tree);
705 if (local_session_number != 0x00 && local_session_number != 0xFF)
706 nb_resp_corrl( data_ptr, offset, tree);
707 netbios_add_name( "Receiver's Name", data_ptr, offset, NB_RECVER_NAME,
709 if (local_session_number != 0x00 && local_session_number != 0xFF) {
710 netbios_add_name( "Sender's Name", data_ptr, offset,
711 NB_SENDER_NAME, tree);
716 static void dissect_netb_status_resp(const u_char *data_ptr, int offset,
717 frame_data *fd, proto_tree *tree)
719 {/* Handle the STATUS RESPONSE command */
720 guint8 status_response = *(data_ptr + NB_DATA1);
722 proto_tree *data2_tree;
725 nb_call_name_type( data_ptr, offset, tree);
726 if (status_response == 0) {
727 proto_tree_add_text(tree, offset + NB_DATA1, 1,
728 "Status response: NetBIOS 1.x or 2.0");
730 proto_tree_add_text(tree, offset + NB_DATA1, 1,
731 "Status response: NetBIOS 2.1, %u names sent so far",
734 data2 = pletohs(data_ptr + NB_DATA2);
735 td2 = proto_tree_add_text(tree, offset + NB_DATA2, 2, "Status: 0x04x",
737 data2_tree = proto_item_add_subtree(td2, ETT_NETB_STATUS);
738 if (data2 & 0x8000) {
739 proto_tree_add_text(data2_tree, offset, 2, "%s",
740 decode_boolean_bitfield(data2, 0x8000, 8*2,
741 "Data length exceeds maximum frame size", NULL));
743 if (data2 & 0x4000) {
744 proto_tree_add_text(data2_tree, offset, 2, "%s",
745 decode_boolean_bitfield(data2, 0x4000, 8*2,
746 "Data length exceeds user's buffer", NULL));
748 proto_tree_add_text(data2_tree, offset, 2, "%s",
749 decode_numeric_bitfield(data2, 0x3FFF, 2*8,
750 "Status data length = %u"));
751 nb_xmit_corrl( data_ptr, offset, tree);
752 netbios_add_name( "Receiver's Name", data_ptr, offset, NB_RECVER_NAME,
754 netbios_add_name( "Sender's Name", data_ptr, offset, NB_SENDER_NAME,
759 static void dissect_netb_data_ack(const u_char *data_ptr, int offset,
760 frame_data *fd, proto_tree *tree)
762 {/* Handle the DATA ACK command */
764 nb_xmit_corrl( data_ptr, offset, tree);
765 nb_remote_session( data_ptr, offset, tree);
766 nb_local_session( data_ptr, offset, tree);
770 static void dissect_netb_data_first_middle(const u_char *data_ptr, int offset,
771 frame_data *fd, proto_tree *tree)
773 {/* Handle the DATA FIRST MIDDLE command */
775 netbios_data_first_middle_flags( data_ptr, tree, offset + NB_FLAGS);
777 nb_resync_indicator(data_ptr, offset, tree);
778 nb_xmit_corrl( data_ptr, offset, tree);
779 nb_resp_corrl( data_ptr, offset, tree);
780 nb_remote_session( data_ptr, offset, tree);
781 nb_local_session( data_ptr, offset, tree);
786 static void dissect_netb_data_only_last(const u_char *data_ptr, int offset,
787 frame_data *fd, proto_tree *tree)
789 {/* Handle the DATA ONLY LAST command */
791 netbios_data_only_flags( data_ptr, tree, offset + NB_FLAGS);
793 nb_resync_indicator(data_ptr, offset, tree);
794 nb_xmit_corrl( data_ptr, offset, tree);
795 nb_resp_corrl( data_ptr, offset, tree);
796 nb_remote_session( data_ptr, offset, tree);
797 nb_local_session( data_ptr, offset, tree);
802 static void dissect_netb_session_confirm(const u_char *data_ptr, int offset,
803 frame_data *fd, proto_tree *tree)
805 {/* Handle the SESSION CONFIRM command */
807 netbios_add_ses_confirm_flags( data_ptr, tree, offset + NB_FLAGS);
809 nb_data2( "Max data recv size: %u", 2, data_ptr, offset, tree);
810 nb_xmit_corrl( data_ptr, offset, tree);
811 nb_resp_corrl( data_ptr, offset, tree);
812 nb_remote_session( data_ptr, offset, tree);
813 nb_local_session( data_ptr, offset, tree);
817 static void dissect_netb_session_end(const u_char *data_ptr, int offset,
818 frame_data *fd, proto_tree *tree)
820 {/* Handle the SESSION END command */
821 guint16 termination_indicator = pletohs(data_ptr + NB_DATA2);
823 switch (termination_indicator) {
826 proto_tree_add_text( tree, offset + NB_DATA2, 2,
827 "Termination indicator: Normal session end");
831 proto_tree_add_text( tree, offset + NB_DATA2, 2,
832 "Termination indicator: Abormal session end");
836 proto_tree_add_text( tree, offset + NB_DATA2, 2,
837 "Termination indicator: 0x%04x (should be 0x0000 or 0x0001)",
838 termination_indicator);
842 nb_remote_session( data_ptr, offset, tree);
843 nb_local_session( data_ptr, offset, tree);
847 static void dissect_netb_session_init(const u_char *data_ptr, int offset,
848 frame_data *fd, proto_tree *tree)
850 {/* Handle the SESSION INITIALIZE command */
852 netbios_add_session_init_flags( data_ptr, tree, offset + NB_FLAGS);
854 nb_data2( "Max data recv size: %u", 2, data_ptr, offset, tree);
855 nb_resp_corrl( data_ptr, offset, tree);
856 nb_xmit_corrl( data_ptr, offset, tree);
857 nb_remote_session( data_ptr, offset, tree);
858 nb_local_session( data_ptr, offset, tree);
862 static void dissect_netb_no_receive(const u_char *data_ptr, int offset,
863 frame_data *fd, proto_tree *tree)
865 {/* Handle the NO RECEIVE command */
867 netbios_no_receive_flags( data_ptr, tree, offset + NB_FLAGS);
869 nb_data2( "Number of data bytes accepted: %u", 2, data_ptr, offset, tree);
870 nb_remote_session( data_ptr, offset, tree);
871 nb_local_session( data_ptr, offset, tree);
876 static void dissect_netb_receive_outstanding(const u_char *data_ptr, int offset,
877 frame_data *fd, proto_tree *tree)
879 {/* Handle the RECEIVE OUTSTANDING command */
881 nb_data2( "Number of data bytes accepted: %u", 2, data_ptr, offset, tree);
882 nb_remote_session( data_ptr, offset, tree);
883 nb_local_session( data_ptr, offset, tree);
888 static void dissect_netb_receive_continue(const u_char *data_ptr, int offset,
889 frame_data *fd, proto_tree *tree)
891 {/* Handle the RECEIVE CONTINUE command */
893 nb_xmit_corrl( data_ptr, offset, tree);
894 nb_remote_session( data_ptr, offset, tree);
895 nb_local_session( data_ptr, offset, tree);
900 /************************************************************************/
902 /* The table routines called by the top level to handle commands */
904 /************************************************************************/
907 void (*dissect_netb[])(const u_char *, int, frame_data *, proto_tree *) = {
909 dissect_netb_add_group_name, /* Add Group Name 0x00 */
910 dissect_netb_add_name, /* Add Name 0x01 */
911 dissect_netb_name_in_conflict,/* Name In Conflict 0x02 */
912 dissect_netb_status_query, /* Status Query 0x03 */
913 dissect_netb_unknown, /* unknown 0x04 */
914 dissect_netb_unknown, /* unknown 0x05 */
915 dissect_netb_unknown, /* unknown 0x06 */
916 dissect_netb_unknown, /* Terminate Trace 0x07 */
917 dissect_netb_datagram, /* Datagram 0x08 */
918 dissect_netb_datagram_bcast, /* Datagram Broadcast 0x09 */
919 dissect_netb_name_query, /* Name Query 0x0A */
920 dissect_netb_unknown, /* unknown 0x0B */
921 dissect_netb_unknown, /* unknown 0x0C */
922 dissect_netb_add_name_resp, /* Add Name Response 0x0D */
923 dissect_netb_name_resp, /* Name Recognized 0x0E */
924 dissect_netb_status_resp, /* Status Response 0x0F */
925 dissect_netb_unknown, /* unknown 0x10 */
926 dissect_netb_unknown, /* unknown 0x11 */
927 dissect_netb_unknown, /* unknown 0x12 */
928 dissect_netb_unknown, /* Terminate Trace 0x13 */
929 dissect_netb_data_ack, /* Data Ack 0x14 */
930 dissect_netb_data_first_middle,/* Data First Middle 0x15 */
931 dissect_netb_data_only_last, /* Data Only Last 0x16 */
932 dissect_netb_session_confirm, /* Session Confirm 0x17 */
933 dissect_netb_session_end, /* Session End 0x18 */
934 dissect_netb_session_init, /* Session Initialize 0x19 */
935 dissect_netb_no_receive, /* No Receive 0x1A */
936 dissect_netb_receive_outstanding,/* Receive Outstanding 0x1B */
937 dissect_netb_receive_continue,/* Receive Continue 0x1C */
938 dissect_netb_unknown, /* unknown 0x1D */
939 dissect_netb_unknown, /* unknown 0x1E */
941 dissect_netb_unknown, /* Session Alive 0x1f (nothing to do) */
945 void dissect_netbios(const u_char *pd, int offset, frame_data *fd,
949 const u_char *nb_data_ptr;
950 proto_tree *netb_tree;
952 guint16 hdr_len, command;
953 char name[(NETBIOS_NAME_LEN - 1)*4 + 1];
956 nb_data_ptr = &pd[offset];
958 /* Find NetBIOS marker EFFF, this is done because I have seen an extra LLC */
959 /* byte on our network. This only checks for one extra LLC byte. */
961 if (( *(nb_data_ptr + 2) != 0xff) || ( *(nb_data_ptr + 3) != 0xef)){
963 ++nb_data_ptr; /** marker not found shift one byte */
965 if (( *(nb_data_ptr + 2) != 0xff)
966 || ( *(nb_data_ptr + 3) != 0xef)){
967 if (check_col(fd, COL_PROTOCOL))
968 col_add_str(fd, COL_PROTOCOL, "NetBIOS");
970 if (check_col(fd, COL_INFO)) /* print bad packet */
971 col_add_str(fd, COL_INFO, "Bad packet");
974 ti = proto_tree_add_item(tree, proto_netbios,
975 offset, END_OF_FRAME, NULL);
976 netb_tree = proto_item_add_subtree(ti, ETT_NETB);
978 proto_tree_add_text( netb_tree, offset,
979 END_OF_FRAME, "Data (%u bytes)",
986 /* To do: check for runts, errs, etc. */
988 hdr_len = pletohs( nb_data_ptr + NB_LENGTH);
989 command = *(nb_data_ptr + NB_COMMAND);
992 if (check_col(fd, COL_PROTOCOL))
993 col_add_str(fd, COL_PROTOCOL, "NetBIOS");
995 if (check_col(fd, COL_INFO)) { /* print command name */
998 name_type = get_netbios_name( pd, offset + 12, name);
999 col_add_fstr(fd, COL_INFO, "%s for %s<%02x>",
1000 CommandName[ command], name, name_type);
1004 name_type = get_netbios_name( pd, offset + 28, name);
1005 col_add_fstr(fd, COL_INFO, "%s - %s<%02x>",
1006 CommandName[ command], name, name_type);
1010 if ( command < sizeof( dissect_netb)/ sizeof(void *))
1011 col_add_fstr(fd, COL_INFO, "%s", CommandName[ command]);
1013 col_add_fstr(fd, COL_INFO, "Unknown");
1020 ti = proto_tree_add_item(tree, proto_netbios, offset, END_OF_FRAME, NULL);
1022 netb_tree = proto_item_add_subtree(ti, ETT_NETB);
1024 proto_tree_add_text(netb_tree, offset, 2,
1025 "Header Length: %d", hdr_len);
1027 proto_tree_add_text(netb_tree, offset + 2, 2,
1028 "Delimiter: EFFF (NetBIOS)");
1030 proto_tree_add_text(netb_tree, offset + NB_COMMAND, 1,
1031 "Command: 0x%02x (%s)", command, CommandName[ command]);
1033 /* if command in table range */
1034 if ( command < sizeof( dissect_netb)/ sizeof(void *))
1036 /* branch to handle commands */
1037 (dissect_netb[ command])( nb_data_ptr, offset, fd,
1041 /* Test for SMB data */
1042 if ( (END_OF_FRAME) > ( hdr_len + 4)){ /* if enough data */
1044 nb_data_ptr += hdr_len; /* move past header */
1046 if (( *nb_data_ptr == 0xff) && /* if SMB marker */
1047 ( *(nb_data_ptr + 1) == 'S') &&
1048 ( *(nb_data_ptr + 2) == 'M') &&
1049 ( *(nb_data_ptr + 3) == 'B'))
1051 dissect_smb(pd, offset + hdr_len, fd, tree,
1052 END_OF_FRAME - hdr_len);
1055 /*$$$$ somewhere around here need to check for frame padding */
1060 void proto_register_netbios(void)
1063 proto_netbios = proto_register_protocol("NetBIOS", "netbios");