netdev
[Top] [All Lists]

Re: [PATCH] IPv6 IPsec support

To: Mitsuru KANDA / 神田 充 <mk@xxxxxxxxxx>
Subject: Re: [PATCH] IPv6 IPsec support
From: Kunihiro Ishiguro <kunihiro@xxxxxxxxxxxxxx>
Date: Wed, 19 Feb 2003 15:10:53 -0800
Cc: "David S. Miller" <davem@xxxxxxxxxx>, kuznet@xxxxxxxxxxxxx, netdev@xxxxxxxxxxx, usagi-core@xxxxxxxxxxxxxx
In-reply-to: <m3el645hv3.wl@xxxxxxxxxx>
References: <20030219134850.5f203ea7.Kazunori.Miyazawa@xxxxxxxxxxxxxxx> <20030218.233301.98333082.davem@xxxxxxxxxx> <m3el645hv3.wl@xxxxxxxxxx>
Sender: netdev-bounce@xxxxxxxxxxx
User-agent: Wanderlust/2.10.0 (Venus) SEMI/1.14.3 (Ushinoya) FLIM/1.14.2 (Yagi-Nishiguchi) APEL/10.3 Emacs/21.2.92 (i686-pc-linux-gnu) MULE/5.0 (SAKAKI)
This will not be useful other than Miyazaki/Kanda.  I've applied
miyazaki's patch then try to diff against local code.

o xfrm6_selector_match() fix

o No need of option field mutation in xfrm6_rcv().  It is moved to
  ah.c.

o Setting Routing Header's segment_lefts to 0 is wrong.  Let's let it be.

o xfrm6_rcv() try to figure out he is processing AH or ESP by
  ipv6hdr->protocol...  But when other extenstion header exits this
  could be wrong.  Initial protocol value is passed from the caller.

o Some cosmetic change.

And this patch include

o Not removing AH header

o Mutation field provisioning

But there changes are no needed.  Miyazaki, would you mind to take a
look into this?  Have fun ;-).
--
Kunihiro Ishiguro

diff -ruN linux-2.5.62.orig/include/net/ipv6.h linux-2.5.62/include/net/ipv6.h
--- linux-2.5.62.orig/include/net/ipv6.h        2003-02-14 15:52:28.000000000 
-0800
+++ linux-2.5.62/include/net/ipv6.h     2003-02-19 13:19:38.000000000 -0800
@@ -41,7 +41,7 @@
 
 #define NEXTHDR_MAX            255
 
-
+#define IP6OPT_MUTABLE  0x20
 
 #define IPV6_DEFAULT_HOPLIMIT   64
 #define IPV6_DEFAULT_MCASTHOPS 1
diff -ruN linux-2.5.62.orig/include/net/xfrm.h linux-2.5.62/include/net/xfrm.h
--- linux-2.5.62.orig/include/net/xfrm.h        2003-02-19 14:24:53.000000000 
-0800
+++ linux-2.5.62/include/net/xfrm.h     2003-02-19 14:03:20.000000000 -0800
@@ -414,7 +414,7 @@
 extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
 extern int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi 
*fl);
 extern int xfrm4_rcv(struct sk_buff *skb);
-extern int xfrm6_rcv(struct sk_buff *skb);
+extern int xfrm6_rcv(struct sk_buff *skb, u8 proto);
 extern int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, 
int dir);
 extern int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int 
optlen);
 
@@ -452,11 +452,37 @@
 extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name);
 extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name);
 
