+ sm->src.family = IPv4;
+ sm->src.ip.v4 = hdr->ip_src.s_addr;
+
+ sm->dst.family = IPv4;
+ sm->dst.ip.v4 = hdr->ip_dst.s_addr;
+
+ helper_ip_deeper(pdata + IP_HDR_LEN, len - IP_HDR_LEN, sm);
+ return 1;
+}
+
+static int helper_ipv6(HELPER_ARGS) {
+ const struct ip6_hdr *hdr = (const struct ip6_hdr *)pdata;
+
+ if (len < IPV6_HDR_LEN) {
+ verbosef("ipv6: packet too short (%u bytes)", len);
+ return 0;
+ }
+ if ((hdr->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
+ verbosef("ipv6: bad version (%02x, expecting %02x)",
+ hdr->ip6_vfc & IPV6_VERSION_MASK, IPV6_VERSION);
+ return 0;
+ }
+
+ /* IPv4 has "total length," but IPv6 has "payload length" which doesn't
+ * count the header bytes.
+ */
+ sm->len = ntohs(hdr->ip6_plen) + IPV6_HDR_LEN;
+ sm->proto = hdr->ip6_nxt;
+ sm->src.family = IPv6;
+ memcpy(&sm->src.ip.v6, &hdr->ip6_src, sizeof(sm->src.ip.v6));
+ sm->dst.family = IPv6;
+ memcpy(&sm->dst.ip.v6, &hdr->ip6_dst, sizeof(sm->dst.ip.v6));
+
+ /* Don't do proto accounting if this packet uses extension headers. */
+ switch (sm->proto) {
+ case 0: /* Hop-by-Hop Options */
+ case IPPROTO_NONE:
+ case IPPROTO_DSTOPTS:
+ case IPPROTO_ROUTING:
+ case IPPROTO_FRAGMENT:
+ case IPPROTO_AH:
+ case IPPROTO_ESP:
+ case 135: /* Mobility */
+ sm->proto = IPPROTO_INVALID;
+ return 1; /* but we have addresses, so host accounting is ok */
+
+ default:
+ helper_ip_deeper(pdata + IPV6_HDR_LEN, len - IPV6_HDR_LEN, sm);
+ return 1;
+ }
+}
+
+static void helper_ip_deeper(HELPER_ARGS) {
+ /* At this stage we have IP addresses so we can do host accounting.
+ * If proto decode fails, we set IPPROTO_INVALID to skip proto accounting.
+ * We don't need to "return 0" like other helpers.
+ */