/src/wireshark/epan/dissectors/packet-netbios.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* packet-netbios.c |
2 | | * Routines for NetBIOS protocol packet disassembly |
3 | | * Jeff Foster <jfoste@woodward.com> |
4 | | * Copyright 1999 Jeffrey C. Foster |
5 | | * |
6 | | * derived from the packet-nbns.c |
7 | | * |
8 | | * Wireshark - Network traffic analyzer |
9 | | * By Gerald Combs <gerald@wireshark.org> |
10 | | * Copyright 1998 Gerald Combs |
11 | | * |
12 | | * SPDX-License-Identifier: GPL-2.0-or-later |
13 | | */ |
14 | | |
15 | | #include "config.h" |
16 | | |
17 | | #include <epan/packet.h> |
18 | | #include <epan/capture_dissectors.h> |
19 | | #include <epan/llcsaps.h> |
20 | | #include <epan/reassemble.h> |
21 | | #include <epan/prefs.h> |
22 | | #include <epan/expert.h> |
23 | | #include <epan/tfs.h> |
24 | | #include <wsutil/array.h> |
25 | | #include "packet-netbios.h" |
26 | | |
27 | | void proto_register_netbios(void); |
28 | | void proto_reg_handoff_netbios(void); |
29 | | |
30 | | static dissector_handle_t netbios_handle; |
31 | | static capture_dissector_handle_t netbios_cap_handle; |
32 | | |
33 | | /* Netbios command numbers */ |
34 | 0 | #define NB_ADD_GROUP 0x00 |
35 | 0 | #define NB_ADD_NAME 0x01 |
36 | | #define NB_NAME_IN_CONFLICT 0x02 |
37 | | #define NB_STATUS_QUERY 0x03 |
38 | | #define NB_TERMINATE_TRACE_R 0x07 |
39 | 0 | #define NB_DATAGRAM 0x08 |
40 | 0 | #define NB_DATAGRAM_BCAST 0x09 |
41 | 0 | #define NB_NAME_QUERY 0x0a |
42 | | #define NB_ADD_NAME_RESP 0x0d |
43 | 0 | #define NB_NAME_RESP 0x0e |
44 | | #define NB_STATUS_RESP 0x0f |
45 | | #define NB_TERMINATE_TRACE_LR 0x13 |
46 | | #define NB_DATA_ACK 0x14 |
47 | 0 | #define NB_DATA_FIRST_MIDDLE 0x15 |
48 | 0 | #define NB_DATA_ONLY_LAST 0x16 |
49 | | #define NB_SESSION_CONFIRM 0x17 |
50 | | #define NB_SESSION_END 0x18 |
51 | | #define NB_SESSION_INIT 0x19 |
52 | | #define NB_NO_RECEIVE 0x1a |
53 | | #define NB_RECEIVE_OUTSTANDING 0x1b |
54 | | #define NB_RECEIVE_CONTINUE 0x1c |
55 | | #define NB_KEEP_ALIVE 0x1f |
56 | | |
57 | | /* Offsets of fields in the NetBIOS header. */ |
58 | 0 | #define NB_LENGTH 0 |
59 | | #define NB_DELIMITER 2 |
60 | 0 | #define NB_COMMAND 4 |
61 | 0 | #define NB_FLAGS 5 |
62 | 0 | #define NB_DATA1 5 |
63 | | #define NB_RESYNC 6 |
64 | 0 | #define NB_DATA2 6 |
65 | 0 | #define NB_CALL_NAME_TYPE 7 |
66 | 0 | #define NB_XMIT_CORL 8 |
67 | 0 | #define NB_RESP_CORL 10 |
68 | 0 | #define NB_RMT_SES 12 |
69 | 0 | #define NB_LOCAL_SES 13 |
70 | 0 | #define NB_RECVER_NAME 12 |
71 | 0 | #define NB_SENDER_NAME 28 |
72 | | |
73 | | |
74 | | static int proto_netbios; |
75 | | static int hf_netb_cmd; |
76 | | static int hf_netb_hdr_len; |
77 | | static int hf_netb_delimiter; |
78 | | static int hf_netb_xmit_corrl; |
79 | | static int hf_netb_resp_corrl; |
80 | | static int hf_netb_call_name_type; |
81 | | static int hf_netb_version; |
82 | | static int hf_netbios_no_receive_flags; |
83 | | static int hf_netbios_no_receive_flags_send_no_ack; |
84 | | static int hf_netb_largest_frame; |
85 | | static int hf_netb_nb_name; |
86 | | static int hf_netb_nb_name_type; |
87 | | static int hf_netb_status_buffer_len; |
88 | | static int hf_netb_status; |
89 | | static int hf_netb_name_type; |
90 | | static int hf_netb_max_data_recv_size; |
91 | | static int hf_netb_termination_indicator; |
92 | | static int hf_netb_num_data_bytes_accepted; |
93 | | static int hf_netb_local_ses_no; |
94 | | static int hf_netb_remote_ses_no; |
95 | | static int hf_netb_flags; |
96 | | static int hf_netb_flags_send_no_ack; |
97 | | static int hf_netb_flags_ack; |
98 | | static int hf_netb_flags_ack_with_data; |
99 | | static int hf_netb_flags_ack_expected; |
100 | | static int hf_netb_flags_recv_cont_req; |
101 | | static int hf_netb_data2; |
102 | | static int hf_netb_data2_frame; |
103 | | static int hf_netb_data2_user; |
104 | | static int hf_netb_data2_status; |
105 | | static int hf_netb_datagram_mac; |
106 | | static int hf_netb_datagram_bcast_mac; |
107 | | static int hf_netb_resync_indicator; |
108 | | static int hf_netb_status_request; |
109 | | static int hf_netb_local_session_no; |
110 | | static int hf_netb_state_of_name; |
111 | | static int hf_netb_status_response; |
112 | | static int hf_netb_fragments; |
113 | | static int hf_netb_fragment; |
114 | | static int hf_netb_fragment_overlap; |
115 | | static int hf_netb_fragment_overlap_conflict; |
116 | | static int hf_netb_fragment_multiple_tails; |
117 | | static int hf_netb_fragment_too_long_fragment; |
118 | | static int hf_netb_fragment_error; |
119 | | static int hf_netb_fragment_count; |
120 | | static int hf_netb_reassembled_length; |
121 | | |
122 | | static int ett_netb; |
123 | | static int ett_netb_name; |
124 | | static int ett_netb_flags; |
125 | | static int ett_netb_status; |
126 | | static int ett_netb_fragments; |
127 | | static int ett_netb_fragment; |
128 | | |
129 | | static expert_field ei_netb_unknown_command_data; |
130 | | |
131 | | static const fragment_items netbios_frag_items = { |
132 | | &ett_netb_fragment, |
133 | | &ett_netb_fragments, |
134 | | &hf_netb_fragments, |
135 | | &hf_netb_fragment, |
136 | | &hf_netb_fragment_overlap, |
137 | | &hf_netb_fragment_overlap_conflict, |
138 | | &hf_netb_fragment_multiple_tails, |
139 | | &hf_netb_fragment_too_long_fragment, |
140 | | &hf_netb_fragment_error, |
141 | | &hf_netb_fragment_count, |
142 | | NULL, |
143 | | &hf_netb_reassembled_length, |
144 | | /* Reassembled data field */ |
145 | | NULL, |
146 | | "fragments" |
147 | | }; |
148 | | |
149 | | /* The strings for the station type, used by get_netbios_name function; |
150 | | many of them came from the file "NetBIOS.txt" in the Zip archive at |
151 | | |
152 | | http://www.net3group.com/ftp/browser.zip |
153 | | */ |
154 | | |
155 | | static const value_string nb_name_type_vals[] = { |
156 | | {0x00, "Workstation/Redirector"}, |
157 | | {0x01, "Browser"}, |
158 | | {0x02, "Workstation/Redirector"}, |
159 | | /* not sure what 0x02 is, I'm seeing a lot of them however */ |
160 | | /* I'm seeing them with workstation/redirection host |
161 | | announcements */ |
162 | | {0x03, "Messenger service/Main name"}, |
163 | | {0x05, "Forwarded name"}, |
164 | | {0x06, "RAS Server service"}, |
165 | | {0x1b, "Domain Master Browser"}, |
166 | | {0x1c, "Domain Controllers"}, |
167 | | {0x1d, "Local Master Browser"}, |
168 | | {0x1e, "Browser Election Service"}, |
169 | | {0x1f, "Net DDE Service"}, |
170 | | {0x20, "Server service"}, |
171 | | {0x21, "RAS client service"}, |
172 | | {0x22, "Exchange Interchange (MSMail Connector)"}, |
173 | | {0x23, "Exchange Store"}, |
174 | | {0x24, "Exchange Directory"}, |
175 | | {0x2b, "Lotus Notes Server service"}, |
176 | | {0x30, "Modem sharing server service"}, |
177 | | {0x31, "Modem sharing client service"}, |
178 | | {0x43, "SMS Clients Remote Control"}, |
179 | | {0x44, "SMS Administrators Remote Control Tool"}, |
180 | | {0x45, "SMS Clients Remote Chat"}, |
181 | | {0x46, "SMS Clients Remote Transfer"}, |
182 | | {0x4c, "DEC Pathworks TCP/IP Service on Windows NT"}, |
183 | | {0x52, "DEC Pathworks TCP/IP Service on Windows NT"}, |
184 | | {0x6a, "Microsoft Exchange IMC"}, |
185 | | {0x87, "Microsoft Exchange MTA"}, |
186 | | {0xbe, "Network Monitor Agent"}, |
187 | | {0xbf, "Network Monitor Analyzer"}, |
188 | | {0x00, NULL} |
189 | | }; |
190 | | static value_string_ext nb_name_type_vals_ext = VALUE_STRING_EXT_INIT(nb_name_type_vals); |
191 | | |
192 | | /* Table for reassembly of fragments. */ |
193 | | static reassembly_table netbios_reassembly_table; |
194 | | |
195 | | /* defragmentation of NetBIOS Frame */ |
196 | | static bool netbios_defragment = true; |
197 | | |
198 | | /* See |
199 | | |
200 | | http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/BK8P7001/CCONTENTS |
201 | | |
202 | | and |
203 | | |
204 | | http://ourworld.compuserve.com/homepages/TimothyDEvans/contents.htm |
205 | | |
206 | | for information about the NetBIOS Frame Protocol (which is what this |
207 | | module dissects). */ |
208 | | |
209 | | /* the strings for the command types */ |
210 | | |
211 | | static const value_string cmd_vals[] = { |
212 | | { NB_ADD_GROUP, "Add Group Name Query" }, |
213 | | { NB_ADD_NAME, "Add Name Query" }, |
214 | | { NB_NAME_IN_CONFLICT, "Name In Conflict" }, |
215 | | { NB_STATUS_QUERY, "Status Query" }, |
216 | | { NB_TERMINATE_TRACE_R, "Terminate Trace" }, |
217 | | { NB_DATAGRAM, "Datagram" }, |
218 | | { NB_DATAGRAM_BCAST, "Broadcast Datagram" }, |
219 | | { NB_NAME_QUERY, "Name Query" }, |
220 | | { NB_ADD_NAME_RESP, "Add Name Response" }, |
221 | | { NB_NAME_RESP, "Name Recognized" }, |
222 | | { NB_STATUS_RESP, "Status Response" }, |
223 | | { NB_TERMINATE_TRACE_LR, "Terminate Trace" }, |
224 | | { NB_DATA_ACK, "Data Ack" }, |
225 | | { NB_DATA_FIRST_MIDDLE, "Data First Middle" }, |
226 | | { NB_DATA_ONLY_LAST, "Data Only Last" }, |
227 | | { NB_SESSION_CONFIRM, "Session Confirm" }, |
228 | | { NB_SESSION_END, "Session End" }, |
229 | | { NB_SESSION_INIT, "Session Initialize" }, |
230 | | { NB_NO_RECEIVE, "No Receive" }, |
231 | | { NB_RECEIVE_OUTSTANDING, "Receive Outstanding" }, |
232 | | { NB_RECEIVE_CONTINUE, "Receive Continue" }, |
233 | | { NB_KEEP_ALIVE, "Session Alive" }, |
234 | | { 0, NULL } |
235 | | }; |
236 | | static value_string_ext cmd_vals_ext = VALUE_STRING_EXT_INIT(cmd_vals); |
237 | | |
238 | | static const value_string name_types[] = { |
239 | | { 0, "Unique name" }, |
240 | | { 1, "Group name" }, |
241 | | { 0, NULL } |
242 | | }; |
243 | | |
244 | | |
245 | | static const true_false_string netb_version_str = { |
246 | | "2.00 or higher", |
247 | | "1.xx" |
248 | | }; |
249 | | |
250 | | static const value_string termination_indicator_vals[] = { |
251 | | { 0x0000, "Normal session end" }, |
252 | | { 0x0001, "Abnormal session end" }, |
253 | | { 0, NULL } |
254 | | }; |
255 | | |
256 | | static const value_string status_vals[] = { |
257 | | { 0, "Add name not in process" }, |
258 | | { 1, "Add name in process" }, |
259 | | { 0, NULL } |
260 | | }; |
261 | | |
262 | | static const value_string max_frame_size_vals[] = { |
263 | | { 0, "516" }, |
264 | | { 1, "1500" }, |
265 | | { 2, "2052" }, |
266 | | { 3, "4472" }, |
267 | | { 4, "8144" }, |
268 | | { 5, "11407" }, |
269 | | { 6, "17800" }, /* 17800 in TR spec, 17749 in NBF spec */ |
270 | | { 7, "65535" }, |
271 | | { 0, NULL } |
272 | | }; |
273 | | |
274 | | |
275 | | static bool |
276 | | capture_netbios(const unsigned char *pd _U_, int offset _U_, int len _U_, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header _U_) |
277 | 0 | { |
278 | 0 | capture_dissector_increment_count(cpinfo, proto_netbios); |
279 | 0 | return true; |
280 | 0 | } |
281 | | |
282 | | |
283 | | int |
284 | | process_netbios_name(const unsigned char *name_ptr, char *name_ret, int name_ret_len) |
285 | 577 | { |
286 | 577 | int i; |
287 | 577 | int name_type = *(name_ptr + NETBIOS_NAME_LEN - 1); |
288 | 577 | unsigned char name_char; |
289 | 577 | char *name_ret_orig = name_ret; |
290 | 577 | static const char hex_digits[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; |
291 | | |
292 | 9.23k | for (i = 0; i < NETBIOS_NAME_LEN - 1; i++) { |
293 | 8.65k | name_char = *name_ptr++; |
294 | 8.65k | if (name_char >= ' ' && name_char <= '~') { |
295 | 2.44k | if (--name_ret_len > 0) |
296 | 2.00k | *name_ret++ = name_char; |
297 | 6.21k | } else { |
298 | | /* It's not printable; show it as <XX>, where |
299 | | XX is the value in hex. */ |
300 | 6.21k | if (--name_ret_len > 0) |
301 | 4.22k | *name_ret++ = '<'; |
302 | 6.21k | if (--name_ret_len > 0) |
303 | 4.22k | *name_ret++ = hex_digits[(name_char >> 4)]; |
304 | 6.21k | if (--name_ret_len > 0) |
305 | 4.21k | *name_ret++ = hex_digits[(name_char & 0x0F)]; |
306 | 6.21k | if (--name_ret_len > 0) |
307 | 4.17k | *name_ret++ = '>'; |
308 | 6.21k | } |
309 | 8.65k | } |
310 | 577 | *name_ret = '\0'; |
311 | | |
312 | | /* Remove trailing space characters from name. */ |
313 | | |
314 | 577 | name_ret--; |
315 | | |
316 | 616 | while (name_ret >= name_ret_orig) { |
317 | 486 | if (*name_ret != ' ') { |
318 | 447 | *(name_ret + 1) = 0; |
319 | 447 | break; |
320 | 447 | } |
321 | 39 | name_ret--; |
322 | 39 | } |
323 | | |
324 | 577 | return name_type; |
325 | 577 | } |
326 | | |
327 | | |
328 | | int |
329 | | get_netbios_name( tvbuff_t *tvb, int offset, char *name_ret, int name_ret_len) |
330 | | |
331 | 188 | {/* Extract the name string and name type. Return the name string in */ |
332 | | /* name_ret and return the name_type. */ |
333 | | |
334 | 188 | return process_netbios_name( tvb_get_ptr( tvb, offset, NETBIOS_NAME_LEN ), name_ret, name_ret_len); |
335 | 188 | } |
336 | | |
337 | | |
338 | | /* |
339 | | * Get a string describing the type of a NetBIOS name. |
340 | | */ |
341 | | const char * |
342 | | netbios_name_type_descr(int name_type) |
343 | | |
344 | 494 | { |
345 | 494 | return val_to_str_ext_const(name_type, &nb_name_type_vals_ext, "Unknown"); |
346 | 494 | } |
347 | | |
348 | | void |
349 | | netbios_add_name(const char* label, tvbuff_t *tvb, int offset, proto_tree *tree) |
350 | | |
351 | 84 | {/* add a name field display tree. Display the name and station type in sub-tree */ |
352 | | |
353 | 84 | proto_tree *field_tree; |
354 | 84 | char name_str[(NETBIOS_NAME_LEN - 1)*4 + 1]; |
355 | 84 | int name_type; |
356 | 84 | const char *name_type_str; |
357 | | |
358 | | /* decode the name field */ |
359 | 84 | name_type = get_netbios_name( tvb, offset, name_str, (NETBIOS_NAME_LEN - 1)*4 + 1); |
360 | 84 | name_type_str = netbios_name_type_descr(name_type); |
361 | 84 | field_tree = proto_tree_add_subtree_format( tree, tvb, offset, NETBIOS_NAME_LEN, |
362 | 84 | ett_netb_name, NULL, "%s: %s<%02x> (%s)", label, name_str, name_type, name_type_str); |
363 | | |
364 | 84 | proto_tree_add_string_format( field_tree, hf_netb_nb_name, tvb, offset, |
365 | 84 | 15, name_str, "%s", name_str); |
366 | 84 | proto_tree_add_uint_format( field_tree, hf_netb_nb_name_type, tvb, offset + 15, 1, name_type, |
367 | 84 | "0x%02x (%s)", name_type, name_type_str); |
368 | 84 | } |
369 | | |
370 | | |
371 | | static void |
372 | | netbios_data_first_middle_flags( tvbuff_t *tvb, proto_tree *tree, int offset) |
373 | | |
374 | 0 | { |
375 | 0 | proto_tree *field_tree; |
376 | 0 | proto_item *tf; |
377 | | |
378 | | /* decode the flag field for Data First Middle packet*/ |
379 | |
|
380 | 0 | tf = proto_tree_add_item(tree, hf_netb_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
381 | 0 | field_tree = proto_item_add_subtree(tf, ett_netb_flags); |
382 | |
|
383 | 0 | proto_tree_add_item( field_tree, hf_netb_flags_ack, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
384 | |
|
385 | 0 | proto_tree_add_item( field_tree, hf_netb_flags_ack_expected, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
386 | |
|
387 | 0 | proto_tree_add_item( field_tree, hf_netb_flags_recv_cont_req, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
388 | 0 | } |
389 | | |
390 | | static void |
391 | | netbios_data_only_flags( tvbuff_t *tvb, proto_tree *tree, int offset) |
392 | | |
393 | 0 | { |
394 | 0 | proto_tree *field_tree; |
395 | 0 | proto_item *tf; |
396 | | |
397 | | /* decode the flag field for Data Only Last packet*/ |
398 | 0 | tf = proto_tree_add_item(tree, hf_netb_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
399 | 0 | field_tree = proto_item_add_subtree(tf, ett_netb_flags); |
400 | |
|
401 | 0 | proto_tree_add_item( field_tree, hf_netb_flags_ack, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
402 | |
|
403 | 0 | proto_tree_add_item( field_tree, hf_netb_flags_ack_with_data, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
404 | |
|
405 | 0 | proto_tree_add_item( field_tree, hf_netb_flags_ack_expected, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
406 | 0 | } |
407 | | |
408 | | |
409 | | |
410 | | static void |
411 | | netbios_add_ses_confirm_flags( tvbuff_t *tvb, proto_tree *tree, int offset) |
412 | | |
413 | 0 | { |
414 | 0 | proto_tree *field_tree; |
415 | 0 | proto_item *tf; |
416 | | |
417 | | /* decode the flag field for Session Confirm packet */ |
418 | 0 | tf = proto_tree_add_item(tree, hf_netb_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
419 | 0 | field_tree = proto_item_add_subtree( tf, ett_netb_flags); |
420 | |
|
421 | 0 | proto_tree_add_item( field_tree, hf_netb_flags_send_no_ack, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
422 | |
|
423 | 0 | proto_tree_add_item( field_tree, hf_netb_version, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
424 | 0 | } |
425 | | |
426 | | |
427 | | static void |
428 | | netbios_add_session_init_flags( tvbuff_t *tvb, proto_tree *tree, int offset) |
429 | | |
430 | 0 | { |
431 | 0 | proto_tree *field_tree; |
432 | 0 | proto_item *tf; |
433 | | |
434 | | /* decode the flag field for Session Init packet */ |
435 | 0 | tf = proto_tree_add_item(tree, hf_netb_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
436 | 0 | field_tree = proto_item_add_subtree(tf, ett_netb_flags); |
437 | |
|
438 | 0 | proto_tree_add_item( field_tree, hf_netb_flags_send_no_ack, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
439 | |
|
440 | 0 | proto_tree_add_item( field_tree, hf_netb_largest_frame, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
441 | |
|
442 | 0 | proto_tree_add_item( field_tree, hf_netb_version, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
443 | 0 | } |
444 | | |
445 | | |
446 | | static void |
447 | | netbios_no_receive_flags( tvbuff_t *tvb, proto_tree *tree, int offset) |
448 | | |
449 | 0 | { |
450 | 0 | proto_tree *field_tree; |
451 | 0 | proto_item *tf; |
452 | | |
453 | | /* decode the flag field for No Receive packet*/ |
454 | 0 | tf = proto_tree_add_item(tree, hf_netbios_no_receive_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
455 | 0 | field_tree = proto_item_add_subtree(tf, ett_netb_flags); |
456 | 0 | proto_tree_add_item(field_tree, hf_netbios_no_receive_flags_send_no_ack, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
457 | 0 | } |
458 | | |
459 | | |
460 | | /************************************************************************/ |
461 | | /* */ |
462 | | /* The routines to display the netbios field values in the tree */ |
463 | | /* */ |
464 | | /************************************************************************/ |
465 | | |
466 | | |
467 | | static void |
468 | | nb_xmit_corrl( tvbuff_t *tvb, int offset, proto_tree *tree) |
469 | | |
470 | 0 | {/* display the transmit correlator */ |
471 | |
|
472 | 0 | proto_tree_add_item( tree, hf_netb_xmit_corrl, tvb, offset + NB_XMIT_CORL, |
473 | 0 | 2, ENC_LITTLE_ENDIAN); |
474 | 0 | } |
475 | | |
476 | | |
477 | | static void |
478 | | nb_resp_corrl( tvbuff_t *tvb, int offset, proto_tree *tree) |
479 | | |
480 | 0 | {/* display the response correlator */ |
481 | |
|
482 | 0 | proto_tree_add_item( tree, hf_netb_resp_corrl, tvb, offset + NB_RESP_CORL, |
483 | 0 | 2, ENC_LITTLE_ENDIAN); |
484 | 0 | } |
485 | | |
486 | | |
487 | | static void |
488 | | nb_call_name_type( tvbuff_t *tvb, int offset, proto_tree *tree) |
489 | | |
490 | 0 | {/* display the call name type */ |
491 | |
|
492 | 0 | proto_tree_add_item( tree, hf_netb_call_name_type, tvb, offset + NB_CALL_NAME_TYPE, |
493 | 0 | 1, ENC_LITTLE_ENDIAN); |
494 | |
|
495 | 0 | } |
496 | | |
497 | | |
498 | | static uint8_t |
499 | | nb_local_session( tvbuff_t *tvb, int offset, proto_tree *tree) |
500 | | |
501 | 0 | {/* add the local session to tree, and return its value */ |
502 | |
|
503 | 0 | uint8_t local_session = tvb_get_uint8( tvb, offset + NB_LOCAL_SES); |
504 | |
|
505 | 0 | proto_tree_add_uint( tree, hf_netb_local_ses_no, tvb, offset + NB_LOCAL_SES, 1, |
506 | 0 | local_session); |
507 | |
|
508 | 0 | return local_session; |
509 | 0 | } |
510 | | |
511 | | |
512 | | static uint8_t |
513 | | nb_remote_session( tvbuff_t *tvb, int offset, proto_tree *tree) |
514 | | |
515 | 0 | {/* add the remote session to tree, and return its value */ |
516 | |
|
517 | 0 | uint8_t remote_session = tvb_get_uint8( tvb, offset + NB_RMT_SES); |
518 | |
|
519 | 0 | proto_tree_add_uint( tree, hf_netb_remote_ses_no, tvb, offset + NB_RMT_SES, 1, |
520 | 0 | remote_session); |
521 | |
|
522 | 0 | return remote_session; |
523 | 0 | } |
524 | | |
525 | | |
526 | | static void |
527 | | nb_data1(int hf, tvbuff_t *tvb, int offset, proto_tree *tree) |
528 | | |
529 | 0 | {/* add the DATA1 to tree with specified hf_ value */ |
530 | |
|
531 | 0 | proto_tree_add_item( tree, hf, tvb, offset + NB_DATA1, 1, ENC_LITTLE_ENDIAN); |
532 | |
|
533 | 0 | } |
534 | | |
535 | | |
536 | | static void |
537 | | nb_data2(int hf, tvbuff_t *tvb, int offset, proto_tree *tree) |
538 | | |
539 | 0 | {/* add the DATA2 to tree with specified hf_ value */ |
540 | |
|
541 | 0 | proto_tree_add_item( tree, hf, tvb, offset + NB_DATA2, 2, ENC_LITTLE_ENDIAN); |
542 | |
|
543 | 0 | } |
544 | | |
545 | | |
546 | | static void |
547 | | nb_resync_indicator( tvbuff_t *tvb, int offset, proto_tree *tree, const char *cmd_str) |
548 | | |
549 | 0 | { |
550 | 0 | uint16_t resync_indicator = tvb_get_letohs( tvb, offset + NB_DATA2); |
551 | | |
552 | |
|
553 | 0 | switch (resync_indicator) { |
554 | | |
555 | 0 | case 0x0000: |
556 | 0 | proto_tree_add_uint_format_value(tree, hf_netb_resync_indicator, tvb, offset + NB_DATA2, 2, |
557 | 0 | resync_indicator, "No re-sync"); |
558 | 0 | break; |
559 | | |
560 | 0 | case 0x0001: |
561 | 0 | proto_tree_add_uint_format_value(tree, hf_netb_resync_indicator, tvb, offset + NB_DATA2, 2, |
562 | 0 | resync_indicator, "First '%s' following 'Receive Outstanding'", cmd_str); |
563 | 0 | break; |
564 | | |
565 | 0 | default: |
566 | 0 | proto_tree_add_item(tree, hf_netb_resync_indicator, tvb, offset + NB_DATA2, 2, ENC_LITTLE_ENDIAN); |
567 | 0 | break; |
568 | 0 | } |
569 | 0 | } |
570 | | |
571 | | /************************************************************************/ |
572 | | /* */ |
573 | | /* The routines called by the top level to handle individual commands */ |
574 | | /* */ |
575 | | /************************************************************************/ |
576 | | |
577 | | static uint32_t |
578 | | dissect_netb_unknown( tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree) |
579 | | |
580 | 0 | {/* Handle any unknown commands, do nothing */ |
581 | |
|
582 | 0 | proto_tree_add_expert(tree, pinfo, &ei_netb_unknown_command_data, tvb, offset + NB_COMMAND + 1, -1); |
583 | |
|
584 | 0 | return 0; |
585 | 0 | } |
586 | | |
587 | | |
588 | | static uint32_t |
589 | | dissect_netb_add_group_name( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
590 | | |
591 | 0 | {/* Handle the ADD GROUP NAME QUERY command */ |
592 | |
|
593 | 0 | nb_resp_corrl( tvb, offset, tree); |
594 | |
|
595 | 0 | netbios_add_name("Group name to add", tvb, offset + NB_SENDER_NAME, |
596 | 0 | tree); |
597 | |
|
598 | 0 | return 0; |
599 | 0 | } |
600 | | |
601 | | |
602 | | static uint32_t |
603 | | dissect_netb_add_name( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
604 | | |
605 | 0 | {/* Handle the ADD NAME QUERY command */ |
606 | |
|
607 | 0 | nb_resp_corrl( tvb, offset, tree); |
608 | |
|
609 | 0 | netbios_add_name("Name to add", tvb, offset + NB_SENDER_NAME, tree); |
610 | |
|
611 | 0 | return 0; |
612 | 0 | } |
613 | | |
614 | | |
615 | | static uint32_t |
616 | | dissect_netb_name_in_conflict( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
617 | | |
618 | 0 | {/* Handle the NAME IN CONFLICT command */ |
619 | |
|
620 | 0 | netbios_add_name("Name In Conflict", tvb, offset + NB_RECVER_NAME, |
621 | 0 | tree); |
622 | 0 | netbios_add_name("Sender's Name", tvb, offset + NB_SENDER_NAME, tree); |
623 | |
|
624 | 0 | return 0; |
625 | 0 | } |
626 | | |
627 | | |
628 | | static uint32_t |
629 | | dissect_netb_status_query( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
630 | | |
631 | 0 | {/* Handle the STATUS QUERY command */ |
632 | 0 | uint8_t status_request = tvb_get_uint8( tvb, offset + NB_DATA1); |
633 | |
|
634 | 0 | switch (status_request) { |
635 | | |
636 | 0 | case 0: |
637 | 0 | proto_tree_add_uint_format_value(tree, hf_netb_status_request, tvb, offset + NB_DATA1, 1, |
638 | 0 | status_request, "NetBIOS 1.x or 2.0"); |
639 | 0 | break; |
640 | | |
641 | 0 | case 1: |
642 | 0 | proto_tree_add_uint_format_value(tree, hf_netb_status_request, tvb, offset + NB_DATA1, 1, |
643 | 0 | status_request, "NetBIOS 2.1, initial status request"); |
644 | 0 | break; |
645 | | |
646 | 0 | default: |
647 | 0 | proto_tree_add_uint_format_value(tree, hf_netb_status_request, tvb, offset + NB_DATA1, 1, |
648 | 0 | status_request, "NetBIOS 2.1, %u names received so far", |
649 | 0 | status_request); |
650 | 0 | break; |
651 | 0 | } |
652 | 0 | nb_data2( hf_netb_status_buffer_len, tvb, offset, tree); |
653 | 0 | nb_resp_corrl( tvb, offset, tree); |
654 | 0 | netbios_add_name("Receiver's Name", tvb, offset + NB_RECVER_NAME, tree); |
655 | 0 | netbios_add_name("Sender's Name", tvb, offset + NB_SENDER_NAME, tree); |
656 | |
|
657 | 0 | return 0; |
658 | 0 | } |
659 | | |
660 | | |
661 | | static uint32_t |
662 | | dissect_netb_terminate_trace( tvbuff_t *tvb _U_, packet_info *pinfo _U_, int offset _U_, proto_tree *tree _U_) |
663 | | |
664 | 0 | {/* Handle the TERMINATE TRACE command */ |
665 | | |
666 | | /* |
667 | | * XXX - are any of the fields in this message significant? |
668 | | * The IBM NetBIOS document shows them as "Reserved". |
669 | | */ |
670 | |
|
671 | 0 | return 0; |
672 | 0 | } |
673 | | |
674 | | |
675 | | static const unsigned char zeroes[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
676 | | |
677 | | static uint32_t |
678 | | dissect_netb_datagram( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
679 | | |
680 | 0 | {/* Handle the DATAGRAM command */ |
681 | |
|
682 | 0 | netbios_add_name("Receiver's Name", tvb, offset + NB_RECVER_NAME, tree); |
683 | | /* Weird. In some datagrams, this is 10 octets of 0, followed |
684 | | by a MAC address.... */ |
685 | |
|
686 | 0 | if (tvb_memeql(tvb, offset + NB_SENDER_NAME, zeroes, 10) == 0) { |
687 | 0 | proto_tree_add_item(tree, hf_netb_datagram_mac, |
688 | 0 | tvb, offset + NB_SENDER_NAME + 10, 6, ENC_NA ); |
689 | 0 | } else { |
690 | 0 | netbios_add_name("Sender's Name", tvb, offset + NB_SENDER_NAME, |
691 | 0 | tree); |
692 | 0 | } |
693 | |
|
694 | 0 | return 0; |
695 | 0 | } |
696 | | |
697 | | |
698 | | static uint32_t |
699 | | dissect_netb_datagram_bcast( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
700 | | |
701 | 0 | {/* Handle the DATAGRAM BROADCAST command */ |
702 | | |
703 | | /* We assume the same weirdness can happen here.... */ |
704 | 0 | if (tvb_memeql(tvb, offset + NB_SENDER_NAME, zeroes, 10) == 0) { |
705 | 0 | proto_tree_add_item(tree, hf_netb_datagram_bcast_mac, |
706 | 0 | tvb, offset + NB_SENDER_NAME + 10, 6, ENC_NA ); |
707 | 0 | } else { |
708 | 0 | netbios_add_name("Sender's Name", tvb, offset + NB_SENDER_NAME, |
709 | 0 | tree); |
710 | 0 | } |
711 | |
|
712 | 0 | return 0; |
713 | 0 | } |
714 | | |
715 | | |
716 | | static uint32_t |
717 | | dissect_netb_name_query( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
718 | | |
719 | 0 | {/* Handle the NAME QUERY command */ |
720 | 0 | uint8_t local_session_number = tvb_get_uint8( tvb, offset + NB_DATA2); |
721 | |
|
722 | 0 | if (local_session_number == 0) { |
723 | 0 | proto_tree_add_uint_format_value( tree, hf_netb_local_session_no, tvb, offset + NB_DATA2, 1, |
724 | 0 | local_session_number, "0 (FIND.NAME request)"); |
725 | 0 | } else { |
726 | 0 | proto_tree_add_item( tree, hf_netb_local_session_no, tvb, offset + NB_DATA2, 1, ENC_LITTLE_ENDIAN); |
727 | 0 | } |
728 | 0 | nb_call_name_type( tvb, offset, tree); |
729 | 0 | nb_resp_corrl( tvb, offset, tree); |
730 | 0 | netbios_add_name("Query Name", tvb, offset + NB_RECVER_NAME, tree); |
731 | 0 | if (local_session_number != 0) { |
732 | 0 | netbios_add_name("Sender's Name", tvb, offset + NB_SENDER_NAME, |
733 | 0 | tree); |
734 | 0 | } |
735 | |
|
736 | 0 | return 0; |
737 | 0 | } |
738 | | |
739 | | |
740 | | static uint32_t |
741 | | dissect_netb_add_name_resp( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
742 | | |
743 | 0 | {/* Handle the ADD NAME RESPONSE command */ |
744 | |
|
745 | 0 | nb_data1( hf_netb_status, tvb, offset, tree); |
746 | 0 | nb_data2( hf_netb_name_type, tvb, offset, tree); |
747 | 0 | nb_xmit_corrl( tvb, offset, tree); |
748 | 0 | netbios_add_name("Name to be added", tvb, offset + NB_RECVER_NAME, |
749 | 0 | tree); |
750 | 0 | netbios_add_name("Name to be added", tvb, offset + NB_SENDER_NAME, |
751 | 0 | tree); |
752 | |
|
753 | 0 | return 0; |
754 | 0 | } |
755 | | |
756 | | |
757 | | static uint32_t |
758 | | dissect_netb_name_resp( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
759 | | |
760 | 0 | {/* Handle the NAME RECOGNIZED command */ |
761 | 0 | uint8_t local_session_number = tvb_get_uint8( tvb, offset + NB_DATA2); |
762 | |
|
763 | 0 | switch (local_session_number) { |
764 | | |
765 | 0 | case 0x00: |
766 | 0 | proto_tree_add_uint_format_value( tree, hf_netb_state_of_name, tvb, offset + NB_DATA2, 1, |
767 | 0 | local_session_number, "No LISTEN pending, or FIND.NAME response"); |
768 | 0 | break; |
769 | | |
770 | 0 | case 0xFF: |
771 | 0 | proto_tree_add_uint_format_value( tree, hf_netb_state_of_name, tvb, offset + NB_DATA2, 1, |
772 | 0 | local_session_number, "LISTEN pending, but insufficient resources to establish session"); |
773 | 0 | break; |
774 | | |
775 | 0 | default: |
776 | 0 | proto_tree_add_item( tree, hf_netb_local_session_no, tvb, offset + NB_DATA2, 1, ENC_LITTLE_ENDIAN); |
777 | 0 | break; |
778 | 0 | } |
779 | 0 | nb_call_name_type( tvb, offset, tree); |
780 | 0 | nb_xmit_corrl( tvb, offset, tree); |
781 | 0 | if (local_session_number != 0x00 && local_session_number != 0xFF) |
782 | 0 | nb_resp_corrl(tvb, offset, tree); |
783 | 0 | netbios_add_name("Receiver's Name", tvb, offset + NB_RECVER_NAME, tree); |
784 | 0 | if (local_session_number != 0x00 && local_session_number != 0xFF) { |
785 | 0 | netbios_add_name("Sender's Name", tvb, offset + NB_SENDER_NAME, |
786 | 0 | tree); |
787 | 0 | } |
788 | |
|
789 | 0 | return 0; |
790 | 0 | } |
791 | | |
792 | | |
793 | | static uint32_t |
794 | | dissect_netb_status_resp( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
795 | | |
796 | 0 | {/* Handle the STATUS RESPONSE command */ |
797 | 0 | uint8_t status_response = tvb_get_uint8( tvb, offset + NB_DATA1); |
798 | 0 | proto_item *td2; |
799 | 0 | proto_tree *data2_tree; |
800 | |
|
801 | 0 | nb_call_name_type( tvb, offset, tree); |
802 | 0 | if (status_response == 0) { |
803 | 0 | proto_tree_add_uint_format_value(tree, hf_netb_status_response, tvb, offset + NB_DATA1, 1, |
804 | 0 | status_response, "NetBIOS 1.x or 2.0"); |
805 | 0 | } else { |
806 | 0 | proto_tree_add_uint_format_value(tree, hf_netb_status_response, tvb, offset + NB_DATA1, 1, |
807 | 0 | status_response, "NetBIOS 2.1, %u names sent so far", |
808 | 0 | status_response); |
809 | 0 | } |
810 | |
|
811 | 0 | td2 = proto_tree_add_item(tree, hf_netb_data2, tvb, offset + NB_DATA2, 2, ENC_LITTLE_ENDIAN); |
812 | 0 | data2_tree = proto_item_add_subtree(td2, ett_netb_status); |
813 | 0 | proto_tree_add_item(data2_tree, hf_netb_data2_frame, tvb, offset + NB_DATA2, 2, ENC_LITTLE_ENDIAN); |
814 | 0 | proto_tree_add_item(data2_tree, hf_netb_data2_user, tvb, offset + NB_DATA2, 2, ENC_LITTLE_ENDIAN); |
815 | 0 | proto_tree_add_item(data2_tree, hf_netb_data2_status, tvb, offset + NB_DATA2, 2, ENC_LITTLE_ENDIAN); |
816 | |
|
817 | 0 | nb_xmit_corrl( tvb, offset, tree); |
818 | 0 | netbios_add_name("Receiver's Name", tvb, offset + NB_RECVER_NAME, tree); |
819 | 0 | netbios_add_name("Sender's Name", tvb, offset + NB_SENDER_NAME, |
820 | 0 | tree); |
821 | |
|
822 | 0 | return 0; |
823 | 0 | } |
824 | | |
825 | | |
826 | | static uint32_t |
827 | | dissect_netb_data_ack( tvbuff_t* tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
828 | | |
829 | 0 | {/* Handle the DATA ACK command */ |
830 | |
|
831 | 0 | nb_xmit_corrl( tvb, offset, tree); |
832 | 0 | nb_remote_session( tvb, offset, tree); |
833 | 0 | nb_local_session( tvb, offset, tree); |
834 | |
|
835 | 0 | return 0; |
836 | 0 | } |
837 | | |
838 | | |
839 | | static uint32_t |
840 | | dissect_netb_data_first_middle( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
841 | | |
842 | 0 | {/* Handle the DATA FIRST MIDDLE command */ |
843 | |
|
844 | 0 | uint8_t remote_session, local_session; |
845 | | |
846 | | /* |
847 | | * This is the first frame, or the middle frame, of a fragmented |
848 | | * packet. |
849 | | * |
850 | | * XXX - there are no sequence numbers, so we have to assume |
851 | | * that fragments arrive in order with no duplicates. |
852 | | * In fact, 802.2 LLC is supposed to handle that, so we |
853 | | * might have to have the LLC dissector do so (but the TCP |
854 | | * dissector doesn't currently handle out-of-order or duplicate |
855 | | * data, either). |
856 | | */ |
857 | |
|
858 | 0 | netbios_data_first_middle_flags( tvb, tree, offset + NB_FLAGS); |
859 | |
|
860 | 0 | nb_resync_indicator( tvb, offset, tree, "DATA FIRST MIDDLE"); |
861 | 0 | nb_xmit_corrl( tvb, offset, tree); |
862 | 0 | nb_resp_corrl( tvb, offset, tree); |
863 | 0 | remote_session = nb_remote_session( tvb, offset, tree); |
864 | 0 | local_session = nb_local_session( tvb, offset, tree); |
865 | | |
866 | | /* |
867 | | * Return a combination of the remote and local session numbers, |
868 | | * for use when reassembling. |
869 | | */ |
870 | 0 | return (remote_session << 8) + local_session; |
871 | 0 | } |
872 | | |
873 | | |
874 | | static uint32_t |
875 | | dissect_netb_data_only_last( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
876 | | |
877 | 0 | {/* Handle the DATA ONLY LAST command */ |
878 | |
|
879 | 0 | uint8_t remote_session, local_session; |
880 | | |
881 | | /* |
882 | | * This is a complete packet, or the last frame of a fragmented |
883 | | * packet. |
884 | | */ |
885 | |
|
886 | 0 | netbios_data_only_flags( tvb, tree, offset + NB_FLAGS); |
887 | |
|
888 | 0 | nb_resync_indicator( tvb, offset, tree, "DATA ONLY LAST"); |
889 | 0 | nb_xmit_corrl( tvb, offset, tree); |
890 | 0 | nb_resp_corrl( tvb, offset, tree); |
891 | 0 | remote_session = nb_remote_session( tvb, offset, tree); |
892 | 0 | local_session = nb_local_session( tvb, offset, tree); |
893 | | |
894 | | /* |
895 | | * Return a combination of the remote and local session numbers, |
896 | | * for use when reassembling. |
897 | | */ |
898 | 0 | return (remote_session << 8) + local_session; |
899 | 0 | } |
900 | | |
901 | | |
902 | | static uint32_t |
903 | | dissect_netb_session_confirm( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
904 | | |
905 | 0 | {/* Handle the SESSION CONFIRM command */ |
906 | |
|
907 | 0 | netbios_add_ses_confirm_flags( tvb, tree, offset + NB_FLAGS); |
908 | |
|
909 | 0 | nb_data2( hf_netb_max_data_recv_size, tvb, offset, tree); |
910 | 0 | nb_xmit_corrl( tvb, offset, tree); |
911 | 0 | nb_resp_corrl( tvb, offset, tree); |
912 | 0 | nb_remote_session( tvb, offset, tree); |
913 | 0 | nb_local_session( tvb, offset, tree); |
914 | |
|
915 | 0 | return 0; |
916 | 0 | } |
917 | | |
918 | | |
919 | | static uint32_t |
920 | | dissect_netb_session_end( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
921 | | |
922 | 0 | {/* Handle the SESSION END command */ |
923 | |
|
924 | 0 | nb_data2( hf_netb_termination_indicator, tvb, offset, tree); |
925 | 0 | nb_remote_session( tvb, offset, tree); |
926 | 0 | nb_local_session( tvb, offset, tree); |
927 | |
|
928 | 0 | return 0; |
929 | 0 | } |
930 | | |
931 | | |
932 | | static uint32_t |
933 | | dissect_netb_session_init( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
934 | | |
935 | 0 | {/* Handle the SESSION INITIALIZE command */ |
936 | |
|
937 | 0 | netbios_add_session_init_flags( tvb, tree, offset + NB_FLAGS); |
938 | |
|
939 | 0 | nb_data2( hf_netb_max_data_recv_size, tvb, offset, tree); |
940 | 0 | nb_resp_corrl( tvb, offset, tree); |
941 | 0 | nb_xmit_corrl( tvb, offset, tree); |
942 | 0 | nb_remote_session( tvb, offset, tree); |
943 | 0 | nb_local_session( tvb, offset, tree); |
944 | |
|
945 | 0 | return 0; |
946 | 0 | } |
947 | | |
948 | | static uint32_t |
949 | | dissect_netb_no_receive( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
950 | | |
951 | 0 | {/* Handle the NO RECEIVE command */ |
952 | |
|
953 | 0 | netbios_no_receive_flags( tvb, tree, offset + NB_FLAGS); |
954 | |
|
955 | 0 | nb_data2( hf_netb_num_data_bytes_accepted, tvb, offset, tree); |
956 | 0 | nb_remote_session( tvb, offset, tree); |
957 | 0 | nb_local_session( tvb, offset, tree); |
958 | |
|
959 | 0 | return 0; |
960 | 0 | } |
961 | | |
962 | | |
963 | | static uint32_t |
964 | | dissect_netb_receive_outstanding( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
965 | | |
966 | 0 | {/* Handle the RECEIVE OUTSTANDING command */ |
967 | |
|
968 | 0 | nb_data2( hf_netb_num_data_bytes_accepted, tvb, offset, tree); |
969 | 0 | nb_remote_session( tvb, offset, tree); |
970 | 0 | nb_local_session( tvb, offset, tree); |
971 | |
|
972 | 0 | return 0; |
973 | 0 | } |
974 | | |
975 | | |
976 | | static uint32_t |
977 | | dissect_netb_receive_continue( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
978 | | |
979 | 0 | {/* Handle the RECEIVE CONTINUE command */ |
980 | |
|
981 | 0 | nb_xmit_corrl( tvb, offset, tree); |
982 | 0 | nb_remote_session( tvb, offset, tree); |
983 | 0 | nb_local_session( tvb, offset, tree); |
984 | |
|
985 | 0 | return 0; |
986 | 0 | } |
987 | | |
988 | | |
989 | | static uint32_t |
990 | | dissect_netb_session_alive( tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree) |
991 | | |
992 | 0 | {/* Handle the SESSION ALIVE command */ |
993 | | |
994 | | /* |
995 | | * XXX - all the fields are claimed to be "Reserved", but |
996 | | * the session numbers appear to be non-zero in at least |
997 | | * one capture, and they do appear to match session numbers |
998 | | * in other messages, and I'd expect that you had to identify |
999 | | * sessions in this message in any case. |
1000 | | * |
1001 | | * We show only those fields. |
1002 | | */ |
1003 | 0 | nb_remote_session( tvb, offset, tree); |
1004 | 0 | nb_local_session( tvb, offset, tree); |
1005 | |
|
1006 | 0 | return 0; |
1007 | 0 | } |
1008 | | |
1009 | | |
1010 | | /************************************************************************/ |
1011 | | /* */ |
1012 | | /* The table routines called by the top level to handle commands */ |
1013 | | /* */ |
1014 | | /************************************************************************/ |
1015 | | |
1016 | | static uint32_t (*const dissect_netb[])(tvbuff_t *, packet_info *, int, proto_tree *) = { |
1017 | | |
1018 | | dissect_netb_add_group_name, /* Add Group Name 0x00 */ |
1019 | | dissect_netb_add_name, /* Add Name 0x01 */ |
1020 | | dissect_netb_name_in_conflict, /* Name In Conflict 0x02 */ |
1021 | | dissect_netb_status_query, /* Status Query 0x03 */ |
1022 | | dissect_netb_unknown, /* unknown 0x04 */ |
1023 | | dissect_netb_unknown, /* unknown 0x05 */ |
1024 | | dissect_netb_unknown, /* unknown 0x06 */ |
1025 | | dissect_netb_terminate_trace, /* Terminate Trace 0x07 */ |
1026 | | dissect_netb_datagram, /* Datagram 0x08 */ |
1027 | | dissect_netb_datagram_bcast, /* Datagram Broadcast 0x09 */ |
1028 | | dissect_netb_name_query, /* Name Query 0x0A */ |
1029 | | dissect_netb_unknown, /* unknown 0x0B */ |
1030 | | dissect_netb_unknown, /* unknown 0x0C */ |
1031 | | dissect_netb_add_name_resp, /* Add Name Response 0x0D */ |
1032 | | dissect_netb_name_resp, /* Name Recognized 0x0E */ |
1033 | | dissect_netb_status_resp, /* Status Response 0x0F */ |
1034 | | dissect_netb_unknown, /* unknown 0x10 */ |
1035 | | dissect_netb_unknown, /* unknown 0x11 */ |
1036 | | dissect_netb_unknown, /* unknown 0x12 */ |
1037 | | dissect_netb_terminate_trace, /* Terminate Trace 0x13 */ |
1038 | | dissect_netb_data_ack, /* Data Ack 0x14 */ |
1039 | | dissect_netb_data_first_middle, /* Data First Middle 0x15 */ |
1040 | | dissect_netb_data_only_last, /* Data Only Last 0x16 */ |
1041 | | dissect_netb_session_confirm, /* Session Confirm 0x17 */ |
1042 | | dissect_netb_session_end, /* Session End 0x18 */ |
1043 | | dissect_netb_session_init, /* Session Initialize 0x19 */ |
1044 | | dissect_netb_no_receive, /* No Receive 0x1A */ |
1045 | | dissect_netb_receive_outstanding, /* Receive Outstanding 0x1B */ |
1046 | | dissect_netb_receive_continue, /* Receive Continue 0x1C */ |
1047 | | dissect_netb_unknown, /* unknown 0x1D */ |
1048 | | dissect_netb_unknown, /* unknown 0x1E */ |
1049 | | dissect_netb_session_alive, /* Session Alive 0x1f */ |
1050 | | dissect_netb_unknown, |
1051 | | }; |
1052 | | |
1053 | | static heur_dissector_list_t netbios_heur_subdissector_list; |
1054 | | |
1055 | | static void |
1056 | | dissect_netbios_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) |
1057 | 0 | { |
1058 | 0 | heur_dtbl_entry_t *hdtbl_entry; |
1059 | | |
1060 | | /* |
1061 | | * Try the heuristic dissectors for NetBIOS; if none of them |
1062 | | * accept the packet, dissect it as data. |
1063 | | */ |
1064 | 0 | if (!dissector_try_heuristic(netbios_heur_subdissector_list, |
1065 | 0 | tvb, pinfo, tree, &hdtbl_entry, NULL)) |
1066 | 0 | call_data_dissector(tvb, pinfo, tree); |
1067 | 0 | } |
1068 | | |
1069 | | static int |
1070 | | dissect_netbios(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
1071 | 2 | { |
1072 | 2 | proto_tree *netb_tree = NULL; |
1073 | 2 | proto_item *ti; |
1074 | 2 | uint16_t hdr_len, command; |
1075 | 2 | const char *command_name; |
1076 | 2 | char name[(NETBIOS_NAME_LEN - 1)*4 + 1]; |
1077 | 2 | int name_type; |
1078 | 2 | uint16_t session_id; |
1079 | 2 | bool save_fragmented; |
1080 | 2 | int len; |
1081 | 2 | fragment_head *fd_head; |
1082 | 2 | tvbuff_t *next_tvb; |
1083 | | |
1084 | 2 | int offset = 0; |
1085 | | |
1086 | | /* load the display labels */ |
1087 | 2 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "NetBIOS"); |
1088 | | |
1089 | | |
1090 | | /* Find NetBIOS marker EFFF, this is done because I have seen an extra LLC */ |
1091 | | /* byte on our network. This only checks for one extra LLC byte. */ |
1092 | | |
1093 | 2 | if ( 0xefff != tvb_get_letohs(tvb, 2)){ |
1094 | 2 | ++offset; |
1095 | 2 | if ( 0xefff != tvb_get_letohs(tvb, 3)){ |
1096 | | |
1097 | | /* print bad packet */ |
1098 | 2 | col_set_str( pinfo->cinfo, COL_INFO, "Bad packet, no 0xEFFF marker"); |
1099 | | |
1100 | 2 | return 3; /* this is an unknown packet, no marker */ |
1101 | 2 | } |
1102 | 2 | } |
1103 | | |
1104 | | |
1105 | 0 | hdr_len = tvb_get_letohs(tvb, offset + NB_LENGTH); |
1106 | 0 | command = tvb_get_uint8( tvb, offset + NB_COMMAND); |
1107 | | /* limit command so no table overflows */ |
1108 | 0 | command = MIN(command, array_length(dissect_netb)); |
1109 | | |
1110 | | /* print command name */ |
1111 | 0 | command_name = val_to_str_ext(command, &cmd_vals_ext, "Unknown (0x%02x)"); |
1112 | 0 | switch ( command ) { |
1113 | 0 | case NB_NAME_QUERY: |
1114 | 0 | name_type = get_netbios_name( tvb, offset + 12, name, (NETBIOS_NAME_LEN - 1)*4 + 1); |
1115 | 0 | col_add_fstr( pinfo->cinfo, COL_INFO, "%s for %s<%02x>", command_name, name, name_type); |
1116 | 0 | break; |
1117 | | |
1118 | 0 | case NB_NAME_RESP: |
1119 | 0 | case NB_ADD_NAME: |
1120 | 0 | case NB_ADD_GROUP: |
1121 | 0 | name_type = get_netbios_name( tvb, offset + 28, name, (NETBIOS_NAME_LEN - 1)*4 + 1); |
1122 | 0 | col_add_fstr( pinfo->cinfo, COL_INFO, "%s - %s<%02x>", command_name, name, name_type); |
1123 | 0 | break; |
1124 | | |
1125 | 0 | default: |
1126 | 0 | col_add_str( pinfo->cinfo, COL_INFO, command_name); |
1127 | 0 | break; |
1128 | 0 | } |
1129 | | |
1130 | 0 | if ( tree) { |
1131 | 0 | ti = proto_tree_add_item(tree, proto_netbios, tvb, 0, hdr_len, ENC_NA); |
1132 | 0 | netb_tree = proto_item_add_subtree(ti, ett_netb); |
1133 | |
|
1134 | 0 | proto_tree_add_uint_format_value(netb_tree, hf_netb_hdr_len, tvb, offset, 2, hdr_len, |
1135 | 0 | "%d bytes", hdr_len); |
1136 | |
|
1137 | 0 | proto_tree_add_uint_format_value(netb_tree, hf_netb_delimiter, tvb, offset + 2, 2, |
1138 | 0 | tvb_get_letohs(tvb, offset + 2), "EFFF (NetBIOS)"); |
1139 | |
|
1140 | 0 | proto_tree_add_uint(netb_tree, hf_netb_cmd, tvb, offset + NB_COMMAND, 1, command); |
1141 | 0 | } |
1142 | | |
1143 | | /* if command in table range */ |
1144 | 0 | if ( command < array_length(dissect_netb)) { |
1145 | | |
1146 | | /* branch to handle commands */ |
1147 | 0 | session_id = (dissect_netb[ command])( tvb, pinfo, offset, netb_tree); |
1148 | |
|
1149 | 0 | offset += hdr_len; /* move past header */ |
1150 | |
|
1151 | 0 | save_fragmented = pinfo->fragmented; |
1152 | | |
1153 | | /* |
1154 | | * Process user data in frames that have it. |
1155 | | */ |
1156 | 0 | switch (command) { |
1157 | | |
1158 | 0 | case NB_DATAGRAM: |
1159 | 0 | case NB_DATAGRAM_BCAST: |
1160 | | /* |
1161 | | * No fragmentation here. |
1162 | | */ |
1163 | 0 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
1164 | 0 | dissect_netbios_payload(next_tvb, pinfo, tree); |
1165 | 0 | break; |
1166 | | |
1167 | 0 | case NB_DATA_FIRST_MIDDLE: |
1168 | 0 | case NB_DATA_ONLY_LAST: |
1169 | | /* |
1170 | | * Possibly fragmented. |
1171 | | */ |
1172 | 0 | len = tvb_reported_length_remaining(tvb, offset); |
1173 | 0 | if (netbios_defragment && |
1174 | 0 | tvb_bytes_exist(tvb, offset, len)) { |
1175 | 0 | fd_head = fragment_add_seq_next(&netbios_reassembly_table, |
1176 | 0 | tvb, offset, |
1177 | 0 | pinfo, session_id, NULL, |
1178 | 0 | len, command == NB_DATA_FIRST_MIDDLE); |
1179 | 0 | if (fd_head != NULL) { |
1180 | 0 | if (fd_head->next != NULL) { |
1181 | 0 | next_tvb = tvb_new_chain(tvb, fd_head->tvb_data); |
1182 | 0 | add_new_data_source(pinfo, |
1183 | 0 | next_tvb, |
1184 | 0 | "Reassembled NetBIOS"); |
1185 | | /* Show all fragments. */ |
1186 | 0 | if (tree) { |
1187 | 0 | proto_item *frag_tree_item; |
1188 | |
|
1189 | 0 | show_fragment_seq_tree(fd_head, |
1190 | 0 | &netbios_frag_items, |
1191 | 0 | netb_tree, pinfo, |
1192 | 0 | next_tvb, &frag_tree_item); |
1193 | 0 | } |
1194 | 0 | } else { |
1195 | 0 | next_tvb = tvb_new_subset_remaining(tvb, |
1196 | 0 | offset); |
1197 | 0 | } |
1198 | 0 | } else { |
1199 | 0 | next_tvb = NULL; |
1200 | 0 | } |
1201 | 0 | } else { |
1202 | | /* |
1203 | | * Dissect this, regardless of whether |
1204 | | * it's NB_DATA_FIRST_MIDDLE or |
1205 | | * NB_DATA_ONLY_LAST. |
1206 | | * |
1207 | | * XXX - it'd be nice to show |
1208 | | * NB_DATA_FIRST_MIDDLE as a fragment |
1209 | | * if it's not the first fragment (i.e., |
1210 | | * MIDDLE rather than FIRST), and show |
1211 | | * NB_DATA_ONLY_LAST as a fragment if |
1212 | | * it's part of a fragmented datagram |
1213 | | * (i.e, LAST rather than ONLY), but |
1214 | | * we'd have to do reassembly to |
1215 | | * be able to determine that. |
1216 | | */ |
1217 | 0 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
1218 | 0 | } |
1219 | 0 | if (next_tvb != NULL) |
1220 | 0 | dissect_netbios_payload(next_tvb, pinfo, tree); |
1221 | 0 | else { |
1222 | 0 | next_tvb = tvb_new_subset_remaining (tvb, offset); |
1223 | 0 | call_data_dissector(next_tvb, pinfo, tree); |
1224 | 0 | } |
1225 | 0 | break; |
1226 | 0 | } |
1227 | 0 | pinfo->fragmented = save_fragmented; |
1228 | 0 | } |
1229 | 0 | return tvb_captured_length(tvb); |
1230 | 0 | } |
1231 | | |
1232 | | void |
1233 | | proto_register_netbios(void) |
1234 | 14 | { |
1235 | 14 | static int *ett[] = { |
1236 | 14 | &ett_netb, |
1237 | 14 | &ett_netb_name, |
1238 | 14 | &ett_netb_flags, |
1239 | 14 | &ett_netb_status, |
1240 | 14 | &ett_netb_fragments, |
1241 | 14 | &ett_netb_fragment, |
1242 | 14 | }; |
1243 | | |
1244 | 14 | static hf_register_info hf_netb[] = { |
1245 | 14 | { &hf_netb_cmd, |
1246 | 14 | { "Command", "netbios.command", FT_UINT8, BASE_HEX | BASE_EXT_STRING, |
1247 | 14 | &cmd_vals_ext, 0x0, NULL, HFILL }}, |
1248 | | |
1249 | 14 | { &hf_netb_hdr_len, |
1250 | 14 | { "Length", "netbios.hdr_len", FT_UINT16, BASE_DEC, |
1251 | 14 | NULL, 0x0, "Header Length", HFILL }}, |
1252 | | |
1253 | 14 | { &hf_netb_delimiter, |
1254 | 14 | { "Delimiter", "netbios.delimiter", FT_UINT16, BASE_HEX, |
1255 | 14 | NULL, 0x0, NULL, HFILL }}, |
1256 | | |
1257 | 14 | { &hf_netb_xmit_corrl, |
1258 | 14 | { "Transmit Correlator", "netbios.xmit_corrl", FT_UINT16, BASE_HEX, |
1259 | 14 | NULL, 0x0, NULL, HFILL }}, |
1260 | | |
1261 | 14 | { &hf_netb_resp_corrl, |
1262 | 14 | { "Response Correlator", "netbios.resp_corrl", FT_UINT16, BASE_HEX, |
1263 | 14 | NULL, 0x0, NULL, HFILL }}, |
1264 | | |
1265 | 14 | { &hf_netb_call_name_type, |
1266 | 14 | { "Caller's Name Type", "netbios.call_name_type", FT_UINT8, BASE_HEX, |
1267 | 14 | VALS(name_types), 0x0, NULL, HFILL }}, |
1268 | | |
1269 | 14 | { &hf_netb_nb_name_type, |
1270 | 14 | { "NetBIOS Name Type", "netbios.nb_name_type", FT_UINT8, BASE_HEX |BASE_EXT_STRING, |
1271 | 14 | &nb_name_type_vals_ext, 0x0, NULL, HFILL }}, |
1272 | | |
1273 | 14 | { &hf_netb_nb_name, |
1274 | 14 | { "NetBIOS Name", "netbios.nb_name", FT_STRING, BASE_NONE, |
1275 | 14 | NULL, 0x0, NULL, HFILL }}, |
1276 | | |
1277 | 14 | { &hf_netb_version, |
1278 | 14 | { "NetBIOS Version", "netbios.version", FT_BOOLEAN, 8, |
1279 | 14 | TFS( &netb_version_str), 0x01, NULL, HFILL }}, |
1280 | | |
1281 | 14 | { &hf_netbios_no_receive_flags, |
1282 | 14 | { "Flags", "netbios.no_receive_flags", FT_UINT8, BASE_HEX, NULL, 0x0, |
1283 | 14 | NULL, HFILL }}, |
1284 | | |
1285 | 14 | { &hf_netbios_no_receive_flags_send_no_ack, |
1286 | 14 | { "SEND.NO.ACK data received", "netbios.no_receive_flags.send_no_ack", FT_BOOLEAN, 8, |
1287 | 14 | TFS( &tfs_no_yes), 0x02, NULL, HFILL }}, |
1288 | | |
1289 | 14 | { &hf_netb_largest_frame, |
1290 | 14 | { "Largest Frame", "netbios.largest_frame", FT_UINT8, BASE_DEC, |
1291 | 14 | VALS(max_frame_size_vals), 0x0E, NULL, HFILL }}, |
1292 | | |
1293 | 14 | { &hf_netb_status_buffer_len, |
1294 | 14 | { "Length of status buffer", "netbios.status_buffer_len", FT_UINT16, BASE_DEC, |
1295 | 14 | NULL, 0x0, NULL, HFILL }}, |
1296 | | |
1297 | 14 | { &hf_netb_status, |
1298 | 14 | { "Status", "netbios.status", FT_UINT8, BASE_DEC, |
1299 | 14 | VALS(status_vals), 0x0, NULL, HFILL }}, |
1300 | | |
1301 | 14 | { &hf_netb_name_type, |
1302 | 14 | { "Name type", "netbios.name_type", FT_UINT16, BASE_DEC, |
1303 | 14 | VALS(name_types), 0x0, NULL, HFILL }}, |
1304 | | |
1305 | 14 | { &hf_netb_max_data_recv_size, |
1306 | 14 | { "Maximum data receive size", "netbios.max_data_recv_size", FT_UINT16, BASE_DEC, |
1307 | 14 | NULL, 0x0, NULL, HFILL }}, |
1308 | | |
1309 | 14 | { &hf_netb_termination_indicator, |
1310 | 14 | { "Termination indicator", "netbios.termination_indicator", FT_UINT16, BASE_HEX, |
1311 | 14 | VALS(termination_indicator_vals), 0x0, NULL, HFILL }}, |
1312 | | |
1313 | 14 | { &hf_netb_num_data_bytes_accepted, |
1314 | 14 | { "Number of data bytes accepted", "netbios.num_data_bytes_accepted", FT_UINT16, BASE_DEC, |
1315 | 14 | NULL, 0x0, NULL, HFILL }}, |
1316 | | |
1317 | 14 | { &hf_netb_local_ses_no, |
1318 | 14 | { "Local Session No.", "netbios.local_session", FT_UINT8, BASE_HEX, |
1319 | 14 | NULL, 0x0, NULL, HFILL }}, |
1320 | | |
1321 | 14 | { &hf_netb_remote_ses_no, |
1322 | 14 | { "Remote Session No.", "netbios.remote_session", FT_UINT8, BASE_HEX, |
1323 | 14 | NULL, 0x0, NULL, HFILL }}, |
1324 | | |
1325 | 14 | { &hf_netb_flags, |
1326 | 14 | { "Flags", "netbios.flags", FT_UINT8, BASE_HEX, |
1327 | 14 | NULL, 0x0, NULL, HFILL }}, |
1328 | | |
1329 | 14 | { &hf_netb_flags_send_no_ack, |
1330 | 14 | { "Handle SEND.NO.ACK", "netbios.flags.send_no_ack", FT_BOOLEAN, 8, |
1331 | 14 | TFS( &tfs_yes_no), 0x80, NULL, HFILL }}, |
1332 | | |
1333 | 14 | { &hf_netb_flags_ack, |
1334 | 14 | { "Acknowledge", "netbios.flags.ack", FT_BOOLEAN, 8, |
1335 | 14 | TFS( &tfs_set_notset), 0x08, NULL, HFILL }}, |
1336 | | |
1337 | 14 | { &hf_netb_flags_ack_with_data, |
1338 | 14 | { "Acknowledge with data", "netbios.flags.ack_with_data", FT_BOOLEAN, 8, |
1339 | 14 | TFS( &tfs_allowed_not_allowed), 0x04, NULL, HFILL }}, |
1340 | | |
1341 | 14 | { &hf_netb_flags_ack_expected, |
1342 | 14 | { "Acknowledge expected", "netbios.flags.ack_expected", FT_BOOLEAN, 8, |
1343 | 14 | TFS( &tfs_yes_no), 0x02, NULL, HFILL }}, |
1344 | | |
1345 | 14 | { &hf_netb_flags_recv_cont_req, |
1346 | 14 | { "RECEIVE_CONTINUE requested", "netbios.flags.recv_cont_req", FT_BOOLEAN, 8, |
1347 | 14 | TFS( &tfs_yes_no), 0x01, NULL, HFILL }}, |
1348 | | |
1349 | 14 | { &hf_netb_data2, |
1350 | 14 | { "DATA2 value", "netbios.data2", FT_UINT16, BASE_HEX, |
1351 | 14 | NULL, 0x0, NULL, HFILL }}, |
1352 | | |
1353 | 14 | { &hf_netb_data2_frame, |
1354 | 14 | { "Data length exceeds maximum frame size", "netbios.data2.frame", FT_BOOLEAN, 16, |
1355 | 14 | TFS(&tfs_yes_no), 0x8000, NULL, HFILL }}, |
1356 | | |
1357 | 14 | { &hf_netb_data2_user, |
1358 | 14 | { "Data length exceeds user's buffer", "netbios.data2.user", FT_BOOLEAN, 16, |
1359 | 14 | TFS(&tfs_yes_no), 0x4000, NULL, HFILL }}, |
1360 | | |
1361 | 14 | { &hf_netb_data2_status, |
1362 | 14 | { "Status data length", "netbios.data2.status", FT_UINT16, BASE_DEC, |
1363 | 14 | NULL, 0x3FFF, NULL, HFILL }}, |
1364 | | |
1365 | 14 | { &hf_netb_datagram_mac, |
1366 | 14 | { "Sender's MAC Address", "netbios.datagram_mac", FT_ETHER, BASE_NONE, |
1367 | 14 | NULL, 0x0, NULL, HFILL }}, |
1368 | | |
1369 | 14 | { &hf_netb_datagram_bcast_mac, |
1370 | 14 | { "Sender's Node Address", "netbios.datagram_bcast_mac", FT_ETHER, BASE_NONE, |
1371 | 14 | NULL, 0x0, NULL, HFILL }}, |
1372 | | |
1373 | 14 | { &hf_netb_resync_indicator, |
1374 | 14 | { "Re-sync indicator", "netbios.resync_indicator", FT_UINT16, BASE_HEX, |
1375 | 14 | NULL, 0x0, NULL, HFILL }}, |
1376 | | |
1377 | 14 | { &hf_netb_status_request, |
1378 | 14 | { "Status request", "netbios.status_request", FT_UINT8, BASE_DEC, |
1379 | 14 | NULL, 0x0, NULL, HFILL }}, |
1380 | | |
1381 | 14 | { &hf_netb_local_session_no, |
1382 | 14 | { "Local Session No.", "netbios.local_session_no", FT_UINT8, BASE_HEX, |
1383 | 14 | NULL, 0x0, NULL, HFILL }}, |
1384 | | |
1385 | 14 | { &hf_netb_state_of_name, |
1386 | 14 | { "State of name", "netbios.state_of_name", FT_UINT8, BASE_HEX, |
1387 | 14 | NULL, 0x0, NULL, HFILL }}, |
1388 | | |
1389 | 14 | { &hf_netb_status_response, |
1390 | 14 | { "Status response", "netbios.status_response", FT_UINT8, BASE_DEC, |
1391 | 14 | NULL, 0x0, NULL, HFILL }}, |
1392 | | |
1393 | 14 | { &hf_netb_fragment_overlap, |
1394 | 14 | { "Fragment overlap", "netbios.fragment.overlap", FT_BOOLEAN, BASE_NONE, |
1395 | 14 | NULL, 0x0, "Fragment overlaps with other fragments", HFILL }}, |
1396 | | |
1397 | 14 | { &hf_netb_fragment_overlap_conflict, |
1398 | 14 | { "Conflicting data in fragment overlap", "netbios.fragment.overlap.conflict", |
1399 | 14 | FT_BOOLEAN, BASE_NONE, |
1400 | 14 | NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }}, |
1401 | | |
1402 | 14 | { &hf_netb_fragment_multiple_tails, |
1403 | 14 | { "Multiple tail fragments found", "netbios.fragment.multipletails", |
1404 | 14 | FT_BOOLEAN, BASE_NONE, |
1405 | 14 | NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }}, |
1406 | | |
1407 | 14 | { &hf_netb_fragment_too_long_fragment, |
1408 | 14 | { "Fragment too long", "netbios.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, |
1409 | 14 | NULL, 0x0, "Fragment contained data past end of packet", HFILL }}, |
1410 | | |
1411 | 14 | { &hf_netb_fragment_error, |
1412 | 14 | { "Defragmentation error", "netbios.fragment.error", FT_FRAMENUM, BASE_NONE, |
1413 | 14 | NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }}, |
1414 | | |
1415 | 14 | { &hf_netb_fragment_count, |
1416 | 14 | { "Fragment count", "netbios.fragment.count", FT_UINT32, BASE_DEC, |
1417 | 14 | NULL, 0x0, NULL, HFILL }}, |
1418 | | |
1419 | 14 | { &hf_netb_fragment, |
1420 | 14 | { "NetBIOS Fragment", "netbios.fragment", FT_FRAMENUM, BASE_NONE, |
1421 | 14 | NULL, 0x0, NULL, HFILL }}, |
1422 | | |
1423 | 14 | { &hf_netb_fragments, |
1424 | 14 | { "NetBIOS Fragments", "netbios.fragments", FT_NONE, BASE_NONE, |
1425 | 14 | NULL, 0x0, NULL, HFILL }}, |
1426 | | |
1427 | 14 | { &hf_netb_reassembled_length, |
1428 | 14 | {"Reassembled NetBIOS length", "netbios.reassembled.length", FT_UINT32, BASE_DEC, |
1429 | 14 | NULL, 0x0, "The total length of the reassembled payload", HFILL }}, |
1430 | 14 | }; |
1431 | | |
1432 | 14 | static ei_register_info ei[] = { |
1433 | 14 | { &ei_netb_unknown_command_data, { "netbios.unknown_command_data", PI_UNDECODED, PI_WARN, "Unknown NetBIOS command data", EXPFILL }}, |
1434 | 14 | }; |
1435 | | |
1436 | 14 | module_t *netbios_module; |
1437 | 14 | expert_module_t* expert_netbios; |
1438 | | |
1439 | 14 | proto_netbios = proto_register_protocol("NetBIOS", "NetBIOS", "netbios"); |
1440 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
1441 | 14 | proto_register_field_array(proto_netbios, hf_netb, array_length(hf_netb)); |
1442 | 14 | expert_netbios = expert_register_protocol(proto_netbios); |
1443 | 14 | expert_register_field_array(expert_netbios, ei, array_length(ei)); |
1444 | | |
1445 | 14 | netbios_handle = register_dissector("netbios", dissect_netbios, proto_netbios); |
1446 | 14 | netbios_cap_handle = register_capture_dissector("netbios", capture_netbios, proto_netbios); |
1447 | | |
1448 | 14 | netbios_heur_subdissector_list = register_heur_dissector_list_with_description("netbios", "NetBIOS payload", proto_netbios); |
1449 | | |
1450 | 14 | netbios_module = prefs_register_protocol(proto_netbios, NULL); |
1451 | 14 | prefs_register_bool_preference(netbios_module, "defragment", |
1452 | 14 | "Reassemble fragmented NetBIOS messages spanning multiple frames", |
1453 | 14 | "Whether the NetBIOS dissector should defragment messages spanning multiple frames", |
1454 | 14 | &netbios_defragment); |
1455 | | |
1456 | 14 | reassembly_table_register(&netbios_reassembly_table, |
1457 | 14 | &addresses_reassembly_table_functions); |
1458 | 14 | } |
1459 | | |
1460 | | void |
1461 | | proto_reg_handoff_netbios(void) |
1462 | 14 | { |
1463 | 14 | dissector_add_uint("llc.dsap", SAP_NETBIOS, netbios_handle); |
1464 | 14 | capture_dissector_add_uint("llc.dsap", SAP_NETBIOS, netbios_cap_handle); |
1465 | 14 | } |
1466 | | |
1467 | | |
1468 | | /* |
1469 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
1470 | | * |
1471 | | * Local variables: |
1472 | | * c-basic-offset: 8 |
1473 | | * tab-width: 8 |
1474 | | * indent-tabs-mode: t |
1475 | | * End: |
1476 | | * |
1477 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
1478 | | * :indentSize=8:tabSize=8:noTabs=false: |
1479 | | */ |