+static __inline__ int addr_match(void *token1, void *token2, int prefixlen)
+{
+       __u32 *a1 = token1;
+       __u32 *a2 = token2;
+       int pdw;
+       int pbi;
+
+       pdw = prefixlen >> 5;     /* num of whole __u32 in prefix */
+       pbi = prefixlen &  0x1f;  /* num of bits in incomplete u32 in prefix */
+
+       if (pdw)
+               if (memcmp(a1, a2, pdw << 2))
+                       return 0;
+
+       if (pbi) {
+               __u32 mask;
+
+               mask = htonl((0xffffffff) << (32 - pbi));
+
+               if ((a1[pdw] ^ a2[pdw]) & mask)
+                       return 0;
+       }
+
+       return 1;
+}
+
 static inline int
 xfrm6_selector_match(struct xfrm_selector *sel, struct flowi *fl)
 {
-       return  !memcmp(fl->fl6_dst, &sel->daddr, (sel->prefixlen_d)/8) &&
-               !memcmp(fl->fl6_src, &sel->saddr, (sel->prefixlen_s)/8) &&
+       return  !addr_match(fl->fl6_dst, &sel->daddr, sel->prefixlen_d) &&
+               !addr_match(fl->fl6_src, &sel->saddr, sel->prefixlen_s) &&
                !((fl->uli_u.ports.dport^sel->dport)&sel->dport_mask) &&
                !((fl->uli_u.ports.sport^sel->sport)&sel->sport_mask) &&
                (fl->proto == sel->proto || !sel->proto) &&
diff -ruN -x '*.o' -x '*.cmd' -x '*.ko' -x '*.mod.c' 
linux-2.5.62.orig/net/ipv6/ah.c linux-2.5.62/net/ipv6/ah.c
--- linux-2.5.62.orig/net/ipv6/ah.c     2003-02-19 14:24:53.000000000 -0800
+++ linux-2.5.62/net/ipv6/ah.c  2003-02-19 14:31:12.000000000 -0800
@@ -32,7 +32,6 @@
 
 #define AH_HLEN_NOICV   12
 
-/* XXX no ipv6 ah specific */
 #define NIP6(addr) \
        ntohs((addr).s6_addr16[0]),\
        ntohs((addr).s6_addr16[1]),\
@@ -43,6 +42,214 @@
        ntohs((addr).s6_addr16[6]),\
        ntohs((addr).s6_addr16[7])
 
+static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr)
+{
+       u8 *opt = (u8 *)opthdr;
+       int len = ipv6_optlen(opthdr);
+       int off = 0;
+       int optlen = 0;
+
+       off += 2;
+       len -= 2;
+
+       while (len > 0) {
+
+               switch (opt[off]) {
+
+               case IPV6_TLV_PAD0:
+                       optlen = 1;
+                       break;
+               default:
+                       if (len < 2) 
+                               goto bad;
+                       optlen = opt[off+1]+2;
+                       if (len < optlen)
+                               goto bad;
+                       if (opt[off] & 0x20)
+                               memset(&opt[off+2], 0, opt[off+1]);
+                       break;
+               }
+
+               off += optlen;
+               len -= optlen;
+       }
+       if (len == 0)
+               return 1;
+
+bad:
+       return 0;
+}
+
+int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int dir)
+{
+       u16 offset = sizeof(struct ipv6hdr);
+       struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + 
offset);
+       unsigned int packet_len = skb->tail - skb->nh.raw;
+       u8 nexthdr = skb->nh.ipv6h->nexthdr;
+       u8 nextnexthdr = 0;
+
+       *nh_offset = ((unsigned char *)&skb->nh.ipv6h->nexthdr) - skb->nh.raw;
+
+       while (offset + 1 <= packet_len) {
+
+               switch (nexthdr) {
+
+               case NEXTHDR_HOP:
+                       *nh_offset = offset;
+                       offset += ipv6_optlen(exthdr);
+                       if (!zero_out_mutable_opts(exthdr)) {
+                               if (net_ratelimit())
+                                       printk(KERN_WARNING "overrun 
hopopts\n"); 
+                               return 0;
+                       }
+                       nexthdr = exthdr->nexthdr;
+                       exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+                       break;
+
+               case NEXTHDR_ROUTING:
+                       *nh_offset = offset;
+                       offset += ipv6_optlen(exthdr);
+                       nexthdr = exthdr->nexthdr;
+                       exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+                       break;
+
+               case NEXTHDR_DEST:
+                       *nh_offset = offset;
+                       offset += ipv6_optlen(exthdr);
+                       if (!zero_out_mutable_opts(exthdr))  {
+                               if (net_ratelimit())
+                                       printk(KERN_WARNING "overrun 
destopt\n"); 
+                               return 0;
+                       }
+                       nexthdr = exthdr->nexthdr;
+                       exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+                       break;
+
+               case NEXTHDR_AUTH:
+                       if (dir == XFRM_POLICY_OUT) {
+                               memset(((struct 
ipv6_auth_hdr*)exthdr)->auth_data, 0, 
+                                      (((struct ipv6_auth_hdr*)exthdr)->hdrlen 
- 1) << 2);
+                       }
+                       if (exthdr->nexthdr == NEXTHDR_DEST) {
+                               offset += (((struct 
ipv6_auth_hdr*)exthdr)->hdrlen + 2) << 2;
+                               exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + 
offset);
+                               nextnexthdr = exthdr->nexthdr;
+                               if (!zero_out_mutable_opts(exthdr)) {
+                                       if (net_ratelimit())
+                                               printk(KERN_WARNING "overrun 
destopt\n");
+                                       return 0;
+                               }
+                       }
+                       return nexthdr;
+               default:
+                       return nexthdr;
+               }
+       }
+
+       return nexthdr;
+}
+
+static int ipv6_check_mutable_options(struct sk_buff *skb, struct ipv6hdr *hdr,
+                                     struct inet6_skb_parm *opt)
+{
+       int lim;
+       u8 *optpnt;
+       u8 nexthdr = hdr->nexthdr;
+       int datalen = 0;
+
+       optpnt = (u8*)(hdr+1);
+       lim = ntohs(hdr->payload_len);
+
+       while (lim > 0) {
+               struct ipv6_opt_hdr *opthdr;
+               int hdrlen;
+
+               opthdr = (struct ipv6_opt_hdr*)optpnt;
+
+               switch(nexthdr) {
+               case NEXTHDR_HOP:
+                       opt->hop = optpnt - skb->nh.raw;
+                       hdrlen = ipv6_optlen(opthdr);
+                       datalen += (hdrlen - 2);
+                       break;
+               case NEXTHDR_DEST:
+                       opt->dst1 = optpnt - skb->nh.raw;
+                       hdrlen = ipv6_optlen(opthdr);
+                       datalen += (hdrlen - 2);
+                       break;
+               case NEXTHDR_ROUTING:
+               case NEXTHDR_FRAGMENT:
+               case NEXTHDR_NONE:
+                       hdrlen = ipv6_optlen(opthdr);
+                       break;
+               case NEXTHDR_AUTH:
+                       hdrlen = (opthdr->hdrlen + 2) << 2;
+                       break;
+               default:
+                       goto out;
+               }
+               nexthdr = opthdr->nexthdr;
+               optpnt += hdrlen;
+               lim -= hdrlen;
+       }
+out:
+       return datalen;
+}
+
+static int ah6_set_option(u8 *opthdr, u8 **opt_data, int erase)
+{
+       u8 *optpnt = opthdr;
+       int len = ipv6_optlen((struct ipv6_opt_hdr*)opthdr);
+       int datalen;
+       int optlen;
+
+       optpnt += 2;
+       len -= 2;
+       datalen = len;
+
+       if (erase) {
+               memcpy(*opt_data, optpnt, datalen);
+
+               while (len > 0) {
+                       if (optpnt[0] == IPV6_TLV_PAD0) {
+                               optlen = 1;
+                       } else {
+                               if (len < 2)
+                                       return -1;
+                               optlen = optpnt[1] + 2;
+                               if (optlen > len)
+                                       return -1;
+                               if (optpnt[0] & IP6OPT_MUTABLE)
+                                       memset(optpnt+2, 0, optpnt[1]);
+                       }
+                       optpnt += optlen;
+                       len -= optlen;
+               }
+       } else {
+               memcpy(optpnt, *opt_data, datalen);
+       }
+
+       *opt_data += datalen;
+
+       return 0;
+}
+
+static inline void ah6_clear_mutable_options(struct sk_buff *skb, struct 
inet6_skb_parm *opt, u8 *opt_data)
+{
+       if (opt->hop)
+               ah6_set_option(skb->nh.raw+opt->hop, &opt_data, 1);
+       if (opt->dst1)
+               ah6_set_option(skb->nh.raw+opt->dst1, &opt_data, 1);
+}
+
+static inline void ah6_restore_mutable_options(struct sk_buff *skb, struct 
inet6_skb_parm *opt, u8 *opt_data)
+{
+       if (opt->hop)
+               ah6_set_option(skb->nh.raw+opt->hop, &opt_data, 0);
+       if (opt->dst1)
+               ah6_set_option(skb->nh.raw+opt->dst1, &opt_data, 0);
+}
+
 int ah6_output(struct sk_buff *skb)
 {
        int err;
@@ -50,6 +257,7 @@
        struct dst_entry *dst = skb->dst;
        struct xfrm_state *x  = dst->xfrm;
        struct ipv6hdr *iph = NULL;
+       struct ipv6hdr *top_hdr;
        struct ip_auth_hdr *ah;
        struct ah_data *ahp;
        u16 nh_offset = 0;
@@ -66,13 +274,13 @@
 
        if (x->props.mode) {
                iph = skb->nh.ipv6h;
-               skb->nh.ipv6h = (struct ipv6hdr*)skb_push(skb, 
x->props.header_len);
-               skb->nh.ipv6h->version = 6;
-               skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct 
ipv6hdr));
-               skb->nh.ipv6h->nexthdr = IPPROTO_AH;
-               memcpy(&skb->nh.ipv6h->saddr, &x->props.saddr, sizeof(struct 
in6_addr));
-               memcpy(&skb->nh.ipv6h->daddr, &x->id.daddr, sizeof(struct 
in6_addr));
-               ah = (struct ip_auth_hdr*)(skb->nh.ipv6h+1);
+               top_hdr = (struct ipv6hdr*)skb_push(skb, x->props.header_len);
+               top_hdr->version = 6;
+               top_hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+               top_hdr->nexthdr = IPPROTO_AH;
+               memcpy(&top_hdr->saddr, &x->props.saddr, sizeof(struct 
in6_addr));
+               memcpy(&top_hdr->daddr, &x->id.daddr, sizeof(struct in6_addr));
+               ah = (struct ip_auth_hdr*)(top_hdr+1);
                ah->nexthdr = IPPROTO_IPV6;
        } else {
                hdr_len = skb->h.raw - skb->nh.raw;
@@ -82,42 +290,40 @@
                        goto error;
                }
                memcpy(iph, skb->data, hdr_len);
-               skb->nh.ipv6h = (struct ipv6hdr*)skb_push(skb, 
x->props.header_len);
-               memcpy(skb->nh.ipv6h, iph, hdr_len);
+               top_hdr = (struct ipv6hdr*)skb_push(skb, x->props.header_len);
+               memcpy(top_hdr, iph, hdr_len);
                nexthdr = xfrm6_clear_mutable_options(skb, &nh_offset, 
XFRM_POLICY_OUT);
                if (nexthdr == 0)
                        goto error;
 
                skb->nh.raw[nh_offset] = IPPROTO_AH;
-               skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct 
ipv6hdr));
+               top_hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
                ah = (struct ip_auth_hdr*)(skb->nh.raw+hdr_len);
                ah->nexthdr = nexthdr;
        }
 
-       skb->nh.ipv6h->priority    = 0;
-       skb->nh.ipv6h->flow_lbl[0] = 0;
-       skb->nh.ipv6h->flow_lbl[1] = 0;
-       skb->nh.ipv6h->flow_lbl[2] = 0;
-       skb->nh.ipv6h->hop_limit    = 0;
+       skb->nh.ipv6h = top_hdr;
+       top_hdr->priority    = 0;
+       memset(top_hdr->flow_lbl, 0, 3);
+       top_hdr->hop_limit    = 0;
 
        ahp = x->data;
        ah->hdrlen  = (XFRM_ALIGN8(ahp->icv_trunc_len +
-               AH_HLEN_NOICV) >> 2) - 2;
+                       AH_HLEN_NOICV) >> 2) - 2;
+
        ah->reserved = 0;
        ah->spi = x->id.spi;
        ah->seq_no = htonl(++x->replay.oseq);
        ahp->icv(ahp, skb, ah->auth_data);
 
        if (x->props.mode) {
-               skb->nh.ipv6h->hop_limit   = iph->hop_limit;
-               skb->nh.ipv6h->priority    = iph->priority;     
-               skb->nh.ipv6h->flow_lbl[0] = iph->flow_lbl[0];
-               skb->nh.ipv6h->flow_lbl[1] = iph->flow_lbl[1];
-               skb->nh.ipv6h->flow_lbl[2] = iph->flow_lbl[2];
+               top_hdr->priority = iph->priority;      
+               memcpy(top_hdr->flow_lbl, iph->flow_lbl, 3);
+               top_hdr->hop_limit = iph->hop_limit;
        } else {
-               memcpy(skb->nh.ipv6h, iph, hdr_len);
+               memcpy(top_hdr, iph, hdr_len);
                skb->nh.raw[nh_offset] = IPPROTO_AH;
-               skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct 
ipv6hdr));
+               top_hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
                kfree (iph);
        }
 
