epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-bt-utp.c
blob5dc537997a403a05957f460c28b549903a898e2b
1 /* packet-bt-utp.c
2 * Routines for BT-UTP dissection
3 * Copyright 2011, Xiao Xiangquan <xiaoxiangquan@gmail.com>
4 * Copyright 2021, John Thacker <johnthacker@gmail.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1999 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include "config.h"
15 #include <epan/packet.h>
16 #include <epan/conversation.h>
17 #include <epan/exceptions.h>
18 #include <epan/show_exception.h>
19 #include <epan/expert.h>
20 #include <epan/prefs.h>
21 #include <epan/proto_data.h>
22 #include <epan/unit_strings.h>
24 #include "packet-bt-utp.h"
26 void proto_register_bt_utp(void);
27 void proto_reg_handoff_bt_utp(void);
29 enum {
30 ST_DATA = 0,
31 ST_FIN = 1,
32 ST_STATE = 2,
33 ST_RESET = 3,
34 ST_SYN = 4,
35 ST_NUM_STATES
38 /* V0 hdr: "flags"; V1 hdr: "type" */
39 static const value_string bt_utp_type_vals[] = {
40 { ST_DATA, "Data" },
41 { ST_FIN, "Fin" },
42 { ST_STATE, "State" },
43 { ST_RESET, "Reset" },
44 { ST_SYN, "Syn" },
45 { 0, NULL }
48 enum {
49 EXT_NO_EXTENSION = 0,
50 EXT_SELECTIVE_ACKS = 1,
51 EXT_EXTENSION_BITS = 2,
52 EXT_CLOSE_REASON = 3,
53 EXT_NUM_EXT
56 static const value_string bt_utp_extension_type_vals[] = {
57 { EXT_NO_EXTENSION, "No Extension" },
58 { EXT_SELECTIVE_ACKS, "Selective ACKs" },
59 { EXT_EXTENSION_BITS, "Extension bits" },
60 { EXT_CLOSE_REASON, "Close reason" },
61 { 0, NULL }
64 /* https://github.com/arvidn/libtorrent/blob/master/include/libtorrent/close_reason.hpp */
65 static const value_string bt_utp_close_reason_vals[] = {
66 { 0, "None" },
67 { 1, "Duplicate peer ID" },
68 { 2, "Torrent removed" },
69 { 3, "Memory allocation failed" },
70 { 4, "Port blocked" },
71 { 5, "Address blocked" },
72 { 6, "Upload to upload" },
73 { 7, "Not interested upload only" },
74 { 8, "Timeout" },
75 { 9, "Timeout: interest" },
76 { 10, "Timeout: activity" },
77 { 11, "Timeout: handshake" },
78 { 12, "Timeout: request" },
79 { 13, "Protocol blocked" },
80 { 14, "Peer churn" },
81 { 15, "Too many connections" },
82 { 16, "Too many files" },
83 /* Reasons caused by the peer sending unexpected data are 256 and up */
84 {256, "Encryption error" },
85 {257, "Invalid info hash" },
86 {258, "Self connection" },
87 {259, "Invalid metadata" },
88 {260, "Metadata too big" },
89 {261, "Message too big" },
90 {262, "Invalid message id" },
91 {263, "Invalid message" },
92 {264, "Invalid piece message" },
93 {265, "Invalid have message" },
94 {266, "Invalid bitfield message" },
95 {267, "Invalid choke message" },
96 {268, "Invalid unchoke message" },
97 {269, "Invalid interested message" },
98 {270, "Invalid not interested message" },
99 {271, "Invalid request message" },
100 {272, "Invalid reject message" },
101 {273, "Invalid allow fast message" },
102 {274, "Invalid extended message" },
103 {275, "Invalid cancel message" },
104 {276, "Invalid DHT port message" },
105 {277, "Invalid suggest message" },
106 {278, "Invalid have all message" },
107 {279, "Invalid don't have message" },
108 {280, "Invalid PEX message" },
109 {281, "Invalid metadata request message" },
110 {282, "Invalid metadata message" },
111 {283, "Invalid metadata offset" },
112 {284, "Request when choked" },
113 {285, "Corrupt pieces" },
114 {286, "PEX message too big" },
115 {287, "PEX too frequent" },
116 { 0, NULL }
119 static int proto_bt_utp;
121 /* --- "Original" uTP Header ("version 0" ?) --------------
123 See utp.cpp source code @ https://github.com/bittorrent/libutp
125 -- Fixed Header --
126 0 4 8 16 24 32
127 +-------+-------+---------------+---------------+---------------+
128 | connection_id |
129 +-------+-------+---------------+---------------+---------------+
130 | timestamp_seconds |
131 +---------------+---------------+---------------+---------------+
132 | timestamp_microseconds |
133 +---------------+---------------+---------------+---------------+
134 | timestamp_difference_microseconds |
135 +---------------+---------------+---------------+---------------+
136 | wnd_size | ext | flags | seq_nr [ho] |
137 +---------------+---------------+---------------+---------------+
138 | seq_nr [lo] | ack_nr |
139 +---------------+---------------+---------------+
141 -- Extension Field(s) --
142 0 8 16
143 +---------------+---------------+---------------+---------------+
144 | extension | len | bitmask
145 +---------------+---------------+---------------+---------------+
147 +---------------+---------------+....
151 /* --- Version 1 Header ----------------
153 Specifications: BEP-0029
154 http://www.bittorrent.org/beps/bep_0029.html
156 -- Fixed Header --
157 Fields Types
158 0 4 8 16 24 32
159 +-------+-------+---------------+---------------+---------------+
160 | type | ver | extension | connection_id |
161 +-------+-------+---------------+---------------+---------------+
162 | timestamp_microseconds |
163 +---------------+---------------+---------------+---------------+
164 | timestamp_difference_microseconds |
165 +---------------+---------------+---------------+---------------+
166 | wnd_size |
167 +---------------+---------------+---------------+---------------+
168 | seq_nr | ack_nr |
169 +---------------+---------------+---------------+---------------+
171 -- Extension Field(s) --
172 0 8 16
173 +---------------+---------------+---------------+---------------+
174 | extension | len | bitmask
175 +---------------+---------------+---------------+---------------+
177 +---------------+---------------+....
180 #define V0_FIXED_HDR_SIZE 23
181 #define V1_FIXED_HDR_SIZE 20
183 /* Very early versions of libutp (still used by Transmission) set the max
184 * recv window size to 0x00380000, versions from 2013 and later set it to
185 * 0x00100000, and some other clients use 0x00040000. This is one of the
186 * few possible sources of heuristics.
189 #define V1_MAX_WINDOW_SIZE 0x380000U
191 static dissector_handle_t bt_utp_handle;
192 static dissector_handle_t bittorrent_handle;
194 static int hf_bt_utp_ver;
195 static int hf_bt_utp_type;
196 static int hf_bt_utp_flags;
197 static int hf_bt_utp_extension;
198 static int hf_bt_utp_next_extension_type;
199 static int hf_bt_utp_extension_len;
200 static int hf_bt_utp_extension_bitmask;
201 static int hf_bt_utp_extension_close_reason;
202 static int hf_bt_utp_extension_unknown;
203 static int hf_bt_utp_connection_id_v0;
204 static int hf_bt_utp_connection_id_v1;
205 static int hf_bt_utp_stream;
206 static int hf_bt_utp_timestamp_sec;
207 static int hf_bt_utp_timestamp_us;
208 static int hf_bt_utp_timestamp_diff_us;
209 static int hf_bt_utp_wnd_size_v0;
210 static int hf_bt_utp_wnd_size_v1;
211 static int hf_bt_utp_seq_nr;
212 static int hf_bt_utp_ack_nr;
213 static int hf_bt_utp_len;
214 static int hf_bt_utp_data;
215 static int hf_bt_utp_pdu_size;
216 static int hf_bt_utp_continuation_to;
218 static expert_field ei_extension_len_invalid;
220 static int ett_bt_utp;
221 static int ett_bt_utp_extension;
223 static bool enable_version0;
224 static unsigned max_window_size = V1_MAX_WINDOW_SIZE;
225 /* XXX: Desegmentation and OOO-reassembly are not supported yet */
226 static bool utp_desegment;
227 /*static bool utp_reassemble_out_of_order = false;*/
228 static bool utp_analyze_seq = true;
230 static uint32_t bt_utp_stream_count;
232 typedef struct _utp_multisegment_pdu {
234 uint16_t first_seq;
235 uint16_t last_seq;
236 unsigned first_seq_start_offset;
237 unsigned last_seq_end_offset;
238 /*int length;
239 uint32_t reassembly_id;*/
240 uint32_t first_frame;
242 } utp_multisegment_pdu;
244 typedef struct _utp_flow_t {
245 #if 0
246 /* XXX: Some other things to add in later. */
247 bool base_seq_set;
248 uint16_t base_seq;
249 uint32_t fin;
250 uint32_t window;
251 uint32_t maxnextseq;
252 #endif
254 wmem_tree_t *multisegment_pdus;
255 } utp_flow_t;
257 typedef struct {
258 uint32_t stream;
260 utp_flow_t flow[2];
261 utp_flow_t *fwd;
262 utp_flow_t *rev;
263 #if 0
264 /* XXX: Some other things to add in later. */
265 nstime_t ts_first;
266 nstime_t ts_prev;
267 uint8_t conversation_completeness;
268 #endif
269 } utp_stream_info_t;
271 /* Per-packet header information. */
272 typedef struct {
273 uint8_t type;
274 bool v0;
275 uint32_t connection; /* The prelease "V0" version is 32 bit */
276 uint32_t stream;
277 uint16_t seq;
278 uint16_t ack;
279 uint32_t seglen; /* reported length remaining */
280 bool have_seglen;
282 proto_tree *tree; /* For the bittorrent subdissector to access */
283 } utp_info_t;
285 static utp_stream_info_t*
286 get_utp_stream_info(packet_info *pinfo, utp_info_t *utp_info)
288 conversation_t* conv;
289 utp_stream_info_t *stream_info;
290 uint32_t id_up, id_down;
291 int direction;
293 /* Handle connection ID wrapping correctly. (Mainline libutp source
294 * does not appear to do this, probably fails to connect if the random
295 * connection ID is GMAX_UINT16 and tries again.)
297 if (utp_info->v0) {
298 id_up = utp_info->connection+1;
299 id_down = utp_info->connection-1;
300 } else {
301 id_up = (uint16_t)(utp_info->connection+1);
302 id_down = (uint16_t)(utp_info->connection-1);
305 if (utp_info->type == ST_SYN) {
306 /* SYN packets are special, they have the connection ID for the other
307 * side, and allow us to know both.
309 conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, CONVERSATION_BT_UTP,
310 id_up, utp_info->connection, 0);
311 if (!conv) {
312 /* XXX: A SYN for between the same pair of hosts with a duplicate
313 * connection ID in the same direction is almost surely a retransmission
314 * (unless there's a client that doesn't actually generate random IDs.)
315 * We could check to see if we've gotten a FIN or RST on that same
316 * connection, and also could do like TCP and see if the initial sequence
317 * number matches. (The latter still doesn't help if the client also
318 * doesn't start with random sequence numbers.)
320 conv = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, CONVERSATION_BT_UTP, id_up, utp_info->connection, 0);
322 } else {
323 /* For non-SYN packets, we know our connection ID, but we don't know if
324 * the other side has our ID+1 (src initiated the connection) or our ID-1
325 * (dst initiated). We also don't want find_conversation() to accidentally
326 * call conversation_set_port2() with the wrong ID. So first we see if
327 * we have a wildcarded conversation around (if we've seen previous
328 * non-SYN packets from our current direction but none in the other.)
330 conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, CONVERSATION_BT_UTP, utp_info->connection, 0, NO_PORT_B);
331 if (!conv) {
332 /* Do we have a complete conversation originated by our src, or
333 * possibly a wildcarded conversation originated in this direction
334 * (but we saw a non-SYN for the non-initiating side first)? */
335 conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, CONVERSATION_BT_UTP, utp_info->connection, id_up, 0);
336 if (!conv) {
337 /* As above, but dst initiated? */
338 conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, CONVERSATION_BT_UTP, utp_info->connection, id_down, 0);
339 if (!conv) {
340 /* Didn't find it, so create a new wildcarded conversation. When we
341 * get a packet for the other direction, find_conversation() above
342 * will set port2 with the other connection ID.
344 conv = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, CONVERSATION_BT_UTP, utp_info->connection, 0, NO_PORT2);
350 stream_info = (utp_stream_info_t *)conversation_get_proto_data(conv, proto_bt_utp);
351 if (!stream_info) {
352 stream_info = wmem_new0(wmem_file_scope(), utp_stream_info_t);
353 stream_info->stream = bt_utp_stream_count++;
354 stream_info->flow[0].multisegment_pdus=wmem_tree_new(wmem_file_scope());
355 stream_info->flow[1].multisegment_pdus=wmem_tree_new(wmem_file_scope());
356 conversation_add_proto_data(conv, proto_bt_utp, stream_info);
359 /* check direction */
360 direction=cmp_address(&pinfo->src, &pinfo->dst);
361 /* if the addresses are equal, match the ports instead. Use
362 * the UDP ports instead of the uTP connection IDs because
363 * we don't know which ID is smaller if we don't have both. */
364 if(direction==0) {
365 direction= (pinfo->srcport > pinfo->destport) ? 1 : -1;
367 if(direction>=0) {
368 stream_info->fwd=&(stream_info->flow[0]);
369 stream_info->rev=&(stream_info->flow[1]);
370 } else {
371 stream_info->fwd=&(stream_info->flow[1]);
372 stream_info->rev=&(stream_info->flow[0]);
375 return stream_info;
378 static void
379 print_pdu_tracking_data(packet_info *pinfo, tvbuff_t *tvb, proto_tree *utp_tree, utp_multisegment_pdu *msp)
381 proto_item *item;
383 col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "[Continuation to #%u] ", msp->first_frame);
384 item=proto_tree_add_uint(utp_tree, hf_bt_utp_continuation_to,
385 tvb, 0, 0, msp->first_frame);
386 proto_item_set_generated(item);
389 static int
390 scan_for_next_pdu(tvbuff_t *tvb, proto_tree *utp_tree, packet_info *pinfo, wmem_tree_t *multisegment_pdus)
392 utp_multisegment_pdu *msp;
393 utp_info_t *p_utp_info;
394 uint16_t seq, prev_seq;
396 p_utp_info = (utp_info_t *)p_get_proto_data(pinfo->pool, pinfo, proto_bt_utp, pinfo->curr_layer_num);
398 /* XXX: Wraparound is possible, as is cycling through all 16 bit
399 * sequence numbers in a connection. We only do this path if
400 * "seq analysis" is on; that ought to do something (relative
401 * sequence numbers definitely, maybe extend the width?) to help,
402 * but doesn't yet.
404 seq = p_utp_info->seq;
405 prev_seq = seq - 1;
406 msp = (utp_multisegment_pdu *)wmem_tree_lookup32_le(multisegment_pdus, prev_seq);
407 if (msp) {
409 if(seq>msp->first_seq && seq<=msp->last_seq) {
410 print_pdu_tracking_data(pinfo, tvb, utp_tree, msp);
413 /* If this segment is completely within a previous PDU
414 * then we just skip this packet
416 if(seq>msp->first_seq && seq<msp->last_seq) {
417 return -1;
420 if(seq>msp->first_seq && seq==msp->last_seq) {
421 if (!PINFO_FD_VISITED(pinfo) && p_utp_info->have_seglen) {
422 /* Unlike TCP, the sequence numbers don't measure bytes, so
423 * we can only really update the end of the MSP when the packets
424 * are in order, and if we have the real segment length (so not
425 * an unreassembled IP fragment).
427 if (p_utp_info->seglen >= msp->last_seq_end_offset) {
428 return msp->last_seq_end_offset;
429 } else {
430 msp->last_seq++;
431 msp->last_seq_end_offset -= p_utp_info->seglen;
432 return -1;
434 } else {
435 /* We can still provide a hint to the offset start in some
436 * cases even when we can't update the MSP.
438 if (msp->last_seq_end_offset < tvb_reported_length(tvb)) {
439 return msp->last_seq_end_offset;
440 } else {
441 return -1;
447 return 0;
450 static utp_multisegment_pdu *
451 pdu_store_sequencenumber_of_next_pdu(packet_info *pinfo, uint16_t seq, int offset, uint32_t bytes_until_next_pdu, wmem_tree_t *multisegment_pdus)
453 utp_multisegment_pdu *msp;
455 msp = wmem_new(wmem_file_scope(), utp_multisegment_pdu);
456 msp->first_seq = seq;
457 msp->first_seq_start_offset = offset;
458 msp->last_seq = seq+1;
459 msp->last_seq_end_offset = bytes_until_next_pdu;
460 msp->first_frame = pinfo->num;
461 wmem_tree_insert32(multisegment_pdus, seq, (void *)msp);
463 return msp;
466 #if 0
467 static void
468 desegment_utp(tvbuff_t *tvb, packet_info *pinfo, int offset,
469 uint32_t seq, uint32_t nxtseq,
470 proto_tree *tree, proto_tree *utp_tree,
471 utp_stream_info_t *stream_info)
475 #endif
477 void
478 utp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
479 bool proto_desegment, unsigned fixed_len,
480 unsigned (*get_pdu_len)(packet_info *, tvbuff_t *, int, void*),
481 dissector_t dissect_pdu, void* dissector_data)
483 volatile int offset = 0;
484 int offset_before;
485 unsigned captured_length_remaining;
486 volatile unsigned plen;
487 unsigned length;
488 tvbuff_t *next_tvb;
489 proto_item *item=NULL;
490 const char *saved_proto;
491 uint8_t curr_layer_num;
492 wmem_list_frame_t *frame;
494 while (tvb_reported_length_remaining(tvb, offset) > 0) {
496 * We use "tvb_ensure_captured_length_remaining()" to make
497 * sure there actually *is* data remaining. The protocol
498 * we're handling could conceivably consists of a sequence of
499 * fixed-length PDUs, and therefore the "get_pdu_len" routine
500 * might not actually fetch anything from the tvbuff, and thus
501 * might not cause an exception to be thrown if we've run past
502 * the end of the tvbuff.
504 * This means we're guaranteed that "captured_length_remaining" is positive.
506 captured_length_remaining = tvb_ensure_captured_length_remaining(tvb, offset);
509 * Can we do reassembly?
511 if (proto_desegment && pinfo->can_desegment) {
513 * Yes - is the fixed-length part of the PDU split across segment
514 * boundaries?
516 if (captured_length_remaining < fixed_len) {
518 * Yes. Tell the uTP dissector where the data for this message
519 * starts in the data it handed us and that we need "some more
520 * data." Don't tell it exactly how many bytes we need because
521 * if/when we ask for even more (after the header) that will
522 * break reassembly.
524 pinfo->desegment_offset = offset;
525 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
526 return;
531 * Get the length of the PDU.
533 plen = (*get_pdu_len)(pinfo, tvb, offset, dissector_data);
534 if (plen == 0) {
536 * Support protocols which have a variable length which cannot
537 * always be determined within the given fixed_len.
540 * If another segment was requested but we can't do reassembly,
541 * abort and warn about the unreassembled packet.
543 THROW_ON(!(proto_desegment && pinfo->can_desegment), FragmentBoundsError);
544 pinfo->desegment_offset = offset;
545 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
546 return;
548 if (plen < fixed_len) {
550 * Either:
552 * 1) the length value extracted from the fixed-length portion
553 * doesn't include the fixed-length portion's length, and
554 * was so large that, when the fixed-length portion's
555 * length was added to it, the total length overflowed;
557 * 2) the length value extracted from the fixed-length portion
558 * includes the fixed-length portion's length, and the value
559 * was less than the fixed-length portion's length, i.e. it
560 * was bogus.
562 * Report this as a bounds error.
564 show_reported_bounds_error(tvb, pinfo, tree);
565 return;
568 /* give a hint to uTP where the next PDU starts
569 * so that it can attempt to find it in case it starts
570 * somewhere in the middle of a segment.
572 if(!pinfo->fd->visited && utp_analyze_seq) {
573 unsigned remaining_bytes;
574 remaining_bytes = tvb_reported_length_remaining(tvb, offset);
575 if(plen>remaining_bytes) {
576 pinfo->want_pdu_tracking=2;
577 pinfo->bytes_until_next_pdu=plen-remaining_bytes;
582 * Can we do reassembly?
584 if (proto_desegment && pinfo->can_desegment) {
586 * Yes - is the PDU split across segment boundaries?
588 if (captured_length_remaining < plen) {
590 * Yes. Tell the TCP dissector where the data for this message
591 * starts in the data it handed us, and how many more bytes we
592 * need, and return.
594 pinfo->desegment_offset = offset;
595 pinfo->desegment_len = plen - captured_length_remaining;
596 return;
600 curr_layer_num = pinfo->curr_layer_num-1;
601 frame = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
602 while (frame && (proto_bt_utp != (int) GPOINTER_TO_UINT(wmem_list_frame_data(frame)))) {
603 frame = wmem_list_frame_prev(frame);
604 curr_layer_num--;
606 #if 0
607 if (captured_length_remaining >= plen || there are more packets)
609 #endif
611 * Display the PDU length as a field
613 item=proto_tree_add_uint(((utp_info_t *)p_get_proto_data(pinfo->pool, pinfo, proto_bt_utp, curr_layer_num))->tree,
614 hf_bt_utp_pdu_size,
615 tvb, offset, plen, plen);
616 proto_item_set_generated(item);
617 #if 0
618 } else {
619 item = proto_tree_add_expert_format((proto_tree *)p_get_proto_data(pinfo->pool, pinfo, proto_bt_utp, curr_layer_num),
620 tvb, offset, -1,
621 "PDU Size: %u cut short at %u",plen,captured_length_remaining);
622 proto_item_set_generated(item);
624 #endif
627 * Construct a tvbuff containing the amount of the payload we have
628 * available. Make its reported length the amount of data in the PDU.
630 length = captured_length_remaining;
631 if (length > plen) {
632 length = plen;
634 next_tvb = tvb_new_subset_length_caplen(tvb, offset, length, plen);
635 if (!(proto_desegment && pinfo->can_desegment)) {
636 /* If we can't do reassembly, give a hint that bounds errors
637 * are probably fragment errors. */
638 tvb_set_fragment(next_tvb);
642 * Dissect the PDU.
644 * If it gets an error that means there's no point in
645 * dissecting any more PDUs, rethrow the exception in
646 * question.
648 * If it gets any other error, report it and continue, as that
649 * means that PDU got an error, but that doesn't mean we should
650 * stop dissecting PDUs within this frame or chunk of reassembled
651 * data.
653 saved_proto = pinfo->current_proto;
654 TRY {
655 (*dissect_pdu)(next_tvb, pinfo, tree, dissector_data);
657 CATCH_NONFATAL_ERRORS {
658 show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
660 * Restore the saved protocol as well; we do this after
661 * show_exception(), so that the "Malformed packet" indication
662 * shows the protocol for which dissection failed.
664 pinfo->current_proto = saved_proto;
666 ENDTRY;
669 * Step to the next PDU.
670 * Make sure we don't overflow.
672 offset_before = offset;
673 offset += plen;
674 if (offset <= offset_before)
675 break;
679 static int
680 get_utp_version(tvbuff_t *tvb) {
681 uint8_t v0_flags;
682 uint8_t v1_ver_type, ext, ext_len;
683 uint32_t window;
684 unsigned len, offset = 0;
685 int ver = -1;
687 /* Simple heuristics inspired by code from utp.cpp */
689 len = tvb_captured_length(tvb);
691 /* Version 1? */
692 if (len < V1_FIXED_HDR_SIZE) {
693 return -1;
696 v1_ver_type = tvb_get_uint8(tvb, 0);
697 ext = tvb_get_uint8(tvb, 1);
698 if (((v1_ver_type & 0x0f) == 1) && ((v1_ver_type>>4) < ST_NUM_STATES) &&
699 (ext < EXT_NUM_EXT)) {
700 window = tvb_get_uint32(tvb, 12, ENC_BIG_ENDIAN);
701 if (window > max_window_size) {
702 return -1;
704 ver = 1;
705 offset = V1_FIXED_HDR_SIZE;
706 } else if (enable_version0) {
707 /* Version 0? */
708 if (len < V0_FIXED_HDR_SIZE) {
709 return -1;
711 v0_flags = tvb_get_uint8(tvb, 18);
712 ext = tvb_get_uint8(tvb, 17);
713 if ((v0_flags < ST_NUM_STATES) && (ext < EXT_NUM_EXT)) {
714 ver = 0;
715 offset = V0_FIXED_HDR_SIZE;
719 if (ver < 0) {
720 return ver;
723 /* In V0 we could use the microseconds value as a heuristic, because
724 * it was tv_usec, but in the modern V1 we cannot, because it is
725 * computed by converting a time_t into a 64 bit quantity of microseconds
726 * and then taking the lower 32 bits, so all possible values are likely.
728 /* If we have an extension, then check the next two bytes,
729 * the first of which is another extension type (likely NO_EXTENSION)
730 * and the second of which is a length, which must be at least 4.
732 if (ext != EXT_NO_EXTENSION) {
733 if (len < offset + 2) {
734 return -1;
736 ext = tvb_get_uint8(tvb, offset);
737 ext_len = tvb_get_uint8(tvb, offset+1);
738 if (ext >= EXT_NUM_EXT || ext_len < 4) {
739 return -1;
743 return ver;
746 static int
747 dissect_utp_header_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, uint8_t *extension_type)
749 /* "Original" (V0) */
750 utp_info_t *p_utp_info = NULL;
751 utp_stream_info_t *stream_info = NULL;
753 proto_item *ti;
754 uint32_t type, connection, win, seq, ack;
756 p_utp_info = wmem_new(pinfo->pool, utp_info_t);
757 p_utp_info->v0 = true;
758 p_add_proto_data(pinfo->pool, pinfo, proto_bt_utp, pinfo->curr_layer_num, p_utp_info);
760 proto_tree_add_item_ret_uint(tree, hf_bt_utp_connection_id_v0, tvb, offset, 4, ENC_BIG_ENDIAN, &connection);
761 offset += 4;
762 proto_tree_add_item(tree, hf_bt_utp_timestamp_sec, tvb, offset, 4, ENC_BIG_ENDIAN);
763 offset += 4;
764 proto_tree_add_item(tree, hf_bt_utp_timestamp_us, tvb, offset, 4, ENC_BIG_ENDIAN);
765 offset += 4;
766 proto_tree_add_item(tree, hf_bt_utp_timestamp_diff_us, tvb, offset, 4, ENC_BIG_ENDIAN);
767 offset += 4;
768 proto_tree_add_item_ret_uint(tree, hf_bt_utp_wnd_size_v0, tvb, offset, 1, ENC_BIG_ENDIAN, &win);
769 offset += 1;
770 proto_tree_add_item(tree, hf_bt_utp_next_extension_type, tvb, offset, 1, ENC_BIG_ENDIAN);
771 *extension_type = tvb_get_uint8(tvb, offset);
772 offset += 1;
773 proto_tree_add_item_ret_uint(tree, hf_bt_utp_flags, tvb, offset, 1, ENC_BIG_ENDIAN, &type);
774 offset += 1;
776 col_append_fstr(pinfo->cinfo, COL_INFO, "Connection ID:%d [%s]", connection, val_to_str(type, bt_utp_type_vals, "Unknown %d"));
777 p_utp_info->type = type;
778 p_utp_info->connection = connection;
780 proto_tree_add_item(tree, hf_bt_utp_seq_nr, tvb, offset, 2, ENC_BIG_ENDIAN);
781 offset += 2;
782 proto_tree_add_item(tree, hf_bt_utp_ack_nr, tvb, offset, 2, ENC_BIG_ENDIAN);
783 offset += 2;
785 proto_tree_add_item_ret_uint(tree, hf_bt_utp_seq_nr, tvb, offset, 2, ENC_BIG_ENDIAN, &seq);
786 col_append_str_uint(pinfo->cinfo, COL_INFO, "Seq", seq, " ");
787 p_utp_info->seq = seq;
788 offset += 2;
789 proto_tree_add_item_ret_uint(tree, hf_bt_utp_ack_nr, tvb, offset, 2, ENC_BIG_ENDIAN, &ack);
790 col_append_str_uint(pinfo->cinfo, COL_INFO, "Ack", ack, " ");
791 p_utp_info->ack = ack;
792 offset += 2;
793 col_append_str_uint(pinfo->cinfo, COL_INFO, "Win", win, " ");
795 stream_info = get_utp_stream_info(pinfo, p_utp_info);
796 ti = proto_tree_add_uint(tree, hf_bt_utp_stream, tvb, offset, 0, stream_info->stream);
797 p_utp_info->stream = stream_info->stream;
798 proto_item_set_generated(ti);
800 return offset;
803 static int
804 dissect_utp_header_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, uint8_t *extension_type)
806 /* V1 */
807 utp_info_t *p_utp_info = NULL;
808 utp_stream_info_t *stream_info = NULL;
810 proto_item *ti;
812 uint32_t type, connection, win, seq, ack;
814 p_utp_info = wmem_new(pinfo->pool, utp_info_t);
815 p_utp_info->v0 = false;
816 p_add_proto_data(pinfo->pool, pinfo, proto_bt_utp, pinfo->curr_layer_num, p_utp_info);
818 proto_tree_add_item(tree, hf_bt_utp_ver, tvb, offset, 1, ENC_BIG_ENDIAN);
819 proto_tree_add_item_ret_uint(tree, hf_bt_utp_type, tvb, offset, 1, ENC_BIG_ENDIAN, &type);
820 offset += 1;
821 proto_tree_add_item(tree, hf_bt_utp_next_extension_type, tvb, offset, 1, ENC_BIG_ENDIAN);
822 *extension_type = tvb_get_uint8(tvb, offset);
823 offset += 1;
824 proto_tree_add_item_ret_uint(tree, hf_bt_utp_connection_id_v1, tvb, offset, 2, ENC_BIG_ENDIAN, &connection);
825 offset += 2;
827 col_append_fstr(pinfo->cinfo, COL_INFO, "Connection ID:%d [%s]", connection, val_to_str(type, bt_utp_type_vals, "Unknown %d"));
828 p_utp_info->type = type;
829 p_utp_info->connection = connection;
831 proto_tree_add_item(tree, hf_bt_utp_timestamp_us, tvb, offset, 4, ENC_BIG_ENDIAN);
832 offset += 4;
833 proto_tree_add_item(tree, hf_bt_utp_timestamp_diff_us, tvb, offset, 4, ENC_BIG_ENDIAN);
834 offset += 4;
835 proto_tree_add_item_ret_uint(tree, hf_bt_utp_wnd_size_v1, tvb, offset, 4, ENC_BIG_ENDIAN, &win);
836 offset += 4;
837 proto_tree_add_item_ret_uint(tree, hf_bt_utp_seq_nr, tvb, offset, 2, ENC_BIG_ENDIAN, &seq);
838 col_append_str_uint(pinfo->cinfo, COL_INFO, "Seq", seq, " ");
839 p_utp_info->seq = seq;
840 offset += 2;
841 proto_tree_add_item_ret_uint(tree, hf_bt_utp_ack_nr, tvb, offset, 2, ENC_BIG_ENDIAN, &ack);
842 col_append_str_uint(pinfo->cinfo, COL_INFO, "Ack", ack, " ");
843 p_utp_info->ack = ack;
844 offset += 2;
845 col_append_str_uint(pinfo->cinfo, COL_INFO, "Win", win, " ");
847 stream_info = get_utp_stream_info(pinfo, p_utp_info);
848 ti = proto_tree_add_uint(tree, hf_bt_utp_stream, tvb, offset, 0, stream_info->stream);
849 p_utp_info->stream = stream_info->stream;
850 proto_item_set_generated(ti);
852 /* XXX: Multisegment PDUs are the top priority to add, but a number of
853 * other features in the TCP dissector would be useful- relative sequence
854 * numbers, conversation completeness, maybe even tracking SACKs.
856 return offset;
859 static int
860 dissect_utp_extension(tvbuff_t *tvb, packet_info _U_*pinfo, proto_tree *tree, int offset, uint8_t *extension_type)
862 proto_item *ti;
863 proto_tree *ext_tree;
864 uint32_t next_extension, extension_length;
865 /* display the extension tree */
867 while(*extension_type != EXT_NO_EXTENSION && offset < (int)tvb_reported_length(tvb))
869 ti = proto_tree_add_none_format(tree, hf_bt_utp_extension, tvb, offset, -1, "Extension: %s", val_to_str_const(*extension_type, bt_utp_extension_type_vals, "Unknown"));
870 ext_tree = proto_item_add_subtree(ti, ett_bt_utp_extension);
872 proto_tree_add_item_ret_uint(ext_tree, hf_bt_utp_next_extension_type, tvb, offset, 1, ENC_BIG_ENDIAN, &next_extension);
873 offset += 1;
875 proto_tree_add_item_ret_uint(ext_tree, hf_bt_utp_extension_len, tvb, offset, 1, ENC_BIG_ENDIAN, &extension_length);
876 proto_item_append_text(ti, ", Len=%d", extension_length);
877 offset += 1;
879 switch(*extension_type){
880 case EXT_SELECTIVE_ACKS: /* 1 */
882 proto_tree_add_item(ext_tree, hf_bt_utp_extension_bitmask, tvb, offset, extension_length, ENC_NA);
883 break;
885 case EXT_EXTENSION_BITS: /* 2 */
887 proto_tree_add_item(ext_tree, hf_bt_utp_extension_bitmask, tvb, offset, extension_length, ENC_NA);
888 break;
890 case EXT_CLOSE_REASON: /* 3 */
892 if (extension_length != 4) {
893 expert_add_info(pinfo, ti, &ei_extension_len_invalid);
895 proto_tree_add_item(ext_tree, hf_bt_utp_extension_close_reason, tvb, offset, 4, ENC_NA);
896 break;
898 default:
899 proto_tree_add_item(ext_tree, hf_bt_utp_extension_unknown, tvb, offset, extension_length, ENC_NA);
900 break;
902 offset += extension_length;
903 proto_item_set_len(ti, 1 + 1 + extension_length);
904 *extension_type = next_extension;
907 return offset;
910 static bool
911 decode_utp(tvbuff_t *tvb, int offset, packet_info *pinfo,
912 proto_tree *tree)
914 proto_tree *parent_tree;
915 tvbuff_t *next_tvb;
916 int save_desegment_offset;
917 uint32_t save_desegment_len;
919 /* XXX: Check for retransmission? */
921 next_tvb = tvb_new_subset_remaining(tvb, offset);
923 save_desegment_offset = pinfo->desegment_offset;
924 save_desegment_len = pinfo->desegment_len;
926 /* The only possible payload is bittorrent */
928 parent_tree = proto_tree_get_parent_tree(tree);
929 if (call_dissector_with_data(bittorrent_handle, next_tvb, pinfo, parent_tree, NULL)) {
930 pinfo->want_pdu_tracking -= !!(pinfo->want_pdu_tracking);
931 return true;
934 DISSECTOR_ASSERT(save_desegment_offset == pinfo->desegment_offset &&
935 save_desegment_len == pinfo->desegment_len);
937 call_data_dissector(tvb, pinfo, parent_tree);
938 pinfo->want_pdu_tracking -= !!(pinfo->want_pdu_tracking);
940 return false;
943 static void
944 process_utp_payload(tvbuff_t *tvb, packet_info *pinfo,
945 proto_tree *tree, uint16_t seq, bool is_utp_segment,
946 utp_stream_info_t *stream_info)
948 volatile int offset = 0;
949 pinfo->want_pdu_tracking = 0;
951 TRY {
952 if (is_utp_segment) {
953 /* See if an unaligned PDU */
954 if (stream_info && utp_analyze_seq && (!utp_desegment)) {
955 offset = scan_for_next_pdu(tvb, tree, pinfo,
956 stream_info->fwd->multisegment_pdus);
960 if ((offset != -1) && decode_utp(tvb, offset, pinfo, tree)) {
962 * We succeeded in handing off to bittorent.
964 * Is this a segment (so we're not desegmenting for whatever
965 * reason)? Then at least do rudimentary PDU tracking.
967 if(is_utp_segment) {
968 /* if !visited, check want_pdu_tracking and
969 store it in table */
970 if(stream_info && (!pinfo->fd->visited) &&
971 utp_analyze_seq && pinfo->want_pdu_tracking) {
972 pdu_store_sequencenumber_of_next_pdu(
973 pinfo,
974 seq,
975 offset,
976 pinfo->bytes_until_next_pdu,
977 stream_info->fwd->multisegment_pdus);
982 CATCH_ALL {
983 /* We got an exception. Before dissection is aborted and execution
984 * is transferred back to (probably) the frame dissector, do PDU
985 * tracking if we need to because this is a segment.
987 if (is_utp_segment) {
988 if(stream_info && (!pinfo->fd->visited) &&
989 utp_analyze_seq && pinfo->want_pdu_tracking) {
990 pdu_store_sequencenumber_of_next_pdu(
991 pinfo,
992 seq,
993 offset,
994 pinfo->bytes_until_next_pdu,
995 stream_info->fwd->multisegment_pdus);
998 RETHROW;
1000 ENDTRY;
1003 static unsigned
1004 dissect_utp_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1006 proto_item *ti;
1008 utp_info_t *p_utp_info;
1009 unsigned len_tvb;
1010 bool save_fragmented;
1012 p_utp_info = (utp_info_t *)p_get_proto_data(pinfo->pool, pinfo, proto_bt_utp, pinfo->curr_layer_num);
1014 p_utp_info->tree = tree;
1016 utp_stream_info_t *stream_info;
1017 stream_info = get_utp_stream_info(pinfo, p_utp_info);
1019 len_tvb = tvb_reported_length(tvb);
1021 /* As with TCP, if we've been handed an IP fragment, we don't really
1022 * know how big the segment is, and we don't really want to do anything
1023 * if this is an error packet from ICMP or similar.
1025 * XXX: We don't want to desegment if the UDP checksum is bad either.
1026 * Need to add that to the per-packet info that UDP stores and access
1027 * it.
1029 pinfo->can_desegment = 0;
1030 if (!pinfo->fragmented && !pinfo->flags.in_error_pkt) {
1031 p_utp_info->seglen = len_tvb;
1032 p_utp_info->have_seglen = true;
1034 ti = proto_tree_add_uint(tree, hf_bt_utp_len, tvb, 0, 0, len_tvb);
1035 proto_item_set_generated(ti);
1036 col_append_str_uint(pinfo->cinfo, COL_INFO, "Len", len_tvb, " ");
1038 if (utp_desegment && tvb_bytes_exist(tvb, 0, len_tvb)) {
1039 /* If we actually have the bytes too then we can desegment. */
1040 pinfo->can_desegment = 2;
1042 } else {
1043 p_utp_info->have_seglen = false;
1046 if(tvb_captured_length(tvb)) {
1047 proto_tree_add_item(tree, hf_bt_utp_data, tvb, 0, len_tvb, ENC_NA);
1048 if (pinfo->can_desegment) {
1049 /* XXX: desegment_utp() is not implemented, but we can't get
1050 * into this code path yet because utp_desegment is false. */
1051 } else {
1052 save_fragmented = pinfo->fragmented;
1053 pinfo->fragmented = true;
1054 process_utp_payload(tvb, pinfo, tree, p_utp_info->seq, true, stream_info);
1055 pinfo->fragmented = save_fragmented;
1059 return len_tvb;
1062 static int
1063 dissect_bt_utp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1065 int version;
1066 version = get_utp_version(tvb);
1068 /* try dissecting */
1069 if (version >= 0)
1071 proto_tree *sub_tree = NULL;
1072 proto_item *ti;
1073 int offset = 0;
1074 uint8_t extension_type;
1076 /* set the protocol column */
1077 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BT-uTP");
1078 col_clear(pinfo->cinfo, COL_INFO);
1080 /* Determine header version */
1082 if (version == 0) {
1083 ti = proto_tree_add_protocol_format(tree, proto_bt_utp, tvb, 0, -1,
1084 "uTorrent Transport Protocol V0");
1085 sub_tree = proto_item_add_subtree(ti, ett_bt_utp);
1086 offset = dissect_utp_header_v0(tvb, pinfo, sub_tree, offset, &extension_type);
1087 } else {
1088 ti = proto_tree_add_item(tree, proto_bt_utp, tvb, 0, -1, ENC_NA);
1089 sub_tree = proto_item_add_subtree(ti, ett_bt_utp);
1090 offset = dissect_utp_header_v1(tvb, pinfo, sub_tree, offset, &extension_type);
1093 offset = dissect_utp_extension(tvb, pinfo, sub_tree, offset, &extension_type);
1095 offset += dissect_utp_payload(tvb_new_subset_remaining(tvb, offset), pinfo, sub_tree);
1097 return offset;
1099 return 0;
1102 static bool
1103 dissect_bt_utp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1105 int version;
1106 version = get_utp_version(tvb);
1108 if (version >= 0)
1110 conversation_t *conversation;
1112 conversation = find_or_create_conversation(pinfo);
1113 conversation_set_dissector_from_frame_number(conversation, pinfo->num, bt_utp_handle);
1115 dissect_bt_utp(tvb, pinfo, tree, data);
1116 return true;
1119 return false;
1122 static void
1123 utp_init(void)
1125 bt_utp_stream_count = 0;
1128 void
1129 proto_register_bt_utp(void)
1131 static hf_register_info hf[] = {
1132 { &hf_bt_utp_ver,
1133 { "Version", "bt-utp.ver",
1134 FT_UINT8, BASE_DEC, NULL, 0x0F,
1135 NULL, HFILL }
1137 { &hf_bt_utp_flags,
1138 { "Flags", "bt-utp.flags",
1139 FT_UINT8, BASE_DEC, VALS(bt_utp_type_vals), 0x0,
1140 NULL, HFILL }
1142 { &hf_bt_utp_type,
1143 { "Type", "bt-utp.type",
1144 FT_UINT8, BASE_DEC, VALS(bt_utp_type_vals), 0xF0,
1145 NULL, HFILL }
1147 { &hf_bt_utp_extension,
1148 { "Extension", "bt-utp.extension",
1149 FT_NONE, BASE_NONE, NULL, 0x0,
1150 NULL, HFILL }
1152 { &hf_bt_utp_next_extension_type,
1153 { "Next Extension Type", "bt-utp.next_extension_type",
1154 FT_UINT8, BASE_DEC, VALS(bt_utp_extension_type_vals), 0x0,
1155 NULL, HFILL }
1157 { &hf_bt_utp_extension_len,
1158 { "Extension Length", "bt-utp.extension_len",
1159 FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0,
1160 NULL, HFILL }
1162 { &hf_bt_utp_extension_bitmask,
1163 { "Extension Bitmask", "bt-utp.extension_bitmask",
1164 FT_BYTES, BASE_NONE, NULL, 0x0,
1165 NULL, HFILL }
1167 { &hf_bt_utp_extension_close_reason,
1168 { "Close Reason", "bt-utp.extension_close_reason",
1169 FT_UINT32, BASE_DEC, VALS(bt_utp_close_reason_vals), 0x0,
1170 NULL, HFILL }
1172 { &hf_bt_utp_extension_unknown,
1173 { "Extension Unknown", "bt-utp.extension_unknown",
1174 FT_BYTES, BASE_NONE, NULL, 0x0,
1175 NULL, HFILL }
1177 { &hf_bt_utp_connection_id_v0,
1178 { "Connection ID", "bt-utp.connection_id",
1179 FT_UINT32, BASE_DEC, NULL, 0x0,
1180 NULL, HFILL }
1182 { &hf_bt_utp_connection_id_v1,
1183 { "Connection ID", "bt-utp.connection_id",
1184 FT_UINT16, BASE_DEC, NULL, 0x0,
1185 NULL, HFILL }
1187 { &hf_bt_utp_stream,
1188 { "Stream index", "bt-utp.stream",
1189 FT_UINT32, BASE_DEC, NULL, 0x0,
1190 NULL, HFILL }
1192 { &hf_bt_utp_timestamp_sec,
1193 { "Timestamp seconds", "bt-utp.timestamp_sec",
1194 FT_UINT32, BASE_DEC, NULL, 0x0,
1195 NULL, HFILL }
1197 { &hf_bt_utp_timestamp_us,
1198 { "Timestamp Microseconds", "bt-utp.timestamp_us",
1199 FT_UINT32, BASE_DEC, NULL, 0x0,
1200 NULL, HFILL }
1202 { &hf_bt_utp_timestamp_diff_us,
1203 { "Timestamp Difference Microseconds", "bt-utp.timestamp_diff_us",
1204 FT_UINT32, BASE_DEC, NULL, 0x0,
1205 NULL, HFILL }
1207 { &hf_bt_utp_wnd_size_v0,
1208 { "Window Size", "bt-utp.wnd_size",
1209 FT_UINT8, BASE_DEC, NULL, 0x0,
1210 "V0 receive window size, in multiples of 350 bytes", HFILL }
1212 { &hf_bt_utp_wnd_size_v1,
1213 { "Window Size", "bt-utp.wnd_size",
1214 FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0,
1215 NULL, HFILL }
1217 { &hf_bt_utp_seq_nr,
1218 { "Sequence number", "bt-utp.seq_nr",
1219 FT_UINT16, BASE_DEC, NULL, 0x0,
1220 NULL, HFILL }
1222 { &hf_bt_utp_ack_nr,
1223 { "ACK number", "bt-utp.ack_nr",
1224 FT_UINT16, BASE_DEC, NULL, 0x0,
1225 NULL, HFILL }
1227 { &hf_bt_utp_len,
1228 { "uTP Segment Len", "bt-utp.len",
1229 FT_UINT32, BASE_DEC, NULL, 0x0,
1230 NULL, HFILL }
1232 { &hf_bt_utp_data,
1233 { "Data", "bt-utp.data",
1234 FT_BYTES, BASE_NONE, NULL, 0x0,
1235 NULL, HFILL }
1237 { &hf_bt_utp_pdu_size,
1238 { "PDU Size", "bt-utp.pdu.size",
1239 FT_UINT32, BASE_DEC, NULL, 0x0,
1240 "The size of this PDU", HFILL }
1242 { &hf_bt_utp_continuation_to,
1243 { "This is a continuation to the PDU in frame",
1244 "bt-utp.continuation_to", FT_FRAMENUM, BASE_NONE,
1245 NULL, 0x0, "This is a continuation to the PDU in frame #", HFILL }
1249 static ei_register_info ei[] = {
1250 { &ei_extension_len_invalid,
1251 { "bt-utp.extension_len.invalid", PI_PROTOCOL, PI_WARN,
1252 "The extension is an unexpected length", EXPFILL }
1256 /* Setup protocol subtree array */
1257 static int *ett[] = { &ett_bt_utp, &ett_bt_utp_extension };
1259 module_t *bt_utp_module;
1260 expert_module_t *expert_bt_utp;
1262 /* Register protocol */
1263 proto_bt_utp = proto_register_protocol ("uTorrent Transport Protocol", "BT-uTP", "bt-utp");
1265 bt_utp_module = prefs_register_protocol(proto_bt_utp, NULL);
1266 prefs_register_obsolete_preference(bt_utp_module, "enable");
1267 prefs_register_bool_preference(bt_utp_module,
1268 "analyze_sequence_numbers",
1269 "Analyze uTP sequence numbers",
1270 "Make the uTP dissector analyze uTP sequence numbers. Currently this "
1271 "just means that it tries to find the correct start offset of a PDU "
1272 "if it detected that previous in-order packets spanned multiple "
1273 "frames.",
1274 &utp_analyze_seq);
1275 prefs_register_bool_preference(bt_utp_module,
1276 "enable_version0",
1277 "Dissect prerelease (version 0) packets",
1278 "Whether the dissector should attempt to dissect packets with the "
1279 "obsolete format (version 0) that predates BEP 29 (22-Jun-2009)",
1280 &enable_version0);
1281 prefs_register_uint_preference(bt_utp_module,
1282 "max_window_size",
1283 "Maximum window size (in hex)",
1284 "Maximum receive window size allowed by the dissector. Early clients "
1285 "(and a few modern ones) set this value to 0x380000 (the default), "
1286 "later ones use smaller values like 0x100000 and 0x40000. A higher "
1287 "value can detect nonstandard packets, but at the cost of false "
1288 "positives.",
1289 16, &max_window_size);
1291 proto_register_field_array(proto_bt_utp, hf, array_length(hf));
1292 proto_register_subtree_array(ett, array_length(ett));
1294 expert_bt_utp = expert_register_protocol(proto_bt_utp);
1295 expert_register_field_array(expert_bt_utp, ei, array_length(ei));
1297 register_init_routine(utp_init);
1299 bt_utp_handle = register_dissector("bt-utp", dissect_bt_utp, proto_bt_utp);
1302 void
1303 proto_reg_handoff_bt_utp(void)
1305 /* disabled by default since heuristic is weak */
1306 /* XXX: The heuristic is stronger now, but might still get false positives
1307 * on packets with lots of zero bytes. Needs more testing before enabling
1308 * by default.
1310 heur_dissector_add("udp", dissect_bt_utp_heur, "BitTorrent UTP over UDP", "bt_utp_udp", proto_bt_utp, HEURISTIC_DISABLE);
1312 dissector_add_for_decode_as_with_preference("udp.port", bt_utp_handle);
1314 bittorrent_handle = find_dissector_add_dependency("bittorrent.utp", proto_bt_utp);
1318 * Editor modelines
1320 * Local Variables:
1321 * c-basic-offset: 2
1322 * tab-width: 8
1323 * indent-tabs-mode: nil
1324 * End:
1326 * ex: set shiftwidth=2 tabstop=8 expandtab:
1327 * :indentSize=2:tabSize=8:noTabs=true: