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