Commit 000936d4 authored by Mitsuru Kanda's avatar Mitsuru Kanda Committed by Christoph Hellwig

[IPV6]: Fix esp6 extension headers handling.

parent dad243d2
...@@ -315,7 +315,7 @@ extern int ip6_build_xmit(struct sock *sk, ...@@ -315,7 +315,7 @@ extern int ip6_build_xmit(struct sock *sk,
unsigned length, unsigned length,
struct ipv6_txoptions *opt, struct ipv6_txoptions *opt,
int hlimit, int flags); int hlimit, int flags);
extern int ip6_found_nexthdr(struct sk_buff *skb, u8 **nexthdr); extern int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr);
extern int ip6_append_data(struct sock *sk, extern int ip6_append_data(struct sock *sk,
int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb),
......
...@@ -39,57 +39,6 @@ ...@@ -39,57 +39,6 @@
#define MAX_SG_ONSTACK 4 #define MAX_SG_ONSTACK 4
/* BUGS:
* - we assume replay seqno is always present.
*/
/* Move to common area: it is shared with AH. */
/* Common with AH after some work on arguments. */
static int get_offset(u8 *packet, u32 packet_len, u8 *nexthdr, struct ipv6_opt_hdr **prevhdr)
{
u16 offset = sizeof(struct ipv6hdr);
struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(packet + offset);
u8 nextnexthdr;
*nexthdr = ((struct ipv6hdr*)packet)->nexthdr;
while (offset + 1 < packet_len) {
switch (*nexthdr) {
case NEXTHDR_HOP:
case NEXTHDR_ROUTING:
offset += ipv6_optlen(exthdr);
*nexthdr = exthdr->nexthdr;
*prevhdr = exthdr;
exthdr = (struct ipv6_opt_hdr*)(packet + offset);
break;
case NEXTHDR_DEST:
nextnexthdr =
((struct ipv6_opt_hdr*)(packet + offset + ipv6_optlen(exthdr)))->nexthdr;
/* XXX We know the option is inner dest opt
with next next header check. */
if (nextnexthdr != NEXTHDR_HOP &&
nextnexthdr != NEXTHDR_ROUTING &&
nextnexthdr != NEXTHDR_DEST) {
return offset;
}
offset += ipv6_optlen(exthdr);
*nexthdr = exthdr->nexthdr;
*prevhdr = exthdr;
exthdr = (struct ipv6_opt_hdr*)(packet + offset);
break;
default :
return offset;
}
}
return offset;
}
int esp6_output(struct sk_buff *skb) int esp6_output(struct sk_buff *skb)
{ {
int err; int err;
...@@ -101,12 +50,12 @@ int esp6_output(struct sk_buff *skb) ...@@ -101,12 +50,12 @@ int esp6_output(struct sk_buff *skb)
struct crypto_tfm *tfm; struct crypto_tfm *tfm;
struct esp_data *esp; struct esp_data *esp;
struct sk_buff *trailer; struct sk_buff *trailer;
struct ipv6_opt_hdr *prevhdr = NULL;
int blksize; int blksize;
int clen; int clen;
int alen; int alen;
int nfrags; int nfrags;
u8 nexthdr; u8 *prevhdr;
u8 nexthdr = 0;
/* First, if the skb is not checksummed, complete checksum. */ /* First, if the skb is not checksummed, complete checksum. */
if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) { if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) {
...@@ -123,7 +72,9 @@ int esp6_output(struct sk_buff *skb) ...@@ -123,7 +72,9 @@ int esp6_output(struct sk_buff *skb)
/* Strip IP header in transport mode. Save it. */ /* Strip IP header in transport mode. Save it. */
if (!x->props.mode) { if (!x->props.mode) {
hdr_len = get_offset(skb->nh.raw, skb->len, &nexthdr, &prevhdr); hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
nexthdr = *prevhdr;
*prevhdr = IPPROTO_ESP;
iph = kmalloc(hdr_len, GFP_ATOMIC); iph = kmalloc(hdr_len, GFP_ATOMIC);
if (!iph) { if (!iph) {
err = -ENOMEM; err = -ENOMEM;
...@@ -178,18 +129,12 @@ int esp6_output(struct sk_buff *skb) ...@@ -178,18 +129,12 @@ int esp6_output(struct sk_buff *skb)
ipv6_addr_copy(&top_iph->daddr, ipv6_addr_copy(&top_iph->daddr,
(struct in6_addr *)&x->id.daddr); (struct in6_addr *)&x->id.daddr);
} else { } else {
/* XXX exthdr */
esph = (struct ipv6_esp_hdr*)skb_push(skb, x->props.header_len); esph = (struct ipv6_esp_hdr*)skb_push(skb, x->props.header_len);
skb->h.raw = (unsigned char*)esph; skb->h.raw = (unsigned char*)esph;
top_iph = (struct ipv6hdr*)skb_push(skb, hdr_len); top_iph = (struct ipv6hdr*)skb_push(skb, hdr_len);
memcpy(top_iph, iph, hdr_len); memcpy(top_iph, iph, hdr_len);
kfree(iph); kfree(iph);
top_iph->payload_len = htons(skb->len + alen - sizeof(struct ipv6hdr)); top_iph->payload_len = htons(skb->len + alen - sizeof(struct ipv6hdr));
if (prevhdr) {
prevhdr->nexthdr = IPPROTO_ESP;
} else {
top_iph->nexthdr = IPPROTO_ESP;
}
*(u8*)(trailer->tail - 1) = nexthdr; *(u8*)(trailer->tail - 1) = nexthdr;
} }
...@@ -302,6 +247,7 @@ int esp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_b ...@@ -302,6 +247,7 @@ int esp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_b
struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags];
struct scatterlist *sg = sgbuf; struct scatterlist *sg = sgbuf;
u8 padlen; u8 padlen;
u8 *prevhdr;
if (unlikely(nfrags > MAX_SG_ONSTACK)) { if (unlikely(nfrags > MAX_SG_ONSTACK)) {
sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
...@@ -325,11 +271,13 @@ int esp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_b ...@@ -325,11 +271,13 @@ int esp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_b
} }
/* ... check padding bits here. Silly. :-) */ /* ... check padding bits here. Silly. :-) */
ret_nexthdr = ((struct ipv6hdr*)tmp_hdr)->nexthdr = nexthdr[1];
pskb_trim(skb, skb->len - alen - padlen - 2); pskb_trim(skb, skb->len - alen - padlen - 2);
skb->h.raw = skb_pull(skb, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen); skb->h.raw = skb_pull(skb, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen);
skb->nh.raw += sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen; skb->nh.raw += sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen;
memcpy(skb->nh.raw, tmp_hdr, hdr_len); memcpy(skb->nh.raw, tmp_hdr, hdr_len);
skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
ip6_find_1stfragopt(skb, &prevhdr);
ret_nexthdr = *prevhdr = nexthdr[1];
} }
kfree(tmp_hdr); kfree(tmp_hdr);
return ret_nexthdr; return ret_nexthdr;
......
...@@ -887,7 +887,7 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) ...@@ -887,7 +887,7 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
#endif #endif
} }
int ip6_found_nexthdr(struct sk_buff *skb, u8 **nexthdr) int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
{ {
u16 offset = sizeof(struct ipv6hdr); u16 offset = sizeof(struct ipv6hdr);
struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1); struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1);
...@@ -929,7 +929,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) ...@@ -929,7 +929,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
u8 *prevhdr, nexthdr = 0; u8 *prevhdr, nexthdr = 0;
dev = rt->u.dst.dev; dev = rt->u.dst.dev;
hlen = ip6_found_nexthdr(skb, &prevhdr); hlen = ip6_find_1stfragopt(skb, &prevhdr);
nexthdr = *prevhdr; nexthdr = *prevhdr;
mtu = dst_pmtu(&rt->u.dst) - hlen - sizeof(struct frag_hdr); mtu = dst_pmtu(&rt->u.dst) - hlen - sizeof(struct frag_hdr);
......
...@@ -105,7 +105,7 @@ static int ipcomp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, s ...@@ -105,7 +105,7 @@ static int ipcomp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, s
iph = skb->nh.ipv6h; iph = skb->nh.ipv6h;
iph->payload_len = htons(skb->len); iph->payload_len = htons(skb->len);
ip6_found_nexthdr(skb, &prevhdr); ip6_find_1stfragopt(skb, &prevhdr);
*prevhdr = nexthdr; *prevhdr = nexthdr;
out: out:
if (tmp_hdr) if (tmp_hdr)
...@@ -160,7 +160,7 @@ static int ipcomp6_output(struct sk_buff *skb) ...@@ -160,7 +160,7 @@ static int ipcomp6_output(struct sk_buff *skb)
skb->nh.raw = skb->data; /* == top_iph */ skb->nh.raw = skb->data; /* == top_iph */
skb->h.raw = skb->nh.raw + hdr_len; skb->h.raw = skb->nh.raw + hdr_len;
} else { } else {
hdr_len = ip6_found_nexthdr(skb, &prevhdr); hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
nexthdr = *prevhdr; nexthdr = *prevhdr;
} }
...@@ -203,7 +203,7 @@ static int ipcomp6_output(struct sk_buff *skb) ...@@ -203,7 +203,7 @@ static int ipcomp6_output(struct sk_buff *skb)
top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
skb->nh.raw = skb->data; /* top_iph */ skb->nh.raw = skb->data; /* top_iph */
ip6_found_nexthdr(skb, &prevhdr); ip6_find_1stfragopt(skb, &prevhdr);
*prevhdr = IPPROTO_COMP; *prevhdr = IPPROTO_COMP;
ipch = (struct ipv6_comp_hdr *)((unsigned char *)top_iph + hdr_len); ipch = (struct ipv6_comp_hdr *)((unsigned char *)top_iph + hdr_len);
......
...@@ -35,6 +35,6 @@ EXPORT_SYMBOL(ipv6_chk_addr); ...@@ -35,6 +35,6 @@ EXPORT_SYMBOL(ipv6_chk_addr);
EXPORT_SYMBOL(in6addr_any); EXPORT_SYMBOL(in6addr_any);
EXPORT_SYMBOL(in6addr_loopback); EXPORT_SYMBOL(in6addr_loopback);
EXPORT_SYMBOL(in6_dev_finish_destroy); EXPORT_SYMBOL(in6_dev_finish_destroy);
EXPORT_SYMBOL(ip6_found_nexthdr); EXPORT_SYMBOL(ip6_find_1stfragopt);
EXPORT_SYMBOL(xfrm6_rcv); EXPORT_SYMBOL(xfrm6_rcv);
EXPORT_SYMBOL(xfrm6_clear_mutable_options); EXPORT_SYMBOL(xfrm6_clear_mutable_options);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment