Exemplo n.º 1
0
/* This tests the case that the 802.11 hack does something different for: when
 * the terminal segment in a fragmented datagram arrives first.
 */
static void test_fragment_add_seq_check_1(void)
{
    fragment_data *fd_head;

    printf("Starting test test_fragment_add_seq_check_1\n");

    pinfo.fd->num = 1;
    fd_head=fragment_add_seq_check(tvb, 10, &pinfo, 12, fragment_table,
                                   reassembled_table, 1, 50, FALSE);

    ASSERT_EQ(1,g_hash_table_size(fragment_table));
    ASSERT_EQ(0,g_hash_table_size(reassembled_table));
    ASSERT_EQ(NULL,fd_head);

    /* Now add the missing segment */
    pinfo.fd->num = 2;
    fd_head=fragment_add_seq_check(tvb, 5, &pinfo, 12, fragment_table,
                                   reassembled_table, 0, 60, TRUE);

    ASSERT_EQ(0,g_hash_table_size(fragment_table));
    ASSERT_EQ(2,g_hash_table_size(reassembled_table));
    ASSERT_NE(NULL,fd_head);

    /* check the contents of the structure */
    ASSERT_EQ(0,fd_head->frame);  /* unused */
    ASSERT_EQ(0,fd_head->offset); /* unused */
    ASSERT_EQ(110,fd_head->len); /* the length of data we have */
    ASSERT_EQ(1,fd_head->datalen); /* seqno of the last fragment we have */
    ASSERT_EQ(2,fd_head->reassembled_in);
    ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET,fd_head->flags);
    ASSERT_NE(NULL,fd_head->data);
    ASSERT_NE(NULL,fd_head->next);

    ASSERT_EQ(2,fd_head->next->frame);
    ASSERT_EQ(0,fd_head->next->offset);  /* seqno */
    ASSERT_EQ(60,fd_head->next->len);    /* segment length */
    ASSERT_EQ(0,fd_head->next->flags);
    ASSERT_EQ(NULL,fd_head->next->data);
    ASSERT_NE(NULL,fd_head->next->next);

    ASSERT_EQ(1,fd_head->next->next->frame);
    ASSERT_EQ(1,fd_head->next->next->offset);  /* seqno */
    ASSERT_EQ(50,fd_head->next->next->len);    /* segment length */
    ASSERT_EQ(0,fd_head->next->next->flags);
    ASSERT_EQ(NULL,fd_head->next->next->data);
    ASSERT_EQ(NULL,fd_head->next->next->next);

    /* test the actual reassembly */
    ASSERT(!memcmp(fd_head->data,data+5,60));
    ASSERT(!memcmp(fd_head->data+60,data+10,50));
}
Exemplo n.º 2
0
/** Handle a PFT packet which has the fragmentation header. This uses the
 * standard wireshark methods for reassembling fragments. If FEC is used,
 * the FEC is handled too. For the moment, all the fragments must be
 * available but this could be improved.
 *  \param[in,out] tvb The buffer containing the current fragment
 *  \param[in,out] pinfo The packet info structure
 *  \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
 *  \param[in] findex the fragment count
 *  \param[in] fcount the number of fragments
 *  \param[in] seq the sequence number of the reassembled packet
 *  \param[in] offset the offset into the tvb of the fragment
 *  \param[in] plen the length of each fragment
 *  \param[in] fec is fec used
 *  \param[in] rsk the number of useful bytes in each chunk
 *  \param[in] rsz the number of padding bytes in each chunk
 */
static tvbuff_t *
dissect_pft_fragmented(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
  guint32 findex,
  guint32 fcount,
  guint16 seq,
  gint offset,
  guint16 plen,
  gboolean fec,
  guint16 rsk,
  guint16 rsz
)
{
  gboolean first, last;
  tvbuff_t *new_tvb=NULL;
  fragment_data *frag_edcp = NULL;
  pinfo->fragmented = TRUE;
  first = findex == 0;
  last = fcount == (findex+1);
  frag_edcp = fragment_add_seq_check (
    tvb, offset, pinfo,
    seq,
    dcp_fragment_table, dcp_reassembled_table,
    findex,
    plen,
    !last);
  if(fec) {
    new_tvb = dissect_pft_fec_detailed(
      tvb, pinfo, tree, findex, fcount, seq, offset, plen, fec, rsk, rsz, frag_edcp
      );
  } else {
    new_tvb = process_reassembled_data (tvb, offset, pinfo,
                                        "Reassembled DCP (ETSI)",
                                        frag_edcp, &dcp_frag_items,
                                        NULL, tree);
  }
  if (check_col (pinfo->cinfo, COL_INFO)) {
    if(new_tvb) {
      col_append_str (pinfo->cinfo, COL_INFO, " (Message Reassembled)");
    } else {
      if(last) {
        col_append_str (pinfo->cinfo, COL_INFO, " (Message Reassembly failure)");
      } else {
        col_append_fstr (pinfo->cinfo, COL_INFO, " (Message fragment %u)", findex);
      }
    }
    if(first)
      col_append_str (pinfo->cinfo, COL_INFO, " (first)");
    if(last)
      col_append_str (pinfo->cinfo, COL_INFO, " (last)");
  }
  return new_tvb;
}
Exemplo n.º 3
0
/*
 * Dissect a standard (reliable) ts2 packet, reassembling if required.
 */
