2 * Routines for Network Block Device (NBD) dissection.
4 * https://github.com/NetworkBlockDevice/nbd/blob/master/doc/proto.md
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include <epan/packet.h>
18 #include <epan/prefs.h>
19 #include <epan/expert.h>
20 #include <epan/unit_strings.h>
22 #include <wsutil/array.h>
23 #include "packet-tcp.h"
24 #include "packet-tls-utils.h"
26 void proto_register_nbd(void);
27 void proto_reg_handoff_nbd(void);
30 static int hf_nbd_hnd_magic
;
31 static int hf_nbd_hnd_flags
;
32 static int hf_nbd_hnd_flags_fixed_new
;
33 static int hf_nbd_hnd_flags_no_zeroes
;
34 static int hf_nbd_hnd_opt
;
35 static int hf_nbd_hnd_reply
;
36 static int hf_nbd_cli_flags
;
37 static int hf_nbd_cli_flags_fixed_new
;
38 static int hf_nbd_cli_flags_no_zeroes
;
39 static int hf_nbd_magic
;
40 static int hf_nbd_cmd_flags
;
41 static int hf_nbd_cmd_flags_fua
;
42 static int hf_nbd_cmd_flags_no_hole
;
43 static int hf_nbd_cmd_flags_df
;
44 static int hf_nbd_cmd_flags_req_one
;
45 static int hf_nbd_cmd_flags_fast_zero
;
46 static int hf_nbd_cmd_flags_payload_len
;
47 static int hf_nbd_reply_flags
;
48 static int hf_nbd_reply_flags_done
;
49 static int hf_nbd_export_size
;
50 static int hf_nbd_trans_flags
;
51 static int hf_nbd_trans_flags_has_flags
;
52 static int hf_nbd_trans_flags_read_only
;
53 static int hf_nbd_trans_flags_flush
;
54 static int hf_nbd_trans_flags_fua
;
55 static int hf_nbd_trans_flags_rotational
;
56 static int hf_nbd_trans_flags_trim
;
57 static int hf_nbd_trans_flags_write_zeroes
;
58 static int hf_nbd_trans_flags_df
;
59 static int hf_nbd_trans_flags_multi_conn
;
60 static int hf_nbd_trans_flags_resize
;
61 static int hf_nbd_trans_flags_cache
;
62 static int hf_nbd_trans_flags_fast_zero
;
63 static int hf_nbd_trans_flags_block_status_payload
;
64 static int hf_nbd_reserved
;
65 static int hf_nbd_type
;
66 static int hf_nbd_reply_type
;
67 static int hf_nbd_error
;
68 static int hf_nbd_handle
;
69 static int hf_nbd_from
;
70 static int hf_nbd_len
;
71 static int hf_nbd_response_in
;
72 static int hf_nbd_response_to
;
73 static int hf_nbd_time
;
74 static int hf_nbd_export_name_len
;
75 static int hf_nbd_export_name
;
76 static int hf_nbd_info_num
;
77 static int hf_nbd_info
;
78 static int hf_nbd_query_num
;
79 static int hf_nbd_query
;
80 static int hf_nbd_export_description
;
81 static int hf_nbd_block_size_min
;
82 static int hf_nbd_block_size_prefer
;
83 static int hf_nbd_payload_size_max
;
84 static int hf_nbd_meta_context_id
;
85 static int hf_nbd_meta_context_name
;
86 static int hf_nbd_error_msg_len
;
87 static int hf_nbd_error_msg
;
88 static int hf_nbd_data
;
89 static int hf_nbd_hole_size
;
90 static int hf_nbd_status_flags
;
93 static int ett_nbd_hnd_flags
;
94 static int ett_nbd_cli_flags
;
95 static int ett_nbd_cmd_flags
;
96 static int ett_nbd_reply_flags
;
97 static int ett_nbd_trans_flags
;
99 static expert_field ei_nbd_hnd_reply_error
;
100 static expert_field ei_nbd_unexpected_data
;
102 static dissector_handle_t nbd_handle
;
103 static dissector_handle_t tls_handle
;
105 static bool nbd_desegment
= true;
107 static void apply_nbd_prefs(void);
109 #define NBD_TCP_PORTS "10809" /* IANA-registered */
111 static range_t
*nbd_port_range
;
113 typedef struct _nbd_transaction_t
{
120 typedef struct _nbd_option_t
{
126 typedef struct _nbd_conv_info_t
{
129 wmem_tree_t
*opts
; /* indexed by packet# (per spec, client MUST not send
130 a new option until reply received for previous */
131 wmem_tree_t
*unacked_pdus
; /* indexed by handle, which wraps quite frequently */
132 wmem_tree_t
*acked_pdus
; /* indexed by packet# and handle */
135 typedef enum _nbd_state_e
{
142 #define NBD_HND_INIT_MAGIC 0x4e42444d41474943 // "NBDMAGIC"
143 #define NBD_HND_OPT_MAGIC 0x49484156454F5054 // "IHAVEOPT"
144 #define NBD_HND_REPLY_MAGIC 0x03e889045565a9
145 #define NBD_HND_OLD_MAGIC 0x00420281861253
147 #define NBD_REQUEST_MAGIC 0x25609513
148 #define NBD_RESPONSE_MAGIC 0x67446698
149 #define NBD_STRUCTURED_REPLY_MAGIC 0x668e33ef
151 #define NBD_OPT_EXPORT_NAME 1
152 #define NBD_OPT_ABORT 2
153 #define NBD_OPT_LIST 3
154 #define NBD_OPT_PEEK_EXPORT 4
155 #define NBD_OPT_STARTTLS 5
156 #define NBD_OPT_INFO 6
158 #define NBD_OPT_STRUCTURED_REPLY 8
159 #define NBD_OPT_LIST_META_CONTEXT 9
160 #define NBD_OPT_SET_META_CONTEXT 10
161 #define NBD_OPT_EXTENDED_HEADERS 11
163 static const value_string nbd_opt_vals
[] = {
164 {NBD_OPT_EXPORT_NAME
, "Export Name"},
165 {NBD_OPT_ABORT
, "Abort"},
166 {NBD_OPT_LIST
, "List"},
167 {NBD_OPT_PEEK_EXPORT
, "Peek Export"}, // Withdrawn
168 {NBD_OPT_STARTTLS
, "STARTTLS"},
169 {NBD_OPT_INFO
, "Info"},
171 {NBD_OPT_STRUCTURED_REPLY
, "Structured Reply"},
172 {NBD_OPT_LIST_META_CONTEXT
, "List Metadata Contexts"},
173 {NBD_OPT_SET_META_CONTEXT
, "Set Metadata Contexts"},
174 {NBD_OPT_EXTENDED_HEADERS
, "Extended Headers"},
178 #define NBD_INFO_EXPORT 0
179 #define NBD_INFO_NAME 1
180 #define NBD_INFO_DESCRIPTION 2
181 #define NBD_INFO_BLOCK_SIZE 3
183 static const value_string nbd_info_vals
[] = {
184 {NBD_INFO_EXPORT
, "Export"},
185 {NBD_INFO_NAME
, "Name"},
186 {NBD_INFO_DESCRIPTION
, "Description"},
187 {NBD_INFO_BLOCK_SIZE
, "Block Size"},
191 #define NBD_REP_ACK 1
192 #define NBD_REP_SERVER 2
193 #define NBD_REP_INFO 3
194 #define NBD_REP_META_CONTEXT 4
195 #define NBD_REP_ERR_UNSUP UINT32_C((1U << 31) + 1)
196 #define NBD_REP_ERR_POLICY UINT32_C((1U << 31) + 2)
197 #define NBD_REP_ERR_INVALID UINT32_C((1U << 31) + 3)
198 #define NBD_REP_ERR_PLATFORM UINT32_C((1U << 31) + 4)
199 #define NBD_REP_ERR_TLS_REQD UINT32_C((1U << 31) + 5)
200 #define NBD_REP_ERR_UNKNOWN UINT32_C((1U << 31) + 6)
201 #define NBD_REP_ERR_SHUTDOWN UINT32_C((1U << 31) + 7)
202 #define NBD_REP_ERR_BLOCK_SIZE_REQD UINT32_C((1U << 31) + 8)
203 #define NBD_REP_ERR_TOO_BIG UINT32_C((1U << 31) + 9)
204 #define NBD_REP_ERR_EXT_HEADER_REQD UINT32_C((1U << 31) + 10)
206 static const value_string nbd_hnd_reply_vals
[] = {
207 {NBD_REP_ACK
, "ACK"},
208 {NBD_REP_SERVER
, "Server"},
209 {NBD_REP_INFO
, "Information"},
210 {NBD_REP_META_CONTEXT
, "Metadata Context"},
211 {NBD_REP_ERR_UNSUP
, "Unknown option"},
212 {NBD_REP_ERR_POLICY
, "Forbidden by policy"},
213 {NBD_REP_ERR_INVALID
, "Syntactically or semantically invalid"},
214 {NBD_REP_ERR_PLATFORM
, "Unsupported by platform or as compiled"},
215 {NBD_REP_ERR_TLS_REQD
, "TLS required"},
216 {NBD_REP_ERR_UNKNOWN
, "Export not available"},
217 {NBD_REP_ERR_SHUTDOWN
, "Server shutdown in process"},
218 {NBD_REP_ERR_BLOCK_SIZE_REQD
, "Export requires negotiating non-default block size support"},
219 {NBD_REP_ERR_TOO_BIG
, "Request or reply too large to process"},
220 {NBD_REP_ERR_EXT_HEADER_REQD
, "Export requires negotiating extended header support"},
224 #define NBD_CMD_READ 0
225 #define NBD_CMD_WRITE 1
226 #define NBD_CMD_DISC 2
227 #define NBD_CMD_FLUSH 3
228 #define NBD_CMD_TRIM 4
229 #define NBD_CMD_CACHE 5
230 #define NBD_CMD_WRITE_ZEROES 6
231 #define NBD_CMD_BLOCK_STATUS 7
232 #define NBD_CMD_RESIZE 8
234 static const value_string nbd_type_vals
[] = {
235 {NBD_CMD_READ
, "Read"},
236 {NBD_CMD_WRITE
, "Write"},
237 {NBD_CMD_DISC
, "Disconnect"},
238 {NBD_CMD_FLUSH
, "Flush"},
239 {NBD_CMD_TRIM
, "Trim"},
240 {NBD_CMD_CACHE
, "Cache"},
241 {NBD_CMD_WRITE_ZEROES
, "Write Zeroes"},
242 {NBD_CMD_BLOCK_STATUS
, "Block Status"},
243 {NBD_CMD_RESIZE
, "Resize"},
247 #define NBD_REPLY_NONE 0
248 #define NBD_REPLY_OFFSET_DATA 1
249 #define NBD_REPLY_OFFSET_HOLE 2
250 #define NBD_REPLY_BLOCK_STATUS 5
251 #define NBD_REPLY_BLOCK_STATUS_EXT 6
252 #define NBD_REPLY_ERROR 32769
253 #define NBD_REPLY_ERROR_OFFSET 32770
255 static const value_string nbd_reply_type_vals
[] = {
256 {NBD_REPLY_NONE
, "NBD_REPLY_NONE"},
257 {NBD_REPLY_OFFSET_DATA
, "NBD_REPLY_OFFSET_DATA"},
258 {NBD_REPLY_OFFSET_HOLE
, "NBD_REPLY_OFFSET_HOLE"},
259 {NBD_REPLY_BLOCK_STATUS
, "NBD_REPLY_BLOCK_STATUS"},
260 {NBD_REPLY_BLOCK_STATUS_EXT
, "NBD_REPLY_BLOCK_STATUS_EXT"},
261 {NBD_REPLY_ERROR
, "NBD_REPLY_ERROR"},
262 {NBD_REPLY_ERROR_OFFSET
, "NBD_REPLY_ERROR_OFFSET"},
266 #define NBD_SUCCESS 0
269 #define NBD_ENOMEM 12
270 #define NBD_EINVAL 22
271 #define NBD_ENOSPC 28
272 #define NBD_EOVERFLOW 75
273 #define NBD_ENOTSUP 95
274 #define NBD_ESHUTDOWN 108
276 static const value_string nbd_error_vals
[] = {
277 {NBD_SUCCESS
, "Success"},
278 {NBD_EPERM
, "Operation not permitted"},
279 {NBD_EIO
, "Input/output error"},
280 {NBD_ENOMEM
, "Cannot allocate memory"},
281 {NBD_EINVAL
, "Invalid argument"},
282 {NBD_ENOSPC
, "No space left on device"},
283 {NBD_EOVERFLOW
, "Value too large"},
284 {NBD_ENOTSUP
, "Operation not supported"},
285 {NBD_ESHUTDOWN
, "Server is in the process of being shut down"},
289 #define NBD_FLAG_NO_ZEROES 0x0002
292 nbd_from_server(packet_info
*pinfo
)
294 if (value_is_in_range(nbd_port_range
, pinfo
->srcport
)) {
296 } else if (value_is_in_range(nbd_port_range
, pinfo
->destport
)) {
302 static nbd_conv_info_t
*
303 get_nbd_conv_info(packet_info
*pinfo
)
305 conversation_t
*conversation
;
306 nbd_conv_info_t
*nbd_info
;
308 conversation
= find_or_create_conversation(pinfo
);
311 * Do we already have a state structure for this conv
313 nbd_info
= (nbd_conv_info_t
*)conversation_get_proto_data(conversation
, proto_nbd
);
316 /* No. Attach that information to the conversation, and add
317 * it to the list of information structures.
319 nbd_info
= wmem_new(wmem_file_scope(), nbd_conv_info_t
);
320 nbd_info
->no_zeroes
= false;
321 nbd_info
->state
= wmem_tree_new(wmem_file_scope());
322 nbd_info
->opts
= wmem_tree_new(wmem_file_scope());
323 nbd_info
->unacked_pdus
= wmem_tree_new(wmem_file_scope());
324 nbd_info
->acked_pdus
= wmem_tree_new(wmem_file_scope());
326 conversation_add_proto_data(conversation
, proto_nbd
, nbd_info
);
332 nbd_set_state(packet_info
*pinfo
, nbd_state_e state
)
334 nbd_conv_info_t
*nbd_info
;
335 nbd_state_e current_state
;
337 nbd_info
= get_nbd_conv_info(pinfo
);
338 current_state
= (nbd_state_e
)GPOINTER_TO_UINT(wmem_tree_lookup32_le(nbd_info
->state
, pinfo
->num
));
339 if (current_state
!= state
) {
340 wmem_tree_insert32(nbd_info
->state
, pinfo
->num
, GUINT_TO_POINTER(state
));
344 /* This function will try to determine the complete size of a PDU
345 * based on the information in the header.
348 get_nbd_tcp_pdu_len(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, void *data _U_
)
350 uint32_t magic
, type
, packet
;
351 conversation_t
*conversation
;
352 nbd_conv_info_t
*nbd_info
;
353 nbd_transaction_t
*nbd_trans
=NULL
;
354 wmem_tree_key_t hkey
[3];
357 magic
=tvb_get_ntohl(tvb
, offset
);
360 case NBD_REQUEST_MAGIC
:
361 type
=tvb_get_ntohs(tvb
, offset
+6);
364 return tvb_get_ntohl(tvb
, offset
+24)+28;
367 * NB: Length field should always be present (and zero)
368 * for other types too.
372 case NBD_RESPONSE_MAGIC
:
374 * Do we have a conversation for this connection?
376 conversation
= find_conversation_pinfo(pinfo
, 0);
377 if (conversation
== NULL
) {
378 /* No, so just return the rest of the current packet */
379 return tvb_captured_length(tvb
);
382 * Do we have a state structure for this conv
384 nbd_info
= (nbd_conv_info_t
*)conversation_get_proto_data(conversation
, proto_nbd
);
386 /* No, so just return the rest of the current packet */
387 return tvb_captured_length(tvb
);
389 if(!pinfo
->fd
->visited
){
391 * Do we have a state structure for this transaction
393 handle
[0]=tvb_get_ntohl(tvb
, offset
+8);
394 handle
[1]=tvb_get_ntohl(tvb
, offset
+12);
398 nbd_trans
=(nbd_transaction_t
*)wmem_tree_lookup32_array(nbd_info
->unacked_pdus
, hkey
);
400 /* No, so just return the rest of the current packet */
401 return tvb_captured_length(tvb
);
405 * Do we have a state structure for this transaction
407 handle
[0]=tvb_get_ntohl(tvb
, offset
+8);
408 handle
[1]=tvb_get_ntohl(tvb
, offset
+12);
415 nbd_trans
=(nbd_transaction_t
*)wmem_tree_lookup32_array(nbd_info
->acked_pdus
, hkey
);
417 /* No, so just return the rest of the current packet */
418 return tvb_captured_length(tvb
);
421 /* If this is a read response we must add the datalen to
424 if(nbd_trans
->type
==NBD_CMD_READ
){
425 return 16+nbd_trans
->datalen
;
429 case NBD_STRUCTURED_REPLY_MAGIC
:
430 return tvb_get_ntohl(tvb
, offset
+16)+20;
435 /* Did not really look like a NBD packet after all */
439 static int * const nbd_cmd_flags
[] = {
440 &hf_nbd_cmd_flags_fua
,
441 &hf_nbd_cmd_flags_no_hole
,
442 &hf_nbd_cmd_flags_df
,
443 &hf_nbd_cmd_flags_req_one
,
444 &hf_nbd_cmd_flags_fast_zero
,
445 &hf_nbd_cmd_flags_payload_len
,
449 static int * const nbd_reply_flags
[] = {
450 &hf_nbd_reply_flags_done
,
454 static int * const nbd_trans_flags
[] = {
455 &hf_nbd_trans_flags_has_flags
,
456 &hf_nbd_trans_flags_read_only
,
457 &hf_nbd_trans_flags_flush
,
458 &hf_nbd_trans_flags_fua
,
459 &hf_nbd_trans_flags_rotational
,
460 &hf_nbd_trans_flags_trim
,
461 &hf_nbd_trans_flags_write_zeroes
,
462 &hf_nbd_trans_flags_df
,
463 &hf_nbd_trans_flags_multi_conn
,
464 &hf_nbd_trans_flags_resize
,
465 &hf_nbd_trans_flags_cache
,
466 &hf_nbd_trans_flags_fast_zero
,
467 &hf_nbd_trans_flags_block_status_payload
,
472 dissect_nbd_structured_reply(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, unsigned type
)
479 case NBD_REPLY_OFFSET_DATA
:
480 proto_tree_add_item(tree
, hf_nbd_from
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
483 proto_tree_add_item(tree
, hf_nbd_data
, tvb
, offset
, -1, ENC_NA
);
484 offset
= tvb_reported_length(tvb
);
487 case NBD_REPLY_OFFSET_HOLE
:
488 proto_tree_add_item(tree
, hf_nbd_from
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
491 proto_tree_add_item(tree
, hf_nbd_hole_size
, tvb
, offset
, 4, ENC_NA
);
492 offset
= tvb_reported_length(tvb
);
495 case NBD_REPLY_BLOCK_STATUS
:
496 proto_tree_add_item(tree
, hf_nbd_meta_context_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
498 while (tvb_reported_length_remaining(tvb
, offset
)) {
499 proto_tree_add_item(tree
, hf_nbd_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
501 proto_tree_add_item(tree
, hf_nbd_status_flags
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
506 case NBD_REPLY_ERROR
:
507 proto_tree_add_item(tree
, hf_nbd_error
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
509 proto_tree_add_item_ret_uint(tree
, hf_nbd_error_msg_len
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &len
);
511 proto_tree_add_item(tree
, hf_nbd_error_msg
, tvb
, offset
, len
, ENC_UTF_8
);
514 case NBD_REPLY_ERROR_OFFSET
:
515 proto_tree_add_item(tree
, hf_nbd_error
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
517 proto_tree_add_item_ret_uint(tree
, hf_nbd_error_msg_len
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &len
);
519 proto_tree_add_item(tree
, hf_nbd_error_msg
, tvb
, offset
, len
, ENC_UTF_8
);
521 proto_tree_add_item(tree
, hf_nbd_from
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
525 if (tvb_reported_length_remaining(tvb
, offset
)) {
526 item
= proto_tree_add_item(tree
, hf_nbd_data
, tvb
, offset
, -1, ENC_NA
);
527 expert_add_info(pinfo
, item
, &ei_nbd_unexpected_data
);
530 return tvb_reported_length(tvb
);
534 dissect_nbd_tcp_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
536 uint32_t magic
, error
, packet
, data_len
, type
;
540 proto_tree
*tree
=NULL
;
541 proto_item
*item
=NULL
;
542 nbd_conv_info_t
*nbd_info
;
543 nbd_transaction_t
*nbd_trans
=NULL
;
544 wmem_tree_key_t hkey
[3];
546 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "NBD");
548 col_clear(pinfo
->cinfo
, COL_INFO
);
550 item
= proto_tree_add_item(parent_tree
, proto_nbd
, tvb
, 0, -1, ENC_NA
);
551 tree
= proto_item_add_subtree(item
, ett_nbd
);
554 magic
=tvb_get_ntohl(tvb
, offset
);
555 proto_tree_add_item(tree
, hf_nbd_magic
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
559 /* grab what we need to do the request/response matching */
561 case NBD_REQUEST_MAGIC
:
562 case NBD_RESPONSE_MAGIC
:
563 case NBD_STRUCTURED_REPLY_MAGIC
:
564 handle
[0]=tvb_get_ntohl(tvb
, offset
+4);
565 handle
[1]=tvb_get_ntohl(tvb
, offset
+8);
571 nbd_info
= get_nbd_conv_info(pinfo
);
572 if(!pinfo
->fd
->visited
){
574 case NBD_REQUEST_MAGIC
:
575 /* This is a request */
576 nbd_trans
=wmem_new(wmem_file_scope(), nbd_transaction_t
);
577 nbd_trans
->req_frame
=pinfo
->num
;
578 nbd_trans
->rep_frame
=0;
579 nbd_trans
->req_time
=pinfo
->abs_ts
;
580 nbd_trans
->type
=tvb_get_ntohl(tvb
, offset
);
581 nbd_trans
->datalen
=tvb_get_ntohl(tvb
, offset
+20);
587 wmem_tree_insert32_array(nbd_info
->unacked_pdus
, hkey
, (void *)nbd_trans
);
590 case NBD_RESPONSE_MAGIC
:
591 case NBD_STRUCTURED_REPLY_MAGIC
:
592 /* There MAY be multiple structured reply chunk to the
593 * same request (with the same cookie/handle), instead
594 * of TCP segmentation. In that case the later ones
595 * will replace the older ones for matching.
601 nbd_trans
=(nbd_transaction_t
*)wmem_tree_lookup32_array(nbd_info
->unacked_pdus
, hkey
);
603 nbd_trans
->rep_frame
=pinfo
->num
;
606 hkey
[0].key
=&nbd_trans
->rep_frame
;
610 wmem_tree_insert32_array(nbd_info
->acked_pdus
, hkey
, (void *)nbd_trans
);
612 hkey
[0].key
=&nbd_trans
->req_frame
;
616 wmem_tree_insert32_array(nbd_info
->acked_pdus
, hkey
, (void *)nbd_trans
);
620 ws_assert_not_reached();
630 nbd_trans
=(nbd_transaction_t
*)wmem_tree_lookup32_array(nbd_info
->acked_pdus
, hkey
);
632 /* The bloody handles are reused !!! even though they are 64 bits.
633 * So we must verify we got the "correct" one
635 if( (magic
==NBD_RESPONSE_MAGIC
|| magic
==NBD_STRUCTURED_REPLY_MAGIC
)
637 && (pinfo
->num
<nbd_trans
->req_frame
) ){
638 /* must have been the wrong one */
643 /* create a "fake" nbd_trans structure */
644 nbd_trans
=wmem_new(pinfo
->pool
, nbd_transaction_t
);
645 nbd_trans
->req_frame
=0;
646 nbd_trans
->rep_frame
=0;
647 nbd_trans
->req_time
=pinfo
->abs_ts
;
648 if (magic
== NBD_REQUEST_MAGIC
) {
649 nbd_trans
->type
=tvb_get_ntohl(tvb
, offset
);
650 nbd_trans
->datalen
=tvb_get_ntohl(tvb
, offset
+20);
652 nbd_trans
->type
=0xffff;
653 nbd_trans
->datalen
=0;
657 /* print state tracking in the tree */
659 case NBD_REQUEST_MAGIC
:
660 /* This is a request */
661 if(nbd_trans
->rep_frame
){
664 it
=proto_tree_add_uint(tree
, hf_nbd_response_in
, tvb
, 0, 0, nbd_trans
->rep_frame
);
665 proto_item_set_generated(it
);
668 case NBD_RESPONSE_MAGIC
:
669 case NBD_STRUCTURED_REPLY_MAGIC
:
670 /* This is a reply */
671 if(nbd_trans
->req_frame
){
675 it
=proto_tree_add_uint(tree
, hf_nbd_response_to
, tvb
, 0, 0, nbd_trans
->req_frame
);
676 proto_item_set_generated(it
);
678 nstime_delta(&ns
, &pinfo
->abs_ts
, &nbd_trans
->req_time
);
679 it
=proto_tree_add_time(tree
, hf_nbd_time
, tvb
, 0, 0, &ns
);
680 proto_item_set_generated(it
);
686 case NBD_REQUEST_MAGIC
:
687 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_nbd_cmd_flags
,
688 ett_nbd_cmd_flags
, nbd_cmd_flags
, ENC_BIG_ENDIAN
);
691 proto_tree_add_item(tree
, hf_nbd_type
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
694 proto_tree_add_item(tree
, hf_nbd_handle
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
697 from
=tvb_get_ntoh64(tvb
, offset
);
698 proto_tree_add_item(tree
, hf_nbd_from
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
701 proto_tree_add_item(tree
, hf_nbd_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
704 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s Request", val_to_str(nbd_trans
->type
, nbd_type_vals
, "Unknown (%d)"));
705 switch(nbd_trans
->type
){
710 case NBD_CMD_WRITE_ZEROES
:
711 case NBD_CMD_BLOCK_STATUS
:
712 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " Offset:0x%" PRIx64
" Length:%d", from
, nbd_trans
->datalen
);
716 if(nbd_trans
->type
==NBD_CMD_WRITE
){
717 proto_tree_add_item(tree
, hf_nbd_data
, tvb
, offset
, nbd_trans
->datalen
, ENC_NA
);
720 case NBD_RESPONSE_MAGIC
:
721 item
=proto_tree_add_uint(tree
, hf_nbd_type
, tvb
, 0, 0, nbd_trans
->type
);
722 proto_item_set_generated(item
);
724 error
=tvb_get_ntohl(tvb
, offset
);
725 proto_tree_add_item(tree
, hf_nbd_error
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
728 proto_tree_add_item(tree
, hf_nbd_handle
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
731 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s Response %s", val_to_str(nbd_trans
->type
, nbd_type_vals
, "Unknown (%d)"), val_to_str(error
, nbd_error_vals
, "Unknown error (%d)"));
733 if(nbd_trans
->type
==NBD_CMD_READ
){
734 proto_tree_add_item(tree
, hf_nbd_data
, tvb
, offset
, nbd_trans
->datalen
, ENC_NA
);
737 case NBD_STRUCTURED_REPLY_MAGIC
:
738 /* structured reply flags */
739 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_nbd_reply_flags
,
740 ett_nbd_reply_flags
, nbd_reply_flags
, ENC_BIG_ENDIAN
);
742 item
= proto_tree_add_item_ret_uint(tree
, hf_nbd_reply_type
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &type
);
744 expert_add_info(pinfo
, item
, &ei_nbd_hnd_reply_error
);
748 proto_tree_add_item(tree
, hf_nbd_handle
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
751 proto_tree_add_item_ret_uint(tree
, hf_nbd_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &data_len
);
754 dissect_nbd_structured_reply(tvb_new_subset_length(tvb
, offset
, data_len
), pinfo
, tree
, type
);
755 /*offset += data_len; */
758 return tvb_captured_length(tvb
);
762 dissect_nbd_transmission(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
764 uint32_t magic
, type
;
767 /* We want 8 to test the type */
768 if (tvb_captured_length(tvb
) < 8) {
772 magic
= tvb_get_ntohl(tvb
, 0);
773 type
= tvb_get_ntohs(tvb
, 6);
776 case NBD_REQUEST_MAGIC
:
778 if (!try_val_to_str(type
, nbd_type_vals
)) {
783 case NBD_RESPONSE_MAGIC
:
786 case NBD_STRUCTURED_REPLY_MAGIC
:
788 if (!try_val_to_str(type
, nbd_reply_type_vals
)) {
797 nbd_set_state(pinfo
, STATE_HND_DONE
);
798 tcp_dissect_pdus(tvb
, pinfo
, tree
, nbd_desegment
, pdu_fixed
, get_nbd_tcp_pdu_len
, dissect_nbd_tcp_pdu
, data
);
799 return tvb_captured_length(tvb
);
803 get_nbd_opt_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
, void *data _U_
)
805 unsigned pdu_len
= tvb_get_uint32(tvb
, offset
+ 12, ENC_BIG_ENDIAN
);
811 dissect_nbd_opt_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
816 uint32_t opt
, data_len
, name_len
, info_num
;
817 nbd_conv_info_t
*nbd_info
;
818 nbd_option_t
*nbd_opt
;
819 const uint8_t *export_name
;
821 item
= proto_tree_add_item(parent_tree
, proto_nbd
, tvb
, 0, -1, ENC_NA
);
822 tree
= proto_item_add_subtree(item
, ett_nbd
);
824 proto_tree_add_item(tree
, hf_nbd_hnd_magic
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
827 nbd_info
= get_nbd_conv_info(pinfo
);
828 if (!PINFO_FD_VISITED(pinfo
)) {
829 nbd_opt
= wmem_new(wmem_file_scope(), nbd_option_t
);
830 nbd_opt
->req_frame
=pinfo
->num
;
831 nbd_opt
->rep_frame
=0;
832 nbd_opt
->req_time
=pinfo
->abs_ts
;
833 nbd_opt
->opt
=tvb_get_ntohl(tvb
, offset
);
835 wmem_tree_insert32(nbd_info
->opts
, pinfo
->num
, (void *)nbd_opt
);
837 nbd_opt
= (nbd_option_t
*)wmem_tree_lookup32(nbd_info
->opts
, pinfo
->num
);
838 if (nbd_opt
&& nbd_opt
->rep_frame
) {
839 item
= proto_tree_add_uint(tree
, hf_nbd_response_in
, tvb
, 0, 0, nbd_opt
->rep_frame
);
840 proto_item_set_generated(item
);
844 proto_tree_add_item_ret_uint(tree
, hf_nbd_hnd_opt
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &opt
);
845 col_append_sep_str(pinfo
->cinfo
, COL_INFO
, NULL
, val_to_str(opt
, nbd_opt_vals
, "Unknown (%d)"));
849 proto_tree_add_item_ret_uint(tree
, hf_nbd_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &data_len
);
854 case NBD_OPT_EXPORT_NAME
:
855 proto_tree_add_item_ret_string(tree
, hf_nbd_export_name
, tvb
, offset
, data_len
, ENC_UTF_8
, pinfo
->pool
, &export_name
);
856 col_append_sep_str(pinfo
->cinfo
, COL_INFO
, ":", export_name
);
860 proto_tree_add_item_ret_uint(tree
, hf_nbd_export_name_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &name_len
);
862 proto_tree_add_item(tree
, hf_nbd_export_name
, tvb
, offset
, name_len
, ENC_UTF_8
);
864 proto_tree_add_item_ret_uint(tree
, hf_nbd_info_num
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &info_num
);
866 for (unsigned i
= 0; i
< info_num
; ++i
) {
867 proto_tree_add_item(tree
, hf_nbd_info
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
871 case NBD_OPT_LIST_META_CONTEXT
:
872 case NBD_OPT_SET_META_CONTEXT
:
873 proto_tree_add_item_ret_uint(tree
, hf_nbd_export_name_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &name_len
);
875 proto_tree_add_item(tree
, hf_nbd_export_name
, tvb
, offset
, name_len
, ENC_UTF_8
);
877 proto_tree_add_item_ret_uint(tree
, hf_nbd_query_num
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &info_num
);
879 for (unsigned i
= 0; i
< info_num
; ++i
) {
880 proto_tree_add_item_ret_length(tree
, hf_nbd_query
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &name_len
);
885 proto_tree_add_item(tree
, hf_nbd_data
, tvb
, offset
, data_len
, ENC_NA
);
889 return tvb_captured_length(tvb
);
893 get_nbd_opt_reply_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
, void *data _U_
)
895 unsigned pdu_len
= tvb_get_uint32(tvb
, offset
+ 16, ENC_BIG_ENDIAN
);
901 dissect_nbd_opt_reply(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, unsigned type
)
905 uint32_t name_len
, info_type
;
909 proto_tree_add_item_ret_uint(tree
, hf_nbd_export_name_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &name_len
);
911 proto_tree_add_item(tree
, hf_nbd_export_name
, tvb
, offset
, name_len
, ENC_UTF_8
);
915 proto_tree_add_item_ret_uint(tree
, hf_nbd_info
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &info_type
);
918 case NBD_INFO_EXPORT
:
919 proto_tree_add_item(tree
, hf_nbd_export_size
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
922 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_nbd_trans_flags
,
923 ett_nbd_trans_flags
, nbd_trans_flags
, ENC_BIG_ENDIAN
);
927 proto_tree_add_item(tree
, hf_nbd_export_name
, tvb
, offset
, tvb_reported_length_remaining(tvb
, offset
), ENC_UTF_8
);
928 offset
= tvb_reported_length(tvb
);
930 case NBD_INFO_DESCRIPTION
:
931 proto_tree_add_item(tree
, hf_nbd_export_description
, tvb
, offset
, tvb_reported_length_remaining(tvb
, offset
), ENC_UTF_8
);
932 offset
= tvb_reported_length(tvb
);
934 case NBD_INFO_BLOCK_SIZE
:
935 proto_tree_add_item(tree
, hf_nbd_block_size_min
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
937 proto_tree_add_item(tree
, hf_nbd_block_size_prefer
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
939 proto_tree_add_item(tree
, hf_nbd_payload_size_max
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
943 case NBD_REP_META_CONTEXT
:
944 proto_tree_add_item(tree
, hf_nbd_meta_context_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
946 proto_tree_add_item(tree
, hf_nbd_meta_context_name
, tvb
, offset
, tvb_reported_length_remaining(tvb
, offset
), ENC_UTF_8
);
947 offset
= tvb_reported_length(tvb
);
950 if (tvb_reported_length_remaining(tvb
, offset
)) {
951 if (type
& UINT32_C(1 << 31)) {
952 proto_tree_add_item(tree
, hf_nbd_error_msg
, tvb
, offset
, -1, ENC_UTF_8
);
954 item
= proto_tree_add_item(tree
, hf_nbd_data
, tvb
, offset
, -1, ENC_NA
);
955 expert_add_info(pinfo
, item
, &ei_nbd_unexpected_data
);
959 return tvb_reported_length(tvb
);
963 dissect_nbd_opt_reply_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
965 proto_item
*item
, *gen_item
;
968 uint32_t opt
, reply
, data_len
;
969 nbd_conv_info_t
*nbd_info
;
970 nbd_option_t
*nbd_opt
;
972 item
= proto_tree_add_item(parent_tree
, proto_nbd
, tvb
, 0, -1, ENC_NA
);
973 tree
= proto_item_add_subtree(item
, ett_nbd
);
975 item
= proto_tree_add_item(tree
, hf_nbd_hnd_magic
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
978 nbd_info
= get_nbd_conv_info(pinfo
);
979 nbd_opt
= (nbd_option_t
*)wmem_tree_lookup32_le(nbd_info
->opts
, pinfo
->num
);
981 proto_tree_add_item_ret_uint(tree
, hf_nbd_hnd_opt
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &opt
);
982 col_append_sep_str(pinfo
->cinfo
, COL_INFO
, NULL
, val_to_str(opt
, nbd_opt_vals
, "Unknown (%d)"));
985 if (nbd_opt
&& nbd_opt
->opt
== opt
) {
986 nbd_opt
->rep_frame
= pinfo
->num
;
988 gen_item
= proto_tree_add_uint(tree
, hf_nbd_response_to
, tvb
, 0, 0, nbd_opt
->req_frame
);
989 proto_item_set_generated(gen_item
);
990 proto_tree_move_item(tree
, item
, gen_item
);
994 nstime_delta(&ns
, &pinfo
->abs_ts
, &nbd_opt
->req_time
);
995 gen_item
= proto_tree_add_time(tree
, hf_nbd_time
, tvb
, 0, 0, &ns
);
996 proto_item_set_generated(gen_item
);
997 proto_tree_move_item(tree
, item
, gen_item
);
1000 item
= proto_tree_add_item_ret_uint(tree
, hf_nbd_hnd_reply
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &reply
);
1001 col_append_sep_str(pinfo
->cinfo
, COL_INFO
, NULL
, val_to_str(reply
, nbd_hnd_reply_vals
, "Unknown (%d)"));
1002 if (reply
& UINT64_C(0x80000000)) {
1003 expert_add_info(pinfo
, item
, &ei_nbd_hnd_reply_error
);
1005 if (opt
== NBD_OPT_STARTTLS
&& reply
== NBD_REP_ACK
) {
1006 ssl_starttls_ack(tls_handle
, pinfo
, nbd_handle
);
1011 proto_tree_add_item_ret_uint(tree
, hf_nbd_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &data_len
);
1014 dissect_nbd_opt_reply(tvb_new_subset_length(tvb
, offset
, data_len
), pinfo
, tree
, reply
);
1015 return tvb_captured_length(tvb
);
1019 get_nbd_export_len(packet_info
*pinfo
, tvbuff_t
*tvb _U_
, int offset _U_
, void *data _U_
)
1021 nbd_conv_info_t
*nbd_info
;
1023 nbd_info
= get_nbd_conv_info(pinfo
);
1024 /* There might, or might not, be 124 bytes of zeroes, depending on
1025 * what was negotiated in the flags. */
1026 return 10 + (nbd_info
->no_zeroes
? 0 : 124);
1030 dissect_nbd_export_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
1035 nbd_conv_info_t
*nbd_info
;
1036 nbd_option_t
*nbd_opt
;
1038 item
= proto_tree_add_item(parent_tree
, proto_nbd
, tvb
, 0, -1, ENC_NA
);
1039 tree
= proto_item_add_subtree(item
, ett_nbd
);
1041 nbd_info
= get_nbd_conv_info(pinfo
);
1042 nbd_opt
= (nbd_option_t
*)wmem_tree_lookup32_le(nbd_info
->opts
, pinfo
->num
);
1044 if (nbd_opt
&& nbd_opt
->opt
== NBD_OPT_EXPORT_NAME
) {
1045 nbd_opt
->rep_frame
= pinfo
->num
;
1047 item
= proto_tree_add_uint(tree
, hf_nbd_response_to
, tvb
, 0, 0, nbd_opt
->req_frame
);
1048 proto_item_set_generated(item
);
1051 nstime_delta(&ns
, &pinfo
->abs_ts
, &nbd_opt
->req_time
);
1052 item
= proto_tree_add_time(tree
, hf_nbd_time
, tvb
, 0, 0, &ns
);
1053 proto_item_set_generated(item
);
1055 item
= proto_tree_add_uint(tree
, hf_nbd_hnd_opt
, tvb
, 0, 0, nbd_opt
->opt
);
1056 proto_item_set_generated(item
);
1059 proto_tree_add_item(tree
, hf_nbd_export_size
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1062 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_nbd_trans_flags
,
1063 ett_nbd_trans_flags
, nbd_trans_flags
, ENC_BIG_ENDIAN
);
1064 col_set_str(pinfo
->cinfo
, COL_INFO
, "Transmission Flags");
1067 if (tvb_captured_length_remaining(tvb
, offset
)) {
1068 proto_tree_add_item(tree
, hf_nbd_reserved
, tvb
, offset
, -1, ENC_NA
);
1071 return tvb_captured_length(tvb
);
1074 /* These flags have the same offset, but one is a 16 bit bitmask
1075 * and one is a 32 bit bitmask, which might matter for future
1078 static int * const nbd_hnd_flags
[] = {
1079 &hf_nbd_hnd_flags_fixed_new
,
1080 &hf_nbd_hnd_flags_no_zeroes
,
1084 static int * const nbd_cli_flags
[] = {
1085 &hf_nbd_cli_flags_fixed_new
,
1086 &hf_nbd_cli_flags_no_zeroes
,
1091 get_nbd_old_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, void *data _U_
)
1093 return 144; // 8 + 8 + 4 + 124
1097 dissect_nbd_old_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
1103 col_set_str(pinfo
->cinfo
, COL_INFO
, "Oldstyle Handshake");
1105 item
= proto_tree_add_item(parent_tree
, proto_nbd
, tvb
, 0, -1, ENC_NA
);
1106 tree
= proto_item_add_subtree(item
, ett_nbd
);
1108 proto_tree_add_item(tree
, hf_nbd_hnd_magic
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1111 proto_tree_add_item(tree
, hf_nbd_export_size
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1114 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_nbd_hnd_flags
,
1115 ett_nbd_hnd_flags
, nbd_hnd_flags
, ENC_BIG_ENDIAN
);
1118 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_nbd_trans_flags
,
1119 ett_nbd_trans_flags
, nbd_trans_flags
, ENC_BIG_ENDIAN
);
1122 proto_tree_add_item(tree
, hf_nbd_reserved
, tvb
, offset
, 124, ENC_NA
);
1124 return tvb_captured_length(tvb
);
1128 dissect_nbd_hnd(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void *data _U_
)
1134 //nbd_conv_info_t *nbd_info;
1136 nbd_state_e new_state
;
1138 //nbd_info = get_nbd_conv_info(pinfo);
1139 bool from_server
= nbd_from_server(pinfo
);
1141 /* We want 8 to test the magic number */
1142 if (tvb_captured_length_remaining(tvb
, offset
) < 8) {
1146 magic
= tvb_get_uint64(tvb
, offset
, ENC_BIG_ENDIAN
);
1149 case NBD_HND_INIT_MAGIC
:
1150 item
= proto_tree_add_item(parent_tree
, proto_nbd
, tvb
, 0, 8, ENC_NA
);
1151 tree
= proto_item_add_subtree(item
, ett_nbd
);
1153 proto_tree_add_item(tree
, hf_nbd_hnd_magic
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1154 col_set_str(pinfo
->cinfo
, COL_INFO
, "Handshake Start");
1155 nbd_set_state(pinfo
, STATE_HND_INIT
);
1157 case NBD_HND_OPT_MAGIC
:
1158 /* Unfortunately the server and client use the same OPT_MAGIC,
1159 * and they mean something different about what is expected next.
1161 new_state
= from_server
? STATE_HND_INIT
: STATE_HND_OPT
;
1162 nbd_set_state(pinfo
, new_state
);
1164 item
= proto_tree_add_item(parent_tree
, proto_nbd
, tvb
, 0, 8, ENC_NA
);
1165 tree
= proto_item_add_subtree(item
, ett_nbd
);
1167 proto_tree_add_item(tree
, hf_nbd_hnd_magic
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1168 col_set_str(pinfo
->cinfo
, COL_INFO
, "Newstyle Handshake");
1170 tcp_dissect_pdus(tvb
, pinfo
, parent_tree
, nbd_desegment
, 16, get_nbd_opt_len
, dissect_nbd_opt_pdu
, data
);
1173 case NBD_HND_REPLY_MAGIC
:
1174 nbd_set_state(pinfo
, STATE_HND_OPT
);
1175 tcp_dissect_pdus(tvb
, pinfo
, parent_tree
, nbd_desegment
, 20, get_nbd_opt_reply_len
, dissect_nbd_opt_reply_pdu
, data
);
1177 case NBD_HND_OLD_MAGIC
:
1178 tcp_dissect_pdus(tvb
, pinfo
, parent_tree
, nbd_desegment
, 20, get_nbd_old_len
, dissect_nbd_old_pdu
, data
);
1184 return tvb_captured_length(tvb
);
1188 dissect_nbd(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
1191 proto_tree
*tree
=NULL
;
1192 proto_item
*item
=NULL
;
1193 nbd_conv_info_t
*nbd_info
;
1195 nbd_state_e current_state
;
1197 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "NBD");
1199 col_clear(pinfo
->cinfo
, COL_INFO
);
1201 bool from_server
= nbd_from_server(pinfo
);
1202 nbd_info
= get_nbd_conv_info(pinfo
);
1203 current_state
= (nbd_state_e
)GPOINTER_TO_UINT(wmem_tree_lookup32_le(nbd_info
->state
, pinfo
->num
));
1204 nbd_option_t
*nbd_opt
;
1205 nbd_opt
= (nbd_option_t
*)wmem_tree_lookup32_le(nbd_info
->opts
, pinfo
->num
);
1207 /* NBD has 8 byte magic numbers for the handshake phase, and 4 byte
1208 * magic numbers for the transmission phase. A few handshake messages
1209 * are not preceded by magic numbers in that direction (and one magic
1210 * number is used for different messages types in the two directions.)
1213 if (!dissect_nbd_transmission(tvb
, pinfo
, parent_tree
, data
)) {
1214 if (!dissect_nbd_hnd(tvb
, pinfo
, parent_tree
, data
)) {
1216 item
= proto_tree_add_item(parent_tree
, proto_nbd
, tvb
, 0, -1, ENC_NA
);
1217 tree
= proto_item_add_subtree(item
, ett_nbd
);
1219 if (current_state
== STATE_HND_INIT
) {
1222 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_nbd_hnd_flags
,
1223 ett_nbd_hnd_flags
, nbd_hnd_flags
, ENC_BIG_ENDIAN
);
1224 col_set_str(pinfo
->cinfo
, COL_INFO
, "Handshake Flags");
1226 proto_tree_add_bitmask_ret_uint64(tree
, tvb
, offset
, hf_nbd_cli_flags
,
1227 ett_nbd_hnd_flags
, nbd_cli_flags
, ENC_BIG_ENDIAN
, &flags
);
1228 col_set_str(pinfo
->cinfo
, COL_INFO
, "Client Flags");
1229 if (flags
& NBD_FLAG_NO_ZEROES
) {
1230 nbd_info
->no_zeroes
= true;
1233 } else if (current_state
== STATE_HND_OPT
&& nbd_opt
&& nbd_opt
->opt
== NBD_OPT_EXPORT_NAME
) {
1234 tcp_dissect_pdus(tvb
, pinfo
, tree
, nbd_desegment
, 10, get_nbd_export_len
, dissect_nbd_export_pdu
, data
);
1238 return tvb_captured_length(tvb
);
1242 dissect_nbd_tcp_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
1244 uint32_t magic
, type
;
1246 conversation_t
*conversation
;
1247 conversation
= find_or_create_conversation(pinfo
);
1249 /* We need at least this much to tell whether this is NBD or not */
1250 if(tvb_captured_length(tvb
)<4){
1254 /* Check if it looks like NBD */
1255 magic
=tvb_get_ntohl(tvb
, 0);
1257 case NBD_REQUEST_MAGIC
:
1258 /* requests are 28 bytes or more */
1259 if(tvb_captured_length(tvb
)<28){
1263 type
=tvb_get_ntohs(tvb
, 6);
1264 if (!try_val_to_str(type
, nbd_type_vals
)) {
1267 conversation_set_dissector(conversation
, nbd_handle
);
1268 tcp_dissect_pdus(tvb
, pinfo
, tree
, nbd_desegment
, 28, get_nbd_tcp_pdu_len
, dissect_nbd_tcp_pdu
, data
);
1270 case NBD_RESPONSE_MAGIC
:
1271 /* responses are 16 bytes or more */
1272 if(tvb_captured_length(tvb
)<16){
1275 conversation_set_dissector(conversation
, nbd_handle
);
1276 tcp_dissect_pdus(tvb
, pinfo
, tree
, nbd_desegment
, 16, get_nbd_tcp_pdu_len
, dissect_nbd_tcp_pdu
, data
);
1278 case NBD_STRUCTURED_REPLY_MAGIC
:
1279 /* structured replies are 20 bytes or more,
1280 * and the length is in bytes 17-20. */
1281 if(tvb_captured_length(tvb
)<20){
1284 conversation_set_dissector(conversation
, nbd_handle
);
1285 tcp_dissect_pdus(tvb
, pinfo
, tree
, nbd_desegment
, 20, get_nbd_tcp_pdu_len
, dissect_nbd_tcp_pdu
, data
);
1290 if (tvb_captured_length(tvb
) < 8){
1293 magic64
= tvb_get_uint64(tvb
, 0, ENC_BIG_ENDIAN
);
1295 case NBD_HND_INIT_MAGIC
:
1296 case NBD_HND_OPT_MAGIC
:
1297 case NBD_HND_REPLY_MAGIC
:
1298 case NBD_HND_OLD_MAGIC
:
1299 conversation_set_dissector(conversation
, nbd_handle
);
1300 dissect_nbd(tvb
, pinfo
, tree
, data
);
1309 void proto_register_nbd(void)
1311 static hf_register_info hf
[] = {
1312 { &hf_nbd_hnd_magic
,
1313 { "Magic", "nbd.hnd.magic", FT_UINT64
, BASE_HEX
,
1314 NULL
, 0x0, NULL
, HFILL
}},
1315 { &hf_nbd_hnd_flags
,
1316 { "Handshake Flags", "nbd.hnd.flags", FT_UINT16
, BASE_HEX
,
1317 NULL
, 0x0, NULL
, HFILL
}},
1318 { &hf_nbd_hnd_flags_fixed_new
,
1319 { "Fixed Newstyle", "nbd.hnd.flags.fixed_new", FT_BOOLEAN
, 16,
1320 TFS(&tfs_set_notset
), 0x0001, NULL
, HFILL
}},
1321 { &hf_nbd_hnd_flags_no_zeroes
,
1322 { "No Zeroes", "nbd.hnd.flags.no_zeroes", FT_BOOLEAN
, 16,
1323 TFS(&tfs_set_notset
), NBD_FLAG_NO_ZEROES
, NULL
, HFILL
}},
1324 { &hf_nbd_cli_flags
,
1325 { "Client Flags", "nbd.cli.flags", FT_UINT32
, BASE_HEX
,
1326 NULL
, 0x0, NULL
, HFILL
}},
1327 { &hf_nbd_cli_flags_fixed_new
,
1328 { "Fixed Newstyle", "nbd.cli.flags.fixed_new", FT_BOOLEAN
, 32,
1329 TFS(&tfs_set_notset
), 0x00000001, NULL
, HFILL
}},
1330 { &hf_nbd_cli_flags_no_zeroes
,
1331 { "No Zeroes", "nbd.cli.flags.no_zeroes", FT_BOOLEAN
, 32,
1332 TFS(&tfs_set_notset
), NBD_FLAG_NO_ZEROES
, NULL
, HFILL
}},
1334 { "Option", "nbd.hnd.opt", FT_UINT32
, BASE_HEX
,
1335 VALS(nbd_opt_vals
), 0x0, NULL
, HFILL
}},
1336 { &hf_nbd_hnd_reply
,
1337 { "Reply", "nbd.hnd.reply", FT_UINT32
, BASE_HEX
,
1338 VALS(nbd_hnd_reply_vals
), 0x0, NULL
, HFILL
}},
1340 { "Magic", "nbd.magic", FT_UINT32
, BASE_HEX
,
1341 NULL
, 0x0, NULL
, HFILL
}},
1342 { &hf_nbd_cmd_flags
,
1343 { "Command Flags", "nbd.cmd.flags", FT_UINT16
, BASE_HEX
,
1344 NULL
, 0x0, NULL
, HFILL
}},
1345 { &hf_nbd_cmd_flags_fua
,
1346 { "Forced Unit Access", "nbd.cmd.flags.fua", FT_BOOLEAN
, 16,
1347 TFS(&tfs_set_notset
), 0x0001, NULL
, HFILL
}},
1348 { &hf_nbd_cmd_flags_no_hole
,
1349 { "No Hole", "nbd.cmd.flags.no_hole", FT_BOOLEAN
, 16,
1350 TFS(&tfs_set_notset
), 0x0002, NULL
, HFILL
}},
1351 { &hf_nbd_cmd_flags_df
,
1352 { "Don't Fragment", "nbd.cmd.flags.df", FT_BOOLEAN
, 16,
1353 TFS(&tfs_set_notset
), 0x0004, NULL
, HFILL
}},
1354 { &hf_nbd_cmd_flags_req_one
,
1355 { "Request One", "nbd.cmd.flags.req_one", FT_BOOLEAN
, 16,
1356 TFS(&tfs_set_notset
), 0x0008, NULL
, HFILL
}},
1357 { &hf_nbd_cmd_flags_fast_zero
,
1358 { "Fast Zero", "nbd.cmd.flags.fast_zero", FT_BOOLEAN
, 16,
1359 TFS(&tfs_set_notset
), 0x0010, NULL
, HFILL
}},
1360 { &hf_nbd_cmd_flags_payload_len
,
1361 { "Payload Len", "nbd.cmd.flags.payload_len", FT_BOOLEAN
, 16,
1362 TFS(&tfs_set_notset
), 0x0020, NULL
, HFILL
}},
1363 { &hf_nbd_reply_flags
,
1364 { "Reply Flags", "nbd.reply.flags", FT_UINT16
, BASE_HEX
,
1365 NULL
, 0x0, NULL
, HFILL
}},
1366 { &hf_nbd_reply_flags_done
,
1367 { "Done", "nbd.reply.flags.done", FT_BOOLEAN
, 16,
1368 TFS(&tfs_set_notset
), 0x0001, NULL
, HFILL
}},
1369 { &hf_nbd_export_size
,
1370 { "Export Size", "nbd.export.size", FT_UINT64
, BASE_DEC
|BASE_UNIT_STRING
,
1371 UNS(&units_byte_bytes
), 0x0, NULL
, HFILL
}},
1372 { &hf_nbd_trans_flags
,
1373 { "Transmission Flags", "nbd.export.trans.flags", FT_UINT16
, BASE_HEX
,
1374 NULL
, 0x0, NULL
, HFILL
}},
1375 { &hf_nbd_trans_flags_has_flags
,
1376 { "Has Flags", "nbd.trans.flags.has_flags", FT_BOOLEAN
, 16,
1377 TFS(&tfs_set_notset
), 0x0001, NULL
, HFILL
}},
1378 { &hf_nbd_trans_flags_read_only
,
1379 { "Read Only", "nbd.trans.flags.read_only", FT_BOOLEAN
, 16,
1380 TFS(&tfs_set_notset
), 0x0002, NULL
, HFILL
}},
1381 { &hf_nbd_trans_flags_flush
,
1382 { "Flush", "nbd.trans.flags.flush", FT_BOOLEAN
, 16,
1383 TFS(&tfs_supported_not_supported
), 0x0004, NULL
, HFILL
}},
1384 { &hf_nbd_trans_flags_fua
,
1385 { "Forced Unit Access", "nbd.trans.flags.fua", FT_BOOLEAN
, 16,
1386 TFS(&tfs_supported_not_supported
), 0x0008, NULL
, HFILL
}},
1387 { &hf_nbd_trans_flags_rotational
,
1388 { "Rotational", "nbd.trans.flags.rotational", FT_BOOLEAN
, 16,
1389 TFS(&tfs_set_notset
), 0x0010, NULL
, HFILL
}},
1390 { &hf_nbd_trans_flags_trim
,
1391 { "Trim", "nbd.trans.flags.trim", FT_BOOLEAN
, 16,
1392 TFS(&tfs_supported_not_supported
), 0x0020, NULL
, HFILL
}},
1393 { &hf_nbd_trans_flags_write_zeroes
,
1394 { "Write Zeroes", "nbd.trans.flags.write_zeroes", FT_BOOLEAN
, 16,
1395 TFS(&tfs_supported_not_supported
), 0x0040, NULL
, HFILL
}},
1396 { &hf_nbd_trans_flags_df
,
1397 { "Don't Fragment", "nbd.trans.flags.df", FT_BOOLEAN
, 16,
1398 TFS(&tfs_supported_not_supported
), 0x0080, NULL
, HFILL
}},
1399 { &hf_nbd_trans_flags_multi_conn
,
1400 { "Multiple Connections", "nbd.trans.flags.multi_conn", FT_BOOLEAN
, 16,
1401 TFS(&tfs_supported_not_supported
), 0x0100, NULL
, HFILL
}},
1402 { &hf_nbd_trans_flags_resize
,
1403 { "Resize", "nbd.trans.flags.resize", FT_BOOLEAN
, 16,
1404 TFS(&tfs_supported_not_supported
), 0x0200, NULL
, HFILL
}},
1405 { &hf_nbd_trans_flags_cache
,
1406 { "Cache", "nbd.trans.flags.cache", FT_BOOLEAN
, 16,
1407 TFS(&tfs_supported_not_supported
), 0x0400, NULL
, HFILL
}},
1408 { &hf_nbd_trans_flags_fast_zero
,
1409 { "Fast Zeroes", "nbd.trans.flags.fast_zero", FT_BOOLEAN
, 16,
1410 TFS(&tfs_supported_not_supported
), 0x0800, NULL
, HFILL
}},
1411 { &hf_nbd_trans_flags_block_status_payload
,
1412 { "Block Status Payload", "nbd.trans.flags.block_status_payload", FT_BOOLEAN
, 16,
1413 TFS(&tfs_supported_not_supported
), 0x1000, NULL
, HFILL
}},
1415 { "Reserved (Zeroes)", "nbd.reserved", FT_BYTES
, BASE_NONE
,
1416 NULL
, 0x0, NULL
, HFILL
}},
1418 { "Type", "nbd.type", FT_UINT16
, BASE_DEC
,
1419 VALS(nbd_type_vals
), 0x0, NULL
, HFILL
}},
1420 { &hf_nbd_reply_type
,
1421 { "Reply Type", "nbd.reply.type", FT_UINT16
, BASE_DEC
,
1422 VALS(nbd_reply_type_vals
), 0x0, NULL
, HFILL
}},
1424 { "Error", "nbd.error", FT_UINT32
, BASE_DEC
,
1425 VALS(nbd_error_vals
), 0x0, NULL
, HFILL
}},
1427 { "Length", "nbd.len", FT_UINT32
, BASE_DEC
,
1428 NULL
, 0x0, NULL
, HFILL
}},
1430 { "Handle", "nbd.handle", FT_UINT64
, BASE_HEX
,
1431 NULL
, 0x0, NULL
, HFILL
}},
1433 { "From", "nbd.from", FT_UINT64
, BASE_HEX
,
1434 NULL
, 0x0, NULL
, HFILL
}},
1435 { &hf_nbd_response_in
,
1436 { "Response In", "nbd.response_in", FT_FRAMENUM
, BASE_NONE
,
1437 FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE
), 0x0, "The response to this NBD request is in this frame", HFILL
}},
1438 { &hf_nbd_response_to
,
1439 { "Request In", "nbd.response_to", FT_FRAMENUM
, BASE_NONE
,
1440 FRAMENUM_TYPE(FT_FRAMENUM_REQUEST
), 0x0, "This is a response to the NBD request in this frame", HFILL
}},
1442 { "Time", "nbd.time", FT_RELATIVE_TIME
, BASE_NONE
,
1443 NULL
, 0x0, "The time between the Call and the Reply", HFILL
}},
1445 { &hf_nbd_export_name_len
,
1446 { "Export Name Length", "nbd.export.name.len", FT_UINT32
, BASE_DEC
,
1447 NULL
, 0x0, NULL
, HFILL
}},
1448 { &hf_nbd_export_name
,
1449 { "Export Name", "nbd.export.name", FT_STRING
, BASE_NONE
,
1450 NULL
, 0x0, NULL
, HFILL
}},
1452 { "Number of Information Requests", "nbd.info.num", FT_UINT16
, BASE_DEC
,
1453 NULL
, 0x0, NULL
, HFILL
}},
1455 { "Information Type", "nbd.info", FT_UINT16
, BASE_DEC
,
1456 VALS(nbd_info_vals
), 0x0, NULL
, HFILL
}},
1457 { &hf_nbd_query_num
,
1458 { "Number of Queries", "nbd.query.num", FT_UINT32
, BASE_DEC
,
1459 NULL
, 0x0, NULL
, HFILL
}},
1461 { "Query", "nbd.query", FT_UINT_STRING
, BASE_NONE
,
1462 NULL
, 0x0, NULL
, HFILL
}},
1463 { &hf_nbd_export_description
,
1464 { "Export Description", "nbd.export.description", FT_STRING
, BASE_NONE
,
1465 NULL
, 0x0, NULL
, HFILL
}},
1466 { &hf_nbd_block_size_min
,
1467 { "Minimum Block Size", "nbd.block_size.min", FT_UINT32
, BASE_DEC
,
1468 NULL
, 0x0, NULL
, HFILL
}},
1469 { &hf_nbd_block_size_prefer
,
1470 { "Preferred Block Size", "nbd.block_size.prefer", FT_UINT32
, BASE_DEC
,
1471 NULL
, 0x0, NULL
, HFILL
}},
1472 { &hf_nbd_payload_size_max
,
1473 { "Maximum Payload Size", "nbd.payload_size.max", FT_UINT32
, BASE_DEC
,
1474 NULL
, 0x0, NULL
, HFILL
}},
1475 { &hf_nbd_meta_context_id
,
1476 { "Metadata Context ID", "nbd.meta_context.id", FT_UINT32
, BASE_DEC
,
1477 NULL
, 0x0, NULL
, HFILL
}},
1478 { &hf_nbd_meta_context_name
,
1479 { "Metadata Context Name", "nbd.meta_context.name", FT_STRING
, BASE_NONE
,
1480 NULL
, 0x0, NULL
, HFILL
}},
1481 { &hf_nbd_error_msg_len
,
1482 { "Message Length", "nbd.error_msg.len", FT_UINT16
, BASE_DEC
,
1483 NULL
, 0x0, NULL
, HFILL
}},
1484 { &hf_nbd_error_msg
,
1485 { "Error Message", "nbd.error_msg", FT_STRING
, BASE_NONE
,
1486 NULL
, 0x0, NULL
, HFILL
}},
1488 { "Data", "nbd.data", FT_BYTES
, BASE_NONE
,
1489 NULL
, 0x0, NULL
, HFILL
}},
1490 { &hf_nbd_hole_size
,
1491 { "Hole Size", "nbd.hole_size", FT_UINT32
, BASE_DEC
|BASE_UNIT_STRING
,
1492 UNS(&units_byte_bytes
), 0x0, NULL
, HFILL
}},
1493 { &hf_nbd_status_flags
,
1494 { "Block Status Flags", "nbd.status_flags", FT_UINT32
, BASE_DEC
,
1495 NULL
, 0x0, "Status flags as defined by metadata context", HFILL
}},
1500 static int *ett
[] = {
1505 &ett_nbd_reply_flags
,
1506 &ett_nbd_trans_flags
,
1509 static ei_register_info ei
[] = {
1510 { &ei_nbd_hnd_reply_error
, {"nbd.hnd.reply.error", PI_RESPONSE_CODE
, PI_NOTE
, "Reply Error", EXPFILL
}},
1511 { &ei_nbd_unexpected_data
, {"nbd.data.unexpected", PI_UNDECODED
, PI_WARN
, "Unexpected data", EXPFILL
}},
1514 module_t
*nbd_module
;
1515 expert_module_t
*expert_nbd
;
1517 proto_nbd
= proto_register_protocol("Network Block Device",
1519 proto_register_field_array(proto_nbd
, hf
, array_length(hf
));
1520 proto_register_subtree_array(ett
, array_length(ett
));
1521 expert_nbd
= expert_register_protocol(proto_nbd
);
1522 expert_register_field_array(expert_nbd
, ei
, array_length(ei
));
1524 nbd_module
= prefs_register_protocol(proto_nbd
, apply_nbd_prefs
);
1525 prefs_register_bool_preference(nbd_module
, "desegment_nbd_messages",
1526 "Reassemble NBD messages spanning multiple TCP segments",
1527 "Whether the NBD dissector should reassemble messages spanning multiple TCP segments."
1528 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings",
1531 nbd_handle
= register_dissector("nbd", dissect_nbd
, proto_nbd
);
1535 apply_nbd_prefs(void)
1537 // XXX - There should be a reset_uint_range ?
1538 dissector_delete_uint_range("tls.port", nbd_port_range
, nbd_handle
);
1539 nbd_port_range
= prefs_get_range_value("NBD", "tcp.port");
1540 dissector_add_uint_range("tls.port", nbd_port_range
, nbd_handle
);
1544 proto_reg_handoff_nbd(void)
1546 heur_dissector_add("tcp", dissect_nbd_tcp_heur
, "NBD over TCP", "nbd_tcp", proto_nbd
, HEURISTIC_ENABLE
);
1547 dissector_add_uint_range_with_preference("tcp.port", NBD_TCP_PORTS
, nbd_handle
);
1548 tls_handle
= find_dissector_add_dependency("tls", proto_nbd
);
1553 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1558 * indent-tabs-mode: t
1561 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1562 * :indentSize=8:tabSize=8:noTabs=false: