diff options
author | Masahide NAKAMURA <nakam@linux-ipv6.org> | 2006-08-23 22:19:50 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 18:06:51 -0400 |
commit | a80ff03e05e4343d647780c116b02ec86078fd24 (patch) | |
tree | 71f62b9b95ad1b01b2af9d3032324bb2501ae703 | |
parent | c61a404325093250b676f40ad8f4dd00f3bcab5f (diff) |
[IPV6]: Allow to replace skbuff by TLV parser.
In receiving Mobile IPv6 home address option which is a TLV carried by
destination options header, kernel will try to mangle source adderss
of packet. Think of cloned skbuff it is required to replace it by the
parser just like routing header case.
This is a framework to achieve that to allow TLV parser to replace
inbound skbuff pointer.
Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org>
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/ipv6.h | 2 | ||||
-rw-r--r-- | net/ipv6/exthdrs.c | 29 | ||||
-rw-r--r-- | net/ipv6/ip6_input.c | 2 |
3 files changed, 21 insertions, 12 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index c4ea12710576..8e6ec6063f8c 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
@@ -229,7 +229,7 @@ extern int ip6_ra_control(struct sock *sk, int sel, | |||
229 | void (*destructor)(struct sock *)); | 229 | void (*destructor)(struct sock *)); |
230 | 230 | ||
231 | 231 | ||
232 | extern int ipv6_parse_hopopts(struct sk_buff *skb); | 232 | extern int ipv6_parse_hopopts(struct sk_buff **skbp); |
233 | 233 | ||
234 | extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt); | 234 | extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt); |
235 | extern struct ipv6_txoptions * ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, | 235 | extern struct ipv6_txoptions * ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, |
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 50ff49e518bc..1cdd0f0b5d34 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -102,7 +102,7 @@ int ipv6_find_tlv(struct sk_buff *skb, int offset, int type) | |||
102 | 102 | ||
103 | struct tlvtype_proc { | 103 | struct tlvtype_proc { |
104 | int type; | 104 | int type; |
105 | int (*func)(struct sk_buff *skb, int offset); | 105 | int (*func)(struct sk_buff **skbp, int offset); |
106 | }; | 106 | }; |
107 | 107 | ||
108 | /********************* | 108 | /********************* |
@@ -111,8 +111,10 @@ struct tlvtype_proc { | |||
111 | 111 | ||
112 | /* An unknown option is detected, decide what to do */ | 112 | /* An unknown option is detected, decide what to do */ |
113 | 113 | ||
114 | static int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff) | 114 | static int ip6_tlvopt_unknown(struct sk_buff **skbp, int optoff) |
115 | { | 115 | { |
116 | struct sk_buff *skb = *skbp; | ||
117 | |||
116 | switch ((skb->nh.raw[optoff] & 0xC0) >> 6) { | 118 | switch ((skb->nh.raw[optoff] & 0xC0) >> 6) { |
117 | case 0: /* ignore */ | 119 | case 0: /* ignore */ |
118 | return 1; | 120 | return 1; |
@@ -137,8 +139,9 @@ static int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff) | |||
137 | 139 | ||
138 | /* Parse tlv encoded option header (hop-by-hop or destination) */ | 140 | /* Parse tlv encoded option header (hop-by-hop or destination) */ |
139 | 141 | ||
140 | static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb) | 142 | static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff **skbp) |
141 | { | 143 | { |
144 | struct sk_buff *skb = *skbp; | ||
142 | struct tlvtype_proc *curr; | 145 | struct tlvtype_proc *curr; |
143 | int off = skb->h.raw - skb->nh.raw; | 146 | int off = skb->h.raw - skb->nh.raw; |
144 | int len = ((skb->h.raw[1]+1)<<3); | 147 | int len = ((skb->h.raw[1]+1)<<3); |
@@ -168,13 +171,13 @@ static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb) | |||
168 | /* type specific length/alignment | 171 | /* type specific length/alignment |
169 | checks will be performed in the | 172 | checks will be performed in the |
170 | func(). */ | 173 | func(). */ |
171 | if (curr->func(skb, off) == 0) | 174 | if (curr->func(skbp, off) == 0) |
172 | return 0; | 175 | return 0; |
173 | break; | 176 | break; |
174 | } | 177 | } |
175 | } | 178 | } |
176 | if (curr->type < 0) { | 179 | if (curr->type < 0) { |
177 | if (ip6_tlvopt_unknown(skb, off) == 0) | 180 | if (ip6_tlvopt_unknown(skbp, off) == 0) |
178 | return 0; | 181 | return 0; |
179 | } | 182 | } |
180 | break; | 183 | break; |
@@ -213,7 +216,8 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
213 | opt->lastopt = skb->h.raw - skb->nh.raw; | 216 | opt->lastopt = skb->h.raw - skb->nh.raw; |
214 | opt->dst1 = skb->h.raw - skb->nh.raw; | 217 | opt->dst1 = skb->h.raw - skb->nh.raw; |
215 | 218 | ||
216 | if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { | 219 | if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) { |
220 | skb = *skbp; | ||
217 | skb->h.raw += ((skb->h.raw[1]+1)<<3); | 221 | skb->h.raw += ((skb->h.raw[1]+1)<<3); |
218 | opt->nhoff = opt->dst1; | 222 | opt->nhoff = opt->dst1; |
219 | return 1; | 223 | return 1; |
@@ -517,8 +521,10 @@ EXPORT_SYMBOL_GPL(ipv6_invert_rthdr); | |||
517 | 521 | ||
518 | /* Router Alert as of RFC 2711 */ | 522 | /* Router Alert as of RFC 2711 */ |
519 | 523 | ||
520 | static int ipv6_hop_ra(struct sk_buff *skb, int optoff) | 524 | static int ipv6_hop_ra(struct sk_buff **skbp, int optoff) |
521 | { | 525 | { |
526 | struct sk_buff *skb = *skbp; | ||
527 | |||
522 | if (skb->nh.raw[optoff+1] == 2) { | 528 | if (skb->nh.raw[optoff+1] == 2) { |
523 | IP6CB(skb)->ra = optoff; | 529 | IP6CB(skb)->ra = optoff; |
524 | return 1; | 530 | return 1; |
@@ -531,8 +537,9 @@ static int ipv6_hop_ra(struct sk_buff *skb, int optoff) | |||
531 | 537 | ||
532 | /* Jumbo payload */ | 538 | /* Jumbo payload */ |
533 | 539 | ||
534 | static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) | 540 | static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff) |
535 | { | 541 | { |
542 | struct sk_buff *skb = *skbp; | ||
536 | u32 pkt_len; | 543 | u32 pkt_len; |
537 | 544 | ||
538 | if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) { | 545 | if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) { |
@@ -581,8 +588,9 @@ static struct tlvtype_proc tlvprochopopt_lst[] = { | |||
581 | { -1, } | 588 | { -1, } |
582 | }; | 589 | }; |
583 | 590 | ||
584 | int ipv6_parse_hopopts(struct sk_buff *skb) | 591 | int ipv6_parse_hopopts(struct sk_buff **skbp) |
585 | { | 592 | { |
593 | struct sk_buff *skb = *skbp; | ||
586 | struct inet6_skb_parm *opt = IP6CB(skb); | 594 | struct inet6_skb_parm *opt = IP6CB(skb); |
587 | 595 | ||
588 | /* | 596 | /* |
@@ -598,7 +606,8 @@ int ipv6_parse_hopopts(struct sk_buff *skb) | |||
598 | } | 606 | } |
599 | 607 | ||
600 | opt->hop = sizeof(struct ipv6hdr); | 608 | opt->hop = sizeof(struct ipv6hdr); |
601 | if (ip6_parse_tlv(tlvprochopopt_lst, skb)) { | 609 | if (ip6_parse_tlv(tlvprochopopt_lst, skbp)) { |
610 | skb = *skbp; | ||
602 | skb->h.raw += (skb->h.raw[1]+1)<<3; | 611 | skb->h.raw += (skb->h.raw[1]+1)<<3; |
603 | opt->nhoff = sizeof(struct ipv6hdr); | 612 | opt->nhoff = sizeof(struct ipv6hdr); |
604 | return 1; | 613 | return 1; |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 25c2a9e03895..6b8e6d76a58b 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
@@ -111,7 +111,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
111 | } | 111 | } |
112 | 112 | ||
113 | if (hdr->nexthdr == NEXTHDR_HOP) { | 113 | if (hdr->nexthdr == NEXTHDR_HOP) { |
114 | if (ipv6_parse_hopopts(skb) < 0) { | 114 | if (ipv6_parse_hopopts(&skb) < 0) { |
115 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 115 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); |
116 | return 0; | 116 | return 0; |
117 | } | 117 | } |