Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-nbd.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-nbd.c
2
 * Routines for Network Block Device (NBD) dissection.
3
 *
4
 * https://github.com/NetworkBlockDevice/nbd/blob/master/doc/proto.md
5
 *
6
 * Ronnie sahlberg 2006
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/prefs.h>
19
#include <epan/expert.h>
20
#include <epan/unit_strings.h>
21
#include <epan/tfs.h>
22
#include <wsutil/array.h>
23
#include "packet-tcp.h"
24
#include "packet-tls-utils.h"
25
26
void proto_register_nbd(void);
27
void proto_reg_handoff_nbd(void);
28
29
static int proto_nbd;
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;
91
92
static int ett_nbd;
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;
98
99
static expert_field ei_nbd_hnd_reply_error;
100
static expert_field ei_nbd_unexpected_data;
101
102
static dissector_handle_t nbd_handle;
103
static dissector_handle_t tls_handle;
104
105
static bool nbd_desegment = true;
106
107
static void apply_nbd_prefs(void);
108
109
14
#define NBD_TCP_PORTS "10809" /* IANA-registered */
110
111
static range_t *nbd_port_range;
112
113
typedef struct _nbd_transaction_t {
114
  uint32_t req_frame;
115
  uint32_t rep_frame;
116
  nstime_t req_time;
117
  uint32_t datalen;
118
  uint16_t type;
119
} nbd_transaction_t;
120
typedef struct _nbd_option_t {
121
  uint32_t req_frame;
122
  uint32_t rep_frame;
123
  nstime_t req_time;
124
  uint32_t opt;
125
} nbd_option_t;
126
typedef struct _nbd_conv_info_t {
127
  bool no_zeroes;
128
  wmem_tree_t *state;
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 */
133
} nbd_conv_info_t;
134
135
typedef enum _nbd_state_e {
136
  STATE_UNK = 0,
137
  STATE_HND_INIT,
138
  STATE_HND_OPT,
139
  STATE_HND_DONE
140
} nbd_state_e;
141
142
3
#define NBD_HND_INIT_MAGIC  0x4e42444d41474943 // "NBDMAGIC"
143
5
#define NBD_HND_OPT_MAGIC 0x49484156454F5054 // "IHAVEOPT"
144
19
#define NBD_HND_REPLY_MAGIC 0x03e889045565a9
145
14
#define NBD_HND_OLD_MAGIC 0x00420281861253
146
147
0
#define NBD_REQUEST_MAGIC   0x25609513
148
0
#define NBD_RESPONSE_MAGIC    0x67446698
149
0
#define NBD_STRUCTURED_REPLY_MAGIC  0x668e33ef
150
151
6
#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
46
#define NBD_OPT_STARTTLS  5
156
0
#define NBD_OPT_INFO    6
157
0
#define NBD_OPT_GO    7
158
#define NBD_OPT_STRUCTURED_REPLY  8
159
0
#define NBD_OPT_LIST_META_CONTEXT 9
160
0
#define NBD_OPT_SET_META_CONTEXT  10
161
#define NBD_OPT_EXTENDED_HEADERS  11
162
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"},
170
  {NBD_OPT_GO,    "Go"},
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"},
175
  {0, NULL}
176
};
177
178
0
#define NBD_INFO_EXPORT 0
179
0
#define NBD_INFO_NAME 1
180
0
#define NBD_INFO_DESCRIPTION  2
181
0
#define NBD_INFO_BLOCK_SIZE 3
182
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"},
188
  {0, NULL}
189
};
190
191
0
#define NBD_REP_ACK 1
192
0
#define NBD_REP_SERVER  2
193
0
#define NBD_REP_INFO  3
194
0
#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)
205
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"},
221
  {0, NULL}
222
};
223
224
0
#define NBD_CMD_READ      0
225
0
#define NBD_CMD_WRITE     1
226
#define NBD_CMD_DISC      2
227
#define NBD_CMD_FLUSH     3
228
0
#define NBD_CMD_TRIM      4
229
0
#define NBD_CMD_CACHE     5
230
0
#define NBD_CMD_WRITE_ZEROES    6
231
0
#define NBD_CMD_BLOCK_STATUS    7
232
#define NBD_CMD_RESIZE      8
233
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"},
244
  {0, NULL}
245
};
246
247
#define NBD_REPLY_NONE    0
248
0
#define NBD_REPLY_OFFSET_DATA 1
249
0
#define NBD_REPLY_OFFSET_HOLE 2
250
0
#define NBD_REPLY_BLOCK_STATUS  5
251
#define NBD_REPLY_BLOCK_STATUS_EXT 6
252
0
#define NBD_REPLY_ERROR   32769
253
0
#define NBD_REPLY_ERROR_OFFSET  32770
254
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"},
263
  {0, NULL}
264
};
265
266
#define NBD_SUCCESS 0
267
#define NBD_EPERM 1
268
#define NBD_EIO   5
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
275
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"},
286
  {0, NULL}
287
};
288
289
28
#define NBD_FLAG_NO_ZEROES 0x0002
290
291
static bool
292
nbd_from_server(packet_info *pinfo)
293
182
{
294
182
  if (value_is_in_range(nbd_port_range, pinfo->srcport)) {
295
0
    return true;
296
182
  } else if (value_is_in_range(nbd_port_range, pinfo->destport)) {
297
0
    return false;
298
0
  }
299
182
  return false;
300
182
}
301
302
static nbd_conv_info_t*
303
get_nbd_conv_info(packet_info *pinfo)
304
130
{
305
130
  conversation_t *conversation;
306
130
  nbd_conv_info_t *nbd_info;
307
308
130
  conversation = find_or_create_conversation(pinfo);
309
310
  /*
311
   * Do we already have a state structure for this conv
312
   */
313
130
  nbd_info = (nbd_conv_info_t *)conversation_get_proto_data(conversation, proto_nbd);
314
315
130
  if (!nbd_info) {
316
    /* No.  Attach that information to the conversation, and add
317
     * it to the list of information structures.
318
     */
319
12
    nbd_info = wmem_new(wmem_file_scope(), nbd_conv_info_t);
320
12
    nbd_info->no_zeroes    = false;
321
12
    nbd_info->state        = wmem_tree_new(wmem_file_scope());
322
12
    nbd_info->opts         = wmem_tree_new(wmem_file_scope());
323
12
    nbd_info->unacked_pdus = wmem_tree_new(wmem_file_scope());
324
12
    nbd_info->acked_pdus   = wmem_tree_new(wmem_file_scope());
325
326
12
    conversation_add_proto_data(conversation, proto_nbd, nbd_info);
327
12
  }
328
130
  return nbd_info;
329
130
}
330
331
static void
332
nbd_set_state(packet_info *pinfo, nbd_state_e state)
333
13
{
334
13
  nbd_conv_info_t *nbd_info;
335
13
  nbd_state_e current_state;
336
337
13
  nbd_info = get_nbd_conv_info(pinfo);
338
13
  current_state = (nbd_state_e)GPOINTER_TO_UINT(wmem_tree_lookup32_le(nbd_info->state, pinfo->num));
339
13
  if (current_state != state) {
340
10
    wmem_tree_insert32(nbd_info->state, pinfo->num, GUINT_TO_POINTER(state));
341
10
  }
342
13
}
343
344
/* This function will try to determine the complete size of a PDU
345
 * based on the information in the header.
346
 */
347
static unsigned
348
get_nbd_tcp_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset, void *data _U_)
349
0
{
350
0
  uint32_t magic, type, packet;
351
0
  conversation_t *conversation;
352
0
  nbd_conv_info_t *nbd_info;
353
0
  nbd_transaction_t *nbd_trans=NULL;
354
0
  wmem_tree_key_t hkey[3];
355
0
  uint32_t handle[2];
356
357
0
  magic=tvb_get_ntohl(tvb, offset);
358
359
0
  switch(magic){
360
0
  case NBD_REQUEST_MAGIC:
361
0
    type=tvb_get_ntohs(tvb, offset+6);
362
0
    switch(type){
363
0
    case NBD_CMD_WRITE:
364
0
      return tvb_get_ntohl(tvb, offset+24)+28;
365
0
    default:
366
      /*
367
       * NB: Length field should always be present (and zero)
368
       * for other types too.
369
       */
370
0
      return 28;
371
0
    }
372
0
  case NBD_RESPONSE_MAGIC:
373
    /*
374
     * Do we have a conversation for this connection?
375
     */
376
0
    conversation = find_conversation_pinfo(pinfo, 0);
377
0
    if (conversation == NULL) {
378
      /* No, so just return the rest of the current packet */
379
0
      return tvb_captured_length(tvb);
380
0
    }
381
    /*
382
     * Do we have a state structure for this conv
383
     */
384
0
    nbd_info = (nbd_conv_info_t *)conversation_get_proto_data(conversation, proto_nbd);
385
0
    if (!nbd_info) {
386
      /* No, so just return the rest of the current packet */
387
0
      return tvb_captured_length(tvb);
388
0
    }
389
0
    if(!pinfo->fd->visited){
390
      /*
391
       * Do we have a state structure for this transaction
392
       */
393
0
      handle[0]=tvb_get_ntohl(tvb, offset+8);
394
0
      handle[1]=tvb_get_ntohl(tvb, offset+12);
395
0
      hkey[0].length=2;
396
0
      hkey[0].key=handle;
397
0
      hkey[1].length=0;
398
0
      nbd_trans=(nbd_transaction_t *)wmem_tree_lookup32_array(nbd_info->unacked_pdus, hkey);
399
0
      if(!nbd_trans){
400
        /* No, so just return the rest of the current packet */
401
0
        return tvb_captured_length(tvb);
402
0
      }
403
0
    } else {
404
      /*
405
       * Do we have a state structure for this transaction
406
       */
407
0
      handle[0]=tvb_get_ntohl(tvb, offset+8);
408
0
      handle[1]=tvb_get_ntohl(tvb, offset+12);
409
0
      packet=pinfo->num;
410
0
      hkey[0].length=1;
411
0
      hkey[0].key=&packet;
412
0
      hkey[1].length=2;
413
0
      hkey[1].key=handle;
414
0
      hkey[2].length=0;
415
0
      nbd_trans=(nbd_transaction_t *)wmem_tree_lookup32_array(nbd_info->acked_pdus, hkey);
416
0
      if(!nbd_trans){
417
        /* No, so just return the rest of the current packet */
418
0
        return tvb_captured_length(tvb);
419
0
      }
420
0
    }
421
    /* If this is a read response we must add the datalen to
422
     * the pdu size
423
     */
424
0
    if(nbd_trans->type==NBD_CMD_READ){
425
0
      return 16+nbd_trans->datalen;
426
0
    } else {
427
0
      return 16;
428
0
    }
429
0
  case NBD_STRUCTURED_REPLY_MAGIC:
430
0
    return tvb_get_ntohl(tvb, offset+16)+20;
431
0
  default:
432
0
    break;
433
0
  }
434
435
  /* Did not really look like a NBD packet after all */
436
0
  return 0;
437
0
}
438
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,
446
  NULL,
447
};
448
449
static int * const nbd_reply_flags[] = {
450
  &hf_nbd_reply_flags_done,
451
  NULL,
452
};
453
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,
468
  NULL,
469
};
470
471
static int
472
dissect_nbd_structured_reply(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, unsigned type)
473
0
{
474
0
  proto_item *item;
475
0
  int offset = 0;
476
0
  uint32_t len;
477
478
0
  switch (type) {
479
0
  case NBD_REPLY_OFFSET_DATA:
480
0
    proto_tree_add_item(tree, hf_nbd_from, tvb, offset, 8, ENC_BIG_ENDIAN);
481
0
    offset += 8;
482
483
0
    proto_tree_add_item(tree, hf_nbd_data, tvb, offset, -1, ENC_NA);
484
0
    offset = tvb_reported_length(tvb);
485
0
    break;
486
487
0
  case NBD_REPLY_OFFSET_HOLE:
488
0
    proto_tree_add_item(tree, hf_nbd_from, tvb, offset, 8, ENC_BIG_ENDIAN);
489
0
    offset += 8;
490
491
0
    proto_tree_add_item(tree, hf_nbd_hole_size, tvb, offset, 4, ENC_NA);
492
0
    offset = tvb_reported_length(tvb);
493
0
    break;
494
495
0
  case NBD_REPLY_BLOCK_STATUS:
496
0
    proto_tree_add_item(tree, hf_nbd_meta_context_id, tvb, offset, 4, ENC_BIG_ENDIAN);
497
0
    offset += 4;
498
0
    while (tvb_reported_length_remaining(tvb, offset)) {
499
0
      proto_tree_add_item(tree, hf_nbd_len, tvb, offset, 4, ENC_BIG_ENDIAN);
500
0
      offset += 4;
501
0
      proto_tree_add_item(tree, hf_nbd_status_flags, tvb, offset, 4, ENC_BIG_ENDIAN);
502
0
      offset += 4;
503
0
    }
504
0
    break;
505
506
0
  case NBD_REPLY_ERROR:
507
0
    proto_tree_add_item(tree, hf_nbd_error, tvb, offset, 4, ENC_BIG_ENDIAN);
508
0
    offset += 4;
509
0
    proto_tree_add_item_ret_uint(tree, hf_nbd_error_msg_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len);
510
0
    offset += 2;
511
0
    proto_tree_add_item(tree, hf_nbd_error_msg, tvb, offset, len, ENC_UTF_8);
512
0
    break;
513
514
0
  case NBD_REPLY_ERROR_OFFSET:
515
0
    proto_tree_add_item(tree, hf_nbd_error, tvb, offset, 4, ENC_BIG_ENDIAN);
516
0
    offset += 4;
517
0
    proto_tree_add_item_ret_uint(tree, hf_nbd_error_msg_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len);
518
0
    offset += 2;
519
0
    proto_tree_add_item(tree, hf_nbd_error_msg, tvb, offset, len, ENC_UTF_8);
520
0
    offset += len;
521
0
    proto_tree_add_item(tree, hf_nbd_from, tvb, offset, 8, ENC_BIG_ENDIAN);
522
0
    offset += 8;
523
0
  }
524
525
0
  if (tvb_reported_length_remaining(tvb, offset)) {
526
0
    item = proto_tree_add_item(tree, hf_nbd_data, tvb, offset, -1, ENC_NA);
527
0
    expert_add_info(pinfo, item, &ei_nbd_unexpected_data);
528
0
  }
529
530
0
  return tvb_reported_length(tvb);
531
0
}
532
533
static int
534
dissect_nbd_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
535
0
{
536
0
  uint32_t magic, error, packet, data_len, type;
537
0
  uint32_t handle[2];
538
0
  uint64_t from;
539
0
  int offset=0;
540
0
  proto_tree *tree=NULL;
541
0
  proto_item *item=NULL;
542
0
  nbd_conv_info_t *nbd_info;
543
0
  nbd_transaction_t *nbd_trans=NULL;
544
0
  wmem_tree_key_t hkey[3];
545
546
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBD");
547
548
0
  col_clear(pinfo->cinfo, COL_INFO);
549
550
0
  item = proto_tree_add_item(parent_tree, proto_nbd, tvb, 0, -1, ENC_NA);
551
0
  tree = proto_item_add_subtree(item, ett_nbd);
552
553
554
0
  magic=tvb_get_ntohl(tvb, offset);
555
0
  proto_tree_add_item(tree, hf_nbd_magic, tvb, offset, 4, ENC_BIG_ENDIAN);
556
0
  offset+=4;
557
558
559
  /* grab what we need to do the request/response matching */
560
0
  switch(magic){
561
0
  case NBD_REQUEST_MAGIC:
562
0
  case NBD_RESPONSE_MAGIC:
563
0
  case NBD_STRUCTURED_REPLY_MAGIC:
564
0
    handle[0]=tvb_get_ntohl(tvb, offset+4);
565
0
    handle[1]=tvb_get_ntohl(tvb, offset+8);
566
0
    break;
567
0
  default:
568
0
    return 4;
569
0
  }
570
571
0
  nbd_info = get_nbd_conv_info(pinfo);
572
0
  if(!pinfo->fd->visited){
573
0
    switch (magic) {
574
0
    case NBD_REQUEST_MAGIC:
575
      /* This is a request */
576
0
      nbd_trans=wmem_new(wmem_file_scope(), nbd_transaction_t);
577
0
      nbd_trans->req_frame=pinfo->num;
578
0
      nbd_trans->rep_frame=0;
579
0
      nbd_trans->req_time=pinfo->abs_ts;
580
0
      nbd_trans->type=tvb_get_ntohl(tvb, offset);
581
0
      nbd_trans->datalen=tvb_get_ntohl(tvb, offset+20);
582
583
0
      hkey[0].length=2;
584
0
      hkey[0].key=handle;
585
0
      hkey[1].length=0;
586
587
0
      wmem_tree_insert32_array(nbd_info->unacked_pdus, hkey, (void *)nbd_trans);
588
0
      break;
589
590
0
    case NBD_RESPONSE_MAGIC:
591
0
    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.
596
       */
597
0
      hkey[0].length=2;
598
0
      hkey[0].key=handle;
599
0
      hkey[1].length=0;
600
601
0
      nbd_trans=(nbd_transaction_t *)wmem_tree_lookup32_array(nbd_info->unacked_pdus, hkey);
602
0
      if(nbd_trans){
603
0
        nbd_trans->rep_frame=pinfo->num;
604
605
0
        hkey[0].length=1;
606
0
        hkey[0].key=&nbd_trans->rep_frame;
607
0
        hkey[1].length=2;
608
0
        hkey[1].key=handle;
609
0
        hkey[2].length=0;
610
0
        wmem_tree_insert32_array(nbd_info->acked_pdus, hkey, (void *)nbd_trans);
611
0
        hkey[0].length=1;
612
0
        hkey[0].key=&nbd_trans->req_frame;
613
0
        hkey[1].length=2;
614
0
        hkey[1].key=handle;
615
0
        hkey[2].length=0;
616
0
        wmem_tree_insert32_array(nbd_info->acked_pdus, hkey, (void *)nbd_trans);
617
0
      }
618
0
      break;
619
0
    default:
620
0
      ws_assert_not_reached();
621
0
    }
622
0
  } else {
623
0
    packet=pinfo->num;
624
0
    hkey[0].length=1;
625
0
    hkey[0].key=&packet;
626
0
    hkey[1].length=2;
627
0
    hkey[1].key=handle;
628
0
    hkey[2].length=0;
629
630
0
    nbd_trans=(nbd_transaction_t *)wmem_tree_lookup32_array(nbd_info->acked_pdus, hkey);
631
0
  }
632
  /* The bloody handles are reused !!! even though they are 64 bits.
633
   * So we must verify we got the "correct" one
634
   */
635
0
  if( (magic==NBD_RESPONSE_MAGIC || magic==NBD_STRUCTURED_REPLY_MAGIC)
636
0
  &&  (nbd_trans)
637
0
  &&  (pinfo->num<nbd_trans->req_frame) ){
638
    /* must have been the wrong one */
639
0
    nbd_trans=NULL;
640
0
  }
641
642
0
  if(!nbd_trans){
643
    /* create a "fake" nbd_trans structure */
644
0
    nbd_trans=wmem_new(pinfo->pool, nbd_transaction_t);
645
0
    nbd_trans->req_frame=0;
646
0
    nbd_trans->rep_frame=0;
647
0
    nbd_trans->req_time=pinfo->abs_ts;
648
0
    if (magic == NBD_REQUEST_MAGIC) {
649
0
      nbd_trans->type=tvb_get_ntohl(tvb, offset);
650
0
      nbd_trans->datalen=tvb_get_ntohl(tvb, offset+20);
651
0
    } else {
652
0
      nbd_trans->type=0xffff;
653
0
      nbd_trans->datalen=0;
654
0
    }
655
0
  }
656
657
  /* print state tracking in the tree */
658
0
  switch (magic) {
659
0
  case NBD_REQUEST_MAGIC:
660
    /* This is a request */
661
0
    if(nbd_trans->rep_frame){
662
0
      proto_item *it;
663
664
0
      it=proto_tree_add_uint(tree, hf_nbd_response_in, tvb, 0, 0, nbd_trans->rep_frame);
665
0
      proto_item_set_generated(it);
666
0
    }
667
0
    break;
668
0
  case NBD_RESPONSE_MAGIC:
669
0
  case NBD_STRUCTURED_REPLY_MAGIC:
670
    /* This is a reply */
671
0
    if(nbd_trans->req_frame){
672
0
      proto_item *it;
673
0
      nstime_t ns;
674
675
0
      it=proto_tree_add_uint(tree, hf_nbd_response_to, tvb, 0, 0, nbd_trans->req_frame);
676
0
      proto_item_set_generated(it);
677
678
0
      nstime_delta(&ns, &pinfo->abs_ts, &nbd_trans->req_time);
679
0
      it=proto_tree_add_time(tree, hf_nbd_time, tvb, 0, 0, &ns);
680
0
      proto_item_set_generated(it);
681
0
    }
682
0
  }
683
684
685
0
  switch(magic){
686
0
  case NBD_REQUEST_MAGIC:
687
0
    proto_tree_add_bitmask(tree, tvb, offset, hf_nbd_cmd_flags,
688
0
      ett_nbd_cmd_flags, nbd_cmd_flags, ENC_BIG_ENDIAN);
689
0
    offset+=2;
690
691
0
    proto_tree_add_item(tree, hf_nbd_type, tvb, offset, 2, ENC_BIG_ENDIAN);
692
0
    offset+=2;
693
694
0
    proto_tree_add_item(tree, hf_nbd_handle, tvb, offset, 8, ENC_BIG_ENDIAN);
695
0
    offset+=8;
696
697
0
    from=tvb_get_ntoh64(tvb, offset);
698
0
    proto_tree_add_item(tree, hf_nbd_from, tvb, offset, 8, ENC_BIG_ENDIAN);
699
0
    offset+=8;
700
701
0
    proto_tree_add_item(tree, hf_nbd_len, tvb, offset, 4, ENC_BIG_ENDIAN);
702
0
    offset+=4;
703
704
0
    col_add_fstr(pinfo->cinfo, COL_INFO, "%s Request", val_to_str(nbd_trans->type, nbd_type_vals, "Unknown (%d)"));
705
0
    switch(nbd_trans->type){
706
0
    case NBD_CMD_WRITE:
707
0
    case NBD_CMD_READ:
708
0
    case NBD_CMD_TRIM:
709
0
    case NBD_CMD_CACHE:
710
0
    case NBD_CMD_WRITE_ZEROES:
711
0
    case NBD_CMD_BLOCK_STATUS:
712
0
      col_append_fstr(pinfo->cinfo, COL_INFO, "  Offset:0x%" PRIx64 " Length:%d", from, nbd_trans->datalen);
713
0
      break;
714
0
    }
715
716
0
    if(nbd_trans->type==NBD_CMD_WRITE){
717
0
      proto_tree_add_item(tree, hf_nbd_data, tvb, offset, nbd_trans->datalen, ENC_NA);
718
0
    }
719
0
    break;
720
0
  case NBD_RESPONSE_MAGIC:
721
0
    item=proto_tree_add_uint(tree, hf_nbd_type, tvb, 0, 0, nbd_trans->type);
722
0
    proto_item_set_generated(item);
723
724
0
    error=tvb_get_ntohl(tvb, offset);
725
0
    proto_tree_add_item(tree, hf_nbd_error, tvb, offset, 4, ENC_BIG_ENDIAN);
726
0
    offset+=4;
727
728
0
    proto_tree_add_item(tree, hf_nbd_handle, tvb, offset, 8, ENC_BIG_ENDIAN);
729
0
    offset+=8;
730
731
0
    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)"));
732
733
0
    if(nbd_trans->type==NBD_CMD_READ){
734
0
      proto_tree_add_item(tree, hf_nbd_data, tvb, offset, nbd_trans->datalen, ENC_NA);
735
0
    }
736
0
    break;
737
0
  case NBD_STRUCTURED_REPLY_MAGIC:
738
    /* structured reply flags */
739
0
    proto_tree_add_bitmask(tree, tvb, offset, hf_nbd_reply_flags,
740
0
      ett_nbd_reply_flags, nbd_reply_flags, ENC_BIG_ENDIAN);
741
0
    offset+=2;
742
0
    item = proto_tree_add_item_ret_uint(tree, hf_nbd_reply_type, tvb, offset, 2, ENC_BIG_ENDIAN, &type);
743
0
    if (type & 0x8000) {
744
0
      expert_add_info(pinfo, item, &ei_nbd_hnd_reply_error);
745
0
    }
746
0
    offset+=2;
747
748
0
    proto_tree_add_item(tree, hf_nbd_handle, tvb, offset, 8, ENC_BIG_ENDIAN);
749
0
    offset+=8;
750
751
0
    proto_tree_add_item_ret_uint(tree, hf_nbd_len, tvb, offset, 4, ENC_BIG_ENDIAN, &data_len);
752
0
    offset+=4;
753
754
0
    dissect_nbd_structured_reply(tvb_new_subset_length(tvb, offset, data_len), pinfo, tree, type);
755
    /*offset += data_len; */
756
0
  }
757
758
0
  return tvb_captured_length(tvb);
