From: Kunihiro Ishiguro <kunihiro@ipinfusion.com>
To: "Mitsuru KANDA / 神田 充" <mk@karaba.org>
Cc: "David S. Miller" <davem@redhat.com>,
kuznet@ms2.inr.ac.ru, netdev@oss.sgi.com,
usagi-core@linux-ipv6.org
Subject: Re: [PATCH] IPv6 IPsec support
Date: Wed, 19 Feb 2003 15:10:53 -0800 [thread overview]
Message-ID: <87bs17hnnm.wl@ipinfusion.com> (raw)
In-Reply-To: <m3el645hv3.wl@karaba.org>
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;
next prev parent reply other threads:[~2003-02-19 23:10 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-02-19 4:48 [PATCH] IPv6 IPsec support Kazunori MIyazawa
2003-02-19 4:50 ` David S. Miller
2003-02-19 5:10 ` Kunihiro Ishiguro
2003-02-19 5:17 ` Mitsuru KANDA / 神田 充
2003-02-19 5:58 ` Kazunori Miyazawa
2003-02-19 5:30 ` YOSHIFUJI Hideaki / 吉藤英明
2003-02-19 5:57 ` Kunihiro Ishiguro
2003-02-19 7:02 ` David S. Miller
2003-02-19 9:13 ` Kunihiro Ishiguro
2003-02-19 7:13 ` David S. Miller
2003-02-19 7:33 ` David S. Miller
2003-02-19 14:39 ` (usagi-core 11926) " Kazunori MIyazawa
2003-02-19 21:27 ` David S. Miller
2003-02-19 16:56 ` Mitsuru KANDA / 神田 充
2003-02-19 21:43 ` David S. Miller
2003-02-19 23:10 ` Kunihiro Ishiguro [this message]
2003-02-20 0:37 ` David S. Miller
-- strict thread matches above, loose matches on Subject: below --
2003-02-22 11:26 [PATCH] IPv6 IPSEC support Kazunori Miyazawa
2003-02-22 11:13 ` David S. Miller
2003-02-22 12:15 ` Kazunori Miyazawa
2003-02-22 12:49 ` YOSHIFUJI Hideaki / 吉藤英明
2003-02-22 23:47 ` David S. Miller
2003-02-23 0:44 ` YOSHIFUJI Hideaki / 吉藤英明
2003-02-23 15:35 ` Kazunori Miyazawa
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87bs17hnnm.wl@ipinfusion.com \
--to=kunihiro@ipinfusion.com \
--cc=davem@redhat.com \
--cc=kuznet@ms2.inr.ac.ru \
--cc=mk@karaba.org \
--cc=netdev@oss.sgi.com \
--cc=usagi-core@linux-ipv6.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).