@@ -139,42 +345,48 @@
 int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
 {
        int ah_hlen;
-       struct ipv6hdr *iph;
+       struct ipv6hdr *hdr;
        struct ipv6_auth_hdr *ah;
        struct ah_data *ahp;
-       unsigned char *tmp_hdr = NULL;
-       int hdr_len = skb->h.raw - skb->nh.raw;
-       u8 nexthdr = 0;
+       struct inet6_skb_parm opt;
+       char work_buf[8];
+       int optlen;
+       u8 *opt_data = NULL;
 
        if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
                goto out;
 
        ah = (struct ipv6_auth_hdr*)skb->data;
-
        ahp = x->data;
-        ah_hlen = (ah->hdrlen + 2) << 2;
+       ah_hlen = (ah->hdrlen + 2) << 2;
 
-        if (ah_hlen != XFRM_ALIGN8(ahp->icv_full_len + AH_HLEN_NOICV) &&
-            ah_hlen != XFRM_ALIGN8(ahp->icv_trunc_len + AH_HLEN_NOICV))
-                goto out;
+       if (ah_hlen != XFRM_ALIGN8(ahp->icv_full_len + AH_HLEN_NOICV) &&
+           ah_hlen != XFRM_ALIGN8(ahp->icv_trunc_len + AH_HLEN_NOICV))
+               goto out;
 
        if (!pskb_may_pull(skb, (ah->hdrlen+2)<<2))
                goto out;
 
-       /* We are going to _remove_ AH header to keep sockets happy,
-        * so... Later this can change. */
-       if (skb_cloned(skb) &&
-           pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
-               goto out;
-       tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC);
-       if (!tmp_hdr)
-               goto out;
-       memcpy(tmp_hdr, skb->nh.raw, hdr_len);
-       ah = (struct ipv6_auth_hdr*)skb->data;
-       iph = skb->nh.ipv6h;
+       hdr = skb->nh.ipv6h;
 
+       memcpy(work_buf, hdr, 8);
+       hdr->priority = 0;
+       memset(hdr->flow_lbl, 0, 3);
+       hdr->hop_limit = 0;
+
+       memset(&opt, 0, sizeof(struct inet6_skb_parm));
+       optlen = ipv6_check_mutable_options(skb, hdr, &opt);
+       if (optlen < 0)
+               goto out;
         {
                u8 auth_data[ahp->icv_trunc_len];
+               
+               if (optlen) {
+                       opt_data = kmalloc(optlen, GFP_ATOMIC);
+                       if (!opt_data)
+                               goto out;
+                       ah6_clear_mutable_options(skb, &opt, opt_data);
+               }
                memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
                memset(ah->auth_data, 0, ahp->icv_trunc_len);
                skb_push(skb, skb->data - skb->nh.raw);
@@ -185,22 +397,19 @@
                        x->stats.integrity_failed++;
                        goto free_out;
                }
+               if (optlen) {
+                       ah6_restore_mutable_options(skb, &opt, opt_data);
+                       kfree (opt_data);
+               }
        }
