static int get_address_v5(tvbuff_t *tvb, int offset, socks_hash_entry_t *hash_info) { /* decode the v5 address and return offset of next byte */ int a_type; address addr; a_type = tvb_get_guint8(tvb, offset); offset += 1; switch(a_type) { case 1: /* IPv4 address */ if ( hash_info) { TVB_SET_ADDRESS(&addr, AT_IPv4, tvb, offset, 4); SE_COPY_ADDRESS(&hash_info->dst_addr, &addr); } offset += 4; break; case 4: /* IPv6 address */ if ( hash_info) { TVB_SET_ADDRESS(&addr, AT_IPv6, tvb, offset, 16); SE_COPY_ADDRESS(&hash_info->dst_addr, &addr); } offset += 16; break; case 3: /* domain name address */ offset += tvb_get_guint8(tvb, offset) + 1; break; } return offset; }
static void dissect_arcnet_common (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, gboolean has_offset, gboolean has_exception) { int offset = 0; guint8 dst, src, protID, split_flag; tvbuff_t *next_tvb; proto_item *ti = NULL; proto_tree *arcnet_tree = NULL; col_set_str (pinfo->cinfo, COL_PROTOCOL, "ARCNET"); col_set_str(pinfo->cinfo, COL_INFO, "ARCNET"); src = tvb_get_guint8 (tvb, 0); dst = tvb_get_guint8 (tvb, 1); TVB_SET_ADDRESS(&pinfo->dl_src, AT_ARCNET, tvb, 0, 1); TVB_SET_ADDRESS(&pinfo->src, AT_ARCNET, tvb, 0, 1); TVB_SET_ADDRESS(&pinfo->dl_dst, AT_ARCNET, tvb, 1, 1); TVB_SET_ADDRESS(&pinfo->dst, AT_ARCNET, tvb, 1, 1); ti = proto_tree_add_item (tree, proto_arcnet, tvb, 0, -1, ENC_NA); arcnet_tree = proto_item_add_subtree (ti, ett_arcnet); proto_tree_add_uint (arcnet_tree, hf_arcnet_src, tvb, offset, 1, src); offset++; proto_tree_add_uint (arcnet_tree, hf_arcnet_dst, tvb, offset, 1, dst); offset++; if (has_offset) { proto_tree_add_item (arcnet_tree, hf_arcnet_offset, tvb, offset, 2, ENC_NA); offset += 2; } protID = tvb_get_guint8 (tvb, offset); proto_tree_add_uint (arcnet_tree, hf_arcnet_protID, tvb, offset, 1, protID); offset++; switch (protID) { case ARCNET_PROTO_IP_1051: case ARCNET_PROTO_ARP_1051: case ARCNET_PROTO_DIAGNOSE: case ARCNET_PROTO_BACNET: /* XXX - no fragmentation? */ /* No fragmentation stuff in the header */ break; default: /* * Show the fragmentation stuff - flag and sequence ID. * * XXX - on at least some versions of NetBSD, it appears that * we might get ARCNET frames, not reassembled packets; if so, * we should reassemble them. * * XXX - but on FreeBSD it appears that we get reassembled packets * on input (but apparently we get frames on output - or maybe * we get the packet *and* all its frames!); how to tell the * difference? It looks from the FreeBSD reassembly code as if * the reassembled packet arrives with the header for the first * frame. It also looks as if, on output, we first get the * full packet, with a header containing none of the fragmentation * stuff, and then get the frames. * * On Linux, we get only reassembled packets, and the exception * frame stuff is hidden - there's a split flag and sequence * number, but it appears that it will never have the exception * frame stuff. * * XXX - what about OpenBSD? And, for that matter, what about * Windows? (I suspect Windows supplies reassembled frames, * as WinPcap, like PF_PACKET sockets, taps into the networking * stack just as other protocols do.) */ split_flag = tvb_get_guint8 (tvb, offset); if (has_exception && split_flag == 0xff) { /* This is an exception packet. The flag value there is the "this is an exception flag" packet; the next two bytes after it are padding. */ proto_tree_add_uint (arcnet_tree, hf_arcnet_exception_flag, tvb, offset, 1, split_flag); offset++; proto_tree_add_item(arcnet_tree, hf_arcnet_padding, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* Another copy of the packet type appears after the padding. */ proto_tree_add_item (arcnet_tree, hf_arcnet_protID, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; /* And after that comes the real split flag. */ split_flag = tvb_get_guint8 (tvb, offset); } proto_tree_add_uint (arcnet_tree, hf_arcnet_split_flag, tvb, offset, 1, split_flag); offset++; proto_tree_add_item (arcnet_tree, hf_arcnet_sequence, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; break; } /* Set the length of the ARCNET header protocol tree item. */ proto_item_set_len(ti, offset); next_tvb = tvb_new_subset_remaining (tvb, offset); if (!dissector_try_uint (arcnet_dissector_table, protID, next_tvb, pinfo, tree)) { col_add_fstr (pinfo->cinfo, COL_PROTOCOL, "0x%04x", protID); call_dissector (data_handle, next_tvb, pinfo, tree); } }
static int dissect_ppcap_destination_address(tvbuff_t *tvb, packet_info * pinfo, proto_tree * ppcap_tree1, int offset) { int key2; guint16 msg_len; msg_len = tvb_get_ntohs(tvb, offset); proto_tree_add_item( ppcap_tree1, hf_ppcap_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset = offset + 2; proto_tree_add_item(ppcap_tree1, hf_ppcap_destreserved, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; key2 = tvb_get_ntohs(tvb, offset); proto_tree_add_item(ppcap_tree1, hf_ppcap_address_type, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; if (key2 == 1) { ssn = tvb_get_guint8(tvb, offset); proto_tree_add_item(ppcap_tree1, hf_ppcap_ssn1, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(ppcap_tree1, hf_ppcap_spc1, tvb, offset, 3, ENC_BIG_ENDIAN); /*dst_addr1 = (guint32 )tvb_get_ntoh24(tvb, offset);*/ mtp3_addr_dpc = wmem_new0(wmem_packet_scope(), mtp3_addr_pc_t); mtp3_addr_dpc->pc = (guint32)tvb_get_ntoh24(tvb, offset); mtp3_addr_dpc->type = ITU_STANDARD; mtp3_addr_dpc->ni = 0; SET_ADDRESS(&pinfo->dst, AT_SS7PC, sizeof(mtp3_addr_pc_t), (guint8 *) mtp3_addr_dpc); if (msg_len%4) msg_len = msg_len + (4 - (msg_len%4)); offset += msg_len-1; return offset; } else if (key2 == 2) { proto_tree_add_item(ppcap_tree1, hf_ppcap_dpc, tvb, offset, 4, ENC_BIG_ENDIAN); /*dst_addr1 = (guint32 )tvb_get_ntoh24(tvb, offset);*/ mtp3_addr_dpc = wmem_new0(wmem_packet_scope(), mtp3_addr_pc_t); mtp3_addr_dpc->pc = tvb_get_ntohl(tvb, offset); mtp3_addr_dpc->type = ITU_STANDARD; mtp3_addr_dpc->ni = 0; SET_ADDRESS(&pinfo->dst, AT_SS7PC, sizeof(mtp3_addr_pc_t), (guint8 *) mtp3_addr_dpc); } else if (key2 == 3) { if (msg_len%16 != 0) { proto_tree_add_ipv4(ppcap_tree1, hf_ppcap_destination_ip_address1, tvb, offset, msg_len, tvb_get_ipv4(tvb, offset)); TVB_SET_ADDRESS(&pinfo->net_dst, AT_IPv4, tvb, offset, 4); COPY_ADDRESS_SHALLOW(&pinfo->dst, &pinfo->net_dst); } else { struct e_in6_addr value; tvb_get_ipv6(tvb, offset,&value); proto_tree_add_ipv6(ppcap_tree1, hf_ppcap_destination_ip_address2, tvb, offset, msg_len, &value); TVB_SET_ADDRESS(&pinfo->net_dst, AT_IPv6, tvb, offset, 6); COPY_ADDRESS_SHALLOW(&pinfo->dst, &pinfo->net_dst); } } else if (key2 == 4) { char *string; string = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, msg_len, ENC_UTF_8|ENC_NA); proto_tree_add_string(ppcap_tree1, hf_ppcap_destination_nodeid, tvb, offset, msg_len, string); TVB_SET_ADDRESS(&pinfo->net_dst, AT_STRINGZ, tvb, offset, msg_len); COPY_ADDRESS_SHALLOW(&pinfo->dst, &pinfo->net_dst); } if (msg_len%4) msg_len = msg_len+(4-(msg_len%4)); offset += msg_len; return offset; }
static int dissect_ppcap_source_address(tvbuff_t *tvb, packet_info *pinfo, proto_tree * ppcap_tree1, int offset) { int key1; guint16 msg_len; msg_len = tvb_get_ntohs(tvb, offset); proto_tree_add_item( ppcap_tree1, hf_ppcap_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset = offset + 2; proto_tree_add_item(ppcap_tree1, hf_ppcap_reserved, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; key1 = tvb_get_ntohs(tvb, offset); proto_tree_add_item(ppcap_tree1, hf_ppcap_address_type, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; if (key1 == 1) { proto_tree_add_item(ppcap_tree1, hf_ppcap_ssn, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(ppcap_tree1, hf_ppcap_spc, tvb, offset, 3, ENC_BIG_ENDIAN); /*src_addr1 = (guint32 )tvb_get_ntoh24(tvb, offset);*/ mtp3_addr_opc = wmem_new0(wmem_packet_scope(), mtp3_addr_pc_t); mtp3_addr_opc->pc = (guint32 )tvb_get_ntoh24(tvb, offset); mtp3_addr_opc->type = ITU_STANDARD; mtp3_addr_opc->ni = 0; /*SET_ADDRESS(&pinfo->net_src, AT_SS7PC, sizeof(mtp3_addr_pc_t), (guint8 *) mtp3_addr_opc);*/ SET_ADDRESS(&pinfo->src, AT_SS7PC, sizeof(mtp3_addr_pc_t), (guint8 *) mtp3_addr_opc); if (msg_len%4) msg_len = msg_len + (4 - (msg_len%4)); offset += msg_len-1; return offset; } else if (key1 == 2) { proto_tree_add_item(ppcap_tree1, hf_ppcap_opc, tvb, offset, msg_len, ENC_BIG_ENDIAN); /*src_addr1 = (guint32 )tvb_get_ntoh24(tvb, offset);*/ mtp3_addr_opc = wmem_new0(wmem_packet_scope(), mtp3_addr_pc_t); mtp3_addr_opc->pc = tvb_get_ntohl(tvb, offset); mtp3_addr_opc->type = ITU_STANDARD; mtp3_addr_opc->ni = 0; SET_ADDRESS(&pinfo->src, AT_SS7PC, sizeof(mtp3_addr_pc_t), (guint8 *) mtp3_addr_opc); } else if (key1 == 3) { if (msg_len%16 != 0) { proto_tree_add_ipv4(ppcap_tree1, hf_ppcap_source_ip_address1, tvb, offset, msg_len, tvb_get_ipv4(tvb, offset)); TVB_SET_ADDRESS(&pinfo->net_src, AT_IPv4, tvb, offset, 4); COPY_ADDRESS_SHALLOW(&pinfo->src, &pinfo->net_src); } else { struct e_in6_addr value; tvb_get_ipv6(tvb, offset, &value); proto_tree_add_ipv6(ppcap_tree1, hf_ppcap_source_ip_address2, tvb, offset, msg_len, &value); TVB_SET_ADDRESS(&pinfo->net_src, AT_IPv6, tvb, offset, 6); COPY_ADDRESS_SHALLOW(&pinfo->src, &pinfo->net_src); } } else if (key1 == 4) { proto_tree_add_item(ppcap_tree1, hf_ppcap_source_nodeid, tvb, offset, msg_len, ENC_ASCII|ENC_NA); TVB_SET_ADDRESS(&pinfo->net_src, AT_STRINGZ, tvb, offset, msg_len); COPY_ADDRESS_SHALLOW(&pinfo->src, &pinfo->net_src); } if (msg_len%4) msg_len = msg_len + (4 - (msg_len%4)); offset += msg_len; return offset; }
static void dissect_tr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *tr_tree, *bf_tree; proto_item *ti, *hidden_item; guint8 rcf1, rcf2; tvbuff_t *next_tvb; volatile int frame_type; volatile int fixoffset = 0; volatile int source_routed = 0; volatile guint8 trn_rif_bytes; volatile guint8 actual_rif_bytes; volatile guint8 c1_nonsr; volatile guint8 c2_nonsr; volatile guint16 first2_sr; tvbuff_t *volatile tr_tvb; static tr_hdr trh_arr[4]; static int trh_current=0; tr_hdr *volatile trh; /* non-source-routed version of source addr */ static guint8 trn_shost_nonsr[6]; /* has to be static due to SET_ADDRESS */ int x; /* Token-Ring Strings */ static const char *fc[] = { "MAC", "LLC", "Reserved", "Unknown" }; trh_current++; if(trh_current==4){ trh_current=0; } trh=&trh_arr[trh_current]; col_set_str(pinfo->cinfo, COL_PROTOCOL, "TR"); if (fix_linux_botches) x = check_for_old_linux_tvb((tvbuff_t*) tvb); else x = 0; if (x != 0) { /* Actually packet starts x bytes into what we have got but with all source routing compressed. See comment above */ tr_tvb = tvb_new_subset_remaining((tvbuff_t*) tvb, x); } else { tr_tvb = tvb; } /* Get the data */ trh->fc = tvb_get_guint8(tr_tvb, 1); TVB_SET_ADDRESS(&trh->src, AT_ETHER, tr_tvb, 8, 6); TVB_SET_ADDRESS(&trh->dst, AT_ETHER, tr_tvb, 2, 6); /* if the high bit on the first byte of src hwaddr is 1, then this packet is source-routed */ memcpy(trn_shost_nonsr, trh->src.data, 6); source_routed = trn_shost_nonsr[0] & 128; trn_shost_nonsr[0] &= 127; frame_type = (trh->fc & 192) >> 6; col_add_fstr(pinfo->cinfo, COL_INFO, "Token-Ring %s", fc[frame_type]); trn_rif_bytes = tvb_get_guint8(tr_tvb, 14) & 31; if (fix_linux_botches) { /* the Linux 2.0 TR code strips source-route bits in * order to test for SR. This can be removed from most * packets with oltr, but not all. So, I try to figure out * which packets should have been SR here. I'll check to * see if there's a SNAP or IPX field right after * my RIF fields. * * The Linux 2.4.18 code, at least appears to do the * same thing, from a capture I got from somebody running * 2.4.18 (RH 7.1, so perhaps this is a Red Hat * "improvement"). */ if (frame_type == 1 && !source_routed && trn_rif_bytes > 0) { TRY { c1_nonsr = tvb_get_guint8(tr_tvb, 14); c2_nonsr = tvb_get_guint8(tr_tvb, 15); if (c1_nonsr != c2_nonsr) { first2_sr = tvb_get_ntohs(tr_tvb, trn_rif_bytes + 0x0e); if ( ( first2_sr == 0xaaaa && tvb_get_guint8(tr_tvb, trn_rif_bytes + 0x10) == 0x03) || first2_sr == 0xe0e0 || first2_sr == 0xe0aa ) { source_routed = 1; } } } CATCH(BoundsError) { /* We had no information beyond the TR header. Just assume * this is a normal (non-Linux) TR header. */ ; } ENDTRY; } }
static void dissect_netrom_proto(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_tree *netrom_tree; int offset; #if 0 guint8 src_ssid; guint8 dst_ssid; #endif guint8 op_code; guint8 cct_index; guint8 cct_id; tvbuff_t *next_tvb; col_set_str( pinfo->cinfo, COL_PROTOCOL, "NET/ROM" ); col_clear( pinfo->cinfo, COL_INFO ); offset = 0; /* source */ TVB_SET_ADDRESS(&pinfo->dl_src, AT_AX25, tvb, offset, AX25_ADDR_LEN); TVB_SET_ADDRESS(&pinfo->src, AT_AX25, tvb, offset, AX25_ADDR_LEN); /* src_ssid = tvb_get_guint8(tvb, offset+6); */ offset += AX25_ADDR_LEN; /* step over src addr */ /* destination */ TVB_SET_ADDRESS(&pinfo->dl_dst, AT_AX25, tvb, offset, AX25_ADDR_LEN); TVB_SET_ADDRESS(&pinfo->dst, AT_AX25, tvb, offset, AX25_ADDR_LEN); /* dst_ssid = tvb_get_guint8(tvb, offset+6); */ offset += AX25_ADDR_LEN; /* step over dst addr */ offset += 1; /* step over ttl */ cct_index = tvb_get_guint8( tvb, offset ); offset += 1; /* step over cct index*/ cct_id = tvb_get_guint8( tvb, offset ); offset += 1; /* step over cct id */ offset += 1; /* step over n_s */ offset += 1; /* step over n_r */ /* frame type */ op_code = tvb_get_guint8( tvb, offset ) & 0x0f; /*offset += 1;*/ /* step over op_code */ col_add_fstr( pinfo->cinfo, COL_INFO, "%s", val_to_str_const( op_code, op_code_vals_text, "Unknown" )); /* if ( tree ) */ { /* create display subtree for the protocol */ ti = proto_tree_add_protocol_format( tree, proto_netrom, tvb, 0, NETROM_HEADER_SIZE, "NET/ROM, Src: %s, Dst: %s", address_to_str(wmem_packet_scope(), &pinfo->src), address_to_str(wmem_packet_scope(), &pinfo->dst)); netrom_tree = proto_item_add_subtree( ti, ett_netrom ); offset = 0; /* source */ proto_tree_add_item( netrom_tree, hf_netrom_src, tvb, offset, AX25_ADDR_LEN, ENC_NA ); offset += AX25_ADDR_LEN; /* destination */ proto_tree_add_item( netrom_tree, hf_netrom_dst, tvb, offset, AX25_ADDR_LEN, ENC_NA ); offset += AX25_ADDR_LEN; /* ttl */ proto_tree_add_item( netrom_tree, hf_netrom_ttl, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; switch ( op_code ) { case NETROM_PROTOEXT : /* cct index */ proto_tree_add_item( netrom_tree, hf_netrom_my_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* cct id */ proto_tree_add_item( netrom_tree, hf_netrom_my_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* unused */ offset += 1; /* unused */ offset += 1; break; case NETROM_CONNREQ : /* cct index */ proto_tree_add_item( netrom_tree, hf_netrom_my_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* cct id */ proto_tree_add_item( netrom_tree, hf_netrom_my_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* unused */ offset += 1; /* unused */ offset += 1; break; case NETROM_CONNACK : /* your cct index */ proto_tree_add_item( netrom_tree, hf_netrom_your_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* your cct id */ proto_tree_add_item( netrom_tree, hf_netrom_your_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* my cct index */ proto_tree_add_item( netrom_tree, hf_netrom_my_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* my cct id */ proto_tree_add_item( netrom_tree, hf_netrom_my_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; break; case NETROM_DISCREQ : /* your cct index */ proto_tree_add_item( netrom_tree, hf_netrom_your_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* your cct id */ proto_tree_add_item( netrom_tree, hf_netrom_your_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* unused */ offset += 1; /* unused */ offset += 1; break; case NETROM_DISCACK : /* your cct index */ proto_tree_add_item( netrom_tree, hf_netrom_your_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* your cct id */ proto_tree_add_item( netrom_tree, hf_netrom_your_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* unused */ offset += 1; /* unused */ offset += 1; break; case NETROM_INFO : /* your cct index */ proto_tree_add_item( netrom_tree, hf_netrom_your_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* your cct id */ proto_tree_add_item( netrom_tree, hf_netrom_your_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* n_s */ proto_tree_add_item( netrom_tree, hf_netrom_n_s, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* n_r */ proto_tree_add_item( netrom_tree, hf_netrom_n_r, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; break; case NETROM_INFOACK : /* your cct index */ proto_tree_add_item( netrom_tree, hf_netrom_your_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* your cct id */ proto_tree_add_item( netrom_tree, hf_netrom_your_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* unused */ offset += 1; /* n_r */ proto_tree_add_item( netrom_tree, hf_netrom_n_r, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; break; default : offset += 1; offset += 1; offset += 1; offset += 1; break; } /* type */ dissect_netrom_type( tvb, offset, pinfo, netrom_tree, hf_netrom_type, ett_netrom_type, &netrom_type_items ); offset += 1; switch ( op_code ) { case NETROM_PROTOEXT : break; case NETROM_CONNREQ : /* proposed window size */ proto_tree_add_item( netrom_tree, hf_netrom_pwindow, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; proto_tree_add_item( netrom_tree, hf_netrom_user, tvb, offset, AX25_ADDR_LEN, ENC_NA ); offset += AX25_ADDR_LEN; proto_tree_add_item( netrom_tree, hf_netrom_node, tvb, offset, AX25_ADDR_LEN, ENC_NA ); offset += AX25_ADDR_LEN; break; case NETROM_CONNACK : /* accepted window size */ proto_tree_add_item( netrom_tree, hf_netrom_awindow, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; break; case NETROM_DISCREQ : break; case NETROM_DISCACK : break; case NETROM_INFO : break; case NETROM_INFOACK : break; default : break; } } /* Call sub-dissectors here */ next_tvb = tvb_new_subset_remaining(tvb, offset); switch ( op_code ) { case NETROM_PROTOEXT : if ( cct_index == NETROM_PROTO_IP && cct_id == NETROM_PROTO_IP ) call_dissector( ip_handle , next_tvb, pinfo, tree ); else call_dissector( data_handle , next_tvb, pinfo, tree ); break; case NETROM_INFO : default : call_dissector( data_handle , next_tvb, pinfo, tree ); break; } }
static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *clnp_tree; proto_item *ti, *ti_len = NULL, *ti_pdu_len = NULL, *ti_tot_len = NULL; guint8 cnf_proto_id; guint8 cnf_hdr_len; guint8 cnf_vers; guint8 cnf_ttl; guint8 cnf_type; char flag_string[6+1]; const char *pdu_type_string; proto_tree *type_tree; guint16 segment_length; guint16 du_id = 0; guint16 segment_offset = 0; guint16 total_length; guint16 cnf_cksum; cksum_status_t cksum_status; int offset; guchar src_len, dst_len, nsel, opt_len = 0; guint next_length; proto_tree *discpdu_tree; gboolean save_in_error_pkt; fragment_head *fd_head; tvbuff_t *next_tvb; gboolean update_col_info = TRUE; gboolean save_fragmented; heur_dtbl_entry_t *hdtbl_entry; col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP"); col_clear(pinfo->cinfo, COL_INFO); cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID); if (cnf_proto_id == NLPID_NULL) { col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset"); ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, ENC_NA); clnp_tree = proto_item_add_subtree(ti, ett_clnp); proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1, cnf_proto_id, "Inactive subset"); next_tvb = tvb_new_subset_remaining(tvb, 1); if (call_dissector(ositp_inactive_handle, next_tvb, pinfo, tree) == 0) call_dissector(data_handle,tvb, pinfo, tree); return; } /* return if version not known */ cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS); if (cnf_vers != ISO8473_V1) { call_dissector(data_handle,tvb, pinfo, tree); return; } /* fixed part decoding */ cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN); ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, ENC_NA); clnp_tree = proto_item_add_subtree(ti, ett_clnp); proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1, cnf_proto_id); ti_len = proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1, cnf_hdr_len); if (cnf_hdr_len < FIXED_PART_LEN) { /* Header length is less than the length of the fixed part of the header. */ expert_add_info_format(pinfo, ti_len, &ei_clnp_length, "Header length value < minimum length %u", FIXED_PART_LEN); return; } proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1, cnf_vers); cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL); proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1, cnf_ttl, "Holding Time : %u (%u.%u secs)", cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5); cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE); pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals, "Unknown (0x%02x)"); flag_string[0] = '\0'; if (cnf_type & CNF_SEG_OK) g_strlcat(flag_string, "S ", 7); if (cnf_type & CNF_MORE_SEGS) g_strlcat(flag_string, "M ", 7); if (cnf_type & CNF_ERR_OK) g_strlcat(flag_string, "E ", 7); ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1, cnf_type, "PDU Type : 0x%02x (%s%s)", cnf_type, flag_string, pdu_type_string); type_tree = proto_item_add_subtree(ti, ett_clnp_type); proto_tree_add_item(type_tree, hf_clnp_cnf_segmentation, tvb, P_CLNP_TYPE, 1, ENC_NA); proto_tree_add_item(type_tree, hf_clnp_cnf_more_segments, tvb, P_CLNP_TYPE, 1, ENC_NA); proto_tree_add_item(type_tree, hf_clnp_cnf_report_error, tvb, P_CLNP_TYPE, 1, ENC_NA); proto_tree_add_item(type_tree, hf_clnp_cnf_type, tvb, P_CLNP_TYPE, 1, ENC_BIG_ENDIAN); /* If we don't have the full header - i.e., not enough to see the segmentation part and determine whether this datagram is segmented or not - set the Info column now; we'll get an exception before we set it otherwise. */ if (tvb_length(tvb) < cnf_hdr_len) { col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string); } segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN); ti_pdu_len = proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2, segment_length); if (segment_length < cnf_hdr_len) { /* Segment length is less than the header length. */ expert_add_info_format(pinfo, ti_pdu_len, &ei_clnp_length, "PDU length < header length %u", cnf_hdr_len); return; } cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM); cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum); switch (cksum_status) { default: /* * No checksum present, or not enough of the header present to * checksum it. */ proto_tree_add_uint(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum); break; case CKSUM_OK: /* * Checksum is correct. */ proto_tree_add_uint_format_value(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum, "0x%04x (correct)", cnf_cksum); break; case CKSUM_NOT_OK: /* * Checksum is not correct. */ proto_tree_add_uint_format_value(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum, "0x%04x (incorrect)", cnf_cksum); break; } opt_len = cnf_hdr_len; opt_len -= FIXED_PART_LEN; /* Fixed part of Header */ /* address part */ offset = P_CLNP_ADDRESS_PART; if (opt_len < 1) { /* Header length is less than the minimum value in CLNP, including the destination address length. */ expert_add_info_format(pinfo, ti_len, &ei_clnp_length, "Header length value < %u", FIXED_PART_LEN + 1); return; } dst_len = tvb_get_guint8(tvb, offset); if (tree) { proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1, dst_len); } offset += 1; opt_len -= 1; if (opt_len < dst_len) { /* Header length is less than the minimum value, including the destination address length and the destination address. */ expert_add_info_format(pinfo, ti_len, &ei_clnp_length, "Header length value < %u", FIXED_PART_LEN + 1 + dst_len); return; } nsel = tvb_get_guint8(tvb, offset + dst_len - 1); TVB_SET_ADDRESS(&pinfo->net_dst, get_osi_address_type(), tvb, offset, dst_len); COPY_ADDRESS_SHALLOW(&pinfo->dst, &pinfo->net_dst); proto_tree_add_bytes_format_value(clnp_tree, hf_clnp_dest, tvb, offset, dst_len, NULL, "%s", print_nsap_net(tvb, offset, dst_len)); offset += dst_len; opt_len -= dst_len; if (opt_len < 1) { /* Header length is less than the minimum value, including the destination address length, the destination address, and the source address length. */ expert_add_info_format(pinfo, ti_len, &ei_clnp_length, "Header length value < %u", FIXED_PART_LEN + 1 + dst_len + 1); return; } src_len = tvb_get_guint8(tvb, offset); if (tree) { proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb, offset, 1, src_len); } offset += 1; opt_len -= 1; if (opt_len < src_len) { /* Header length is less than the minimum value, including the destination address length, the destination address, the source address length, and the source address. */ expert_add_info_format(pinfo, ti_len, &ei_clnp_length, "Header length value < %u", FIXED_PART_LEN + 1 + dst_len + 1 + src_len); return; } TVB_SET_ADDRESS(&pinfo->net_src, get_osi_address_type(), tvb, offset, src_len); COPY_ADDRESS_SHALLOW(&pinfo->src, &pinfo->net_src); proto_tree_add_bytes_format_value(clnp_tree, hf_clnp_src, tvb, offset, src_len, NULL, "%s", print_nsap_net(tvb, offset, src_len)); offset += src_len; opt_len -= src_len; /* Segmentation Part */ if (cnf_type & CNF_SEG_OK) { if (opt_len < SEGMENTATION_PART_LEN) { /* Header length is less than the minimum value, including the destination address length, the destination address, the source address length, the source address, and the segmentation part. */ expert_add_info_format(pinfo, ti_len, &ei_clnp_length, "Header length value < %u", FIXED_PART_LEN + 1 + dst_len + 1 + SEGMENTATION_PART_LEN); return; } du_id = tvb_get_ntohs(tvb, offset); proto_tree_add_item(clnp_tree, hf_clnp_data_unit_identifier, tvb, offset, 2, ENC_BIG_ENDIAN); segment_offset = tvb_get_ntohs(tvb, offset + 2); proto_tree_add_item(clnp_tree, hf_clnp_segment_offset, tvb, offset + 2 , 2, ENC_BIG_ENDIAN); total_length = tvb_get_ntohs(tvb, offset + 4); ti_tot_len = proto_tree_add_item(clnp_tree, hf_clnp_total_length, tvb, offset + 4 , 2, ENC_BIG_ENDIAN); if (total_length < segment_length) { /* Reassembled length is less than the length of this segment. */ expert_add_info_format(pinfo, ti_tot_len, &ei_clnp_length, "Total length < segment length %u", segment_length); return; } offset += SEGMENTATION_PART_LEN; opt_len -= SEGMENTATION_PART_LEN; } dissect_osi_options(opt_len, tvb, offset, clnp_tree); offset += opt_len; /* If clnp_reassemble is on, this is a segment, we have all the * data in the segment, and the checksum is valid, then just add the * segment to the hashtable. */ save_fragmented = pinfo->fragmented; if (clnp_reassemble && (cnf_type & CNF_SEG_OK) && ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) && tvb_bytes_exist(tvb, offset, segment_length - cnf_hdr_len) && segment_length > cnf_hdr_len && cksum_status != CKSUM_NOT_OK) { fd_head = fragment_add_check(&clnp_reassembly_table, tvb, offset, pinfo, du_id, NULL, segment_offset, segment_length - cnf_hdr_len, cnf_type & CNF_MORE_SEGS); next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CLNP", fd_head, &clnp_frag_items, &update_col_info, clnp_tree); } else { /* If this is the first segment, dissect its contents, otherwise just show it as a segment. XXX - if we eventually don't save the reassembled contents of all segmented datagrams, we may want to always reassemble. */ if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) { /* Not the first segment - don't dissect it. */ next_tvb = NULL; } else { /* First segment, or not segmented. Dissect what we have here. */ /* Get a tvbuff for the payload. Set its length to the segment length, and flag it as a fragment, so going past the end reports FragmentBoundsError, i.e. "there's data missing because this isn't reassembled", not ReportedBoundsError, i.e. "the dissector ran past the end of the packet, so the packet must not have been constructed properly". */ next_tvb = tvb_new_subset_length(tvb, offset, segment_length - cnf_hdr_len); tvb_set_fragment(next_tvb); /* * If this is the first segment, but not the only segment, * tell the next protocol that. */ if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS)) pinfo->fragmented = TRUE; else pinfo->fragmented = FALSE; } } if (next_tvb == NULL) { /* Just show this as a segment. */ col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)", pdu_type_string, flag_string, segment_offset); /* As we haven't reassembled anything, we haven't changed "pi", so we don't have to restore it. */ call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree); pinfo->fragmented = save_fragmented; return; } if (tvb_offset_exists(tvb, offset)) { switch (cnf_type & CNF_TYPE) { case DT_NPDU: case MD_NPDU: /* Continue with COTP if any data. XXX - if this isn't the first Derived PDU of a segmented Initial PDU, skip that? */ if (nsel==NSEL_NET && tvb_get_guint8(next_tvb, 0)==NLPID_ISO10747_IDRP) { if(call_dissector(idrp_handle, next_tvb, pinfo, tree) != 0) { pinfo->fragmented = save_fragmented; return; } } if (nsel == (guchar)tp_nsap_selector || always_decode_transport) { if (call_dissector(ositp_handle, next_tvb, pinfo, tree) != 0) { pinfo->fragmented = save_fragmented; return; /* yes, it appears to be COTP or CLTP */ } } if (dissector_try_heuristic(clnp_heur_subdissector_list, next_tvb, pinfo, tree, &hdtbl_entry, NULL)) { pinfo->fragmented = save_fragmented; return; /* yes, it appears to be one of the protocols in the heuristic list */ } break; case ER_NPDU: /* The payload is the header and "none, some, or all of the data part of the discarded PDU", i.e. it's like an ICMP error; dissect it as a CLNP PDU. */ col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string); next_length = tvb_length_remaining(tvb, offset); if (next_length != 0) { /* We have payload; dissect it. */ discpdu_tree = proto_tree_add_subtree(clnp_tree, tvb, offset, next_length, ett_clnp_disc_pdu, NULL, "Discarded PDU"); /* Save the current value of the "we're inside an error packet" flag, and set that flag; subdissectors may treat packets that are the payload of error packets differently from "real" packets. */ save_in_error_pkt = pinfo->flags.in_error_pkt; pinfo->flags.in_error_pkt = TRUE; call_dissector(clnp_handle, next_tvb, pinfo, discpdu_tree); /* Restore the "we're inside an error packet" flag. */ pinfo->flags.in_error_pkt = save_in_error_pkt; } pinfo->fragmented = save_fragmented; return; /* we're done with this PDU */ case ERQ_NPDU: case ERP_NPDU: /* XXX - dissect this */ break; } } col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string); call_dissector(data_handle,next_tvb, pinfo, tree); pinfo->fragmented = save_fragmented; } /* dissect_clnp */