diff --git a/packet-icmpv6.c b/packet-icmpv6.c new file mode 100644 index 0000000000..accc61a627 --- /dev/null +++ b/packet-icmpv6.c @@ -0,0 +1,558 @@ +/* packet-icmpv6.c + * Routines for ICMPv6 packet disassembly + * + * $Id: packet-icmpv6.c,v 1.1 1999/03/29 02:21:34 gram Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include +#include "packet.h" +#include "packet-ipv6.h" +#include "resolv.h" +#include "util.h" + +#ifndef offsetof +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) +#endif + +static void +dissect_icmpv6opt(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +{ + proto_tree *icmp6opt_tree, *field_tree; + proto_item *ti, *tf; + struct nd_opt_hdr *opt; + int len; + char *typename; + + if (!tree) + return; + +again: + if (!(fd->cap_len > offset)) + return; + + opt = (struct nd_opt_hdr *)&pd[offset]; + len = opt->nd_opt_len << 3; + + /* !!! specify length */ + ti = proto_tree_add_item(tree, offset, len, "ICMPv6 options"); + icmp6opt_tree = proto_tree_new(); + proto_item_add_subtree(ti, icmp6opt_tree, ETT_ICMPv6OPT); + + switch (opt->nd_opt_type) { + case ND_OPT_SOURCE_LINKADDR: + typename = "Source link-layer address"; + break; + case ND_OPT_TARGET_LINKADDR: + typename = "Target link-layer address"; + break; + case ND_OPT_PREFIX_INFORMATION: + typename = "Prefix information"; + break; + case ND_OPT_REDIRECTED_HEADER: + typename = "Redirected header"; + break; + case ND_OPT_MTU: + typename = "MTU"; + break; + default: + typename = "Unknown"; + break; + } + + proto_tree_add_item(icmp6opt_tree, + offset + offsetof(struct nd_opt_hdr, nd_opt_type), 1, + "Type: 0x%02x (%s)", opt->nd_opt_type, typename); + proto_tree_add_item(icmp6opt_tree, + offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1, + "Length: %d bytes (0x%02x)", opt->nd_opt_len << 3, opt->nd_opt_len); + + /* decode... */ + switch (opt->nd_opt_type) { + case ND_OPT_SOURCE_LINKADDR: + case ND_OPT_TARGET_LINKADDR: + { + char *t; + const char *p; + int len, i; + len = (opt->nd_opt_len << 3) - sizeof(*opt); + t = (char *)malloc(len * 3); + memset(t, 0, len * 3); + p = &pd[offset + sizeof(*opt)]; + for (i = 0; i < len; i++) { + if (i) + t[i * 3 - 1] = ':'; + sprintf(&t[i * 3], "%02x", p[i] & 0xff); + } + proto_tree_add_item(icmp6opt_tree, + offset + sizeof(*opt), len, "Link-layer address: %s", t); + break; + } + case ND_OPT_PREFIX_INFORMATION: + { + struct nd_opt_prefix_info *pi = (struct nd_opt_prefix_info *)opt; + int flagoff; + proto_tree_add_item(icmp6opt_tree, + offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix_len), + 1, "Prefix length: %d", pi->nd_opt_pi_prefix_len); + + flagoff = offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved); + tf = proto_tree_add_item(icmp6opt_tree, flagoff, 1, "Flags: 0x%02x", + pntohl(&pi->nd_opt_pi_flags_reserved)); + field_tree = proto_tree_new(); + proto_item_add_subtree(tf, field_tree, ETT_ICMPv6FLAG); + proto_tree_add_item(field_tree, flagoff, 1, "%s", + decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved, + 0x80, 8, "Onlink", "Not onlink")); + proto_tree_add_item(field_tree, flagoff, 1, "%s", + decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved, + 0x40, 8, "Auto", "Not auto")); + + proto_tree_add_item(icmp6opt_tree, + offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time), + 4, "Valid lifetime: 0x%08x", + pntohl(&pi->nd_opt_pi_valid_time)); + proto_tree_add_item(icmp6opt_tree, + offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time), + 4, "Preferred lifetime: 0x%08x", + pntohl(&pi->nd_opt_pi_preferred_time)); + proto_tree_add_item(icmp6opt_tree, + offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix), + 16, "Prefix: %s", ip6_to_str(&pi->nd_opt_pi_prefix)); + break; + } + case ND_OPT_REDIRECTED_HEADER: + proto_tree_add_item(icmp6opt_tree, + offset + 8, (opt->nd_opt_len << 3) - 8, "Redirected packet"); + /* tiny sanity check */ + if ((pd[offset + 8] & 0xf0) == 0x60) + dissect_ipv6(pd, offset + 8, fd, icmp6opt_tree); + else + dissect_data(pd, offset + 8, fd, icmp6opt_tree); + break; + case ND_OPT_MTU: + { + struct nd_opt_mtu *pi = (struct nd_opt_mtu *)opt; + proto_tree_add_item(icmp6opt_tree, + offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu), 4, + "MTU: %d", pi->nd_opt_mtu_mtu); + break; + } + } + + offset += (opt->nd_opt_len << 3); + goto again; +} + +void +dissect_icmpv6(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +{ + proto_tree *icmp6_tree, *field_tree; + proto_item *ti, *tf = NULL; + struct icmp6_hdr *dp; + char *codename, *typename; + int len; + + dp = (struct icmp6_hdr *)&pd[offset]; + codename = typename = "Unknown"; + len = sizeof(*dp); + switch (dp->icmp6_type) { + case ICMP6_DST_UNREACH: + typename = "Unreachable"; + switch (dp->icmp6_code) { + case ICMP6_DST_UNREACH_NOROUTE: + codename = "Route unreachable"; + break; + case ICMP6_DST_UNREACH_ADMIN: + codename = "Administratively prohibited"; + break; + case ICMP6_DST_UNREACH_NOTNEIGHBOR: + codename = "Not a neighbor"; + break; + case ICMP6_DST_UNREACH_ADDR: + codename = "Address unreachable"; + break; + case ICMP6_DST_UNREACH_NOPORT: + codename = "Port unreachable"; + break; + } + break; + case ICMP6_PACKET_TOO_BIG: + typename = "Too big"; + codename = NULL; + break; + case ICMP6_TIME_EXCEEDED: + typename = "Time exceeded"; + switch (dp->icmp6_code) { + case ICMP6_TIME_EXCEED_TRANSIT: + codename = "In-transit"; + break; + case ICMP6_TIME_EXCEED_REASSEMBLY: + codename = "Reassembly"; + break; + } + case ICMP6_PARAM_PROB: + typename = "Parameter problem"; + switch (dp->icmp6_code) { + case ICMP6_PARAMPROB_HEADER: + codename = "Header"; + break; + case ICMP6_PARAMPROB_NEXTHEADER: + codename = "Next header"; + break; + case ICMP6_PARAMPROB_OPTION: + codename = "Option"; + break; + } + case ICMP6_ECHO_REQUEST: + typename = "Echo request"; + codename = NULL; + break; + case ICMP6_ECHO_REPLY: + typename = "Echo reply"; + codename = NULL; + break; + case ICMP6_MEMBERSHIP_QUERY: + typename = "Multicast listener query"; + codename = NULL; + break; + case ICMP6_MEMBERSHIP_REPORT: + typename = "Multicast listener report"; + codename = NULL; + break; + case ICMP6_MEMBERSHIP_REDUCTION: + typename = "Multicast listener done"; + codename = NULL; + break; + case ND_ROUTER_SOLICIT: + typename = "Router solicitation"; + codename = NULL; + len = sizeof(struct nd_router_solicit); + break; + case ND_ROUTER_ADVERT: + typename = "Router advertisement"; + codename = NULL; + len = sizeof(struct nd_router_advert); + break; + case ND_NEIGHBOR_SOLICIT: + typename = "Neighbor solicitation"; + codename = NULL; + len = sizeof(struct nd_neighbor_solicit); + break; + case ND_NEIGHBOR_ADVERT: + typename = "Neighbor advertisement"; + codename = NULL; + len = sizeof(struct nd_neighbor_advert); + break; + case ND_REDIRECT: + typename = "Redirect"; + codename = NULL; + len = sizeof(struct nd_redirect); + break; + case ICMP6_ROUTER_RENUMBERING: + typename = "Router renumbering"; + switch (dp->icmp6_code) { + case ICMP6_ROUTER_RENUMBERING_COMMAND: + codename = "Command"; + break; + case ICMP6_ROUTER_RENUMBERING_RESULT: + codename = "Result"; + break; + } + len = sizeof(struct icmp6_router_renum); + break; + } + + if (check_col(fd, COL_PROTOCOL)) + col_add_str(fd, COL_PROTOCOL, "ICMPv6"); + if (check_col(fd, COL_INFO)) { + char typebuf[256], codebuf[256]; + + if (typename && strcmp(typename, "Unknown") == 0) { + snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)", + dp->icmp6_type); + typename = typebuf; + } + if (codename && strcmp(codename, "Unknown") == 0) { + snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)", + dp->icmp6_code); + codename = codebuf; + } + if (codename) { + col_add_fstr(fd, COL_INFO, "%s (%s)", + typename, codename); + } else { + col_add_fstr(fd, COL_INFO, "%s", typename); + } + } + + if (tree) { + /* !!! specify length */ + ti = proto_tree_add_item(tree, offset, len, + "ICMPv6"); + icmp6_tree = proto_tree_new(); + proto_item_add_subtree(ti, icmp6_tree, ETT_ICMPv6); + + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct icmp6_hdr, icmp6_type), 1, + "Type: 0x%02x (%s)", dp->icmp6_type, typename); + if (codename) { + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct icmp6_hdr, icmp6_code), 1, + "Code: 0x%02x (%s)", dp->icmp6_code, codename); + } + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2, + "Checksum: 0x%04x", (guint16)htons(dp->icmp6_cksum)); + + /* decode... */ + switch (dp->icmp6_type) { + case ICMP6_DST_UNREACH: + case ICMP6_TIME_EXCEEDED: + /* tiny sanity check */ + if ((pd[offset + sizeof(*dp)] & 0xf0) == 0x60) { + dissect_ipv6(pd, offset + sizeof(*dp), fd, icmp6_tree); + } else { + dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree); + } + break; + case ICMP6_PACKET_TOO_BIG: + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4, + "MTU: %d", pntohl(&dp->icmp6_mtu)); + /* tiny sanity check */ + if ((pd[offset + sizeof(*dp)] & 0xf0) == 0x60) { + dissect_ipv6(pd, offset + sizeof(*dp), fd, icmp6_tree); + } else { + dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree); + } + break; + case ICMP6_PARAM_PROB: + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4, + "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr)); + /* tiny sanity check */ + if ((pd[offset + sizeof(*dp)] & 0xf0) == 0x60) { + dissect_ipv6(pd, offset + sizeof(*dp), fd, icmp6_tree); + } else { + dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree); + } + break; + case ICMP6_ECHO_REQUEST: + case ICMP6_ECHO_REPLY: + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct icmp6_hdr, icmp6_id), 2, + "ID: 0x%04x", (guint16)ntohs(dp->icmp6_id)); + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct icmp6_hdr, icmp6_seq), 2, + "Sequence: 0x%04x", (guint16)ntohs(dp->icmp6_seq)); + dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree); + break; + case ICMP6_MEMBERSHIP_QUERY: + case ICMP6_MEMBERSHIP_REPORT: + case ICMP6_MEMBERSHIP_REDUCTION: + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2, + "Maximum response delay: %d", + (guint16)ntohs(dp->icmp6_maxdelay)); + proto_tree_add_item(icmp6_tree, offset + sizeof(*dp), 16, + "Multicast Address: %s", + ip6_to_str((struct e_in6_addr *)(dp + 1))); + break; + case ND_ROUTER_SOLICIT: + dissect_icmpv6opt(pd, offset + sizeof(*dp), fd, icmp6_tree); + break; + case ND_ROUTER_ADVERT: + { + struct nd_router_advert *ra = (struct nd_router_advert *)dp; + int flagoff; + guint32 ra_flags; + + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit), + 1, "Cur hop limit: %d", ra->nd_ra_curhoplimit); + + flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved); + ra_flags = pntohl(&pd[flagoff]); + tf = proto_tree_add_item(icmp6_tree, flagoff, 4, "Flags: 0x%08x", ra_flags); + field_tree = proto_tree_new(); + proto_item_add_subtree(tf, field_tree, ETT_ICMPv6FLAG); + proto_tree_add_item(field_tree, flagoff, 4, "%s", + decode_boolean_bitfield(ra_flags, + 0x80000000, 32, "Managed", "Not managed")); + proto_tree_add_item(field_tree, flagoff, 4, "%s", + decode_boolean_bitfield(ra_flags, + 0x40000000, 32, "Other", "Not other")); + + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime), + 2, "Router lifetime: %d", + (guint16)ntohs(ra->nd_ra_router_lifetime)); + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4, + "Reachable time: %d", pntohl(&ra->nd_ra_reachable)); + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4, + "Retrans time: %d", pntohl(&ra->nd_ra_retransmit)); + dissect_icmpv6opt(pd, offset + sizeof(struct nd_router_advert), fd, icmp6_tree); + break; + } + case ND_NEIGHBOR_SOLICIT: + { + struct nd_neighbor_solicit *ns = (struct nd_neighbor_solicit *)dp; + + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16, +#ifdef INET6 + "Target: %s (%s)", + get_hostname6(&ns->nd_ns_target), +#else + "Target: %s", +#endif + ip6_to_str(&ns->nd_ns_target)); + + dissect_icmpv6opt(pd, offset + sizeof(*ns), fd, icmp6_tree); + break; + } + case ND_NEIGHBOR_ADVERT: + { + int flagoff, targetoff; + guint32 na_flags; + struct e_in6_addr *na_target_p; + + flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved); + na_flags = pntohl(&pd[flagoff]); + + tf = proto_tree_add_item(icmp6_tree, flagoff, 4, "Flags: 0x%08x", na_flags); + field_tree = proto_tree_new(); + proto_item_add_subtree(tf, field_tree, ETT_ICMPv6FLAG); + proto_tree_add_item(field_tree, flagoff, 4, "%s", + decode_boolean_bitfield(na_flags, + 0x80000000, 32, "Router", "Not router")); + proto_tree_add_item(field_tree, flagoff, 4, "%s", + decode_boolean_bitfield(na_flags, + 0x40000000, 32, "Solicited", "Not adverted")); + proto_tree_add_item(field_tree, flagoff, 4, "%s", + decode_boolean_bitfield(na_flags, + 0x20000000, 32, "Override", "Not override")); + + targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target); + na_target_p = (struct e_in6_addr*) &pd[targetoff]; + proto_tree_add_item(icmp6_tree, targetoff, 16, +#ifdef INET6 + "Target: %s (%s)", + get_hostname6(na_target_p), +#else + "Target: %s", +#endif + ip6_to_str(na_target_p)); + + dissect_icmpv6opt(pd, offset + sizeof(struct nd_neighbor_advert), fd, icmp6_tree); + break; + } + case ND_REDIRECT: + { + struct nd_redirect *rd = (struct nd_redirect *)dp; + + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct nd_redirect, nd_rd_target), 16, +#ifdef INET6 + "Target: %s (%s)", + get_hostname6(&rd->nd_rd_target), +#else + "Target: %s", +#endif + ip6_to_str(&rd->nd_rd_target)); + + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct nd_redirect, nd_rd_dst), 16, +#ifdef INET6 + "Destination: %s (%s)", + get_hostname6(&rd->nd_rd_dst), +#else + "Destination: %s", +#endif + ip6_to_str(&rd->nd_rd_dst)); + + dissect_icmpv6opt(pd, offset + sizeof(*rd), fd, icmp6_tree); + break; + } + case ICMP6_ROUTER_RENUMBERING: + { + struct icmp6_router_renum *rr = (struct icmp6_router_renum *)dp; + int flagoff; + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4, + /*"Sequence number: 0x%08x", (u_int32_t)htonl(rr->rr_seqnum));*/ + "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum)); + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct icmp6_router_renum, rr_segnum), 1, + "Segment number: 0x%02x", rr->rr_segnum); + + flagoff = offset + offsetof(struct icmp6_router_renum, rr_segnum) + 1; + tf = proto_tree_add_item(icmp6_tree, flagoff, 4, "Flags: 0x%08x", + pd[flagoff]); + field_tree = proto_tree_new(); + proto_item_add_subtree(tf, field_tree, ETT_ICMPv6FLAG); + proto_tree_add_item(field_tree, flagoff, 1, "%s", + decode_boolean_bitfield(pd[flagoff], 0x80, 8, + "Test command", "Not test command")); + proto_tree_add_item(field_tree, flagoff, 1, "%s", + decode_boolean_bitfield(pd[flagoff], 0x40, 8, + "Result requested", "Result not requested")); + proto_tree_add_item(field_tree, flagoff, 1, "%s", + decode_boolean_bitfield(pd[flagoff], 0x20, 8, + "All interfaces", "Not all interfaces")); + proto_tree_add_item(field_tree, flagoff, 1, "%s", + decode_boolean_bitfield(pd[flagoff], 0x10, 8, + "Site specific", "Not site specific")); + proto_tree_add_item(field_tree, flagoff, 1, "%s", + decode_boolean_bitfield(pd[flagoff], 0x08, 8, + "Processed previously", "Complete result")); + + proto_tree_add_item(icmp6_tree, + offset + offsetof(struct icmp6_router_renum, rr_segnum), 2, + "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay)); + dissect_data(pd, offset + sizeof(*rr), fd, tree); /*XXX*/ + } + default: + dissect_data(pd, offset + sizeof(*dp), fd, tree); + break; + } + } +} diff --git a/packet-ipsec.c b/packet-ipsec.c new file mode 100644 index 0000000000..5d74f133ad --- /dev/null +++ b/packet-ipsec.c @@ -0,0 +1,141 @@ +/* packet-ipsec.c + * Routines for IPsec packet disassembly + * + * $Id: packet-ipsec.c,v 1.1 1999/03/29 02:21:34 gram Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include +#include "packet.h" +#include "resolv.h" + +struct newah { + guint8 ah_nxt; /* Next Header */ + guint8 ah_len; /* Length of data + 1, in 32bit */ + guint16 ah_reserve; /* Reserved for future use */ + guint32 ah_spi; /* Security parameter index */ + guint32 ah_seq; /* Sequence number field */ + /* variable size, 32bit bound*/ /* Authentication data */ +}; + +struct newesp { + guint32 esp_spi; /* ESP */ + guint32 esp_seq; /* Sequence number */ + /*variable size*/ /* (IV and) Payload data */ + /*variable size*/ /* padding */ + /*8bit*/ /* pad size */ + /*8bit*/ /* next header */ + /*8bit*/ /* next header */ + /*variable size, 32bit bound*/ /* Authentication data */ +}; + +#ifndef offsetof +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) +#endif + +int +dissect_ah(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +{ + proto_tree *ah_tree; + proto_item *ti; + struct newah ah; + int advance; + + memcpy(&ah, (void *) &pd[offset], sizeof(ah)); + advance = sizeof(ah) + ((ah.ah_len - 1) << 2); + + if (check_col(fd, COL_PROTOCOL)) + col_add_str(fd, COL_PROTOCOL, "AH"); + if (check_col(fd, COL_INFO)) { + col_add_fstr(fd, COL_INFO, "AH (SPI=%08x)", + (guint32)ntohl(ah.ah_spi)); + } + + if (tree) { + /* !!! specify length */ + ti = proto_tree_add_item(tree, offset, advance, "Authentication Header"); + ah_tree = proto_tree_new(); + proto_item_add_subtree(ti, ah_tree, ETT_AH); + + proto_tree_add_item(ah_tree, offset + offsetof(struct newah, ah_nxt), 1, + "Next Header: %d", ah.ah_nxt); + proto_tree_add_item(ah_tree, offset + offsetof(struct newah, ah_len), 1, + "Length: %d", ah.ah_len << 2); + proto_tree_add_item(ah_tree, offset + offsetof(struct newah, ah_spi), 4, + "SPI: %08x", (guint32)ntohl(ah.ah_spi)); + proto_tree_add_item(ah_tree, offset + offsetof(struct newah, ah_seq), 4, + "Sequence?: %08x", (guint32)ntohl(ah.ah_seq)); + proto_tree_add_item(ah_tree, offset + sizeof(ah), (ah.ah_len - 1) << 2, + "ICV"); + } + + /* start of the new header (could be a extension header) */ + return advance; +} + +void +dissect_esp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +{ + proto_tree *esp_tree; + proto_item *ti; + struct newesp esp; + + memcpy(&esp, (void *) &pd[offset], sizeof(esp)); + + /* + * load the top pane info. This should be overwritten by + * the next protocol in the stack + */ + if (check_col(fd, COL_PROTOCOL)) + col_add_str(fd, COL_PROTOCOL, "ESP"); + if (check_col(fd, COL_INFO)) { + col_add_fstr(fd, COL_INFO, "ESP (SPI=%08x)", + (guint32)ntohl(esp.esp_spi)); + } + + /* + * populate a tree in the second pane with the status of the link layer + * (ie none) + */ + if(tree) { + ti = proto_tree_add_item(tree, 0, 0, "Encapsulated Security Payload"); + esp_tree = proto_tree_new(); + proto_item_add_subtree(ti, esp_tree, ETT_ESP); + proto_tree_add_item(esp_tree, offset + offsetof(struct newesp, esp_spi), 4, + "SPI: %08x", (guint32)ntohl(esp.esp_spi)); + proto_tree_add_item(esp_tree, offset + offsetof(struct newesp, esp_seq), 4, + "Sequence?: %08x", (guint32)ntohl(esp.esp_seq)); + } +}