aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasahide NAKAMURA <nakam@linux-ipv6.org>2006-08-23 22:19:50 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 18:06:51 -0400
commita80ff03e05e4343d647780c116b02ec86078fd24 (patch)
tree71f62b9b95ad1b01b2af9d3032324bb2501ae703
parentc61a404325093250b676f40ad8f4dd00f3bcab5f (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.h2
-rw-r--r--net/ipv6/exthdrs.c29
-rw-r--r--net/ipv6/ip6_input.c2
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
232extern int ipv6_parse_hopopts(struct sk_buff *skb); 232extern int ipv6_parse_hopopts(struct sk_buff **skbp);
233 233
234extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt); 234extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt);
235extern struct ipv6_txoptions * ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, 235extern 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
103struct tlvtype_proc { 103struct 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
114static int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff) 114static 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
140static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb) 142static 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
520static int ipv6_hop_ra(struct sk_buff *skb, int optoff) 524static 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
534static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) 540static 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
584int ipv6_parse_hopopts(struct sk_buff *skb) 591int 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 }