aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorMasahide NAKAMURA <nakam@linux-ipv6.org>2006-08-23 22:29:47 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 18:06:56 -0400
commit27637df92e25dfb45dd71a93a2f4bf9c080fa627 (patch)
treee4c477a1faff6faf7ae2812a921c06c4116f3731 /net
parent793832361fe7e9c3fcae2edd1d293c583a0a095c (diff)
[IPV6] IPSEC: Support sending with Mobile IPv6 extension headers.
Mobile IPv6 defines home address option as an option of destination options header. It is placed before fragment header then ip6_find_1stfragopt() is fixed to know about it. Home address option also carries final source address of the flow, then outbound AH calculation should take care of it like routing header case. Based on MIPL2 kernel patch. 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>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/ah6.c109
-rw-r--r--net/ipv6/ip6_output.c18
2 files changed, 122 insertions, 5 deletions
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 6c0aa51319a5..0f2b4e330aa9 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -74,6 +74,68 @@ bad:
74 return 0; 74 return 0;
75} 75}
76 76
77#ifdef CONFIG_IPV6_MIP6
78/**
79 * ipv6_rearrange_destopt - rearrange IPv6 destination options header
80 * @iph: IPv6 header
81 * @destopt: destionation options header
82 */
83static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *destopt)
84{
85 u8 *opt = (u8 *)destopt;
86 int len = ipv6_optlen(destopt);
87 int off = 0;
88 int optlen = 0;
89
90 off += 2;
91 len -= 2;
92
93 while (len > 0) {
94
95 switch (opt[off]) {
96
97 case IPV6_TLV_PAD0:
98 optlen = 1;
99 break;
100 default:
101 if (len < 2)
102 goto bad;
103 optlen = opt[off+1]+2;
104 if (len < optlen)
105 goto bad;
106
107 /* Rearrange the source address in @iph and the
108 * addresses in home address option for final source.
109 * See 11.3.2 of RFC 3775 for details.
110 */
111 if (opt[off] == IPV6_TLV_HAO) {
112 struct in6_addr final_addr;
113 struct ipv6_destopt_hao *hao;
114
115 hao = (struct ipv6_destopt_hao *)&opt[off];
116 if (hao->length != sizeof(hao->addr)) {
117 if (net_ratelimit())
118 printk(KERN_WARNING "destopt hao: invalid header length: %u\n", hao->length);
119 goto bad;
120 }
121 ipv6_addr_copy(&final_addr, &hao->addr);
122 ipv6_addr_copy(&hao->addr, &iph->saddr);
123 ipv6_addr_copy(&iph->saddr, &final_addr);
124 }
125 break;
126 }
127
128 off += optlen;
129 len -= optlen;
130 }
131 if (len == 0)
132 return;
133
134bad:
135 return;
136}
137#endif
138
77/** 139/**
78 * ipv6_rearrange_rthdr - rearrange IPv6 routing header 140 * ipv6_rearrange_rthdr - rearrange IPv6 routing header
79 * @iph: IPv6 header 141 * @iph: IPv6 header
@@ -113,7 +175,11 @@ static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr)
113 ipv6_addr_copy(&iph->daddr, &final_addr); 175 ipv6_addr_copy(&iph->daddr, &final_addr);
114} 176}
115 177
178#ifdef CONFIG_IPV6_MIP6
179static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
180#else
116static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len) 181static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len)
182#endif
117{ 183{
118 union { 184 union {
119 struct ipv6hdr *iph; 185 struct ipv6hdr *iph;
@@ -128,6 +194,28 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len)
128 194
129 while (exthdr.raw < end) { 195 while (exthdr.raw < end) {
130 switch (nexthdr) { 196 switch (nexthdr) {
197#ifdef CONFIG_IPV6_MIP6
198 case NEXTHDR_HOP:
199 if (!zero_out_mutable_opts(exthdr.opth)) {
200 LIMIT_NETDEBUG(
201 KERN_WARNING "overrun %sopts\n",
202 nexthdr == NEXTHDR_HOP ?
203 "hop" : "dest");
204 return -EINVAL;
205 }
206 break;
207 case NEXTHDR_DEST:
208 if (dir == XFRM_POLICY_OUT)
209 ipv6_rearrange_destopt(iph, exthdr.opth);
210 if (!zero_out_mutable_opts(exthdr.opth)) {
211 LIMIT_NETDEBUG(
212 KERN_WARNING "overrun %sopts\n",
213 nexthdr == NEXTHDR_HOP ?
214 "hop" : "dest");
215 return -EINVAL;
216 }
217 break;
218#else
131 case NEXTHDR_HOP: 219 case NEXTHDR_HOP:
132 case NEXTHDR_DEST: 220 case NEXTHDR_DEST:
133 if (!zero_out_mutable_opts(exthdr.opth)) { 221 if (!zero_out_mutable_opts(exthdr.opth)) {
@@ -138,6 +226,7 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len)
138 return -EINVAL; 226 return -EINVAL;
139 } 227 }
140 break; 228 break;
229#endif
141 230
142 case NEXTHDR_ROUTING: 231 case NEXTHDR_ROUTING:
143 ipv6_rearrange_rthdr(iph, exthdr.rth); 232 ipv6_rearrange_rthdr(iph, exthdr.rth);
@@ -164,6 +253,9 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
164 u8 nexthdr; 253 u8 nexthdr;
165 char tmp_base[8]; 254 char tmp_base[8];
166 struct { 255 struct {
256#ifdef CONFIG_IPV6_MIP6
257 struct in6_addr saddr;
258#endif
167 struct in6_addr daddr; 259 struct in6_addr daddr;
168 char hdrs[0]; 260 char hdrs[0];
169 } *tmp_ext; 261 } *tmp_ext;
@@ -188,10 +280,18 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
188 err = -ENOMEM; 280 err = -ENOMEM;
189 goto error; 281 goto error;
190 } 282 }
283#ifdef CONFIG_IPV6_MIP6
284 memcpy(tmp_ext, &top_iph->saddr, extlen);
285 err = ipv6_clear_mutable_options(top_iph,
286 extlen - sizeof(*tmp_ext) +
287 sizeof(*top_iph),
288 XFRM_POLICY_OUT);
289#else
191 memcpy(tmp_ext, &top_iph->daddr, extlen); 290 memcpy(tmp_ext, &top_iph->daddr, extlen);
192 err = ipv6_clear_mutable_options(top_iph, 291 err = ipv6_clear_mutable_options(top_iph,
193 extlen - sizeof(*tmp_ext) + 292 extlen - sizeof(*tmp_ext) +
194 sizeof(*top_iph)); 293 sizeof(*top_iph));
294#endif
195 if (err) 295 if (err)
196 goto error_free_iph; 296 goto error_free_iph;
197 } 297 }
@@ -222,7 +322,11 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
222 322
223 memcpy(top_iph, tmp_base, sizeof(tmp_base)); 323 memcpy(top_iph, tmp_base, sizeof(tmp_base));
224 if (tmp_ext) { 324 if (tmp_ext) {
325#ifdef CONFIG_IPV6_MIP6
326 memcpy(&top_iph->saddr, tmp_ext, extlen);
327#else
225 memcpy(&top_iph->daddr, tmp_ext, extlen); 328 memcpy(&top_iph->daddr, tmp_ext, extlen);
329#endif
226error_free_iph: 330error_free_iph:
227 kfree(tmp_ext); 331 kfree(tmp_ext);
228 } 332 }
@@ -282,8 +386,13 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
282 if (!tmp_hdr) 386 if (!tmp_hdr)
283 goto out; 387 goto out;
284 memcpy(tmp_hdr, skb->nh.raw, hdr_len); 388 memcpy(tmp_hdr, skb->nh.raw, hdr_len);
389#ifdef CONFIG_IPV6_MIP6
390 if (ipv6_clear_mutable_options(skb->nh.ipv6h, hdr_len, XFRM_POLICY_IN))
391 goto free_out;
392#else
285 if (ipv6_clear_mutable_options(skb->nh.ipv6h, hdr_len)) 393 if (ipv6_clear_mutable_options(skb->nh.ipv6h, hdr_len))
286 goto free_out; 394 goto free_out;
395#endif
287 skb->nh.ipv6h->priority = 0; 396 skb->nh.ipv6h->priority = 0;
288 skb->nh.ipv6h->flow_lbl[0] = 0; 397 skb->nh.ipv6h->flow_lbl[0] = 0;
289 skb->nh.ipv6h->flow_lbl[1] = 0; 398 skb->nh.ipv6h->flow_lbl[1] = 0;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 258e3e45f5e0..c14ea1ecf379 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -475,17 +475,25 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
475 switch (**nexthdr) { 475 switch (**nexthdr) {
476 476
477 case NEXTHDR_HOP: 477 case NEXTHDR_HOP:
478 break;
478 case NEXTHDR_ROUTING: 479 case NEXTHDR_ROUTING:
480 found_rhdr = 1;
481 break;
479 case NEXTHDR_DEST: 482 case NEXTHDR_DEST:
480 if (**nexthdr == NEXTHDR_ROUTING) found_rhdr = 1; 483#ifdef CONFIG_IPV6_MIP6
481 if (**nexthdr == NEXTHDR_DEST && found_rhdr) return offset; 484 if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
482 offset += ipv6_optlen(exthdr); 485 break;
483 *nexthdr = &exthdr->nexthdr; 486#endif
484 exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); 487 if (found_rhdr)
488 return offset;
485 break; 489 break;
486 default : 490 default :
487 return offset; 491 return offset;
488 } 492 }
493
494 offset += ipv6_optlen(exthdr);
495 *nexthdr = &exthdr->nexthdr;
496 exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
489 } 497 }
490 498
491 return offset; 499 return offset;