Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-drbd.c
Line
Count
Source
1
/* packet-drbd.c
2
 * Routines for DRBD dissection
3
 * By Joel Colledge <joel.colledge@linbit.com>
4
 * Copyright 2019, LINBIT Information Technologies GmbH
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
/*
14
 * Wireshark dissector for DRBD - Distributed Replicated Block Device.
15
 * The DRBD Linux kernel module sources can be found at https://github.com/LINBIT/drbd
16
 * More information about Linbit and DRBD can be found at https://www.linbit.com/
17
 */
18
19
#include <config.h>
20
21
#include <epan/packet.h>
22
#include <epan/exceptions.h>
23
#include <epan/unit_strings.h>
24
#include "packet-tcp.h"
25
26
#include <wsutil/str_util.h>
27
#include <wsutil/array.h>
28
29
/* Known as SHARED_SECRET_MAX in the DRBD sources */
30
0
#define DRBD_STRING_MAX 64
31
32
enum drbd_packet {
33
    P_DATA                = 0x00,
34
    P_DATA_REPLY          = 0x01,
35
    P_RS_DATA_REPLY       = 0x02,
36
    P_BARRIER             = 0x03,
37
    P_BITMAP              = 0x04,
38
    P_BECOME_SYNC_TARGET  = 0x05,
39
    P_BECOME_SYNC_SOURCE  = 0x06,
40
    P_UNPLUG_REMOTE       = 0x07,
41
    P_DATA_REQUEST        = 0x08,
42
    P_RS_DATA_REQUEST     = 0x09,
43
    P_SYNC_PARAM          = 0x0a,
44
    P_PROTOCOL            = 0x0b,
45
    P_UUIDS               = 0x0c,
46
    P_SIZES               = 0x0d,
47
    P_STATE               = 0x0e,
48
    P_SYNC_UUID           = 0x0f,
49
    P_AUTH_CHALLENGE      = 0x10,
50
    P_AUTH_RESPONSE       = 0x11,
51
    P_STATE_CHG_REQ       = 0x12,
52
53
    P_PING                = 0x13,
54
    P_PING_ACK            = 0x14,
55
    P_RECV_ACK            = 0x15,
56
    P_WRITE_ACK           = 0x16,
57
    P_RS_WRITE_ACK        = 0x17,
58
    P_SUPERSEDED          = 0x18,
59
    P_NEG_ACK             = 0x19,
60
    P_NEG_DREPLY          = 0x1a,
61
    P_NEG_RS_DREPLY       = 0x1b,
62
    P_BARRIER_ACK         = 0x1c,
63
    P_STATE_CHG_REPLY     = 0x1d,
64
65
    P_OV_REQUEST          = 0x1e,
66
    P_OV_REPLY            = 0x1f,
67
    P_OV_RESULT           = 0x20,
68
    P_CSUM_RS_REQUEST     = 0x21,
69
    P_RS_IS_IN_SYNC       = 0x22,
70
    P_SYNC_PARAM89        = 0x23,
71
    P_COMPRESSED_BITMAP   = 0x24,
72
73
    P_DELAY_PROBE         = 0x27,
74
    P_OUT_OF_SYNC         = 0x28,
75
    P_RS_CANCEL           = 0x29,
76
    P_CONN_ST_CHG_REQ     = 0x2a,
77
    P_CONN_ST_CHG_REPLY   = 0x2b,
78
    P_RETRY_WRITE         = 0x2c,
79
    P_PROTOCOL_UPDATE     = 0x2d,
80
    P_TWOPC_PREPARE       = 0x2e,
81
    P_TWOPC_ABORT         = 0x2f,
82
83
    P_DAGTAG              = 0x30,
84
85
    P_TRIM                = 0x31,
86
87
    P_RS_THIN_REQ         = 0x32,
88
    P_RS_DEALLOCATED      = 0x33,
89
90
    P_WSAME               = 0x34,
91
    P_TWOPC_PREP_RSZ      = 0x35,
92
    P_ZEROES              = 0x36,
93
94
    P_PEER_ACK            = 0x40,
95
    P_PEERS_IN_SYNC       = 0x41,
96
97
    P_UUIDS110            = 0x42,
98
    P_PEER_DAGTAG         = 0x43,
99
    P_CURRENT_UUID        = 0x44,
100
101
    P_TWOPC_YES           = 0x45,
102
    P_TWOPC_NO            = 0x46,
103
    P_TWOPC_COMMIT        = 0x47,
104
    P_TWOPC_RETRY         = 0x48,
105
106
    P_CONFIRM_STABLE      = 0x49,
107
108
    P_RS_CANCEL_AHEAD     = 0x4a,
109
110
    P_DISCONNECT          = 0x4b,
111
112
    P_RS_DAGTAG_REQ       = 0x4c,
113
    P_RS_CSUM_DAGTAG_REQ  = 0x4d,
114
    P_RS_THIN_DAGTAG_REQ  = 0x4e,
115
    P_OV_DAGTAG_REQ       = 0x4f,
116
    P_OV_DAGTAG_REPLY     = 0x50,
117
118
    P_WRITE_ACK_IN_SYNC   = 0x51,
119
    P_RS_NEG_ACK          = 0x52,
120
    P_OV_RESULT_ID        = 0x53,
121
    P_RS_DEALLOCATED_ID   = 0x54,
122
123
    P_INITIAL_META        = 0xfff1,
124
    P_INITIAL_DATA        = 0xfff2,
125
126
    P_CONNECTION_FEATURES = 0xfffe
127
};
128
129
typedef struct {
130
    uint32_t tid;
131
    int32_t initiator_node_id;
132
} drbd_twopc_key;
133
134
typedef struct {
135
    uint32_t prepare_frame;
136
    enum drbd_packet command;
137
} drbd_twopc_val;
138
139
static unsigned drbd_twopc_key_hash(const void *k)
140
0
{
141
0
  const drbd_twopc_key *key = (const drbd_twopc_key *) k;
142
143
0
  return key->tid;
144
0
}
145
146
static int drbd_twopc_key_equal(const void *k1, const void *k2)
147
0
{
148
0
  const drbd_twopc_key *key1 = (const drbd_twopc_key*) k1;
149
0
  const drbd_twopc_key *key2 = (const drbd_twopc_key*) k2;
150
151
0
  return key1->tid == key2->tid && key1->initiator_node_id == key2->initiator_node_id;
152
0
}
153
154
typedef struct {
155
    wmem_map_t *twopc;
156
} drbd_conv;
157
158
typedef struct value_payload_decoder {
159
    int value;
160
    void (*state_reader_fn)(tvbuff_t *, packet_info *, drbd_conv *);
161
    void (*tree_fn)(tvbuff_t *, proto_tree *, drbd_conv *);
162
} value_payload_decoder;
163
164
static const value_string packet_names[] = {
165
    { P_DATA, "P_DATA" },
166
    { P_DATA_REPLY, "P_DATA_REPLY" },
167
    { P_RS_DATA_REPLY, "P_RS_DATA_REPLY" },
168
    { P_BARRIER, "P_BARRIER" },
169
    { P_BITMAP, "P_BITMAP" },
170
    { P_BECOME_SYNC_TARGET, "P_BECOME_SYNC_TARGET" },
171
    { P_BECOME_SYNC_SOURCE, "P_BECOME_SYNC_SOURCE" },
172
    { P_UNPLUG_REMOTE, "P_UNPLUG_REMOTE" },
173
    { P_DATA_REQUEST, "P_DATA_REQUEST" },
174
    { P_RS_DATA_REQUEST, "P_RS_DATA_REQUEST" },
175
    { P_SYNC_PARAM, "P_SYNC_PARAM" },
176
    { P_PROTOCOL, "P_PROTOCOL" },
177
    { P_UUIDS, "P_UUIDS" },
178
    { P_SIZES, "P_SIZES" },
179
    { P_STATE, "P_STATE" },
180
    { P_SYNC_UUID, "P_SYNC_UUID" },
181
    { P_AUTH_CHALLENGE, "P_AUTH_CHALLENGE" },
182
    { P_AUTH_RESPONSE, "P_AUTH_RESPONSE" },
183
    { P_STATE_CHG_REQ, "P_STATE_CHG_REQ" },
184
185
    { P_PING, "P_PING" },
186
    { P_PING_ACK, "P_PING_ACK" },
187
    { P_RECV_ACK, "P_RECV_ACK" },
188
    { P_WRITE_ACK, "P_WRITE_ACK" },
189
    { P_RS_WRITE_ACK, "P_RS_WRITE_ACK" },
190
    { P_SUPERSEDED, "P_SUPERSEDED" },
191
    { P_NEG_ACK, "P_NEG_ACK" },
192
    { P_NEG_DREPLY, "P_NEG_DREPLY" },
193
    { P_NEG_RS_DREPLY, "P_NEG_RS_DREPLY" },
194
    { P_BARRIER_ACK, "P_BARRIER_ACK" },
195
    { P_STATE_CHG_REPLY, "P_STATE_CHG_REPLY" },
196
197
    { P_OV_REQUEST, "P_OV_REQUEST" },
198
    { P_OV_REPLY, "P_OV_REPLY" },
199
    { P_OV_RESULT, "P_OV_RESULT" },
200
    { P_CSUM_RS_REQUEST, "P_CSUM_RS_REQUEST" },
201
    { P_RS_IS_IN_SYNC, "P_RS_IS_IN_SYNC" },
202
    { P_SYNC_PARAM89, "P_SYNC_PARAM89" },
203
    { P_COMPRESSED_BITMAP, "P_COMPRESSED_BITMAP" },
204
205
    { P_DELAY_PROBE, "P_DELAY_PROBE" },
206
    { P_OUT_OF_SYNC, "P_OUT_OF_SYNC" },
207
    { P_RS_CANCEL, "P_RS_CANCEL" },
208
    { P_CONN_ST_CHG_REQ, "P_CONN_ST_CHG_REQ" },
209
    { P_CONN_ST_CHG_REPLY, "P_CONN_ST_CHG_REPLY" },
210
    { P_RETRY_WRITE, "P_RETRY_WRITE" },
211
    { P_PROTOCOL_UPDATE, "P_PROTOCOL_UPDATE" },
212
    { P_TWOPC_PREPARE, "P_TWOPC_PREPARE" },
213
    { P_TWOPC_ABORT, "P_TWOPC_ABORT" },
214
215
    { P_DAGTAG, "P_DAGTAG" },
216
217
    { P_TRIM, "P_TRIM" },
218
219
    { P_RS_THIN_REQ, "P_RS_THIN_REQ" },
220
    { P_RS_DEALLOCATED, "P_RS_DEALLOCATED" },
221
222
    { P_WSAME, "P_WSAME" },
223
    { P_TWOPC_PREP_RSZ, "P_TWOPC_PREP_RSZ" },
224
    { P_ZEROES, "P_ZEROES" },
225
226
    { P_PEER_ACK, "P_PEER_ACK" },
227
    { P_PEERS_IN_SYNC, "P_PEERS_IN_SYNC" },
228
229
    { P_UUIDS110, "P_UUIDS110" },
230
    { P_PEER_DAGTAG, "P_PEER_DAGTAG" },
231
    { P_CURRENT_UUID, "P_CURRENT_UUID" },
232
233
    { P_TWOPC_YES, "P_TWOPC_YES" },
234
    { P_TWOPC_NO, "P_TWOPC_NO" },
235
    { P_TWOPC_COMMIT, "P_TWOPC_COMMIT" },
236
    { P_TWOPC_RETRY, "P_TWOPC_RETRY" },
237
238
    { P_CONFIRM_STABLE, "P_CONFIRM_STABLE" },
239
240
    { P_RS_CANCEL_AHEAD, "P_RS_CANCEL_AHEAD" },
241
242
    { P_DISCONNECT, "P_DISCONNECT" },
243
244
    { P_RS_DAGTAG_REQ, "P_RS_DAGTAG_REQ" },
245
    { P_RS_CSUM_DAGTAG_REQ, "P_RS_CSUM_DAGTAG_REQ" },
246
    { P_RS_THIN_DAGTAG_REQ, "P_RS_THIN_DAGTAG_REQ" },
247
    { P_OV_DAGTAG_REQ, "P_OV_DAGTAG_REQ" },
248
    { P_OV_DAGTAG_REPLY, "P_OV_DAGTAG_REPLY" },
249
250
    { P_WRITE_ACK_IN_SYNC, "P_WRITE_ACK_IN_SYNC" },
251
    { P_RS_NEG_ACK, "P_RS_NEG_ACK" },
252
    { P_OV_RESULT_ID, "P_OV_RESULT_ID" },
253
    { P_RS_DEALLOCATED_ID, "P_RS_DEALLOCATED_ID" },
254
255
    { P_INITIAL_META, "P_INITIAL_META" },
256
    { P_INITIAL_DATA, "P_INITIAL_DATA" },
257
258
    { P_CONNECTION_FEATURES, "P_CONNECTION_FEATURES" },
259
    { 0, NULL }
260
};
261
262
#define DRBD_PROT_A   1
263
#define DRBD_PROT_B   2
264
#define DRBD_PROT_C   3
265
266
static const value_string protocol_names[] = {
267
    { DRBD_PROT_A, "A" },
268
    { DRBD_PROT_B, "B" },
269
    { DRBD_PROT_C, "C" },
270
    { 0, NULL }
271
};
272
273
#define DRBD_ROLE_UNKNOWN   0
274
#define DRBD_ROLE_PRIMARY   1
275
#define DRBD_ROLE_SECONDARY 2
276
277
static const value_string role_names[] = {
278
    { DRBD_ROLE_UNKNOWN, "UNKNOWN" },
279
    { DRBD_ROLE_PRIMARY, "PRIMARY" },
280
    { DRBD_ROLE_SECONDARY, "SECONDARY" },
281
    { 0, NULL }
282
};
283
284
#define DRBD_CONNECTION_STATE_C_STANDALONE 0
285
#define DRBD_CONNECTION_STATE_C_DISCONNECTING 1
286
#define DRBD_CONNECTION_STATE_C_UNCONNECTED 2
287
#define DRBD_CONNECTION_STATE_C_TIMEOUT 3
288
#define DRBD_CONNECTION_STATE_C_BROKEN_PIPE 4
289
#define DRBD_CONNECTION_STATE_C_NETWORK_FAILURE 5
290
#define DRBD_CONNECTION_STATE_C_PROTOCOL_ERROR 6
291
#define DRBD_CONNECTION_STATE_C_TEAR_DOWN 7
292
#define DRBD_CONNECTION_STATE_C_CONNECTING 8
293
#define DRBD_CONNECTION_STATE_C_CONNECTED 9
294
#define DRBD_CONNECTION_STATE_L_ESTABLISHED 10
295
#define DRBD_CONNECTION_STATE_L_STARTING_SYNC_S 11
296
#define DRBD_CONNECTION_STATE_L_STARTING_SYNC_T 12
297
#define DRBD_CONNECTION_STATE_L_WF_BITMAP_S 13
298
#define DRBD_CONNECTION_STATE_L_WF_BITMAP_T 14
299
#define DRBD_CONNECTION_STATE_L_WF_SYNC_UUID 15
300
#define DRBD_CONNECTION_STATE_L_SYNC_SOURCE 16
301
#define DRBD_CONNECTION_STATE_L_SYNC_TARGET 17
302
#define DRBD_CONNECTION_STATE_L_VERIFY_S 18
303
#define DRBD_CONNECTION_STATE_L_VERIFY_T 19
304
#define DRBD_CONNECTION_STATE_L_PAUSED_SYNC_S 20
305
#define DRBD_CONNECTION_STATE_L_PAUSED_SYNC_T 21
306
#define DRBD_CONNECTION_STATE_L_AHEAD 22
307
#define DRBD_CONNECTION_STATE_L_BEHIND 23
308
309
static const value_string connection_state_names[] = {
310
    { DRBD_CONNECTION_STATE_C_STANDALONE, "C_STANDALONE" },
311
    { DRBD_CONNECTION_STATE_C_DISCONNECTING, "C_DISCONNECTING" },
312
    { DRBD_CONNECTION_STATE_C_UNCONNECTED, "C_UNCONNECTED" },
313
    { DRBD_CONNECTION_STATE_C_TIMEOUT, "C_TIMEOUT" },
314
    { DRBD_CONNECTION_STATE_C_BROKEN_PIPE, "C_BROKEN_PIPE" },
315
    { DRBD_CONNECTION_STATE_C_NETWORK_FAILURE, "C_NETWORK_FAILURE" },
316
    { DRBD_CONNECTION_STATE_C_PROTOCOL_ERROR, "C_PROTOCOL_ERROR" },
317
    { DRBD_CONNECTION_STATE_C_TEAR_DOWN, "C_TEAR_DOWN" },
318
    { DRBD_CONNECTION_STATE_C_CONNECTING, "C_CONNECTING" },
319
    { DRBD_CONNECTION_STATE_C_CONNECTED, "C_CONNECTED" },
320
    { DRBD_CONNECTION_STATE_L_ESTABLISHED, "L_ESTABLISHED" },
321
    { DRBD_CONNECTION_STATE_L_STARTING_SYNC_S, "L_STARTING_SYNC_S" },
322
    { DRBD_CONNECTION_STATE_L_STARTING_SYNC_T, "L_STARTING_SYNC_T" },
323
    { DRBD_CONNECTION_STATE_L_WF_BITMAP_S, "L_WF_BITMAP_S" },
324
    { DRBD_CONNECTION_STATE_L_WF_BITMAP_T, "L_WF_BITMAP_T" },
325
    { DRBD_CONNECTION_STATE_L_WF_SYNC_UUID, "L_WF_SYNC_UUID" },
326
    { DRBD_CONNECTION_STATE_L_SYNC_SOURCE, "L_SYNC_SOURCE" },
327
    { DRBD_CONNECTION_STATE_L_SYNC_TARGET, "L_SYNC_TARGET" },
328
    { DRBD_CONNECTION_STATE_L_VERIFY_S, "L_VERIFY_S" },
329
    { DRBD_CONNECTION_STATE_L_VERIFY_T, "L_VERIFY_T" },
330
    { DRBD_CONNECTION_STATE_L_PAUSED_SYNC_S, "L_PAUSED_SYNC_S" },
331
    { DRBD_CONNECTION_STATE_L_PAUSED_SYNC_T, "L_PAUSED_SYNC_T" },
332
    { DRBD_CONNECTION_STATE_L_AHEAD, "L_AHEAD" },
333
    { DRBD_CONNECTION_STATE_L_BEHIND, "L_BEHIND" },
334
    { 0, NULL }
335
};
336
337
#define DRBD_DISK_STATE_DISKLESS 0
338
#define DRBD_DISK_STATE_ATTACHING 1
339
#define DRBD_DISK_STATE_DETACHING 2
340
#define DRBD_DISK_STATE_FAILED 3
341
#define DRBD_DISK_STATE_NEGOTIATING 4
342
#define DRBD_DISK_STATE_INCONSISTENT 5
343
#define DRBD_DISK_STATE_OUTDATED 6
344
#define DRBD_DISK_STATE_UNKNOWN 7
345
#define DRBD_DISK_STATE_CONSISTENT 8
346
#define DRBD_DISK_STATE_UP_TO_DATE 9
347
348
static const value_string disk_state_names[] = {
349
    { DRBD_DISK_STATE_DISKLESS, "D_DISKLESS" },
350
    { DRBD_DISK_STATE_ATTACHING, "D_ATTACHING" },
351
    { DRBD_DISK_STATE_DETACHING, "D_DETACHING" },
352
    { DRBD_DISK_STATE_FAILED, "D_FAILED" },
353
    { DRBD_DISK_STATE_NEGOTIATING, "D_NEGOTIATING" },
354
    { DRBD_DISK_STATE_INCONSISTENT, "D_INCONSISTENT" },
355
    { DRBD_DISK_STATE_OUTDATED, "D_OUTDATED" },
356
    { DRBD_DISK_STATE_UNKNOWN, "D_UNKNOWN" },
357
    { DRBD_DISK_STATE_CONSISTENT, "D_CONSISTENT" },
358
    { DRBD_DISK_STATE_UP_TO_DATE, "D_UP_TO_DATE" },
359
    { 0, NULL }
360
};
361
362
14
#define STATE_ROLE (0x3 << 0)    /* 3/4   primary/secondary/unknown */
363
14
#define STATE_PEER (0x3 << 2)    /* 3/4   primary/secondary/unknown */
364
14
#define STATE_CONN (0x1f << 4)    /* 17/32   cstates */
365
14
#define STATE_DISK (0xf << 9)    /* 8/16  from D_DISKLESS to D_UP_TO_DATE */
366
14
#define STATE_PDSK (0xf << 13)    /* 8/16  from D_DISKLESS to D_UP_TO_DATE */
367
14
#define STATE_SUSP (0x1 << 17)    /* 2/2   IO suspended no/yes (by user) */
368
14
#define STATE_AFTR_ISP (0x1 << 18)  /* isp .. imposed sync pause */
369
14
#define STATE_PEER_ISP (0x1 << 19)
370
14
#define STATE_USER_ISP (0x1 << 20)
371
14
#define STATE_SUSP_NOD (0x1 << 21)  /* IO suspended because no data */
372
14
#define STATE_SUSP_FEN (0x1 << 22)  /* IO suspended because fence peer handler runs*/
373
14
#define STATE_QUORUM (0x1 << 23)
374
375
0
#define TWOPC_HAS_FLAGS     0x80000000 /* For packet dissectors */
376
14
#define TWOPC_HAS_REACHABLE 0x40000000 /* The reachable_nodes field is valid */
377
378
14
#define UUID_FLAG_DISCARD_MY_DATA 1
379
14
#define UUID_FLAG_CRASHED_PRIMARY 2
380
14
#define UUID_FLAG_INCONSISTENT 4
381
14
#define UUID_FLAG_SKIP_INITIAL_SYNC 8
382
14
#define UUID_FLAG_NEW_DATAGEN 16
383
14
#define UUID_FLAG_STABLE 32
384
14
#define UUID_FLAG_GOT_STABLE 64
385
14
#define UUID_FLAG_RESYNC 128
386
14
#define UUID_FLAG_RECONNECT 256
387
14
#define UUID_FLAG_DISKLESS_PRIMARY 512
388
14
#define UUID_FLAG_PRIMARY_LOST_QUORUM 1024
389
390
14
#define DP_HARDBARRIER        1
391
14
#define DP_RW_SYNC            2
392
14
#define DP_MAY_SET_IN_SYNC    4
393
14
#define DP_UNPLUG             8
394
14
#define DP_FUA               16
395
14
#define DP_FLUSH             32
396
14
#define DP_DISCARD           64
397
14
#define DP_SEND_RECEIVE_ACK 128
398
14
#define DP_SEND_WRITE_ACK   256
399
14
#define DP_WSAME            512
400
14
#define DP_ZEROES          1024
401
402
#define OV_RESULT_SKIP         4710
403
#define OV_RESULT_IN_SYNC      4711
404
#define OV_RESULT_OUT_OF_SYNC  4712
405
406
static const val64_string ov_result_codes[] = {
407
    { OV_RESULT_SKIP, "SKIP" },
408
    { OV_RESULT_IN_SYNC, "IN_SYNC" },
409
    { OV_RESULT_OUT_OF_SYNC, "OUT_OF_SYNC" },
410
    { 0, NULL }
411
};
412
413
#define DRBD_STREAM_DATA 0
414
#define DRBD_STREAM_CONTROL 1
415
416
static const value_string stream_names[] = {
417
    { DRBD_STREAM_DATA, "Data" },
418
    { DRBD_STREAM_CONTROL, "Control" },
419
    { 0, NULL }
420
};
421
422
static void dissect_drbd_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
423
424
static void read_state_twopc_prepare(tvbuff_t *tvb, packet_info *pinfo, drbd_conv *conv_data);
425
static void read_state_twopc_prep_rsz(tvbuff_t *tvb, packet_info *pinfo, drbd_conv *conv_data);
426
427
static void decode_payload_connection_features(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
428
static void decode_payload_auth_challenge(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
429
static void decode_payload_auth_response(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
430
static void decode_payload_data(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
431
static void decode_payload_barrier(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
432
static void decode_payload_dagtag_data_request(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
433
static void decode_payload_data_request(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
434
static void decode_payload_sync_param(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
435
static void decode_payload_protocol(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
436
static void decode_payload_uuids(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
437
static void decode_payload_sizes(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
438
static void decode_payload_state(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
439
static void decode_payload_req_state(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
440
static void decode_payload_sync_uuid(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
441
static void decode_payload_skip(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
442
static void decode_payload_out_of_sync(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
443
static void decode_payload_twopc_prepare(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
444
static void decode_payload_twopc_prep_rsz(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
445
static void decode_payload_twopc_commit(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
446
static void decode_payload_dagtag(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
447
static void decode_payload_uuids110(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
448
static void decode_payload_peer_dagtag(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
449
static void decode_payload_current_uuid(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
450
static void decode_payload_data_size(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
451
static void decode_payload_data_wsame(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
452
static void decode_payload_rs_deallocated(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
453
454
static void decode_payload_block_ack(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
455
static void decode_payload_ov_result(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
456
static void decode_payload_barrier_ack(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
457
static void decode_payload_confirm_stable(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
458
static void decode_payload_rq_s_reply(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
459
static void decode_payload_peer_ack(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
460
static void decode_payload_peers_in_sync(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
461
static void decode_payload_twopc_reply(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data);
462
463
static const value_payload_decoder payload_decoders[] = {
464
    { P_CONNECTION_FEATURES, NULL, decode_payload_connection_features },
465
    { P_AUTH_CHALLENGE, NULL, decode_payload_auth_challenge },
466
    { P_AUTH_RESPONSE, NULL, decode_payload_auth_response },
467
    { P_DATA, NULL, decode_payload_data },
468
    { P_DATA_REPLY, NULL, decode_payload_data },
469
    { P_RS_DATA_REPLY, NULL, decode_payload_data },
470
    { P_BARRIER, NULL, decode_payload_barrier },
471
    { P_BITMAP, NULL, NULL }, /* TODO: decode additional data */
472
    { P_COMPRESSED_BITMAP, NULL, NULL }, /* TODO: decode additional data */
473
    { P_UNPLUG_REMOTE, NULL, NULL },
474
    { P_DATA_REQUEST, NULL, decode_payload_data_request },
475
    { P_RS_DATA_REQUEST, NULL, decode_payload_data_request },
476
    { P_SYNC_PARAM, NULL, decode_payload_sync_param },
477
    { P_SYNC_PARAM89, NULL, decode_payload_sync_param },
478
    { P_PROTOCOL, NULL, decode_payload_protocol },
479
    { P_UUIDS, NULL, decode_payload_uuids },
480
    { P_SIZES, NULL, decode_payload_sizes },
481
    { P_STATE, NULL, decode_payload_state },
482
    { P_STATE_CHG_REQ, NULL, decode_payload_req_state },
483
    { P_SYNC_UUID, NULL, decode_payload_sync_uuid },
484
    { P_OV_REQUEST, NULL, decode_payload_data_request },
485
    { P_OV_REPLY, NULL, decode_payload_data_request }, /* TODO: decode additional data */
486
    { P_CSUM_RS_REQUEST, NULL, decode_payload_data_request }, /* TODO: decode additional data */
487
    { P_RS_THIN_REQ, NULL, decode_payload_data_request },
488
    { P_DELAY_PROBE, NULL, decode_payload_skip },
489
    { P_OUT_OF_SYNC, NULL, decode_payload_out_of_sync },
490
    { P_CONN_ST_CHG_REQ, NULL, decode_payload_req_state },
491
    { P_PROTOCOL_UPDATE, NULL, decode_payload_protocol }, /* TODO: decode additional data */
492
    { P_TWOPC_PREPARE, read_state_twopc_prepare, decode_payload_twopc_prepare },
493
    { P_TWOPC_PREP_RSZ, read_state_twopc_prep_rsz, decode_payload_twopc_prep_rsz },
494
    { P_TWOPC_ABORT, NULL, decode_payload_twopc_commit },
495
    { P_DAGTAG, NULL, decode_payload_dagtag },
496
    { P_UUIDS110, NULL, decode_payload_uuids110 },
497
    { P_PEER_DAGTAG, NULL, decode_payload_peer_dagtag },
498
    { P_CURRENT_UUID, NULL, decode_payload_current_uuid },
499
    { P_TWOPC_COMMIT, NULL, decode_payload_twopc_commit },
500
    { P_TRIM, NULL, decode_payload_data_size },
501
    { P_ZEROES, NULL, decode_payload_data_size },
502
    { P_RS_DEALLOCATED, NULL, decode_payload_rs_deallocated },
503
    { P_RS_DEALLOCATED_ID, NULL, decode_payload_block_ack },
504
    { P_WSAME, NULL, decode_payload_data_wsame },
505
    { P_DISCONNECT, NULL, NULL },
506
    { P_RS_DAGTAG_REQ, NULL, decode_payload_dagtag_data_request },
507
    { P_RS_CSUM_DAGTAG_REQ, NULL, decode_payload_dagtag_data_request },
508
    { P_RS_THIN_DAGTAG_REQ, NULL, decode_payload_dagtag_data_request },
509
    { P_OV_DAGTAG_REQ, NULL, decode_payload_dagtag_data_request },
510
    { P_OV_DAGTAG_REPLY, NULL, decode_payload_dagtag_data_request },
511
512
    { P_PING, NULL, NULL },
513
    { P_PING_ACK, NULL, NULL },
514
    { P_RECV_ACK, NULL, decode_payload_block_ack },
515
    { P_WRITE_ACK, NULL, decode_payload_block_ack },
516
    { P_WRITE_ACK_IN_SYNC, NULL, decode_payload_block_ack },
517
    { P_SUPERSEDED, NULL, decode_payload_block_ack },
518
    { P_NEG_ACK, NULL, decode_payload_block_ack },
519
    { P_NEG_DREPLY, NULL, decode_payload_block_ack },
520
    { P_NEG_RS_DREPLY, NULL, decode_payload_block_ack },
521
    { P_RS_WRITE_ACK, NULL, decode_payload_block_ack },
522
    { P_RS_NEG_ACK, NULL, decode_payload_block_ack },
523
    { P_OV_RESULT, NULL, decode_payload_block_ack },
524
    { P_OV_RESULT_ID, NULL, decode_payload_ov_result },
525
    { P_BARRIER_ACK, NULL, decode_payload_barrier_ack },
526
    { P_CONFIRM_STABLE, NULL, decode_payload_confirm_stable },
527
    { P_STATE_CHG_REPLY, NULL, decode_payload_rq_s_reply },
528
    { P_RS_IS_IN_SYNC, NULL, decode_payload_block_ack },
529
    { P_DELAY_PROBE, NULL, decode_payload_skip },
530
    { P_RS_CANCEL, NULL, decode_payload_block_ack },
531
    { P_RS_CANCEL_AHEAD, NULL, decode_payload_block_ack },
532
    { P_CONN_ST_CHG_REPLY, NULL, decode_payload_rq_s_reply },
533
    { P_RETRY_WRITE, NULL, decode_payload_block_ack },
534
    { P_PEER_ACK, NULL, decode_payload_peer_ack },
535
    { P_PEERS_IN_SYNC, NULL, decode_payload_peers_in_sync },
536
    { P_TWOPC_YES, NULL, decode_payload_twopc_reply },
537
    { P_TWOPC_NO, NULL, decode_payload_twopc_reply },
538
    { P_TWOPC_RETRY, NULL, decode_payload_twopc_reply },
539
};
540
541
542
void proto_register_drbd(void);
543
void proto_reg_handoff_drbd(void);
544
545
static dissector_handle_t drbd_handle;
546
static dissector_handle_t drbd_lb_tcp_handle;
547
548
static int proto_drbd;
549
static int proto_drbd_lb_tcp;
550
551
static int hf_drbd_command;
552
static int hf_drbd_length;
553
static int hf_drbd_volume;
554
static int hf_drbd_auth_challenge_nonce;
555
static int hf_drbd_auth_response_hash;
556
static int hf_drbd_sector;
557
static int hf_drbd_block_id;
558
static int hf_drbd_seq_num;
559
static int hf_drbd_ov_result;
560
static int hf_drbd_dp_flags;
561
static int hf_drbd_data;
562
static int hf_drbd_size;
563
static int hf_drbd_protocol_min;
564
static int hf_drbd_feature_flags;
565
static int hf_drbd_protocol_max;
566
static int hf_drbd_sender_node_id;
567
static int hf_drbd_receiver_node_id;
568
static int hf_drbd_barrier;
569
static int hf_drbd_set_size;
570
static int hf_drbd_oldest_block_id;
571
static int hf_drbd_youngest_block_id;
572
static int hf_drbd_resync_rate;
573
static int hf_drbd_verify_alg;
574
static int hf_drbd_csums_alg;
575
static int hf_drbd_c_plan_ahead;
576
static int hf_drbd_c_delay_target;
577
static int hf_drbd_c_fill_target;
578
static int hf_drbd_c_max_rate;
579
static int hf_drbd_protocol;
580
static int hf_drbd_after_sb_0p;
581
static int hf_drbd_after_sb_1p;
582
static int hf_drbd_after_sb_2p;
583
static int hf_drbd_conn_flags;
584
static int hf_drbd_two_primaries;
585
static int hf_drbd_integrity_alg;
586
static int hf_drbd_current_uuid;
587
static int hf_drbd_bitmap_uuid;
588
static int hf_drbd_history_uuid_list;
589
static int hf_drbd_history_uuid;
590
static int hf_drbd_dirty_bits;
591
static int hf_drbd_uuid_flags;
592
static int hf_drbd_node_mask;
593
static int hf_drbd_bitmap_uuids_mask;
594
static int hf_drbd_uuid;
595
static int hf_drbd_weak_nodes;
596
static int hf_drbd_physical_block_size;
597
static int hf_drbd_logical_block_size;
598
static int hf_drbd_alignment_offset;
599
static int hf_drbd_io_min;
600
static int hf_drbd_io_opt;
601
static int hf_drbd_discard_enabled;
602
static int hf_drbd_discard_zeroes_data;
603
static int hf_drbd_write_same_capable;
604
static int hf_drbd_d_size;
605
static int hf_drbd_u_size;
606
static int hf_drbd_c_size;
607
static int hf_drbd_max_bio_size;
608
static int hf_drbd_queue_order_type;
609
static int hf_drbd_dds_flags;
610
static int hf_drbd_state;
611
static int hf_drbd_retcode;
612
static int hf_drbd_twopc_prepare_in;
613
static int hf_drbd_tid;
614
static int hf_drbd_twopc_flags;
615
static int hf_drbd_initiator_node_id;
616
static int hf_drbd_target_node_id;
617
static int hf_drbd_nodes_to_reach;
618
static int hf_drbd_primary_nodes;
619
static int hf_drbd_user_size;
620
static int hf_drbd_diskful_primary_nodes;
621
static int hf_drbd_exposed_size;
622
static int hf_drbd_reachable_nodes;
623
static int hf_drbd_max_possible_size;
624
static int hf_drbd_offset;
625
static int hf_drbd_dagtag;
626
static int hf_drbd_dagtag_node_id;
627
static int hf_drbd_new_rx_descs_data;
628
static int hf_drbd_new_rx_descs_control;
629
static int hf_drbd_rx_desc_stolen_from;
630
631
static int hf_drbd_state_role;
632
static int hf_drbd_state_peer;
633
static int hf_drbd_state_conn;
634
static int hf_drbd_state_disk;
635
static int hf_drbd_state_pdsk;
636
static int hf_drbd_state_susp;
637
static int hf_drbd_state_aftr_isp;
638
static int hf_drbd_state_peer_isp;
639
static int hf_drbd_state_user_isp;
640
static int hf_drbd_state_susp_nod;
641
static int hf_drbd_state_susp_fen;
642
static int hf_drbd_state_quorum;
643
644
static int hf_drbd_twopc_flag_has_reachable;
645
646
static int hf_drbd_uuid_flag_discard_my_data;
647
static int hf_drbd_uuid_flag_crashed_primary;
648
static int hf_drbd_uuid_flag_inconsistent;
649
static int hf_drbd_uuid_flag_skip_initial_sync;
650
static int hf_drbd_uuid_flag_new_datagen;
651
static int hf_drbd_uuid_flag_stable;
652
static int hf_drbd_uuid_flag_got_stable;
653
static int hf_drbd_uuid_flag_resync;
654
static int hf_drbd_uuid_flag_reconnect;
655
static int hf_drbd_uuid_flag_diskless_primary;
656
static int hf_drbd_uuid_flag_primary_lost_quorum;
657
658
static int hf_drbd_dp_hardbarrier;
659
static int hf_drbd_dp_rw_sync;
660
static int hf_drbd_dp_may_set_in_sync;
661
static int hf_drbd_dp_unplug;
662
static int hf_drbd_dp_fua;
663
static int hf_drbd_dp_flush;
664
static int hf_drbd_dp_discard;
665
static int hf_drbd_dp_send_receive_ack;
666
static int hf_drbd_dp_send_write_ack;
667
static int hf_drbd_dp_wsame;
668
static int hf_drbd_dp_zeroes;
669
670
static int hf_drbd_lb_tcp_seq;
671
static int hf_drbd_lb_tcp_length;
672
673
static int ett_drbd;
674
static int ett_drbd_lb_tcp;
675
static int ett_drbd_state;
676
static int ett_drbd_twopc_flags;
677
static int ett_drbd_uuid_flags;
678
static int ett_drbd_history_uuids;
679
static int ett_drbd_data_flags;
680
681
static int * const state_fields[] = {
682
    &hf_drbd_state_role,
683
    &hf_drbd_state_peer,
684
    &hf_drbd_state_conn,
685
    &hf_drbd_state_disk,
686
    &hf_drbd_state_pdsk,
687
    &hf_drbd_state_susp,
688
    &hf_drbd_state_aftr_isp,
689
    &hf_drbd_state_peer_isp,
690
    &hf_drbd_state_user_isp,
691
    &hf_drbd_state_susp_nod,
692
    &hf_drbd_state_susp_fen,
693
    &hf_drbd_state_quorum,
694
    NULL
695
};
696
697
static int * const twopc_flag_fields[] = {
698
    &hf_drbd_twopc_flag_has_reachable,
699
    NULL
700
};
701
702
static int * const uuid_flag_fields[] = {
703
    &hf_drbd_uuid_flag_discard_my_data,
704
    &hf_drbd_uuid_flag_crashed_primary,
705
    &hf_drbd_uuid_flag_inconsistent,
706
    &hf_drbd_uuid_flag_skip_initial_sync,
707
    &hf_drbd_uuid_flag_new_datagen,
708
    &hf_drbd_uuid_flag_stable,
709
    &hf_drbd_uuid_flag_got_stable,
710
    &hf_drbd_uuid_flag_resync,
711
    &hf_drbd_uuid_flag_reconnect,
712
    &hf_drbd_uuid_flag_diskless_primary,
713
    &hf_drbd_uuid_flag_primary_lost_quorum,
714
    NULL
715
};
716
717
static int * const data_flag_fields[] = {
718
    &hf_drbd_dp_hardbarrier,
719
    &hf_drbd_dp_rw_sync,
720
    &hf_drbd_dp_may_set_in_sync,
721
    &hf_drbd_dp_unplug,
722
    &hf_drbd_dp_fua,
723
    &hf_drbd_dp_flush,
724
    &hf_drbd_dp_discard,
725
    &hf_drbd_dp_send_receive_ack,
726
    &hf_drbd_dp_send_write_ack,
727
    &hf_drbd_dp_wsame,
728
    &hf_drbd_dp_zeroes,
729
    NULL
730
};
731
732
0
#define CHALLENGE_LEN 64
733
734
0
static bool is_bit_set_64(uint64_t value, int bit) {
735
0
    return !!(value & (UINT64_C(1) << bit));
736
0
}
737
738
/*
739
 * Length of the frame header.
740
 */
741
0
#define DRBD_FRAME_HEADER_80_LEN 8
742
0
#define DRBD_FRAME_HEADER_95_LEN 8
743
0
#define DRBD_FRAME_HEADER_100_LEN 16
744
0
#define DRBD_TRANSPORT_RDMA_PACKET_LEN 16
745
746
0
#define DRBD_MAGIC 0x83740267
747
0
#define DRBD_MAGIC_BIG 0x835a
748
0
#define DRBD_MAGIC_100 0x8620ec20
749
0
#define DRBD_TRANSPORT_RDMA_MAGIC 0x5257494E
750
751
static unsigned read_drbd_packet_len(tvbuff_t *tvb, int offset)
752
0
{
753
0
    uint32_t magic32;
754
0
    uint16_t magic16;
755
756
0
    magic32 = tvb_get_ntohl(tvb, offset);
757
758
0
    if (magic32 == DRBD_MAGIC)
759
0
        return DRBD_FRAME_HEADER_80_LEN + tvb_get_ntohs(tvb, offset + 6);
760
761
0
    if (tvb_reported_length_remaining(tvb, offset) >= DRBD_FRAME_HEADER_100_LEN && magic32 == DRBD_MAGIC_100)
762
0
        return DRBD_FRAME_HEADER_100_LEN + tvb_get_ntohl(tvb, offset + 8);
763
764
0
    magic16 = tvb_get_ntohs(tvb, offset);
765
766
0
    if (magic16 == DRBD_MAGIC_BIG)
767
0
        return DRBD_FRAME_HEADER_95_LEN + tvb_get_ntohl(tvb, offset + 4);
768
769
0
    return 0;
770
0
}
771
772
static unsigned get_drbd_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset, void *data _U_)
773
0
{
774
0
    unsigned drbd_len = read_drbd_packet_len(tvb, offset);
775
776
0
    if (tvb_reported_length_remaining(tvb, offset) >= DRBD_FRAME_HEADER_100_LEN && !drbd_len) {
777
        /* We have enough data to recognize any header, but none matched.
778
         * Either there is data corruption or this is actually an lb-tcp
779
         * stream. It is possible that the capture is missing the first lb-tcp
780
         * header. In that case, the stream will be misidentified as normal
781
         * DRBD on TCP.
782
         *
783
         * Reset the dissector and throw some exception so that a new dissector
784
         * is chosen by the heuristic. */
785
0
        conversation_t *conversation = find_or_create_conversation(pinfo);
786
0
        conversation_set_dissector(conversation, NULL);
787
0
        THROW(ReportedBoundsError);
788
0
    }
789
790
0
    return drbd_len;
791
0
}
792
793
static int dissect_drbd_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
794
0
{
795
0
    dissect_drbd_message(tvb, pinfo, tree);
796
0
    return tvb_reported_length(tvb);
797
0
}
798
799
static int dissect_drbd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
800
0
{
801
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "DRBD");
802
0
    tcp_dissect_pdus(tvb, pinfo, tree, true, DRBD_FRAME_HEADER_80_LEN,
803
0
            get_drbd_pdu_len, dissect_drbd_pdu, data);
804
0
    return tvb_reported_length(tvb);
805
0
}
806
807
static unsigned get_drbd_lb_tcp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
808
0
{
809
0
    return 8 + tvb_get_ntohl(tvb, offset + 4);
810
0
}
811
812
static int dissect_drbd_lb_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
813
0
{
814
0
    proto_tree      *lb_tcp_tree;
815
0
    proto_item      *lb_tcp_ti;
816
817
0
    lb_tcp_ti = proto_tree_add_item(tree, proto_drbd_lb_tcp, tvb, 0, -1, ENC_NA);
818
0
    proto_item_set_text(lb_tcp_ti, "DRBD [lb-tcp]");
819
0
    lb_tcp_tree = proto_item_add_subtree(lb_tcp_ti, ett_drbd_lb_tcp);
820
821
0
    proto_tree_add_item(lb_tcp_tree, hf_drbd_lb_tcp_seq, tvb, 0, 4, ENC_BIG_ENDIAN);
822
0
    proto_tree_add_item(lb_tcp_tree, hf_drbd_lb_tcp_length, tvb, 4, 4, ENC_BIG_ENDIAN);
823
824
0
    unsigned offset = 8;
825
0
    while (tvb_captured_length(tvb) >= offset + DRBD_FRAME_HEADER_80_LEN) {
826
0
        unsigned length = read_drbd_packet_len(tvb, offset);
827
828
        /* Was a header recognized? */
829
0
        if (length == 0) {
830
0
            const char *info_text = col_get_text(pinfo->cinfo, COL_INFO);
831
832
0
            col_clear(pinfo->cinfo, COL_INFO);
833
0
            if (!info_text || !info_text[0])
834
0
                col_append_ports(pinfo->cinfo, COL_INFO, PT_TCP, pinfo->srcport, pinfo->destport);
835
0
            col_append_str(pinfo->cinfo, COL_INFO, " [lb-tcp Payload]");
836
0
            col_set_fence(pinfo->cinfo, COL_INFO);
837
838
0
            break;
839
0
        }
840
841
0
        dissect_drbd_message(tvb_new_subset_length(tvb, offset, length), pinfo, tree);
842
843
0
        offset += length;
844
0
    }
845
846
0
    return tvb_reported_length(tvb);
847
0
}
848
849
static int dissect_drbd_lb_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
850
0
{
851
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "DRBD lb-tcp");
852
0
    tcp_dissect_pdus(tvb, pinfo, tree, true, 8,
853
0
            get_drbd_lb_tcp_pdu_len, dissect_drbd_lb_tcp_pdu, data);
854
0
    return tvb_reported_length(tvb);
855
0
}
856
857
static bool test_drbd_header(tvbuff_t *tvb, int offset)
858
0
{
859
0
    int reported_length = tvb_reported_length(tvb);
860
0
    int captured_length = tvb_captured_length(tvb);
861
862
0
    if (reported_length < offset + DRBD_FRAME_HEADER_80_LEN || captured_length < offset + 4)
863
0
        return false;
864
865
0
    uint32_t magic32 = tvb_get_ntohl(tvb, offset);
866
867
0
    if (magic32 == DRBD_MAGIC)
868
0
        return true;
869
0
    else if (reported_length >= offset + DRBD_FRAME_HEADER_100_LEN && magic32 == DRBD_MAGIC_100)
870
0
        return true;
871
0
    else {
872
0
        uint16_t magic16 = tvb_get_ntohs(tvb, offset);
873
0
        if (magic16 == DRBD_MAGIC_BIG)
874
0
            return true;
875
0
    }
876
877
0
    return false;
878
0
}
879
880
static bool test_drbd_rdma_control_header(tvbuff_t *tvb)
881
0
{
882
0
    unsigned reported_length = tvb_reported_length(tvb);
883
0
    if (reported_length < DRBD_TRANSPORT_RDMA_PACKET_LEN || tvb_captured_length(tvb) < 4) {
884
0
        return false;
885
0
    }
886
887
0
    uint32_t magic32 = tvb_get_ntohl(tvb, 0);
888
0
    return magic32 == DRBD_TRANSPORT_RDMA_MAGIC;
889
0
}
890
891
static bool test_drbd_protocol(tvbuff_t *tvb, packet_info *pinfo,
892
        proto_tree *tree, void *data _U_)
893
0
{
894
0
    if (!test_drbd_header(tvb, 0))
895
0
        return false;
896
897
0
    conversation_t *conversation = find_or_create_conversation(pinfo);
898
0
    conversation_set_dissector(conversation, drbd_handle);
899
0
    dissect_drbd(tvb, pinfo, tree, data);
900
901
0
    return true;
902
0
}
903
904
static bool test_drbd_lb_tcp_protocol(tvbuff_t *tvb, packet_info *pinfo,
905
        proto_tree *tree, void *data _U_)
906
0
{
907
    /* DRBD packets may be split between lb-tcp wrapper packets. As a result,
908
     * there may be lb-tcp packets that do not contain any DRBD header.
909
     * However, we have no other way to identify lb-tcp packets, so look for a
910
     * DRBD header anyway. This is a best-effort solution. */
911
0
    if (!test_drbd_header(tvb, 8))
912
0
        return false;
913
914
0
    conversation_t *conversation = find_or_create_conversation(pinfo);
915
0
    conversation_set_dissector(conversation, drbd_lb_tcp_handle);
916
0
    dissect_drbd_lb_tcp(tvb, pinfo, tree, data);
917
918
0
    return true;
919
0
}
920
921
/*
922
 * A DRBD connection consists of 2 TCP connections. We need information from
923
 * one to correctly interpret the other. However, it is impossible to determine
924
 * definitely just from a packet trace which TCP connections belong together.
925
 * Fortunately, there is an essentially universal convention that the
926
 * connections have a statically allocated port number in common. One
927
 * connection uses it on one node, the other connection uses the same port
928
 * number but on the other node. The other port numbers are dynamically
929
 * allocated and thus greater.
930
 *
931
 * For example, the connections use:
932
 * 1. Port 7000 on node A, port 44444 on node B
933
 * 2. Port 55555 on node A, port 7000 on node B
934
 *
935
 * Hence we can associate one conversation_t to the DRBD connection by keying
936
 * it on the lower port number and the two addresses in a consistent order.
937
 */
938
static conversation_t *find_drbd_conversation(packet_info *pinfo)
939
0
{
940
0
    address* addr_a;
941
0
    address* addr_b;
942
0
    uint32_t port_a = MIN(pinfo->srcport, pinfo->destport);
943
944
0
    if (cmp_address(&pinfo->src, &pinfo->dst) < 0) {
945
0
        addr_a = &pinfo->src;
946
0
        addr_b = &pinfo->dst;
947
0
    } else {
948
0
        addr_a = &pinfo->dst;
949
0
        addr_b = &pinfo->src;
950
0
    }
951
952
0
    conversation_t *conv = find_conversation(pinfo->num, addr_a, addr_b, CONVERSATION_TCP, port_a, 0, NO_PORT_B);
953
0
    if (!conv)
954
0
    {
955
        /* CONVERSATION_TEMPLATE prevents the port information being added once
956
         * a wildcard search matches. */
957
0
        conv = conversation_new(pinfo->num, addr_a, addr_b, CONVERSATION_TCP, port_a, 0,
958
0
                NO_PORT2|CONVERSATION_TEMPLATE);
959
0
    }
960
961
0
    return conv;
962
0
}
963
964
/**
965
 * Returns buffer containing the payload.
966
 */
967
static tvbuff_t *decode_header(tvbuff_t *tvb, proto_tree *pt, uint16_t *command)
968
0
{
969
0
    uint32_t magic32;
970
0
    uint16_t magic16;
971
972
0
    magic32 = tvb_get_ntohl(tvb, 0);
973
974
0
    if (magic32 == DRBD_MAGIC) {
975
0
        *command = tvb_get_ntohs(tvb, 4);
976
977
0
        proto_tree_add_item(pt, hf_drbd_command, tvb, 4, 2, ENC_BIG_ENDIAN);
978
0
        proto_tree_add_item(pt, hf_drbd_length, tvb, 6, 2, ENC_BIG_ENDIAN);
979
980
0
        return tvb_new_subset_remaining(tvb, DRBD_FRAME_HEADER_80_LEN);
981
0
    }
982
983
0
    if (tvb_reported_length(tvb) >= DRBD_FRAME_HEADER_100_LEN && magic32 == DRBD_MAGIC_100) {
984
0
        *command = tvb_get_ntohs(tvb, 6);
985
986
0
        proto_tree_add_item(pt, hf_drbd_volume, tvb, 4, 2, ENC_BIG_ENDIAN);
987
0
        proto_tree_add_item(pt, hf_drbd_command, tvb, 6, 2, ENC_BIG_ENDIAN);
988
0
        proto_tree_add_item(pt, hf_drbd_length, tvb, 8, 4, ENC_BIG_ENDIAN);
989
990
0
        return tvb_new_subset_remaining(tvb, DRBD_FRAME_HEADER_100_LEN);
991
0
    }
992
993
0
    magic16 = tvb_get_ntohs(tvb, 0);
994
995
0
    if (magic16 == DRBD_MAGIC_BIG) {
996
0
        *command = tvb_get_ntohs(tvb, 2);
997
998
0
        proto_tree_add_item(pt, hf_drbd_command, tvb, 2, 2, ENC_BIG_ENDIAN);
999
0
        proto_tree_add_item(pt, hf_drbd_length, tvb, 4, 4, ENC_BIG_ENDIAN);
1000
1001
0
        return tvb_new_subset_remaining(tvb, DRBD_FRAME_HEADER_95_LEN);
1002
0
    }
1003
1004
0
    return NULL;
1005
0
}
1006
1007
static const value_payload_decoder *find_payload_decoder(uint16_t command)
1008
0
{
1009
0
    for (unsigned int i = 0; i < array_length(payload_decoders); i++) {
1010
0
        if (payload_decoders[i].value == command) {
1011
0
            return &payload_decoders[i];
1012
0
        }
1013
0
    }
1014
1015
0
    return NULL;
1016
0
}
1017
1018
static void dissect_drbd_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1019
0
{
1020
0
    proto_tree      *drbd_tree;
1021
0
    proto_item      *ti;
1022
0
    uint16_t        command = -1;
1023
1024
0
    col_clear(pinfo->cinfo, COL_INFO);
1025
1026
0
    ti = proto_tree_add_item(tree, proto_drbd, tvb, 0, -1, ENC_NA);
1027
0
    drbd_tree = proto_item_add_subtree(ti, ett_drbd);
1028
1029
0
    tvbuff_t *payload_tvb = decode_header(tvb, drbd_tree, &command);
1030
1031
0
    if (!payload_tvb)
1032
0
        return;
1033
1034
    /* Indicate what kind of message this is. */
1035
0
    const char *packet_name = val_to_str(pinfo->pool, command, packet_names, "Unknown (0x%02x)");
1036
0
    const char *info_text = col_get_text(pinfo->cinfo, COL_INFO);
1037
0
    if (!info_text || !info_text[0])
1038
0
        col_append_ports(pinfo->cinfo, COL_INFO, PT_TCP, pinfo->srcport, pinfo->destport);
1039
0
    col_append_fstr(pinfo->cinfo, COL_INFO, " [%s]", packet_name);
1040
0
    col_set_fence(pinfo->cinfo, COL_INFO);
1041
1042
0
    conversation_t *conv = find_drbd_conversation(pinfo);
1043
0
    drbd_conv *conv_data = (drbd_conv *)conversation_get_proto_data(conv, proto_drbd);
1044
0
    if (!conv_data) {
1045
0
        conv_data = wmem_new0(wmem_file_scope(), drbd_conv);
1046
0
        conv_data->twopc = wmem_map_new(wmem_file_scope(), drbd_twopc_key_hash, drbd_twopc_key_equal);
1047
0
        conversation_add_proto_data(conv, proto_drbd, conv_data);
1048
0
    }
1049
1050
0
    const value_payload_decoder *payload_decoder = find_payload_decoder(command);
1051
1052
0
    if (!PINFO_FD_VISITED(pinfo) && payload_decoder && payload_decoder->state_reader_fn)
1053
0
        (*payload_decoder->state_reader_fn) (payload_tvb, pinfo, conv_data);
1054
1055
0
    if (tree == NULL)
1056
0
        return;
1057
1058
0
    proto_item_set_text(ti, "DRBD [%s]", packet_name);
1059
1060
0
    if (payload_decoder && payload_decoder->tree_fn)
1061
0
        (*payload_decoder->tree_fn) (payload_tvb, drbd_tree, conv_data);
1062
0
}
1063
1064
static void drbd_ib_append_col_info(packet_info *pinfo, const char *packet_name)
1065
0
{
1066
0
    const char *info_text;
1067
1068
0
    col_clear(pinfo->cinfo, COL_INFO);
1069
0
    info_text = col_get_text(pinfo->cinfo, COL_INFO);
1070
0
    if (!info_text || !info_text[0])
1071
0
        col_append_fstr(pinfo->cinfo, COL_INFO, "QP=0x%06x [%s]", pinfo->destport, packet_name);
1072
0
    else
1073
0
        col_append_fstr(pinfo->cinfo, COL_INFO, " [%s]", packet_name);
1074
0
    col_set_fence(pinfo->cinfo, COL_INFO);
1075
0
}
1076
1077
static void dissect_drbd_ib_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1078
0
{
1079
0
    proto_tree      *drbd_tree;
1080
0
    proto_item      *ti;
1081
0
    uint16_t        command = -1;
1082
1083
0
    ti = proto_tree_add_item(tree, proto_drbd, tvb, 0, -1, ENC_NA);
1084
0
    drbd_tree = proto_item_add_subtree(ti, ett_drbd);
1085
1086
0
    tvbuff_t *payload_tvb = decode_header(tvb, drbd_tree, &command);
1087
1088
0
    if (!payload_tvb)
1089
0
        return;
1090
1091
    /* Indicate what kind of message this is. */
1092
0
    const char *packet_name = val_to_str(pinfo->pool, command, packet_names, "Unknown (0x%02x)");
1093
0
    drbd_ib_append_col_info(pinfo, packet_name);
1094
1095
0
    if (tree == NULL)
1096
0
        return;
1097
1098
0
    proto_item_set_text(ti, "DRBD [%s]", packet_name);
1099
1100
0
    const value_payload_decoder *payload_decoder = find_payload_decoder(command);
1101
1102
0
    if (payload_decoder && payload_decoder->tree_fn)
1103
0
        (*payload_decoder->tree_fn) (payload_tvb, drbd_tree, NULL);
1104
0
}
1105
1106
static void dissect_drbd_ib_control_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1107
0
{
1108
0
    proto_tree      *drbd_tree;
1109
0
    proto_item      *ti;
1110
1111
0
    drbd_ib_append_col_info(pinfo, "RDMA Flow Control");
1112
1113
0
    if (tree == NULL)
1114
0
        return;
1115
1116
0
    ti = proto_tree_add_item(tree, proto_drbd, tvb, 0, -1, ENC_NA);
1117
0
    proto_item_set_text(ti, "DRBD [RDMA Flow Control]");
1118
0
    drbd_tree = proto_item_add_subtree(ti, ett_drbd);
1119
1120
0
    proto_tree_add_item(drbd_tree, hf_drbd_new_rx_descs_data, tvb, 4, 4, ENC_BIG_ENDIAN);
1121
0
    proto_tree_add_item(drbd_tree, hf_drbd_new_rx_descs_control, tvb, 8, 4, ENC_BIG_ENDIAN);
1122
0
    proto_tree_add_item(drbd_tree, hf_drbd_rx_desc_stolen_from, tvb, 12, 4, ENC_BIG_ENDIAN);
1123
0
}
1124
1125
static bool dissect_drbd_ib(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1126
0
{
1127
0
    if (!test_drbd_header(tvb, 0) && !test_drbd_rdma_control_header(tvb))
1128
0
        return false;
1129
1130
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "DRBD RDMA");
1131
0
    while (1) {
1132
0
        unsigned length;
1133
0
        bool is_control_packet = test_drbd_rdma_control_header(tvb);
1134
1135
0
        if (is_control_packet)
1136
0
            length = DRBD_TRANSPORT_RDMA_PACKET_LEN;
1137
0
        else
1138
0
            length = read_drbd_packet_len(tvb, 0);
1139
1140
        /* Was a header recognized? */
1141
0
        if (length == 0)
1142
0
            break;
1143
1144
0
        tvbuff_t *packet_tvb = tvb_new_subset_length(tvb, 0, length);
1145
1146
0
        if (is_control_packet)
1147
0
            dissect_drbd_ib_control_message(packet_tvb, pinfo, tree);
1148
0
        else
1149
0
            dissect_drbd_ib_message(packet_tvb, pinfo, tree);
1150
1151
        /* Is there enough data for another DRBD packet? */
1152
0
        if (tvb_reported_length(tvb) < length + DRBD_FRAME_HEADER_80_LEN)
1153
0
            break;
1154
1155
        /* Move to the next DRBD packet. */
1156
0
        tvb = tvb_new_subset_remaining(tvb, length);
1157
0
    }
1158
1159
0
    return true;
1160
0
}
1161
1162
static void insert_twopc(tvbuff_t *tvb, packet_info *pinfo, drbd_conv *conv_data, enum drbd_packet command)
1163
0
{
1164
0
    uint32_t flags = tvb_get_ntohl(tvb, 4);
1165
1166
0
    drbd_twopc_key *key = wmem_new0(wmem_file_scope(), drbd_twopc_key);
1167
0
    key->tid = tvb_get_ntohl(tvb, 0);
1168
0
    if (flags & TWOPC_HAS_FLAGS)
1169
0
        key->initiator_node_id = tvb_get_int8(tvb, 10);
1170
0
    else
1171
0
        key->initiator_node_id = tvb_get_ntohil(tvb, 4);
1172
1173
0
    drbd_twopc_val *val = wmem_new0(wmem_file_scope(), drbd_twopc_val);
1174
0
    val->prepare_frame = pinfo->num;
1175
0
    val->command = command;
1176
1177
0
    wmem_map_insert(conv_data->twopc, key, val);
1178
0
}
1179
1180
static void read_state_twopc_prepare(tvbuff_t *tvb, packet_info *pinfo, drbd_conv *conv_data)
1181
0
{
1182
0
    insert_twopc(tvb, pinfo, conv_data, P_TWOPC_PREPARE);
1183
0
}
1184
1185
static void read_state_twopc_prep_rsz(tvbuff_t *tvb, packet_info *pinfo, drbd_conv *conv_data)
1186
0
{
1187
0
    insert_twopc(tvb, pinfo, conv_data, P_TWOPC_PREP_RSZ);
1188
0
}
1189
1190
static void decode_payload_connection_features(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1191
0
{
1192
0
    proto_tree_add_item(tree, hf_drbd_protocol_min, tvb, 0, 4, ENC_BIG_ENDIAN);
1193
0
    proto_tree_add_item(tree, hf_drbd_feature_flags, tvb, 4, 4, ENC_BIG_ENDIAN);
1194
0
    proto_tree_add_item(tree, hf_drbd_protocol_max, tvb, 8, 4, ENC_BIG_ENDIAN);
1195
0
    proto_tree_add_item(tree, hf_drbd_sender_node_id, tvb, 12, 4, ENC_BIG_ENDIAN);
1196
0
    proto_tree_add_item(tree, hf_drbd_receiver_node_id, tvb, 16, 4, ENC_BIG_ENDIAN);
1197
0
}
1198
1199
static void decode_payload_auth_challenge(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1200
0
{
1201
0
    proto_tree_add_bytes_format(tree, hf_drbd_auth_challenge_nonce, tvb, 0, CHALLENGE_LEN, NULL, "Nonce");
1202
0
}
1203
1204
static void decode_payload_auth_response(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1205
0
{
1206
0
    proto_tree_add_bytes_format(tree, hf_drbd_auth_response_hash, tvb, 0, -1, NULL, "Hash");
1207
0
}
1208
1209
static void decode_data_common(tvbuff_t *tvb, proto_tree *tree)
1210
0
{
1211
0
    proto_tree_add_item(tree, hf_drbd_sector, tvb, 0, 8, ENC_BIG_ENDIAN);
1212
0
    proto_tree_add_item(tree, hf_drbd_block_id, tvb, 8, 8, ENC_LITTLE_ENDIAN);
1213
0
    proto_tree_add_item(tree, hf_drbd_seq_num, tvb, 16, 4, ENC_BIG_ENDIAN);
1214
0
    proto_tree_add_bitmask(tree, tvb, 20, hf_drbd_dp_flags, ett_drbd_data_flags, data_flag_fields, ENC_BIG_ENDIAN);
1215
0
}
1216
1217
static void decode_payload_data(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1218
0
{
1219
0
    decode_data_common(tvb, tree);
1220
1221
0
    unsigned nbytes = tvb_reported_length_remaining(tvb, 24);
1222
0
    proto_tree_add_uint(tree, hf_drbd_size, tvb, 0, 0, nbytes);
1223
1224
    /* For infiniband the data is not in this tvb, so we do not show the data field. */
1225
0
    if (tvb_captured_length(tvb) >= 24 + nbytes) {
1226
0
        proto_tree_add_bytes_format(tree, hf_drbd_data, tvb, 24,
1227
0
                nbytes, NULL, "Data (%u byte%s)", nbytes, plurality(nbytes, "", "s"));
1228
0
    }
1229
0
}
1230
1231
static void decode_payload_barrier(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1232
0
{
1233
0
    proto_tree_add_item(tree, hf_drbd_barrier, tvb, 0, 4, ENC_LITTLE_ENDIAN);
1234
0
}
1235
1236
static void decode_payload_data_request(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1237
0
{
1238
0
    proto_tree_add_item(tree, hf_drbd_sector, tvb, 0, 8, ENC_BIG_ENDIAN);
1239
0
    proto_tree_add_item(tree, hf_drbd_block_id, tvb, 8, 8, ENC_LITTLE_ENDIAN);
1240
0
    proto_tree_add_item(tree, hf_drbd_size, tvb, 16, 4, ENC_BIG_ENDIAN);
1241
0
}
1242
1243
static void decode_payload_dagtag_data_request(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1244
0
{
1245
0
    proto_tree_add_item(tree, hf_drbd_sector, tvb, 0, 8, ENC_BIG_ENDIAN);
1246
0
    proto_tree_add_item(tree, hf_drbd_block_id, tvb, 8, 8, ENC_LITTLE_ENDIAN);
1247
0
    proto_tree_add_item(tree, hf_drbd_size, tvb, 16, 4, ENC_BIG_ENDIAN);
1248
0
    proto_tree_add_item(tree, hf_drbd_dagtag_node_id, tvb, 20, 4, ENC_BIG_ENDIAN);
1249
0
    proto_tree_add_item(tree, hf_drbd_dagtag, tvb, 24, 8, ENC_BIG_ENDIAN);
1250
0
}
1251
1252
static void decode_payload_sync_param(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1253
0
{
1254
0
    unsigned length = tvb_reported_length(tvb);
1255
0
    unsigned offset = 0;
1256
1257
0
    proto_tree_add_item(tree, hf_drbd_resync_rate, tvb, offset, 4, ENC_BIG_ENDIAN);
1258
0
    offset += 4;
1259
0
    proto_tree_add_item(tree, hf_drbd_verify_alg, tvb, offset, DRBD_STRING_MAX, ENC_ASCII);
1260
0
    offset += DRBD_STRING_MAX;
1261
1262
0
    if (length >= offset + DRBD_STRING_MAX) {
1263
0
        proto_tree_add_item(tree, hf_drbd_csums_alg, tvb, offset, DRBD_STRING_MAX, ENC_ASCII);
1264
0
        offset += DRBD_STRING_MAX;
1265
0
    }
1266
1267
0
    if (length >= offset + 16) {
1268
0
        proto_tree_add_item(tree, hf_drbd_c_plan_ahead, tvb, offset, 4, ENC_BIG_ENDIAN);
1269
0
        proto_tree_add_item(tree, hf_drbd_c_delay_target, tvb, offset + 4, 4, ENC_BIG_ENDIAN);
1270
0
        proto_tree_add_item(tree, hf_drbd_c_fill_target, tvb, offset + 8, 4, ENC_BIG_ENDIAN);
1271
0
        proto_tree_add_item(tree, hf_drbd_c_max_rate, tvb, offset + 12, 4, ENC_BIG_ENDIAN);
1272
0
    }
1273
0
}
1274
1275
static void decode_payload_protocol(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1276
0
{
1277
0
    proto_tree_add_item(tree, hf_drbd_protocol, tvb, 0, 4, ENC_BIG_ENDIAN);
1278
0
    proto_tree_add_item(tree, hf_drbd_after_sb_0p, tvb, 4, 4, ENC_BIG_ENDIAN);
1279
0
    proto_tree_add_item(tree, hf_drbd_after_sb_1p, tvb, 8, 4, ENC_BIG_ENDIAN);
1280
0
    proto_tree_add_item(tree, hf_drbd_after_sb_2p, tvb, 12, 4, ENC_BIG_ENDIAN);
1281
0
    proto_tree_add_item(tree, hf_drbd_conn_flags, tvb, 16, 4, ENC_BIG_ENDIAN);
1282
0
    proto_tree_add_item(tree, hf_drbd_two_primaries, tvb, 20, 4, ENC_BIG_ENDIAN);
1283
0
    proto_tree_add_item(tree, hf_drbd_integrity_alg, tvb, 24, -1, ENC_ASCII);
1284
0
}
1285
1286
static void decode_payload_uuids(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1287
0
{
1288
0
    proto_tree_add_item(tree, hf_drbd_current_uuid, tvb, 0, 8, ENC_BIG_ENDIAN);
1289
0
    proto_tree_add_item(tree, hf_drbd_bitmap_uuid, tvb, 8, 8, ENC_BIG_ENDIAN);
1290
0
    proto_tree_add_item(tree, hf_drbd_history_uuid, tvb, 16, 8, ENC_BIG_ENDIAN);
1291
0
    proto_tree_add_item(tree, hf_drbd_history_uuid, tvb, 24, 8, ENC_BIG_ENDIAN);
1292
0
    proto_tree_add_item(tree, hf_drbd_dirty_bits, tvb, 32, 8, ENC_BIG_ENDIAN);
1293
0
    proto_tree_add_bitmask(tree, tvb, 40, hf_drbd_uuid_flags, ett_drbd_uuid_flags, uuid_flag_fields, ENC_BIG_ENDIAN);
1294
0
}
1295
1296
static void decode_payload_sizes(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1297
0
{
1298
0
    proto_tree_add_item(tree, hf_drbd_d_size, tvb, 0, 8, ENC_BIG_ENDIAN);
1299
0
    proto_tree_add_item(tree, hf_drbd_u_size, tvb, 8, 8, ENC_BIG_ENDIAN);
1300
0
    proto_tree_add_item(tree, hf_drbd_c_size, tvb, 16, 8, ENC_BIG_ENDIAN);
1301
0
    proto_tree_add_item(tree, hf_drbd_max_bio_size, tvb, 24, 4, ENC_BIG_ENDIAN);
1302
0
    proto_tree_add_item(tree, hf_drbd_queue_order_type, tvb, 28, 2, ENC_BIG_ENDIAN);
1303
0
    proto_tree_add_item(tree, hf_drbd_dds_flags, tvb, 30, 2, ENC_BIG_ENDIAN);
1304
0
    proto_tree_add_item(tree, hf_drbd_physical_block_size, tvb, 32, 4, ENC_BIG_ENDIAN);
1305
0
    proto_tree_add_item(tree, hf_drbd_logical_block_size, tvb, 36, 4, ENC_BIG_ENDIAN);
1306
0
    proto_tree_add_item(tree, hf_drbd_alignment_offset, tvb, 40, 4, ENC_BIG_ENDIAN);
1307
0
    proto_tree_add_item(tree, hf_drbd_io_min, tvb, 44, 4, ENC_BIG_ENDIAN);
1308
0
    proto_tree_add_item(tree, hf_drbd_io_opt, tvb, 48, 4, ENC_BIG_ENDIAN);
1309
0
    proto_tree_add_item(tree, hf_drbd_discard_enabled, tvb, 52, 1, ENC_BIG_ENDIAN);
1310
0
    proto_tree_add_item(tree, hf_drbd_discard_zeroes_data, tvb, 53, 1, ENC_BIG_ENDIAN);
1311
0
    proto_tree_add_item(tree, hf_drbd_write_same_capable, tvb, 54, 1, ENC_BIG_ENDIAN);
1312
0
}
1313
1314
static void decode_payload_state(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1315
0
{
1316
0
    proto_tree_add_bitmask(tree, tvb, 0, hf_drbd_state, ett_drbd_state, state_fields, ENC_BIG_ENDIAN);
1317
0
}
1318
1319
/* Filter fields leaving only those with bitmask overlapping with the given mask. */
1320
static void mask_fields(uint32_t mask, int * const fields[], int * masked_fields[])
1321
0
{
1322
0
        int masked_i = 0;
1323
1324
0
        for (int fields_i = 0; fields[fields_i]; fields_i++) {
1325
0
            header_field_info *hf = proto_registrar_get_nth(*fields[fields_i]);
1326
1327
0
            if (hf && mask & hf->bitmask) {
1328
0
                masked_fields[masked_i] = fields[fields_i];
1329
0
                masked_i++;
1330
0
            }
1331
0
        }
1332
1333
0
        masked_fields[masked_i] = NULL;
1334
0
}
1335
1336
static void decode_state_change(tvbuff_t *tvb, proto_tree *tree, int offset)
1337
0
{
1338
0
        uint32_t state_mask = tvb_get_ntohl(tvb, offset);
1339
0
        int * masked_state_fields[array_length(state_fields)];
1340
0
        mask_fields(state_mask, state_fields, masked_state_fields);
1341
1342
0
        if (masked_state_fields[0]) {
1343
0
            proto_tree_add_bitmask(tree, tvb, offset + 4, hf_drbd_state, ett_drbd_state, masked_state_fields, ENC_BIG_ENDIAN);
1344
0
        } else {
1345
0
            proto_tree_add_item(tree, hf_drbd_state, tvb, offset + 4, 4, ENC_BIG_ENDIAN);
1346
0
        }
1347
0
}
1348
1349
static void decode_payload_req_state(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1350
0
{
1351
0
    decode_state_change(tvb, tree, 0);
1352
0
}
1353
1354
static void decode_payload_sync_uuid(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1355
0
{
1356
0
    proto_tree_add_item(tree, hf_drbd_uuid, tvb, 0, 8, ENC_BIG_ENDIAN);
1357
0
}
1358
1359
static void decode_payload_skip(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1360
0
{
1361
0
    proto_tree_add_item(tree, hf_drbd_seq_num, tvb, 0, 4, ENC_BIG_ENDIAN);
1362
0
    proto_tree_add_item(tree, hf_drbd_offset, tvb, 4, 4, ENC_BIG_ENDIAN);
1363
0
}
1364
1365
static void decode_payload_out_of_sync(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1366
0
{
1367
0
    proto_tree_add_item(tree, hf_drbd_sector, tvb, 0, 8, ENC_BIG_ENDIAN);
1368
0
    proto_tree_add_item(tree, hf_drbd_size, tvb, 8, 4, ENC_BIG_ENDIAN);
1369
0
}
1370
1371
/* Return the twopc flags, if present. */
1372
static uint32_t decode_twopc_request_common(tvbuff_t *tvb, proto_tree *tree, drbd_twopc_key *key)
1373
0
{
1374
0
    proto_tree_add_item_ret_uint(tree, hf_drbd_tid, tvb, 0, 4, ENC_BIG_ENDIAN,
1375
0
            key ? &key->tid : NULL);
1376
1377
0
    uint32_t flags = tvb_get_ntohl(tvb, 4);
1378
0
    if (flags & TWOPC_HAS_FLAGS) {
1379
0
        proto_tree_add_bitmask(tree, tvb, 4, hf_drbd_twopc_flags, ett_drbd_twopc_flags, twopc_flag_fields, ENC_BIG_ENDIAN);
1380
0
        proto_tree_add_item_ret_int(tree, hf_drbd_initiator_node_id, tvb, 10, 1, ENC_BIG_ENDIAN,
1381
0
                key ? &key->initiator_node_id : NULL);
1382
0
        proto_tree_add_item(tree, hf_drbd_target_node_id, tvb, 11, 1, ENC_BIG_ENDIAN);
1383
0
    } else {
1384
0
        flags = 0;
1385
0
        proto_tree_add_item_ret_int(tree, hf_drbd_initiator_node_id, tvb, 4, 4, ENC_BIG_ENDIAN,
1386
0
                key ? &key->initiator_node_id : NULL);
1387
0
        proto_tree_add_item(tree, hf_drbd_target_node_id, tvb, 8, 4, ENC_BIG_ENDIAN);
1388
0
    }
1389
1390
0
    proto_tree_add_item(tree, hf_drbd_nodes_to_reach, tvb, 12, 8, ENC_BIG_ENDIAN);
1391
0
    return flags;
1392
0
}
1393
1394
static void decode_payload_twopc_prepare(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1395
0
{
1396
0
    uint32_t flags = decode_twopc_request_common(tvb, tree, NULL);
1397
1398
0
    if (!(flags & TWOPC_HAS_FLAGS))
1399
0
        proto_tree_add_item(tree, hf_drbd_primary_nodes, tvb, 20, 8, ENC_BIG_ENDIAN);
1400
1401
0
    decode_state_change(tvb, tree, 28);
1402
0
}
1403
1404
static void decode_payload_twopc_prep_rsz(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1405
0
{
1406
0
    decode_twopc_request_common(tvb, tree, NULL);
1407
1408
0
    proto_tree_add_item(tree, hf_drbd_user_size, tvb, 20, 8, ENC_BIG_ENDIAN);
1409
0
    proto_tree_add_item(tree, hf_drbd_dds_flags, tvb, 28, 2, ENC_BIG_ENDIAN);
1410
0
}
1411
1412
static void decode_payload_twopc_commit(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data)
1413
0
{
1414
0
    drbd_twopc_key key;
1415
0
    uint32_t flags = decode_twopc_request_common(tvb, tree, &key);
1416
1417
0
    if (!conv_data)
1418
0
        return;
1419
1420
0
    drbd_twopc_val *val = wmem_map_lookup(conv_data->twopc, &key);
1421
0
    if (!val)
1422
0
        return;
1423
1424
0
    proto_item *it = proto_tree_add_uint(tree, hf_drbd_twopc_prepare_in,
1425
0
            tvb, 0, 0, val->prepare_frame);
1426
0
    proto_item_set_generated(it);
1427
1428
0
    if (val->command == P_TWOPC_PREPARE) {
1429
0
        proto_tree_add_item(tree, hf_drbd_primary_nodes, tvb, 20, 8, ENC_BIG_ENDIAN);
1430
0
        if (!(flags & TWOPC_HAS_FLAGS))
1431
0
            decode_state_change(tvb, tree, 28);
1432
0
        else if (flags & TWOPC_HAS_REACHABLE)
1433
0
            proto_tree_add_item(tree, hf_drbd_reachable_nodes, tvb, 28, 8, ENC_BIG_ENDIAN);
1434
0
    } else if (val->command == P_TWOPC_PREP_RSZ) {
1435
0
        proto_tree_add_item(tree, hf_drbd_diskful_primary_nodes, tvb, 20, 8, ENC_BIG_ENDIAN);
1436
0
        proto_tree_add_item(tree, hf_drbd_exposed_size, tvb, 28, 8, ENC_BIG_ENDIAN);
1437
0
    }
1438
0
}
1439
1440
static void decode_payload_dagtag(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1441
0
{
1442
0
    proto_tree_add_item(tree, hf_drbd_dagtag, tvb, 0, 8, ENC_BIG_ENDIAN);
1443
0
}
1444
1445
static void decode_payload_uuids110(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1446
0
{
1447
0
    proto_tree_add_item(tree, hf_drbd_current_uuid, tvb, 0, 8, ENC_BIG_ENDIAN);
1448
0
    proto_tree_add_item(tree, hf_drbd_dirty_bits, tvb, 8, 8, ENC_BIG_ENDIAN);
1449
0
    proto_tree_add_bitmask(tree, tvb, 16, hf_drbd_uuid_flags, ett_drbd_uuid_flags, uuid_flag_fields, ENC_BIG_ENDIAN);
1450
0
    proto_tree_add_item(tree, hf_drbd_node_mask, tvb, 24, 8, ENC_BIG_ENDIAN);
1451
1452
0
    uint64_t bitmap_uuids_mask;
1453
0
    proto_tree_add_item_ret_uint64(tree, hf_drbd_bitmap_uuids_mask, tvb, 32, 8, ENC_BIG_ENDIAN, &bitmap_uuids_mask);
1454
1455
0
    unsigned offset = 40;
1456
0
    for (int i = 0; i < 64; i++) {
1457
0
        if (is_bit_set_64(bitmap_uuids_mask, i)) {
1458
0
            uint64_t bitmap_uuid = tvb_get_ntoh64(tvb, offset);
1459
0
            proto_tree_add_uint64_format(tree, hf_drbd_bitmap_uuid, tvb, offset, 8, bitmap_uuid,
1460
0
                    "Bitmap UUID for node %d: 0x%016" PRIx64, i, bitmap_uuid);
1461
0
            offset += 8;
1462
0
        }
1463
0
    }
1464
1465
0
    proto_item *history_uuids = proto_tree_add_item(tree, hf_drbd_history_uuid_list, tvb, offset, -1, ENC_NA);
1466
0
    proto_tree *history_tree = proto_item_add_subtree(history_uuids, ett_drbd_history_uuids);
1467
0
    unsigned total_length = tvb_reported_length(tvb);
1468
0
    while (offset < total_length) {
1469
0
        proto_tree_add_item(history_tree, hf_drbd_history_uuid, tvb, offset, 8, ENC_BIG_ENDIAN);
1470
0
        offset += 8;
1471
0
    }
1472
0
}
1473
1474
static void decode_payload_peer_dagtag(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1475
0
{
1476
0
    proto_tree_add_item(tree, hf_drbd_dagtag, tvb, 0, 8, ENC_BIG_ENDIAN);
1477
0
    proto_tree_add_item(tree, hf_drbd_dagtag_node_id, tvb, 8, 4, ENC_BIG_ENDIAN);
1478
0
}
1479
1480
static void decode_payload_current_uuid(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1481
0
{
1482
0
    proto_tree_add_item(tree, hf_drbd_uuid, tvb, 0, 8, ENC_BIG_ENDIAN);
1483
0
    proto_tree_add_item(tree, hf_drbd_weak_nodes, tvb, 8, 8, ENC_BIG_ENDIAN);
1484
0
}
1485
1486
static void decode_payload_data_size(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1487
0
{
1488
0
    decode_data_common(tvb, tree);
1489
0
    proto_tree_add_item(tree, hf_drbd_size, tvb, 24, 4, ENC_BIG_ENDIAN);
1490
0
}
1491
1492
static void decode_payload_data_wsame(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1493
0
{
1494
0
    decode_data_common(tvb, tree);
1495
0
    proto_tree_add_item(tree, hf_drbd_size, tvb, 24, 4, ENC_BIG_ENDIAN);
1496
1497
0
    unsigned nbytes = tvb_reported_length_remaining(tvb, 28);
1498
    /* For infiniband the data is not in this tvb, so we do not show the data field. */
1499
0
    if (tvb_captured_length(tvb) >= 28 + nbytes) {
1500
0
        proto_tree_add_bytes_format(tree, hf_drbd_data, tvb, 28,
1501
0
                nbytes, NULL, "Data (%u byte%s)", nbytes, plurality(nbytes, "", "s"));
1502
0
    }
1503
0
}
1504
1505
static void decode_payload_rs_deallocated(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1506
0
{
1507
0
    proto_tree_add_item(tree, hf_drbd_sector, tvb, 0, 8, ENC_BIG_ENDIAN);
1508
0
    proto_tree_add_item(tree, hf_drbd_size, tvb, 8, 4, ENC_BIG_ENDIAN);
1509
0
}
1510
1511
static void decode_payload_block_ack(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1512
0
{
1513
0
    proto_tree_add_item(tree, hf_drbd_sector, tvb, 0, 8, ENC_BIG_ENDIAN);
1514
0
    proto_tree_add_item(tree, hf_drbd_block_id, tvb, 8, 8, ENC_LITTLE_ENDIAN);
1515
0
    proto_tree_add_item(tree, hf_drbd_size, tvb, 16, 4, ENC_BIG_ENDIAN);
1516
0
    proto_tree_add_item(tree, hf_drbd_seq_num, tvb, 20, 4, ENC_BIG_ENDIAN);
1517
0
}
1518
1519
static void decode_payload_ov_result(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1520
0
{
1521
0
    proto_tree_add_item(tree, hf_drbd_sector, tvb, 0, 8, ENC_BIG_ENDIAN);
1522
0
    proto_tree_add_item(tree, hf_drbd_block_id, tvb, 8, 8, ENC_LITTLE_ENDIAN);
1523
0
    proto_tree_add_item(tree, hf_drbd_size, tvb, 16, 4, ENC_BIG_ENDIAN);
1524
0
    proto_tree_add_item(tree, hf_drbd_seq_num, tvb, 20, 4, ENC_BIG_ENDIAN);
1525
0
    proto_tree_add_item(tree, hf_drbd_ov_result, tvb, 24, 8, ENC_BIG_ENDIAN);
1526
0
}
1527
1528
static void decode_payload_barrier_ack(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1529
0
{
1530
0
    proto_tree_add_item(tree, hf_drbd_barrier, tvb, 0, 4, ENC_LITTLE_ENDIAN);
1531
0
    proto_tree_add_item(tree, hf_drbd_set_size, tvb, 4, 4, ENC_BIG_ENDIAN);
1532
0
}
1533
1534
static void decode_payload_confirm_stable(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1535
0
{
1536
0
    proto_tree_add_item(tree, hf_drbd_oldest_block_id, tvb, 0, 8, ENC_LITTLE_ENDIAN);
1537
0
    proto_tree_add_item(tree, hf_drbd_youngest_block_id, tvb, 8, 8, ENC_LITTLE_ENDIAN);
1538
0
    proto_tree_add_item(tree, hf_drbd_set_size, tvb, 16, 4, ENC_BIG_ENDIAN);
1539
0
}
1540
1541
static void decode_payload_rq_s_reply(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1542
0
{
1543
0
    proto_tree_add_item(tree, hf_drbd_retcode, tvb, 0, 4, ENC_BIG_ENDIAN);
1544
0
}
1545
1546
static void decode_payload_peer_ack(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1547
0
{
1548
0
    proto_tree_add_item(tree, hf_drbd_node_mask, tvb, 0, 8, ENC_BIG_ENDIAN);
1549
0
    proto_tree_add_item(tree, hf_drbd_dagtag, tvb, 8, 8, ENC_BIG_ENDIAN);
1550
0
}
1551
1552
static void decode_payload_peers_in_sync(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data _U_)
1553
0
{
1554
0
    proto_tree_add_item(tree, hf_drbd_sector, tvb, 0, 8, ENC_BIG_ENDIAN);
1555
0
    proto_tree_add_item(tree, hf_drbd_node_mask, tvb, 8, 8, ENC_BIG_ENDIAN);
1556
0
    proto_tree_add_item(tree, hf_drbd_size, tvb, 16, 4, ENC_BIG_ENDIAN);
1557
0
}
1558
1559
static void decode_payload_twopc_reply(tvbuff_t *tvb, proto_tree *tree, drbd_conv *conv_data)
1560
0
{
1561
0
    drbd_twopc_key key;
1562
1563
0
    proto_tree_add_item_ret_uint(tree, hf_drbd_tid, tvb, 0, 4, ENC_BIG_ENDIAN,
1564
0
            &key.tid);
1565
0
    proto_tree_add_item_ret_int(tree, hf_drbd_initiator_node_id, tvb, 4, 4, ENC_BIG_ENDIAN,
1566
0
            &key.initiator_node_id);
1567
0
    proto_tree_add_item(tree, hf_drbd_reachable_nodes, tvb, 8, 8, ENC_BIG_ENDIAN);
1568
1569
0
    if (!conv_data)
1570
0
        return;
1571
1572
0
    drbd_twopc_val *val = wmem_map_lookup(conv_data->twopc, &key);
1573
0
    if (!val)
1574
0
        return;
1575
1576
0
    proto_item *it = proto_tree_add_uint(tree, hf_drbd_twopc_prepare_in,
1577
0
            tvb, 0, 0, val->prepare_frame);
1578
0
    proto_item_set_generated(it);
1579
1580
0
    if (val->command == P_TWOPC_PREPARE) {
1581
0
        proto_tree_add_item(tree, hf_drbd_primary_nodes, tvb, 16, 8, ENC_BIG_ENDIAN);
1582
0
        proto_tree_add_item(tree, hf_drbd_weak_nodes, tvb, 24, 8, ENC_BIG_ENDIAN);
1583
0
    } else if (val->command == P_TWOPC_PREP_RSZ) {
1584
0
        proto_tree_add_item(tree, hf_drbd_diskful_primary_nodes, tvb, 16, 8, ENC_BIG_ENDIAN);
1585
0
        proto_tree_add_item(tree, hf_drbd_max_possible_size, tvb, 24, 8, ENC_BIG_ENDIAN);
1586
0
    }
1587
0
}
1588
1589
static void format_node_mask(char *s, uint64_t value)
1590
0
{
1591
0
    if (!value) {
1592
0
        (void) g_strlcpy(s, "<none>", ITEM_LABEL_LENGTH);
1593
0
        return;
1594
0
    }
1595
1596
0
    int written = 0;
1597
0
    int run_start = -1;
1598
0
    for (int i = 0; i < 64 && written < ITEM_LABEL_LENGTH; i++) {
1599
0
        bool is_set = is_bit_set_64(value, i);
1600
1601
0
        int run_end;
1602
0
        if (!is_set) {
1603
0
            run_end = i;
1604
0
        } else if (i == 63) {
1605
0
            if (run_start == -1)
1606
0
                run_start = i;
1607
0
            run_end = 64;
1608
0
        } else {
1609
0
            run_end = -1;
1610
0
        }
1611
1612
0
        if (run_start != -1 && run_end != -1) {
1613
0
            int run_length = run_end - run_start;
1614
0
            const char *sep = written ? ", " : "";
1615
1616
0
            if (run_length == 1)
1617
0
                written += snprintf(s + written, ITEM_LABEL_LENGTH - written, "%s%d", sep, run_start);
1618
0
            else if (run_length == 2)
1619
0
                written += snprintf(s + written, ITEM_LABEL_LENGTH - written, "%s%d, %d", sep, run_start, run_start + 1);
1620
0
            else
1621
0
                written += snprintf(s + written, ITEM_LABEL_LENGTH - written, "%s%d - %d", sep, run_start, run_end - 1);
1622
0
        }
1623
1624
0
        if (!is_set)
1625
0
            run_start = -1;
1626
0
        else if (run_start == -1)
1627
0
            run_start = i;
1628
0
    }
1629
0
}
1630
1631
void proto_register_drbd(void)
1632
14
{
1633
14
    static hf_register_info hf[] = {
1634
14
        { &hf_drbd_command, { "Command", "drbd.command", FT_UINT16, BASE_HEX, VALS(packet_names), 0x0, NULL, HFILL }},
1635
14
        { &hf_drbd_length, { "Payload length", "drbd.length", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
1636
14
        { &hf_drbd_volume, { "Volume", "drbd.volume", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1637
14
        { &hf_drbd_auth_challenge_nonce, { "Nonce", "drbd.auth_nonce", FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x0, NULL, HFILL }},
1638
14
        { &hf_drbd_auth_response_hash, { "Hash", "drbd.auth_hash", FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x0, NULL, HFILL }},
1639
14
        { &hf_drbd_sector, { "Sector", "drbd.sector", FT_UINT64, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1640
14
        { &hf_drbd_block_id, { "Block ID", "drbd.block_id", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1641
14
        { &hf_drbd_seq_num, { "Sequence number", "drbd.seq_num", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1642
14
        { &hf_drbd_ov_result, { "Online verify result", "drbd.ov_result", FT_UINT64, BASE_DEC|BASE_VAL64_STRING, VALS64(ov_result_codes), 0x0, NULL, HFILL }},
1643
14
        { &hf_drbd_dp_flags, { "Data flags", "drbd.dp_flags", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1644
14
        { &hf_drbd_data, { "Data", "drbd.data", FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x0, NULL, HFILL }},
1645
14
        { &hf_drbd_size, { "Size", "drbd.size", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1646
14
        { &hf_drbd_protocol_min, { "protocol_min", "drbd.protocol_min", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1647
14
        { &hf_drbd_feature_flags, { "feature_flags", "drbd.feature_flags", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1648
14
        { &hf_drbd_protocol_max, { "protocol_max", "drbd.protocol_max", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1649
14
        { &hf_drbd_sender_node_id, { "sender_node_id", "drbd.sender_node_id", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1650
14
        { &hf_drbd_receiver_node_id, { "receiver_node_id", "drbd.receiver_node_id", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1651
14
        { &hf_drbd_barrier, { "barrier", "drbd.barrier", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1652
14
        { &hf_drbd_set_size, { "set_size", "drbd.set_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1653
14
        { &hf_drbd_oldest_block_id, { "oldest_block_id", "drbd.oldest_block_id", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1654
14
        { &hf_drbd_youngest_block_id, { "youngest_block_id", "drbd.youngest_block_id", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1655
14
        { &hf_drbd_resync_rate, { "resync_rate", "drbd.resync_rate", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_kibps), 0x0, NULL, HFILL }},
1656
14
        { &hf_drbd_verify_alg, { "verify_alg", "drbd.verify_alg", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1657
14
        { &hf_drbd_csums_alg, { "csums_alg", "drbd.csums_alg", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1658
14
        { &hf_drbd_c_plan_ahead, { "c_plan_ahead", "drbd.c_plan_ahead", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1659
14
        { &hf_drbd_c_delay_target, { "c_delay_target", "drbd.c_delay_target", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1660
14
        { &hf_drbd_c_fill_target, { "c_fill_target", "drbd.c_fill_target", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1661
14
        { &hf_drbd_c_max_rate, { "c_max_rate", "drbd.c_max_rate", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_kibps), 0x0, NULL, HFILL }},
1662
14
        { &hf_drbd_protocol, { "protocol", "drbd.protocol", FT_UINT32, BASE_HEX, VALS(protocol_names), 0x0, NULL, HFILL }},
1663
14
        { &hf_drbd_after_sb_0p, { "after_sb_0p", "drbd.after_sb_0p", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
1664
14
        { &hf_drbd_after_sb_1p, { "after_sb_1p", "drbd.after_sb_1p", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
1665
14
        { &hf_drbd_after_sb_2p, { "after_sb_2p", "drbd.after_sb_2p", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
1666
14
        { &hf_drbd_conn_flags, { "conn_flags", "drbd.conn_flags", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1667
14
        { &hf_drbd_two_primaries, { "two_primaries", "drbd.two_primaries", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1668
14
        { &hf_drbd_integrity_alg, { "integrity_alg", "drbd.integrity_alg", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1669
14
        { &hf_drbd_current_uuid, { "Current UUID", "drbd.current_uuid", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1670
14
        { &hf_drbd_bitmap_uuid, { "Bitmap UUID", "drbd.bitmap_uuid", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1671
14
        { &hf_drbd_history_uuid_list, { "History UUIDs", "drbd.history_uuids", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1672
14
        { &hf_drbd_history_uuid, { "History UUID", "drbd.history_uuid", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1673
14
        { &hf_drbd_dirty_bits, { "Dirty bits", "drbd.dirty_bits", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1674
14
        { &hf_drbd_uuid_flags, { "UUID flags", "drbd.uuid_flags", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1675
14
        { &hf_drbd_node_mask, { "Nodes", "drbd.node_mask", FT_UINT64, BASE_CUSTOM, CF_FUNC(format_node_mask), 0x0, NULL, HFILL }},
1676
14
        { &hf_drbd_bitmap_uuids_mask, { "Bitmap UUID nodes", "drbd.bitmap_uuids_mask", FT_UINT64, BASE_CUSTOM, CF_FUNC(format_node_mask), 0x0, NULL, HFILL }},
1677
14
        { &hf_drbd_uuid, { "uuid", "drbd.uuid", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1678
14
        { &hf_drbd_weak_nodes, { "weak_nodes", "drbd.weak_nodes", FT_UINT64, BASE_CUSTOM, CF_FUNC(format_node_mask), 0x0, NULL, HFILL }},
1679
14
        { &hf_drbd_physical_block_size, { "physical_block_size", "drbd.physical_block_size", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1680
14
        { &hf_drbd_logical_block_size, { "logical_block_size", "drbd.logical_block_size", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1681
14
        { &hf_drbd_alignment_offset, { "alignment_offset", "drbd.alignment_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1682
14
        { &hf_drbd_io_min, { "io_min", "drbd.io_min", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1683
14
        { &hf_drbd_io_opt, { "io_opt", "drbd.io_opt", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1684
14
        { &hf_drbd_discard_enabled, { "discard_enabled", "drbd.discard_enabled", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1685
14
        { &hf_drbd_discard_zeroes_data, { "discard_zeroes_data", "drbd.discard_zeroes_data", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1686
14
        { &hf_drbd_write_same_capable, { "write_same_capable", "drbd.write_same_capable", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1687
14
        { &hf_drbd_d_size, { "d_size", "drbd.d_size", FT_UINT64, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1688
14
        { &hf_drbd_u_size, { "u_size", "drbd.u_size", FT_UINT64, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1689
14
        { &hf_drbd_c_size, { "c_size", "drbd.c_size", FT_UINT64, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1690
14
        { &hf_drbd_max_bio_size, { "max_bio_size", "drbd.max_bio_size", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1691
14
        { &hf_drbd_queue_order_type, { "queue_order_type", "drbd.queue_order_type", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1692
14
        { &hf_drbd_dds_flags, { "dds_flags", "drbd.dds_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1693
14
        { &hf_drbd_state, { "state", "drbd.state", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1694
14
        { &hf_drbd_retcode, { "retcode", "drbd.retcode", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
1695
14
        { &hf_drbd_twopc_prepare_in, { "Two-phase commit prepare in", "drbd.twopc_prepare_in", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0, NULL, HFILL }},
1696
14
        { &hf_drbd_tid, { "tid", "drbd.tid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1697
14
        { &hf_drbd_twopc_flags, { "twopc_flags", "drbd.twopc_flags", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1698
14
        { &hf_drbd_initiator_node_id, { "initiator_node_id", "drbd.initiator_node_id", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1699
14
        { &hf_drbd_target_node_id, { "target_node_id", "drbd.target_node_id", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1700
14
        { &hf_drbd_nodes_to_reach, { "nodes_to_reach", "drbd.nodes_to_reach", FT_UINT64, BASE_CUSTOM, CF_FUNC(format_node_mask), 0x0, NULL, HFILL }},
1701
14
        { &hf_drbd_primary_nodes, { "primary_nodes", "drbd.primary_nodes", FT_UINT64, BASE_CUSTOM, CF_FUNC(format_node_mask), 0x0, NULL, HFILL }},
1702
14
        { &hf_drbd_user_size, { "user_size", "drbd.user_size", FT_UINT64, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1703
14
        { &hf_drbd_diskful_primary_nodes, { "diskful_primary_nodes", "drbd.diskful_primary_nodes", FT_UINT64, BASE_CUSTOM, CF_FUNC(format_node_mask), 0x0, NULL, HFILL }},
1704
14
        { &hf_drbd_exposed_size, { "exposed_size", "drbd.exposed_size", FT_UINT64, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1705
14
        { &hf_drbd_reachable_nodes, { "reachable_nodes", "drbd.reachable_nodes", FT_UINT64, BASE_CUSTOM, CF_FUNC(format_node_mask), 0x0, NULL, HFILL }},
1706
14
        { &hf_drbd_max_possible_size, { "max_possible_size", "drbd.max_possible_size", FT_UINT64, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1707
14
        { &hf_drbd_offset, { "offset", "drbd.offset", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1708
14
        { &hf_drbd_dagtag, { "dagtag", "drbd.dagtag", FT_UINT64, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL }},
1709
14
        { &hf_drbd_dagtag_node_id, { "dagtag_node_id", "drbd.dagtag_node_id", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1710
14
        { &hf_drbd_new_rx_descs_data, { "New descriptors received (data)", "drbd.new_rx_descs_data", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1711
14
        { &hf_drbd_new_rx_descs_control, { "New descriptors received (control)", "drbd.new_rx_descs_control", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1712
14
        { &hf_drbd_rx_desc_stolen_from, { "Descriptor stolen from", "drbd.rx_desc_stolen_from", FT_INT32, BASE_DEC, VALS(stream_names), 0x0, NULL, HFILL }},
1713
1714
14
        { &hf_drbd_state_role, { "role", "drbd.state.role", FT_UINT32, BASE_DEC, VALS(role_names), STATE_ROLE, NULL, HFILL }},
1715
14
        { &hf_drbd_state_peer, { "peer", "drbd.state.peer", FT_UINT32, BASE_DEC, VALS(role_names), STATE_PEER, NULL, HFILL }},
1716
14
        { &hf_drbd_state_conn, { "conn", "drbd.state.conn", FT_UINT32, BASE_DEC, VALS(connection_state_names), STATE_CONN, NULL, HFILL }},
1717
14
        { &hf_drbd_state_disk, { "disk", "drbd.state.disk", FT_UINT32, BASE_DEC, VALS(disk_state_names), STATE_DISK, NULL, HFILL }},
1718
14
        { &hf_drbd_state_pdsk, { "pdsk", "drbd.state.pdsk", FT_UINT32, BASE_DEC, VALS(disk_state_names), STATE_PDSK, NULL, HFILL }},
1719
14
        { &hf_drbd_state_susp, { "susp", "drbd.state.susp", FT_BOOLEAN, 32, NULL, STATE_SUSP, NULL, HFILL }},
1720
14
        { &hf_drbd_state_aftr_isp, { "aftr_isp", "drbd.state.aftr_isp", FT_BOOLEAN, 32, NULL, STATE_AFTR_ISP, NULL, HFILL }},
1721
14
        { &hf_drbd_state_peer_isp, { "peer_isp", "drbd.state.peer_isp", FT_BOOLEAN, 32, NULL, STATE_PEER_ISP, NULL, HFILL }},
1722
14
        { &hf_drbd_state_user_isp, { "user_isp", "drbd.state.user_isp", FT_BOOLEAN, 32, NULL, STATE_USER_ISP, NULL, HFILL }},
1723
14
        { &hf_drbd_state_susp_nod, { "susp_nod", "drbd.state.susp_nod", FT_BOOLEAN, 32, NULL, STATE_SUSP_NOD, NULL, HFILL }},
1724
14
        { &hf_drbd_state_susp_fen, { "susp_fen", "drbd.state.susp_fen", FT_BOOLEAN, 32, NULL, STATE_SUSP_FEN, NULL, HFILL }},
1725
14
        { &hf_drbd_state_quorum, { "quorum", "drbd.state.quorum", FT_BOOLEAN, 32, NULL, STATE_QUORUM, NULL, HFILL }},
1726
1727
14
        { &hf_drbd_twopc_flag_has_reachable, { "has_reachable", "drbd.twopc_flags.has_reachable", FT_BOOLEAN, 32, NULL, TWOPC_HAS_REACHABLE, NULL, HFILL }},
1728
1729
14
        { &hf_drbd_uuid_flag_discard_my_data, { "discard_my_data", "drbd.uuid_flag.discard_my_data", FT_BOOLEAN, 64, NULL, UUID_FLAG_DISCARD_MY_DATA, NULL, HFILL }},
1730
14
        { &hf_drbd_uuid_flag_crashed_primary, { "crashed_primary", "drbd.uuid_flag.crashed_primary", FT_BOOLEAN, 64, NULL, UUID_FLAG_CRASHED_PRIMARY, NULL, HFILL }},
1731
14
        { &hf_drbd_uuid_flag_inconsistent, { "inconsistent", "drbd.uuid_flag.inconsistent", FT_BOOLEAN, 64, NULL, UUID_FLAG_INCONSISTENT, NULL, HFILL }},
1732
14
        { &hf_drbd_uuid_flag_skip_initial_sync, { "skip_initial_sync", "drbd.uuid_flag.skip_initial_sync", FT_BOOLEAN, 64, NULL, UUID_FLAG_SKIP_INITIAL_SYNC, NULL, HFILL }},
1733
14
        { &hf_drbd_uuid_flag_new_datagen, { "new_datagen", "drbd.uuid_flag.new_datagen", FT_BOOLEAN, 64, NULL, UUID_FLAG_NEW_DATAGEN, NULL, HFILL }},
1734
14
        { &hf_drbd_uuid_flag_stable, { "stable", "drbd.uuid_flag.stable", FT_BOOLEAN, 64, NULL, UUID_FLAG_STABLE, NULL, HFILL }},
1735
14
        { &hf_drbd_uuid_flag_got_stable, { "got_stable", "drbd.uuid_flag.got_stable", FT_BOOLEAN, 64, NULL, UUID_FLAG_GOT_STABLE, NULL, HFILL }},
1736
14
        { &hf_drbd_uuid_flag_resync, { "resync", "drbd.uuid_flag.resync", FT_BOOLEAN, 64, NULL, UUID_FLAG_RESYNC, NULL, HFILL }},
1737
14
        { &hf_drbd_uuid_flag_reconnect, { "reconnect", "drbd.uuid_flag.reconnect", FT_BOOLEAN, 64, NULL, UUID_FLAG_RECONNECT, NULL, HFILL }},
1738
14
        { &hf_drbd_uuid_flag_diskless_primary, { "diskless_primary", "drbd.uuid_flag.diskless_primary", FT_BOOLEAN, 64, NULL, UUID_FLAG_DISKLESS_PRIMARY, NULL, HFILL }},
1739
14
        { &hf_drbd_uuid_flag_primary_lost_quorum, { "primary_lost_quorum", "drbd.uuid_flag.primary_lost_quorum", FT_BOOLEAN, 64, NULL, UUID_FLAG_PRIMARY_LOST_QUORUM, NULL, HFILL }},
1740
1741
14
        { &hf_drbd_dp_hardbarrier, { "hardbarrier", "drbd.dp_flag.hardbarrier", FT_BOOLEAN, 32, NULL, DP_HARDBARRIER, NULL, HFILL }},
1742
14
        { &hf_drbd_dp_rw_sync, { "rw_sync", "drbd.dp_flag.rw_sync", FT_BOOLEAN, 32, NULL, DP_RW_SYNC, NULL, HFILL }},
1743
14
        { &hf_drbd_dp_may_set_in_sync, { "may_set_in_sync", "drbd.dp_flag.may_set_in_sync", FT_BOOLEAN, 32, NULL, DP_MAY_SET_IN_SYNC, NULL, HFILL }},
1744
14
        { &hf_drbd_dp_unplug, { "unplug", "drbd.dp_flag.unplug", FT_BOOLEAN, 32, NULL, DP_UNPLUG, NULL, HFILL }},
1745
14
        { &hf_drbd_dp_fua, { "fua", "drbd.dp_flag.fua", FT_BOOLEAN, 32, NULL, DP_FUA, NULL, HFILL }},
1746
14
        { &hf_drbd_dp_flush, { "flush", "drbd.dp_flag.flush", FT_BOOLEAN, 32, NULL, DP_FLUSH, NULL, HFILL }},
1747
14
        { &hf_drbd_dp_discard, { "discard", "drbd.dp_flag.discard", FT_BOOLEAN, 32, NULL, DP_DISCARD, NULL, HFILL }},
1748
14
        { &hf_drbd_dp_send_receive_ack, { "send_receive_ack", "drbd.dp_flag.send_receive_ack", FT_BOOLEAN, 32, NULL, DP_SEND_RECEIVE_ACK, NULL, HFILL }},
1749
14
        { &hf_drbd_dp_send_write_ack, { "send_write_ack", "drbd.dp_flag.send_write_ack", FT_BOOLEAN, 32, NULL, DP_SEND_WRITE_ACK, NULL, HFILL }},
1750
14
        { &hf_drbd_dp_wsame, { "wsame", "drbd.dp_flag.wsame", FT_BOOLEAN, 32, NULL, DP_WSAME, NULL, HFILL }},
1751
14
        { &hf_drbd_dp_zeroes, { "zeroes", "drbd.dp_flag.zeroes", FT_BOOLEAN, 32, NULL, DP_ZEROES, NULL, HFILL }},
1752
14
    };
1753
1754
14
    static hf_register_info hf_lb_tcp[] = {
1755
14
        { &hf_drbd_lb_tcp_seq, { "lb-tcp sequence number", "drbd_lb_tcp.seq", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1756
14
        { &hf_drbd_lb_tcp_length, { "lb-tcp length", "drbd_lb_tcp.length", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
1757
14
    };
1758
1759
14
    static int *ett[] = {
1760
14
        &ett_drbd,
1761
14
        &ett_drbd_lb_tcp,
1762
14
        &ett_drbd_state,
1763
14
        &ett_drbd_twopc_flags,
1764
14
        &ett_drbd_uuid_flags,
1765
14
        &ett_drbd_history_uuids,
1766
14
        &ett_drbd_data_flags,
1767
14
    };
1768
1769
14
    proto_drbd = proto_register_protocol("DRBD Protocol", "DRBD", "drbd");
1770
14
    proto_register_field_array(proto_drbd, hf, array_length(hf));
1771
1772
14
    proto_drbd_lb_tcp = proto_register_protocol("DRBD Load-Balanced Protocol", "DRBD lb-tcp", "drbd_lb_tcp");
1773
14
    proto_register_field_array(proto_drbd_lb_tcp, hf_lb_tcp, array_length(hf_lb_tcp));
1774
1775
14
    proto_register_subtree_array(ett, array_length(ett));
1776
1777
14
    drbd_handle = register_dissector("drbd", dissect_drbd, proto_drbd);
1778
14
    drbd_lb_tcp_handle = register_dissector("drbd_lb_tcp", dissect_drbd_lb_tcp, proto_drbd_lb_tcp);
1779
14
}
1780
1781
void proto_reg_handoff_drbd(void)
1782
14
{
1783
14
    heur_dissector_add("tcp", test_drbd_protocol, "DRBD over TCP", "drbd_tcp", proto_drbd, HEURISTIC_DISABLE);
1784
14
    heur_dissector_add("infiniband.payload", dissect_drbd_ib, "DRBD over RDMA", "drbd_rdma", proto_drbd, HEURISTIC_DISABLE);
1785
14
    heur_dissector_add("tcp", test_drbd_lb_tcp_protocol, "DRBD Load-Balanced over TCP", "drbd_lb_tcp", proto_drbd_lb_tcp, HEURISTIC_DISABLE);
1786
14
}
1787
1788
/*
1789
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1790
 *
1791
 * Local variables:
1792
 * c-basic-offset: 4
1793
 * tab-width: 8
1794
 * indent-tabs-mode: nil
1795
 * End:
1796
 *
1797
 * vi: set shiftwidth=4 tabstop=8 expandtab:
1798
 * :indentSize=4:tabSize=8:noTabs=true:
1799
 */