static void ts2_standard_dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ts2_tree, ts2_conversation *conversation_data)
{
    guint8 save_fragmented;
    tvbuff_t *new_tvb, *next_tvb;
    fragment_data *frag_msg ;
    guint16 fragment_number;
    ts2_frag *frag;
    gboolean outoforder;

    guint16 type = tvb_get_letohs(tvb, 2);
    /*guint16 class = tvb_get_letohs(tvb, 0);*/
    proto_tree_add_item(ts2_tree, hf_ts2_seqnum, tvb, 12, 4, TRUE);

    /* XXX: Following fragmentation stuff should be separate from the GUI stuff ??    */
    /* Get our stored fragmentation data or create one! */
    if ( ! ( frag = p_get_proto_data(pinfo->fd, proto_ts2) ) ) {
        frag = se_alloc(sizeof(ts2_frag));
        frag->frag_num=0;
    }

    /* decide if the packet is server to client or client to server
     * then check its fragmentation
     */
    if(!(pinfo->fd->flags.visited))
    {
        if(conversation_data->server_port == pinfo->srcport)
        {
            frag->fragmented = ts2_standard_find_fragments(tvb, &conversation_data->last_inorder_server_frame, &conversation_data->server_frag_size, &conversation_data->server_frag_num, &outoforder);
            frag->frag_num=conversation_data->server_frag_num;
            frag->frag_size=conversation_data->server_frag_size;
        }
        else
        {

            frag->fragmented = ts2_standard_find_fragments(tvb, &conversation_data->last_inorder_client_frame, &conversation_data->client_frag_size, &conversation_data->client_frag_num, &outoforder);
            frag->frag_num=conversation_data->client_frag_num;
            frag->frag_size=conversation_data->client_frag_size;
        }
        frag->outoforder=outoforder;
        p_add_proto_data(pinfo->fd, proto_ts2, frag);
    }

    /* Get our stored fragmentation data */
    frag = p_get_proto_data(pinfo->fd, proto_ts2);

    proto_tree_add_item(ts2_tree, hf_ts2_resend_count, tvb, 16, 2, TRUE);
    proto_tree_add_item(ts2_tree, hf_ts2_fragmentnumber, tvb, 18, 2, TRUE);
    ts2_add_checked_crc32(ts2_tree, hf_ts2_crc32, tvb, 20, tvb_get_letohl(tvb, 20));

    /* Reassemble the packet if its fragmented */
    new_tvb = NULL;
    if(frag->fragmented)
    {
        save_fragmented = pinfo->fragmented;
        frag_msg = NULL;
        pinfo->fragmented = TRUE;
        fragment_number = tvb_get_letohs(tvb, 18);
        frag_msg = fragment_add_seq_check(tvb, 24, pinfo, type,	msg_fragment_table, msg_reassembled_table, frag->frag_num, tvb_length_remaining(tvb, 24), fragment_number);
        new_tvb = process_reassembled_data(tvb, 24, pinfo,"Reassembled Message", frag_msg, &msg_frag_items, NULL, ts2_tree);
        if (frag_msg)
        {   /* Reassembled */
            if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, " (Message Reassembled)");
        }
        else
        {   /* Not last packet of reassembled Short Message */
            if (check_col(pinfo->cinfo, COL_INFO))col_append_fstr(pinfo->cinfo, COL_INFO," (Message fragment %u)", frag->frag_num);
        }
        if (new_tvb)
            next_tvb = new_tvb;
        else
            next_tvb = tvb_new_subset_remaining(tvb, 24);
        pinfo->fragmented = save_fragmented;
    }
    else
        next_tvb = tvb_new_subset_remaining(tvb, 24);

    /* If we have a full packet now dissect it */
    if((new_tvb || !frag->fragmented) && !frag->outoforder)
    {
        switch(type)
        {
        case TS2T_LOGINPART2:
            ts2_parse_loginpart2(next_tvb, ts2_tree);
            break;
        case TS2T_CHANNELLIST:
            ts2_parse_channellist(next_tvb, ts2_tree);
            break;
        case TS2T_PLAYERLIST:
            ts2_parse_playerlist(next_tvb, ts2_tree);
            break;
        case TS2T_NEWPLAYERJOINED:
            ts2_parse_newplayerjoined(next_tvb, ts2_tree);
            break;
        case TS2T_KNOWNPLAYERUPDATE:
            ts2_parse_knownplayerupdate(next_tvb, ts2_tree);
            break;
        case TS2T_PLAYERLEFT:
            ts2_parse_playerleft(next_tvb, ts2_tree);
            break;
        case TS2T_PLAYERKICKED:
            ts2_parse_playerleft(next_tvb, ts2_tree);
            break;
        case TS2T_LOGINEND:
            ts2_parse_loginend(next_tvb, ts2_tree);
            break;
        case TS2T_CHANGESTATUS:
            ts2_parse_changestatus(next_tvb, ts2_tree);
            break;
        case TS2T_SWITCHCHANNEL:
            ts2_parse_switchchannel(next_tvb, ts2_tree);
            break;
        case TS2T_CHANNELCHANGE:
            ts2_parse_channelchange(next_tvb, ts2_tree);
            break;
        }
    }
    /* The packet is out of order, update the cinfo and ignore the packet */
    if(frag->outoforder)
        if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, " (Out Of Order, ignored)");
}
/* Parse Short Message, only if UDH present
 * (otherwise this function is not called).
 * Call WSP dissector if port matches WSP traffic.
 */
