aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasahide NAKAMURA <nakam@linux-ipv6.org>2006-08-23 22:24:48 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 18:06:53 -0400
commita831f5bbc89a9978795504be9e1ff412043f8f77 (patch)
tree755b7e5478b64358a5716fdaa675516d9d36ab3d
parent842426e719f86cd5709617208efae93ff1a1e2d8 (diff)
[IPV6] MIP6: Add inbound interface of home address option.
Add inbound function of home address option by registering it to TLV table for destination options header. Based on MIPL2 kernel patch. This patch was also written by: Ville Nuorvala <vnuorval@tcs.hut.fi> 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/linux/ipv6.h3
-rw-r--r--net/ipv6/exthdrs.c84
2 files changed, 86 insertions, 1 deletions
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 5bf4406e26d4..db3b2ba0f4f8 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -226,6 +226,9 @@ struct inet6_skb_parm {
226 __u16 dst0; 226 __u16 dst0;
227 __u16 srcrt; 227 __u16 srcrt;
228 __u16 dst1; 228 __u16 dst1;
229#ifdef CONFIG_IPV6_MIP6
230 __u16 dsthao;
231#endif
229 __u16 lastopt; 232 __u16 lastopt;
230 __u32 nhoff; 233 __u32 nhoff;
231 __u16 flags; 234 __u16 flags;
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 1cdd0f0b5d34..6a6466bb5f26 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -196,8 +196,80 @@ bad:
196 Destination options header. 196 Destination options header.
197 *****************************/ 197 *****************************/
198 198
199#ifdef CONFIG_IPV6_MIP6
200static int ipv6_dest_hao(struct sk_buff **skbp, int optoff)
201{
202 struct sk_buff *skb = *skbp;
203 struct ipv6_destopt_hao *hao;
204 struct inet6_skb_parm *opt = IP6CB(skb);
205 struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb->nh.raw;
206 struct in6_addr tmp_addr;
207 int ret;
208
209 if (opt->dsthao) {
210 LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
211 goto discard;
212 }
213 opt->dsthao = opt->dst1;
214 opt->dst1 = 0;
215
216 hao = (struct ipv6_destopt_hao *)(skb->nh.raw + optoff);
217
218 if (hao->length != 16) {
219 LIMIT_NETDEBUG(
220 KERN_DEBUG "hao invalid option length = %d\n", hao->length);
221 goto discard;
222 }
223
224 if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
225 LIMIT_NETDEBUG(
226 KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr));
227 goto discard;
228 }
229
230 ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
231 (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
232 if (unlikely(ret < 0))
233 goto discard;
234
235 if (skb_cloned(skb)) {
236 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
237 if (skb2 == NULL)
238 goto discard;
239
240 kfree_skb(skb);
241
242 /* update all variable using below by copied skbuff */
243 *skbp = skb = skb2;
244 hao = (struct ipv6_destopt_hao *)(skb2->nh.raw + optoff);
245 ipv6h = (struct ipv6hdr *)skb2->nh.raw;
246 }
247
248 if (skb->ip_summed == CHECKSUM_COMPLETE)
249 skb->ip_summed = CHECKSUM_NONE;
250
251 ipv6_addr_copy(&tmp_addr, &ipv6h->saddr);
252 ipv6_addr_copy(&ipv6h->saddr, &hao->addr);
253 ipv6_addr_copy(&hao->addr, &tmp_addr);
254
255 if (skb->tstamp.off_sec == 0)
256 __net_timestamp(skb);
257
258 return 1;
259
260 discard:
261 kfree_skb(skb);
262 return 0;
263}
264#endif
265
199static struct tlvtype_proc tlvprocdestopt_lst[] = { 266static struct tlvtype_proc tlvprocdestopt_lst[] = {
200 /* No destination options are defined now */ 267#ifdef CONFIG_IPV6_MIP6
268 {
269 .type = IPV6_TLV_HAO,
270 .func = ipv6_dest_hao,
271 },
272#endif
201 {-1, NULL} 273 {-1, NULL}
202}; 274};
203 275
@@ -205,6 +277,9 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
205{ 277{
206 struct sk_buff *skb = *skbp; 278 struct sk_buff *skb = *skbp;
207 struct inet6_skb_parm *opt = IP6CB(skb); 279 struct inet6_skb_parm *opt = IP6CB(skb);
280#ifdef CONFIG_IPV6_MIP6
281 __u16 dstbuf;
282#endif
208 283
209 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || 284 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
210 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { 285 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
@@ -215,11 +290,18 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
215 290
216 opt->lastopt = skb->h.raw - skb->nh.raw; 291 opt->lastopt = skb->h.raw - skb->nh.raw;
217 opt->dst1 = skb->h.raw - skb->nh.raw; 292 opt->dst1 = skb->h.raw - skb->nh.raw;
293#ifdef CONFIG_IPV6_MIP6
294 dstbuf = opt->dst1;
295#endif
218 296
219 if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) { 297 if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) {
220 skb = *skbp; 298 skb = *skbp;
221 skb->h.raw += ((skb->h.raw[1]+1)<<3); 299 skb->h.raw += ((skb->h.raw[1]+1)<<3);
300#ifdef CONFIG_IPV6_MIP6
301 opt->nhoff = dstbuf;
302#else
222 opt->nhoff = opt->dst1; 303 opt->nhoff = opt->dst1;
304#endif
223 return 1; 305 return 1;
224 } 306 }
225 307