aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-03-18 14:09:07 -0400
committerDavid S. Miller <davem@davemloft.net>2014-03-18 14:09:07 -0400
commit995dca4ce9dddf48597bd3e0427447acd4509f1d (patch)
treeea74e64d0cf2b957ff4dc22e53f4140eabfb0495 /net/ipv6
parentd70e941bff5f223017ba7001b8eb0423a636c070 (diff)
parent61220ab349485d911083d0b7990ccd3db6c63297 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next
Steffen Klassert says: ==================== One patch to rename a newly introduced struct. The rest is the rework of the IPsec virtual tunnel interface for ipv6 to support inter address family tunneling and namespace crossing. 1) Rename the newly introduced struct xfrm_filter to avoid a conflict with iproute2. From Nicolas Dichtel. 2) Introduce xfrm_input_afinfo to access the address family dependent tunnel callback functions properly. 3) Add and use a IPsec protocol multiplexer for ipv6. 4) Remove dst_entry caching. vti can lookup multiple different dst entries, dependent of the configured xfrm states. Therefore it does not make to cache a dst_entry. 5) Remove caching of flow informations. vti6 does not use the the tunnel endpoint addresses to do route and xfrm lookups. 6) Update the vti6 to use its own receive hook. 7) Remove the now unused xfrm_tunnel_notifier. This was used from vti and is replaced by the IPsec protocol multiplexer hooks. 8) Support inter address family tunneling for vti6. 9) Check if the tunnel endpoints of the xfrm state and the vti interface are matching and return an error otherwise. 10) Enable namespace crossing for vti devices. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/Makefile2
-rw-r--r--net/ipv6/ah6.c24
-rw-r--r--net/ipv6/esp6.c26
-rw-r--r--net/ipv6/ip6_vti.c308
-rw-r--r--net/ipv6/ipcomp6.c22
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c63
-rw-r--r--net/ipv6/xfrm6_policy.c7
-rw-r--r--net/ipv6/xfrm6_protocol.c270
8 files changed, 543 insertions, 179 deletions
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 17bb830872db..2fe68364bb20 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -16,7 +16,7 @@ ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o
16ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o 16ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o
17 17
18ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ 18ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \
19 xfrm6_output.o 19 xfrm6_output.o xfrm6_protocol.o
20ipv6-$(CONFIG_NETFILTER) += netfilter.o 20ipv6-$(CONFIG_NETFILTER) += netfilter.o
21ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o 21ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o
22ipv6-$(CONFIG_PROC_FS) += proc.o 22ipv6-$(CONFIG_PROC_FS) += proc.o
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 6c5f0949e0ab..72a4930bdc0a 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -643,8 +643,8 @@ out:
643 return err; 643 return err;
644} 644}
645 645
646static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 646static int ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
647 u8 type, u8 code, int offset, __be32 info) 647 u8 type, u8 code, int offset, __be32 info)
648{ 648{
649 struct net *net = dev_net(skb->dev); 649 struct net *net = dev_net(skb->dev);
650 struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; 650 struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
@@ -653,17 +653,19 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
653 653
654 if (type != ICMPV6_PKT_TOOBIG && 654 if (type != ICMPV6_PKT_TOOBIG &&
655 type != NDISC_REDIRECT) 655 type != NDISC_REDIRECT)
656 return; 656 return 0;
657 657
658 x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); 658 x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6);
659 if (!x) 659 if (!x)
660 return; 660 return 0;
661 661
662 if (type == NDISC_REDIRECT) 662 if (type == NDISC_REDIRECT)
663 ip6_redirect(skb, net, skb->dev->ifindex, 0); 663 ip6_redirect(skb, net, skb->dev->ifindex, 0);
664 else 664 else
665 ip6_update_pmtu(skb, net, info, 0, 0); 665 ip6_update_pmtu(skb, net, info, 0, 0);
666 xfrm_state_put(x); 666 xfrm_state_put(x);
667
668 return 0;
667} 669}
668 670
669static int ah6_init_state(struct xfrm_state *x) 671static int ah6_init_state(struct xfrm_state *x)
@@ -748,6 +750,11 @@ static void ah6_destroy(struct xfrm_state *x)
748 kfree(ahp); 750 kfree(ahp);
749} 751}
750 752
753static int ah6_rcv_cb(struct sk_buff *skb, int err)
754{
755 return 0;
756}
757
751static const struct xfrm_type ah6_type = 758static const struct xfrm_type ah6_type =
752{ 759{
753 .description = "AH6", 760 .description = "AH6",
@@ -761,10 +768,11 @@ static const struct xfrm_type ah6_type =
761 .hdr_offset = xfrm6_find_1stfragopt, 768 .hdr_offset = xfrm6_find_1stfragopt,
762}; 769};
763 770
764static const struct inet6_protocol ah6_protocol = { 771static struct xfrm6_protocol ah6_protocol = {
765 .handler = xfrm6_rcv, 772 .handler = xfrm6_rcv,
773 .cb_handler = ah6_rcv_cb,
766 .err_handler = ah6_err, 774 .err_handler = ah6_err,
767 .flags = INET6_PROTO_NOPOLICY, 775 .priority = 0,
768}; 776};
769 777
770static int __init ah6_init(void) 778static int __init ah6_init(void)
@@ -774,7 +782,7 @@ static int __init ah6_init(void)
774 return -EAGAIN; 782 return -EAGAIN;
775 } 783 }
776 784
777 if (inet6_add_protocol(&ah6_protocol, IPPROTO_AH) < 0) { 785 if (xfrm6_protocol_register(&ah6_protocol, IPPROTO_AH) < 0) {
778 pr_info("%s: can't add protocol\n", __func__); 786 pr_info("%s: can't add protocol\n", __func__);
779 xfrm_unregister_type(&ah6_type, AF_INET6); 787 xfrm_unregister_type(&ah6_type, AF_INET6);
780 return -EAGAIN; 788 return -EAGAIN;
@@ -785,7 +793,7 @@ static int __init ah6_init(void)
785 793
786static void __exit ah6_fini(void) 794static void __exit ah6_fini(void)
787{ 795{
788 if (inet6_del_protocol(&ah6_protocol, IPPROTO_AH) < 0) 796 if (xfrm6_protocol_deregister(&ah6_protocol, IPPROTO_AH) < 0)
789 pr_info("%s: can't remove protocol\n", __func__); 797 pr_info("%s: can't remove protocol\n", __func__);
790 798
791 if (xfrm_unregister_type(&ah6_type, AF_INET6) < 0) 799 if (xfrm_unregister_type(&ah6_type, AF_INET6) < 0)
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 6eef8a7e35f2..d15da1377149 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -421,8 +421,8 @@ static u32 esp6_get_mtu(struct xfrm_state *x, int mtu)
421 net_adj) & ~(blksize - 1)) + net_adj - 2; 421 net_adj) & ~(blksize - 1)) + net_adj - 2;
422} 422}
423 423
424static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 424static int esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
425 u8 type, u8 code, int offset, __be32 info) 425 u8 type, u8 code, int offset, __be32 info)
426{ 426{
427 struct net *net = dev_net(skb->dev); 427 struct net *net = dev_net(skb->dev);
428 const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data; 428 const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data;
@@ -431,18 +431,20 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
431 431
432 if (type != ICMPV6_PKT_TOOBIG && 432 if (type != ICMPV6_PKT_TOOBIG &&
433 type != NDISC_REDIRECT) 433 type != NDISC_REDIRECT)
434 return; 434 return 0;
435 435
436 x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, 436 x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
437 esph->spi, IPPROTO_ESP, AF_INET6); 437 esph->spi, IPPROTO_ESP, AF_INET6);
438 if (!x) 438 if (!x)
439 return; 439 return 0;
440 440
441 if (type == NDISC_REDIRECT) 441 if (type == NDISC_REDIRECT)
442 ip6_redirect(skb, net, skb->dev->ifindex, 0); 442 ip6_redirect(skb, net, skb->dev->ifindex, 0);
443 else 443 else
444 ip6_update_pmtu(skb, net, info, 0, 0); 444 ip6_update_pmtu(skb, net, info, 0, 0);
445 xfrm_state_put(x); 445 xfrm_state_put(x);
446
447 return 0;
446} 448}
447 449
448static void esp6_destroy(struct xfrm_state *x) 450static void esp6_destroy(struct xfrm_state *x)
@@ -614,6 +616,11 @@ error:
614 return err; 616 return err;
615} 617}
616 618
619static int esp6_rcv_cb(struct sk_buff *skb, int err)
620{
621 return 0;
622}
623
617static const struct xfrm_type esp6_type = 624static const struct xfrm_type esp6_type =
618{ 625{
619 .description = "ESP6", 626 .description = "ESP6",
@@ -628,10 +635,11 @@ static const struct xfrm_type esp6_type =
628 .hdr_offset = xfrm6_find_1stfragopt, 635 .hdr_offset = xfrm6_find_1stfragopt,
629}; 636};
630 637
631static const struct inet6_protocol esp6_protocol = { 638static struct xfrm6_protocol esp6_protocol = {
632 .handler = xfrm6_rcv, 639 .handler = xfrm6_rcv,
640 .cb_handler = esp6_rcv_cb,
633 .err_handler = esp6_err, 641 .err_handler = esp6_err,
634 .flags = INET6_PROTO_NOPOLICY, 642 .priority = 0,
635}; 643};
636 644
637static int __init esp6_init(void) 645static int __init esp6_init(void)
@@ -640,7 +648,7 @@ static int __init esp6_init(void)
640 pr_info("%s: can't add xfrm type\n", __func__); 648 pr_info("%s: can't add xfrm type\n", __func__);
641 return -EAGAIN; 649 return -EAGAIN;
642 } 650 }
643 if (inet6_add_protocol(&esp6_protocol, IPPROTO_ESP) < 0) { 651 if (xfrm6_protocol_register(&esp6_protocol, IPPROTO_ESP) < 0) {
644 pr_info("%s: can't add protocol\n", __func__); 652 pr_info("%s: can't add protocol\n", __func__);
645 xfrm_unregister_type(&esp6_type, AF_INET6); 653 xfrm_unregister_type(&esp6_type, AF_INET6);
646 return -EAGAIN; 654 return -EAGAIN;
@@ -651,7 +659,7 @@ static int __init esp6_init(void)
651 659
652static void __exit esp6_fini(void) 660static void __exit esp6_fini(void)
653{ 661{
654 if (inet6_del_protocol(&esp6_protocol, IPPROTO_ESP) < 0) 662 if (xfrm6_protocol_deregister(&esp6_protocol, IPPROTO_ESP) < 0)
655 pr_info("%s: can't remove protocol\n", __func__); 663 pr_info("%s: can't remove protocol\n", __func__);
656 if (xfrm_unregister_type(&esp6_type, AF_INET6) < 0) 664 if (xfrm_unregister_type(&esp6_type, AF_INET6) < 0)
657 pr_info("%s: can't remove xfrm type\n", __func__); 665 pr_info("%s: can't remove xfrm type\n", __func__);
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
index 864914399391..b7c0f827140b 100644
--- a/net/ipv6/ip6_vti.c
+++ b/net/ipv6/ip6_vti.c
@@ -278,7 +278,6 @@ static void vti6_dev_uninit(struct net_device *dev)
278 RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); 278 RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
279 else 279 else
280 vti6_tnl_unlink(ip6n, t); 280 vti6_tnl_unlink(ip6n, t);
281 ip6_tnl_dst_reset(t);
282 dev_put(dev); 281 dev_put(dev);
283} 282}
284 283
@@ -288,11 +287,8 @@ static int vti6_rcv(struct sk_buff *skb)
288 const struct ipv6hdr *ipv6h = ipv6_hdr(skb); 287 const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
289 288
290 rcu_read_lock(); 289 rcu_read_lock();
291
292 if ((t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, 290 if ((t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
293 &ipv6h->daddr)) != NULL) { 291 &ipv6h->daddr)) != NULL) {
294 struct pcpu_sw_netstats *tstats;
295
296 if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) { 292 if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) {
297 rcu_read_unlock(); 293 rcu_read_unlock();
298 goto discard; 294 goto discard;
@@ -309,27 +305,58 @@ static int vti6_rcv(struct sk_buff *skb)
309 goto discard; 305 goto discard;
310 } 306 }
311 307
312 tstats = this_cpu_ptr(t->dev->tstats); 308 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t;
313 u64_stats_update_begin(&tstats->syncp); 309 skb->mark = be32_to_cpu(t->parms.i_key);
314 tstats->rx_packets++;
315 tstats->rx_bytes += skb->len;
316 u64_stats_update_end(&tstats->syncp);
317
318 skb->mark = 0;
319 secpath_reset(skb);
320 skb->dev = t->dev;
321 310
322 rcu_read_unlock(); 311 rcu_read_unlock();
323 return 0; 312
313 return xfrm6_rcv(skb);
324 } 314 }
325 rcu_read_unlock(); 315 rcu_read_unlock();
326 return 1; 316 return -EINVAL;
327
328discard: 317discard:
329 kfree_skb(skb); 318 kfree_skb(skb);
330 return 0; 319 return 0;
331} 320}
332 321
322static int vti6_rcv_cb(struct sk_buff *skb, int err)
323{
324 unsigned short family;
325 struct net_device *dev;
326 struct pcpu_sw_netstats *tstats;
327 struct xfrm_state *x;
328 struct ip6_tnl *t = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6;
329
330 if (!t)
331 return 1;
332
333 dev = t->dev;
334
335 if (err) {
336 dev->stats.rx_errors++;
337 dev->stats.rx_dropped++;
338
339 return 0;
340 }
341
342 x = xfrm_input_state(skb);
343 family = x->inner_mode->afinfo->family;
344
345 if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family))
346 return -EPERM;
347
348 skb_scrub_packet(skb, !net_eq(t->net, dev_net(skb->dev)));
349 skb->dev = dev;
350
351 tstats = this_cpu_ptr(dev->tstats);
352 u64_stats_update_begin(&tstats->syncp);
353 tstats->rx_packets++;
354 tstats->rx_bytes += skb->len;
355 u64_stats_update_end(&tstats->syncp);
356
357 return 0;
358}
359
333/** 360/**
334 * vti6_addr_conflict - compare packet addresses to tunnel's own 361 * vti6_addr_conflict - compare packet addresses to tunnel's own
335 * @t: the outgoing tunnel device 362 * @t: the outgoing tunnel device
@@ -349,44 +376,56 @@ vti6_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
349 return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); 376 return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
350} 377}
351 378
379static bool vti6_state_check(const struct xfrm_state *x,
380 const struct in6_addr *dst,
381 const struct in6_addr *src)
382{
383 xfrm_address_t *daddr = (xfrm_address_t *)dst;
384 xfrm_address_t *saddr = (xfrm_address_t *)src;
385
386 /* if there is no transform then this tunnel is not functional.
387 * Or if the xfrm is not mode tunnel.
388 */
389 if (!x || x->props.mode != XFRM_MODE_TUNNEL ||
390 x->props.family != AF_INET6)
391 return false;
392
393 if (ipv6_addr_any(dst))
394 return xfrm_addr_equal(saddr, &x->props.saddr, AF_INET6);
395
396 if (!xfrm_state_addr_check(x, daddr, saddr, AF_INET6))
397 return false;
398
399 return true;
400}
401
352/** 402/**
353 * vti6_xmit - send a packet 403 * vti6_xmit - send a packet
354 * @skb: the outgoing socket buffer 404 * @skb: the outgoing socket buffer
355 * @dev: the outgoing tunnel device 405 * @dev: the outgoing tunnel device
406 * @fl: the flow informations for the xfrm_lookup
356 **/ 407 **/
357static int vti6_xmit(struct sk_buff *skb, struct net_device *dev) 408static int
409vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
358{ 410{
359 struct net *net = dev_net(dev);
360 struct ip6_tnl *t = netdev_priv(dev); 411 struct ip6_tnl *t = netdev_priv(dev);
361 struct net_device_stats *stats = &t->dev->stats; 412 struct net_device_stats *stats = &t->dev->stats;
362 struct dst_entry *dst = NULL, *ndst = NULL; 413 struct dst_entry *dst = skb_dst(skb);
363 struct flowi6 fl6;
364 struct ipv6hdr *ipv6h = ipv6_hdr(skb);
365 struct net_device *tdev; 414 struct net_device *tdev;
366 int err = -1; 415 int err = -1;
367 416
368 if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) || 417 if (!dst)
369 !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h)) 418 goto tx_err_link_failure;
370 return err;
371
372 dst = ip6_tnl_dst_check(t);
373 if (!dst) {
374 memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
375
376 ndst = ip6_route_output(net, NULL, &fl6);
377 419
378 if (ndst->error) 420 dst_hold(dst);
379 goto tx_err_link_failure; 421 dst = xfrm_lookup(t->net, dst, fl, NULL, 0);
380 ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(&fl6), NULL, 0); 422 if (IS_ERR(dst)) {
381 if (IS_ERR(ndst)) { 423 err = PTR_ERR(dst);
382 err = PTR_ERR(ndst); 424 dst = NULL;
383 ndst = NULL; 425 goto tx_err_link_failure;
384 goto tx_err_link_failure;
385 }
386 dst = ndst;
387 } 426 }
388 427
389 if (!dst->xfrm || dst->xfrm->props.mode != XFRM_MODE_TUNNEL) 428 if (!vti6_state_check(dst->xfrm, &t->parms.raddr, &t->parms.laddr))
390 goto tx_err_link_failure; 429 goto tx_err_link_failure;
391 430
392 tdev = dst->dev; 431 tdev = dst->dev;
@@ -398,14 +437,21 @@ static int vti6_xmit(struct sk_buff *skb, struct net_device *dev)
398 goto tx_err_dst_release; 437 goto tx_err_dst_release;
399 } 438 }
400 439
440 skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev)));
441 skb_dst_set(skb, dst);
442 skb->dev = skb_dst(skb)->dev;
401 443
402 skb_dst_drop(skb); 444 err = dst_output(skb);
403 skb_dst_set_noref(skb, dst); 445 if (net_xmit_eval(err) == 0) {
446 struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
404 447
405 ip6tunnel_xmit(skb, dev); 448 u64_stats_update_begin(&tstats->syncp);
406 if (ndst) { 449 tstats->tx_bytes += skb->len;
407 dev->mtu = dst_mtu(ndst); 450 tstats->tx_packets++;
408 ip6_tnl_dst_store(t, ndst); 451 u64_stats_update_end(&tstats->syncp);
452 } else {
453 stats->tx_errors++;
454 stats->tx_aborted_errors++;
409 } 455 }
410 456
411 return 0; 457 return 0;
@@ -413,7 +459,7 @@ tx_err_link_failure:
413 stats->tx_carrier_errors++; 459 stats->tx_carrier_errors++;
414 dst_link_failure(skb); 460 dst_link_failure(skb);
415tx_err_dst_release: 461tx_err_dst_release:
416 dst_release(ndst); 462 dst_release(dst);
417 return err; 463 return err;
418} 464}
419 465
@@ -422,16 +468,33 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
422{ 468{
423 struct ip6_tnl *t = netdev_priv(dev); 469 struct ip6_tnl *t = netdev_priv(dev);
424 struct net_device_stats *stats = &t->dev->stats; 470 struct net_device_stats *stats = &t->dev->stats;
471 struct ipv6hdr *ipv6h;
472 struct flowi fl;
425 int ret; 473 int ret;
426 474
475 memset(&fl, 0, sizeof(fl));
476 skb->mark = be32_to_cpu(t->parms.o_key);
477
427 switch (skb->protocol) { 478 switch (skb->protocol) {
428 case htons(ETH_P_IPV6): 479 case htons(ETH_P_IPV6):
429 ret = vti6_xmit(skb, dev); 480 ipv6h = ipv6_hdr(skb);
481
482 if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
483 !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h))
484 goto tx_err;
485
486 xfrm_decode_session(skb, &fl, AF_INET6);
487 memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
488 break;
489 case htons(ETH_P_IP):
490 xfrm_decode_session(skb, &fl, AF_INET);
491 memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
430 break; 492 break;
431 default: 493 default:
432 goto tx_err; 494 goto tx_err;
433 } 495 }
434 496
497 ret = vti6_xmit(skb, dev, &fl);
435 if (ret < 0) 498 if (ret < 0)
436 goto tx_err; 499 goto tx_err;
437 500
@@ -444,24 +507,66 @@ tx_err:
444 return NETDEV_TX_OK; 507 return NETDEV_TX_OK;
445} 508}
446 509
510static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
511 u8 type, u8 code, int offset, __be32 info)
512{
513 __be32 spi;
514 struct xfrm_state *x;
515 struct ip6_tnl *t;
516 struct ip_esp_hdr *esph;
517 struct ip_auth_hdr *ah;
518 struct ip_comp_hdr *ipch;
519 struct net *net = dev_net(skb->dev);
520 const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data;
521 int protocol = iph->nexthdr;
522
523 t = vti6_tnl_lookup(dev_net(skb->dev), &iph->daddr, &iph->saddr);
524 if (!t)
525 return -1;
526
527 switch (protocol) {
528 case IPPROTO_ESP:
529 esph = (struct ip_esp_hdr *)(skb->data + offset);
530 spi = esph->spi;
531 break;
532 case IPPROTO_AH:
533 ah = (struct ip_auth_hdr *)(skb->data + offset);
534 spi = ah->spi;
535 break;
536 case IPPROTO_COMP:
537 ipch = (struct ip_comp_hdr *)(skb->data + offset);
538 spi = htonl(ntohs(ipch->cpi));
539 break;
540 default:
541 return 0;
542 }
543
544 if (type != ICMPV6_PKT_TOOBIG &&
545 type != NDISC_REDIRECT)
546 return 0;
547
548 x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
549 spi, protocol, AF_INET6);
550 if (!x)
551 return 0;
552
553 if (type == NDISC_REDIRECT)
554 ip6_redirect(skb, net, skb->dev->ifindex, 0);
555 else
556 ip6_update_pmtu(skb, net, info, 0, 0);
557 xfrm_state_put(x);
558
559 return 0;
560}
561
447static void vti6_link_config(struct ip6_tnl *t) 562static void vti6_link_config(struct ip6_tnl *t)
448{ 563{
449 struct dst_entry *dst;
450 struct net_device *dev = t->dev; 564 struct net_device *dev = t->dev;
451 struct __ip6_tnl_parm *p = &t->parms; 565 struct __ip6_tnl_parm *p = &t->parms;
452 struct flowi6 *fl6 = &t->fl.u.ip6;
453 566
454 memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); 567 memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
455 memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); 568 memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
456 569
457 /* Set up flowi template */
458 fl6->saddr = p->laddr;
459 fl6->daddr = p->raddr;
460 fl6->flowi6_oif = p->link;
461 fl6->flowi6_mark = be32_to_cpu(p->i_key);
462 fl6->flowi6_proto = p->proto;
463 fl6->flowlabel = 0;
464
465 p->flags &= ~(IP6_TNL_F_CAP_XMIT | IP6_TNL_F_CAP_RCV | 570 p->flags &= ~(IP6_TNL_F_CAP_XMIT | IP6_TNL_F_CAP_RCV |
466 IP6_TNL_F_CAP_PER_PACKET); 571 IP6_TNL_F_CAP_PER_PACKET);
467 p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr); 572 p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr);
@@ -472,28 +577,6 @@ static void vti6_link_config(struct ip6_tnl *t)
472 dev->flags &= ~IFF_POINTOPOINT; 577 dev->flags &= ~IFF_POINTOPOINT;
473 578
474 dev->iflink = p->link; 579 dev->iflink = p->link;
475
476 if (p->flags & IP6_TNL_F_CAP_XMIT) {
477
478 dst = ip6_route_output(dev_net(dev), NULL, fl6);
479 if (dst->error)
480 return;
481
482 dst = xfrm_lookup(dev_net(dev), dst, flowi6_to_flowi(fl6),
483 NULL, 0);
484 if (IS_ERR(dst))
485 return;
486
487 if (dst->dev) {
488 dev->hard_header_len = dst->dev->hard_header_len;
489
490 dev->mtu = dst_mtu(dst);
491
492 if (dev->mtu < IPV6_MIN_MTU)
493 dev->mtu = IPV6_MIN_MTU;
494 }
495 dst_release(dst);
496 }
497} 580}
498 581
499/** 582/**
@@ -720,7 +803,6 @@ static void vti6_dev_setup(struct net_device *dev)
720 t = netdev_priv(dev); 803 t = netdev_priv(dev);
721 dev->flags |= IFF_NOARP; 804 dev->flags |= IFF_NOARP;
722 dev->addr_len = sizeof(struct in6_addr); 805 dev->addr_len = sizeof(struct in6_addr);
723 dev->features |= NETIF_F_NETNS_LOCAL;
724 dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; 806 dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
725} 807}
726 808
@@ -908,11 +990,6 @@ static struct rtnl_link_ops vti6_link_ops __read_mostly = {
908 .fill_info = vti6_fill_info, 990 .fill_info = vti6_fill_info,
909}; 991};
910 992
911static struct xfrm_tunnel_notifier vti6_handler __read_mostly = {
912 .handler = vti6_rcv,
913 .priority = 1,
914};
915
916static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n) 993static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n)
917{ 994{
918 int h; 995 int h;
@@ -984,6 +1061,27 @@ static struct pernet_operations vti6_net_ops = {
984 .size = sizeof(struct vti6_net), 1061 .size = sizeof(struct vti6_net),
985}; 1062};
986 1063
1064static struct xfrm6_protocol vti_esp6_protocol __read_mostly = {
1065 .handler = vti6_rcv,
1066 .cb_handler = vti6_rcv_cb,
1067 .err_handler = vti6_err,
1068 .priority = 100,
1069};
1070
1071static struct xfrm6_protocol vti_ah6_protocol __read_mostly = {
1072 .handler = vti6_rcv,
1073 .cb_handler = vti6_rcv_cb,
1074 .err_handler = vti6_err,
1075 .priority = 100,
1076};
1077
1078static struct xfrm6_protocol vti_ipcomp6_protocol __read_mostly = {
1079 .handler = vti6_rcv,
1080 .cb_handler = vti6_rcv_cb,
1081 .err_handler = vti6_err,
1082 .priority = 100,
1083};
1084
987/** 1085/**
988 * vti6_tunnel_init - register protocol and reserve needed resources 1086 * vti6_tunnel_init - register protocol and reserve needed resources
989 * 1087 *
@@ -997,11 +1095,33 @@ static int __init vti6_tunnel_init(void)
997 if (err < 0) 1095 if (err < 0)
998 goto out_pernet; 1096 goto out_pernet;
999 1097
1000 err = xfrm6_mode_tunnel_input_register(&vti6_handler); 1098 err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP);
1001 if (err < 0) { 1099 if (err < 0) {
1002 pr_err("%s: can't register vti6\n", __func__); 1100 unregister_pernet_device(&vti6_net_ops);
1101 pr_err("%s: can't register vti6 protocol\n", __func__);
1102
1003 goto out; 1103 goto out;
1004 } 1104 }
1105
1106 err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH);
1107 if (err < 0) {
1108 xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
1109 unregister_pernet_device(&vti6_net_ops);
1110 pr_err("%s: can't register vti6 protocol\n", __func__);
1111
1112 goto out;
1113 }
1114
1115 err = xfrm6_protocol_register(&vti_ipcomp6_protocol, IPPROTO_COMP);
1116 if (err < 0) {
1117 xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH);
1118 xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
1119 unregister_pernet_device(&vti6_net_ops);
1120 pr_err("%s: can't register vti6 protocol\n", __func__);
1121
1122 goto out;
1123 }
1124
1005 err = rtnl_link_register(&vti6_link_ops); 1125 err = rtnl_link_register(&vti6_link_ops);
1006 if (err < 0) 1126 if (err < 0)
1007 goto rtnl_link_failed; 1127 goto rtnl_link_failed;
@@ -1009,7 +1129,9 @@ static int __init vti6_tunnel_init(void)
1009 return 0; 1129 return 0;
1010 1130
1011rtnl_link_failed: 1131rtnl_link_failed:
1012 xfrm6_mode_tunnel_input_deregister(&vti6_handler); 1132 xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP);
1133 xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH);
1134 xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
1013out: 1135out:
1014 unregister_pernet_device(&vti6_net_ops); 1136 unregister_pernet_device(&vti6_net_ops);
1015out_pernet: 1137out_pernet:
@@ -1022,8 +1144,12 @@ out_pernet:
1022static void __exit vti6_tunnel_cleanup(void) 1144static void __exit vti6_tunnel_cleanup(void)
1023{ 1145{
1024 rtnl_link_unregister(&vti6_link_ops); 1146 rtnl_link_unregister(&vti6_link_ops);
1025 if (xfrm6_mode_tunnel_input_deregister(&vti6_handler)) 1147 if (xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP))
1026 pr_info("%s: can't deregister vti6\n", __func__); 1148 pr_info("%s: can't deregister protocol\n", __func__);
1149 if (xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH))
1150 pr_info("%s: can't deregister protocol\n", __func__);
1151 if (xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP))
1152 pr_info("%s: can't deregister protocol\n", __func__);
1027 1153
1028 unregister_pernet_device(&vti6_net_ops); 1154 unregister_pernet_device(&vti6_net_ops);
1029} 1155}
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index da9becb42e81..d1c793cffcb5 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -53,7 +53,7 @@
53#include <linux/icmpv6.h> 53#include <linux/icmpv6.h>
54#include <linux/mutex.h> 54#include <linux/mutex.h>
55 55
56static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 56static int ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
57 u8 type, u8 code, int offset, __be32 info) 57 u8 type, u8 code, int offset, __be32 info)
58{ 58{
59 struct net *net = dev_net(skb->dev); 59 struct net *net = dev_net(skb->dev);
@@ -65,19 +65,21 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
65 65
66 if (type != ICMPV6_PKT_TOOBIG && 66 if (type != ICMPV6_PKT_TOOBIG &&
67 type != NDISC_REDIRECT) 67 type != NDISC_REDIRECT)
68 return; 68 return 0;
69 69
70 spi = htonl(ntohs(ipcomph->cpi)); 70 spi = htonl(ntohs(ipcomph->cpi));
71 x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, 71 x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
72 spi, IPPROTO_COMP, AF_INET6); 72 spi, IPPROTO_COMP, AF_INET6);
73 if (!x) 73 if (!x)
74 return; 74 return 0;
75 75
76 if (type == NDISC_REDIRECT) 76 if (type == NDISC_REDIRECT)
77 ip6_redirect(skb, net, skb->dev->ifindex, 0); 77 ip6_redirect(skb, net, skb->dev->ifindex, 0);
78 else 78 else
79 ip6_update_pmtu(skb, net, info, 0, 0); 79 ip6_update_pmtu(skb, net, info, 0, 0);
80 xfrm_state_put(x); 80 xfrm_state_put(x);
81
82 return 0;
81} 83}
82 84
83static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) 85static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
@@ -174,6 +176,11 @@ out:
174 return err; 176 return err;
175} 177}
176 178
179static int ipcomp6_rcv_cb(struct sk_buff *skb, int err)
180{
181 return 0;
182}
183
177static const struct xfrm_type ipcomp6_type = 184static const struct xfrm_type ipcomp6_type =
178{ 185{
179 .description = "IPCOMP6", 186 .description = "IPCOMP6",
@@ -186,11 +193,12 @@ static const struct xfrm_type ipcomp6_type =
186 .hdr_offset = xfrm6_find_1stfragopt, 193 .hdr_offset = xfrm6_find_1stfragopt,
187}; 194};
188 195
189static const struct inet6_protocol ipcomp6_protocol = 196static struct xfrm6_protocol ipcomp6_protocol =
190{ 197{
191 .handler = xfrm6_rcv, 198 .handler = xfrm6_rcv,
199 .cb_handler = ipcomp6_rcv_cb,
192 .err_handler = ipcomp6_err, 200 .err_handler = ipcomp6_err,
193 .flags = INET6_PROTO_NOPOLICY, 201 .priority = 0,
194}; 202};
195 203
196static int __init ipcomp6_init(void) 204static int __init ipcomp6_init(void)
@@ -199,7 +207,7 @@ static int __init ipcomp6_init(void)
199 pr_info("%s: can't add xfrm type\n", __func__); 207 pr_info("%s: can't add xfrm type\n", __func__);
200 return -EAGAIN; 208 return -EAGAIN;
201 } 209 }
202 if (inet6_add_protocol(&ipcomp6_protocol, IPPROTO_COMP) < 0) { 210 if (xfrm6_protocol_register(&ipcomp6_protocol, IPPROTO_COMP) < 0) {
203 pr_info("%s: can't add protocol\n", __func__); 211 pr_info("%s: can't add protocol\n", __func__);
204 xfrm_unregister_type(&ipcomp6_type, AF_INET6); 212 xfrm_unregister_type(&ipcomp6_type, AF_INET6);
205 return -EAGAIN; 213 return -EAGAIN;
@@ -209,7 +217,7 @@ static int __init ipcomp6_init(void)
209 217
210static void __exit ipcomp6_fini(void) 218static void __exit ipcomp6_fini(void)
211{ 219{
212 if (inet6_del_protocol(&ipcomp6_protocol, IPPROTO_COMP) < 0) 220 if (xfrm6_protocol_deregister(&ipcomp6_protocol, IPPROTO_COMP) < 0)
213 pr_info("%s: can't remove protocol\n", __func__); 221 pr_info("%s: can't remove protocol\n", __func__);
214 if (xfrm_unregister_type(&ipcomp6_type, AF_INET6) < 0) 222 if (xfrm_unregister_type(&ipcomp6_type, AF_INET6) < 0)
215 pr_info("%s: can't remove xfrm type\n", __func__); 223 pr_info("%s: can't remove xfrm type\n", __func__);
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index cb04f7a16b5e..901ef6f8addc 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -18,65 +18,6 @@
18#include <net/ipv6.h> 18#include <net/ipv6.h>
19#include <net/xfrm.h> 19#include <net/xfrm.h>
20 20
21/* Informational hook. The decap is still done here. */
22static struct xfrm_tunnel_notifier __rcu *rcv_notify_handlers __read_mostly;
23static DEFINE_MUTEX(xfrm6_mode_tunnel_input_mutex);
24
25int xfrm6_mode_tunnel_input_register(struct xfrm_tunnel_notifier *handler)
26{
27 struct xfrm_tunnel_notifier __rcu **pprev;
28 struct xfrm_tunnel_notifier *t;
29 int ret = -EEXIST;
30 int priority = handler->priority;
31
32 mutex_lock(&xfrm6_mode_tunnel_input_mutex);
33
34 for (pprev = &rcv_notify_handlers;
35 (t = rcu_dereference_protected(*pprev,
36 lockdep_is_held(&xfrm6_mode_tunnel_input_mutex))) != NULL;
37 pprev = &t->next) {
38 if (t->priority > priority)
39 break;
40 if (t->priority == priority)
41 goto err;
42
43 }
44
45 handler->next = *pprev;
46 rcu_assign_pointer(*pprev, handler);
47
48 ret = 0;
49
50err:
51 mutex_unlock(&xfrm6_mode_tunnel_input_mutex);
52 return ret;
53}
54EXPORT_SYMBOL_GPL(xfrm6_mode_tunnel_input_register);
55
56int xfrm6_mode_tunnel_input_deregister(struct xfrm_tunnel_notifier *handler)
57{
58 struct xfrm_tunnel_notifier __rcu **pprev;
59 struct xfrm_tunnel_notifier *t;
60 int ret = -ENOENT;
61
62 mutex_lock(&xfrm6_mode_tunnel_input_mutex);
63 for (pprev = &rcv_notify_handlers;
64 (t = rcu_dereference_protected(*pprev,
65 lockdep_is_held(&xfrm6_mode_tunnel_input_mutex))) != NULL;
66 pprev = &t->next) {
67 if (t == handler) {
68 *pprev = handler->next;
69 ret = 0;
70 break;
71 }
72 }
73 mutex_unlock(&xfrm6_mode_tunnel_input_mutex);
74 synchronize_net();
75
76 return ret;
77}
78EXPORT_SYMBOL_GPL(xfrm6_mode_tunnel_input_deregister);
79
80static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) 21static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
81{ 22{
82 const struct ipv6hdr *outer_iph = ipv6_hdr(skb); 23 const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
@@ -130,7 +71,6 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
130 71
131static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) 72static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
132{ 73{
133 struct xfrm_tunnel_notifier *handler;
134 int err = -EINVAL; 74 int err = -EINVAL;
135 75
136 if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6) 76 if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6)
@@ -138,9 +78,6 @@ static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
138 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 78 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
139 goto out; 79 goto out;
140 80
141 for_each_input_rcu(rcv_notify_handlers, handler)
142 handler->handler(skb);
143
144 err = skb_unclone(skb, GFP_ATOMIC); 81 err = skb_unclone(skb, GFP_ATOMIC);
145 if (err) 82 if (err)
146 goto out; 83 goto out;
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 5f8e128c512d..2a0bbda2c76a 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -389,11 +389,17 @@ int __init xfrm6_init(void)
389 if (ret) 389 if (ret)
390 goto out_policy; 390 goto out_policy;
391 391
392 ret = xfrm6_protocol_init();
393 if (ret)
394 goto out_state;
395
392#ifdef CONFIG_SYSCTL 396#ifdef CONFIG_SYSCTL
393 register_pernet_subsys(&xfrm6_net_ops); 397 register_pernet_subsys(&xfrm6_net_ops);
394#endif 398#endif
395out: 399out:
396 return ret; 400 return ret;
401out_state:
402 xfrm6_state_fini();
397out_policy: 403out_policy:
398 xfrm6_policy_fini(); 404 xfrm6_policy_fini();
399 goto out; 405 goto out;
@@ -404,6 +410,7 @@ void xfrm6_fini(void)
404#ifdef CONFIG_SYSCTL 410#ifdef CONFIG_SYSCTL
405 unregister_pernet_subsys(&xfrm6_net_ops); 411 unregister_pernet_subsys(&xfrm6_net_ops);
406#endif 412#endif
413 xfrm6_protocol_fini();
407 xfrm6_policy_fini(); 414 xfrm6_policy_fini();
408 xfrm6_state_fini(); 415 xfrm6_state_fini();
409 dst_entries_destroy(&xfrm6_dst_ops); 416 dst_entries_destroy(&xfrm6_dst_ops);
diff --git a/net/ipv6/xfrm6_protocol.c b/net/ipv6/xfrm6_protocol.c
new file mode 100644
index 000000000000..6ab989c486f7
--- /dev/null
+++ b/net/ipv6/xfrm6_protocol.c
@@ -0,0 +1,270 @@
1/* xfrm6_protocol.c - Generic xfrm protocol multiplexer for ipv6.
2 *
3 * Copyright (C) 2013 secunet Security Networks AG
4 *
5 * Author:
6 * Steffen Klassert <steffen.klassert@secunet.com>
7 *
8 * Based on:
9 * net/ipv4/xfrm4_protocol.c
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version.
15 */
16
17#include <linux/init.h>
18#include <linux/mutex.h>
19#include <linux/skbuff.h>
20#include <linux/icmpv6.h>
21#include <net/ipv6.h>
22#include <net/protocol.h>
23#include <net/xfrm.h>
24
25static struct xfrm6_protocol __rcu *esp6_handlers __read_mostly;
26static struct xfrm6_protocol __rcu *ah6_handlers __read_mostly;
27static struct xfrm6_protocol __rcu *ipcomp6_handlers __read_mostly;
28static DEFINE_MUTEX(xfrm6_protocol_mutex);
29
30static inline struct xfrm6_protocol __rcu **proto_handlers(u8 protocol)
31{
32 switch (protocol) {
33 case IPPROTO_ESP:
34 return &esp6_handlers;
35 case IPPROTO_AH:
36 return &ah6_handlers;
37 case IPPROTO_COMP:
38 return &ipcomp6_handlers;
39 }
40
41 return NULL;
42}
43
44#define for_each_protocol_rcu(head, handler) \
45 for (handler = rcu_dereference(head); \
46 handler != NULL; \
47 handler = rcu_dereference(handler->next)) \
48
49int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
50{
51 int ret;
52 struct xfrm6_protocol *handler;
53
54 for_each_protocol_rcu(*proto_handlers(protocol), handler)
55 if ((ret = handler->cb_handler(skb, err)) <= 0)
56 return ret;
57
58 return 0;
59}
60EXPORT_SYMBOL(xfrm6_rcv_cb);
61
62static int xfrm6_esp_rcv(struct sk_buff *skb)
63{
64 int ret;
65 struct xfrm6_protocol *handler;
66
67 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
68
69 for_each_protocol_rcu(esp6_handlers, handler)
70 if ((ret = handler->handler(skb)) != -EINVAL)
71 return ret;
72
73 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
74
75 kfree_skb(skb);
76 return 0;
77}
78
79static void xfrm6_esp_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
80 u8 type, u8 code, int offset, __be32 info)
81{
82 struct xfrm6_protocol *handler;
83
84 for_each_protocol_rcu(esp6_handlers, handler)
85 if (!handler->err_handler(skb, opt, type, code, offset, info))
86 break;
87}
88
89static int xfrm6_ah_rcv(struct sk_buff *skb)
90{
91 int ret;
92 struct xfrm6_protocol *handler;
93
94 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
95
96 for_each_protocol_rcu(ah6_handlers, handler)
97 if ((ret = handler->handler(skb)) != -EINVAL)
98 return ret;
99
100 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
101
102 kfree_skb(skb);
103 return 0;
104}
105
106static void xfrm6_ah_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
107 u8 type, u8 code, int offset, __be32 info)
108{
109 struct xfrm6_protocol *handler;
110
111 for_each_protocol_rcu(ah6_handlers, handler)
112 if (!handler->err_handler(skb, opt, type, code, offset, info))
113 break;
114}
115
116static int xfrm6_ipcomp_rcv(struct sk_buff *skb)
117{
118 int ret;
119 struct xfrm6_protocol *handler;
120
121 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
122
123 for_each_protocol_rcu(ipcomp6_handlers, handler)
124 if ((ret = handler->handler(skb)) != -EINVAL)
125 return ret;
126
127 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
128
129 kfree_skb(skb);
130 return 0;
131}
132
133static void xfrm6_ipcomp_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
134 u8 type, u8 code, int offset, __be32 info)
135{
136 struct xfrm6_protocol *handler;
137
138 for_each_protocol_rcu(ipcomp6_handlers, handler)
139 if (!handler->err_handler(skb, opt, type, code, offset, info))
140 break;
141}
142
143static const struct inet6_protocol esp6_protocol = {
144 .handler = xfrm6_esp_rcv,
145 .err_handler = xfrm6_esp_err,
146 .flags = INET6_PROTO_NOPOLICY,
147};
148
149static const struct inet6_protocol ah6_protocol = {
150 .handler = xfrm6_ah_rcv,
151 .err_handler = xfrm6_ah_err,
152 .flags = INET6_PROTO_NOPOLICY,
153};
154
155static const struct inet6_protocol ipcomp6_protocol = {
156 .handler = xfrm6_ipcomp_rcv,
157 .err_handler = xfrm6_ipcomp_err,
158 .flags = INET6_PROTO_NOPOLICY,
159};
160
161static struct xfrm_input_afinfo xfrm6_input_afinfo = {
162 .family = AF_INET6,
163 .owner = THIS_MODULE,
164 .callback = xfrm6_rcv_cb,
165};
166
167static inline const struct inet6_protocol *netproto(unsigned char protocol)
168{
169 switch (protocol) {
170 case IPPROTO_ESP:
171 return &esp6_protocol;
172 case IPPROTO_AH:
173 return &ah6_protocol;
174 case IPPROTO_COMP:
175 return &ipcomp6_protocol;
176 }
177
178 return NULL;
179}
180
181int xfrm6_protocol_register(struct xfrm6_protocol *handler,
182 unsigned char protocol)
183{
184 struct xfrm6_protocol __rcu **pprev;
185 struct xfrm6_protocol *t;
186 bool add_netproto = false;
187
188 int ret = -EEXIST;
189 int priority = handler->priority;
190
191 mutex_lock(&xfrm6_protocol_mutex);
192
193 if (!rcu_dereference_protected(*proto_handlers(protocol),
194 lockdep_is_held(&xfrm6_protocol_mutex)))
195 add_netproto = true;
196
197 for (pprev = proto_handlers(protocol);
198 (t = rcu_dereference_protected(*pprev,
199 lockdep_is_held(&xfrm6_protocol_mutex))) != NULL;
200 pprev = &t->next) {
201 if (t->priority < priority)
202 break;
203 if (t->priority == priority)
204 goto err;
205 }
206
207 handler->next = *pprev;
208 rcu_assign_pointer(*pprev, handler);
209
210 ret = 0;
211
212err:
213 mutex_unlock(&xfrm6_protocol_mutex);
214
215 if (add_netproto) {
216 if (inet6_add_protocol(netproto(protocol), protocol)) {
217 pr_err("%s: can't add protocol\n", __func__);
218 ret = -EAGAIN;
219 }
220 }
221
222 return ret;
223}
224EXPORT_SYMBOL(xfrm6_protocol_register);
225
226int xfrm6_protocol_deregister(struct xfrm6_protocol *handler,
227 unsigned char protocol)
228{
229 struct xfrm6_protocol __rcu **pprev;
230 struct xfrm6_protocol *t;
231 int ret = -ENOENT;
232
233 mutex_lock(&xfrm6_protocol_mutex);
234
235 for (pprev = proto_handlers(protocol);
236 (t = rcu_dereference_protected(*pprev,
237 lockdep_is_held(&xfrm6_protocol_mutex))) != NULL;
238 pprev = &t->next) {
239 if (t == handler) {
240 *pprev = handler->next;
241 ret = 0;
242 break;
243 }
244 }
245
246 if (!rcu_dereference_protected(*proto_handlers(protocol),
247 lockdep_is_held(&xfrm6_protocol_mutex))) {
248 if (inet6_del_protocol(netproto(protocol), protocol) < 0) {
249 pr_err("%s: can't remove protocol\n", __func__);
250 ret = -EAGAIN;
251 }
252 }
253
254 mutex_unlock(&xfrm6_protocol_mutex);
255
256 synchronize_net();
257
258 return ret;
259}
260EXPORT_SYMBOL(xfrm6_protocol_deregister);
261
262int __init xfrm6_protocol_init(void)
263{
264 return xfrm_input_register_afinfo(&xfrm6_input_afinfo);
265}
266
267void xfrm6_protocol_fini(void)
268{
269 xfrm_input_unregister_afinfo(&xfrm6_input_afinfo);
270}