static fragment_head * force_reassemble_seq(reassembly_table *table, packet_info *pinfo, guint32 id) { fragment_head *fd_head; fragment_item *fd_i; fragment_item *last_fd; guint32 dfpos, size, packet_lost, burst_lost, seq_num; guint8 *data; fd_head = fragment_get(table, pinfo, id, NULL); /* have we already seen this frame ?*/ if (pinfo->fd->flags.visited) { if (fd_head != NULL && fd_head->flags & FD_DEFRAGMENTED) { return fd_head; } else { return NULL; } } if (fd_head==NULL){ /* we must have it to continue */ return NULL; } /* check for packet lost and count the burst of packet lost */ packet_lost = 0; burst_lost = 0; seq_num = 0; for(fd_i=fd_head->next;fd_i;fd_i=fd_i->next) { if (seq_num != fd_i->offset) { packet_lost += fd_i->offset - seq_num; if ( (fd_i->offset - seq_num) > burst_lost ) { burst_lost = fd_i->offset - seq_num; } } seq_num = fd_i->offset + 1; } /* we have received an entire packet, defragment it and * free all fragments */ size=0; last_fd=NULL; for(fd_i=fd_head->next;fd_i;fd_i=fd_i->next) { if(!last_fd || last_fd->offset!=fd_i->offset){ size+=fd_i->len; } last_fd=fd_i; } data = (guint8 *) g_malloc(size); fd_head->tvb_data = tvb_new_real_data(data, size, size); fd_head->len = size; /* record size for caller */ /* add all data fragments */ dfpos = 0; last_fd=NULL; for (fd_i=fd_head->next;fd_i && fd_i->len + dfpos <= size;fd_i=fd_i->next) { if (fd_i->len) { if(!last_fd || last_fd->offset!=fd_i->offset){ memcpy(data+dfpos,tvb_get_ptr(fd_i->tvb_data,0,fd_i->len),fd_i->len); dfpos += fd_i->len; } else { /* duplicate/retransmission/overlap */ fd_i->flags |= FD_OVERLAP; fd_head->flags |= FD_OVERLAP; if( (last_fd->len!=fd_i->datalen) || tvb_memeql(last_fd->tvb_data, 0, tvb_get_ptr(fd_i->tvb_data, 0, last_fd->len), last_fd->len) ){ fd_i->flags |= FD_OVERLAPCONFLICT; fd_head->flags |= FD_OVERLAPCONFLICT; } } } last_fd=fd_i; } /* we have defragmented the pdu, now free all fragments*/ for (fd_i=fd_head->next;fd_i;fd_i=fd_i->next) { if(fd_i->tvb_data){ tvb_free(fd_i->tvb_data); fd_i->tvb_data=NULL; } } /* mark this packet as defragmented */ fd_head->flags |= FD_DEFRAGMENTED; fd_head->reassembled_in=pinfo->fd->num; col_append_fstr(pinfo->cinfo, COL_INFO, " (t4-data Reassembled: %d pack lost, %d pack burst lost)", packet_lost, burst_lost); p_t38_packet_conv_info->packet_lost = packet_lost; p_t38_packet_conv_info->burst_lost = burst_lost; return fd_head; }
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; }
static void dissect_btobex(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_tree *st; fragment_data *frag_msg = NULL; gboolean save_fragmented, complete; tvbuff_t* new_tvb = NULL; tvbuff_t* next_tvb = NULL; guint32 no_of_segments = 0; int offset = 0; save_fragmented = pinfo->fragmented; complete = FALSE; if (fragment_get(pinfo, pinfo->p2p_dir, fragment_table)) { /* not the first fragment */ frag_msg = fragment_add_seq_next(tvb, 0, pinfo, pinfo->p2p_dir, fragment_table, reassembled_table, tvb_length(tvb), TRUE); new_tvb = process_reassembled_data(tvb, 0, pinfo, "Reassembled Obex packet", frag_msg, &btobex_frag_items, NULL, tree); pinfo->fragmented = TRUE; } else { if (tvb_length(tvb) < tvb_get_ntohs(tvb, offset+1)) { /* first fragment in a sequence */ no_of_segments = tvb_get_ntohs(tvb, offset+1)/tvb_length(tvb); if (tvb_get_ntohs(tvb, offset+1) > (no_of_segments * tvb_length(tvb))) no_of_segments++; frag_msg = fragment_add_seq_next(tvb, 0, pinfo, pinfo->p2p_dir, fragment_table, reassembled_table, tvb_length(tvb), TRUE); fragment_set_tot_len(pinfo, pinfo->p2p_dir, fragment_table, no_of_segments-1); new_tvb = process_reassembled_data(tvb, 0, pinfo, "Reassembled Obex packet", frag_msg, &btobex_frag_items, NULL, tree); pinfo->fragmented = TRUE; } else if (tvb_length(tvb) == tvb_get_ntohs(tvb, offset+1)) { /* non-fragmented */ complete = TRUE; pinfo->fragmented = FALSE; } } if (new_tvb) { /* take it all */ next_tvb = new_tvb; complete = TRUE; } else { /* make a new subset */ next_tvb = tvb_new_subset_remaining(tvb, offset); } if (complete) { guint8 code, final_flag; /* fully dissectable packet ready */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "OBEX"); ti = proto_tree_add_item(tree, proto_btobex, next_tvb, 0, -1, ENC_NA); st = proto_item_add_subtree(ti, ett_btobex); /* op/response code */ code = tvb_get_guint8(next_tvb, offset) & BTOBEX_CODE_VALS_MASK; final_flag = tvb_get_guint8(next_tvb, offset) & 0x80; switch (pinfo->p2p_dir) { case P2P_DIR_SENT: col_add_fstr(pinfo->cinfo, COL_INFO, "Sent "); break; case P2P_DIR_RECV: col_add_fstr(pinfo->cinfo, COL_INFO, "Rcvd "); break; case P2P_DIR_UNKNOWN: break; default: col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction %d ", pinfo->p2p_dir); break; } col_append_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str_ext_const(code, &code_vals_ext, "Unknown")); if ((code < BTOBEX_CODE_VALS_CONTINUE) || (code == BTOBEX_CODE_VALS_ABORT)) { proto_tree_add_item(st, hf_opcode, next_tvb, offset, 1, ENC_BIG_ENDIAN); if (pinfo->p2p_dir == P2P_DIR_SENT || pinfo->p2p_dir == P2P_DIR_RECV) { last_opcode[pinfo->p2p_dir] = code; } } else { proto_tree_add_item(st, hf_response_code, next_tvb, offset, 1, ENC_BIG_ENDIAN); } proto_tree_add_item(st, hf_final_flag, next_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; /* length */ proto_tree_add_item(st, hf_length, next_tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; switch(code) { case BTOBEX_CODE_VALS_CONNECT: proto_tree_add_item(st, hf_version, next_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(st, hf_flags, next_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(st, hf_max_pkt_len, next_tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; break; case BTOBEX_CODE_VALS_PUT: case BTOBEX_CODE_VALS_GET: col_append_fstr(pinfo->cinfo, COL_INFO, " %s", (final_flag == 0x80) ? "final" : "continue"); break; case BTOBEX_CODE_VALS_SET_PATH: proto_tree_add_item(st, hf_flags, next_tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(st, hf_set_path_flags_0, next_tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(st, hf_set_path_flags_1, next_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(st, hf_constants, next_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; break; case BTOBEX_CODE_VALS_DISCONNECT: case BTOBEX_CODE_VALS_ABORT: break; default: { guint8 response_opcode = last_opcode[(pinfo->p2p_dir + 1) & 0x01]; if (response_opcode == BTOBEX_CODE_VALS_CONNECT) { proto_tree_add_item(st, hf_version, next_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(st, hf_flags, next_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(st, hf_max_pkt_len, next_tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; } } break; } dissect_headers(st, next_tvb, offset, pinfo); } else { /* packet fragment */ col_add_fstr(pinfo->cinfo, COL_INFO, "%s Obex fragment", (pinfo->p2p_dir==P2P_DIR_SENT) ? "Sent" : "Rcvd"); call_dissector(data_handle, next_tvb, pinfo, tree); } pinfo->fragmented = save_fragmented; }
static int dissect_gssapi_work(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_verifier) { proto_item *volatile item; proto_tree *volatile subtree; volatile int return_offset = 0; gssapi_conv_info_t *volatile gss_info; gssapi_oid_value *oidvalue; dissector_handle_t handle; conversation_t *conversation; tvbuff_t *oid_tvb; int len, start_offset, oid_start_offset; volatile int offset; gint8 appclass; gboolean pc, ind_field; gint32 tag; guint32 len1; const char *oid; fragment_data *fd_head=NULL; gssapi_frag_info_t *fi; tvbuff_t *volatile gss_tvb=NULL; asn1_ctx_t asn1_ctx; void *pd_save; start_offset=0; offset=0; asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo); /* * We don't know whether the data is encrypted, so say it's * not, for now. The subdissector must set gssapi_data_encrypted * if it is. */ pinfo->gssapi_data_encrypted = FALSE; /* * We need a conversation for later */ conversation = find_or_create_conversation(pinfo); gss_info = (gssapi_conv_info_t *)conversation_get_proto_data(conversation, proto_gssapi); if (!gss_info) { gss_info = se_new(gssapi_conv_info_t); gss_info->oid=NULL; gss_info->do_reassembly=FALSE; gss_info->frags=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "gssapi_frags"); conversation_add_proto_data(conversation, proto_gssapi, gss_info); } item = proto_tree_add_item( tree, proto_gssapi, tvb, offset, -1, ENC_NA); subtree = proto_item_add_subtree(item, ett_gssapi); /* * Catch the ReportedBoundsError exception; the stuff we've been * handed doesn't necessarily run to the end of the packet, it's * an item inside a packet, so if it happens to be malformed (or * we, or a dissector we call, has a bug), so that an exception * is thrown, we want to report the error, but return and let * our caller dissect the rest of the packet. * * If it gets a BoundsError, we can stop, as there's nothing more * in the packet after our blob to see, so we just re-throw the * exception. */ pd_save = pinfo->private_data; TRY { gss_tvb=tvb; /* First of all, if it's the first time we see this packet * then check whether we are in the middle of reassembly or not */ if( (!pinfo->fd->flags.visited) && (gss_info->do_reassembly) && (gssapi_reassembly) ){ fi=(gssapi_frag_info_t *)se_tree_lookup32(gss_info->frags, gss_info->first_frame); if(!fi){ goto done; } se_tree_insert32(gss_info->frags, pinfo->fd->num, fi); fd_head=fragment_add(&gssapi_reassembly_table, tvb, 0, pinfo, fi->first_frame, NULL, gss_info->frag_offset, tvb_length(tvb), TRUE); gss_info->frag_offset+=tvb_length(tvb); /* we need more fragments */ if(!fd_head){ goto done; } /* this blob is now fully reassembled */ gss_info->do_reassembly=FALSE; fi->reassembled_in=pinfo->fd->num; gss_tvb=tvb_new_child_real_data(tvb, fd_head->data, fd_head->datalen, fd_head->datalen); add_new_data_source(pinfo, gss_tvb, "Reassembled GSSAPI"); } /* We have seen this packet before. * Is this blob part of reassembly or a normal blob ? */ if( (pinfo->fd->flags.visited) && (gssapi_reassembly) ){ fi=(gssapi_frag_info_t *)se_tree_lookup32(gss_info->frags, pinfo->fd->num); if(fi){ fd_head=fragment_get(&gssapi_reassembly_table, pinfo, fi->first_frame, NULL); if(fd_head && (fd_head->flags&FD_DEFRAGMENTED)){ if(pinfo->fd->num==fi->reassembled_in){ proto_item *frag_tree_item; gss_tvb=tvb_new_child_real_data(tvb, fd_head->data, fd_head->datalen, fd_head->datalen); add_new_data_source(pinfo, gss_tvb, "Reassembled GSSAPI"); show_fragment_tree(fd_head, &gssapi_frag_items, tree, pinfo, tvb, &frag_tree_item); } else { proto_item *it; it=proto_tree_add_uint(tree, hf_gssapi_reassembled_in, tvb, 0, 0, fi->reassembled_in); PROTO_ITEM_SET_GENERATED(it); goto done; } } } } /* Read header */ offset = get_ber_identifier(gss_tvb, offset, &appclass, &pc, &tag); offset = get_ber_length(gss_tvb, offset, &len1, &ind_field); if (!(appclass == BER_CLASS_APP && pc && tag == 0)) { /* It could be NTLMSSP, with no OID. This can happen for anything that microsoft calls 'Negotiate' or GSS-SPNEGO */ if ((tvb_length_remaining(gss_tvb, start_offset)>7) && (tvb_strneql(gss_tvb, start_offset, "NTLMSSP", 7) == 0)) { return_offset = call_dissector(ntlmssp_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); goto done; } /* Maybe it's new NTLMSSP payload */ if ((tvb_length_remaining(gss_tvb, start_offset)>16) && ((tvb_memeql(gss_tvb, start_offset, "\x01\x00\x00\x00", 4) == 0))) { return_offset = call_dissector(ntlmssp_payload_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); pinfo->gssapi_data_encrypted = TRUE; goto done; } if ((tvb_length_remaining(gss_tvb, start_offset)==16) && ((tvb_memeql(gss_tvb, start_offset, "\x01\x00\x00\x00", 4) == 0))) { if( is_verifier ) { return_offset = call_dissector(ntlmssp_verf_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); } else if( pinfo->gssapi_encrypted_tvb ) { return_offset = call_dissector(ntlmssp_data_only_handle, tvb_new_subset_remaining(pinfo->gssapi_encrypted_tvb, 0), pinfo, subtree); pinfo->gssapi_data_encrypted = TRUE; } goto done; } /* Maybe it's new GSSKRB5 CFX Wrapping */ if ((tvb_length_remaining(gss_tvb, start_offset)>2) && ((tvb_memeql(gss_tvb, start_offset, "\04\x04", 2) == 0) || (tvb_memeql(gss_tvb, start_offset, "\05\x04", 2) == 0))) { return_offset = call_dissector(spnego_krb5_wrap_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); goto done; } /* * If we do not recognise an Application class, * then we are probably dealing with an inner context * token or a wrap token, and we should retrieve the * gssapi_oid_value pointer from the per-frame data or, * if there is no per-frame data (as would be the case * the first time we dissect this frame), from the * conversation that exists or that we created from * pinfo (and then make it per-frame data). * We need to make it per-frame data as there can be * more than one GSS-API negotiation in a conversation. * * Note! We "cheat". Since we only need the pointer, * we store that as the data. (That's not really * "cheating" - the per-frame data and per-conversation * data code doesn't care what you supply as a data * pointer; it just treats it as an opaque pointer, it * doesn't dereference it or free what it points to.) */ oidvalue = (gssapi_oid_value *)p_get_proto_data(pinfo->fd, proto_gssapi, 0); if (!oidvalue && !pinfo->fd->flags.visited) { /* No handle attached to this frame, but it's the first */ /* pass, so it'd be attached to the conversation. */ oidvalue = gss_info->oid; if (gss_info->oid) p_add_proto_data(pinfo->fd, proto_gssapi, 0, gss_info->oid); } if (!oidvalue) { proto_tree_add_text(subtree, gss_tvb, start_offset, 0, "Unknown header (class=%d, pc=%d, tag=%d)", appclass, pc, tag); return_offset = tvb_length(gss_tvb); goto done; } else { tvbuff_t *oid_tvb_local; oid_tvb_local = tvb_new_subset_remaining(gss_tvb, start_offset); if (is_verifier) handle = oidvalue->wrap_handle; else handle = oidvalue->handle; len = call_dissector(handle, oid_tvb_local, pinfo, subtree); if (len == 0) return_offset = tvb_length(gss_tvb); else return_offset = start_offset + len; goto done; /* We are finished here */ } } /* Read oid */ oid_start_offset=offset; offset=dissect_ber_object_identifier_str(FALSE, &asn1_ctx, subtree, gss_tvb, offset, hf_gssapi_oid, &oid); oidvalue = gssapi_lookup_oid_str(oid); /* Check if we need reassembly of this blob. * Only try reassembly for OIDs we recognize * and when we have the entire tvb * * SMB will sometimes split one large GSSAPI blob * across multiple SMB/SessionSetup commands. * While we should look at the uid returned in the response * to the first SessionSetup and use that as a key * instead for simplicity we assume there will not be several * such authentication at once on a single tcp session */ if( (!pinfo->fd->flags.visited) && (oidvalue) && (tvb_length(gss_tvb)==tvb_reported_length(gss_tvb)) && (len1>(guint32)tvb_length_remaining(gss_tvb, oid_start_offset)) && (gssapi_reassembly) ){ fi=se_new(gssapi_frag_info_t); fi->first_frame=pinfo->fd->num; fi->reassembled_in=0; se_tree_insert32(gss_info->frags, pinfo->fd->num, fi); fragment_add(&gssapi_reassembly_table, gss_tvb, 0, pinfo, pinfo->fd->num, NULL, 0, tvb_length(gss_tvb), TRUE); fragment_set_tot_len(&gssapi_reassembly_table, pinfo, pinfo->fd->num, NULL, len1+oid_start_offset); gss_info->do_reassembly=TRUE; gss_info->first_frame=pinfo->fd->num; gss_info->frag_offset=tvb_length(gss_tvb); goto done; } /* * Hand off to subdissector. */ if ((oidvalue == NULL) || !proto_is_protocol_enabled(oidvalue->proto)) { /* No dissector for this oid */ proto_tree_add_text(subtree, gss_tvb, oid_start_offset, -1, "Token object"); return_offset = tvb_length(gss_tvb); goto done; } /* Save a pointer to the data for the OID for the * GSSAPI protocol for this conversation. */ /* * Now add the proto data ... * but only if it is not already there. */ if(!gss_info->oid){ gss_info->oid=oidvalue; } if (is_verifier) { handle = oidvalue->wrap_handle; if (handle != NULL) { oid_tvb = tvb_new_subset_remaining(gss_tvb, offset); len = call_dissector(handle, oid_tvb, pinfo, subtree); if (len == 0) return_offset = tvb_length(gss_tvb); else return_offset = offset + len; } else { proto_tree_add_text(subtree, gss_tvb, offset, -1, "Authentication verifier"); return_offset = tvb_length(gss_tvb); } } else { handle = oidvalue->handle; if (handle != NULL) { oid_tvb = tvb_new_subset_remaining(gss_tvb, offset); len = call_dissector(handle, oid_tvb, pinfo, subtree); if (len == 0) return_offset = tvb_length(gss_tvb); else return_offset = offset + len; } else { proto_tree_add_text(subtree, gss_tvb, offset, -1, "Authentication credentials"); return_offset = tvb_length(gss_tvb); } } done: ; } CATCH_NONFATAL_ERRORS { /* * Somebody threw an exception that means that there * was a problem dissecting the payload; that means * that a dissector was found, so we don't need to * dissect the payload as data or update the protocol * or info columns. * * Just show the exception and then drive on to show * the trailer, after noting that a dissector was found * and restoring the protocol value that was in effect * before we called the subdissector. * * Restore the private_data structure in case one of the * called dissectors modified it (and, due to the exception, * was unable to restore it). */ pinfo->private_data = pd_save; show_exception(gss_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); } ENDTRY; proto_item_set_len(item, return_offset); return return_offset; }
/* This tests the functionality of fragment_set_partial_reassembly for * FD_BLOCKSEQUENCE reassembly. * * We add a sequence of fragments thus: * seqno frame offset len (initial) more_frags * ----- ----- ------ --- -------------------- * 0 1 10 50 false * 1 2 0 40 true * 1 3 0 40 true (a duplicate fragment) * 2 4 20 100 false * 3 5 0 40 false */ static void test_fragment_add_seq_partial_reassembly(void) { fragment_data *fd_head, *fd; printf("Starting test test_fragment_add_seq_partial_reassembly\n"); /* generally it's probably fair to assume that we will be called with * more_frags=FALSE. */ pinfo.fd->num = 1; fd_head=fragment_add_seq(tvb, 10, &pinfo, 12, fragment_table, 0, 50, FALSE); ASSERT_EQ(1,g_hash_table_size(fragment_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(50,fd_head->len); /* the length of data we have */ ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */ ASSERT_EQ(1,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(1,fd_head->next->frame); ASSERT_EQ(0,fd_head->next->offset); /* seqno */ ASSERT_EQ(50,fd_head->next->len); /* segment length */ ASSERT_EQ(0,fd_head->next->flags); ASSERT_EQ(NULL,fd_head->next->data); ASSERT_EQ(NULL,fd_head->next->next); /* test the actual reassembly */ ASSERT(!memcmp(fd_head->data,data+10,50)); /* now we announce that the reassembly wasn't complete after all. */ fragment_set_partial_reassembly(&pinfo,12,fragment_table); /* and add another segment. To mix things up slightly (and so that we can * check on the state of things), we're going to set the more_frags flag * here */ pinfo.fd->num = 2; fd_head=fragment_add_seq(tvb, 0, &pinfo, 12, fragment_table, 1, 40, TRUE); ASSERT_EQ(1,g_hash_table_size(fragment_table)); ASSERT_EQ(NULL,fd_head); fd_head=fragment_get(&pinfo,12,fragment_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(50,fd_head->len); the length of data we have */ ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */ ASSERT_EQ(0,fd_head->reassembled_in); ASSERT_EQ(FD_BLOCKSEQUENCE,fd_head->flags); ASSERT_NE(NULL,fd_head->data); ASSERT_NE(NULL,fd_head->next); fd=fd_head->next; ASSERT_EQ(1,fd->frame); ASSERT_EQ(0,fd->offset); /* seqno */ ASSERT_EQ(50,fd->len); /* segment length */ ASSERT_EQ(FD_NOT_MALLOCED,fd->flags); ASSERT_EQ(fd_head->data,fd->data); ASSERT_NE(NULL,fd->next); fd=fd->next; ASSERT_EQ(2,fd->frame); ASSERT_EQ(1,fd->offset); /* seqno */ ASSERT_EQ(40,fd->len); /* segment length */ ASSERT_EQ(0,fd->flags); ASSERT_NE(NULL,fd->data); ASSERT_EQ(NULL,fd->next); /* Another copy of the second segment. */ pinfo.fd->num = 3; fd_head=fragment_add_seq(tvb, 0, &pinfo, 12, fragment_table, 1, 40, TRUE); ASSERT_EQ(1,g_hash_table_size(fragment_table)); ASSERT_EQ(NULL,fd_head); fd_head=fragment_get(&pinfo,12,fragment_table); ASSERT_NE(NULL,fd_head); ASSERT_EQ(0,fd_head->frame); /* unused */ ASSERT_EQ(0,fd_head->offset); /* unused */ /* ASSERT_EQ(50,fd_head->len); the length of data we have */ ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */ ASSERT_EQ(0,fd_head->reassembled_in); ASSERT_EQ(FD_BLOCKSEQUENCE,fd_head->flags); ASSERT_NE(NULL,fd_head->data); ASSERT_NE(NULL,fd_head->next); fd=fd_head->next; ASSERT_EQ(1,fd->frame); ASSERT_EQ(0,fd->offset); /* seqno */ ASSERT_EQ(50,fd->len); /* segment length */ ASSERT_EQ(FD_NOT_MALLOCED,fd->flags); ASSERT_EQ(fd_head->data,fd->data); ASSERT_NE(NULL,fd->next); fd=fd->next; ASSERT_EQ(2,fd->frame); ASSERT_EQ(1,fd->offset); /* seqno */ ASSERT_EQ(40,fd->len); /* segment length */ ASSERT_EQ(0,fd->flags); ASSERT_NE(NULL,fd->data); ASSERT_NE(NULL,fd->next); fd=fd->next; ASSERT_EQ(3,fd->frame); ASSERT_EQ(1,fd->offset); /* seqno */ ASSERT_EQ(40,fd->len); /* segment length */ ASSERT_EQ(0,fd->flags); ASSERT_NE(NULL,fd->data); ASSERT_EQ(NULL,fd->next); /* have another go at wrapping things up */ pinfo.fd->num = 4; fd_head=fragment_add_seq(tvb, 20, &pinfo, 12, fragment_table, 2, 100, FALSE); ASSERT_EQ(1,g_hash_table_size(fragment_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(190,fd_head->len); /* the length of data we have */ ASSERT_EQ(2,fd_head->datalen); /* seqno of the last fragment we have */ ASSERT_EQ(4,fd_head->reassembled_in); ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags); ASSERT_NE(NULL,fd_head->data); ASSERT_NE(NULL,fd_head->next); fd=fd_head->next; ASSERT_EQ(1,fd->frame); ASSERT_EQ(0,fd->offset); /* seqno */ ASSERT_EQ(50,fd->len); /* segment length */ ASSERT_EQ(0,fd->flags); ASSERT_EQ(NULL,fd->data); ASSERT_NE(NULL,fd->next); fd=fd->next; ASSERT_EQ(2,fd->frame); ASSERT_EQ(1,fd->offset); /* seqno */ ASSERT_EQ(40,fd->len); /* segment length */ ASSERT_EQ(0,fd->flags); ASSERT_EQ(NULL,fd->data); ASSERT_NE(NULL,fd->next); fd=fd->next; ASSERT_EQ(3,fd->frame); ASSERT_EQ(1,fd->offset); /* seqno */ ASSERT_EQ(40,fd->len); /* segment length */ ASSERT_EQ(FD_OVERLAP,fd->flags); ASSERT_EQ(NULL,fd->data); ASSERT_NE(NULL,fd->next); fd=fd->next; ASSERT_EQ(4,fd->frame); ASSERT_EQ(2,fd->offset); /* seqno */ ASSERT_EQ(100,fd->len); /* segment length */ ASSERT_EQ(0,fd->flags); ASSERT_EQ(NULL,fd->data); ASSERT_EQ(NULL,fd->next); /* test the actual reassembly */ ASSERT(!memcmp(fd_head->data,data+10,50)); ASSERT(!memcmp(fd_head->data+50,data,40)); ASSERT(!memcmp(fd_head->data+90,data+20,100)); /* do it again (this time it is more complicated, with an overlap in the * reassembly) */ fragment_set_partial_reassembly(&pinfo,12,fragment_table); pinfo.fd->num = 5; fd_head=fragment_add_seq(tvb, 0, &pinfo, 12, fragment_table, 3, 40, FALSE); fd_head=fragment_get(&pinfo,12,fragment_table); ASSERT_NE(NULL,fd_head); ASSERT_EQ(0,fd_head->frame); /* unused */ ASSERT_EQ(0,fd_head->offset); /* unused */ ASSERT_EQ(230,fd_head->len); /* the length of data we have */ ASSERT_EQ(3,fd_head->datalen); /* seqno of the last fragment we have */ ASSERT_EQ(5,fd_head->reassembled_in); ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags); ASSERT_NE(NULL,fd_head->data); ASSERT_NE(NULL,fd_head->next); fd=fd_head->next; ASSERT_EQ(1,fd->frame); ASSERT_EQ(0,fd->offset); /* seqno */ ASSERT_EQ(50,fd->len); /* segment length */ ASSERT_EQ(0,fd->flags); ASSERT_EQ(NULL,fd->data); ASSERT_NE(NULL,fd->next); fd=fd->next; ASSERT_EQ(2,fd->frame); ASSERT_EQ(1,fd->offset); /* seqno */ ASSERT_EQ(40,fd->len); /* segment length */ ASSERT_EQ(0,fd->flags); ASSERT_EQ(NULL,fd->data); ASSERT_NE(NULL,fd->next); fd=fd->next; ASSERT_EQ(3,fd->frame); ASSERT_EQ(1,fd->offset); /* seqno */ ASSERT_EQ(40,fd->len); /* segment length */ ASSERT_EQ(FD_OVERLAP,fd->flags); ASSERT_EQ(NULL,fd->data); ASSERT_NE(NULL,fd->next); fd=fd->next; ASSERT_EQ(4,fd->frame); ASSERT_EQ(2,fd->offset); /* seqno */ ASSERT_EQ(100,fd->len); /* segment length */ ASSERT_EQ(0,fd->flags); ASSERT_EQ(NULL,fd->data); ASSERT_NE(NULL,fd->next); fd=fd->next; ASSERT_EQ(5,fd->frame); ASSERT_EQ(3,fd->offset); /* seqno */ ASSERT_EQ(40,fd->len); /* segment length */ ASSERT_EQ(0,fd->flags); ASSERT_EQ(NULL,fd->data); ASSERT_EQ(NULL,fd->next); /* test the actual reassembly */ ASSERT(!memcmp(fd_head->data,data+10,50)); ASSERT(!memcmp(fd_head->data+50,data,40)); ASSERT(!memcmp(fd_head->data+90,data+20,100)); ASSERT(!memcmp(fd_head->data+190,data,40)); }