summaryrefslogtreecommitdiff
path: root/proto_icmpv6.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto_icmpv6.c')
-rw-r--r--proto_icmpv6.c1641
1 files changed, 1641 insertions, 0 deletions
diff --git a/proto_icmpv6.c b/proto_icmpv6.c
new file mode 100644
index 0000000..6b2d826
--- /dev/null
+++ b/proto_icmpv6.c
@@ -0,0 +1,1641 @@
+/*
+ * netsniff-ng - the packet sniffing beast
+ * Copyright 2012 Markus Amend <markus@netsniff-ng.org>, Deutsche Flugsicherung GmbH
+ * Subject to the GPL, version 2.
+ *
+ * ICMPv6 described in RFC4443, RFC2710, RFC4861, RFC2894,
+ * RFC4620, RFC3122, RFC3810, RFC3775, RFC3971, RFC4065
+ * RFC4286
+ * Look also for an good overview:
+ * http://www.iana.org/assignments/icmpv6-parameters
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <asm/byteorder.h>
+
+#include "proto.h"
+#include "protos.h"
+#include "dissector_eth.h"
+#include "pkt_buff.h"
+#include "built_in.h"
+
+#define icmpv6_code_range_valid(code, sarr) ((code) < array_size((sarr)))
+
+struct icmpv6_general_hdr {
+ uint8_t h_type;
+ uint8_t h_code;
+ uint16_t h_chksum;
+} __packed;
+
+/* for type 0x01 and 0x03 */
+struct icmpv6_type_1_3 {
+ uint32_t unused;
+ uint8_t invoking_pkt[0];
+} __packed;
+
+struct icmpv6_type_2 {
+ uint32_t MTU;
+ uint8_t invoking_pkt[0];
+} __packed;
+
+struct icmpv6_type_4 {
+ uint32_t pointer;
+ uint8_t invoking_pkt[0];
+} __packed;
+
+struct icmpv6_type_128_129 {
+ uint16_t id;
+ uint16_t sn;
+ uint8_t data[0];
+} __packed;
+
+/* MLDv1 msg */
+struct icmpv6_type_130_131_132 {
+ uint16_t maxrespdel;
+ uint16_t res;
+ struct in6_addr ipv6_addr;
+} __packed;
+/* end MLDv1 msg */
+
+struct icmpv6_type_130_mldv2 {
+ uint8_t resv_S_QRV;
+ uint8_t QQIC;
+ uint16_t nr_src;
+ struct in6_addr ipv6_addr[0];
+} __packed;
+
+/* Neighbor Discovery msg */
+struct icmpv6_type_133_141_142 {
+ uint32_t res;
+ uint8_t ops[0];
+} __packed;
+
+struct icmpv6_type_134 {
+ uint8_t cur_hop_limit;
+ uint8_t m_o_res;
+ uint16_t router_lifetime;
+ uint32_t reachable_time;
+ uint32_t retrans_timer;
+ uint8_t ops[0];
+} __packed;
+
+struct icmpv6_type_135 {
+ uint32_t res;
+ struct in6_addr ipv6_addr;
+ uint8_t ops[0];
+} __packed;
+
+struct icmpv6_type_136 {
+ uint32_t r_s_o_res;
+ struct in6_addr ipv6_addr;
+ uint8_t ops[0];
+} __packed;
+
+struct icmpv6_type_137 {
+ uint32_t res;
+ struct in6_addr ipv6_targ_addr;
+ struct in6_addr ipv6_dest_addr;
+ uint8_t ops[0];
+} __packed;
+
+struct icmpv6_neighb_disc_ops_general {
+ uint8_t type;
+ uint8_t len;
+ uint8_t ops[0];
+} __packed;
+
+struct icmpv6_neighb_disc_ops_type_1_2 {
+ uint8_t link_lay_addr[0];
+} __packed;
+
+struct icmpv6_neighb_disc_ops_type_3 {
+ uint8_t prefix_len;
+ uint8_t l_a_res1;
+ uint32_t valid_lifetime;
+ uint32_t preferred_lifetime;
+ uint32_t res2;
+ struct in6_addr prefix;
+} __packed;
+
+struct icmpv6_neighb_disc_ops_type_4 {
+ uint16_t res1;
+ uint32_t res2;
+ uint8_t ip_hdr_data[0];
+} __packed;
+
+struct icmpv6_neighb_disc_ops_type_5 {
+ uint16_t res1;
+ uint32_t MTU;
+} __packed;
+
+struct icmpv6_neighb_disc_ops_type_9_10 {
+ uint16_t res1;
+ uint32_t res2;
+ uint8_t ip_hdr_data[0];
+} __packed;
+
+struct icmpv6_neighb_disc_ops_type_15 {
+ uint8_t name_type;
+ size_t pad_len;
+ char name[0];
+ uint8_t pad[0];
+} __packed;
+
+struct icmpv6_neighb_disc_ops_type_16 {
+ uint8_t cert_type;
+ uint8_t res;
+ uint8_t cert[0];
+ uint8_t pad[0];
+} __packed;
+
+struct icmpv6_neighb_disc_ops_type_17 {
+ uint8_t opt_code;
+ uint8_t prefix_len;
+ uint8_t data[0];
+} __packed;
+
+struct icmpv6_neighb_disc_ops_type_17_1 {
+ uint32_t res;
+ struct in6_addr ipv6_addr;
+} __packed;
+
+struct icmpv6_neighb_disc_ops_type_17_2 {
+ struct in6_addr ipv6_addr;
+} __packed;
+
+struct icmpv6_neighb_disc_ops_type_19 {
+ uint8_t opt_code;
+ uint8_t lla[0];
+} __packed;
+/* end Neighbor Discovery msg */
+
+struct icmpv6_type_138 {
+ uint32_t seq_nr;
+ uint8_t seg_nr;
+ uint8_t flags;
+ uint16_t maxdelay;
+ uint32_t res;
+} __packed;
+
+/* Node Information Queries */
+struct icmpv6_type_139_140 {
+ uint16_t qtype;
+ uint16_t flags;
+ uint64_t nonce;
+ uint8_t data[0];
+} __packed;
+/* end Node Information Queries */
+
+/* MLDv2 report */
+struct icmpv6_type_143 {
+ uint16_t res;
+ uint16_t nr_rec;
+ uint8_t addr_rec[0];
+} __packed;
+
+struct icmpv6_mldv2_addr_rec {
+ uint8_t rec_type;
+ uint8_t aux_data_len;
+ uint16_t nr_src;
+ struct in6_addr multic_addr;
+ struct in6_addr src_addr[0];
+} __packed;
+/* end MLDv2 report */
+
+/* ICMP Mobility Support */
+struct icmpv6_type_144_146 {
+ uint16_t id;
+ uint16_t res;
+} __packed;
+
+struct icmpv6_type_145 {
+ uint16_t id;
+ uint16_t res;
+ struct in6_addr home_agent_addr[0];
+} __packed;
+
+struct icmpv6_type_147 {
+ uint16_t id;
+ uint16_t m_o_res;
+ uint8_t ops[0];
+} __packed;
+/* end ICMP Mobility Support */
+
+/* SEcure Neighbor Discovery */
+struct icmpv6_type_148 {
+ uint16_t id;
+ uint16_t comp;
+ uint8_t ops[0];
+} __packed;
+
+struct icmpv6_type_149 {
+ uint16_t id;
+ uint16_t all_comp;
+ uint16_t comp;
+ uint16_t res;
+ uint8_t ops[0];
+} __packed;
+/* end SEcure Neighbor Discovery */
+
+struct icmpv6_type_150 {
+ union {
+ uint32_t subtype_res;
+ struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ uint32_t res :24,
+ subtype :8;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ uint32_t subtype :8,
+ res :24;
+#else
+# error "Please fix <asm/byteorder.h>"
+#endif
+ };
+ };
+ uint8_t ops[0];
+} __packed;
+
+/* Multicast Router Discovery */
+struct icmpv6_type_151 {
+ uint16_t query_intv;
+ uint16_t rob_var;
+} __packed;
+
+struct icmpv6_type_152 {
+ uint8_t null[0];
+} __packed;
+
+struct icmpv6_type_153 {
+ uint8_t null[0];
+} __packed;
+/* end Multicast Router Discovery */
+
+struct icmpv6_type_154 {
+ uint8_t subtype;
+ uint8_t res;
+ uint16_t id;
+ uint8_t ops[0];
+} __packed;
+
+static int8_t print_ipv6_addr_list(struct pkt_buff *pkt, uint8_t nr_addr)
+{
+ char address[INET6_ADDRSTRLEN];
+ struct in6_addr *addr;
+
+ while (nr_addr--) {
+ addr = (struct in6_addr *) pkt_pull(pkt, sizeof(*addr));
+ if (addr == NULL)
+ return 0;
+
+ tprintf("\n\t Address: %s",
+ inet_ntop(AF_INET6, addr, address,
+ sizeof(address)));
+ }
+
+ return 1;
+}
+
+static const char *icmpv6_mcast_rec_types[] = {
+ "MODE_IS_INCLUDE",
+ "MODE_IS_EXCLUDE",
+ "CHANGE_TO_INCLUDE_MODE",
+ "CHANGE_TO_EXCLUDE_MODE",
+ "ALLOW_NEW_SOURCES",
+ "BLOCK_OLD_SOURCES",
+};
+
+static int8_t dissect_icmpv6_mcast_rec(struct pkt_buff *pkt,
+ uint16_t nr_rec)
+{
+ uint16_t nr_src, aux_data_len_bytes;
+ char address[INET6_ADDRSTRLEN];
+ struct icmpv6_mldv2_addr_rec *addr_rec;
+
+ while (nr_rec--) {
+ addr_rec = (struct icmpv6_mldv2_addr_rec *)
+ pkt_pull(pkt,sizeof(*addr_rec));
+ if (addr_rec == NULL)
+ return 0;
+ aux_data_len_bytes = addr_rec->aux_data_len * 4;
+ nr_src = ntohs(addr_rec->nr_src);
+
+ tprintf(", Rec Type %s (%u)",
+ icmpv6_code_range_valid(addr_rec->rec_type - 1,
+ icmpv6_mcast_rec_types) ?
+ icmpv6_mcast_rec_types[addr_rec->rec_type - 1]
+ : "Unknown", addr_rec->rec_type);
+ if (aux_data_len_bytes > pkt_len(pkt)) {
+ tprintf(", Aux Data Len (%u, %u bytes) %s",
+ addr_rec->aux_data_len,
+ aux_data_len_bytes,
+ colorize_start_full(black, red) "invalid"
+ colorize_end());
+ return 0;
+ }
+ tprintf(", Aux Data Len (%u, %u bytes)",addr_rec->aux_data_len,
+ aux_data_len_bytes);
+ tprintf(", Nr. of Sources (%u)",nr_src);
+ tprintf(", Address: %s",
+ inet_ntop(AF_INET6, &addr_rec->multic_addr,
+ address, sizeof(address)));
+
+ if(!print_ipv6_addr_list(pkt, nr_src))
+ return 0;
+
+ if (aux_data_len_bytes > pkt_len(pkt)) {
+ tprintf("\nAux Data Len %s",
+ colorize_start_full(black, red) "invalid"
+ colorize_end());
+ return 0;
+ }
+
+ tprintf(", Aux Data: ");
+ while (aux_data_len_bytes--) {
+ tprintf("%x", *pkt_pull(pkt,1));
+ }
+ }
+
+ return 1;
+}
+
+static int8_t dissect_neighb_disc_ops_1(struct pkt_buff *pkt,
+ ssize_t len)
+{
+ struct icmpv6_neighb_disc_ops_type_1_2 *icmp_neighb_disc_1;
+
+ icmp_neighb_disc_1 = (struct icmpv6_neighb_disc_ops_type_1_2 *)
+ pkt_pull(pkt,sizeof(*icmp_neighb_disc_1));
+ if (icmp_neighb_disc_1 == NULL)
+ return 0;
+ len -= sizeof(*icmp_neighb_disc_1);
+ if (len < 0)
+ return 0;
+
+ tprintf("Address 0x");
+
+ while(len--){
+ tprintf("%x", *pkt_pull(pkt,1));
+ }
+
+ return 1;
+}
+
+static int8_t dissect_neighb_disc_ops_2(struct pkt_buff *pkt,
+ ssize_t len)
+{
+ return dissect_neighb_disc_ops_1(pkt, len);
+}
+
+static int8_t dissect_neighb_disc_ops_3(struct pkt_buff *pkt,
+ ssize_t len)
+{
+ char address[INET6_ADDRSTRLEN];
+ struct icmpv6_neighb_disc_ops_type_3 *icmp_neighb_disc_3;
+
+ icmp_neighb_disc_3 = (struct icmpv6_neighb_disc_ops_type_3 *)
+ pkt_pull(pkt,sizeof(*icmp_neighb_disc_3));
+ if (icmp_neighb_disc_3 == NULL)
+ return 0;
+ len -= sizeof(*icmp_neighb_disc_3);
+ if (len < 0)
+ return 0;
+
+ tprintf("Prefix Len (%u) ",icmp_neighb_disc_3->prefix_len);
+ tprintf("L (%u) A (%u) Res1 (0x%x) ",icmp_neighb_disc_3->l_a_res1 >> 7,
+ (icmp_neighb_disc_3->l_a_res1 >> 7) & 0x1,
+ icmp_neighb_disc_3->l_a_res1 & 0x3F);
+ tprintf("Valid Lifetime (%us) ",
+ ntohl(icmp_neighb_disc_3->valid_lifetime));
+ tprintf("Preferred Lifetime (%us) ",
+ ntohl(icmp_neighb_disc_3->preferred_lifetime));
+ tprintf("Reserved2 (0x%x) ",
+ ntohl(icmp_neighb_disc_3->res2));
+ tprintf("Prefix: %s ",
+ inet_ntop(AF_INET6,&icmp_neighb_disc_3->prefix,
+ address, sizeof(address)));
+
+ return 1;
+}
+
+static int8_t dissect_neighb_disc_ops_4(struct pkt_buff *pkt,
+ ssize_t len)
+{
+ struct icmpv6_neighb_disc_ops_type_4 *icmp_neighb_disc_4;
+
+ icmp_neighb_disc_4 = (struct icmpv6_neighb_disc_ops_type_4 *)
+ pkt_pull(pkt,sizeof(*icmp_neighb_disc_4));
+ if (icmp_neighb_disc_4 == NULL)
+ return 0;
+ len -= sizeof(*icmp_neighb_disc_4);
+ if (len < 0)
+ return 0;
+
+ tprintf("Reserved 1 (0x%x) ", ntohs(icmp_neighb_disc_4->res1));
+ tprintf("Reserved 2 (0x%x) ", ntohl(icmp_neighb_disc_4->res2));
+ tprintf("IP header + data ");
+
+ while (len--) {
+ tprintf("%x", *pkt_pull(pkt,1));
+ }
+
+ return 1;
+}
+
+static int8_t dissect_neighb_disc_ops_5(struct pkt_buff *pkt,
+ ssize_t len)
+{
+ struct icmpv6_neighb_disc_ops_type_5 *icmp_neighb_disc_5;
+
+ icmp_neighb_disc_5 = (struct icmpv6_neighb_disc_ops_type_5 *)
+ pkt_pull(pkt,sizeof(*icmp_neighb_disc_5));
+ if (icmp_neighb_disc_5 == NULL)
+ return 0;
+ len -= sizeof(*icmp_neighb_disc_5);
+ if (len < 0)
+ return 0;
+
+ tprintf("Reserved (0x%x) ", ntohs(icmp_neighb_disc_5->res1));
+ tprintf("MTU (%u)", ntohl(icmp_neighb_disc_5->MTU));
+
+ return 1;
+}
+
+static int8_t dissect_neighb_disc_ops_9(struct pkt_buff *pkt,
+ ssize_t len)
+{
+ struct icmpv6_neighb_disc_ops_type_9_10 *icmp_neighb_disc_9;
+
+ icmp_neighb_disc_9 = (struct icmpv6_neighb_disc_ops_type_9_10 *)
+ pkt_pull(pkt,sizeof(*icmp_neighb_disc_9));
+ if (icmp_neighb_disc_9 == NULL)
+ return 0;
+ len -= sizeof(*icmp_neighb_disc_9);
+ if (len < 0)
+ return 0;
+
+ tprintf("Reserved 1 (0x%x) ", ntohs(icmp_neighb_disc_9->res1));
+ tprintf("Reserved 2 (0x%x) ", ntohl(icmp_neighb_disc_9->res2));
+
+ return print_ipv6_addr_list(pkt, len / sizeof(struct in6_addr));
+}
+
+static int8_t dissect_neighb_disc_ops_10(struct pkt_buff *pkt,
+ ssize_t len)
+{
+ return dissect_neighb_disc_ops_9(pkt, len);
+}
+
+static const char *icmpv6_neighb_disc_ops_15_name[] = {
+ "DER Encoded X.501 Name",
+ "FQDN",
+};
+
+static int8_t dissect_neighb_disc_ops_15(struct pkt_buff *pkt,
+ ssize_t len)
+{
+ size_t pad_len;
+ ssize_t name_len;
+ struct icmpv6_neighb_disc_ops_type_15 *icmp_neighb_disc_15;
+
+ icmp_neighb_disc_15 = (struct icmpv6_neighb_disc_ops_type_15 *)
+ pkt_pull(pkt,sizeof(*icmp_neighb_disc_15));
+ if (icmp_neighb_disc_15 == NULL)
+ return 0;
+ len -= sizeof(*icmp_neighb_disc_15);
+ if (len < 0)
+ return 0;
+ pad_len = icmp_neighb_disc_15->pad_len;
+
+ tprintf("Name Type %s (%u) ",
+ icmpv6_code_range_valid(icmp_neighb_disc_15->name_type - 1,
+ icmpv6_neighb_disc_ops_15_name) ?
+ icmpv6_neighb_disc_ops_15_name[
+ icmp_neighb_disc_15->name_type - 1] : "Unknown",
+ icmp_neighb_disc_15->name_type);
+ if (pad_len > len) {
+ tprintf("Pad Len (%zu, invalid)\n%s", pad_len,
+ colorize_start_full(black, red)
+ "Skip Option" colorize_end());
+ pkt_pull(pkt, len);
+ return 1;
+ }
+ else
+ tprintf("Pad Len (%zu) ", pad_len);
+
+ name_len = len - pad_len;
+
+ tprintf("Name (");
+ while (name_len--) {
+ tprintf("%c", *pkt_pull(pkt,1));
+ }
+ tprintf(") ");
+
+ tprintf("Padding (");
+
+ while (pad_len--) {
+ tprintf("%x", *pkt_pull(pkt,1));
+ }
+ tprintf(")");
+
+ return 1;
+}
+
+static const char *icmpv6_neighb_disc_ops_16_cert[] = {
+ "X.509v3 Certificate",
+};
+
+static int8_t dissect_neighb_disc_ops_16(struct pkt_buff *pkt,
+ ssize_t len)
+{
+ struct icmpv6_neighb_disc_ops_type_16 *icmp_neighb_disc_16;
+
+ icmp_neighb_disc_16 = (struct icmpv6_neighb_disc_ops_type_16 *)
+ pkt_pull(pkt,sizeof(*icmp_neighb_disc_16));
+ if (icmp_neighb_disc_16 == NULL)
+ return 0;
+ len -= sizeof(*icmp_neighb_disc_16);
+ if (len < 0)
+ return 0;
+
+ tprintf("Cert Type %s (%u) ",
+ icmpv6_code_range_valid(icmp_neighb_disc_16->cert_type - 1,
+ icmpv6_neighb_disc_ops_16_cert) ?
+ icmpv6_neighb_disc_ops_16_cert[
+ icmp_neighb_disc_16->cert_type - 1] : "Unknown",
+ icmp_neighb_disc_16->cert_type);
+ tprintf("Res (0x%x) ", icmp_neighb_disc_16->res);
+
+ tprintf("Certificate + Padding (");
+ while (len--) {
+ tprintf("%x", *pkt_pull(pkt,1));
+ }
+ tprintf(") ");
+
+ return 1;
+}
+
+static const char *icmpv6_neighb_disc_ops_17_codes[] = {
+ "Old Care-of Address",
+ "New Care-of Address",
+ "NAR's IP address",
+ "NAR's Prefix",
+};
+
+static int8_t dissect_neighb_disc_ops_17(struct pkt_buff *pkt,
+ ssize_t len)
+{
+ char address[INET6_ADDRSTRLEN];
+ struct icmpv6_neighb_disc_ops_type_17 *icmp_neighb_disc_17;
+
+ icmp_neighb_disc_17 = (struct icmpv6_neighb_disc_ops_type_17 *)
+ pkt_pull(pkt,sizeof(*icmp_neighb_disc_17));
+ if (icmp_neighb_disc_17 == NULL)
+ return 0;
+ len -= sizeof(*icmp_neighb_disc_17);
+ if (len < 0)
+ return 0;
+
+ tprintf("Opt Code %s (%u) ",
+ icmpv6_code_range_valid(icmp_neighb_disc_17->opt_code - 1,
+ icmpv6_neighb_disc_ops_17_codes) ?
+ icmpv6_neighb_disc_ops_17_codes[
+ icmp_neighb_disc_17->opt_code - 1] : "Unknown",
+ icmp_neighb_disc_17->opt_code);
+ tprintf("Prefix Len (%u) ", icmp_neighb_disc_17->prefix_len);
+
+ if (len == sizeof(struct icmpv6_neighb_disc_ops_type_17_1)) {
+ struct icmpv6_neighb_disc_ops_type_17_1
+ *icmp_neighb_disc_17_1;
+
+ icmp_neighb_disc_17_1 =
+ (struct icmpv6_neighb_disc_ops_type_17_1 *)
+ pkt_pull(pkt,sizeof(*icmp_neighb_disc_17_1));
+ if (icmp_neighb_disc_17_1 == NULL)
+ return 0;
+ len -= sizeof(*icmp_neighb_disc_17_1);
+ if (len < 0)
+ return 0;
+
+ tprintf("Res (0x%x) ",icmp_neighb_disc_17_1->res);
+ tprintf("Addr: %s ",
+ inet_ntop(AF_INET6,&icmp_neighb_disc_17_1->ipv6_addr,
+ address, sizeof(address)));
+ }
+ else if (len == sizeof(struct icmpv6_neighb_disc_ops_type_17_2)) {
+ struct icmpv6_neighb_disc_ops_type_17_2
+ *icmp_neighb_disc_17_2;
+
+ icmp_neighb_disc_17_2 =
+ (struct icmpv6_neighb_disc_ops_type_17_2 *)
+ pkt_pull(pkt,sizeof(*icmp_neighb_disc_17_2));
+ if (icmp_neighb_disc_17_2 == NULL)
+ return 0;
+ len -= sizeof(*icmp_neighb_disc_17_2);
+ if (len < 0)
+ return 0;
+
+ tprintf("Addr: %s ",
+ inet_ntop(AF_INET6,&icmp_neighb_disc_17_2->ipv6_addr,
+ address, sizeof(address)));
+ }
+ else {
+ tprintf("%s (", colorize_start_full(black, red)
+ "Error Wrong Length. Skip Option" colorize_end());
+ while (len--) {
+ tprintf("%x", *pkt_pull(pkt,1));
+ }
+ tprintf(") ");
+ }
+
+ return 1;
+}
+
+static const char *icmpv6_neighb_disc_ops_19_codes[] = {
+ "Wildcard requesting resolution for all nearby access points",
+ "Link-Layer Address of the New Access Point",
+ "Link-Layer Address of the MN",
+ "Link-Layer Address of the NAR",
+ "Link-Layer Address of the source of RtSolPr or PrRtAdv \
+ message",
+ "The access point identified by the LLA belongs to the \
+ current interface of the router",
+ "No prefix information available for the access point \
+ identified by the LLA",
+ "No fast handover support available for the access point \
+ identified by the LLA",
+};
+
+static int8_t dissect_neighb_disc_ops_19(struct pkt_buff *pkt,
+ ssize_t len)
+{
+ struct icmpv6_neighb_disc_ops_type_19 *icmp_neighb_disc_19;
+
+ icmp_neighb_disc_19 = (struct icmpv6_neighb_disc_ops_type_19 *)
+ pkt_pull(pkt,sizeof(*icmp_neighb_disc_19));
+ if (icmp_neighb_disc_19 == NULL)
+ return 0;
+ len -= sizeof(*icmp_neighb_disc_19);
+ if (len < 0)
+ return 0;
+
+ tprintf("Opt Code %s (%u) ",
+ icmpv6_code_range_valid(icmp_neighb_disc_19->opt_code,
+ icmpv6_neighb_disc_ops_19_codes) ?
+ icmpv6_neighb_disc_ops_19_codes[
+ icmp_neighb_disc_19->opt_code] : "Unknown",
+ icmp_neighb_disc_19->opt_code);
+
+ tprintf("LLA (");
+ while(len--){
+ tprintf("%x", *pkt_pull(pkt,1));
+ }
+ tprintf(") ");
+
+ return 1;
+}
+
+static inline char *icmpv6_neighb_disc_ops(uint8_t code) {
+ switch (code) {
+ case 1: return "Source Link-Layer Address";
+ case 2: return "Target Link-Layer Address";
+ case 3: return "Prefix Information";
+ case 4: return "Redirected Header";
+ case 5: return "MTU";
+ case 6: return "NBMA Shortcut Limit Option";
+ case 7: return "Advertisement Interval Option";
+ case 8: return "Home Agent Information Option";
+ case 9: return "Source Address List";
+ case 10: return "Target Address List";
+ case 11: return "CGA option";
+ case 12: return "RSA Signature option";
+ case 13: return "Timestamp option";
+ case 14: return "Nonce option";
+ case 15: return "Trust Anchor option";
+ case 16: return "Certificate option";
+ case 17: return "IP Address/Prefix Option";
+ case 18: return "New Router Prefix Information Option";
+ case 19: return "Link-layer Address Option";
+ case 20: return "Neighbor Advertisement Acknowledgment Option";
+
+ case 23: return "Prefix Information";
+ case 24: return "Redirected Header";
+ case 25: return "MTU";
+ case 26: return "NBMA Shortcut Limit Option";
+ case 27: return "Advertisement Interval Option";
+ case 28: return "Home Agent Information Option";
+ case 29: return "Source Address List";
+ case 30: return "Target Address List";
+ case 31: return "DNS Search List Option";
+ case 32: return "Proxy Signature (PS)";
+
+ case 138: return "CARD Request option";
+ case 139: return "CARD Reply option";
+
+ case 253: return "RFC3692-style Experiment 1";
+ case 254: return "RFC3692-style Experiment 2";
+ }
+
+ return NULL;
+};
+
+static int8_t dissect_neighb_disc_ops(struct pkt_buff *pkt)
+{
+ size_t pad_bytes;
+ uint16_t ops_total_len;
+ ssize_t ops_payl_len;
+ struct icmpv6_neighb_disc_ops_general *icmp_neighb_disc;
+
+ while(pkt_len(pkt)) {
+ icmp_neighb_disc = (struct icmpv6_neighb_disc_ops_general *)
+ pkt_pull(pkt,sizeof(*icmp_neighb_disc));
+ if (icmp_neighb_disc == NULL)
+ return 0;
+
+ ops_total_len = icmp_neighb_disc->len * 8;
+ pad_bytes = (size_t) (ops_total_len % 8);
+ ops_payl_len = ops_total_len - sizeof(*icmp_neighb_disc) -
+ pad_bytes;
+
+ tprintf("\n\tOption %s (%u) ",
+ icmpv6_neighb_disc_ops(icmp_neighb_disc->type) ?
+ icmpv6_neighb_disc_ops(icmp_neighb_disc->type)
+ : "Type Unknown", icmp_neighb_disc->type);
+ if (ops_payl_len > pkt_len(pkt) || ops_payl_len < 0) {
+ tprintf("Length (%u, %u bytes, %s%s%s) ",
+ icmp_neighb_disc->len,
+ ops_total_len,
+ colorize_start_full(black, red),
+ "invalid", colorize_end());
+ return 0;
+ }
+
+ tprintf("Length (%u, %u bytes) ",icmp_neighb_disc->len,
+ ops_total_len);
+
+ switch (icmp_neighb_disc->type) {
+ case 1:
+ if (!dissect_neighb_disc_ops_1(pkt, ops_payl_len))
+ return 0;
+ break;
+ case 2:
+ if (!dissect_neighb_disc_ops_2(pkt, ops_payl_len))
+ return 0;
+ break;
+ case 3:
+ if (!dissect_neighb_disc_ops_3(pkt, ops_payl_len))
+ return 0;
+ break;
+ case 4:
+ if (!dissect_neighb_disc_ops_4(pkt, ops_payl_len))
+ return 0;
+ break;
+ case 5:
+ if (!dissect_neighb_disc_ops_5(pkt, ops_payl_len))
+ return 0;
+ break;
+ /* Type 9 and 10 defined in
+ * http://tools.ietf.org/html/rfc3122#section-3.1
+ */
+ case 9:
+ if (!dissect_neighb_disc_ops_9(pkt, ops_payl_len))
+ return 0;
+ break;
+ case 10:
+ if (!dissect_neighb_disc_ops_10(pkt, ops_payl_len))
+ return 0;
+ break;
+ /* Type 15 and 16 defined in
+ * http://tools.ietf.org/html/rfc3971#section-6.4.3
+ * http://tools.ietf.org/html/rfc3971#section-6.4.4
+ */
+ case 15:
+ if (!dissect_neighb_disc_ops_15(pkt, ops_payl_len))
+ return 0;
+ break;
+ case 16:
+ if (!dissect_neighb_disc_ops_16(pkt, ops_payl_len))
+ return 0;
+ break;
+ /* Type 17 and 19 defined in
+ * http://tools.ietf.org/html/rfc5568#section-6.4
+ */
+ case 17:
+ if (!dissect_neighb_disc_ops_17(pkt, ops_payl_len))
+ return 0;
+ break;
+ case 19:
+ if (!dissect_neighb_disc_ops_19(pkt, ops_payl_len))
+ return 0;
+ break;
+ default:
+ pkt_pull(pkt, ops_payl_len);
+ }
+
+ /* Skip Padding Bytes */
+ if (pad_bytes > pkt_len(pkt)) {
+ tprintf(" %s",colorize_start_full(black, red)
+ "Invalid Padding" colorize_end());
+ return 0;
+ }
+ pkt_pull(pkt, pad_bytes);
+ }
+
+ return 1;
+}
+
+static const char *icmpv6_type_1_codes[] = {
+ "No route to destination",
+ "Communication with destination administratively prohibited",
+ "Beyond scope of source address",
+ "Address unreachable",
+ "Port unreachable",
+ "Source address failed ingress/egress policy",
+ "Reject route to destination",
+ "Error in Source Routing Header",
+};
+
+static int8_t dissect_icmpv6_type1(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_1_3 *icmp_1;
+
+ icmp_1 = (struct icmpv6_type_1_3 *) pkt_pull(pkt,sizeof(*icmp_1));
+ if (icmp_1 == NULL)
+ return 0;
+
+ tprintf(", Unused (0x%x)",ntohl(icmp_1->unused));
+ tprintf(" Payload include as much of invoking packet");
+
+ return 1;
+}
+
+static int8_t dissect_icmpv6_type2(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_2 *icmp_2;
+
+ icmp_2 = (struct icmpv6_type_2 *) pkt_pull(pkt,sizeof(*icmp_2));
+ if (icmp_2 == NULL)
+ return 0;
+
+ tprintf(", MTU (0x%x)",ntohl(icmp_2->MTU));
+ tprintf(" Payload include as much of invoking packet");
+
+ return 1;
+}
+
+static const char *icmpv6_type_3_codes[] = {
+ "Hop limit exceeded in transit",
+ "Fragment reassembly time exceeded",
+};
+
+static int8_t dissect_icmpv6_type3(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_1_3 *icmp_3;
+
+ icmp_3 = (struct icmpv6_type_1_3 *) pkt_pull(pkt,sizeof(*icmp_3));
+ if (icmp_3 == NULL)
+ return 0;
+
+ tprintf(", Unused (0x%x)",ntohl(icmp_3->unused));
+ tprintf(" Payload include as much of invoking packet");
+
+ return 1;
+}
+
+static const char *icmpv6_type_4_codes[] = {
+ "Erroneous header field encountered",
+ "Unrecognized Next Header type encountered",
+ "Unrecognized IPv6 option encountered",
+};
+
+static int8_t dissect_icmpv6_type4(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_4 *icmp_4;
+
+ icmp_4 = (struct icmpv6_type_4 *) pkt_pull(pkt,sizeof(*icmp_4));
+ if (icmp_4 == NULL)
+ return 0;
+
+ tprintf(", Pointer (0x%x)",ntohl(icmp_4->pointer));
+ tprintf(" Payload include as much of invoking packet");
+
+ return 1;
+}
+
+static int8_t dissect_icmpv6_type128(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_128_129 *icmp_128;
+
+ icmp_128 = (struct icmpv6_type_128_129 *)
+ pkt_pull(pkt,sizeof(*icmp_128));
+ if (icmp_128 == NULL)
+ return 0;
+
+ tprintf(", ID (0x%x)",ntohs(icmp_128->id));
+ tprintf(", Seq. Nr. (%u)",ntohs(icmp_128->sn));
+ tprintf(" Payload include Data");
+
+ return 1;
+}
+
+static int8_t dissect_icmpv6_type129(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_128_129 *icmp_129;
+
+ icmp_129 = (struct icmpv6_type_128_129 *)
+ pkt_pull(pkt,sizeof(*icmp_129));
+ if (icmp_129 == NULL)
+ return 0;
+
+ tprintf(", ID (0x%x)",ntohs(icmp_129->id));
+ tprintf(", Seq. Nr. (%u)",ntohs(icmp_129->sn));
+ tprintf(" Payload include Data");
+
+ return 1;
+}
+
+static int8_t dissect_icmpv6_type130(struct pkt_buff *pkt)
+{
+ char address[INET6_ADDRSTRLEN];
+ uint16_t nr_src, maxrespdel;
+ uint8_t switch_mldv2 = 0;
+ struct icmpv6_type_130_131_132 *icmp_130;
+
+ icmp_130 = (struct icmpv6_type_130_131_132 *)
+ pkt_pull(pkt,sizeof(*icmp_130));
+ if (icmp_130 == NULL)
+ return 0;
+ maxrespdel = ntohs(icmp_130->maxrespdel);
+
+ if(pkt_len(pkt) >= sizeof(struct icmpv6_type_130_mldv2))
+ switch_mldv2 = 1;
+
+ if(switch_mldv2)
+ tprintf(", MLDv2, Max Resp Delay (%ums)", maxrespdel >> 15 ?
+ (((maxrespdel & 0xFFF) | 0x1000) <<
+ (((maxrespdel >> 12) & 0x3) + 3)) : maxrespdel);
+ else
+ tprintf(", Max Resp Delay (%ums)",maxrespdel);
+ tprintf(", Res (0x%x)",ntohs(icmp_130->res));
+ tprintf(", Address: %s",
+ inet_ntop(AF_INET6, &icmp_130->ipv6_addr,
+ address, sizeof(address)));
+
+ if(switch_mldv2) {
+ struct icmpv6_type_130_mldv2 *icmp_130_mldv2;
+
+ icmp_130_mldv2 = (struct icmpv6_type_130_mldv2 *)
+ pkt_pull(pkt,sizeof(*icmp_130_mldv2));
+ if (icmp_130_mldv2 == NULL)
+ return 0;
+
+ nr_src = ntohs(icmp_130_mldv2->nr_src);
+
+ tprintf(", Resv (0x%x)",icmp_130_mldv2->resv_S_QRV >> 4);
+ tprintf(", S (%u)",(icmp_130_mldv2->resv_S_QRV >> 3) & 0x1);
+ tprintf(", QRV (0x%x)",icmp_130_mldv2->resv_S_QRV & 0x3);
+ tprintf(", QQIC (%u)",icmp_130_mldv2->QQIC);
+ tprintf(", Nr Src (%u)",nr_src);
+
+ return print_ipv6_addr_list(pkt, nr_src);
+ }
+
+ return 1;
+}
+
+static int8_t dissect_icmpv6_type131(struct pkt_buff *pkt)
+{
+ char address[INET6_ADDRSTRLEN];
+ struct icmpv6_type_130_131_132 *icmp_131;
+
+ icmp_131 = (struct icmpv6_type_130_131_132 *)
+ pkt_pull(pkt,sizeof(*icmp_131));
+ if (icmp_131 == NULL)
+ return 0;
+
+ tprintf(", Max Resp Delay (%ums)",ntohs(icmp_131->maxrespdel));
+ tprintf(", Res (0x%x)",ntohs(icmp_131->res));
+ tprintf(", Address: %s",
+ inet_ntop(AF_INET6, &icmp_131->ipv6_addr,
+ address, sizeof(address)));
+
+ return 1;
+}
+
+static inline int8_t dissect_icmpv6_type132(struct pkt_buff *pkt)
+{
+ return dissect_icmpv6_type131(pkt);
+}
+
+static int8_t dissect_icmpv6_type133(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_133_141_142 *icmp_133;
+
+ icmp_133 = (struct icmpv6_type_133_141_142 *)
+ pkt_pull(pkt,sizeof(*icmp_133));
+ if (icmp_133 == NULL)
+ return 0;
+
+ tprintf(", Reserved (0x%x)",ntohl(icmp_133->res));
+
+ return dissect_neighb_disc_ops(pkt);
+}
+
+static int8_t dissect_icmpv6_type134(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_134 *icmp_134;
+
+ icmp_134 = (struct icmpv6_type_134 *)
+ pkt_pull(pkt,sizeof(*icmp_134));
+ if (icmp_134 == NULL)
+ return 0;
+
+ tprintf(", Cur Hop Limit (%u)",icmp_134->cur_hop_limit);
+ tprintf(", M (%u) O (%u)",icmp_134->m_o_res >> 7,
+ (icmp_134->m_o_res >> 6) & 0x1);
+ tprintf(", Router Lifetime (%us)",ntohs(icmp_134->router_lifetime));
+ tprintf(", Reachable Time (%ums)",ntohl(icmp_134->reachable_time));
+ tprintf(", Retrans Timer (%ums)",ntohl(icmp_134->retrans_timer));
+
+ return dissect_neighb_disc_ops(pkt);
+}
+
+static int8_t dissect_icmpv6_type135(struct pkt_buff *pkt)
+{
+ char address[INET6_ADDRSTRLEN];
+ struct icmpv6_type_135 *icmp_135;
+
+ icmp_135 = (struct icmpv6_type_135 *)
+ pkt_pull(pkt,sizeof(*icmp_135));
+ if (icmp_135 == NULL)
+ return 0;
+
+ tprintf(", Reserved (0x%x)",ntohl(icmp_135->res));
+ tprintf(", Target Address: %s",
+ inet_ntop(AF_INET6, &icmp_135->ipv6_addr,
+ address, sizeof(address)));
+
+ return dissect_neighb_disc_ops(pkt);
+}
+
+static int8_t dissect_icmpv6_type136(struct pkt_buff *pkt)
+{
+ char address[INET6_ADDRSTRLEN];
+ uint32_t r_s_o_res;
+ struct icmpv6_type_136 *icmp_136;
+
+ icmp_136 = (struct icmpv6_type_136 *)
+ pkt_pull(pkt,sizeof(*icmp_136));
+ if (icmp_136 == NULL)
+ return 0;
+ r_s_o_res = ntohl(icmp_136->r_s_o_res);
+
+ tprintf(", R (%u) S (%u) O (%u) Reserved (0x%x)", r_s_o_res >> 31,
+ (r_s_o_res >> 30) & 0x1, (r_s_o_res >> 29) & 0x1,
+ r_s_o_res & 0x1FFFFFFF);
+ tprintf(", Target Address: %s",
+ inet_ntop(AF_INET6, &icmp_136->ipv6_addr,
+ address, sizeof(address)));
+
+ return dissect_neighb_disc_ops(pkt);
+}
+
+static int8_t dissect_icmpv6_type137(struct pkt_buff *pkt)
+{
+ char address[INET6_ADDRSTRLEN];
+ struct icmpv6_type_137 *icmp_137;
+
+ icmp_137 = (struct icmpv6_type_137 *)
+ pkt_pull(pkt,sizeof(*icmp_137));
+ if (icmp_137 == NULL)
+ return 0;
+
+ tprintf(", Reserved (0x%x)",icmp_137->res);
+ tprintf(", Target Address: %s",
+ inet_ntop(AF_INET6, &icmp_137->ipv6_targ_addr,
+ address, sizeof(address)));
+ tprintf(", Dest Address: %s",
+ inet_ntop(AF_INET6, &icmp_137->ipv6_dest_addr,
+ address, sizeof(address)));
+
+ return dissect_neighb_disc_ops(pkt);
+}
+
+static void dissect_icmpv6_rr_body(struct pkt_buff *pkt)
+{
+ /*
+ * Upgrade Dissector for Message Body
+ * from http://tools.ietf.org/html/rfc2894#section-3.2
+ */
+ if(pkt_len(pkt))
+ tprintf(" Message Body recognized");
+}
+
+static inline char *icmpv6_type_138_codes(uint8_t code) {
+ switch (code) {
+ case 1: return "Router Renumbering Command";
+ case 2: return "Router Renumbering Result";
+ case 255: return "Sequence Number Reset";
+ }
+
+ return NULL;
+};
+
+static int8_t dissect_icmpv6_type138(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_138 *icmp_138;
+
+ icmp_138 = (struct icmpv6_type_138 *)
+ pkt_pull(pkt,sizeof(*icmp_138));
+ if (icmp_138 == NULL)
+ return 0;
+
+ tprintf(", Sequence Nr. (%u)",ntohl(icmp_138->seq_nr));
+ tprintf(", Segment Nr. (%u)",icmp_138->seg_nr);
+ tprintf(", T (%u) R (%u) A (%u) S (%u) P (%u) Res \
+ (0x%x) ",icmp_138->flags >> 7, (icmp_138->flags >> 6) & 1,
+ (icmp_138->flags >> 5) & 1, (icmp_138->flags >> 4) & 1,
+ (icmp_138->flags >> 3) & 1, icmp_138->flags & 7);
+ tprintf(", Max Delay (%ums)", ntohs(icmp_138->maxdelay));
+ tprintf(", Res (0x%x)", ntohl(icmp_138->res));
+
+ dissect_icmpv6_rr_body(pkt);
+
+ return 1;
+}
+
+static void dissect_icmpv6_node_inf_data(struct pkt_buff *pkt)
+{
+ /*
+ * Upgrade Dissector for Data field
+ * http://tools.ietf.org/html/rfc4620#section-4
+ */
+ if(pkt_len(pkt))
+ tprintf(" Data recognized");
+}
+
+static const char *icmpv6_node_inf_qtypes[] = {
+ "NOOP",
+ "unused",
+ "Node Name",
+ "Node Addresses",
+ "IPv4 Addresses ",
+};
+
+static const char *icmpv6_type_139_codes[] = {
+ "Data contains IPv6 Address",
+ "Data contains Name or nothing",
+ "Data contains IPv4 Address",
+};
+
+static int8_t dissect_icmpv6_type139(struct pkt_buff *pkt)
+{
+ const char *qtype_name = "Unknown";
+ uint16_t qtype_nr;
+ struct icmpv6_type_139_140 *icmp_139;
+
+ icmp_139 = (struct icmpv6_type_139_140 *)
+ pkt_pull(pkt,sizeof(*icmp_139));
+ if (icmp_139 == NULL)
+ return 0;
+
+ qtype_nr = ntohs(icmp_139->qtype);
+ if (icmpv6_code_range_valid(qtype_nr, icmpv6_node_inf_qtypes))
+ qtype_name = icmpv6_node_inf_qtypes[qtype_nr];
+
+ tprintf(", Qtype %s (%u)", qtype_name, qtype_nr);
+ tprintf(", Flags (0x%x)", ntohs(icmp_139->flags));
+ tprintf(", Nonce (0x%lx)", ntohll(icmp_139->nonce));
+
+ dissect_icmpv6_node_inf_data(pkt);
+
+ return 1;
+}
+
+static char *icmpv6_type_140_codes[] = {
+ "Successfull reply",
+ "Responder refuses answer",
+ "Qtype is unknown to the Responder",
+};
+
+static inline int8_t dissect_icmpv6_type140(struct pkt_buff *pkt)
+{
+ return dissect_icmpv6_type139(pkt);
+}
+
+static inline int8_t dissect_icmpv6_type141(struct pkt_buff *pkt)
+{
+ return dissect_icmpv6_type133(pkt);
+}
+
+static inline int8_t dissect_icmpv6_type142(struct pkt_buff *pkt)
+{
+ return dissect_icmpv6_type133(pkt);
+}
+
+static int8_t dissect_icmpv6_type143(struct pkt_buff *pkt)
+{
+ uint16_t nr_rec;
+ struct icmpv6_type_143 *icmp_143;
+
+ icmp_143 = (struct icmpv6_type_143 *)
+ pkt_pull(pkt,sizeof(*icmp_143));
+ if (icmp_143 == NULL)
+ return 0;
+ nr_rec = ntohs(icmp_143->nr_rec);
+
+ tprintf(", Res (0x%x)",ntohs(icmp_143->res));
+ tprintf(", Nr. Mcast Addr Records (%u)",nr_rec);
+
+ return dissect_icmpv6_mcast_rec(pkt, nr_rec);
+}
+
+static int8_t dissect_icmpv6_type144(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_144_146 *icmp_144;
+
+ icmp_144 = (struct icmpv6_type_144_146 *)
+ pkt_pull(pkt,sizeof(*icmp_144));
+ if (icmp_144 == NULL)
+ return 0;
+
+ tprintf(", ID (%u)",ntohs(icmp_144->id));
+ tprintf(", Res (0x%x)",ntohs(icmp_144->res));
+
+ return 1;
+}
+
+static int8_t dissect_icmpv6_type145(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_145 *icmp_145;
+
+ icmp_145 = (struct icmpv6_type_145 *)
+ pkt_pull(pkt,sizeof(*icmp_145));
+ if (icmp_145 == NULL)
+ return 0;
+
+ tprintf(", ID (%u)",ntohs(icmp_145->id));
+ tprintf(", Res (0x%x)",ntohs(icmp_145->res));
+
+ return print_ipv6_addr_list(pkt, pkt_len(pkt) /
+ sizeof(struct in6_addr));
+}
+
+static inline int8_t dissect_icmpv6_type146(struct pkt_buff *pkt)
+{
+ return dissect_icmpv6_type144(pkt);
+}
+
+static int8_t dissect_icmpv6_type147(struct pkt_buff *pkt)
+{
+ uint16_t m_o_res;
+ struct icmpv6_type_147 *icmp_147;
+
+ icmp_147 = (struct icmpv6_type_147 *)
+ pkt_pull(pkt,sizeof(*icmp_147));
+ if (icmp_147 == NULL)
+ return 0;
+ m_o_res = ntohs(icmp_147->m_o_res);
+
+ tprintf(", ID (%u)",ntohs(icmp_147->id));
+ tprintf(", M (%u) O (%u) Res (0x%x)",m_o_res >> 15,
+ (m_o_res >> 14) & 1, m_o_res & 0x3FFF);
+
+ return dissect_neighb_disc_ops(pkt);
+}
+
+static int8_t dissect_icmpv6_type148(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_148 *icmp_148;
+
+ icmp_148 = (struct icmpv6_type_148 *)
+ pkt_pull(pkt,sizeof(*icmp_148));
+ if (icmp_148 == NULL)
+ return 0;
+
+ tprintf(", ID (%u)",ntohs(icmp_148->id));
+ tprintf(", Component (%u)",ntohs(icmp_148->comp));
+
+ return dissect_neighb_disc_ops(pkt);
+}
+
+static int8_t dissect_icmpv6_type149(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_149 *icmp_149;
+
+ icmp_149 = (struct icmpv6_type_149 *)
+ pkt_pull(pkt,sizeof(*icmp_149));
+ if (icmp_149 == NULL)
+ return 0;
+
+ tprintf(", ID (%u)",ntohs(icmp_149->id));
+ tprintf(", All Components (%u)",ntohs(icmp_149->all_comp));
+ tprintf(", Component (%u)",ntohs(icmp_149->comp));
+ tprintf(", Res (0x%x)",ntohs(icmp_149->res));
+
+ return dissect_neighb_disc_ops(pkt);
+}
+
+static int8_t dissect_icmpv6_type150(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_150 *icmp_150;
+
+ icmp_150 = (struct icmpv6_type_150 *)
+ pkt_pull(pkt,sizeof(*icmp_150));
+ if (icmp_150 == NULL)
+ return 0;
+
+ tprintf(", Subtype (%u)",icmp_150->subtype);
+ tprintf(", Res (0x%x)",icmp_150->res);
+ tprintf(", Options in Payload");
+
+ return 1;
+}
+
+static int8_t dissect_icmpv6_type151(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_151 *icmp_151;
+
+ icmp_151 = (struct icmpv6_type_151 *)
+ pkt_pull(pkt,sizeof(*icmp_151));
+ if (icmp_151 == NULL)
+ return 0;
+
+ tprintf(", Query Interval (%us)",ntohs(icmp_151->query_intv));
+ tprintf(", Robustness Variable (%u)",ntohs(icmp_151->rob_var));
+
+ return 1;
+}
+
+static int8_t dissect_icmpv6_type152(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_152 *icmp_152;
+
+ icmp_152 = (struct icmpv6_type_152 *)
+ pkt_pull(pkt,sizeof(*icmp_152));
+ if (icmp_152 == NULL)
+ return 0;
+
+ return 1;
+}
+
+static int8_t dissect_icmpv6_type153(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_153 *icmp_153;
+
+ icmp_153 = (struct icmpv6_type_153 *)
+ pkt_pull(pkt,sizeof(*icmp_153));
+ if (icmp_153 == NULL)
+ return 0;
+
+ return 1;
+}
+
+static int8_t dissect_icmpv6_type154(struct pkt_buff *pkt)
+{
+ struct icmpv6_type_154 *icmp_154;
+
+ icmp_154 = (struct icmpv6_type_154 *)
+ pkt_pull(pkt,sizeof(*icmp_154));
+ if (icmp_154 == NULL)
+ return 0;
+
+ tprintf(", Subtype (%u)",icmp_154->subtype);
+ tprintf(", Res (0x%x)",icmp_154->res);
+ tprintf(", ID (%u)",ntohs(icmp_154->id));
+
+ return dissect_neighb_disc_ops(pkt);
+}
+
+static inline char *icmpv6_type_155_codes(uint8_t code) {
+ switch (code) {
+ case 0x00: return "DODAG Information Solicitation";
+ case 0x01: return "DODAG Information Object";
+ case 0x02: return "Destination Advertisement Object";
+ case 0x03: return "Destination Advertisement Object Acknowledgment";
+ case 0x80: return "Secure DODAG Information Solicitation";
+ case 0x81: return "Secure DODAG Information Object";
+ case 0x82: return "Secure Destination Advertisement Object";
+ case 0x83: return "Secure Destination Advertisement Object Acknowledgment";
+ case 0x8A: return "Consistency Check";
+ }
+
+ return NULL;
+};
+
+static void icmpv6_process(struct icmpv6_general_hdr *icmp, const char **type,
+ const char **code, int8_t (**optional)(struct pkt_buff *pkt))
+{
+ *type = "Unknown Type";
+ *code = "Unknown Code";
+
+ switch (icmp->h_type) {
+ case 1:
+ *type = "Destination Unreachable";
+ if (icmpv6_code_range_valid(icmp->h_code, icmpv6_type_1_codes))
+ *code = icmpv6_type_1_codes[icmp->h_code];
+ *optional = dissect_icmpv6_type1;
+ return;
+ case 2:
+ *type = "Packet Too Big";
+ *optional = dissect_icmpv6_type2;
+ return;
+ case 3:
+ *type = "Time Exceeded";
+ if (icmpv6_code_range_valid(icmp->h_code, icmpv6_type_3_codes))
+ *code = icmpv6_type_3_codes[icmp->h_code];
+ *optional = dissect_icmpv6_type3;
+ return;
+ case 4:
+ *type = "Parameter Problem";
+ if (icmpv6_code_range_valid(icmp->h_code, icmpv6_type_4_codes))
+ *code = icmpv6_type_4_codes[icmp->h_code];
+ *optional = dissect_icmpv6_type4;
+ return;
+ case 100:
+ *type = "Private experimation";
+ return;
+ case 101:
+ *type = "Private experimation";
+ return;
+ case 127:
+ *type = "Reserved for expansion of ICMPv6 error messages";
+ return;
+ case 128:
+ *type = "Echo Request";
+ *optional = dissect_icmpv6_type128;
+ return;
+ case 129:
+ *type = "Echo Reply";
+ *optional = dissect_icmpv6_type129;
+ return;
+ case 130:
+ *type = "Multicast Listener Query";
+ *optional = dissect_icmpv6_type130;
+ return;
+ case 131:
+ *type = "Multicast Listener Report";
+ *optional = dissect_icmpv6_type131;
+ return;
+ case 132:
+ *type = "Multicast Listener Done";
+ *optional = dissect_icmpv6_type132;
+ return;
+ case 133:
+ *type = "Router Solicitation";
+ *optional = dissect_icmpv6_type133;
+ return;
+ case 134:
+ *type = "Router Advertisement";
+ *optional = dissect_icmpv6_type134;
+ return;
+ case 135:
+ *type = "Neighbor Solicitation";
+ *optional = dissect_icmpv6_type135;
+ return;
+ case 136:
+ *type = "Neighbor Advertisement";
+ *optional = dissect_icmpv6_type136;
+ return;
+ case 137:
+ *type = "Redirect Message";
+ *optional = dissect_icmpv6_type137;
+ return;
+ case 138:
+ *type = "Router Renumbering";
+ if(icmpv6_type_138_codes(icmp->h_code))
+ *code = icmpv6_type_138_codes(icmp->h_code);
+ *optional = dissect_icmpv6_type138;
+ return;
+ case 139:
+ *type = "ICMP Node Information Query";
+ if (icmpv6_code_range_valid(icmp->h_code,
+ icmpv6_type_139_codes))
+ *code = icmpv6_type_139_codes[icmp->h_code];
+ *optional = dissect_icmpv6_type139;
+ return;
+ case 140:
+ *type = "ICMP Node Information Response";
+ if (icmpv6_code_range_valid(icmp->h_code,
+ icmpv6_type_140_codes))
+ *code = icmpv6_type_140_codes[icmp->h_code];
+ *optional = dissect_icmpv6_type140;
+ return;
+ case 141:
+ *type = "Inverse Neighbor Discovery Solicitation Message";
+ *optional = dissect_icmpv6_type141;
+ return;
+ case 142:
+ *type = "Inverse Neighbor Discovery Advertisement Message";
+ *optional = dissect_icmpv6_type142;
+ return;
+ case 143:
+ *type = "Multicast Listener Report v2";
+ *optional = dissect_icmpv6_type143;
+ return;
+ case 144:
+ *type = "Home Agent Address Discovery Request Message";
+ *optional = dissect_icmpv6_type144;
+ return;
+ case 145:
+ *type = "Home Agent Address Discovery Reply Message";
+ *optional = dissect_icmpv6_type145;
+ return;
+ case 146:
+ *type = "Mobile Prefix Solicitation";
+ *optional = dissect_icmpv6_type146;
+ return;
+ case 147:
+ *type = "Mobile Prefix Advertisement";
+ *optional = dissect_icmpv6_type147;
+ return;
+ case 148:
+ *type = "Certification Path Solicitation";
+ *optional = dissect_icmpv6_type148;
+ return;
+ case 149:
+ *type = "Certification Path Advertisement";
+ *optional = dissect_icmpv6_type149;
+ return;
+ case 150:
+ *type = "ICMP messages utilized by experimental mobility "
+ "protocols such as Seamoby";
+ *optional = dissect_icmpv6_type150;
+ return;
+ case 151:
+ *type = "Multicast Router Advertisement";
+ *code = "Ad. Interval";
+ *optional = dissect_icmpv6_type151;
+ return;
+ case 152:
+ *type = "Multicast Router Solicitation";
+ *code = "Reserved";
+ *optional = dissect_icmpv6_type152;
+ return;
+ case 153:
+ *type = "Multicast Router Termination";
+ *code = "Reserved";
+ *optional = dissect_icmpv6_type153;
+ return;
+ case 154:
+ *type = "FMIPv6 Messages";
+ *optional = dissect_icmpv6_type154;
+ return;
+ case 155:
+ *type = "RPL Control Message";
+ if(icmpv6_type_155_codes(icmp->h_code))
+ *code = icmpv6_type_155_codes(icmp->h_code);
+ return;
+ case 200:
+ *type = "Private experimation";
+ return;
+ case 201:
+ *type = "Private experimation";
+ return;
+ case 255:
+ *type = "Reserved for expansion of ICMPv6 error messages";
+ return;
+ }
+}
+
+static void icmpv6(struct pkt_buff *pkt)
+{
+ const char *type = NULL, *code = NULL;
+ int8_t (*optional)(struct pkt_buff *pkt) = NULL;
+ struct icmpv6_general_hdr *icmp =
+ (struct icmpv6_general_hdr *) pkt_pull(pkt, sizeof(*icmp));
+
+ if (icmp == NULL)
+ return;
+
+ icmpv6_process(icmp, &type, &code, &optional);
+
+ tprintf(" [ ICMPv6 ");
+ tprintf("%s (%u), ", type, icmp->h_type);
+ tprintf("%s (%u), ", code, icmp->h_code);
+ tprintf("Chks (0x%x)", ntohs(icmp->h_chksum));
+ if (optional)
+ if (!((*optional) (pkt)))
+ tprintf("\n%s%s%s", colorize_start_full(black, red),
+ "Failed to dissect Message", colorize_end());
+ tprintf(" ]\n");
+}
+
+static void icmpv6_less(struct pkt_buff *pkt)
+{
+ struct icmpv6_general_hdr *icmp =
+ (struct icmpv6_general_hdr *) pkt_pull(pkt, sizeof(*icmp));
+
+ if (icmp == NULL)
+ return;
+
+ tprintf(" ICMPv6 Type (%u) Code (%u)", icmp->h_type, icmp->h_code);
+}
+
+struct protocol icmpv6_ops = {
+ .key = 0x3A,
+ .print_full = icmpv6,
+ .print_less = icmpv6_less,
+};