static int dissect_rx_abort(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset, guint32 seq, guint32 callnumber) { proto_tree *tree; proto_item *item; int old_offset=offset; if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "ABORT " "Seq: %lu " "Call: %lu " "Source Port: %s " "Destination Port: %s ", (unsigned long)seq, (unsigned long)callnumber, get_udp_port(pinfo->srcport), get_udp_port(pinfo->destport) ); } item = proto_tree_add_item(parent_tree, hf_rx_abort, tvb, offset, -1, FALSE); tree = proto_item_add_subtree(item, ett_rx_abort); /* kvno */ proto_tree_add_item(tree, hf_rx_abortcode, tvb, offset, 4, FALSE); offset += 4; proto_item_set_len(item, offset-old_offset); return offset; }
static int dissect_rx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset, guint32 seq, guint32 callnumber) { proto_tree *tree; proto_item *item; guint32 version, tl; int old_offset=offset; if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "RESPONSE " "Seq: %lu " "Call: %lu " "Source Port: %s " "Destination Port: %s ", (unsigned long)seq, (unsigned long)callnumber, get_udp_port(pinfo->srcport), get_udp_port(pinfo->destport) ); } item = proto_tree_add_item(parent_tree, hf_rx_response, tvb, offset, -1, FALSE); tree = proto_item_add_subtree(item, ett_rx_response); version = tvb_get_ntohl(tvb, offset); proto_tree_add_uint(tree, hf_rx_version, tvb, offset, 4, version); offset += 4; if (version==2) { /* skip unused */ offset += 4; /* encrypted : struct */ offset = dissect_rx_response_encrypted(tvb, tree, offset); /* kvno */ proto_tree_add_item(tree, hf_rx_kvno, tvb, offset, 4, FALSE); offset += 4; /* ticket_len */ tl = tvb_get_ntohl(tvb, offset); proto_tree_add_uint(tree, hf_rx_ticket_len, tvb, offset, 4, tl); offset += 4; tvb_ensure_bytes_exist(tvb, offset, tl); proto_tree_add_item(tree, hf_rx_ticket, tvb, offset, tl, FALSE); offset += tl; } proto_item_set_len(item, offset-old_offset); return offset; }
static int dissect_rx_challenge(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset, guint32 seq, guint32 callnumber) { proto_tree *tree; proto_item *item; guint32 version; int old_offset=offset; if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "CHALLENGE " "Seq: %lu " "Call: %lu " "Source Port: %s " "Destination Port: %s ", (unsigned long)seq, (unsigned long)callnumber, get_udp_port(pinfo->srcport), get_udp_port(pinfo->destport) ); } item = proto_tree_add_item(parent_tree, hf_rx_challenge, tvb, offset, -1, FALSE); tree = proto_item_add_subtree(item, ett_rx_challenge); version = tvb_get_ntohl(tvb, offset); proto_tree_add_uint(tree, hf_rx_version, tvb, offset, 4, version); offset += 4; if (version==2) { proto_tree_add_item(tree, hf_rx_nonce, tvb, offset, 4, FALSE); offset += 4; proto_tree_add_item(tree, hf_rx_min_level, tvb, offset, 4, FALSE); offset += 4; } proto_item_set_len(item, offset-old_offset); return offset; }
static void dissect_tpcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { tpcpdu_t tpcph; proto_tree *tpcp_tree = NULL, *field_tree = NULL; proto_item *ti, *tf; guint8 length = TPCP_VER_1_LENGTH; col_set_str(pinfo->cinfo, COL_PROTOCOL, "TPCP"); col_clear(pinfo->cinfo, COL_INFO); /* need to find out which version!! */ tpcph.version = tvb_get_guint8(tvb, 0); /* as version 1 and 2 are so similar use the same structure, just don't use as much for version 1*/ if (tpcph.version == TPCP_VER_1) { length = TPCP_VER_1_LENGTH; tvb_memcpy(tvb, (guint8 *) &tpcph, 0, length); } else if (tpcph.version == TPCP_VER_2){ length = TPCP_VER_2_LENGTH; tvb_memcpy(tvb, (guint8 *) &tpcph, 0, length); } tpcph.id = g_ntohs(tpcph.id); tpcph.flags = g_ntohs(tpcph.flags); tpcph.cport = g_ntohs(tpcph.cport); if (check_col(pinfo->cinfo, COL_INFO)) col_add_fstr(pinfo->cinfo, COL_INFO,"%s id %d CPort %s CIP %s SIP %s", val_to_str(tpcph.type, type_vals, "Unknown"), tpcph.id, get_udp_port(tpcph.cport), ip_to_str((guint8 *)&tpcph.caddr), ip_to_str((guint8 *)&tpcph.saddr)); if (tree) { ti = proto_tree_add_protocol_format(tree, proto_tpcp, tvb, 0, length, "Alteon WebSystems - Transparent Proxy Cache Protocol"); tpcp_tree = proto_item_add_subtree(ti, ett_tpcp); proto_tree_add_item(tpcp_tree, hf_tpcp_version, tvb, 0, 1, tpcph.version); proto_tree_add_uint_format(tpcp_tree, hf_tpcp_type, tvb, 1, 1, tpcph.type, "Type: %s (%d)", val_to_str(tpcph.type, type_vals, "Unknown"), tpcph.type); /* flags next , i'll do that when I can work out how to do it :-( */ tf = proto_tree_add_text(tpcp_tree, tvb, 2, 2, "Flags: 0x%04x",tpcph.flags); field_tree = proto_item_add_subtree(tf, ett_tpcp_flags); proto_tree_add_boolean(field_tree, hf_tpcp_flags_tcp, tvb, 2, 2, tpcph.flags); proto_tree_add_boolean(field_tree, hf_tpcp_flags_redir, tvb, 2,2, tpcph.flags); proto_tree_add_boolean(field_tree, hf_tpcp_flags_xon, tvb, 2, 2, tpcph.flags); proto_tree_add_boolean(field_tree, hf_tpcp_flags_xoff, tvb, 2, 2, tpcph.flags); proto_tree_add_uint(tpcp_tree, hf_tpcp_id, tvb, 4, 2, tpcph.id); proto_tree_add_uint_format(tpcp_tree, hf_tpcp_cport, tvb, 6, 2, tpcph.cport, "Client Source port: %s", get_udp_port(tpcph.cport)); proto_tree_add_ipv4(tpcp_tree, hf_tpcp_caddr, tvb, 8, 4, tpcph.caddr); proto_tree_add_ipv4(tpcp_tree, hf_tpcp_saddr, tvb, 12, 4, tpcph.saddr); if (tpcph.version == TPCP_VER_2) { proto_tree_add_ipv4(tpcp_tree, hf_tpcp_vaddr, tvb, 16, 4, tpcph.vaddr); proto_tree_add_ipv4(tpcp_tree, hf_tpcp_rasaddr, tvb, 20, 4, tpcph.rasaddr); proto_tree_add_text(tpcp_tree, tvb, 24, 4, "Signature: %u", tpcph.signature); } } }
static void dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 ip_proto) { proto_tree *udp_tree = NULL; proto_item *ti, *hidden_item, *port_item; guint len; guint reported_len; vec_t cksum_vec[4]; guint32 phdr[2]; guint16 computed_cksum; int offset = 0; e_udphdr *udph; proto_tree *checksum_tree; proto_item *item; conversation_t *conv = NULL; struct udp_analysis *udpd = NULL; proto_tree *process_tree; udph=ep_new(e_udphdr); SET_ADDRESS(&udph->ip_src, pinfo->src.type, pinfo->src.len, pinfo->src.data); SET_ADDRESS(&udph->ip_dst, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data); col_set_str(pinfo->cinfo, COL_PROTOCOL, (ip_proto == IP_PROTO_UDP) ? "UDP" : "UDPlite"); col_clear(pinfo->cinfo, COL_INFO); udph->uh_sport=tvb_get_ntohs(tvb, offset); udph->uh_dport=tvb_get_ntohs(tvb, offset+2); col_add_fstr(pinfo->cinfo, COL_INFO, "Source port: %s Destination port: %s", get_udp_port(udph->uh_sport), get_udp_port(udph->uh_dport)); if (tree) { if (udp_summary_in_tree) { if (ip_proto == IP_PROTO_UDP) { ti = proto_tree_add_protocol_format(tree, proto_udp, tvb, offset, 8, "User Datagram Protocol, Src Port: %s (%u), Dst Port: %s (%u)", get_udp_port(udph->uh_sport), udph->uh_sport, get_udp_port(udph->uh_dport), udph->uh_dport); } else { ti = proto_tree_add_protocol_format(tree, proto_udplite, tvb, offset, 8, "Lightweight User Datagram Protocol, Src Port: %s (%u), Dst Port: %s (%u)", get_udp_port(udph->uh_sport), udph->uh_sport, get_udp_port(udph->uh_dport), udph->uh_dport); } } else { ti = proto_tree_add_item(tree, (ip_proto == IP_PROTO_UDP) ? proto_udp : proto_udplite, tvb, offset, 8, ENC_NA); } udp_tree = proto_item_add_subtree(ti, ett_udp); port_item = proto_tree_add_uint_format(udp_tree, hf_udp_srcport, tvb, offset, 2, udph->uh_sport, "Source port: %s (%u)", get_udp_port(udph->uh_sport), udph->uh_sport); /* The beginning port number, 32768 + 666 (33434), is from LBL's traceroute.c source code and this code * further assumes that 3 attempts are made per hop */ if(udph->uh_sport > 32768 + 666 && udph->uh_sport <= 32768 + 666 + 30) expert_add_info_format(pinfo, port_item, PI_SEQUENCE, PI_CHAT, "Possible traceroute: hop #%u, attempt #%u", ((udph->uh_sport - 32768 - 666 - 1) / 3) + 1, ((udph->uh_sport - 32768 - 666 - 1) % 3) + 1 ); port_item = proto_tree_add_uint_format(udp_tree, hf_udp_dstport, tvb, offset + 2, 2, udph->uh_dport, "Destination port: %s (%u)", get_udp_port(udph->uh_dport), udph->uh_dport); if(udph->uh_dport > 32768 + 666 && udph->uh_dport <= 32768 + 666 + 30) expert_add_info_format(pinfo, port_item, PI_SEQUENCE, PI_CHAT, "Possible traceroute: hop #%u, attempt #%u", ((udph->uh_dport - 32768 - 666 - 1) / 3) + 1, ((udph->uh_dport - 32768 - 666 - 1) % 3) + 1 ); hidden_item = proto_tree_add_uint(udp_tree, hf_udp_port, tvb, offset, 2, udph->uh_sport); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_uint(udp_tree, hf_udp_port, tvb, offset+2, 2, udph->uh_dport); PROTO_ITEM_SET_HIDDEN(hidden_item); } if (ip_proto == IP_PROTO_UDP) { udph->uh_ulen = udph->uh_sum_cov = tvb_get_ntohs(tvb, offset+4); if (udph->uh_ulen < 8) { /* Bogus length - it includes the header, so it must be >= 8. */ /* XXX - should handle IPv6 UDP jumbograms (RFC 2675), where the length is zero */ item = proto_tree_add_uint_format(udp_tree, hf_udp_length, tvb, offset + 4, 2, udph->uh_ulen, "Length: %u (bogus, must be >= 8)", udph->uh_ulen); expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Bad length value %u < 8", udph->uh_ulen); col_append_fstr(pinfo->cinfo, COL_INFO, " [BAD UDP LENGTH %u < 8]", udph->uh_ulen); return; } if ((udph->uh_ulen > tvb_reported_length(tvb)) && ! pinfo->fragmented && ! pinfo->flags.in_error_pkt) { /* Bogus length - it goes past the end of the IP payload */ item = proto_tree_add_uint_format(udp_tree, hf_udp_length, tvb, offset + 4, 2, udph->uh_ulen, "Length: %u (bogus, payload length %u)", udph->uh_ulen, tvb_reported_length(tvb)); expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Bad length value %u > IP payload length", udph->uh_ulen); col_append_fstr(pinfo->cinfo, COL_INFO, " [BAD UDP LENGTH %u > IP PAYLOAD LENGTH]", udph->uh_ulen); } else { if (tree) { proto_tree_add_uint(udp_tree, hf_udp_length, tvb, offset + 4, 2, udph->uh_ulen); /* XXX - why is this here, given that this is UDP, not Lightweight UDP? */ hidden_item = proto_tree_add_uint(udp_tree, hf_udplite_checksum_coverage, tvb, offset + 4, 0, udph->uh_sum_cov); PROTO_ITEM_SET_HIDDEN(hidden_item); } } } else { udph->uh_ulen = pinfo->iplen - pinfo->iphdrlen; udph->uh_sum_cov = tvb_get_ntohs(tvb, offset+4); if (((udph->uh_sum_cov > 0) && (udph->uh_sum_cov < 8)) || (udph->uh_sum_cov > udph->uh_ulen)) { /* Bogus length - it includes the header, so it must be >= 8, and no larger then the IP payload size. */ if (tree) { hidden_item = proto_tree_add_boolean(udp_tree, hf_udplite_checksum_coverage_bad, tvb, offset + 4, 2, TRUE); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_uint(udp_tree, hf_udp_length, tvb, offset + 4, 0, udph->uh_ulen); PROTO_ITEM_SET_HIDDEN(hidden_item); } item = proto_tree_add_uint_format(udp_tree, hf_udplite_checksum_coverage, tvb, offset + 4, 2, udph->uh_sum_cov, "Checksum coverage: %u (bogus, must be >= 8 and <= %u (ip.len-ip.hdr_len))", udph->uh_sum_cov, udph->uh_ulen); expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Bad checksum coverage length value %u < 8 or > %u", udph->uh_sum_cov, udph->uh_ulen); col_append_fstr(pinfo->cinfo, COL_INFO, " [BAD LIGHTWEIGHT UDP CHECKSUM COVERAGE LENGTH %u < 8 or > %u]", udph->uh_sum_cov, udph->uh_ulen); if (!udplite_ignore_checksum_coverage) return; } else { if (tree) { hidden_item = proto_tree_add_uint(udp_tree, hf_udp_length, tvb, offset + 4, 0, udph->uh_ulen); PROTO_ITEM_SET_HIDDEN(hidden_item); proto_tree_add_uint(udp_tree, hf_udplite_checksum_coverage, tvb, offset + 4, 2, udph->uh_sum_cov); } } } udph->uh_sum_cov = (udph->uh_sum_cov) ? udph->uh_sum_cov : udph->uh_ulen; udph->uh_sum = tvb_get_ntohs(tvb, offset+6); reported_len = tvb_reported_length(tvb); len = tvb_length(tvb); if (udph->uh_sum == 0) { /* No checksum supplied in the packet. */ if ((ip_proto == IP_PROTO_UDP) && (pinfo->src.type == AT_IPv4)) { item = proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb, offset + 6, 2, 0, "Checksum: 0x%04x (none)", 0); checksum_tree = proto_item_add_subtree(item, ett_udp_checksum); item = proto_tree_add_boolean(checksum_tree, hf_udp_checksum_good, tvb, offset + 6, 2, FALSE); PROTO_ITEM_SET_GENERATED(item); item = proto_tree_add_boolean(checksum_tree, hf_udp_checksum_bad, tvb, offset + 6, 2, FALSE); PROTO_ITEM_SET_GENERATED(item); } else { item = proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb, offset + 6, 2, 0, "Checksum: 0x%04x (Illegal)", 0); expert_add_info_format(pinfo, item, PI_CHECKSUM, PI_ERROR, "Illegal Checksum value (0)"); col_append_fstr(pinfo->cinfo, COL_INFO, " [ILLEGAL CHECKSUM (0)]"); checksum_tree = proto_item_add_subtree(item, ett_udp_checksum); item = proto_tree_add_boolean(checksum_tree, hf_udp_checksum_good, tvb, offset + 6, 2, FALSE); PROTO_ITEM_SET_GENERATED(item); item = proto_tree_add_boolean(checksum_tree, hf_udp_checksum_bad, tvb, offset + 6, 2, TRUE); PROTO_ITEM_SET_GENERATED(item); } } else if (!pinfo->fragmented && len >= reported_len && len >= udph->uh_sum_cov && reported_len >= udph->uh_sum_cov && udph->uh_sum_cov >=8) { /* The packet isn't part of a fragmented datagram and isn't truncated, so we can checksum it. XXX - make a bigger scatter-gather list once we do fragment reassembly? */ if (((ip_proto == IP_PROTO_UDP) && (udp_check_checksum)) || ((ip_proto == IP_PROTO_UDPLITE) && (udplite_check_checksum))) { /* Set up the fields of the pseudo-header. */ cksum_vec[0].ptr = (const guint8 *)pinfo->src.data; cksum_vec[0].len = pinfo->src.len; cksum_vec[1].ptr = (const guint8 *)pinfo->dst.data; cksum_vec[1].len = pinfo->dst.len; cksum_vec[2].ptr = (const guint8 *)&phdr; switch (pinfo->src.type) { case AT_IPv4: if (ip_proto == IP_PROTO_UDP) phdr[0] = g_htonl((ip_proto<<16) | udph->uh_ulen); else phdr[0] = g_htonl((ip_proto<<16) | reported_len); cksum_vec[2].len = 4; break; case AT_IPv6: if (ip_proto == IP_PROTO_UDP) phdr[0] = g_htonl(udph->uh_ulen); else phdr[0] = g_htonl(reported_len); phdr[1] = g_htonl(ip_proto); cksum_vec[2].len = 8; break; default: /* UDP runs only atop IPv4 and IPv6.... */ DISSECTOR_ASSERT_NOT_REACHED(); break; } cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, udph->uh_sum_cov); cksum_vec[3].len = udph->uh_sum_cov; computed_cksum = in_cksum(&cksum_vec[0], 4); if (computed_cksum == 0) { item = proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb, offset + 6, 2, udph->uh_sum, "Checksum: 0x%04x [correct]", udph->uh_sum); checksum_tree = proto_item_add_subtree(item, ett_udp_checksum); item = proto_tree_add_boolean(checksum_tree, hf_udp_checksum_good, tvb, offset + 6, 2, TRUE); PROTO_ITEM_SET_GENERATED(item); item = proto_tree_add_boolean(checksum_tree, hf_udp_checksum_bad, tvb, offset + 6, 2, FALSE); PROTO_ITEM_SET_GENERATED(item); } else { item = proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb, offset + 6, 2, udph->uh_sum, "Checksum: 0x%04x [incorrect, should be 0x%04x (maybe caused by \"UDP checksum offload\"?)]", udph->uh_sum, in_cksum_shouldbe(udph->uh_sum, computed_cksum)); checksum_tree = proto_item_add_subtree(item, ett_udp_checksum); item = proto_tree_add_boolean(checksum_tree, hf_udp_checksum_good, tvb, offset + 6, 2, FALSE); PROTO_ITEM_SET_GENERATED(item); item = proto_tree_add_boolean(checksum_tree, hf_udp_checksum_bad, tvb, offset + 6, 2, TRUE); PROTO_ITEM_SET_GENERATED(item); expert_add_info_format(pinfo, item, PI_CHECKSUM, PI_ERROR, "Bad checksum"); col_append_fstr(pinfo->cinfo, COL_INFO, " [UDP CHECKSUM INCORRECT]"); } } else { item = proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb, offset + 6, 2, udph->uh_sum, "Checksum: 0x%04x [validation disabled]", udph->uh_sum); checksum_tree = proto_item_add_subtree(item, ett_udp_checksum); item = proto_tree_add_boolean(checksum_tree, hf_udp_checksum_good, tvb, offset + 6, 2, FALSE); PROTO_ITEM_SET_GENERATED(item); item = proto_tree_add_boolean(checksum_tree, hf_udp_checksum_bad, tvb, offset + 6, 2, FALSE); PROTO_ITEM_SET_GENERATED(item); } } else { item = proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb, offset + 6, 2, udph->uh_sum, "Checksum: 0x%04x [unchecked, not all data available]", udph->uh_sum); checksum_tree = proto_item_add_subtree(item, ett_udp_checksum); item = proto_tree_add_boolean(checksum_tree, hf_udp_checksum_good, tvb, offset + 6, 2, FALSE); PROTO_ITEM_SET_GENERATED(item); item = proto_tree_add_boolean(checksum_tree, hf_udp_checksum_bad, tvb, offset + 6, 2, FALSE); PROTO_ITEM_SET_GENERATED(item); } /* Skip over header */ offset += 8; pinfo->ptype = PT_UDP; pinfo->srcport = udph->uh_sport; pinfo->destport = udph->uh_dport; tap_queue_packet(udp_tap, pinfo, udph); /* find(or create if needed) the conversation for this udp session */ if (udp_process_info) { conv=find_or_create_conversation(pinfo); udpd=get_udp_conversation_data(conv,pinfo); } if (udpd && ((udpd->fwd && udpd->fwd->command) || (udpd->rev && udpd->rev->command))) { ti = proto_tree_add_text(udp_tree, tvb, offset, 0, "Process Information"); PROTO_ITEM_SET_GENERATED(ti); process_tree = proto_item_add_subtree(ti, ett_udp_process_info); if (udpd->fwd && udpd->fwd->command) { proto_tree_add_uint_format_value(process_tree, hf_udp_proc_dst_uid, tvb, 0, 0, udpd->fwd->process_uid, "%u", udpd->fwd->process_uid); proto_tree_add_uint_format_value(process_tree, hf_udp_proc_dst_pid, tvb, 0, 0, udpd->fwd->process_pid, "%u", udpd->fwd->process_pid); proto_tree_add_string_format_value(process_tree, hf_udp_proc_dst_uname, tvb, 0, 0, udpd->fwd->username, "%s", udpd->fwd->username); proto_tree_add_string_format_value(process_tree, hf_udp_proc_dst_cmd, tvb, 0, 0, udpd->fwd->command, "%s", udpd->fwd->command); } if (udpd->rev->command) { proto_tree_add_uint_format_value(process_tree, hf_udp_proc_src_uid, tvb, 0, 0, udpd->rev->process_uid, "%u", udpd->rev->process_uid); proto_tree_add_uint_format_value(process_tree, hf_udp_proc_src_pid, tvb, 0, 0, udpd->rev->process_pid, "%u", udpd->rev->process_pid); proto_tree_add_string_format_value(process_tree, hf_udp_proc_src_uname, tvb, 0, 0, udpd->rev->username, "%s", udpd->rev->username); proto_tree_add_string_format_value(process_tree, hf_udp_proc_src_cmd, tvb, 0, 0, udpd->rev->command, "%s", udpd->rev->command); } } /* * Call sub-dissectors. * * XXX - should we do this if this is included in an error packet? * It might be nice to see the details of the packet that caused the * ICMP error, but it might not be nice to have the dissector update * state based on it. * Also, we probably don't want to run UDP taps on those packets. * * We definitely don't want to do it for an error packet if there's * nothing left in the packet. */ if (!pinfo->flags.in_error_pkt || tvb_length_remaining(tvb, offset) > 0) decode_udp_ports(tvb, offset, pinfo, tree, udph->uh_sport, udph->uh_dport, udph->uh_ulen); }
static int dissect_rx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) { proto_tree *tree; proto_item *item; int offset = 0; struct rxinfo rxinfo; guint8 type; nstime_t ts; guint32 seq, callnumber; guint16 serviceid; /* Ensure we have enough data */ if (tvb_length(tvb) < 28) return 0; /* Make sure it's a known type */ type = tvb_get_guint8(tvb, 20); if (type == 0 || type == 10 || type == 11 || type == 12 || type > 13) return 0; col_set_str(pinfo->cinfo, COL_PROTOCOL, "RX"); col_clear(pinfo->cinfo, COL_INFO); item = proto_tree_add_protocol_format(parent_tree, proto_rx, tvb, offset, 28, "RX Protocol"); tree = proto_item_add_subtree(item, ett_rx); /* epoch : 4 bytes */ rxinfo.epoch = tvb_get_ntohl(tvb, offset); ts.secs = rxinfo.epoch; ts.nsecs = 0; proto_tree_add_time(tree, hf_rx_epoch, tvb, offset, 4, &ts); offset += 4; /* cid : 4 bytes */ rxinfo.cid = tvb_get_ntohl(tvb, offset); proto_tree_add_item(tree, hf_rx_cid, tvb, offset, 4, FALSE); offset += 4; /* callnumber : 4 bytes */ callnumber = tvb_get_ntohl(tvb, offset); proto_tree_add_uint(tree, hf_rx_callnumber, tvb, offset, 4, callnumber); offset += 4; rxinfo.callnumber = callnumber; /* seq : 4 bytes */ seq = tvb_get_ntohl(tvb, offset); proto_tree_add_uint(tree, hf_rx_seq, tvb, offset, 4, seq); offset += 4; rxinfo.seq = seq; /* serial : 4 bytes */ proto_tree_add_item(tree, hf_rx_serial, tvb, offset, 4, FALSE); offset += 4; /* type : 1 byte */ type = tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_rx_type, tvb, offset, 1, type); offset += 1; rxinfo.type = type; /* flags : 1 byte */ offset = dissect_rx_flags(tvb, &rxinfo, tree, offset); /* userstatus : 1 byte */ proto_tree_add_item(tree, hf_rx_userstatus, tvb, offset, 1, FALSE); offset += 1; /* sequrityindex : 1 byte */ proto_tree_add_item(tree, hf_rx_securityindex, tvb, offset, 1, FALSE); offset += 1; /* * How clever: even though the AFS header files indicate that the * serviceId is first, it's really encoded _after_ the spare field. * I wasted a day figuring that out! */ /* spare */ proto_tree_add_item(tree, hf_rx_spare, tvb, offset, 2, FALSE); offset += 2; /* service id : 2 bytes */ serviceid = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(tree, hf_rx_serviceid, tvb, offset, 2, serviceid); offset += 2; rxinfo.serviceid = serviceid; switch (type) { case RX_PACKET_TYPE_ACK: /*dissect_rx_acks(tvb, pinfo, parent_tree, offset, cant create it in a parallell tree, then ett seasrch wont work */ dissect_rx_acks(tvb, pinfo, tree, offset, seq, callnumber); break; case RX_PACKET_TYPE_ACKALL: /* does not contain any payload */ if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "ACKALL " "Seq: %lu " "Call: %lu " "Source Port: %s " "Destination Port: %s ", (unsigned long)seq, (unsigned long)callnumber, get_udp_port(pinfo->srcport), get_udp_port(pinfo->destport) ); } break; case RX_PACKET_TYPE_CHALLENGE: dissect_rx_challenge(tvb, pinfo, tree, offset, seq, callnumber); break; case RX_PACKET_TYPE_RESPONSE: dissect_rx_response(tvb, pinfo, tree, offset, seq, callnumber); break; case RX_PACKET_TYPE_DATA: { tvbuff_t *next_tvb; void* pd_save; pd_save = pinfo->private_data; pinfo->private_data = &rxinfo; next_tvb = tvb_new_subset_remaining(tvb, offset); call_dissector(afs_handle, next_tvb, pinfo, parent_tree); pinfo->private_data = pd_save; }; break; case RX_PACKET_TYPE_ABORT: dissect_rx_abort(tvb, pinfo, tree, offset, seq, callnumber); break; } return(tvb_length(tvb)); }
static int dissect_rx_acks(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset, guint32 seq, guint32 callnumber) { proto_tree *tree; proto_item *item; guint8 num; int old_offset = offset; if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "ACK " "Seq: %lu " "Call: %lu " "Source Port: %s " "Destination Port: %s ", (unsigned long)seq, (unsigned long)callnumber, get_udp_port(pinfo->srcport), get_udp_port(pinfo->destport) ); } item = proto_tree_add_item(parent_tree, hf_rx_ack, tvb, offset, -1, FALSE); tree = proto_item_add_subtree(item, ett_rx_ack); /* bufferspace: 2 bytes*/ proto_tree_add_item(tree, hf_rx_bufferspace, tvb, offset, 2, FALSE); offset += 2; /* maxskew: 2 bytes*/ proto_tree_add_item(tree, hf_rx_maxskew, tvb, offset, 2, FALSE); offset += 2; /* first packet: 4 bytes*/ proto_tree_add_item(tree, hf_rx_first_packet, tvb, offset, 4, FALSE); offset += 4; /* prev packet: 4 bytes*/ proto_tree_add_item(tree, hf_rx_prev_packet, tvb, offset, 4, FALSE); offset += 4; /* serial : 4 bytes */ proto_tree_add_item(tree, hf_rx_serial, tvb, offset, 4, FALSE); offset += 4; /* reason : 1 byte */ proto_tree_add_item(tree, hf_rx_reason, tvb, offset, 1, FALSE); offset += 1; /* nACKs */ num = tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_rx_numacks, tvb, offset, 1, num); offset += 1; while(num--){ proto_tree_add_item(tree, hf_rx_ack_type, tvb, offset, 1, FALSE); offset += 1; } /* Some implementations adds some extra fields. * As far as I can see, these first add 3 padding bytes and then * up to 4 32-bit values. (0,3,4 have been witnessed) * * RX as a protocol seems to be completely nondefined and seems to lack * any sort of documentation other than "read the source of any of the * (compatible?) implementations. */ if (tvb_length_remaining(tvb, offset)>3) { offset += 3; /* guess. some implementations adds 3 bytes */ if (tvb_reported_length_remaining(tvb, offset) >= 4){ proto_tree_add_item(tree, hf_rx_ifmtu, tvb, offset, 4, FALSE); offset += 4; } if (tvb_reported_length_remaining(tvb, offset) >= 4){ proto_tree_add_item(tree, hf_rx_maxmtu, tvb, offset, 4, FALSE); offset += 4; } if (tvb_reported_length_remaining(tvb, offset) >= 4){ proto_tree_add_item(tree, hf_rx_rwind, tvb, offset, 4, FALSE); offset += 4; } if (tvb_reported_length_remaining(tvb, offset) >= 4){ proto_tree_add_item(tree, hf_rx_maxpackets, tvb, offset, 4, FALSE); offset += 4; } } proto_item_set_len(item, offset-old_offset); return offset; }