759
0
}
760
761
static int
762
dissect_nbd_transmission(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
763
91
{
764
91
  uint32_t magic, type;
765
91
  unsigned pdu_fixed;
766
767
  /* We want 8 to test the type */
768
91
  if (tvb_captured_length(tvb) < 8) {
769
0
    return 0;
770
0
  }
771
772
91
  magic = tvb_get_ntohl(tvb, 0);
773
91
  type = tvb_get_ntohs(tvb, 6);
774
775
91
  switch(magic){
776
0
  case NBD_REQUEST_MAGIC:
777
    /* verify type */
778
0
    if (!try_val_to_str(type, nbd_type_vals)) {
779
0
      return 0;
780
0
    }
781
0
    pdu_fixed = 28;
782
0
    break;
783
0
  case NBD_RESPONSE_MAGIC:
784
0
    pdu_fixed = 16;
785
0
    break;
786
0
  case NBD_STRUCTURED_REPLY_MAGIC:
787
    /* verify type */
788
0
    if (!try_val_to_str(type, nbd_reply_type_vals)) {
789
0
      return 0;
790
0
    }
791
0
    pdu_fixed = 20;
792
0
    break;
793
91
  default:
794
91
    return 0;
795
91
  }
796
797
0
  nbd_set_state(pinfo, STATE_HND_DONE);
798
0
  tcp_dissect_pdus(tvb, pinfo, tree, nbd_desegment, pdu_fixed, get_nbd_tcp_pdu_len, dissect_nbd_tcp_pdu, data);
799
0
  return tvb_captured_length(tvb);
800
91
}
801
802
static unsigned
803
get_nbd_opt_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
804
3
{
805
3
  unsigned pdu_len = tvb_get_uint32(tvb, offset + 12, ENC_BIG_ENDIAN);
806
807
3
  return 16 + pdu_len;
808
3
}
809
810
static int
811
dissect_nbd_opt_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
812
3
{
813
3
  proto_item *item;
814
3
  proto_tree *tree;
815
3
  int offset = 0;
816
3
  uint32_t opt, data_len, name_len, info_num;
817
3
  nbd_conv_info_t *nbd_info;
818
3
  nbd_option_t *nbd_opt;
819
3
  const uint8_t *export_name;
820
821
3
  item = proto_tree_add_item(parent_tree, proto_nbd, tvb, 0, -1, ENC_NA);
822
3
  tree = proto_item_add_subtree(item, ett_nbd);
823
824
3
  proto_tree_add_item(tree, hf_nbd_hnd_magic, tvb, offset, 8, ENC_BIG_ENDIAN);
825
3
  offset += 8;
826
827
3
  nbd_info = get_nbd_conv_info(pinfo);
828
3
  if (!PINFO_FD_VISITED(pinfo)) {
829
3
    nbd_opt = wmem_new(wmem_file_scope(), nbd_option_t);
830
3
    nbd_opt->req_frame=pinfo->num;
831
3
    nbd_opt->rep_frame=0;
832
3
    nbd_opt->req_time=pinfo->abs_ts;
833
3
    nbd_opt->opt=tvb_get_ntohl(tvb, offset);
834
835
3
    wmem_tree_insert32(nbd_info->opts, pinfo->num, (void *)nbd_opt);
836
3
  } else {
837
0
    nbd_opt = (nbd_option_t*)wmem_tree_lookup32(nbd_info->opts, pinfo->num);
838
0
    if (nbd_opt && nbd_opt->rep_frame) {
839
0
      item = proto_tree_add_uint(tree, hf_nbd_response_in, tvb, 0, 0, nbd_opt->rep_frame);
840
0
      proto_item_set_generated(item);
841
0
    }
842
0
  }
843
844
3
  proto_tree_add_item_ret_uint(tree, hf_nbd_hnd_opt, tvb, offset, 4, ENC_BIG_ENDIAN, &opt);
845
3
  col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, val_to_str(opt, nbd_opt_vals, "Unknown (%d)"));
846
847
3
  offset += 4;
848
849
3
  proto_tree_add_item_ret_uint(tree, hf_nbd_len, tvb, offset, 4, ENC_BIG_ENDIAN, &data_len);
850
3
  offset += 4;
851
852
3
  if (data_len) {
853
2
    switch (opt) {
854
0
    case NBD_OPT_EXPORT_NAME:
855
0
      proto_tree_add_item_ret_string(tree, hf_nbd_export_name, tvb, offset, data_len, ENC_UTF_8, pinfo->pool, &export_name);
856
0
      col_append_sep_str(pinfo->cinfo, COL_INFO, ":", export_name);
857
0
      break;
858
0
    case NBD_OPT_INFO:
859
0
    case NBD_OPT_GO:
860
0
      proto_tree_add_item_ret_uint(tree, hf_nbd_export_name_len, tvb, offset, 4, ENC_BIG_ENDIAN, &name_len);
861
0
      offset += 4;
862
0
      proto_tree_add_item(tree, hf_nbd_export_name, tvb, offset, name_len, ENC_UTF_8);
863
0
      offset += name_len;
864
0
      proto_tree_add_item_ret_uint(tree, hf_nbd_info_num, tvb, offset, 2, ENC_BIG_ENDIAN, &info_num);
865
0
      offset += 2;
866
0
      for (unsigned i = 0; i < info_num; ++i) {
867
0
        proto_tree_add_item(tree, hf_nbd_info, tvb, offset, 2, ENC_BIG_ENDIAN);
868
0
        offset += 2;
869
0
      }
870
0
      break;
871
0
    case NBD_OPT_LIST_META_CONTEXT:
872
0
    case NBD_OPT_SET_META_CONTEXT:
873
0
      proto_tree_add_item_ret_uint(tree, hf_nbd_export_name_len, tvb, offset, 4, ENC_BIG_ENDIAN, &name_len);
874
0
      offset += 4;
875
0
      proto_tree_add_item(tree, hf_nbd_export_name, tvb, offset, name_len, ENC_UTF_8);
876
0
      offset += name_len;
877
0
      proto_tree_add_item_ret_uint(tree, hf_nbd_query_num, tvb, offset, 4, ENC_BIG_ENDIAN, &info_num);
878
0
      offset += 4;
879
0
      for (unsigned i = 0; i < info_num; ++i) {
880
0
        proto_tree_add_item_ret_length(tree, hf_nbd_query, tvb, offset, 2, ENC_BIG_ENDIAN, &name_len);
881
0
        offset += name_len;
882
0
      }
883
0
      break;
884
2
    default:
885
2
      proto_tree_add_item(tree, hf_nbd_data, tvb, offset, data_len, ENC_NA);
886
2
    }
887
2
  }
888
889
1
  return tvb_captured_length(tvb);
890
3
}
891
892
static unsigned
893
get_nbd_opt_reply_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
894
24
{
895
24
  unsigned pdu_len = tvb_get_uint32(tvb, offset + 16, ENC_BIG_ENDIAN);
896
897
24
  return 20 + pdu_len;
898
24
}
899
900
static int
901
dissect_nbd_opt_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned type)
902
23
{
903
23
  proto_item *item;
904
23
  int offset = 0;
905
23
  uint32_t name_len, info_type;
906
907
23
  switch (type) {
908
0
  case NBD_REP_SERVER:
909
0
    proto_tree_add_item_ret_uint(tree, hf_nbd_export_name_len, tvb, offset, 4, ENC_BIG_ENDIAN, &name_len);
910
0
    offset += 4;
911
0
    proto_tree_add_item(tree, hf_nbd_export_name, tvb, offset, name_len, ENC_UTF_8);
912
0
    offset += name_len;
913
0
    break;
914
0
  case NBD_REP_INFO:
915
0
    proto_tree_add_item_ret_uint(tree, hf_nbd_info, tvb, offset, 2, ENC_BIG_ENDIAN, &info_type);
916
0
    offset += 2;
917
0
    switch (info_type) {
918
0
      case NBD_INFO_EXPORT:
919
0
      proto_tree_add_item(tree, hf_nbd_export_size, tvb, offset, 8, ENC_BIG_ENDIAN);
920
0
      offset += 8;
921
922
0
      proto_tree_add_bitmask(tree, tvb, offset, hf_nbd_trans_flags,
923
0
        ett_nbd_trans_flags, nbd_trans_flags, ENC_BIG_ENDIAN);
924
0
      offset += 2;
925
0
      break;
926
0
      case NBD_INFO_NAME:
927
0
      proto_tree_add_item(tree, hf_nbd_export_name, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_UTF_8);
928
0
      offset = tvb_reported_length(tvb);
929
0
      break;
930
0
      case NBD_INFO_DESCRIPTION:
931
0
      proto_tree_add_item(tree, hf_nbd_export_description, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_UTF_8);
932
0
      offset = tvb_reported_length(tvb);
933
0
      break;
934
0
      case NBD_INFO_BLOCK_SIZE:
935
0
      proto_tree_add_item(tree, hf_nbd_block_size_min, tvb, offset, 4, ENC_BIG_ENDIAN);
936
0
      offset += 4;
937
0
      proto_tree_add_item(tree, hf_nbd_block_size_prefer, tvb, offset, 4, ENC_BIG_ENDIAN);
938
0
      offset += 4;
939
0
      proto_tree_add_item(tree, hf_nbd_payload_size_max, tvb, offset, 4, ENC_BIG_ENDIAN);
940
0
      offset += 4;
941
0
    }
942
0
    break;
943
0
  case NBD_REP_META_CONTEXT:
944
0
    proto_tree_add_item(tree, hf_nbd_meta_context_id, tvb, offset, 4, ENC_BIG_ENDIAN);
945
0
    offset += 4;
946
0
    proto_tree_add_item(tree, hf_nbd_meta_context_name, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_UTF_8);
947
0
    offset = tvb_reported_length(tvb);
948
23
  }
949
950
23
  if (tvb_reported_length_remaining(tvb, offset)) {
951
11
    if (type & UINT32_C(1 << 31)) {
952
2
      proto_tree_add_item(tree, hf_nbd_error_msg, tvb, offset, -1, ENC_UTF_8);
953
9
    } else {
954
9
      item = proto_tree_add_item(tree, hf_nbd_data, tvb, offset, -1, ENC_NA);
955
9
      expert_add_info(pinfo, item, &ei_nbd_unexpected_data);
956
9
    }
957
11
  }
958
959
23
  return tvb_reported_length(tvb);
960
23
}
961
962
static int
963
dissect_nbd_opt_reply_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
964
23
{
965
23
  proto_item *item, *gen_item;
966
23
  proto_tree *tree;
967
23
  int offset = 0;
968
23
  uint32_t opt, reply, data_len;
969
23
  nbd_conv_info_t *nbd_info;
970
23
  nbd_option_t *nbd_opt;
971
972
23
  item = proto_tree_add_item(parent_tree, proto_nbd, tvb, 0, -1, ENC_NA);
973
23
  tree = proto_item_add_subtree(item, ett_nbd);
974
975
23
  item = proto_tree_add_item(tree, hf_nbd_hnd_magic, tvb, offset, 8, ENC_BIG_ENDIAN);
976
23
  offset += 8;
977
978
23
  nbd_info = get_nbd_conv_info(pinfo);
979
23
  nbd_opt = (nbd_option_t*)wmem_tree_lookup32_le(nbd_info->opts, pinfo->num);
980
981
23
  proto_tree_add_item_ret_uint(tree, hf_nbd_hnd_opt, tvb, offset, 4, ENC_BIG_ENDIAN, &opt);
982
23
  col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, val_to_str(opt, nbd_opt_vals, "Unknown (%d)"));
