/* Code to actually dissect the packets */ static void dissect_mdshdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti_main, *ti_hdr, *ti_trlr; proto_item *hidden_item; proto_tree *mdshdr_tree_main, *mdshdr_tree_hdr, *mdshdr_tree_trlr; int offset = 0; guint pktlen; tvbuff_t *next_tvb; guint8 sof, eof; guint16 vsan; guint8 span_id; int trailer_start = 0; /*0 means "no trailer found"*/ /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MDS Header"); col_clear(pinfo->cinfo, COL_INFO); sof = tvb_get_guint8 (tvb, offset+MDSHDR_SOF_OFFSET) & 0x0F; pktlen = tvb_get_ntohs (tvb, offset+MDSHDR_PKTLEN_OFFSET) & 0x1FFF; vsan = tvb_get_ntohs (tvb, offset+MDSHDR_VSAN_OFFSET) & 0x0FFF; span_id = (tvb_get_ntohs (tvb, offset+MDSHDR_VSAN_OFFSET) & 0xF000) >> 12; /* The Mdshdr trailer is at the end of the frame */ if (tvb_length (tvb) >= MDSHDR_HEADER_SIZE + pktlen /* Avoid header/trailer overlap if something wrong */ && pktlen >= MDSHDR_TRAILER_SIZE ) { trailer_start = MDSHDR_HEADER_SIZE + pktlen - MDSHDR_TRAILER_SIZE; eof = tvb_get_guint8 (tvb, trailer_start); tvb_set_reported_length (tvb, MDSHDR_HEADER_SIZE+pktlen); } else { eof = MDSHDR_EOF_UNKNOWN; } pinfo->src_idx = (tvb_get_ntohs (tvb, MDSHDR_SIDX_OFFSET) & 0x3FF); pinfo->dst_idx = (tvb_get_ntohs (tvb, MDSHDR_DIDX_OFFSET) & 0xFFC) >> 2; pinfo->vsan = vsan; pinfo->sof_eof = 0; if ((sof == MDSHDR_SOFi3) || (sof == MDSHDR_SOFi2) || (sof == MDSHDR_SOFi1) || (sof == MDSHDR_SOFi4)) { pinfo->sof_eof = PINFO_SOF_FIRST_FRAME; } else if (sof == MDSHDR_SOFf) { pinfo->sof_eof = PINFO_SOF_SOFF; } if (eof != MDSHDR_EOFn) { pinfo->sof_eof |= PINFO_EOF_LAST_FRAME; } else if (eof != MDSHDR_EOFt) { pinfo->sof_eof |= PINFO_EOF_INVALID; } /* In the interest of speed, if "tree" is NULL, don't do any work not necessary to generate protocol tree items. */ if (tree) { /* create display subtree for the protocol */ ti_main = proto_tree_add_protocol_format (tree, proto_mdshdr, tvb, 0, MDSHDR_HEADER_SIZE+pktlen, "MDS Header(%s/%s)", val_to_str(sof, sof_vals, "Unknown(%u)"), val_to_str(eof, eof_vals, "Unknown(%u)")); mdshdr_tree_main = proto_item_add_subtree (ti_main, ett_mdshdr); /* Add Header part as subtree first */ ti_hdr = proto_tree_add_text (mdshdr_tree_main, tvb, MDSHDR_VER_OFFSET, MDSHDR_HEADER_SIZE, "MDS Header"); mdshdr_tree_hdr = proto_item_add_subtree (ti_hdr, ett_mdshdr_hdr); hidden_item = proto_tree_add_item (mdshdr_tree_hdr, hf_mdshdr_sof, tvb, MDSHDR_SOF_OFFSET, MDSHDR_SIZE_BYTE, 0); PROTO_ITEM_SET_HIDDEN(hidden_item); proto_tree_add_item (mdshdr_tree_hdr, hf_mdshdr_pkt_len, tvb, MDSHDR_PKTLEN_OFFSET, MDSHDR_SIZE_INT16, 0); proto_tree_add_item (mdshdr_tree_hdr, hf_mdshdr_dstidx, tvb, MDSHDR_DIDX_OFFSET, MDSHDR_SIZE_INT16, 0); proto_tree_add_item (mdshdr_tree_hdr, hf_mdshdr_srcidx, tvb, MDSHDR_SIDX_OFFSET, MDSHDR_SIZE_INT16, 0); proto_tree_add_item (mdshdr_tree_hdr, hf_mdshdr_vsan, tvb, MDSHDR_VSAN_OFFSET, MDSHDR_SIZE_INT16, 0); hidden_item = proto_tree_add_uint(mdshdr_tree_hdr, hf_mdshdr_span, tvb, MDSHDR_VSAN_OFFSET, MDSHDR_SIZE_BYTE, span_id); PROTO_ITEM_SET_HIDDEN(hidden_item); /* Add Mdshdr Trailer part */ if (tvb_length (tvb) >= MDSHDR_HEADER_SIZE + pktlen && 0 != trailer_start) { ti_trlr = proto_tree_add_text (mdshdr_tree_main, tvb, trailer_start, MDSHDR_TRAILER_SIZE, "MDS Trailer"); mdshdr_tree_trlr = proto_item_add_subtree (ti_trlr, ett_mdshdr_trlr); proto_tree_add_item (mdshdr_tree_trlr, hf_mdshdr_eof, tvb, trailer_start, MDSHDR_SIZE_BYTE, 0); proto_tree_add_item (mdshdr_tree_trlr, hf_mdshdr_fccrc, tvb, trailer_start+2, MDSHDR_SIZE_INT32, 0); } else { proto_tree_add_text (mdshdr_tree_main, tvb, 0, 0, "MDS Trailer: Not Found"); } } /* If this protocol has a sub-dissector call it here, see section 1.8 */ if (tvb_length (tvb) >= MDSHDR_HEADER_SIZE + pktlen && 0 != pktlen /*if something wrong*/) { next_tvb = tvb_new_subset (tvb, MDSHDR_HEADER_SIZE, pktlen, pktlen); /* XXX what to do with the rest of this frame? --ArtemTamazov */ } else { next_tvb = tvb_new_subset_remaining (tvb, MDSHDR_HEADER_SIZE); } /* Call the Fibre Channel dissector */ if (fc_dissector_handle) { call_dissector (fc_dissector_handle, next_tvb, pinfo, tree); } else { call_dissector (data_handle, next_tvb, pinfo, tree); } }
static void dissect_arp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint16 ar_hrd; guint16 ar_pro; guint8 ar_hln; guint8 ar_pln; guint16 ar_op; int tot_len; proto_tree *arp_tree = NULL; proto_item *ti, *item; const gchar *op_str; int sha_offset, spa_offset, tha_offset, tpa_offset; const guint8 *spa_val, *tpa_val; gboolean is_gratuitous; gboolean duplicate_detected = FALSE; guint32 duplicate_ip = 0; /* Call it ARP, for now, so that if we throw an exception before we decide whether it's ARP or RARP or IARP or ATMARP, it shows up in the packet list as ARP. Clear the Info column so that, if we throw an exception, it shows up as a short or malformed ARP frame. */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "ARP"); col_clear(pinfo->cinfo, COL_INFO); /* Hardware Address Type */ ar_hrd = tvb_get_ntohs(tvb, AR_HRD); if (ar_hrd == ARPHRD_ATM2225) { call_dissector(atmarp_handle, tvb, pinfo, tree); return; } /* Protocol Address Type */ ar_pro = tvb_get_ntohs(tvb, AR_PRO); /* Hardware Address Size */ ar_hln = tvb_get_guint8(tvb, AR_HLN); /* Protocol Address Size */ ar_pln = tvb_get_guint8(tvb, AR_PLN); /* Operation */ ar_op = tvb_get_ntohs(tvb, AR_OP); tot_len = MIN_ARP_HEADER_SIZE + ar_hln*2 + ar_pln*2; /* Adjust the length of this tvbuff to include only the ARP datagram. Our caller may use that to determine how much of its packet was padding. */ tvb_set_reported_length(tvb, tot_len); if (check_col(pinfo->cinfo, COL_PROTOCOL)) { switch (ar_op) { case ARPOP_REQUEST: if (global_arp_detect_request_storm) { request_seen(pinfo); } /* FALLTHRU */ case ARPOP_REPLY: default: col_set_str(pinfo->cinfo, COL_PROTOCOL, "ARP"); break; case ARPOP_RREQUEST: case ARPOP_RREPLY: col_set_str(pinfo->cinfo, COL_PROTOCOL, "RARP"); break; case ARPOP_IREQUEST: case ARPOP_IREPLY: col_set_str(pinfo->cinfo, COL_PROTOCOL, "Inverse ARP"); break; } } /* Get the offsets of the addresses. */ /* Source Hardware Address */ sha_offset = MIN_ARP_HEADER_SIZE; /* Source Protocol Address */ spa_offset = sha_offset + ar_hln; /* Target Hardware Address */ tha_offset = spa_offset + ar_pln; /* Target Protocol Address */ tpa_offset = tha_offset + ar_hln; if ((ar_op == ARPOP_REPLY || ar_op == ARPOP_REQUEST) && ARP_HW_IS_ETHER(ar_hrd, ar_hln) && ARP_PRO_IS_IPv4(ar_pro, ar_pln)) { /* inform resolv.c module of the new discovered addresses */ guint32 ip; const guint8 *mac; /* Add sender address if sender MAC address is neither a broadcast/ multicast address nor an all-zero address and if sender IP address isn't all zeroes. */ ip = tvb_get_ipv4(tvb, spa_offset); mac = tvb_get_ptr(tvb, sha_offset, 6); if ((mac[0] & 0x01) == 0 && memcmp(mac, mac_allzero, 6) != 0 && ip != 0) { add_ether_byip(ip, mac); if (global_arp_detect_duplicate_ip_addresses) { duplicate_detected = check_for_duplicate_addresses(pinfo, tree, tvb, mac, ip, &duplicate_ip); } } /* Add target address if target MAC address is neither a broadcast/ multicast address nor an all-zero address and if target IP address isn't all zeroes. */ /* Do not add target address if the packet is a Request. According to the RFC, target addresses in requests have no meaning */ ip = tvb_get_ipv4(tvb, tpa_offset); mac = tvb_get_ptr(tvb, tha_offset, 6); if ((mac[0] & 0x01) == 0 && memcmp(mac, mac_allzero, 6) != 0 && ip != 0 && ar_op != ARPOP_REQUEST) { add_ether_byip(ip, mac); if (global_arp_detect_duplicate_ip_addresses) { duplicate_detected = check_for_duplicate_addresses(pinfo, tree, tvb, mac, ip, &duplicate_ip); } } } if (!tree && !check_col(pinfo->cinfo, COL_INFO)) { /* We're not building a protocol tree and we're not setting the Info column, so we don't have any more work to do. */ return; } spa_val = tvb_get_ptr(tvb, spa_offset, ar_pln); tpa_val = tvb_get_ptr(tvb, tpa_offset, ar_pln); /* ARP requests/replies with the same sender and target protocol address are flagged as "gratuitous ARPs", i.e. ARPs sent out as, in effect, an announcement that the machine has MAC address XX:XX:XX:XX:XX:XX and IPv4 address YY.YY.YY.YY. Requests are to provoke complaints if some other machine has the same IPv4 address, replies are used to announce relocation of network address, like in failover solutions. */ if (((ar_op == ARPOP_REQUEST) || (ar_op == ARPOP_REPLY)) && (memcmp(spa_val, tpa_val, ar_pln) == 0)) is_gratuitous = TRUE; else is_gratuitous = FALSE; if (check_col(pinfo->cinfo, COL_INFO)) { switch (ar_op) { case ARPOP_REQUEST: if (is_gratuitous) col_add_fstr(pinfo->cinfo, COL_INFO, "Gratuitous ARP for %s (Request)", arpproaddr_to_str(tpa_val, ar_pln, ar_pro)); else col_add_fstr(pinfo->cinfo, COL_INFO, "Who has %s? Tell %s", arpproaddr_to_str(tpa_val, ar_pln, ar_pro), arpproaddr_to_str(spa_val, ar_pln, ar_pro)); break; case ARPOP_REPLY: if (is_gratuitous) col_add_fstr(pinfo->cinfo, COL_INFO, "Gratuitous ARP for %s (Reply)", arpproaddr_to_str(spa_val, ar_pln, ar_pro)); else col_add_fstr(pinfo->cinfo, COL_INFO, "%s is at %s", arpproaddr_to_str(spa_val, ar_pln, ar_pro), tvb_arphrdaddr_to_str(tvb, sha_offset, ar_hln, ar_hrd)); break; case ARPOP_RREQUEST: case ARPOP_IREQUEST: col_add_fstr(pinfo->cinfo, COL_INFO, "Who is %s? Tell %s", tvb_arphrdaddr_to_str(tvb, tha_offset, ar_hln, ar_hrd), tvb_arphrdaddr_to_str(tvb, sha_offset, ar_hln, ar_hrd)); break; case ARPOP_RREPLY: col_add_fstr(pinfo->cinfo, COL_INFO, "%s is at %s", tvb_arphrdaddr_to_str(tvb, tha_offset, ar_hln, ar_hrd), arpproaddr_to_str(tpa_val, ar_pln, ar_pro)); break; case ARPOP_IREPLY: col_add_fstr(pinfo->cinfo, COL_INFO, "%s is at %s", tvb_arphrdaddr_to_str(tvb, sha_offset, ar_hln, ar_hrd), arpproaddr_to_str(spa_val, ar_pln, ar_pro)); break; default: col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown ARP opcode 0x%04x", ar_op); break; } } if (tree) { if ((op_str = match_strval(ar_op, op_vals))) { if (is_gratuitous && (ar_op == ARPOP_REQUEST)) op_str = "request/gratuitous ARP"; if (is_gratuitous && (ar_op == ARPOP_REPLY)) op_str = "reply/gratuitous ARP"; ti = proto_tree_add_protocol_format(tree, proto_arp, tvb, 0, tot_len, "Address Resolution Protocol (%s)", op_str); } else ti = proto_tree_add_protocol_format(tree, proto_arp, tvb, 0, tot_len, "Address Resolution Protocol (opcode 0x%04x)", ar_op); arp_tree = proto_item_add_subtree(ti, ett_arp); proto_tree_add_uint(arp_tree, hf_arp_hard_type, tvb, AR_HRD, 2, ar_hrd); proto_tree_add_uint(arp_tree, hf_arp_proto_type, tvb, AR_PRO, 2, ar_pro); proto_tree_add_uint(arp_tree, hf_arp_hard_size, tvb, AR_HLN, 1, ar_hln); proto_tree_add_uint(arp_tree, hf_arp_proto_size, tvb, AR_PLN, 1, ar_pln); proto_tree_add_uint(arp_tree, hf_arp_opcode, tvb, AR_OP, 2, ar_op); item = proto_tree_add_boolean(arp_tree, hf_arp_isgratuitous, tvb, 0, 0, is_gratuitous); PROTO_ITEM_SET_GENERATED(item); if (ar_hln != 0) { proto_tree_add_item(arp_tree, ARP_HW_IS_ETHER(ar_hrd, ar_hln) ? hf_arp_src_hw_mac : hf_arp_src_hw, tvb, sha_offset, ar_hln, FALSE); } if (ar_pln != 0) { proto_tree_add_item(arp_tree, ARP_PRO_IS_IPv4(ar_pro, ar_pln) ? hf_arp_src_proto_ipv4 : hf_arp_src_proto, tvb, spa_offset, ar_pln, FALSE); } if (ar_hln != 0) { proto_tree_add_item(arp_tree, ARP_HW_IS_ETHER(ar_hrd, ar_hln) ? hf_arp_dst_hw_mac : hf_arp_dst_hw, tvb, tha_offset, ar_hln, FALSE); } if (ar_pln != 0) { proto_tree_add_item(arp_tree, ARP_PRO_IS_IPv4(ar_pro, ar_pln) ? hf_arp_dst_proto_ipv4 : hf_arp_dst_proto, tvb, tpa_offset, ar_pln, FALSE); } } if (global_arp_detect_request_storm) { check_for_storm_count(tvb, pinfo, arp_tree); } if (duplicate_detected) { /* Also indicate in info column */ if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, " (duplicate use of %s detected!)", arpproaddr_to_str((guint8*)&duplicate_ip, 4, ETHERTYPE_IP)); } } }
/* Code to actually dissect the packets */ static void dissect_brdwlk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti, *hidden_item; proto_tree *brdwlk_tree = NULL; tvbuff_t *next_tvb; guint8 error, eof, sof; int hdrlen = 2, offset = 0; gint len, reported_len, plen; guint16 pkt_cnt; gboolean dropped_packets; /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "Boardwalk"); col_clear(pinfo->cinfo, COL_INFO); pinfo->vsan = (tvb_get_ntohs (tvb, offset) & 0xFFF); sof = (tvb_get_guint8 (tvb, offset) & 0xF0) >> 4; if ((sof == FCM_DELIM_SOFI3) || (sof == FCM_DELIM_SOFI2) || (sof == FCM_DELIM_SOFI1) || (sof == FCM_DELIM_SOFI4)) { pinfo->sof_eof = PINFO_SOF_FIRST_FRAME; } else if (sof == FCM_DELIM_SOFF) { pinfo->sof_eof = PINFO_SOF_SOFF; } if (tree) { ti = proto_tree_add_protocol_format (tree, proto_brdwlk, tvb, 0, hdrlen, "Boardwalk"); brdwlk_tree = proto_item_add_subtree (ti, ett_brdwlk); proto_tree_add_item (brdwlk_tree, hf_brdwlk_sof, tvb, offset, 1, 0); proto_tree_add_item (brdwlk_tree, hf_brdwlk_vsan, tvb, offset, 2, 0); } /* Locate EOF which is the last 4 bytes of the frame */ len = tvb_length_remaining(tvb, hdrlen); reported_len = tvb_reported_length_remaining(tvb, hdrlen); if (reported_len < 4) { /* * This packet is claimed not to even have enough data for * a 4-byte EOF. * Don't try to process the EOF. */ ; } else if (len < reported_len) { /* * This packet is claimed to have enough data for a 4-byte EOF, * but we didn't capture all of the packet. * Slice off the 4-byte EOF from the reported length, and trim * the captured length so it's no more than the reported length; * that will slice off what of the EOF, if any, is in the * captured length. */ reported_len -= 4; if (len > reported_len) len = reported_len; } else { /* * We have the entire packet, and it includes a 4-byte EOF. * Slice it off, and put it into the tree if we're building * a tree. */ len -= 4; reported_len -= 4; offset = tvb_reported_length(tvb) - 4; pkt_cnt = tvb_get_ntohs (tvb, offset); if (tree) { proto_tree_add_uint (brdwlk_tree, hf_brdwlk_pktcnt, tvb, offset, 2, pkt_cnt); } dropped_packets = FALSE; if (pinfo->fd->flags.visited) { /* * This isn't the first pass, so we can't use the global * "packet_count" variable to determine whether there were * any dropped frames or not. * We therefore attach a non-null pointer as frame data to * any frame preceded by dropped packets. */ if (p_get_proto_data(pinfo->fd, proto_brdwlk) != NULL) dropped_packets = TRUE; } else { /* * This is the first pass, so we have to use the global * "packet_count" variable to determine whether there were * any dropped frames or not. * * XXX - can there be more than one stream of packets, so that * we can't just use a global variable? */ if (pkt_cnt != packet_count + 1) { if (!first_pkt && (pkt_cnt != 0 || (packet_count != BRDWLK_MAX_PACKET_CNT))) { dropped_packets = TRUE; /* * Mark this frame as having been preceded by dropped * packets. (The data we use as the frame data doesn't * matter - it just matters that it's non-null.) */ p_add_proto_data(pinfo->fd, proto_brdwlk, &packet_count); } } if (tree) { hidden_item = proto_tree_add_boolean (brdwlk_tree, hf_brdwlk_drop, tvb, offset, 0, dropped_packets); PROTO_ITEM_SET_HIDDEN(hidden_item); } } packet_count = pkt_cnt; error=tvb_get_guint8(tvb, offset+2); dissect_brdwlk_err(brdwlk_tree, tvb, offset+2); eof = tvb_get_guint8 (tvb, offset+3); if (eof != FCM_DELIM_EOFN) { pinfo->sof_eof |= PINFO_EOF_LAST_FRAME; } else if (eof != FCM_DELIM_EOFT) { pinfo->sof_eof |= PINFO_EOF_INVALID; } if (tree) { proto_tree_add_item (brdwlk_tree, hf_brdwlk_eof, tvb, offset+3, 1, 0); } if ((error & BRDWLK_HAS_PLEN) && tree) { /* In newer Boardwalks, if this bit is set, the actual frame length * is also provided. This length is the size between SOF & EOF * including FC CRC. */ plen = tvb_get_ntohl (tvb, offset-4); plen *= 4; proto_tree_add_uint (brdwlk_tree, hf_brdwlk_plen, tvb, offset-4, 4, plen); #if 0 /* XXX - this would throw an exception if it would increase * the reported length. */ if (error & BRDWLK_TRUNCATED_BIT) { tvb_set_reported_length (tvb, plen); } #endif } } next_tvb = tvb_new_subset (tvb, 2, len, reported_len); if (fc_dissector_handle) { call_dissector (fc_dissector_handle, next_tvb, pinfo, tree); } }
/* * RFC 2225 ATMARP - it's just like ARP, except where it isn't. */ static void dissect_atmarp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint16 ar_hrd; guint16 ar_pro; guint8 ar_shtl; guint8 ar_shl; guint8 ar_sstl; guint8 ar_ssl; guint16 ar_op; guint8 ar_spln; guint8 ar_thtl; guint8 ar_thl; guint8 ar_tstl; guint8 ar_tsl; guint8 ar_tpln; int tot_len; proto_tree *arp_tree; proto_item *ti; const gchar *op_str; int sha_offset, ssa_offset, spa_offset; int tha_offset, tsa_offset, tpa_offset; const guint8 *sha_val, *ssa_val, *spa_val; const guint8 *tha_val, *tsa_val, *tpa_val; const gchar *sha_str, *ssa_str, *spa_str; const gchar *tha_str, *tsa_str, *tpa_str; proto_tree *tl_tree; proto_item *tl; /* Override the setting to "ARP/RARP". */ pinfo->current_proto = "ATMARP"; ar_hrd = tvb_get_ntohs(tvb, ATM_AR_HRD); ar_pro = tvb_get_ntohs(tvb, ATM_AR_PRO); ar_shtl = tvb_get_guint8(tvb, ATM_AR_SHTL); ar_shl = ar_shtl & ATMARP_LEN_MASK; ar_sstl = tvb_get_guint8(tvb, ATM_AR_SSTL); ar_ssl = ar_sstl & ATMARP_LEN_MASK; ar_op = tvb_get_ntohs(tvb, AR_OP); ar_spln = tvb_get_guint8(tvb, ATM_AR_SPLN); ar_thtl = tvb_get_guint8(tvb, ATM_AR_THTL); ar_thl = ar_thtl & ATMARP_LEN_MASK; ar_tstl = tvb_get_guint8(tvb, ATM_AR_TSTL); ar_tsl = ar_tstl & ATMARP_LEN_MASK; ar_tpln = tvb_get_guint8(tvb, ATM_AR_TPLN); tot_len = MIN_ATMARP_HEADER_SIZE + ar_shl + ar_ssl + ar_spln + ar_thl + ar_tsl + ar_tpln; /* Adjust the length of this tvbuff to include only the ARP datagram. Our caller may use that to determine how much of its packet was padding. */ tvb_set_reported_length(tvb, tot_len); /* Extract the addresses. */ sha_offset = MIN_ATMARP_HEADER_SIZE; if (ar_shl != 0) { sha_val = tvb_get_ptr(tvb, sha_offset, ar_shl); sha_str = atmarpnum_to_str(sha_val, ar_shtl); } else { sha_val = NULL; sha_str = "<No address>"; } ssa_offset = sha_offset + ar_shl; if (ar_ssl != 0) { ssa_val = tvb_get_ptr(tvb, ssa_offset, ar_ssl); ssa_str = atmarpsubaddr_to_str(ssa_val, ar_sstl); } else { ssa_val = NULL; ssa_str = NULL; } spa_offset = ssa_offset + ar_ssl; spa_val = tvb_get_ptr(tvb, spa_offset, ar_spln); spa_str = arpproaddr_to_str(spa_val, ar_spln, ar_pro); tha_offset = spa_offset + ar_spln; if (ar_thl != 0) { tha_val = tvb_get_ptr(tvb, tha_offset, ar_thl); tha_str = atmarpnum_to_str(tha_val, ar_thtl); } else { tha_val = NULL; tha_str = "<No address>"; } tsa_offset = tha_offset + ar_thl; if (ar_tsl != 0) { tsa_val = tvb_get_ptr(tvb, tsa_offset, ar_tsl); tsa_str = atmarpsubaddr_to_str(tsa_val, ar_tstl); } else { tsa_val = NULL; tsa_str = NULL; } tpa_offset = tsa_offset + ar_tsl; tpa_val = tvb_get_ptr(tvb, tpa_offset, ar_tpln); tpa_str = arpproaddr_to_str(tpa_val, ar_tpln, ar_pro); if (check_col(pinfo->cinfo, COL_PROTOCOL)) { switch (ar_op) { case ARPOP_REQUEST: case ARPOP_REPLY: case ATMARPOP_NAK: default: col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATMARP"); break; case ARPOP_RREQUEST: case ARPOP_RREPLY: col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATMRARP"); break; case ARPOP_IREQUEST: case ARPOP_IREPLY: col_set_str(pinfo->cinfo, COL_PROTOCOL, "Inverse ATMARP"); break; } } if (check_col(pinfo->cinfo, COL_INFO)) { switch (ar_op) { case ARPOP_REQUEST: col_add_fstr(pinfo->cinfo, COL_INFO, "Who has %s? Tell %s", tpa_str, spa_str); break; case ARPOP_REPLY: col_add_fstr(pinfo->cinfo, COL_INFO, "%s is at %s%s%s", spa_str, sha_str, ((ssa_str != NULL) ? "," : ""), ((ssa_str != NULL) ? ssa_str : "")); break; case ARPOP_IREQUEST: col_add_fstr(pinfo->cinfo, COL_INFO, "Who is %s%s%s? Tell %s%s%s", tha_str, ((tsa_str != NULL) ? "," : ""), ((tsa_str != NULL) ? tsa_str : ""), sha_str, ((ssa_str != NULL) ? "," : ""), ((ssa_str != NULL) ? ssa_str : "")); break; case ARPOP_IREPLY: col_add_fstr(pinfo->cinfo, COL_INFO, "%s%s%s is at %s", sha_str, ((ssa_str != NULL) ? "," : ""), ((ssa_str != NULL) ? ssa_str : ""), spa_str); break; case ATMARPOP_NAK: col_add_fstr(pinfo->cinfo, COL_INFO, "I don't know where %s is", spa_str); break; default: col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown ATMARP opcode 0x%04x", ar_op); break; } } if (tree) { if ((op_str = match_strval(ar_op, atmop_vals))) ti = proto_tree_add_protocol_format(tree, proto_arp, tvb, 0, tot_len, "ATM Address Resolution Protocol (%s)", op_str); else ti = proto_tree_add_protocol_format(tree, proto_arp, tvb, 0, tot_len, "ATM Address Resolution Protocol (opcode 0x%04x)", ar_op); arp_tree = proto_item_add_subtree(ti, ett_arp); proto_tree_add_uint(arp_tree, hf_arp_hard_type, tvb, ATM_AR_HRD, 2, ar_hrd); proto_tree_add_uint(arp_tree, hf_arp_proto_type, tvb, ATM_AR_PRO, 2,ar_pro); tl = proto_tree_add_text(arp_tree, tvb, ATM_AR_SHTL, 1, "Sender ATM number type/length: %s/%u", (ar_shtl & ATMARP_IS_E164 ? "E.164" : "ATM Forum NSAPA"), ar_shl); tl_tree = proto_item_add_subtree(tl, ett_atmarp_tl); proto_tree_add_boolean(tl_tree, hf_atmarp_sht, tvb, ATM_AR_SHTL, 1, ar_shtl); proto_tree_add_uint(tl_tree, hf_atmarp_shl, tvb, ATM_AR_SHTL, 1, ar_shtl); tl = proto_tree_add_text(arp_tree, tvb, ATM_AR_SSTL, 1, "Sender ATM subaddress type/length: %s/%u", (ar_sstl & ATMARP_IS_E164 ? "E.164" : "ATM Forum NSAPA"), ar_ssl); tl_tree = proto_item_add_subtree(tl, ett_atmarp_tl); proto_tree_add_boolean(tl_tree, hf_atmarp_sst, tvb, ATM_AR_SSTL, 1, ar_sstl); proto_tree_add_uint(tl_tree, hf_atmarp_ssl, tvb, ATM_AR_SSTL, 1, ar_sstl); proto_tree_add_uint(arp_tree, hf_arp_opcode, tvb, AR_OP, 2, ar_op); proto_tree_add_uint(arp_tree, hf_atmarp_spln, tvb, ATM_AR_SPLN, 1, ar_spln); tl = proto_tree_add_text(arp_tree, tvb, ATM_AR_THTL, 1, "Target ATM number type/length: %s/%u", (ar_thtl & ATMARP_IS_E164 ? "E.164" : "ATM Forum NSAPA"), ar_thl); tl_tree = proto_item_add_subtree(tl, ett_atmarp_tl); proto_tree_add_boolean(tl_tree, hf_atmarp_tht, tvb, ATM_AR_THTL, 1, ar_thtl); proto_tree_add_uint(tl_tree, hf_atmarp_thl, tvb, ATM_AR_THTL, 1, ar_thtl); tl = proto_tree_add_text(arp_tree, tvb, ATM_AR_TSTL, 1, "Target ATM subaddress type/length: %s/%u", (ar_tstl & ATMARP_IS_E164 ? "E.164" : "ATM Forum NSAPA"), ar_tsl); tl_tree = proto_item_add_subtree(tl, ett_atmarp_tl); proto_tree_add_boolean(tl_tree, hf_atmarp_tst, tvb, ATM_AR_TSTL, 1, ar_tstl); proto_tree_add_uint(tl_tree, hf_atmarp_tsl, tvb, ATM_AR_TSTL, 1, ar_tstl); proto_tree_add_uint(arp_tree, hf_atmarp_tpln, tvb, ATM_AR_TPLN, 1, ar_tpln); if (ar_shl != 0) dissect_atm_number(tvb, sha_offset, ar_shtl, hf_atmarp_src_atm_num_e164, hf_atmarp_src_atm_num_nsap, arp_tree); if (ar_ssl != 0) proto_tree_add_bytes_format(arp_tree, hf_atmarp_src_atm_subaddr, tvb, ssa_offset, ar_ssl, ssa_val, "Sender ATM subaddress: %s", ssa_str); if (ar_spln != 0) { proto_tree_add_item(arp_tree, ARP_PRO_IS_IPv4(ar_pro, ar_spln) ? hf_arp_src_proto_ipv4 : hf_arp_src_proto, tvb, spa_offset, ar_spln, FALSE); } if (ar_thl != 0) dissect_atm_number(tvb, tha_offset, ar_thtl, hf_atmarp_dst_atm_num_e164, hf_atmarp_dst_atm_num_nsap, arp_tree); if (ar_tsl != 0) proto_tree_add_bytes_format(arp_tree, hf_atmarp_dst_atm_subaddr, tvb, tsa_offset, ar_tsl, tsa_val, "Target ATM subaddress: %s", tsa_str); if (ar_tpln != 0) { proto_tree_add_item(arp_tree, ARP_PRO_IS_IPv4(ar_pro, ar_tpln) ? hf_arp_dst_proto_ipv4 : hf_arp_dst_proto, tvb, tpa_offset, ar_tpln, FALSE); } } }
/* Code to actually dissect the packets */ static void dissect_hsr_prp_supervision(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_tree *hsr_prp_supervision_tree; guint8 tlv_type; guint8 tlv_length; guint16 sup_version; int offset; col_set_str(pinfo->cinfo, COL_PROTOCOL, "HSR/PRP"); /* may get modified later while parsing */ col_set_str(pinfo->cinfo, COL_INFO, "HSR or PRP Supervision"); /* create display subtree for the protocol */ ti = proto_tree_add_item(tree, proto_hsr_prp_supervision, tvb, 0, -1, ENC_NA); hsr_prp_supervision_tree = proto_item_add_subtree(ti, ett_hsr_prp_supervision); offset = 0; /* SupVersion */ proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_path, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_version, tvb, offset, 2, ENC_BIG_ENDIAN); sup_version = tvb_get_ntohs(tvb, 0) & 0x0fff; offset += 2; if (sup_version > 0) { /* SupSequenceNumber */ proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_seqno, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; } while (tvb_reported_length_remaining(tvb, offset) > 0) { /* TLV.type */ tlv_type = tvb_get_guint8(tvb, offset); proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_tlv_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /* TLV.length */ tlv_length = tvb_get_guint8(tvb, offset); proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_tlv_length, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /* TLV.value */ if ((tlv_type == 20 || tlv_type == 21 || tlv_type == 23) && (tlv_length == 6 || tlv_length == 12)) { if (tlv_type == 23) { col_set_str(pinfo->cinfo, COL_INFO, "HSR Supervision"); } else { col_set_str(pinfo->cinfo, COL_INFO, "PRP Supervision"); } if (tlv_length == 12) { /* MacAddressA, MacAddressB (PRP only) */ proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_source_mac_address_A, tvb, offset, 6, ENC_NA); proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_source_mac_address_B, tvb, offset+6, 6, ENC_NA); /* PRP-0 supervision: if the node is not a RedBox, we have just read the last TLV. The next two octets are required to be zero by PRP-0. We will dissect those as "end of list" and break. */ } else { /* MacAddress */ proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_source_mac_address, tvb, offset, 6, ENC_NA); } } else if (tlv_type == 30 && tlv_length == 6) { /* RedBoxMacAddress */ proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_red_box_mac_address, tvb, offset, 6, ENC_NA); if (sup_version == 0) { /* PRP-0 supervision: end of TLV data. Stop now, don't interpret the padding. */ offset += tlv_length; break; } } else if (tlv_type == 31 && tlv_length == 6) { /* VdanMacAddress */ proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_vdan_mac_address, tvb, offset, 6, ENC_NA); if (sup_version == 0) { /* PRP-0 supervision: end of TLV data, padding starts */ offset += tlv_length; break; } } else if (tlv_type == 0) { /* End of TLV list. */ offset += tlv_length; break; } else { /* unknown TLV.type, or unexpected TLV.length */ } offset += tlv_length; } proto_item_set_len(ti, offset); /* Adjust the length of this tvbuff to include only the supervision data. This allows the rest to be marked as padding. */ tvb_set_reported_length(tvb, offset); }