gcp_msg_t* gcp_msg(packet_info* pinfo, int o, gboolean keep_persistent_data) { gcp_msg_t* m; guint32 framenum = (guint32)pinfo->fd->num; guint32 offset = (guint32)o; address* src = &(pinfo->src); address* dst = &(pinfo->dst); address* lo_addr; address* hi_addr; if (keep_persistent_data) { emem_tree_key_t key[] = { {1,&(framenum)}, {1,&offset}, {0,NULL} }; if (( m = se_tree_lookup32_array(msgs,key) )) { m->commited = TRUE; return m; } else { m = se_alloc(sizeof(gcp_msg_t)); m->framenum = framenum; m->time = pinfo->fd->abs_ts; m->trxs = NULL; m->commited = FALSE; se_tree_insert32_array(msgs,key,m); } } else { m = ep_new0(gcp_msg_t); m->framenum = framenum; m->trxs = NULL; m->commited = FALSE; } if (CMP_ADDRESS(src, dst) < 0) { lo_addr = src; hi_addr = dst; } else { lo_addr = dst; hi_addr = src; } switch(lo_addr->type) { case AT_NONE: m->lo_addr = 0; m->hi_addr = 0; break; case AT_IPv4: memcpy((guint8*)&(m->hi_addr),hi_addr->data,4); memcpy((guint8*)&(m->lo_addr),lo_addr->data,4); break; case AT_SS7PC: m->hi_addr = mtp3_pc_hash((const mtp3_addr_pc_t *)hi_addr->data); m->lo_addr = mtp3_pc_hash((const mtp3_addr_pc_t *)lo_addr->data); break; default: /* XXX: heuristic and error prone */ m->hi_addr = g_str_hash(ep_address_to_str(hi_addr)); m->lo_addr = g_str_hash(ep_address_to_str(lo_addr)); break; } return m; }
gcp_ctx_t* gcp_ctx(gcp_msg_t* m, gcp_trx_t* t, guint32 c_id, gboolean persistent) { gcp_ctx_t* context = NULL; gcp_ctx_t** context_p = NULL; if ( !m || !t ) return NULL; if (persistent) { emem_tree_key_t ctx_key[] = { {1,&(m->hi_addr)}, {1,&(m->lo_addr)}, {1,&(c_id)}, {0,NULL} }; emem_tree_key_t trx_key[] = { {1,&(m->hi_addr)}, {1,&(m->lo_addr)}, {1,&(t->id)}, {0,NULL} }; if (m->commited) { if (( context = se_tree_lookup32_array(ctxs_by_trx,trx_key) )) { return context; } if ((context_p = se_tree_lookup32_array(ctxs,ctx_key))) { context = *context_p; do { if (context->initial->framenum <= m->framenum) { return context; } } while(( context = context->prev )); DISSECTOR_ASSERT(! "a context should exist"); } } else { if (c_id == CHOOSE_CONTEXT) { if (! ( context = se_tree_lookup32_array(ctxs_by_trx,trx_key))) { context = se_alloc(sizeof(gcp_ctx_t)); context->initial = m; context->cmds = NULL; context->id = c_id; context->terms.last = &(context->terms); context->terms.next = NULL; context->terms.term = NULL; se_tree_insert32_array(ctxs_by_trx,trx_key,context); } } else { if (( context = se_tree_lookup32_array(ctxs_by_trx,trx_key) )) { if (( context_p = se_tree_lookup32_array(ctxs,ctx_key) )) { if (context != *context_p) { if(context->id != CHOOSE_CONTEXT) { context = se_alloc(sizeof(gcp_ctx_t)); } context->initial = m; context->id = c_id; context->cmds = NULL; context->terms.last = &(context->terms); context->terms.next = NULL; context->terms.term = NULL; context->prev = *context_p; *context_p = context; } } else { context_p = se_alloc(sizeof(void*)); *context_p = context; context->initial = m; context->id = c_id; se_tree_insert32_array(ctxs,ctx_key,context_p); } } else if (! ( context_p = se_tree_lookup32_array(ctxs,ctx_key) )) { context = se_alloc(sizeof(gcp_ctx_t)); context->initial = m; context->id = c_id; context->cmds = NULL; context->terms.last = &(context->terms); context->terms.next = NULL; context->terms.term = NULL; context_p = se_alloc(sizeof(void*)); *context_p = context; se_tree_insert32_array(ctxs,ctx_key,context_p); } else { context = *context_p; } } } } else { context = ep_new(gcp_ctx_t); context->initial = m; context->cmds = NULL; context->id = c_id; context->terms.last = &(context->terms); context->terms.next = NULL; context->terms.term = NULL; } return context; }
/* This function will try to determine the complete size of a PDU * based on the information in the header. */ static guint get_nbd_tcp_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset) { guint32 magic, type, packet; conversation_t *conversation; nbd_conv_info_t *nbd_info; nbd_transaction_t *nbd_trans=NULL; emem_tree_key_t hkey[3]; guint32 handle[2]; magic=tvb_get_ntohl(tvb, offset); switch(magic){ case NBD_REQUEST_MAGIC: type=tvb_get_ntohl(tvb, offset+4); switch(type){ case NBD_CMD_WRITE: return tvb_get_ntohl(tvb, offset+24)+28; default: return 28; } case NBD_RESPONSE_MAGIC: /* * Do we have a conversation for this connection? */ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (conversation == NULL) { /* No, so just return the rest of the current packet */ return tvb_length(tvb); } /* * Do we have a state structure for this conv */ nbd_info = (nbd_conv_info_t *)conversation_get_proto_data(conversation, proto_nbd); if (!nbd_info) { /* No, so just return the rest of the current packet */ return tvb_length(tvb); } if(!pinfo->fd->flags.visited){ /* * Do we have a state structure for this transaction */ handle[0]=tvb_get_ntohl(tvb, offset+8); handle[1]=tvb_get_ntohl(tvb, offset+12); hkey[0].length=2; hkey[0].key=handle; hkey[1].length=0; nbd_trans=(nbd_transaction_t *)se_tree_lookup32_array(nbd_info->unacked_pdus, hkey); if(!nbd_trans){ /* No, so just return the rest of the current packet */ return tvb_length(tvb); } } else { /* * Do we have a state structure for this transaction */ handle[0]=tvb_get_ntohl(tvb, offset+8); handle[1]=tvb_get_ntohl(tvb, offset+12); packet=pinfo->fd->num; hkey[0].length=1; hkey[0].key=&packet; hkey[1].length=2; hkey[1].key=handle; hkey[2].length=0; nbd_trans=(nbd_transaction_t *)se_tree_lookup32_array(nbd_info->acked_pdus, hkey); if(!nbd_trans){ /* No, so just return the rest of the current packet */ return tvb_length(tvb); } } /* If this is a read response we must add the datalen to * the pdu size */ if(nbd_trans->type==NBD_CMD_READ){ return 16+nbd_trans->datalen; } else { return 16; } default: break; } /* Did not really look like a NBD packet after all */ return 0; }
gcp_trx_t* gcp_trx(gcp_msg_t* m ,guint32 t_id , gcp_trx_type_t type, gboolean keep_persistent_data) { gcp_trx_t* t = NULL; gcp_trx_msg_t* trxmsg; if ( !m ) return NULL; if (keep_persistent_data) { if (m->commited) { for ( trxmsg = m->trxs; trxmsg; trxmsg = trxmsg->next) { if (trxmsg->trx && trxmsg->trx->id == t_id) { return trxmsg->trx; } } DISSECTOR_ASSERT_NOT_REACHED(); } else { emem_tree_key_t key[] = { {1,&(m->hi_addr)}, {1,&(m->lo_addr)}, {1,&(t_id)}, {0,NULL} }; trxmsg = se_alloc(sizeof(gcp_trx_msg_t)); t = se_tree_lookup32_array(trxs,key); if (!t) { t = se_alloc(sizeof(gcp_trx_t)); t->initial = m; t->id = t_id; t->type = type; t->pendings = 0; t->error = 0; t->cmds = NULL; se_tree_insert32_array(trxs,key,t); } /* XXX: request, reply and ack + point to frames where they are */ switch ( type ) { case GCP_TRX_PENDING: t->pendings++; break; default: break; } } } else { t = ep_new(gcp_trx_t); trxmsg = ep_new(gcp_trx_msg_t); t->initial = NULL; t->id = t_id; t->type = type; t->pendings = 0; t->error = 0; t->cmds = NULL; } DISSECTOR_ASSERT(trxmsg); trxmsg->trx = t; trxmsg->next = NULL; trxmsg->last = trxmsg; if (m->trxs) { m->trxs->last = m->trxs->last->next = trxmsg; } else { m->trxs = trxmsg; } return t; }
static void dissect_nbd_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) { guint32 magic, error, packet; guint32 handle[2]; guint64 from; int offset=0; proto_tree *tree=NULL; proto_item *item=NULL; conversation_t *conversation; nbd_conv_info_t *nbd_info; nbd_transaction_t *nbd_trans=NULL; emem_tree_key_t hkey[3]; col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBD"); col_clear(pinfo->cinfo, COL_INFO); item = proto_tree_add_item(parent_tree, proto_nbd, tvb, 0, -1, ENC_NA); tree = proto_item_add_subtree(item, ett_nbd); magic=tvb_get_ntohl(tvb, offset); proto_tree_add_item(tree, hf_nbd_magic, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; /* grab what we need to do the request/response matching */ switch(magic){ case NBD_REQUEST_MAGIC: case NBD_RESPONSE_MAGIC: handle[0]=tvb_get_ntohl(tvb, offset+4); handle[1]=tvb_get_ntohl(tvb, offset+8); break; default: return; } conversation = find_or_create_conversation(pinfo); /* * Do we already have a state structure for this conv */ nbd_info = (nbd_conv_info_t *)conversation_get_proto_data(conversation, proto_nbd); if (!nbd_info) { /* No. Attach that information to the conversation, and add * it to the list of information structures. */ nbd_info = se_new(nbd_conv_info_t); nbd_info->unacked_pdus=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "nbd_unacked_pdus"); nbd_info->acked_pdus=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "nbd_acked_pdus"); conversation_add_proto_data(conversation, proto_nbd, nbd_info); } if(!pinfo->fd->flags.visited){ if(magic==NBD_REQUEST_MAGIC){ /* This is a request */ nbd_trans=se_new(nbd_transaction_t); nbd_trans->req_frame=pinfo->fd->num; nbd_trans->rep_frame=0; nbd_trans->req_time=pinfo->fd->abs_ts; nbd_trans->type=tvb_get_ntohl(tvb, offset); nbd_trans->datalen=tvb_get_ntohl(tvb, offset+20); hkey[0].length=2; hkey[0].key=handle; hkey[1].length=0; se_tree_insert32_array(nbd_info->unacked_pdus, hkey, (void *)nbd_trans); } else if(magic==NBD_RESPONSE_MAGIC){ hkey[0].length=2; hkey[0].key=handle; hkey[1].length=0; nbd_trans=(nbd_transaction_t *)se_tree_lookup32_array(nbd_info->unacked_pdus, hkey); if(nbd_trans){ nbd_trans->rep_frame=pinfo->fd->num; hkey[0].length=1; hkey[0].key=&nbd_trans->rep_frame; hkey[1].length=2; hkey[1].key=handle; hkey[2].length=0; se_tree_insert32_array(nbd_info->acked_pdus, hkey, (void *)nbd_trans); hkey[0].length=1; hkey[0].key=&nbd_trans->req_frame; hkey[1].length=2; hkey[1].key=handle; hkey[2].length=0; se_tree_insert32_array(nbd_info->acked_pdus, hkey, (void *)nbd_trans); } } } else { packet=pinfo->fd->num; hkey[0].length=1; hkey[0].key=&packet; hkey[1].length=2; hkey[1].key=handle; hkey[2].length=0; nbd_trans=(nbd_transaction_t *)se_tree_lookup32_array(nbd_info->acked_pdus, hkey); } /* The bloody handles are reused !!! eventhough they are 64 bits. * So we must verify we got the "correct" one */ if( (magic==NBD_RESPONSE_MAGIC) && (nbd_trans) && (pinfo->fd->num<nbd_trans->req_frame) ){ /* must have been the wrong one */ nbd_trans=NULL; } if(!nbd_trans){ /* create a "fake" nbd_trans structure */ nbd_trans=ep_new(nbd_transaction_t); nbd_trans->req_frame=0; nbd_trans->rep_frame=0; nbd_trans->req_time=pinfo->fd->abs_ts; nbd_trans->type=0xff; nbd_trans->datalen=0; } /* print state tracking in the tree */ if(magic==NBD_REQUEST_MAGIC){ /* This is a request */ if(nbd_trans->rep_frame){ proto_item *it; it=proto_tree_add_uint(tree, hf_nbd_response_in, tvb, 0, 0, nbd_trans->rep_frame); PROTO_ITEM_SET_GENERATED(it); } } else if(magic==NBD_RESPONSE_MAGIC){ /* This is a reply */ if(nbd_trans->req_frame){ proto_item *it; nstime_t ns; it=proto_tree_add_uint(tree, hf_nbd_response_to, tvb, 0, 0, nbd_trans->req_frame); PROTO_ITEM_SET_GENERATED(it); nstime_delta(&ns, &pinfo->fd->abs_ts, &nbd_trans->req_time); it=proto_tree_add_time(tree, hf_nbd_time, tvb, 0, 0, &ns); PROTO_ITEM_SET_GENERATED(it); } } switch(magic){ case NBD_REQUEST_MAGIC: proto_tree_add_item(tree, hf_nbd_type, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; proto_tree_add_item(tree, hf_nbd_handle, tvb, offset, 8, ENC_BIG_ENDIAN); offset+=8; from=tvb_get_ntoh64(tvb, offset); proto_tree_add_item(tree, hf_nbd_from, tvb, offset, 8, ENC_BIG_ENDIAN); offset+=8; proto_tree_add_item(tree, hf_nbd_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; switch(nbd_trans->type){ case NBD_CMD_WRITE: col_add_fstr(pinfo->cinfo, COL_INFO, "Write Request Offset:0x%" G_GINT64_MODIFIER "x Length:%d", from, nbd_trans->datalen); break; case NBD_CMD_READ: col_add_fstr(pinfo->cinfo, COL_INFO, "Read Request Offset:0x%" G_GINT64_MODIFIER "x Length:%d", from, nbd_trans->datalen); break; case NBD_CMD_DISC: col_set_str(pinfo->cinfo, COL_INFO, "Disconnect Request"); break; } if(nbd_trans->type==NBD_CMD_WRITE){ proto_tree_add_item(tree, hf_nbd_data, tvb, offset, nbd_trans->datalen, ENC_NA); } break; case NBD_RESPONSE_MAGIC: item=proto_tree_add_uint(tree, hf_nbd_type, tvb, 0, 0, nbd_trans->type); PROTO_ITEM_SET_GENERATED(item); error=tvb_get_ntohl(tvb, offset); proto_tree_add_item(tree, hf_nbd_error, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; proto_tree_add_item(tree, hf_nbd_handle, tvb, offset, 8, ENC_BIG_ENDIAN); offset+=8; col_add_fstr(pinfo->cinfo, COL_INFO, "%s Response Error:%d", (nbd_trans->type==NBD_CMD_WRITE)?"Write":"Read", error); if(nbd_trans->type==NBD_CMD_READ){ proto_tree_add_item(tree, hf_nbd_data, tvb, offset, nbd_trans->datalen, ENC_NA); } break; } return; }