983
23
  offset += 4;
984
985
23
  if (nbd_opt && nbd_opt->opt == opt) {
986
0
    nbd_opt->rep_frame = pinfo->num;
987
988
0
    gen_item = proto_tree_add_uint(tree, hf_nbd_response_to, tvb, 0, 0, nbd_opt->req_frame);
989
0
    proto_item_set_generated(gen_item);
990
0
    proto_tree_move_item(tree, item, gen_item);
991
0
    item = gen_item;
992
993
0
    nstime_t ns;
994
0
    nstime_delta(&ns, &pinfo->abs_ts, &nbd_opt->req_time);
995
0
    gen_item = proto_tree_add_time(tree, hf_nbd_time, tvb, 0, 0, &ns);
996
0
    proto_item_set_generated(gen_item);
997
0
    proto_tree_move_item(tree, item, gen_item);
998
0
  }
999
1000
23
  item = proto_tree_add_item_ret_uint(tree, hf_nbd_hnd_reply, tvb, offset, 4, ENC_BIG_ENDIAN, &reply);
1001
23
  col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, val_to_str(reply, nbd_hnd_reply_vals, "Unknown (%d)"));
1002
23
  if (reply & UINT64_C(0x80000000)) {
1003
3
    expert_add_info(pinfo, item, &ei_nbd_hnd_reply_error);
1004
3
  }
1005
23
  if (opt == NBD_OPT_STARTTLS && reply == NBD_REP_ACK) {
1006
0
    ssl_starttls_ack(tls_handle, pinfo, nbd_handle);
1007
0
  }
1008
1009
23
  offset += 4;
1010
1011
23
  proto_tree_add_item_ret_uint(tree, hf_nbd_len, tvb, offset, 4, ENC_BIG_ENDIAN, &data_len);
1012
23
  offset += 4;
1013
1014
23
  dissect_nbd_opt_reply(tvb_new_subset_length(tvb, offset, data_len), pinfo, tree, reply);
1015
23
  return tvb_captured_length(tvb);
1016
23
}
1017
1018
static unsigned
1019
get_nbd_export_len(packet_info *pinfo, tvbuff_t *tvb _U_, int offset _U_, void *data _U_)
1020
0
{
1021
0
  nbd_conv_info_t *nbd_info;
1022
1023
0
  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
0
  return 10 + (nbd_info->no_zeroes ? 0 : 124);
1027
0
}
1028
1029
static int
1030
dissect_nbd_export_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
1031
0
{
1032
0
  proto_item *item;
1033
0
  proto_tree *tree;
1034
0
  int offset = 0;
1035
0
  nbd_conv_info_t *nbd_info;
1036
0
  nbd_option_t *nbd_opt;
1037
1038
0
  item = proto_tree_add_item(parent_tree, proto_nbd, tvb, 0, -1, ENC_NA);
1039
0
  tree = proto_item_add_subtree(item, ett_nbd);
1040
1041
0
  nbd_info = get_nbd_conv_info(pinfo);
1042
0
  nbd_opt = (nbd_option_t*)wmem_tree_lookup32_le(nbd_info->opts, pinfo->num);
1043
1044
0
  if (nbd_opt && nbd_opt->opt == NBD_OPT_EXPORT_NAME) {
1045
0
    nbd_opt->rep_frame = pinfo->num;
1046
1047
0
    item = proto_tree_add_uint(tree, hf_nbd_response_to, tvb, 0, 0, nbd_opt->req_frame);
1048
0
    proto_item_set_generated(item);
1049
1050
0
    nstime_t ns;
1051
0
    nstime_delta(&ns, &pinfo->abs_ts, &nbd_opt->req_time);
1052
0
    item = proto_tree_add_time(tree, hf_nbd_time, tvb, 0, 0, &ns);
1053
0
    proto_item_set_generated(item);
1054
1055
0
    item = proto_tree_add_uint(tree, hf_nbd_hnd_opt, tvb, 0, 0, nbd_opt->opt);
1056
0
    proto_item_set_generated(item);
1057
0
  }
1058
1059
0
  proto_tree_add_item(tree, hf_nbd_export_size, tvb, offset, 8, ENC_BIG_ENDIAN);
1060
0
  offset += 8;
1061
1062
0
  proto_tree_add_bitmask(tree, tvb, offset, hf_nbd_trans_flags,
1063
0
    ett_nbd_trans_flags, nbd_trans_flags, ENC_BIG_ENDIAN);
1064
0
  col_set_str(pinfo->cinfo, COL_INFO, "Transmission Flags");
1065
0
  offset += 2;
1066
1067
0
  if (tvb_captured_length_remaining(tvb, offset)) {
1068
0
    proto_tree_add_item(tree, hf_nbd_reserved, tvb, offset, -1, ENC_NA);
1069
0
  }
1070
1071
0
  return tvb_captured_length(tvb);
1072
0
}
1073
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
1076
 * expansion.
1077
 */
1078
static int * const nbd_hnd_flags[] = {
1079
  &hf_nbd_hnd_flags_fixed_new,
1080
  &hf_nbd_hnd_flags_no_zeroes,
1081
  NULL,
1082
};
1083
1084
static int * const nbd_cli_flags[] = {
1085
  &hf_nbd_cli_flags_fixed_new,
1086
  &hf_nbd_cli_flags_no_zeroes,
1087
  NULL,
1088
};
1089
1090
static unsigned
1091
get_nbd_old_len(packet_info *pinfo _U_, tvbuff_t *tvb _U_, int offset _U_, void *data _U_)
1092
6
{
1093
6
  return 144; // 8 + 8 + 4 + 124
1094
6
}
1095
1096
static int
1097
dissect_nbd_old_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
1098
6
{
1099
6
  proto_item *item;
1100
6
  proto_tree *tree;
1101
6
  int offset = 0;
1102
1103
6
  col_set_str(pinfo->cinfo, COL_INFO, "Oldstyle Handshake");
1104
1105
6
  item = proto_tree_add_item(parent_tree, proto_nbd, tvb, 0, -1, ENC_NA);
1106
6
  tree = proto_item_add_subtree(item, ett_nbd);
1107
1108
6
  proto_tree_add_item(tree, hf_nbd_hnd_magic, tvb, offset, 8, ENC_BIG_ENDIAN);
1109
6
  offset += 8;
1110
1111
6
  proto_tree_add_item(tree, hf_nbd_export_size, tvb, offset, 8, ENC_BIG_ENDIAN);
1112
6
  offset += 8;
1113
1114
6
  proto_tree_add_bitmask(tree, tvb, offset, hf_nbd_hnd_flags,
1115
6
    ett_nbd_hnd_flags, nbd_hnd_flags, ENC_BIG_ENDIAN);
1116
6
  offset += 2;
1117
1118
6
  proto_tree_add_bitmask(tree, tvb, offset, hf_nbd_trans_flags,
1119
6
    ett_nbd_trans_flags, nbd_trans_flags, ENC_BIG_ENDIAN);
1120
6
  offset += 2;
1121
1122
6
  proto_tree_add_item(tree, hf_nbd_reserved, tvb, offset, 124, ENC_NA);
1123
1124
6
  return tvb_captured_length(tvb);
1125
6
}
1126
1127
static int
1128
dissect_nbd_hnd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void *data _U_)
1129
91
{
1130
91
  proto_item *item;
1131
91
  proto_tree *tree;
1132
91
  int offset = 0;
1133
91
  uint64_t magic;
1134
  //nbd_conv_info_t *nbd_info;
1135
1136
91
  nbd_state_e new_state;
1137
1138
  //nbd_info = get_nbd_conv_info(pinfo);
1139
91
  bool from_server = nbd_from_server(pinfo);
1140
1141
  /* We want 8 to test the magic number */
1142
91
  if (tvb_captured_length_remaining(tvb, offset) < 8) {
1143
0
    return 0;
1144
0
  }
1145
1146
91
  magic = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1147
1148
91
  switch (magic) {
1149
2
  case NBD_HND_INIT_MAGIC:
1150
2
    item = proto_tree_add_item(parent_tree, proto_nbd, tvb, 0, 8, ENC_NA);
1151
2
    tree = proto_item_add_subtree(item, ett_nbd);
1152
1153
2
    proto_tree_add_item(tree, hf_nbd_hnd_magic, tvb, offset, 8, ENC_BIG_ENDIAN);
1154
2
    col_set_str(pinfo->cinfo, COL_INFO, "Handshake Start");
1155
2
    nbd_set_state(pinfo, STATE_HND_INIT);
1156
2
    break;
1157
2
  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.
1160
     */
1161
2
    new_state = from_server ? STATE_HND_INIT : STATE_HND_OPT;
1162
2
    nbd_set_state(pinfo, new_state);
1163
2
    if (from_server) {
1164
0
      item = proto_tree_add_item(parent_tree, proto_nbd, tvb, 0, 8, ENC_NA);
1165
0
      tree = proto_item_add_subtree(item, ett_nbd);
1166
1167
0
      proto_tree_add_item(tree, hf_nbd_hnd_magic, tvb, offset, 8, ENC_BIG_ENDIAN);
1168
0
      col_set_str(pinfo->cinfo, COL_INFO, "Newstyle Handshake");
1169
2
    } else {
1170
2
      tcp_dissect_pdus(tvb, pinfo, parent_tree, nbd_desegment, 16, get_nbd_opt_len, dissect_nbd_opt_pdu, data);
1171
2
    }
1172
2
    break;
1173
9
  case NBD_HND_REPLY_MAGIC:
1174
9
    nbd_set_state(pinfo, STATE_HND_OPT);
1175
9
    tcp_dissect_pdus(tvb, pinfo, parent_tree, nbd_desegment, 20, get_nbd_opt_reply_len, dissect_nbd_opt_reply_pdu, data);
1176
9
    break;
1177
2
  case NBD_HND_OLD_MAGIC:
1178
2
    tcp_dissect_pdus(tvb, pinfo, parent_tree, nbd_desegment, 20, get_nbd_old_len, dissect_nbd_old_pdu, data);
1179
2
    break;
1180
76
  default:
1181
76
    return 0;
1182
91
  }
1183
1184
11
  return tvb_captured_length(tvb);
1185
91
}
1186
1187
static int
1188
dissect_nbd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
1189
91
{
1190
91
  int offset=0;
1191
91
  proto_tree *tree=NULL;
1192
91
  proto_item *item=NULL;
1193
91
  nbd_conv_info_t *nbd_info;
1194
1195
91
  nbd_state_e current_state;
1196
1197
91
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBD");
1198
1199
91
  col_clear(pinfo->cinfo, COL_INFO);
1200
1201
91
  bool from_server = nbd_from_server(pinfo);
1202
91
  nbd_info = get_nbd_conv_info(pinfo);
1203
91
  current_state = (nbd_state_e)GPOINTER_TO_UINT(wmem_tree_lookup32_le(nbd_info->state, pinfo->num));
1204
91
  nbd_option_t *nbd_opt;
1205
91
  nbd_opt = (nbd_option_t*)wmem_tree_lookup32_le(nbd_info->opts, pinfo->num);
1206
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.)
1211
   */
1212
1213
91
  if (!dissect_nbd_transmission(tvb, pinfo, parent_tree, data)) {
1214
91
    if (!dissect_nbd_hnd(tvb, pinfo, parent_tree, data)) {
1215
1216
76
      item = proto_tree_add_item(parent_tree, proto_nbd, tvb, 0, -1, ENC_NA);
1217
76
      tree = proto_item_add_subtree(item, ett_nbd);
1218
1219
76
      if (current_state == STATE_HND_INIT) {
1220
0
        uint64_t flags;
1221
0
        if (from_server) {
1222
0
          proto_tree_add_bitmask(tree, tvb, offset, hf_nbd_hnd_flags,
1223
0
            ett_nbd_hnd_flags, nbd_hnd_flags, ENC_BIG_ENDIAN);
1224
0
          col_set_str(pinfo->cinfo, COL_INFO, "Handshake Flags");
1225
0
        } else {
1226
0
          proto_tree_add_bitmask_ret_uint64(tree, tvb, offset, hf_nbd_cli_flags,
1227
0
            ett_nbd_hnd_flags, nbd_cli_flags, ENC_BIG_ENDIAN, &flags);
1228
0
          col_set_str(pinfo->cinfo, COL_INFO, "Client Flags");
1229
0
          if (flags & NBD_FLAG_NO_ZEROES) {
1230
0
            nbd_info->no_zeroes = true;
1231
0
          }
1232
0
        }
1233
76
      } else if (current_state == STATE_HND_OPT && nbd_opt && nbd_opt->opt == NBD_OPT_EXPORT_NAME) {
1234
0
        tcp_dissect_pdus(tvb, pinfo, tree, nbd_desegment, 10, get_nbd_export_len, dissect_nbd_export_pdu, data);
1235
0
      }
1236
76
    }
1237
91
  }
1238
91
  return tvb_captured_length(tvb);