+       memcpy(hdr, work_buf, 8);
+       skb->h.raw += (ah->hdrlen+2)<<2;
+       skb->data = skb->h.raw;
 
-       nexthdr = ah->nexthdr;
-       skb->nh.raw = skb_pull(skb, (ah->hdrlen+2)<<2);
-       memcpy(skb->nh.raw, tmp_hdr, hdr_len);
-       skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
-       skb_pull(skb, hdr_len);
-       skb->h.raw = skb->data;
-
-
-       kfree(tmp_hdr);
-
-       return nexthdr;
-
+       return ah->nexthdr;
 free_out:
-       kfree(tmp_hdr);
+       if (optlen)
+               kfree(opt_data);
 out:
        return -EINVAL;
 }
@@ -208,22 +417,19 @@
 void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 
         int type, int code, int offset, __u32 info)
 {
-       struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
+       struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
        struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+offset);
        struct xfrm_state *x;
 
-       if (type != ICMPV6_DEST_UNREACH ||
-           type != ICMPV6_PKT_TOOBIG)
+       if (type != ICMPV6_DEST_UNREACH || type != ICMPV6_PKT_TOOBIG)
                return;
 
-       x = xfrm6_state_lookup(&iph->daddr, ah->spi, IPPROTO_AH);
+       x = xfrm6_state_lookup(&hdr->daddr, ah->spi, IPPROTO_AH);
        if (!x)
                return;
