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.11 1999/11/30 07:45:41 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-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 static gint ett_netb = -1;
88 static gint ett_netb_name = -1;
89 static gint ett_netb_flags = -1;
90 static gint ett_netb_status = -1;
92 /* The strings for the station type, used by get_netbios_name function;
93 many of them came from the file "NetBIOS.txt" in the Zip archive at
95 http://www.net3group.com/ftp/browser.zip
98 static const value_string name_type_vals[] = {
99 {0x00, "Workstation/Redirector"},
101 {0x02, "Workstation/Redirector"},
102 /* not sure what 0x02 is, I'm seeing alot of them however */
103 /* i'm seeing them with workstation/redirection host
105 {0x03, "Messenger service/Main name"},
106 {0x05, "Forwarded name"},
107 {0x06, "RAS Server service"},
108 {0x1b, "PDC Domain name"},
109 {0x1c, "BDC Domain name"},
110 {0x1d, "Master Browser backup"},
111 {0x1e, "Browser Election Service"},
112 {0x1f, "Net DDE Service"},
113 {0x20, "Server service"},
114 {0x21, "RAS client service"},
115 {0x22, "Exchange Interchange (MSMail Connector)"},
116 {0x23, "Exchange Store"},
117 {0x24, "Exchange Directory"},
118 {0x2b, "Lotus Notes Server service"},
119 {0x30, "Modem sharing server service"},
120 {0x31, "Modem sharing client service"},
121 {0x43, "SMS Clients Remote Control"},
122 {0x44, "SMS Administrators Remote Control Tool"},
123 {0x45, "SMS Clients Remote Chat"},
124 {0x46, "SMS Clients Remote Transfer"},
125 {0x4c, "DEC Pathworks TCP/IP Service on Windows NT"},
126 {0x52, "DEC Pathworks TCP/IP Service on Windows NT"},
127 {0x6a, "Microsoft Exchange IMC"},
128 {0x87, "Microsoft Exchange MTA"},
129 {0xbe, "Network Monitor Agent"},
130 {0xbf, "Network Monitor Analyzer"},
136 http://www.s390.ibm.com/bookmgr-cgi/bookmgr.cmd/BOOKS/BK8P7001/CCONTENTS
140 http://ourworld.compuserve.com/homepages/TimothyDEvans/contents.htm
142 for information about the NetBIOS Frame Protocol (which is what this
145 /* the strings for the command types */
147 static char *CommandName[] = {
148 "Add Group Name Query", /* 0x00 */
149 "Add Name Query", /* 0x01 */
150 "Name In Conflict", /* 0x02 */
151 "Status Query", /* 0x03 */
155 "Terminate Trace", /* 0x07 */
156 "Datagram", /* 0x08 */
157 "Broadcast Datagram", /* 0x09 */
158 "Name Query", /* 0x0A */
161 "Add Name Response", /* 0x0D */
162 "Name Recognized", /* 0x0E */
163 "Status Response", /* 0x0F */
167 "Terminate Trace", /* 0x13 */
168 "Data Ack", /* 0x14 */
169 "Data First Middle", /* 0x15 */
170 "Data Only Last", /* 0x16 */
171 "Session Confirm", /* 0x17 */
172 "Session End", /* 0x18 */
173 "Session Initialize", /* 0x19 */
174 "No Receive", /* 0x1a */
175 "Receive Outstanding", /* 0x1b */
176 "Receive Continue", /* 0x1c */
179 "Session Alive", /* 0x1f */
182 void capture_netbios(const u_char *pd, int offset, guint32 cap_len,
190 process_netbios_name(const u_char *name_ptr, char *name_ret)
193 int name_type = *(name_ptr + NETBIOS_NAME_LEN - 1);
195 static const char hex_digits[16] = "0123456780abcdef";
197 for (i = 0; i < NETBIOS_NAME_LEN - 1; i++) {
198 name_char = *name_ptr++;
199 if (name_char >= ' ' && name_char <= '~')
200 *name_ret++ = name_char;
202 /* It's not printable; show it as <XX>, where
203 XX is the value in hex. */
205 *name_ret++ = hex_digits[(name_char >> 4)];
206 *name_ret++ = hex_digits[(name_char & 0x0F)];
214 int get_netbios_name(const u_char *pd, int offset, char *name_ret)
216 {/* Extract the name string and name type. Return the name string in */
217 /* name_ret and return the name_type. */
218 if (!BYTES_ARE_IN_FRAME(offset, NETBIOS_NAME_LEN)) {
220 * Name goes past end of captured data in packet.
224 return process_netbios_name(&pd[offset], name_ret);
228 * Get a string describing the type of a NetBIOS name.
231 netbios_name_type_descr(int name_type)
233 return val_to_str(name_type, name_type_vals, "Unknown");
236 gboolean netbios_add_name(char* label, const u_char *pd, int offset,
239 {/* add a name field display tree. Display the name and station type in sub-tree */
241 proto_tree *field_tree;
243 char name_str[(NETBIOS_NAME_LEN - 1)*4 + 1];
247 /* decode the name field */
248 name_type = get_netbios_name(pd, offset, name_str);
251 * Name goes past end of captured data in packet.
256 name_type_str = netbios_name_type_descr(name_type);
257 tf = proto_tree_add_text( tree, offset, NETBIOS_NAME_LEN,
258 "%s: %s<%02x> (%s)", label, name_str, name_type, name_type_str);
260 field_tree = proto_item_add_subtree( tf, ett_netb_name);
262 proto_tree_add_text( field_tree, offset, 15, "%s",
264 proto_tree_add_text( field_tree, offset + 15, 1,
265 "0x%02x (%s)", name_type, name_type_str);
270 static void netbios_data_first_middle_flags(const u_char *pd, proto_tree *tree,
274 proto_tree *field_tree;
276 guint flags = pd[offset];
277 /* decode the flag field for Data First Middle packet*/
279 tf = proto_tree_add_text(tree, offset, 1,
280 "Flags: 0x%02x", flags);
281 field_tree = proto_item_add_subtree(tf, ett_netb_flags);
283 proto_tree_add_text(field_tree, offset, 1, "%s",
284 decode_boolean_bitfield(flags, 0x08, 8,
285 "Acknowledge_included", "No Acknowledge_included"));
287 proto_tree_add_text(field_tree, offset, 1, "%s",
288 decode_boolean_bitfield(flags, 0x02, 8,
289 "No acknowledgement expected", "Acknowledgement expected"));
291 proto_tree_add_text(field_tree, offset, 1, "%s",
292 decode_boolean_bitfield(flags, 0x01, 8,
293 "RECEIVE_CONTINUE requested", "RECEIVE_CONTINUE not requested"));
297 static void netbios_data_only_flags(const u_char *pd, proto_tree *tree,
300 proto_tree *field_tree;
302 guint flags = pd[offset];
303 /* decode the flag field for Data Only Last packet*/
305 tf = proto_tree_add_text(tree, offset, 1,
306 "Flags: 0x%02x", flags);
307 field_tree = proto_item_add_subtree(tf, ett_netb_flags);
309 proto_tree_add_text(field_tree, offset, 1, "%s",
310 decode_boolean_bitfield(flags, 0x08, 8,
311 "ACKNOWLEDGE_INCLUDED", "No ACKNOWLEDGE_INCLUDED"));
313 proto_tree_add_text(field_tree, offset, 1, "%s",
314 decode_boolean_bitfield(flags, 0x04, 8,
315 "ACKNOWLEDGE_WITH_DATA_ALLOWED", "No ACKNOWLEDGE_WITH_DATA_ALLOWED"));
317 proto_tree_add_text(field_tree, offset, 1, "%s",
318 decode_boolean_bitfield(flags, 0x02, 8,
319 "No acknowledgement expected", "Acknowledgement expected"));
323 static void netbios_add_ses_confirm_flags(const u_char *pd, proto_tree *tree,
326 proto_tree *field_tree;
328 guint flags = pd[offset];
329 /* decode the flag field for Session Confirm packet */
331 tf = proto_tree_add_text(tree, offset, 1,
332 "Flags: 0x%02x", flags);
333 field_tree = proto_item_add_subtree( tf, ett_netb_flags);
335 proto_tree_add_text(field_tree, offset, 1, "%s",
336 decode_boolean_bitfield(flags, 0x80, 8,
337 "Can handle SEND.NO.ACK", "Can't handle SEND.NO.ACK"));
339 proto_tree_add_text(field_tree, offset, 1, "%s",
340 decode_boolean_bitfield(flags, 0x01, 8,
341 "NetBIOS 2.00 or higher", "NetBIOS 1.xx"));
345 static void netbios_add_session_init_flags(const u_char *pd, proto_tree *tree,
348 proto_tree *field_tree;
350 guint flags = pd[offset];
351 /* decode the flag field for Session Init packet */
353 tf = proto_tree_add_text(tree, offset, 1,
354 "Flags: 0x%02x", flags);
355 field_tree = proto_item_add_subtree(tf, ett_netb_flags);
357 proto_tree_add_text(field_tree, offset, 1, "%s",
358 decode_boolean_bitfield(flags, 0x80, 8,
359 "Can handle SEND.NO.ACK", "Can't handle SEND.NO.ACK"));
361 proto_tree_add_text(field_tree, offset, 1, "%s",
362 decode_numeric_bitfield(flags, 0x0E, 8,
363 "Largest frame value = %u"));
365 proto_tree_add_text(field_tree, offset, 1, "%s",
366 decode_boolean_bitfield(flags, 0x01, 8,
367 "NetBIOS 2.00 or higher", "NetBIOS 1.xx"));
371 static void netbios_no_receive_flags(const u_char *pd, proto_tree *tree,
375 proto_tree *field_tree;
377 guint flags = pd[offset];
378 /* decode the flag field for No Receive packet*/
380 tf = proto_tree_add_text(tree, offset, 1,
381 "Flags: 0x%02x", flags);
384 field_tree = proto_item_add_subtree(tf, ett_netb_flags);
385 proto_tree_add_text(field_tree, offset, 1, "%s",
386 decode_boolean_bitfield(flags, 0x02, 8,
387 "SEND.NO.ACK data not received", NULL));
392 /************************************************************************/
394 /* The routines to display the netbios field values in the tree */
396 /************************************************************************/
399 static void nb_xmit_corrl(const u_char *pd, int offset, proto_tree *tree)
401 {/* display the transmit correlator */
403 proto_tree_add_text( tree, offset + NB_XMIT_CORL, 2,
404 "Transmit Correlator: 0x%04x", pletohs(&pd[offset + NB_XMIT_CORL]));
408 static void nb_resp_corrl(const u_char *pd, int offset, proto_tree *tree)
410 {/* display the response correlator */
412 proto_tree_add_text( tree, offset + NB_RESP_CORL, 2,
413 "Response Correlator: 0x%04x", pletohs(&pd[offset + NB_RESP_CORL]));
417 static void nb_call_name_type(const u_char *pd, int offset,
420 {/* display the call name type */
422 int name_type_value = pd[offset + NB_CALL_NAME_TYPE];
424 switch (name_type_value) {
427 proto_tree_add_text( tree, offset + NB_CALL_NAME_TYPE, 1,
428 "Caller's Name Type: Unique name");
432 proto_tree_add_text( tree, offset + NB_CALL_NAME_TYPE, 1,
433 "Caller's Name Type: Group name");
437 proto_tree_add_text( tree, offset + NB_CALL_NAME_TYPE, 1,
438 "Caller's Name Type: 0x%02x (should be 0 or 1)",
445 static void nb_local_session(const u_char *pd, int offset,
448 {/* add the local session to tree */
450 proto_tree_add_text(tree, offset + NB_LOCAL_SES, 1,
451 "Local Session No.: 0x%02x", pd[offset + NB_LOCAL_SES]);
455 static void nb_remote_session(const u_char *pd, int offset,
458 {/* add the remote session to tree */
460 proto_tree_add_text(tree, offset + NB_RMT_SES, 1,
461 "Remote Session No.: 0x%02x", pd[offset + NB_RMT_SES]);
465 static void nb_data2(char *label, int len, const u_char *pd, int offset,
468 {/* add the DATA2 to tree with format string = label and length of len */
470 int value = (len == 1 ? pd[offset + NB_DATA2]
471 : pletohs(&pd[offset + NB_DATA2]));
473 proto_tree_add_text(tree, offset + NB_DATA2, len, label, value);
476 static void nb_resync_indicator(const u_char *pd, int offset,
479 guint16 resync_indicator = pletohs(&pd[offset + NB_DATA2]);
481 switch (resync_indicator) {
484 proto_tree_add_text(tree, offset + NB_DATA2, 2,
485 "Re-sync indicator: Not first Data First Middle following Receive Outstanding");
489 proto_tree_add_text(tree, offset + NB_DATA2, 2,
490 "Re-sync indicator: First Data First Middle following Receive Outstanding");
494 proto_tree_add_text(tree, offset + NB_DATA2, 2,
495 "Re-sync indicator: 0x%04x", resync_indicator);
500 /************************************************************************/
502 /* The routines called by the top level to handle individual commands */
504 /************************************************************************/
506 static void dissect_netb_unknown(const u_char *data_ptr, int offset,
507 frame_data *fd, proto_tree *tree)
509 {/* Handle any unknow commands, do nothing */
511 /* dissect_data( data_ptr, offset + NB_COMMAND + 1, fd, tree); */
515 static void dissect_netb_add_group_name(const u_char *pd, int offset,
516 frame_data *fd, proto_tree *tree)
518 {/* Handle the ADD GROUP NAME QUERY command */
520 nb_resp_corrl(pd, offset, tree);
522 netbios_add_name("Group name to add", pd, offset + NB_SENDER_NAME,
527 static void dissect_netb_add_name(const u_char *pd, int offset,
528 frame_data *fd, proto_tree *tree)
530 {/* Handle the ADD NAME QUERY command */
532 nb_resp_corrl(pd, offset, tree);
534 netbios_add_name("Name to add", pd, offset + NB_SENDER_NAME, tree);
538 static void dissect_netb_name_in_conflict(const u_char *pd, int offset,
539 frame_data *fd, proto_tree *tree)
541 {/* Handle the NAME IN CONFLICT command */
543 if (!netbios_add_name("Name In Conflict", pd, offset + NB_RECVER_NAME,
546 netbios_add_name("Sender's Name", pd, offset + NB_SENDER_NAME,
551 static void dissect_netb_status_query(const u_char *pd, int offset,
552 frame_data *fd, proto_tree *tree)
554 {/* Handle the STATUS QUERY command */
555 guint8 status_request = pd[offset + NB_DATA1];
557 switch (status_request) {
560 proto_tree_add_text(tree, offset + NB_DATA1, 1,
561 "Status request: NetBIOS 1.x or 2.0");
565 proto_tree_add_text(tree, offset + NB_DATA1, 1,
566 "Status request: NetBIOS 2.1, initial status request");
570 proto_tree_add_text(tree, offset + NB_DATA1, 1,
571 "Status request: NetBIOS 2.1, %u names received so far",
575 nb_data2("Length of status buffer: %u", 2, pd, offset, tree);
576 nb_resp_corrl(pd, offset, tree);
577 if (!netbios_add_name("Receiver's Name", pd, offset + NB_RECVER_NAME,
580 netbios_add_name("Sender's Name", pd, offset + NB_SENDER_NAME,
585 static u_char zeroes[10];
587 static void dissect_netb_datagram(const u_char *pd, int offset,
588 frame_data *fd, proto_tree *tree)
590 {/* Handle the DATAGRAM command */
592 if (!netbios_add_name("Receiver's Name", pd, offset + NB_RECVER_NAME,
595 /* Weird. In some datagrams, this is 10 octets of 0, followed
596 by a MAC address.... */
597 if (memcmp(&pd[offset + NB_SENDER_NAME], zeroes, 10) == 0) {
598 proto_tree_add_text( tree, offset + NB_SENDER_NAME + 10, 6,
599 "Sender's MAC Address: %s",
600 ether_to_str(&pd[offset + NB_SENDER_NAME + 10]));
602 netbios_add_name("Sender's Name", pd, offset + NB_SENDER_NAME,
608 static void dissect_netb_datagram_bcast(const u_char *pd, int offset,
609 frame_data *fd, proto_tree *tree)
611 {/* Handle the DATAGRAM BROADCAST command */
613 /* We assume the same weirdness can happen here.... */
614 if (memcmp(&pd[offset + NB_SENDER_NAME], zeroes, 10) == 0) {
615 proto_tree_add_text( tree, offset + NB_SENDER_NAME + 10, 6,
616 "Sender's Node Address: %s",
617 ether_to_str(&pd[offset + NB_SENDER_NAME + 10]));
619 netbios_add_name("Sender's Name", pd, offset + NB_SENDER_NAME,
625 static void dissect_netb_name_query(const u_char *pd, int offset,
626 frame_data *fd, proto_tree *tree)
628 {/* Handle the NAME QUERY command */
629 guint8 local_session_number = pd[offset + NB_DATA2];
631 if (local_session_number == 0) {
632 proto_tree_add_text( tree, offset + NB_DATA2, 1,
633 "Local Session No.: 0 (FIND.NAME request)");
635 proto_tree_add_text( tree, offset + NB_DATA2, 1,
636 "Local Session No.: 0x%02x", local_session_number);
638 nb_call_name_type(pd, offset, tree);
639 nb_resp_corrl(pd, offset, tree);
640 if (!netbios_add_name("Query Name", pd, offset + NB_RECVER_NAME, tree))
642 if (local_session_number != 0) {
643 netbios_add_name("Sender's Name", pd, offset + NB_SENDER_NAME,
649 static void dissect_netb_add_name_resp(const u_char *pd, int offset,
650 frame_data *fd, proto_tree *tree)
652 {/* Handle the ADD NAME RESPONSE command */
653 guint8 status = pd[offset + NB_DATA1];
654 guint16 name_type = pletohs(&pd[offset + NB_DATA2]);
659 proto_tree_add_text( tree, offset + NB_DATA1, 1,
660 "Status: Add name not in process");
664 proto_tree_add_text( tree, offset + NB_DATA1, 1,
665 "Status: Add name in process");
669 proto_tree_add_text( tree, offset + NB_DATA1, 1,
670 "Status: 0x%02x (should be 0 or 1)", status);
677 proto_tree_add_text( tree, offset + NB_DATA2, 2,
678 "Name type: Unique name");
682 proto_tree_add_text( tree, offset + NB_DATA2, 2,
683 "Name type: Group name");
687 proto_tree_add_text( tree, offset + NB_DATA2, 2,
688 "Name type: 0x%04x (should be 0 or 1)", name_type);
692 nb_xmit_corrl(pd, offset, tree);
693 if (!netbios_add_name("Name to be added", pd, offset + NB_RECVER_NAME,
696 netbios_add_name("Name to be added", pd, offset + NB_SENDER_NAME,
701 static void dissect_netb_name_resp(const u_char *pd, int offset,
702 frame_data *fd, proto_tree *tree)
704 {/* Handle the NAME RECOGNIZED command */
705 guint8 local_session_number = pd[offset + NB_DATA2];
707 switch (local_session_number) {
710 proto_tree_add_text( tree, offset + NB_DATA2, 1,
711 "State of name: No LISTEN pending, or FIND.NAME response");
715 proto_tree_add_text( tree, offset + NB_DATA2, 1,
716 "State of name: LISTEN pending, but insufficient resources to establish session");
720 proto_tree_add_text( tree, offset + NB_DATA2, 1,
721 "Local Session No.: 0x%02x", local_session_number);
724 nb_call_name_type(pd, offset, tree);
725 nb_xmit_corrl(pd, offset, tree);
726 if (local_session_number != 0x00 && local_session_number != 0xFF)
727 nb_resp_corrl(pd, offset, tree);
728 if (!netbios_add_name("Receiver's Name", pd, offset + NB_RECVER_NAME,
731 if (local_session_number != 0x00 && local_session_number != 0xFF) {
732 netbios_add_name("Sender's Name", pd, offset + NB_SENDER_NAME,
738 static void dissect_netb_status_resp(const u_char *pd, int offset,
739 frame_data *fd, proto_tree *tree)
741 {/* Handle the STATUS RESPONSE command */
742 guint8 status_response = pd[offset + NB_DATA1];
744 proto_tree *data2_tree;
747 nb_call_name_type(pd, offset, tree);
748 if (status_response == 0) {
749 proto_tree_add_text(tree, offset + NB_DATA1, 1,
750 "Status response: NetBIOS 1.x or 2.0");
752 proto_tree_add_text(tree, offset + NB_DATA1, 1,
753 "Status response: NetBIOS 2.1, %u names sent so far",
756 data2 = pletohs(&pd[offset + NB_DATA2]);
757 td2 = proto_tree_add_text(tree, offset + NB_DATA2, 2, "Status: 0x04x",
759 data2_tree = proto_item_add_subtree(td2, ett_netb_status);
760 if (data2 & 0x8000) {
761 proto_tree_add_text(data2_tree, offset, 2, "%s",
762 decode_boolean_bitfield(data2, 0x8000, 8*2,
763 "Data length exceeds maximum frame size", NULL));
765 if (data2 & 0x4000) {
766 proto_tree_add_text(data2_tree, offset, 2, "%s",
767 decode_boolean_bitfield(data2, 0x4000, 8*2,
768 "Data length exceeds user's buffer", NULL));
770 proto_tree_add_text(data2_tree, offset, 2, "%s",
771 decode_numeric_bitfield(data2, 0x3FFF, 2*8,
772 "Status data length = %u"));
773 nb_xmit_corrl(pd, offset, tree);
774 if (!netbios_add_name("Receiver's Name", pd, offset + NB_RECVER_NAME,
777 netbios_add_name("Sender's Name", pd, offset + NB_SENDER_NAME,
782 static void dissect_netb_data_ack(const u_char *pd, int offset,
783 frame_data *fd, proto_tree *tree)
785 {/* Handle the DATA ACK command */
787 nb_xmit_corrl(pd, offset, tree);
788 nb_remote_session(pd, offset, tree);
789 nb_local_session(pd, offset, tree);
793 static void dissect_netb_data_first_middle(const u_char *pd, int offset,
794 frame_data *fd, proto_tree *tree)
796 {/* Handle the DATA FIRST MIDDLE command */
798 netbios_data_first_middle_flags(pd, tree, offset + NB_FLAGS);
800 nb_resync_indicator(pd, offset, tree);
801 nb_xmit_corrl(pd, offset, tree);
802 nb_resp_corrl(pd, offset, tree);
803 nb_remote_session(pd, offset, tree);
804 nb_local_session(pd, offset, tree);
808 static void dissect_netb_data_only_last(const u_char *pd, int offset,
809 frame_data *fd, proto_tree *tree)
811 {/* Handle the DATA ONLY LAST command */
813 netbios_data_only_flags(pd, tree, offset + NB_FLAGS);
815 nb_resync_indicator(pd, offset, tree);
816 nb_xmit_corrl(pd, offset, tree);
817 nb_resp_corrl(pd, offset, tree);
818 nb_remote_session(pd, offset, tree);
819 nb_local_session(pd, offset, tree);
823 static void dissect_netb_session_confirm(const u_char *pd, int offset,
824 frame_data *fd, proto_tree *tree)
826 {/* Handle the SESSION CONFIRM command */
828 netbios_add_ses_confirm_flags(pd, tree, offset + NB_FLAGS);
830 nb_data2("Max data recv size: %u", 2, pd, offset, tree);
831 nb_xmit_corrl(pd, offset, tree);
832 nb_resp_corrl(pd, offset, tree);
833 nb_remote_session(pd, offset, tree);
834 nb_local_session(pd, offset, tree);
838 static void dissect_netb_session_end(const u_char *pd, int offset,
839 frame_data *fd, proto_tree *tree)
841 {/* Handle the SESSION END command */
842 guint16 termination_indicator = pletohs(&pd[offset + NB_DATA2]);
844 switch (termination_indicator) {
847 proto_tree_add_text( tree, offset + NB_DATA2, 2,
848 "Termination indicator: Normal session end");
852 proto_tree_add_text( tree, offset + NB_DATA2, 2,
853 "Termination indicator: Abormal session end");
857 proto_tree_add_text( tree, offset + NB_DATA2, 2,
858 "Termination indicator: 0x%04x (should be 0x0000 or 0x0001)",
859 termination_indicator);
863 nb_remote_session(pd, offset, tree);
864 nb_local_session(pd, offset, tree);
868 static void dissect_netb_session_init(const u_char *pd, int offset,
869 frame_data *fd, proto_tree *tree)
871 {/* Handle the SESSION INITIALIZE command */
873 netbios_add_session_init_flags(pd, tree, offset + NB_FLAGS);
875 nb_data2("Max data recv size: %u", 2, pd, offset, tree);
876 nb_resp_corrl(pd, offset, tree);
877 nb_xmit_corrl(pd, offset, tree);
878 nb_remote_session(pd, offset, tree);
879 nb_local_session(pd, offset, tree);
883 static void dissect_netb_no_receive(const u_char *pd, int offset,
884 frame_data *fd, proto_tree *tree)
886 {/* Handle the NO RECEIVE command */
888 netbios_no_receive_flags(pd, tree, offset + NB_FLAGS);
890 nb_data2("Number of data bytes accepted: %u", 2, pd, offset, tree);
891 nb_remote_session(pd, offset, tree);
892 nb_local_session(pd, offset, tree);
896 static void dissect_netb_receive_outstanding(const u_char *pd, int offset,
897 frame_data *fd, proto_tree *tree)
899 {/* Handle the RECEIVE OUTSTANDING command */
901 nb_data2("Number of data bytes accepted: %u", 2, pd, offset, tree);
902 nb_remote_session(pd, offset, tree);
903 nb_local_session(pd, offset, tree);
907 static void dissect_netb_receive_continue(const u_char *pd, int offset,
908 frame_data *fd, proto_tree *tree)
910 {/* Handle the RECEIVE CONTINUE command */
912 nb_xmit_corrl(pd, offset, tree);
913 nb_remote_session(pd, offset, tree);
914 nb_local_session(pd, offset, tree);
918 /************************************************************************/
920 /* The table routines called by the top level to handle commands */
922 /************************************************************************/
925 void (*dissect_netb[])(const u_char *, int, frame_data *, proto_tree *) = {
927 dissect_netb_add_group_name, /* Add Group Name 0x00 */
928 dissect_netb_add_name, /* Add Name 0x01 */
929 dissect_netb_name_in_conflict,/* Name In Conflict 0x02 */
930 dissect_netb_status_query, /* Status Query 0x03 */
931 dissect_netb_unknown, /* unknown 0x04 */
932 dissect_netb_unknown, /* unknown 0x05 */
933 dissect_netb_unknown, /* unknown 0x06 */
934 dissect_netb_unknown, /* Terminate Trace 0x07 */
935 dissect_netb_datagram, /* Datagram 0x08 */
936 dissect_netb_datagram_bcast, /* Datagram Broadcast 0x09 */
937 dissect_netb_name_query, /* Name Query 0x0A */
938 dissect_netb_unknown, /* unknown 0x0B */
939 dissect_netb_unknown, /* unknown 0x0C */
940 dissect_netb_add_name_resp, /* Add Name Response 0x0D */
941 dissect_netb_name_resp, /* Name Recognized 0x0E */
942 dissect_netb_status_resp, /* Status Response 0x0F */
943 dissect_netb_unknown, /* unknown 0x10 */
944 dissect_netb_unknown, /* unknown 0x11 */
945 dissect_netb_unknown, /* unknown 0x12 */
946 dissect_netb_unknown, /* Terminate Trace 0x13 */
947 dissect_netb_data_ack, /* Data Ack 0x14 */
948 dissect_netb_data_first_middle,/* Data First Middle 0x15 */
949 dissect_netb_data_only_last, /* Data Only Last 0x16 */
950 dissect_netb_session_confirm, /* Session Confirm 0x17 */
951 dissect_netb_session_end, /* Session End 0x18 */
952 dissect_netb_session_init, /* Session Initialize 0x19 */
953 dissect_netb_no_receive, /* No Receive 0x1A */
954 dissect_netb_receive_outstanding,/* Receive Outstanding 0x1B */
955 dissect_netb_receive_continue,/* Receive Continue 0x1C */
956 dissect_netb_unknown, /* unknown 0x1D */
957 dissect_netb_unknown, /* unknown 0x1E */
959 dissect_netb_unknown, /* Session Alive 0x1f (nothing to do) */
963 void dissect_netbios(const u_char *pd, int offset, frame_data *fd,
967 proto_tree *netb_tree;
969 guint16 hdr_len, command;
970 char name[(NETBIOS_NAME_LEN - 1)*4 + 1];
973 /* Find NetBIOS marker EFFF, this is done because I have seen an extra LLC */
974 /* byte on our network. This only checks for one extra LLC byte. */
976 if (( pd[offset + 2] != 0xff) || ( pd[offset + 3] != 0xef)){
978 if (( pd[offset + 2] != 0xff)
979 || ( pd[offset + 3] != 0xef)){
980 if (check_col(fd, COL_PROTOCOL))
981 col_add_str(fd, COL_PROTOCOL, "NetBIOS");
983 if (check_col(fd, COL_INFO)) /* print bad packet */
984 col_add_str(fd, COL_INFO, "Bad packet");
987 ti = proto_tree_add_item(tree, proto_netbios,
988 offset, END_OF_FRAME, NULL);
989 netb_tree = proto_item_add_subtree(ti, ett_netb);
991 proto_tree_add_text( netb_tree, offset,
992 END_OF_FRAME, "Data (%u bytes)",
999 /* To do: check for runts, errs, etc. */
1001 hdr_len = pletohs(&pd[offset + NB_LENGTH]);
1002 command = pd[offset + NB_COMMAND];
1004 if (check_col(fd, COL_PROTOCOL))
1005 col_add_str(fd, COL_PROTOCOL, "NetBIOS");
1007 if (check_col(fd, COL_INFO)) { /* print command name */
1008 switch ( command ) {
1010 name_type = get_netbios_name( pd, offset + 12, name);
1011 col_add_fstr(fd, COL_INFO, "%s for %s<%02x>",
1012 CommandName[ command], name, name_type);
1016 name_type = get_netbios_name( pd, offset + 28, name);
1017 col_add_fstr(fd, COL_INFO, "%s - %s<%02x>",
1018 CommandName[ command], name, name_type);
1022 if ( command < sizeof( dissect_netb)/ sizeof(void *))
1023 col_add_fstr(fd, COL_INFO, "%s", CommandName[ command]);
1025 col_add_fstr(fd, COL_INFO, "Unknown");
1032 ti = proto_tree_add_item(tree, proto_netbios, offset, END_OF_FRAME, NULL);
1034 netb_tree = proto_item_add_subtree(ti, ett_netb);
1036 proto_tree_add_text(netb_tree, offset, 2,
1037 "Header Length: %d", hdr_len);
1039 proto_tree_add_text(netb_tree, offset + 2, 2,
1040 "Delimiter: EFFF (NetBIOS)");
1042 proto_tree_add_text(netb_tree, offset + NB_COMMAND, 1,
1043 "Command: 0x%02x (%s)", command, CommandName[ command]);
1045 /* if command in table range */
1046 if ( command < sizeof( dissect_netb)/ sizeof(void *))
1048 /* branch to handle commands */
1049 (dissect_netb[ command])( pd, offset, fd,
1053 /* Test for SMB data */
1054 if ( (END_OF_FRAME) > ( hdr_len + 4)){ /* if enough data */
1056 offset += hdr_len; /* move past header */
1058 if (( pd[offset + 0] == 0xff) && /* if SMB marker */
1059 ( pd[offset + 1] == 'S') &&
1060 ( pd[offset + 2] == 'M') &&
1061 ( pd[offset + 3] == 'B'))
1063 dissect_smb(pd, offset, fd, tree,
1064 END_OF_FRAME - hdr_len);
1067 /*$$$$ somewhere around here need to check for frame padding */
1072 void proto_register_netbios(void)
1074 static gint *ett[] = {
1081 proto_netbios = proto_register_protocol("NetBIOS", "netbios");
1082 proto_register_subtree_array(ett, array_length(ett));