diff --git a/epan/dissectors/packet-usbll.c b/epan/dissectors/packet-usbll.c index 06f6776cad..3fe6963dc6 100644 --- a/epan/dissectors/packet-usbll.c +++ b/epan/dissectors/packet-usbll.c @@ -1628,9 +1628,7 @@ dissect_usbll_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offs */ } } - else if ((ep_info->type == USBLL_EP_BULK) || - (ep_info->type == USBLL_EP_INTERRUPT) || - (ep_info->type == USBLL_EP_ISOCHRONOUS)) + else if ((ep_info->type == USBLL_EP_BULK) || (ep_info->type == USBLL_EP_INTERRUPT)) { if (pid == ep_info->last_data_pid) { @@ -1679,6 +1677,17 @@ dissect_usbll_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offs ep_info->last_data_len = data_size; } } + else if (ep_info->type == USBLL_EP_ISOCHRONOUS) + { + /* TODO: Reassemble high-bandwidth endpoints data */ + transfer = wmem_new0(wmem_file_scope(), usbll_transfer_info_t); + transfer->first_packet = pinfo->num; + transfer->offset = 0; + transfer->type = ep_info->type; + transfer->from_host = from_host; + transfer->more_frags = FALSE; + wmem_map_insert(transfer_info, GUINT_TO_POINTER(pinfo->num), transfer); + } } transfer = (usbll_transfer_info_t *)wmem_map_lookup(transfer_info, GUINT_TO_POINTER(pinfo->num)); @@ -1686,7 +1695,9 @@ dissect_usbll_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offs { tvbuff_t *transfer_tvb; - if ((transfer->first_packet == pinfo->num) && (!transfer->more_frags)) + if ((transfer->first_packet == pinfo->num) && (!transfer->more_frags) && + (((transfer->type == USBLL_EP_CONTROL) && (transfer->from_host)) || + (transfer->type == USBLL_EP_ISOCHRONOUS))) { /* No multi-packet reassembly needed, simply construct tvb */ transfer_tvb = tvb_new_subset_length(tvb, data_offset, data_size); @@ -1695,9 +1706,10 @@ dissect_usbll_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offs else { fragment_head *head; - head = fragment_add_check(&usbll_reassembly_table, tvb, data_offset, - pinfo, transfer->first_packet, NULL, - transfer->offset, data_size, transfer->more_frags); + head = fragment_add_check_with_fallback(&usbll_reassembly_table, + tvb, data_offset, + pinfo, transfer->first_packet, NULL, + transfer->offset, data_size, transfer->more_frags, transfer->first_packet); transfer_tvb = process_reassembled_data(tvb, data_offset, pinfo, "USB transfer", head, &usbll_frag_items, NULL, tree); diff --git a/epan/reassemble.c b/epan/reassemble.c index ab6634750d..40e9ce5d8b 100644 --- a/epan/reassemble.c +++ b/epan/reassemble.c @@ -1200,7 +1200,7 @@ static gboolean fragment_add_work(fragment_head *fd_head, tvbuff_t *tvb, const int offset, const packet_info *pinfo, const guint32 frag_offset, const guint32 frag_data_len, const gboolean more_frags, - const guint32 frag_frame) + const guint32 frag_frame, const gboolean allow_overlaps) { fragment_item *fd; fragment_item *fd_i; @@ -1220,7 +1220,7 @@ fragment_add_work(fragment_head *fd_head, tvbuff_t *tvb, const int offset, /* * Are we adding to an already-completed reassembly? */ - if (fd_head->flags & FD_DEFRAGMENTED) { + if ((fd_head->flags & FD_DEFRAGMENTED) && !allow_overlaps) { /* * Yes. Does this fragment go past the end of the results * of that reassembly? @@ -1698,7 +1698,7 @@ fragment_add_common(reassembly_table *table, tvbuff_t *tvb, const int offset, } if (fragment_add_work(fd_head, tvb, offset, pinfo, frag_offset, - frag_data_len, more_frags, frag_frame)) { + frag_data_len, more_frags, frag_frame, FALSE)) { /* * Reassembly is complete. */ @@ -1759,14 +1759,16 @@ fragment_add_out_of_order(reassembly_table *table, tvbuff_t *tvb, } fragment_head * -fragment_add_check(reassembly_table *table, tvbuff_t *tvb, const int offset, +fragment_add_check_with_fallback(reassembly_table *table, tvbuff_t *tvb, const int offset, const packet_info *pinfo, const guint32 id, const void *data, const guint32 frag_offset, - const guint32 frag_data_len, const gboolean more_frags) + const guint32 frag_data_len, const gboolean more_frags, + const guint32 fallback_frame) { reassembled_key reass_key; fragment_head *fd_head; gpointer orig_key; + gboolean late_retransmission = FALSE; /* * If this isn't the first pass, look for this frame in the table @@ -1783,6 +1785,20 @@ fragment_add_check(reassembly_table *table, tvbuff_t *tvb, const int offset, * the memory allocated for the original key, for example before calling g_hash_table_remove() */ fd_head = lookup_fd_head(table, pinfo, id, data, &orig_key); + if ((fd_head == NULL) && (fallback_frame != pinfo->num)) { + /* Check if there is completed reassembly reachable from fallback frame */ + reass_key.frame = fallback_frame; + reass_key.id = id; + fd_head = (fragment_head *)g_hash_table_lookup(table->reassembled_table, &reass_key); + if (fd_head != NULL) { + /* Found completely reassembled packet, hash it with current frame number */ + reassembled_key *new_key = g_slice_new(reassembled_key); + new_key->frame = pinfo->num; + new_key->id = id; + g_hash_table_insert(table->reassembled_table, new_key, fd_head); + late_retransmission = TRUE; + } + } if (fd_head == NULL) { /* not found, this must be the first snooped fragment for this * packet. Create list-head. @@ -1804,7 +1820,11 @@ fragment_add_check(reassembly_table *table, tvbuff_t *tvb, const int offset, } if (fragment_add_work(fd_head, tvb, offset, pinfo, frag_offset, - frag_data_len, more_frags, pinfo->num)) { + frag_data_len, more_frags, pinfo->num, late_retransmission)) { + /* Nothing left to do if it was a late retransmission */ + if (late_retransmission) { + return fd_head; + } /* * Reassembly is complete. * Remove this from the table of in-progress @@ -1831,6 +1851,16 @@ fragment_add_check(reassembly_table *table, tvbuff_t *tvb, const int offset, } } +fragment_head * +fragment_add_check(reassembly_table *table, tvbuff_t *tvb, const int offset, + const packet_info *pinfo, const guint32 id, + const void *data, const guint32 frag_offset, + const guint32 frag_data_len, const gboolean more_frags) +{ + return fragment_add_check_with_fallback(table, tvb, offset, pinfo, id, data, + frag_offset, frag_data_len, more_frags, pinfo->num); +} + static void fragment_defragment_and_free (fragment_head *fd_head, const packet_info *pinfo) { diff --git a/epan/reassemble.h b/epan/reassemble.h index 4105841ce1..545bfda486 100644 --- a/epan/reassemble.h +++ b/epan/reassemble.h @@ -263,6 +263,22 @@ fragment_add_check(reassembly_table *table, tvbuff_t *tvb, const int offset, const void *data, const guint32 frag_offset, const guint32 frag_data_len, const gboolean more_frags); +/* + * Like fragment_add_check, but handles retransmissions after reassembly. + * + * Start new reassembly only if there is no reassembly in progress and there + * is no completed reassembly reachable from fallback_frame. If there is + * completed reassembly (reachable from fallback_frame), simply links this + * packet into the list, updating the flags if necessary (however actual data + * and reassembled in frame won't be modified). + */ +WS_DLL_PUBLIC fragment_head * +fragment_add_check_with_fallback(reassembly_table *table, tvbuff_t *tvb, const int offset, + const packet_info *pinfo, const guint32 id, + const void *data, const guint32 frag_offset, + const guint32 frag_data_len, const gboolean more_frags, + const guint32 fallback_frame); + /* * Like fragment_add, but fragments have a block sequence number starting from * zero (for the first fragment of each datagram). This differs from diff --git a/packaging/debian/libwireshark0.symbols b/packaging/debian/libwireshark0.symbols index c281753171..f0ce9a7350 100644 --- a/packaging/debian/libwireshark0.symbols +++ b/packaging/debian/libwireshark0.symbols @@ -701,6 +701,7 @@ libwireshark.so.0 libwireshark0 #MINVER# follow_tvb_tap_listener@Base 2.1.0 fragment_add@Base 1.9.1 fragment_add_check@Base 1.9.1 + fragment_add_check_with_fallback@Base 4.2.0 fragment_add_multiple_ok@Base 1.9.1 fragment_add_out_of_order@Base 3.7.0 fragment_add_seq@Base 1.9.1