1239
91
}
1240
1241
static bool
1242
dissect_nbd_tcp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1243
2.25k
{
1244
2.25k
  uint32_t magic, type;
1245
2.25k
  uint64_t magic64;
1246
2.25k
  conversation_t *conversation;
1247
2.25k
  conversation = find_or_create_conversation(pinfo);
1248
1249
  /* We need at least this much to tell whether this is NBD or not */
1250
2.25k
  if(tvb_captured_length(tvb)<4){
1251
70
    return false;
1252
70
  }
1253
1254
  /* Check if it looks like NBD */
1255
2.18k
  magic=tvb_get_ntohl(tvb, 0);
1256
2.18k
  switch(magic){
1257
0
  case NBD_REQUEST_MAGIC:
1258
    /* requests are 28 bytes or more */
1259
0
    if(tvb_captured_length(tvb)<28){
1260
0
      return false;
1261
0
    }
1262
    /* verify type */
1263
0
    type=tvb_get_ntohs(tvb, 6);
1264
0
    if (!try_val_to_str(type, nbd_type_vals)) {
1265
0
      return false;
1266
0
    }
1267
0
    conversation_set_dissector(conversation, nbd_handle);
1268
0
    tcp_dissect_pdus(tvb, pinfo, tree, nbd_desegment, 28, get_nbd_tcp_pdu_len, dissect_nbd_tcp_pdu, data);
1269
0
    return true;
1270
0
  case NBD_RESPONSE_MAGIC:
1271
    /* responses are 16 bytes or more */
1272
0
    if(tvb_captured_length(tvb)<16){
1273
0
      return false;
1274
0
    }
1275
0
    conversation_set_dissector(conversation, nbd_handle);
1276
0
    tcp_dissect_pdus(tvb, pinfo, tree, nbd_desegment, 16, get_nbd_tcp_pdu_len, dissect_nbd_tcp_pdu, data);
1277
0
    return true;
1278
0
  case NBD_STRUCTURED_REPLY_MAGIC:
1279
    /* structured replies are 20 bytes or more,
1280
     * and the length is in bytes 17-20. */
1281
0
    if(tvb_captured_length(tvb)<20){
1282
0
      return false;
1283
0
    }
1284
0
    conversation_set_dissector(conversation, nbd_handle);
1285
0
    tcp_dissect_pdus(tvb, pinfo, tree, nbd_desegment, 20, get_nbd_tcp_pdu_len, dissect_nbd_tcp_pdu, data);
1286
2.18k
  default:
1287
2.18k
    break;
1288
2.18k
  }
1289
1290
2.18k
  if (tvb_captured_length(tvb) < 8){
1291
83
    return false;
1292
83
  }
1293
2.10k
  magic64 = tvb_get_uint64(tvb, 0, ENC_BIG_ENDIAN);
1294
2.10k
  switch (magic64) {
1295
1
  case NBD_HND_INIT_MAGIC:
1296
3
  case NBD_HND_OPT_MAGIC:
1297
10
  case NBD_HND_REPLY_MAGIC:
1298
12
  case NBD_HND_OLD_MAGIC:
1299
12
    conversation_set_dissector(conversation, nbd_handle);
1300
12
    dissect_nbd(tvb, pinfo, tree, data);
1301
12
    return true;
1302
2.09k
  default:
1303
2.09k
    break;
1304
2.10k
  }
1305
1306
2.09k
  return false;
1307
2.10k
}
1308
1309
void proto_register_nbd(void)
1310
14
{
1311
14
  static hf_register_info hf[] = {
1312
14
    { &hf_nbd_hnd_magic,
1313
14
      { "Magic", "nbd.hnd.magic", FT_UINT64, BASE_HEX,
1314
14
        NULL, 0x0, NULL, HFILL }},
1315
14
    { &hf_nbd_hnd_flags,
1316
14
      { "Handshake Flags", "nbd.hnd.flags", FT_UINT16, BASE_HEX,
1317
14
        NULL, 0x0, NULL, HFILL }},
1318
14
    { &hf_nbd_hnd_flags_fixed_new,
1319
14
      { "Fixed Newstyle", "nbd.hnd.flags.fixed_new", FT_BOOLEAN, 16,
1320
14
       TFS(&tfs_set_notset), 0x0001, NULL, HFILL }},
1321
14
    { &hf_nbd_hnd_flags_no_zeroes,
1322
14
      { "No Zeroes", "nbd.hnd.flags.no_zeroes", FT_BOOLEAN, 16,
1323
14
        TFS(&tfs_set_notset), NBD_FLAG_NO_ZEROES, NULL, HFILL }},
1324
14
    { &hf_nbd_cli_flags,
1325
14
      { "Client Flags", "nbd.cli.flags", FT_UINT32, BASE_HEX,
1326
14
        NULL, 0x0, NULL, HFILL }},
1327
14
    { &hf_nbd_cli_flags_fixed_new,
1328
14
      { "Fixed Newstyle", "nbd.cli.flags.fixed_new", FT_BOOLEAN, 32,
1329
14
        TFS(&tfs_set_notset), 0x00000001, NULL, HFILL }},
1330
14
    { &hf_nbd_cli_flags_no_zeroes,
1331
14
      { "No Zeroes", "nbd.cli.flags.no_zeroes", FT_BOOLEAN, 32,
1332
14
        TFS(&tfs_set_notset), NBD_FLAG_NO_ZEROES, NULL, HFILL }},
1333
14
    { &hf_nbd_hnd_opt,
1334
14
      { "Option", "nbd.hnd.opt", FT_UINT32, BASE_HEX,
1335
14
        VALS(nbd_opt_vals), 0x0, NULL, HFILL }},
1336
14
    { &hf_nbd_hnd_reply,
1337
14
      { "Reply", "nbd.hnd.reply", FT_UINT32, BASE_HEX,
1338
14
        VALS(nbd_hnd_reply_vals), 0x0, NULL, HFILL }},
1339
14
    { &hf_nbd_magic,
1340
14
      { "Magic", "nbd.magic", FT_UINT32, BASE_HEX,
1341
14
        NULL, 0x0, NULL, HFILL }},
1342
14
    { &hf_nbd_cmd_flags,
1343
14
      { "Command Flags", "nbd.cmd.flags", FT_UINT16, BASE_HEX,
1344
14
        NULL, 0x0, NULL, HFILL }},
1345
14
    { &hf_nbd_cmd_flags_fua,
1346
14
      { "Forced Unit Access", "nbd.cmd.flags.fua", FT_BOOLEAN, 16,
1347
14
        TFS(&tfs_set_notset), 0x0001, NULL, HFILL }},
1348
14
    { &hf_nbd_cmd_flags_no_hole,
1349
14
      { "No Hole", "nbd.cmd.flags.no_hole", FT_BOOLEAN, 16,
1350
14
        TFS(&tfs_set_notset), 0x0002, NULL, HFILL }},
1351
14
    { &hf_nbd_cmd_flags_df,
1352
14
      { "Don't Fragment", "nbd.cmd.flags.df", FT_BOOLEAN, 16,
1353
14
        TFS(&tfs_set_notset), 0x0004, NULL, HFILL }},
1354
14
    { &hf_nbd_cmd_flags_req_one,
1355
14
      { "Request One", "nbd.cmd.flags.req_one", FT_BOOLEAN, 16,
1356
14
        TFS(&tfs_set_notset), 0x0008, NULL, HFILL }},
1357
14
    { &hf_nbd_cmd_flags_fast_zero,
1358
14
      { "Fast Zero", "nbd.cmd.flags.fast_zero", FT_BOOLEAN, 16,
1359
14
        TFS(&tfs_set_notset), 0x0010, NULL, HFILL }},
1360
14
    { &hf_nbd_cmd_flags_payload_len,
1361
14
      { "Payload Len", "nbd.cmd.flags.payload_len", FT_BOOLEAN, 16,
1362
14
        TFS(&tfs_set_notset), 0x0020, NULL, HFILL }},
1363
14
    { &hf_nbd_reply_flags,
1364
14
      { "Reply Flags", "nbd.reply.flags", FT_UINT16, BASE_HEX,
1365
14
        NULL, 0x0, NULL, HFILL }},
1366
14
    { &hf_nbd_reply_flags_done,
1367
14
      { "Done", "nbd.reply.flags.done", FT_BOOLEAN, 16,
1368
14
        TFS(&tfs_set_notset), 0x0001, NULL, HFILL }},
1369
14
    { &hf_nbd_export_size,
1370
14
      { "Export Size", "nbd.export.size", FT_UINT64, BASE_DEC|BASE_UNIT_STRING,
1371
14
        UNS(&units_byte_bytes), 0x0, NULL, HFILL }},
1372
14
    { &hf_nbd_trans_flags,
1373
14
      { "Transmission Flags", "nbd.export.trans.flags", FT_UINT16, BASE_HEX,
1374
14
        NULL, 0x0, NULL, HFILL }},
1375
14
    { &hf_nbd_trans_flags_has_flags,
1376
14
      { "Has Flags", "nbd.trans.flags.has_flags", FT_BOOLEAN, 16,
1377
14
        TFS(&tfs_set_notset), 0x0001, NULL, HFILL }},
1378
14
    { &hf_nbd_trans_flags_read_only,
1379
14
      { "Read Only", "nbd.trans.flags.read_only", FT_BOOLEAN, 16,
1380
14
        TFS(&tfs_set_notset), 0x0002, NULL, HFILL }},
1381
14
    { &hf_nbd_trans_flags_flush,
1382
14
      { "Flush", "nbd.trans.flags.flush", FT_BOOLEAN, 16,
1383
14
        TFS(&tfs_supported_not_supported), 0x0004, NULL, HFILL }},
1384
14
    { &hf_nbd_trans_flags_fua,
1385
14
      { "Forced Unit Access", "nbd.trans.flags.fua", FT_BOOLEAN, 16,
1386
14
        TFS(&tfs_supported_not_supported), 0x0008, NULL, HFILL }},
1387
14
    { &hf_nbd_trans_flags_rotational,
1388
14
      { "Rotational", "nbd.trans.flags.rotational", FT_BOOLEAN, 16,
1389
14
        TFS(&tfs_set_notset), 0x0010, NULL, HFILL }},
1390
14
    { &hf_nbd_trans_flags_trim,
1391
14
      { "Trim", "nbd.trans.flags.trim", FT_BOOLEAN, 16,
1392
14
        TFS(&tfs_supported_not_supported), 0x0020, NULL, HFILL }},
1393
14
    { &hf_nbd_trans_flags_write_zeroes,
1394
14
      { "Write Zeroes", "nbd.trans.flags.write_zeroes", FT_BOOLEAN, 16,
1395
14
        TFS(&tfs_supported_not_supported), 0x0040, NULL, HFILL }},
1396
14
    { &hf_nbd_trans_flags_df,
1397
14
      { "Don't Fragment", "nbd.trans.flags.df", FT_BOOLEAN, 16,
1398
14
        TFS(&tfs_supported_not_supported), 0x0080, NULL, HFILL }},
1399
14
    { &hf_nbd_trans_flags_multi_conn,
1400
14
      { "Multiple Connections", "nbd.trans.flags.multi_conn", FT_BOOLEAN, 16,
1401
14
        TFS(&tfs_supported_not_supported), 0x0100, NULL, HFILL }},
1402
14
    { &hf_nbd_trans_flags_resize,
1403
14
      { "Resize", "nbd.trans.flags.resize", FT_BOOLEAN, 16,
1404
14
        TFS(&tfs_supported_not_supported), 0x0200, NULL, HFILL }},
1405
14
    { &hf_nbd_trans_flags_cache,
1406
14
      { "Cache", "nbd.trans.flags.cache", FT_BOOLEAN, 16,
1407
14
        TFS(&tfs_supported_not_supported), 0x0400, NULL, HFILL }},
1408
14
    { &hf_nbd_trans_flags_fast_zero,
1409
14
      { "Fast Zeroes", "nbd.trans.flags.fast_zero", FT_BOOLEAN, 16,
1410
14
        TFS(&tfs_supported_not_supported), 0x0800, NULL, HFILL }},
1411
14
    { &hf_nbd_trans_flags_block_status_payload,
1412
14
      { "Block Status Payload", "nbd.trans.flags.block_status_payload", FT_BOOLEAN, 16,
1413
14
        TFS(&tfs_supported_not_supported), 0x1000, NULL, HFILL }},
1414
14
    { &hf_nbd_reserved,
1415
14
      { "Reserved (Zeroes)", "nbd.reserved", FT_BYTES, BASE_NONE,
1416
14
        NULL, 0x0, NULL, HFILL }},
1417
14
    { &hf_nbd_type,
1418
14
      { "Type", "nbd.type", FT_UINT16, BASE_DEC,
1419
14
        VALS(nbd_type_vals), 0x0, NULL, HFILL }},
1420
14
    { &hf_nbd_reply_type,
1421
14
      { "Reply Type", "nbd.reply.type", FT_UINT16, BASE_DEC,
1422
14
        VALS(nbd_reply_type_vals), 0x0, NULL, HFILL }},
1423
14
    { &hf_nbd_error,
1424
14
      { "Error", "nbd.error", FT_UINT32, BASE_DEC,
1425
14
        VALS(nbd_error_vals), 0x0, NULL, HFILL }},
1426
14
    { &hf_nbd_len,
1427
14
      { "Length", "nbd.len", FT_UINT32, BASE_DEC,
1428
14
        NULL, 0x0, NULL, HFILL }},
1429
14
    { &hf_nbd_handle,
1430
14
      { "Handle", "nbd.handle", FT_UINT64, BASE_HEX,
1431
14
        NULL, 0x0, NULL, HFILL }},
1432
14
    { &hf_nbd_from,
1433
14
      { "From", "nbd.from", FT_UINT64, BASE_HEX,
1434
14
        NULL, 0x0, NULL, HFILL }},
1435
14
    { &hf_nbd_response_in,
1436
14
      { "Response In", "nbd.response_in", FT_FRAMENUM, BASE_NONE,
1437
14
        FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0, "The response to this NBD request is in this frame", HFILL }},
1438
14
    { &hf_nbd_response_to,
1439
14
      { "Request In", "nbd.response_to", FT_FRAMENUM, BASE_NONE,
1440
14
        FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0, "This is a response to the NBD request in this frame", HFILL }},
1441
14
    { &hf_nbd_time,
1442
14
      { "Time", "nbd.time", FT_RELATIVE_TIME, BASE_NONE,
1443
14
        NULL, 0x0, "The time between the Call and the Reply", HFILL }},
1444
1445
14
    { &hf_nbd_export_name_len,
1446
14
      { "Export Name Length", "nbd.export.name.len", FT_UINT32, BASE_DEC,
1447
14
        NULL, 0x0, NULL, HFILL }},
1448
14
    { &hf_nbd_export_name,
1449
14
      { "Export Name", "nbd.export.name", FT_STRING, BASE_NONE,
1450
14
        NULL, 0x0, NULL, HFILL }},
1451
14
    { &hf_nbd_info_num,
1452
14
      { "Number of Information Requests", "nbd.info.num", FT_UINT16, BASE_DEC,
1453
14
        NULL, 0x0, NULL, HFILL }},
1454
14
    { &hf_nbd_info,
1455
14
      { "Information Type", "nbd.info", FT_UINT16, BASE_DEC,
1456
14
        VALS(nbd_info_vals), 0x0, NULL, HFILL }},
1457
14
    { &hf_nbd_query_num,
1458
14
      { "Number of Queries", "nbd.query.num", FT_UINT32, BASE_DEC,
1459
14
        NULL, 0x0, NULL, HFILL }},
1460
14
    { &hf_nbd_query,
1461
14
      { "Query", "nbd.query", FT_UINT_STRING, BASE_NONE,
1462
14
        NULL, 0x0, NULL, HFILL }},
1463
14
    { &hf_nbd_export_description,
1464
14
      { "Export Description", "nbd.export.description", FT_STRING, BASE_NONE,
1465
14
        NULL, 0x0, NULL, HFILL }},
1466
14
    { &hf_nbd_block_size_min,
1467
14
      { "Minimum Block Size", "nbd.block_size.min", FT_UINT32, BASE_DEC,
1468
14
        NULL, 0x0, NULL, HFILL }},
1469
14
    { &hf_nbd_block_size_prefer,
1470
14
      { "Preferred Block Size", "nbd.block_size.prefer", FT_UINT32, BASE_DEC,
1471
14
        NULL, 0x0, NULL, HFILL }},
1472
14
    { &hf_nbd_payload_size_max,
1473
14
      { "Maximum Payload Size", "nbd.payload_size.max", FT_UINT32, BASE_DEC,
1474
14
        NULL, 0x0, NULL, HFILL }},
1475
14
    { &hf_nbd_meta_context_id,
1476
14
      { "Metadata Context ID", "nbd.meta_context.id", FT_UINT32, BASE_DEC,
1477
14
        NULL, 0x0, NULL, HFILL }},
1478
14
    { &hf_nbd_meta_context_name,
1479
14
      { "Metadata Context Name", "nbd.meta_context.name", FT_STRING, BASE_NONE,
1480
14
        NULL, 0x0, NULL, HFILL }},
1481
14
    { &hf_nbd_error_msg_len,
1482
14
      { "Message Length", "nbd.error_msg.len", FT_UINT16, BASE_DEC,
1483
14
        NULL, 0x0, NULL, HFILL }},
1484
14
    { &hf_nbd_error_msg,
1485
14
      { "Error Message", "nbd.error_msg", FT_STRING, BASE_NONE,
1486
14
        NULL, 0x0, NULL, HFILL }},
1487
14
    { &hf_nbd_data,
1488
14
      { "Data", "nbd.data", FT_BYTES, BASE_NONE,
1489
14
        NULL, 0x0, NULL, HFILL }},
1490
14
    { &hf_nbd_hole_size,
1491
14
      { "Hole Size", "nbd.hole_size", FT_UINT32, BASE_DEC|BASE_UNIT_STRING,
1492
14
        UNS(&units_byte_bytes), 0x0, NULL, HFILL }},
1493
14
    { &hf_nbd_status_flags,
1494
14
      { "Block Status Flags", "nbd.status_flags", FT_UINT32, BASE_DEC,
1495
14
        NULL, 0x0, "Status flags as defined by metadata context", HFILL }},
1496
1497
14
  };
1498
1499
1500
14
  static int *ett[] = {
1501
14
    &ett_nbd,
1502
14
    &ett_nbd_hnd_flags,
1503
14
    &ett_nbd_cli_flags,
1504
14
    &ett_nbd_cmd_flags,
1505
14
    &ett_nbd_reply_flags,
1506
14
    &ett_nbd_trans_flags,
1507
14
  };
1508
1509
14
  static ei_register_info ei[] = {
1510
14
    { &ei_nbd_hnd_reply_error, {"nbd.hnd.reply.error", PI_RESPONSE_CODE, PI_NOTE, "Reply Error", EXPFILL }},
1511
14
    { &ei_nbd_unexpected_data, {"nbd.data.unexpected", PI_UNDECODED, PI_WARN, "Unexpected data", EXPFILL }},
1512
14
  };
1513
1514
14
  module_t *nbd_module;
1515
14
  expert_module_t *expert_nbd;
1516
1517
14
  proto_nbd = proto_register_protocol("Network Block Device",
1518
14
                                      "NBD", "nbd");
1519
14
  proto_register_field_array(proto_nbd, hf, array_length(hf));
1520
14
  proto_register_subtree_array(ett, array_length(ett));
1521
14
  expert_nbd = expert_register_protocol(proto_nbd);
1522
14
  expert_register_field_array(expert_nbd, ei, array_length(ei));
1523
1524
14
  nbd_module = prefs_register_protocol(proto_nbd, apply_nbd_prefs);
1525
14
  prefs_register_bool_preference(nbd_module, "desegment_nbd_messages",
1526
14
               "Reassemble NBD messages spanning multiple TCP segments",
1527
14
               "Whether the NBD dissector should reassemble messages spanning multiple TCP segments."
1528
14
               " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings",
1529
14
               &nbd_desegment);
1530
1531
14
  nbd_handle = register_dissector("nbd", dissect_nbd, proto_nbd);
1532
14
}
1533
1534
static void
1535
apply_nbd_prefs(void)
1536
14
{
1537
  // XXX - There should be a reset_uint_range ?
1538
14
  dissector_delete_uint_range("tls.port", nbd_port_range, nbd_handle);
1539
14
  nbd_port_range = prefs_get_range_value("NBD", "tcp.port");
1540
14
  dissector_add_uint_range("tls.port", nbd_port_range, nbd_handle);
1541
14
}
1542
1543
void
1544
proto_reg_handoff_nbd(void)
1545
14
{
1546
14
  heur_dissector_add("tcp", dissect_nbd_tcp_heur, "NBD over TCP", "nbd_tcp", proto_nbd, HEURISTIC_ENABLE);
1547
14
  dissector_add_uint_range_with_preference("tcp.port", NBD_TCP_PORTS, nbd_handle);
1548
14
  tls_handle = find_dissector_add_dependency("tls", proto_nbd);
1549
14
  apply_nbd_prefs();
1550
14
}
1551
1552
/*
1553
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1554
 *
1555
 * Local variables:
1556
 * c-basic-offset: 8
1557
 * tab-width: 8
1558
 * indent-tabs-mode: t
1559
 * End:
1560
 *
1561
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1562
 * :indentSize=8:tabSize=8:noTabs=false:
1563
 */