static void
parse_gsm_sms_ud_message(proto_tree *sm_tree, tvbuff_t *tvb, packet_info *pinfo,
		proto_tree *top_tree)
{
	tvbuff_t *sm_tvb = NULL;
	proto_item *subtree, *tree;
	guint8 udh_len, udh, len;
	guint sm_len = tvb_reported_length (tvb);
	guint sm_data_len;
	guint32 i = 0;
	/* Multiple Messages UDH */
	gboolean is_fragmented = FALSE;
	fragment_data *fd_sm = NULL;
	guint16 sm_id = 0, frags = 0, frag = 0;
	gboolean save_fragmented = FALSE, try_gsm_sms_ud_reassemble = FALSE;
	/* SMS Message reassembly */
	gboolean reassembled = FALSE;
	guint32 reassembled_in = 0;
	/* Port Number UDH */
	guint16 p_src = 0, p_dst = 0;
	gboolean ports_available = FALSE;

	udh_len = tvb_get_guint8(tvb, i++);
	tree = proto_tree_add_uint(sm_tree, hf_gsm_sms_udh_length, tvb, 0, 1, udh_len);
	tree = proto_item_add_subtree(tree, ett_udh);
	while (i < udh_len) {
		udh = tvb_get_guint8(tvb, i++);
		len = tvb_get_guint8(tvb, i++);
		subtree = proto_tree_add_uint(tree, hf_gsm_sms_udh_iei,
				tvb, i-2, 2+len, udh);
		switch (udh) {
			case 0x00: /* Multiple messages - 8-bit message ID */
				if (len == 3) {
					sm_id = tvb_get_guint8(tvb, i++);
					frags = tvb_get_guint8(tvb, i++);
					frag  = tvb_get_guint8(tvb, i++);
					if (frags > 1)
						is_fragmented = TRUE;
					proto_item_append_text(subtree,
							": message %u, part %u of %u", sm_id, frag, frags);
					subtree = proto_item_add_subtree(subtree,
							ett_udh_ie);
					proto_tree_add_uint (subtree,
							hf_gsm_sms_udh_multiple_messages_msg_id,
							tvb, i-3, 1, sm_id);
					proto_tree_add_uint (subtree,
							hf_gsm_sms_udh_multiple_messages_msg_parts,
							tvb, i-2, 1, frags);
					proto_tree_add_uint (subtree,
							hf_gsm_sms_udh_multiple_messages_msg_part,
							tvb, i-1, 1, frag);
				} else {
					proto_item_append_text(subtree, " - Invalid format!");
					i += len;
				}
				break;

			case 0x08: /* Multiple messages - 16-bit message ID */
				if (len == 4) {
					sm_id = tvb_get_ntohs(tvb, i); i += 2;
					frags = tvb_get_guint8(tvb, i++);
					frag  = tvb_get_guint8(tvb, i++);
					if (frags > 1)
						is_fragmented = TRUE;
					proto_item_append_text(subtree,
							": message %u, part %u of %u", sm_id, frag, frags);
					subtree = proto_item_add_subtree(subtree,
							ett_udh_ie);
					proto_tree_add_uint (subtree,
							hf_gsm_sms_udh_multiple_messages_msg_id,
							tvb, i-4, 2, sm_id);
					proto_tree_add_uint (subtree,
							hf_gsm_sms_udh_multiple_messages_msg_parts,
							tvb, i-2, 1, frags);
					proto_tree_add_uint (subtree,
							hf_gsm_sms_udh_multiple_messages_msg_part,
							tvb, i-1, 1, frag);
				} else {
					proto_item_append_text(subtree, " - Invalid format!");
					i += len;
				}
				break;

			case 0x04: /* Port Number UDH - 8-bit address */
				if (len == 2) { /* Port fields */
					p_dst = tvb_get_guint8(tvb, i++);
					p_src = tvb_get_guint8(tvb, i++);
					proto_item_append_text(subtree,
							": source port %u, destination port %u",
							p_src, p_dst);
					subtree = proto_item_add_subtree(subtree, ett_udh_ie);
					proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_dst,
							tvb, i-2, 1, p_dst);
					proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_src,
							tvb, i-1, 1, p_src);
					ports_available = TRUE;
				} else {
					proto_item_append_text(subtree, " - Invalid format!");
					i += len;
				}
				break;

			case 0x05: /* Port Number UDH - 16-bit address */
				if (len == 4) { /* Port fields */
					p_dst = tvb_get_ntohs(tvb, i); i += 2;
					p_src = tvb_get_ntohs(tvb, i); i += 2;
					proto_item_append_text(subtree,
							": source port %u, destination port %u",
							p_src, p_dst);
					subtree = proto_item_add_subtree(subtree, ett_udh_ie);
					proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_dst,
							tvb, i-4, 2, p_dst);
					proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_src,
							tvb, i-2, 2, p_src);
					ports_available = TRUE;
				} else {
					proto_item_append_text(subtree, " - Invalid format!");
					i += len;
				}
				break;

			default:
				i += len;
				break;
		}
	}
	if (tvb_reported_length_remaining(tvb, i) <= 0)
		return; /* No more data */

	/*
	 * XXX - where does the "1" come from?  If it weren't there,
	 * "sm_data_len" would, I think, be the same as
	 * "tvb_reported_length_remaining(tvb, i)".
	 *
	 * I think that the above check ensures that "sm_len" won't
	 * be less than or equal to "udh_len", so it ensures that
	 * "sm_len" won't be less than "1 + udh_len", so we don't
	 * have to worry about "sm_data_len" being negative.
	 */
	sm_data_len = sm_len - (1 + udh_len);
	if (sm_data_len == 0)
		return;	/* no more data */

	/*
	 * Try reassembling the packets.
	 * XXX - fragment numbers are 1-origin, but the fragment number
	 * field could be 0.
	 * Should we flag a fragmented message with a fragment number field
	 * of 0?
	 * What if the fragment count is 0?  Should we flag that as well?
	 */
	if ( is_fragmented && frag != 0 && frags != 0 &&
	    tvb_bytes_exist (tvb, i, sm_data_len) ) {
		try_gsm_sms_ud_reassemble = TRUE;
		save_fragmented = pinfo->fragmented;
		pinfo->fragmented = TRUE;
		fd_sm = fragment_add_seq_check (tvb, i, pinfo,
				sm_id, /* guint32 ID for fragments belonging together */
				sm_fragment_table, /* list of message fragments */
				sm_reassembled_table, /* list of reassembled messages */
				frag-1, /* guint32 fragment sequence number */
				sm_data_len, /* guint32 fragment length */
				(frag != frags)); /* More fragments? */
		if (fd_sm) {
			reassembled = TRUE;
			reassembled_in = fd_sm->reassembled_in;
		}
		sm_tvb = process_reassembled_data(tvb, i, pinfo,
		    "Reassembled Short Message", fd_sm, &sm_frag_items,
		    NULL, sm_tree);
		if (reassembled) { /* Reassembled */
			col_append_str (pinfo->cinfo, COL_INFO,
						" (Short Message Reassembled)");
		} else {
			/* Not last packet of reassembled Short Message */
			col_append_fstr (pinfo->cinfo, COL_INFO,
					" (Short Message fragment %u of %u)", frag, frags);
		}
	} /* Else: not fragmented */

	if (! sm_tvb) /* One single Short Message, or not reassembled */
		sm_tvb = tvb_new_subset_remaining (tvb, i);
	/* Try calling a subdissector */
	if (sm_tvb) {
		if ((reassembled && pinfo->fd->num == reassembled_in)
			|| frag==0 || (frag==1 && try_dissect_1st_frag)) {
			/* Try calling a subdissector only if:
			 *  - the Short Message is reassembled in this very packet,
			 *  - the Short Message consists of only one "fragment",
			 *  - the preference "Always Try Dissection for 1st SM fragment"
			 *    is switched on, and this is the SM's 1st fragment. */
			if ( ports_available ) {
				gboolean disallow_write = FALSE; /* TRUE if we changed writability
								    of the columns of the summary */
				if ( prevent_subdissectors_changing_columns && col_get_writable(pinfo->cinfo) ) {
					disallow_write = TRUE;
					col_set_writable(pinfo->cinfo, FALSE);
				}				

				if ( port_number_udh_means_wsp ) {
					call_dissector (wsp_handle, sm_tvb, pinfo, top_tree);
				} else {
					if (! dissector_try_port(gsm_sms_dissector_table, p_src,
								sm_tvb, pinfo, top_tree)) {
						if (! dissector_try_port(gsm_sms_dissector_table, p_dst,
									sm_tvb, pinfo, top_tree)) {
							if (sm_tree) { /* Only display if needed */
								proto_tree_add_text (sm_tree, sm_tvb, 0, -1,
										"Short Message body");
							}
						}
					}
				}
				
				if ( disallow_write )
					col_set_writable(pinfo->cinfo, TRUE);
			} else { /* No ports IE */
				proto_tree_add_text (sm_tree, sm_tvb, 0, -1,
						"Short Message body");
			}
		} else {
			/* The packet is not reassembled,
			 * or it is reassembled in another packet */
			proto_tree_add_text (sm_tree, sm_tvb, 0, -1,
					"Unreassembled Short Message fragment %u of %u",
					frag, frags);
		}
	}

	if (try_gsm_sms_ud_reassemble) /* Clean up defragmentation */
		pinfo->fragmented = save_fragmented;
	return;
}
Exemplo n.º 5
0
static void
dissect_gsm_cell_broadcast(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
   guint8 sms_encoding, total_pages, current_page;
   guint32       offset = 0;
   guint         len, text_len;
   guint32       msg_key;
   proto_item    *cbs_page_item = NULL;
   proto_tree    *cbs_page_tree = NULL;
   guint16       serial_number, message_id;
   tvbuff_t      *cbs_page_tvb = NULL;
   tvbuff_t      *cbs_msg_tvb = NULL;
   fragment_head * frag_data = NULL;

   len = tvb_length(tvb);

   col_append_str(pinfo->cinfo, COL_PROTOCOL, " Cell Broadcast");
   col_append_str(pinfo->cinfo, COL_INFO, " (CBS Page)");

   cbs_page_item = proto_tree_add_protocol_format(proto_tree_get_root(tree), proto_cell_broadcast, tvb, 0, len, "GSM Cell Broadcast");
   cbs_page_tree = proto_item_add_subtree(cbs_page_item, ett_gsm_cbs_page);

   serial_number = tvb_get_ntohs(tvb, offset);
   offset = dissect_cbs_serial_number(tvb, cbs_page_tree, offset);
   message_id = tvb_get_ntohs(tvb, offset);
   offset = dissect_cbs_message_identifier(tvb, cbs_page_tree, offset);
   sms_encoding = dissect_cbs_data_coding_scheme(tvb, pinfo, cbs_page_tree, offset++);
   total_pages = tvb_get_guint8(tvb, offset);
   current_page = (total_pages & 0xF0) >> 4;
   total_pages &= 0x0F;
   proto_tree_add_item(cbs_page_tree, hf_gsm_cbs_current_page, tvb, offset, 1, ENC_BIG_ENDIAN);
   proto_tree_add_item(cbs_page_tree, hf_gsm_cbs_total_pages, tvb, offset++, 1, ENC_BIG_ENDIAN);
   cbs_page_tvb = dissect_cbs_data(sms_encoding, tvb, cbs_page_tree, pinfo, offset );

   if (cbs_page_tvb != NULL)
   {
      text_len = tvb_length(cbs_page_tvb);
      while (text_len && (tvb_get_guint8(cbs_page_tvb, text_len-1) == '\r')) {
         text_len--;
      }
      if (tree != NULL)
      {
         proto_tree *cbs_page_subtree = proto_tree_add_subtree(cbs_page_tree, tvb, offset, -1,
                                        ett_gsm_cbs_page_content, NULL, "Cell Broadcast Page Contents");
         len = tvb_length(cbs_page_tvb);
         proto_tree_add_string(cbs_page_subtree, hf_gsm_cbs_page_content, cbs_page_tvb, 0,
                               text_len, tvb_get_string_enc(wmem_packet_scope(), cbs_page_tvb, 0, text_len, ENC_ASCII));
         len -= text_len;
         if (len)
         {
            proto_tree_add_string(cbs_page_subtree, hf_gsm_cbs_page_content_padding, cbs_page_tvb, text_len, len,
                                  tvb_get_string_enc(wmem_packet_scope(), cbs_page_tvb, text_len, len, ENC_ASCII));
         }
      }
      if (text_len)
      {
         cbs_page_tvb = tvb_new_subset_length(cbs_page_tvb, 0, text_len);
         if (total_pages == 1)
         {
            /* no need for reassembly */
            cbs_msg_tvb = cbs_page_tvb;
         }
         else
         {
             /* now we have a complete page, try to concatenate the full message */
            /* we can use the serial number and message ID as keys, as they are the same for all pages of a message */
            msg_key = (serial_number << 16) + message_id;
            frag_data = fragment_add_seq_check(&gsm_cbs_reassembly_table,
                                               cbs_page_tvb, 0, pinfo, msg_key, NULL,
                                               (current_page -1), text_len,
                                               (current_page!=total_pages));
            cbs_msg_tvb = process_reassembled_data(cbs_page_tvb, 0, pinfo, "Reassembled Cell Broadcast message",
                                                frag_data, &gsm_page_items, NULL, cbs_page_tree);
         }
      }
   }
   if (cbs_msg_tvb != NULL)
   {
      proto_item     *cbs_msg_item = NULL;
      proto_tree    *cbs_msg_tree = NULL;

      len = tvb_length(cbs_msg_tvb);
      col_append_str(pinfo->cinfo, COL_INFO, " (CBS Message)");

      cbs_msg_item = proto_tree_add_protocol_format(proto_tree_get_root(tree), proto_cell_broadcast, cbs_msg_tvb, 0, len, "GSM Cell Broadcast Message");
      cbs_msg_tree = proto_item_add_subtree(cbs_msg_item, ett_cbs_msg);

      proto_tree_add_string(cbs_msg_tree, hf_gsm_cbs_message_content, cbs_msg_tvb, 0, len, tvb_get_string_enc(wmem_packet_scope(), cbs_msg_tvb, 0, len, ENC_ASCII));
   }
}
Exemplo n.º 6
0
static gint
dissect_hci_usb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
    proto_item     *ttree = NULL;
    proto_tree     *titem = NULL;
    proto_item     *pitem = NULL;
    gint            offset = 0;
    usb_conv_info_t *usb_conv_info = (usb_conv_info_t *)data;
    tvbuff_t       *next_tvb = NULL;
    hci_data_t     *hci_data;
    gint            p2p_dir_save;
    guint32         session_id;
    fragment_head  *reassembled;

    if (tvb_length_remaining(tvb, offset) <= 0)
        return 0;

    titem = proto_tree_add_item(tree, proto_hci_usb, tvb, offset, -1, ENC_NA);
    ttree = proto_item_add_subtree(titem, ett_hci_usb);

    col_set_str(pinfo->cinfo, COL_PROTOCOL, "HCI_USB");

    DISSECTOR_ASSERT(usb_conv_info);

    p2p_dir_save = pinfo->p2p_dir;
    pinfo->p2p_dir = usb_conv_info->direction;

    switch (pinfo->p2p_dir) {

    case P2P_DIR_SENT:
        col_set_str(pinfo->cinfo, COL_INFO, "Sent");
        break;

    case P2P_DIR_RECV:
        col_set_str(pinfo->cinfo, COL_INFO, "Rcvd");
        break;

    default:
        col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction");
        break;
    }

    session_id = usb_conv_info->bus_id << 16 | usb_conv_info->device_address << 8 | ((pinfo->p2p_dir == P2P_DIR_RECV) ? 1 : 0 ) << 7 | usb_conv_info->endpoint;

    hci_data = (hci_data_t *) wmem_new(wmem_packet_scope(), hci_data_t);
    hci_data->interface_id = HCI_INTERFACE_USB;
    hci_data->adapter_id = usb_conv_info->bus_id << 8 | usb_conv_info->device_address;
    hci_data->chandle_to_bdaddr_table = chandle_to_bdaddr_table;
    hci_data->bdaddr_to_name_table = bdaddr_to_name_table;
    hci_data->localhost_bdaddr = localhost_bdaddr;
    hci_data->localhost_name = localhost_name;

    pinfo->ptype = PT_BLUETOOTH;

    next_tvb = tvb_new_subset_remaining(tvb, offset);
    if (!pinfo->fd->flags.visited && usb_conv_info->endpoint <= 0x02) {
        fragment_info_t  *fragment_info;

        fragment_info = (fragment_info_t *) wmem_tree_lookup32(fragment_info_table, session_id);
        if (fragment_info == NULL) {
            fragment_info = (fragment_info_t *) wmem_new(wmem_file_scope(), fragment_info_t);
            fragment_info->fragment_id = 0;
            fragment_info->remaining_length = 0;

            wmem_tree_insert32(fragment_info_table, session_id, fragment_info);
        }

        if (fragment_info->fragment_id == 0) {
            switch(usb_conv_info->endpoint)
            {
            case 0:
                fragment_info->remaining_length = tvb_get_guint8(tvb, offset + 2) + 3;
                break;
            case 1:
                fragment_info->remaining_length = tvb_get_guint8(tvb, offset + 1) + 2;
                break;
            case 2:
                fragment_info->remaining_length = tvb_get_letohs(tvb, offset + 2) + 4;
                break;
            }
        }

        fragment_info->remaining_length -= tvb_ensure_length_remaining(tvb, offset);

        fragment_add_seq_check(&hci_usb_reassembly_table,
                               tvb, offset, pinfo, session_id, NULL,
                               fragment_info->fragment_id, tvb_length_remaining(tvb, offset), (fragment_info->remaining_length == 0) ? FALSE : TRUE);
        if (fragment_info->remaining_length > 0)
            fragment_info->fragment_id += 1;
        else
            fragment_info->fragment_id = 0;
    }

    reassembled = fragment_get_reassembled_id(&hci_usb_reassembly_table, pinfo, session_id);
    if (reassembled && pinfo->fd->num < reassembled->reassembled_in) {
        pitem = proto_tree_add_item(ttree, hf_bthci_usb_packet_fragment, tvb, offset, -1, ENC_NA);
        PROTO_ITEM_SET_GENERATED(pitem);

        col_append_str(pinfo->cinfo, COL_INFO, " Fragment");
    } else if (reassembled && pinfo->fd->num == reassembled->reassembled_in) {
        pitem = proto_tree_add_item(ttree, hf_bthci_usb_packet_complete, tvb, offset, -1, ENC_NA);
        PROTO_ITEM_SET_GENERATED(pitem);

        if (reassembled->len > tvb_ensure_length_remaining(tvb, offset)) {
            next_tvb = process_reassembled_data(tvb, 0, pinfo,
                    "Reassembled HCI_USB",
                    reassembled, &hci_usb_msg_frag_items,
                    NULL, ttree);
        }

        switch(usb_conv_info->endpoint)
        {
        case 0:
            call_dissector_with_data(bthci_cmd_handle, next_tvb, pinfo, tree, hci_data);
            break;
        case 1:
            call_dissector_with_data(bthci_evt_handle, next_tvb, pinfo, tree, hci_data);
            break;
        case 2:
            call_dissector_with_data(bthci_acl_handle, next_tvb, pinfo, tree, hci_data);
            break;
        }
    } else {
        pitem = proto_tree_add_item(ttree, hf_bthci_usb_packet_unknown_fragment, tvb, offset, -1, ENC_NA);
        PROTO_ITEM_SET_GENERATED(pitem);
    }

    if (usb_conv_info->endpoint == 0x03) {
        call_dissector_with_data(bthci_sco_handle, next_tvb, pinfo, tree, hci_data);
    } else if (usb_conv_info->endpoint > 0x03) {
        proto_tree_add_item(ttree, hf_bthci_usb_data, tvb, offset, -1, ENC_NA);
    }

    offset += tvb_length_remaining(tvb, offset);

    pinfo->p2p_dir = p2p_dir_save;

    return offset;
}
Exemplo n.º 7
0
static tvbuff_t *
dissect_pft_fec_detailed(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
  guint32 findex,
  guint32 fcount,
  guint16 seq,
  gint offset,
  guint16 plen,
  gboolean fec _U_,
  guint16 rsk,
  guint16 rsz,
  fragment_data *fdx
)
{
  guint16 decoded_size;
  guint32 c_max;
  guint32 rx_min;
  gboolean first, last;
  tvbuff_t *new_tvb=NULL;

  if (fcount > MAX_FRAGMENTS) {
    if (tree)
      proto_tree_add_text(tree, tvb , 0, -1, "[Reassembly of %d fragments not attempted]", fcount);
    return NULL;
  }

  first = findex == 0;
  last = fcount == (findex+1);
  decoded_size = fcount*plen;
  c_max = fcount*plen/(rsk+PFT_RS_P);  /* rounded down */
  rx_min = c_max*rsk/plen;
  if(rx_min*plen<c_max*rsk)
    rx_min++;
  if (fdx)
    new_tvb = process_reassembled_data (tvb, offset, pinfo,
                                        "Reassembled DCP (ETSI)",
                                        fdx, &dcp_frag_items,
                                        NULL, tree);
  else {
    guint fragments=0;
    guint32 *got;
    fragment_data *fd;
    fragment_data *fd_head;

    if(tree)
      proto_tree_add_text (tree, tvb, 0, -1, "want %d, got %d need %d",
                           fcount, fragments, rx_min
        );
    got = ep_alloc(fcount*sizeof(guint32));

    /* make a list of the findex (offset) numbers of the fragments we have */
    fd = fragment_get(pinfo, seq, dcp_fragment_table);
    for (fd_head = fd; fd_head != NULL; fd_head = fd_head->next) {
      if(fd_head->data) {
        got[fragments++] = fd_head->offset; /* this is the findex of the fragment */
      }
    }
    /* put a sentinel at the end */
    got[fragments++] = fcount;
    /* have we got enough for Reed Solomon to try to correct ? */
    if(fragments>=rx_min) { /* yes, in theory */
      guint i,current_findex;
      fragment_data *frag=NULL;
      guint8 *dummy_data = (guint8*) ep_alloc0 (plen);
      tvbuff_t *dummytvb = tvb_new_real_data(dummy_data, plen, plen);
      /* try and decode with missing fragments */
      if(tree)
          proto_tree_add_text (tree, tvb, 0, -1, "want %d, got %d need %d",
                               fcount, fragments, rx_min
            );
      /* fill the fragment table with empty fragments */
      current_findex = 0;
      for(i=0; i<fragments; i++) {
        guint next_fragment_we_have = got[i];
        if (next_fragment_we_have > MAX_FRAGMENTS) {
          if (tree)
            proto_tree_add_text(tree, tvb , 0, -1, "[Reassembly of %d fragments not attempted]", next_fragment_we_have);
          return NULL;
        }
        for(; current_findex<next_fragment_we_have; current_findex++) {
          frag = fragment_add_seq_check (dummytvb, 0, pinfo, seq,
                                         dcp_fragment_table, dcp_reassembled_table, 
                                         current_findex, plen, (current_findex+1!=fcount));
        }
        current_findex++; /* skip over the fragment we have */
      }
      if(frag)
        new_tvb = process_reassembled_data (tvb, offset, pinfo,
                                            "Reassembled DCP (ETSI)",
                                            frag, &dcp_frag_items,
                                            NULL, tree);
    }
  }
  if(new_tvb) {
    gboolean decoded = TRUE;
    tvbuff_t *dtvb = NULL;
    const guint8 *input = tvb_get_ptr(new_tvb, 0, -1);
    guint16 reassembled_size = tvb_length(new_tvb);
    guint8 *deinterleaved = (guint8*) g_malloc (reassembled_size);
    guint8 *output = (guint8*) g_malloc (decoded_size);
    rs_deinterleave(input, deinterleaved, plen, fcount);

    dtvb = tvb_new_child_real_data(tvb, deinterleaved, reassembled_size, reassembled_size);
    add_new_data_source(pinfo, dtvb, "Deinterleaved");
    tvb_set_free_cb(dtvb, g_free);

    decoded = rs_correct_data(deinterleaved, output, c_max, rsk, rsz);
    if(tree)
      proto_tree_add_boolean (tree, hf_edcp_rs_ok, tvb, offset, 2, decoded);

    new_tvb = tvb_new_child_real_data(dtvb, output, decoded_size, decoded_size);
    add_new_data_source(pinfo, new_tvb, "RS Error Corrected Data");
    tvb_set_free_cb(new_tvb, g_free);
  }
  return new_tvb;
}
Exemplo n.º 8
0
static void
dissect_wai(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
/* Format of WAPI protocol packet in WAI authentication system

0      2      3         4         6         8        10        11      12
-------------------------------------------------------------------------------
| Ver. | Type | Subtype | Reserved | Length | packet  |  fragm. | flag | data |
|                                           | seq. no | seq. no |             |
|-----------------------------------------------------------------------------|
Figure 18 from [ref:1]
*/
#define WAI_MESSAGE_LENGTH 12   /*Length of all fields without 'Data' field*/
#define WAI_DATA_OFFSET    WAI_MESSAGE_LENGTH
    guint16        version;
    guint8         subtype;
    guint16        length;
    guint16        packet_num;
    guint8         fragment_num;
    guint8         flags;
    fragment_head *frag_msg;
    proto_tree    *wai_tree     = NULL;
    tvbuff_t      *next_tvb;
    tvbuff_t      *new_tvb;
    const gchar   *subtype_name = "Unknown type";

    length = tvb_get_ntohs(tvb, 6)-WAI_MESSAGE_LENGTH;
    subtype = tvb_get_guint8(tvb, 3);

    /* quick sanity check */
    if ((length != tvb_reported_length (tvb)-WAI_MESSAGE_LENGTH) ||
        (subtype > WAI_SUB_MULTICAST_ANNOUNCE_RESP)) {
        return;
    }

    col_set_str(pinfo->cinfo, COL_PROTOCOL, "WAI");
    col_clear(pinfo->cinfo, COL_INFO);
    version = tvb_get_ntohs(tvb, 0);

    if (version == 1) {
        subtype_name = val_to_str_ext_const(subtype, &wai_subtype_names_ext, "Unknown type");
    }
    col_append_fstr(pinfo->cinfo, COL_INFO, "%s", subtype_name);

    /* Field lengths and offsets in WAI protocol described above */
    packet_num   = tvb_get_ntohs(tvb, 8);
    fragment_num = tvb_get_guint8(tvb, 10);
    flags        = tvb_get_guint8(tvb, 11);

    if (tree) {
        proto_item *wai_item;

        wai_item = proto_tree_add_item(tree, proto_wai, tvb, 0, -1, ENC_NA);

        proto_item_set_text (wai_item, "WAI Protocol (%s)",
                                val_to_str_ext_const(subtype, &wai_subtype_names_ext, "Unknown type"));
        wai_tree = proto_item_add_subtree(wai_item, ett_wai);

        /* Field lengths and offsets in WAI protocol described above */
        proto_tree_add_item(wai_tree, hf_wai_version,   tvb, 0,  2, ENC_BIG_ENDIAN);
        proto_tree_add_item(wai_tree, hf_wai_type,      tvb, 2,  1, ENC_BIG_ENDIAN);
        proto_tree_add_item(wai_tree, hf_wai_subtype,   tvb, 3,  1, ENC_BIG_ENDIAN);
        proto_tree_add_item(wai_tree, hf_wai_reserved,  tvb, 4,  2, ENC_BIG_ENDIAN);
        proto_tree_add_item(wai_tree, hf_wai_length,    tvb, 6,  2, ENC_BIG_ENDIAN);
        proto_tree_add_item(wai_tree, hf_wai_seq,       tvb, 8,  2, ENC_BIG_ENDIAN);
        proto_tree_add_item(wai_tree, hf_wai_fragm_seq, tvb, 10, 1, ENC_BIG_ENDIAN);
        proto_tree_add_item(wai_tree, hf_wai_flag,      tvb, 11, 1, ENC_BIG_ENDIAN);
    }

    frag_msg =  fragment_add_seq_check (&wai_reassembly_table,
                                        tvb, WAI_DATA_OFFSET,
                                        pinfo,
                                        packet_num,
                                        NULL,
                                        fragment_num,
                                        length,
                                        flags);

    next_tvb = tvb_new_subset_remaining(tvb, WAI_DATA_OFFSET);

    /* Replace INFO column if message is fragmented and call data_handle */
    if (flags) {
        col_add_fstr(pinfo->cinfo, COL_INFO,
                     "Fragment (%d) of message, data not dissected", fragment_num);

        process_reassembled_data(tvb, WAI_DATA_OFFSET, pinfo,
                                 "Reassembled WAI", frag_msg, &wai_frag_items,
                                 NULL, wai_tree);

        call_dissector(data_handle, next_tvb, pinfo, tree);
    } else {
        /* If this is the last fragment of fragmented message, then reassamble and dissect
           otherwise only dissect */
        if (fragment_num > 0) {
            new_tvb = process_reassembled_data(tvb, WAI_DATA_OFFSET, pinfo,
                                               "Reassembled WAI", frag_msg, &wai_frag_items,
                                               NULL, wai_tree);

            if (new_tvb) {
                col_set_str(pinfo->cinfo, COL_INFO, "Last fragment of message, data dissected");
                col_append_sep_str(pinfo->cinfo, COL_INFO, ": ", subtype_name);
                next_tvb=new_tvb;
                length = tvb_reported_length (next_tvb);
            }
        }
        /* dissect Data field of WAI packet */
        if (tree) {
            dissect_wai_data(next_tvb, wai_tree, subtype, length);
        }
    }

}
Exemplo n.º 9
0
/* Code to actually dissect the packets
*/
static void
dissect_sndcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
  guint8         addr_field, comp_field, npdu_field1, nsapi, dcomp=0, pcomp=0;
  guint16        offset=0, npdu=0, segment=0, npdu_field2;
  tvbuff_t      *next_tvb, *npdu_tvb;
  gint           len;
  gboolean       first, more_frags, unack;

  /* Set up structures needed to add the protocol subtree and manage it
   */
  proto_item *ti, *address_field_item, *compression_field_item, *npdu_field_item;
  proto_tree *sndcp_tree = NULL, *address_field_tree, *compression_field_tree, *npdu_field_tree;

  /* Make entries in Protocol column and clear Info column on summary display
   */
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "SNDCP");
  col_clear(pinfo->cinfo, COL_INFO);

  /* create display subtree for the protocol
   */
  if (tree) {
    ti         = proto_tree_add_item(tree, proto_sndcp, tvb, 0, -1, FALSE);
    sndcp_tree = proto_item_add_subtree(ti, ett_sndcp);
  }

  /* get address field from next byte
   */
  addr_field = tvb_get_guint8(tvb,offset);
  nsapi      = addr_field & 0xF;
  first      = addr_field & MASK_F;
  more_frags = addr_field & MASK_M;
  unack      = addr_field & MASK_T;

  /* add subtree for the address field
   */
  if (tree) {
    address_field_item = proto_tree_add_uint_format(sndcp_tree,hf_sndcp_nsapi,
                                                    tvb, offset,1, nsapi,
                                                    "Address field  NSAPI: %d", nsapi );
    address_field_tree = proto_item_add_subtree(address_field_item, ett_sndcp_address_field);
    proto_tree_add_boolean(address_field_tree, hf_sndcp_x, tvb,offset,1, addr_field );
    proto_tree_add_boolean(address_field_tree, hf_sndcp_f, tvb,offset,1, addr_field );
    proto_tree_add_boolean(address_field_tree, hf_sndcp_t, tvb,offset,1, addr_field );
    proto_tree_add_boolean(address_field_tree, hf_sndcp_m, tvb,offset,1, addr_field );
    proto_tree_add_uint(address_field_tree, hf_sndcp_nsapib, tvb, offset, 1, addr_field );
  }
  offset++;

  /* get compression pointers from next byte if this is the first segment
   */
  if (first) {
    comp_field = tvb_get_guint8(tvb,offset);
    dcomp      = comp_field & 0xF0;
    pcomp      = comp_field & 0x0F;

    /* add subtree for the compression field
     */
    if (tree) {
      if (!pcomp) {
        if (!dcomp) {
          compression_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "No compression");
        }
        else {
          compression_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "Data compression");
        }
      }
      else {
        if (!dcomp) {
          compression_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "Protocol compression");
        }
        else {
          compression_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "Data and Protocol compression");
        }
      }
      compression_field_tree = proto_item_add_subtree(compression_field_item, ett_sndcp_compression_field);
      proto_tree_add_uint(compression_field_tree, hf_sndcp_dcomp, tvb, offset, 1, comp_field );
      proto_tree_add_uint(compression_field_tree, hf_sndcp_pcomp, tvb, offset, 1, comp_field );
    }
    offset++;

    /* get N-PDU number from next byte for acknowledged mode (only for first segment)
     */
    if (!unack) {
      npdu = npdu_field1 = tvb_get_guint8(tvb,offset);
      if (check_col(pinfo->cinfo, COL_INFO))
        col_add_fstr(pinfo->cinfo, COL_INFO, "SN-DATA N-PDU %d", npdu_field1);
      if (tree) {
        npdu_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "Acknowledged mode, N-PDU %d", npdu_field1 );
        npdu_field_tree = proto_item_add_subtree(npdu_field_item, ett_sndcp_npdu_field);
        proto_tree_add_uint(npdu_field_tree, hf_sndcp_npdu1, tvb, offset, 1, npdu_field1 );
      }
      offset++;
    }
  }

  /* get segment and N-PDU number from next two bytes for unacknowledged mode
   */
  if (unack) {
    npdu_field2     = tvb_get_ntohs(tvb, offset);
    segment         = (npdu_field2 & 0xF000) >> 12;
    npdu            = (npdu_field2 & 0x0FFF);
    if (check_col(pinfo->cinfo, COL_INFO))
      col_add_fstr(pinfo->cinfo, COL_INFO, "SN-UNITDATA N-PDU %d (segment %d)", npdu, segment);
    if (tree) {
      npdu_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,2, "Unacknowledged mode, N-PDU %d (segment %d)", npdu, segment );
      npdu_field_tree = proto_item_add_subtree(npdu_field_item, ett_sndcp_npdu_field);
      proto_tree_add_uint(npdu_field_tree, hf_sndcp_segment, tvb, offset, 2, npdu_field2 );
      proto_tree_add_uint(npdu_field_tree, hf_sndcp_npdu2, tvb, offset, 2, npdu_field2 );
    }
    offset         += 2;
  }

  /* handle N-PDU data, reassemble if necessary
   */
  if (first && !more_frags) {
    next_tvb = tvb_new_subset_remaining (tvb, offset);

    if (!dcomp && !pcomp) {
      call_dissector(ip_handle, next_tvb, pinfo, tree);
    }
    else {
      call_dissector(data_handle, next_tvb, pinfo, tree);
    }
  }
  else {
    /* Try reassembling fragments
     */
    fragment_data  *fd_npdu         = NULL;
    guint32         reassembled_in  = 0;
    gboolean        save_fragmented = pinfo->fragmented;

    len = tvb_length_remaining(tvb, offset);
    if(len<=0){
        return;
    }

    pinfo->fragmented = TRUE;

    if (unack)
      fd_npdu  = fragment_add_seq_check(tvb, offset, pinfo, npdu,
                                        npdu_fragment_table, sndcp_reassembled_table, segment, len, more_frags);
    else
      fd_npdu  = fragment_add(tvb, offset, pinfo, npdu,
                              npdu_fragment_table, offset, len, more_frags);

    npdu_tvb = process_reassembled_data(tvb, offset, pinfo,
                                        "Reassembled N-PDU", fd_npdu, &npdu_frag_items,
                                        NULL, sndcp_tree);
    if (fd_npdu) {
      /* Reassembled
       */
      reassembled_in = fd_npdu->reassembled_in;
      if (pinfo->fd->num == reassembled_in) {
        /* Reassembled in this very packet:
         * We can safely hand the tvb to the IP dissector
         */
        call_dissector(ip_handle, npdu_tvb, pinfo, tree);
      }
      else {
        /* Not reassembled in this packet
         */
        if (check_col(pinfo->cinfo, COL_INFO)) {
          col_append_fstr(pinfo->cinfo, COL_INFO,
                          " (N-PDU payload reassembled in packet %u)",
                          fd_npdu->reassembled_in);
        }
        if (tree) {
          proto_tree_add_text(sndcp_tree, tvb, offset, -1, "Payload");
        }
      }
    } else {
      /* Not reassembled yet, or not reassembled at all
       */
      if (check_col(pinfo->cinfo, COL_INFO)) {
        if (unack)
          col_append_fstr(pinfo->cinfo, COL_INFO, " (Unreassembled fragment %u)", segment);
        else
          col_append_str(pinfo->cinfo, COL_INFO, " (Unreassembled fragment)");
      }
      if (tree) {
        proto_tree_add_text(sndcp_tree, tvb, offset, -1, "Payload");
      }
    }
    /* Now reset fragmentation information in pinfo
     */
    pinfo->fragmented = save_fragmented;
  }
}
Exemplo n.º 10
0
static gint
dissect_hci_usb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
    proto_item        *ttree = NULL;
    proto_tree        *titem = NULL;
    proto_item        *pitem = NULL;
    gint               offset = 0;
    usb_conv_info_t   *usb_conv_info;
    tvbuff_t          *next_tvb = NULL;
    bluetooth_data_t  *bluetooth_data;
    gint               p2p_dir_save;
    guint32            session_id;
    fragment_head     *reassembled;

    bluetooth_data = (bluetooth_data_t *) data;

    /* Reject the packet if data is NULL */
    if (data == NULL)
        return 0;

    DISSECTOR_ASSERT(bluetooth_data->previous_protocol_data_type == BT_PD_USB_CONV_INFO);
    usb_conv_info = bluetooth_data->previous_protocol_data.usb_conv_info;

    titem = proto_tree_add_item(tree, proto_hci_usb, tvb, offset, -1, ENC_NA);
    ttree = proto_item_add_subtree(titem, ett_hci_usb);

    col_set_str(pinfo->cinfo, COL_PROTOCOL, "HCI_USB");

    p2p_dir_save = pinfo->p2p_dir;
    pinfo->p2p_dir = (usb_conv_info->is_request) ? P2P_DIR_SENT : P2P_DIR_RECV;

    switch (pinfo->p2p_dir) {

    case P2P_DIR_SENT:
        col_set_str(pinfo->cinfo, COL_INFO, "Sent");
        break;

    case P2P_DIR_RECV:
        col_set_str(pinfo->cinfo, COL_INFO, "Rcvd");
        break;

    default:
        col_set_str(pinfo->cinfo, COL_INFO, "UnknownDirection");
        break;
    }

    if (usb_conv_info->is_setup) {
        proto_tree_add_item(ttree, hf_bthci_usb_setup_request, tvb, offset, 1, ENC_LITTLE_ENDIAN);
        offset += 1;

        proto_tree_add_item(ttree, hf_bthci_usb_setup_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
        offset += 2;

        proto_tree_add_item(ttree, hf_bthci_usb_setup_adapter_id, tvb, offset, 2, ENC_LITTLE_ENDIAN);
        offset += 2;

        proto_tree_add_item(ttree, hf_bthci_usb_setup_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
        offset += 2;
    }

    session_id = usb_conv_info->bus_id << 16 | usb_conv_info->device_address << 8 | ((pinfo->p2p_dir == P2P_DIR_RECV) ? 1 : 0 ) << 7 | usb_conv_info->endpoint;

    bluetooth_data->adapter_id = usb_conv_info->bus_id << 8 | usb_conv_info->device_address;
/* TODO: adapter disconnect on some USB action, for now do not support adapter disconnection */
    bluetooth_data->adapter_disconnect_in_frame = &max_disconnect_in_frame;

    next_tvb = tvb_new_subset_remaining(tvb, offset);
    if (!pinfo->fd->flags.visited && usb_conv_info->endpoint <= 0x02 &&
            tvb_captured_length(tvb) == tvb_reported_length(tvb)) {
        fragment_info_t  *fragment_info;

        fragment_info = (fragment_info_t *) wmem_tree_lookup32(fragment_info_table, session_id);
        if (fragment_info == NULL) {
            fragment_info = (fragment_info_t *) wmem_new(wmem_file_scope(), fragment_info_t);
            fragment_info->fragment_id = 0;
            fragment_info->remaining_length = 0;

            wmem_tree_insert32(fragment_info_table, session_id, fragment_info);
        }

        if (fragment_info->fragment_id == 0) {
            switch(usb_conv_info->endpoint)
            {
            case 0:
                fragment_info->remaining_length = tvb_get_guint8(tvb, offset + 2) + 3;
                break;
            case 1:
                fragment_info->remaining_length = tvb_get_guint8(tvb, offset + 1) + 2;
                break;
            case 2:
                fragment_info->remaining_length = tvb_get_letohs(tvb, offset + 2) + 4;
                break;
            }
        }

        fragment_info->remaining_length -= tvb_reported_length_remaining(tvb, offset);

        fragment_add_seq_check(&hci_usb_reassembly_table,
                               tvb, offset, pinfo, session_id, NULL,
                               fragment_info->fragment_id, tvb_reported_length_remaining(tvb, offset), (fragment_info->remaining_length == 0) ? FALSE : TRUE);
        if (fragment_info->remaining_length > 0)
            fragment_info->fragment_id += 1;
        else
            fragment_info->fragment_id = 0;
    }

    reassembled = fragment_get_reassembled_id(&hci_usb_reassembly_table, pinfo, session_id);
    if (reassembled && pinfo->num < reassembled->reassembled_in) {
        pitem = proto_tree_add_item(ttree, hf_bthci_usb_packet_fragment, tvb, offset, -1, ENC_NA);
        PROTO_ITEM_SET_GENERATED(pitem);

        col_append_str(pinfo->cinfo, COL_INFO, " Fragment");
    } else if (reassembled && pinfo->num == reassembled->reassembled_in) {
        pitem = proto_tree_add_item(ttree, hf_bthci_usb_packet_complete, tvb, offset, -1, ENC_NA);
        PROTO_ITEM_SET_GENERATED(pitem);

        if (reassembled->len > (guint) tvb_reported_length_remaining(tvb, offset)) {
            next_tvb = process_reassembled_data(tvb, 0, pinfo,
                    "Reassembled HCI_USB",
                    reassembled, &hci_usb_msg_frag_items,
                    NULL, ttree);
        }

        switch(usb_conv_info->endpoint)
        {
        case 0:
            call_dissector_with_data(bthci_cmd_handle, next_tvb, pinfo, tree, bluetooth_data);
            break;
        case 1:
            call_dissector_with_data(bthci_evt_handle, next_tvb, pinfo, tree, bluetooth_data);
            break;
        case 2:
            call_dissector_with_data(bthci_acl_handle, next_tvb, pinfo, tree, bluetooth_data);
            break;
        }
    } else {
        pitem = proto_tree_add_item(ttree, hf_bthci_usb_packet_unknown_fragment, tvb, offset, -1, ENC_NA);
        PROTO_ITEM_SET_GENERATED(pitem);
    }

    if (usb_conv_info->endpoint == 0x03) {
        call_dissector_with_data(bthci_sco_handle, next_tvb, pinfo, tree, bluetooth_data);
    } else if (usb_conv_info->endpoint > 0x03) {
        proto_tree_add_item(ttree, hf_bthci_usb_data, tvb, offset, -1, ENC_NA);
    }

    offset += tvb_reported_length_remaining(tvb, offset);

    pinfo->p2p_dir = p2p_dir_save;

    return offset;
}