-
        printk(KERN_DEBUG "pmtu discvovery on SA AH/%08x/"
                        "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-              ntohl(ah->spi), NIP6(iph->daddr));
-
+              ntohl(ah->spi), NIP6(hdr->daddr));
        xfrm_state_put(x);
 }
 
@@ -315,26 +521,29 @@
        .output         = ah6_output
 };
 
+static inline int
+xfrm6_ah_rcv(struct sk_buff *skb)
+{
+       return xfrm6_rcv(skb, IPPROTO_AH);
+}
+
 static struct inet6_protocol ah6_protocol = {
-       .handler        =       xfrm6_rcv,
+       .handler        =       xfrm6_ah_rcv,
        .err_handler    =       ah6_err,
 };
 
 int __init ah6_init(void)
 {
        SET_MODULE_OWNER(&ah6_type);
-
        if (xfrm6_register_type(&ah6_type) < 0) {
                printk(KERN_INFO "ipv6 ah init: can't add xfrm type\n");
                return -EAGAIN;
        }
-
        if (inet6_add_protocol(&ah6_protocol, IPPROTO_AH) < 0) {
                printk(KERN_INFO "ipv6 ah init: can't add protocol\n");
                xfrm6_unregister_type(&ah6_type);
                return -EAGAIN;
        }
-
        return 0;
 }
 
@@ -342,10 +551,8 @@
 {
        if (inet6_del_protocol(&ah6_protocol, IPPROTO_AH) < 0)
                printk(KERN_INFO "ipv6 ah close: can't remove protocol\n");
-
        if (xfrm6_unregister_type(&ah6_type) < 0)
                printk(KERN_INFO "ipv6 ah close: can't remove xfrm type\n");
-
 }
 
 module_init(ah6_init);
diff -ruN -x '*.o' -x '*.cmd' -x '*.ko' -x '*.mod.c' 
linux-2.5.62.orig/net/ipv6/esp.c linux-2.5.62/net/ipv6/esp.c
--- linux-2.5.62.orig/net/ipv6/esp.c    2003-02-19 14:24:53.000000000 -0800
+++ linux-2.5.62/net/ipv6/esp.c 2003-02-19 14:20:43.000000000 -0800
@@ -35,10 +35,6 @@
 #include <linux/icmpv6.h>
 
 #define MAX_SG_ONSTACK 4
-#if 0
-typedef void (icv_update_fn_t)(struct crypto_tfm *,
-                       struct scatterlist *, unsigned int);
-#endif
 
 /* XXX no ipv6 esp specific */
 #define NIP6(addr) \
@@ -545,8 +541,14 @@
        .output         = esp6_output
 };
 
+static inline int
+xfrm6_esp_rcv(struct sk_buff *skb)
+{
+       return xfrm6_rcv(skb, IPPROTO_ESP);
+}
+
 static struct inet6_protocol esp6_protocol = {
-       .handler        =       xfrm6_rcv,
+       .handler        =       xfrm6_esp_rcv,
        .err_handler    =       esp6_err,
 };
 
diff -ruN -x '*.o' -x '*.cmd' -x '*.ko' -x '*.mod.c' 
linux-2.5.62.orig/net/ipv6/xfrm_input.c linux-2.5.62/net/ipv6/xfrm_input.c
--- linux-2.5.62.orig/net/ipv6/xfrm_input.c     2003-02-19 14:24:53.000000000 
-0800
+++ linux-2.5.62/net/ipv6/xfrm_input.c  2003-02-19 14:06:49.000000000 -0800
@@ -30,11 +30,11 @@
 
 /* Fetch spi and seq frpm ipsec header */
 
-static int xfrm6_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
+static int xfrm6_parse_spi(struct sk_buff *skb, u8 proto, u32 *spi, u32 *seq)
 {
        int offset, offset_seq;
 
-       switch (nexthdr) {
+       switch (proto) {
        case IPPROTO_AH:
                offset = offsetof(struct ip_auth_hdr, spi);
                offset_seq = offsetof(struct ip_auth_hdr, seq_no);
@@ -61,115 +61,7 @@
        return 0;
 }
 
-static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr)
-{
-       u8 *opt = (u8 *)opthdr;
-       int len = ipv6_optlen(opthdr);
-       int off = 0;
-       int optlen = 0;
-
-       off += 2;
-       len -= 2;
-
-       while (len > 0) {
-
-               switch (opt[off]) {
-
-               case IPV6_TLV_PAD0:
-                       optlen = 1;
-                       break;
-               default:
-                       if (len < 2) 
-                               goto bad;
-                       optlen = opt[off+1]+2;
-                       if (len < optlen)
-                               goto bad;
-                       if (opt[off] & 0x20)
-                               memset(&opt[off+2], 0, opt[off+1]);
-                       break;
-               }
-
-               off += optlen;
-               len -= optlen;
-       }
-       if (len == 0)
-               return 1;
-
-bad:
-       return 0;
-}
-
-int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int dir)
-{
-       u16 offset = sizeof(struct ipv6hdr);
-       struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + 
offset);
-       unsigned int packet_len = skb->tail - skb->nh.raw;
-       u8 nexthdr = skb->nh.ipv6h->nexthdr;
-       u8 nextnexthdr = 0;
-
-       *nh_offset = ((unsigned char *)&skb->nh.ipv6h->nexthdr) - skb->nh.raw;
-
-       while (offset + 1 <= packet_len) {
-
-               switch (nexthdr) {
-
-               case NEXTHDR_HOP:
-                       *nh_offset = offset;
-                       offset += ipv6_optlen(exthdr);
-                       if (!zero_out_mutable_opts(exthdr)) {
-                               if (net_ratelimit())
-                                       printk(KERN_WARNING "overrun 
hopopts\n"); 
-                               return 0;
-                       }
-                       nexthdr = exthdr->nexthdr;
-                       exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
-                       break;
-
-               case NEXTHDR_ROUTING:
-                       *nh_offset = offset;
-                       offset += ipv6_optlen(exthdr);
-                       ((struct ipv6_rt_hdr*)exthdr)->segments_left = 0; 
-                       nexthdr = exthdr->nexthdr;
-                       exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
-                       break;
-
-               case NEXTHDR_DEST:
-                       *nh_offset = offset;
-                       offset += ipv6_optlen(exthdr);
-                       if (!zero_out_mutable_opts(exthdr))  {
-                               if (net_ratelimit())
-                                       printk(KERN_WARNING "overrun 
destopt\n"); 
-                               return 0;
-                       }
-                       nexthdr = exthdr->nexthdr;
-                       exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
-                       break;
-
-               case NEXTHDR_AUTH:
-                       if (dir == XFRM_POLICY_OUT) {
-                               memset(((struct 
ipv6_auth_hdr*)exthdr)->auth_data, 0, 
-                                      (((struct ipv6_auth_hdr*)exthdr)->hdrlen 
- 1) << 2);
-                       }
-                       if (exthdr->nexthdr == NEXTHDR_DEST) {
-                               offset += (((struct 
ipv6_auth_hdr*)exthdr)->hdrlen + 2) << 2;
-                               exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + 
offset);
-                               nextnexthdr = exthdr->nexthdr;
-                               if (!zero_out_mutable_opts(exthdr)) {
-                                       if (net_ratelimit())
-                                               printk(KERN_WARNING "overrun 
destopt\n");
-                                       return 0;
-                               }
-                       }
-                       return nexthdr;
-               default:
-                       return nexthdr;
-               }
-       }
-
-       return nexthdr;
-}
-
-int xfrm6_rcv(struct sk_buff *skb)
+int xfrm6_rcv(struct sk_buff *skb, u8 proto)
 {
        int err;
        u32 spi, seq;
@@ -177,32 +69,10 @@
        struct xfrm_state *x;
        int xfrm_nr = 0;
        int decaps = 0;
-       struct ipv6hdr *hdr = skb->nh.ipv6h;
-       unsigned char *tmp_hdr = NULL;
-       int hdr_len = 0;
        u16 nh_offset = 0;
        u8 nexthdr = 0;
 
-       if (hdr->nexthdr == IPPROTO_AH || hdr->nexthdr == IPPROTO_ESP) {
-               nh_offset = ((unsigned char*)&skb->nh.ipv6h->nexthdr) - 
skb->nh.raw;
-               hdr_len = sizeof(struct ipv6hdr);
-       } else {
-               hdr_len = skb->h.raw - skb->nh.raw;
-       }
-
-       tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC);
-       if (!tmp_hdr)
-               goto drop;
-       memcpy(tmp_hdr, skb->nh.raw, hdr_len);
-
-       nexthdr = xfrm6_clear_mutable_options(skb, &nh_offset, XFRM_POLICY_IN);
-       hdr->priority    = 0;
-       hdr->flow_lbl[0] = 0;
-       hdr->flow_lbl[1] = 0;
-       hdr->flow_lbl[2] = 0;
-       hdr->hop_limit   = 0;
-
-       if ((err = xfrm6_parse_spi(skb, nexthdr, &spi, &seq)) != 0)
+       if ((err = xfrm6_parse_spi(skb, proto, &spi, &seq)) != 0)
                goto drop;
        
        do {
@@ -211,9 +81,10 @@
                if (xfrm_nr == XFRM_MAX_DEPTH)
                        goto drop;
 
-               x = xfrm6_state_lookup(&iph->daddr, spi, nexthdr);
+               x = xfrm6_state_lookup(&iph->daddr, spi, proto);
                if (x == NULL)
                        goto drop;
+
                spin_lock(&x->lock);
                if (unlikely(x->km.state != XFRM_STATE_VALID))
                        goto drop_unlock;
@@ -221,8 +92,8 @@
                if (x->props.replay_window && xfrm_replay_check(x, seq))
                        goto drop_unlock;
 
-               nexthdr = x->type->input(x, skb);
-               if (nexthdr <= 0)
+               proto = x->type->input(x, skb);
+               if (proto <= 0)
                        goto drop_unlock;
 
                if (x->props.replay_window)
@@ -237,13 +108,13 @@
 
                iph = skb->nh.ipv6h; /* ??? */ 
 
-               if (nexthdr == NEXTHDR_DEST) {
+               if (proto == NEXTHDR_DEST) {
                        if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
                        !pskb_may_pull(skb, 
(skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
                                err = -EINVAL;
                                goto drop;
                        }
-                       nexthdr = skb->h.raw[0];
+                       proto = skb->h.raw[0];
                        nh_offset = skb->h.raw - skb->nh.raw;
                        skb_pull(skb, (skb->h.raw[1]+1)<<3);
                        skb->h.raw = skb->data;
@@ -258,14 +129,10 @@
                        break;
                }
 
-               if ((err = xfrm6_parse_spi(skb, nexthdr, &spi, &seq)) < 0)
+               if ((err = xfrm6_parse_spi(skb, proto, &spi, &seq)) < 0)
                        goto drop;
        } while (!err);
 
-       memcpy(skb->nh.raw, tmp_hdr, hdr_len);
-       skb->nh.raw[nh_offset] = nexthdr;
-       skb->nh.ipv6h->payload_len = htons(hdr_len + skb->len - sizeof(struct 
ipv6hdr));
-
        /* Allocate new secpath or COW existing one. */
        if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
                struct sec_path *sp;
@@ -295,14 +162,13 @@
                netif_rx(skb);
                return 0;
        } else {
-               return -nexthdr;
+               return -proto;
        }
 
 drop_unlock:
        spin_unlock(&x->lock);
        xfrm_state_put(x);
 drop:
-       if (tmp_hdr) kfree(tmp_hdr);
        while (--xfrm_nr >= 0)
                xfrm_state_put(xfrm_vec[xfrm_nr]);
        kfree_skb(skb);
diff -ruN -x '*.o' -x '*.cmd' -x '*.ko' -x '*.mod.c' 
linux-2.5.62.orig/net/ipv6/xfrm_policy.c linux-2.5.62/net/ipv6/xfrm_policy.c
--- linux-2.5.62.orig/net/ipv6/xfrm_policy.c    2003-02-19 14:24:53.000000000 
-0800
+++ linux-2.5.62/net/ipv6/xfrm_policy.c 2003-02-19 02:50:41.000000000 -0800
@@ -229,7 +229,7 @@
        read_lock_bh(&xfrm_policy_lock);
        for (pol = xfrm_policy_list[dir]; pol; pol = pol->next) {
                struct xfrm_selector *sel = &pol->selector;
-               if (pol->family != AF_INET6) continue);
+               if (pol->family != AF_INET6) continue;
                if (xfrm6_selector_match(sel, fl)) {
                        atomic_inc(&pol->refcnt);
                        break;


<Prev in Thread] Current Thread [Next in Thread>