diff options
-rw-r--r-- | include/net/xfrm.h | 50 | ||||
-rw-r--r-- | include/uapi/linux/xfrm.h | 4 | ||||
-rw-r--r-- | net/ipv4/xfrm4_policy.c | 1 | ||||
-rw-r--r-- | net/ipv4/xfrm4_protocol.c | 13 | ||||
-rw-r--r-- | net/ipv6/Makefile | 2 | ||||
-rw-r--r-- | net/ipv6/ah6.c | 24 | ||||
-rw-r--r-- | net/ipv6/esp6.c | 26 | ||||
-rw-r--r-- | net/ipv6/ip6_vti.c | 308 | ||||
-rw-r--r-- | net/ipv6/ipcomp6.c | 22 | ||||
-rw-r--r-- | net/ipv6/xfrm6_mode_tunnel.c | 63 | ||||
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 7 | ||||
-rw-r--r-- | net/ipv6/xfrm6_protocol.c | 270 | ||||
-rw-r--r-- | net/key/af_key.c | 2 | ||||
-rw-r--r-- | net/xfrm/xfrm_input.c | 75 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 4 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 8 |
16 files changed, 668 insertions, 211 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 23bfd4591e8b..32682ae47b3f 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -121,7 +121,7 @@ struct xfrm_state_walk { | |||
121 | u8 dying; | 121 | u8 dying; |
122 | u8 proto; | 122 | u8 proto; |
123 | u32 seq; | 123 | u32 seq; |
124 | struct xfrm_filter *filter; | 124 | struct xfrm_address_filter *filter; |
125 | }; | 125 | }; |
126 | 126 | ||
127 | /* Full description of state of transformer. */ | 127 | /* Full description of state of transformer. */ |
@@ -349,6 +349,16 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo); | |||
349 | struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); | 349 | struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); |
350 | void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | 350 | void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); |
351 | 351 | ||
352 | struct xfrm_input_afinfo { | ||
353 | unsigned int family; | ||
354 | struct module *owner; | ||
355 | int (*callback)(struct sk_buff *skb, u8 protocol, | ||
356 | int err); | ||
357 | }; | ||
358 | |||
359 | int xfrm_input_register_afinfo(struct xfrm_input_afinfo *afinfo); | ||
360 | int xfrm_input_unregister_afinfo(struct xfrm_input_afinfo *afinfo); | ||
361 | |||
352 | void xfrm_state_delete_tunnel(struct xfrm_state *x); | 362 | void xfrm_state_delete_tunnel(struct xfrm_state *x); |
353 | 363 | ||
354 | struct xfrm_type { | 364 | struct xfrm_type { |
@@ -1364,18 +1374,22 @@ struct xfrm4_protocol { | |||
1364 | int priority; | 1374 | int priority; |
1365 | }; | 1375 | }; |
1366 | 1376 | ||
1367 | /* XFRM tunnel handlers. */ | 1377 | struct xfrm6_protocol { |
1368 | struct xfrm_tunnel { | ||
1369 | int (*handler)(struct sk_buff *skb); | 1378 | int (*handler)(struct sk_buff *skb); |
1370 | int (*err_handler)(struct sk_buff *skb, u32 info); | 1379 | int (*cb_handler)(struct sk_buff *skb, int err); |
1380 | int (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, | ||
1381 | u8 type, u8 code, int offset, __be32 info); | ||
1371 | 1382 | ||
1372 | struct xfrm_tunnel __rcu *next; | 1383 | struct xfrm6_protocol __rcu *next; |
1373 | int priority; | 1384 | int priority; |
1374 | }; | 1385 | }; |
1375 | 1386 | ||
1376 | struct xfrm_tunnel_notifier { | 1387 | /* XFRM tunnel handlers. */ |
1388 | struct xfrm_tunnel { | ||
1377 | int (*handler)(struct sk_buff *skb); | 1389 | int (*handler)(struct sk_buff *skb); |
1378 | struct xfrm_tunnel_notifier __rcu *next; | 1390 | int (*err_handler)(struct sk_buff *skb, u32 info); |
1391 | |||
1392 | struct xfrm_tunnel __rcu *next; | ||
1379 | int priority; | 1393 | int priority; |
1380 | }; | 1394 | }; |
1381 | 1395 | ||
@@ -1392,11 +1406,14 @@ void xfrm4_init(void); | |||
1392 | int xfrm_state_init(struct net *net); | 1406 | int xfrm_state_init(struct net *net); |
1393 | void xfrm_state_fini(struct net *net); | 1407 | void xfrm_state_fini(struct net *net); |
1394 | void xfrm4_state_init(void); | 1408 | void xfrm4_state_init(void); |
1409 | void xfrm4_protocol_init(void); | ||
1395 | #ifdef CONFIG_XFRM | 1410 | #ifdef CONFIG_XFRM |
1396 | int xfrm6_init(void); | 1411 | int xfrm6_init(void); |
1397 | void xfrm6_fini(void); | 1412 | void xfrm6_fini(void); |
1398 | int xfrm6_state_init(void); | 1413 | int xfrm6_state_init(void); |
1399 | void xfrm6_state_fini(void); | 1414 | void xfrm6_state_fini(void); |
1415 | int xfrm6_protocol_init(void); | ||
1416 | void xfrm6_protocol_fini(void); | ||
1400 | #else | 1417 | #else |
1401 | static inline int xfrm6_init(void) | 1418 | static inline int xfrm6_init(void) |
1402 | { | 1419 | { |
@@ -1423,7 +1440,7 @@ static inline void xfrm_sysctl_fini(struct net *net) | |||
1423 | #endif | 1440 | #endif |
1424 | 1441 | ||
1425 | void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, | 1442 | void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, |
1426 | struct xfrm_filter *filter); | 1443 | struct xfrm_address_filter *filter); |
1427 | int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, | 1444 | int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, |
1428 | int (*func)(struct xfrm_state *, int, void*), void *); | 1445 | int (*func)(struct xfrm_state *, int, void*), void *); |
1429 | void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net); | 1446 | void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net); |
@@ -1531,8 +1548,6 @@ int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, unsigned char prot | |||
1531 | int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family); | 1548 | int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family); |
1532 | int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); | 1549 | int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); |
1533 | void xfrm4_local_error(struct sk_buff *skb, u32 mtu); | 1550 | void xfrm4_local_error(struct sk_buff *skb, u32 mtu); |
1534 | int xfrm6_mode_tunnel_input_register(struct xfrm_tunnel_notifier *handler); | ||
1535 | int xfrm6_mode_tunnel_input_deregister(struct xfrm_tunnel_notifier *handler); | ||
1536 | int xfrm6_extract_header(struct sk_buff *skb); | 1551 | int xfrm6_extract_header(struct sk_buff *skb); |
1537 | int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb); | 1552 | int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb); |
1538 | int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi); | 1553 | int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi); |
@@ -1541,6 +1556,9 @@ int xfrm6_rcv(struct sk_buff *skb); | |||
1541 | int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, | 1556 | int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, |
1542 | xfrm_address_t *saddr, u8 proto); | 1557 | xfrm_address_t *saddr, u8 proto); |
1543 | void xfrm6_local_error(struct sk_buff *skb, u32 mtu); | 1558 | void xfrm6_local_error(struct sk_buff *skb, u32 mtu); |
1559 | int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err); | ||
1560 | int xfrm6_protocol_register(struct xfrm6_protocol *handler, unsigned char protocol); | ||
1561 | int xfrm6_protocol_deregister(struct xfrm6_protocol *handler, unsigned char protocol); | ||
1544 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family); | 1562 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family); |
1545 | int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family); | 1563 | int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family); |
1546 | __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr); | 1564 | __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr); |
@@ -1784,18 +1802,6 @@ static inline int xfrm_mark_put(struct sk_buff *skb, const struct xfrm_mark *m) | |||
1784 | return ret; | 1802 | return ret; |
1785 | } | 1803 | } |
1786 | 1804 | ||
1787 | static inline int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, | ||
1788 | u8 protocol, int err) | ||
1789 | { | ||
1790 | switch(family) { | ||
1791 | #ifdef CONFIG_INET | ||
1792 | case AF_INET: | ||
1793 | return xfrm4_rcv_cb(skb, protocol, err); | ||
1794 | #endif | ||
1795 | } | ||
1796 | return 0; | ||
1797 | } | ||
1798 | |||
1799 | static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x, | 1805 | static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x, |
1800 | unsigned int family) | 1806 | unsigned int family) |
1801 | { | 1807 | { |
diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h index 6550c679584f..25e5dd916ba4 100644 --- a/include/uapi/linux/xfrm.h +++ b/include/uapi/linux/xfrm.h | |||
@@ -299,7 +299,7 @@ enum xfrm_attr_type_t { | |||
299 | XFRMA_REPLAY_ESN_VAL, /* struct xfrm_replay_esn */ | 299 | XFRMA_REPLAY_ESN_VAL, /* struct xfrm_replay_esn */ |
300 | XFRMA_SA_EXTRA_FLAGS, /* __u32 */ | 300 | XFRMA_SA_EXTRA_FLAGS, /* __u32 */ |
301 | XFRMA_PROTO, /* __u8 */ | 301 | XFRMA_PROTO, /* __u8 */ |
302 | XFRMA_FILTER, /* struct xfrm_filter */ | 302 | XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */ |
303 | __XFRMA_MAX | 303 | __XFRMA_MAX |
304 | 304 | ||
305 | #define XFRMA_MAX (__XFRMA_MAX - 1) | 305 | #define XFRMA_MAX (__XFRMA_MAX - 1) |
@@ -476,7 +476,7 @@ struct xfrm_user_mapping { | |||
476 | __be16 new_sport; | 476 | __be16 new_sport; |
477 | }; | 477 | }; |
478 | 478 | ||
479 | struct xfrm_filter { | 479 | struct xfrm_address_filter { |
480 | xfrm_address_t saddr; | 480 | xfrm_address_t saddr; |
481 | xfrm_address_t daddr; | 481 | xfrm_address_t daddr; |
482 | __u16 family; | 482 | __u16 family; |
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index e1a63930a967..6156f68a1e90 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -325,6 +325,7 @@ void __init xfrm4_init(void) | |||
325 | 325 | ||
326 | xfrm4_state_init(); | 326 | xfrm4_state_init(); |
327 | xfrm4_policy_init(); | 327 | xfrm4_policy_init(); |
328 | xfrm4_protocol_init(); | ||
328 | #ifdef CONFIG_SYSCTL | 329 | #ifdef CONFIG_SYSCTL |
329 | register_pernet_subsys(&xfrm4_net_ops); | 330 | register_pernet_subsys(&xfrm4_net_ops); |
330 | #endif | 331 | #endif |
diff --git a/net/ipv4/xfrm4_protocol.c b/net/ipv4/xfrm4_protocol.c index cdc09efca442..7f7b243e8139 100644 --- a/net/ipv4/xfrm4_protocol.c +++ b/net/ipv4/xfrm4_protocol.c | |||
@@ -179,6 +179,12 @@ static const struct net_protocol ipcomp4_protocol = { | |||
179 | .netns_ok = 1, | 179 | .netns_ok = 1, |
180 | }; | 180 | }; |
181 | 181 | ||
182 | static struct xfrm_input_afinfo xfrm4_input_afinfo = { | ||
183 | .family = AF_INET, | ||
184 | .owner = THIS_MODULE, | ||
185 | .callback = xfrm4_rcv_cb, | ||
186 | }; | ||
187 | |||
182 | static inline const struct net_protocol *netproto(unsigned char protocol) | 188 | static inline const struct net_protocol *netproto(unsigned char protocol) |
183 | { | 189 | { |
184 | switch (protocol) { | 190 | switch (protocol) { |
@@ -199,7 +205,6 @@ int xfrm4_protocol_register(struct xfrm4_protocol *handler, | |||
199 | struct xfrm4_protocol __rcu **pprev; | 205 | struct xfrm4_protocol __rcu **pprev; |
200 | struct xfrm4_protocol *t; | 206 | struct xfrm4_protocol *t; |
201 | bool add_netproto = false; | 207 | bool add_netproto = false; |
202 | |||
203 | int ret = -EEXIST; | 208 | int ret = -EEXIST; |
204 | int priority = handler->priority; | 209 | int priority = handler->priority; |
205 | 210 | ||
@@ -273,3 +278,9 @@ int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, | |||
273 | return ret; | 278 | return ret; |
274 | } | 279 | } |
275 | EXPORT_SYMBOL(xfrm4_protocol_deregister); | 280 | EXPORT_SYMBOL(xfrm4_protocol_deregister); |
281 | |||
282 | void __init xfrm4_protocol_init(void) | ||
283 | { | ||
284 | xfrm_input_register_afinfo(&xfrm4_input_afinfo); | ||
285 | } | ||
286 | EXPORT_SYMBOL(xfrm4_protocol_init); | ||
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 | |||
16 | ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o | 16 | ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o |
17 | 17 | ||
18 | ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ | 18 | ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ |
19 | xfrm6_output.o | 19 | xfrm6_output.o xfrm6_protocol.o |
20 | ipv6-$(CONFIG_NETFILTER) += netfilter.o | 20 | ipv6-$(CONFIG_NETFILTER) += netfilter.o |
21 | ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o | 21 | ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o |
22 | ipv6-$(CONFIG_PROC_FS) += proc.o | 22 | ipv6-$(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 | ||
646 | static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 646 | static 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 | ||
669 | static int ah6_init_state(struct xfrm_state *x) | 671 | static 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 | ||
753 | static int ah6_rcv_cb(struct sk_buff *skb, int err) | ||
754 | { | ||
755 | return 0; | ||
756 | } | ||
757 | |||
751 | static const struct xfrm_type ah6_type = | 758 | static 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 | ||
764 | static const struct inet6_protocol ah6_protocol = { | 771 | static 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 | ||
770 | static int __init ah6_init(void) | 778 | static 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 | ||
786 | static void __exit ah6_fini(void) | 794 | static 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 | ||
424 | static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 424 | static 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 | ||
448 | static void esp6_destroy(struct xfrm_state *x) | 450 | static void esp6_destroy(struct xfrm_state *x) |
@@ -614,6 +616,11 @@ error: | |||
614 | return err; | 616 | return err; |
615 | } | 617 | } |
616 | 618 | ||
619 | static int esp6_rcv_cb(struct sk_buff *skb, int err) | ||
620 | { | ||
621 | return 0; | ||
622 | } | ||
623 | |||
617 | static const struct xfrm_type esp6_type = | 624 | static 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 | ||
631 | static const struct inet6_protocol esp6_protocol = { | 638 | static 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 | ||
637 | static int __init esp6_init(void) | 645 | static 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 | ||
652 | static void __exit esp6_fini(void) | 660 | static 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 | |||
328 | discard: | 317 | discard: |
329 | kfree_skb(skb); | 318 | kfree_skb(skb); |
330 | return 0; | 319 | return 0; |
331 | } | 320 | } |
332 | 321 | ||
322 | static 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 | ||
379 | static 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 | **/ |
357 | static int vti6_xmit(struct sk_buff *skb, struct net_device *dev) | 408 | static int |
409 | vti6_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); |
415 | tx_err_dst_release: | 461 | tx_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 | ||
510 | static 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 | |||
447 | static void vti6_link_config(struct ip6_tnl *t) | 562 | static 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 | ||
911 | static struct xfrm_tunnel_notifier vti6_handler __read_mostly = { | ||
912 | .handler = vti6_rcv, | ||
913 | .priority = 1, | ||
914 | }; | ||
915 | |||
916 | static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n) | 993 | static 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 | ||
1064 | static 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 | |||
1071 | static 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 | |||
1078 | static 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 | ||
1011 | rtnl_link_failed: | 1131 | rtnl_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); | ||
1013 | out: | 1135 | out: |
1014 | unregister_pernet_device(&vti6_net_ops); | 1136 | unregister_pernet_device(&vti6_net_ops); |
1015 | out_pernet: | 1137 | out_pernet: |
@@ -1022,8 +1144,12 @@ out_pernet: | |||
1022 | static void __exit vti6_tunnel_cleanup(void) | 1144 | static 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 | ||
56 | static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 56 | static 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 | ||
83 | static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) | 85 | static 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 | ||
179 | static int ipcomp6_rcv_cb(struct sk_buff *skb, int err) | ||
180 | { | ||
181 | return 0; | ||
182 | } | ||
183 | |||
177 | static const struct xfrm_type ipcomp6_type = | 184 | static 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 | ||
189 | static const struct inet6_protocol ipcomp6_protocol = | 196 | static 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 | ||
196 | static int __init ipcomp6_init(void) | 204 | static 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 | ||
210 | static void __exit ipcomp6_fini(void) | 218 | static 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. */ | ||
22 | static struct xfrm_tunnel_notifier __rcu *rcv_notify_handlers __read_mostly; | ||
23 | static DEFINE_MUTEX(xfrm6_mode_tunnel_input_mutex); | ||
24 | |||
25 | int 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 | |||
50 | err: | ||
51 | mutex_unlock(&xfrm6_mode_tunnel_input_mutex); | ||
52 | return ret; | ||
53 | } | ||
54 | EXPORT_SYMBOL_GPL(xfrm6_mode_tunnel_input_register); | ||
55 | |||
56 | int 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 | } | ||
78 | EXPORT_SYMBOL_GPL(xfrm6_mode_tunnel_input_deregister); | ||
79 | |||
80 | static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) | 21 | static 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 | ||
131 | static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | 72 | static 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 |
395 | out: | 399 | out: |
396 | return ret; | 400 | return ret; |
401 | out_state: | ||
402 | xfrm6_state_fini(); | ||
397 | out_policy: | 403 | out_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 | |||
25 | static struct xfrm6_protocol __rcu *esp6_handlers __read_mostly; | ||
26 | static struct xfrm6_protocol __rcu *ah6_handlers __read_mostly; | ||
27 | static struct xfrm6_protocol __rcu *ipcomp6_handlers __read_mostly; | ||
28 | static DEFINE_MUTEX(xfrm6_protocol_mutex); | ||
29 | |||
30 | static 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 | |||
49 | int 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 | } | ||
60 | EXPORT_SYMBOL(xfrm6_rcv_cb); | ||
61 | |||
62 | static 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 | |||
79 | static 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 | |||
89 | static 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 | |||
106 | static 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 | |||
116 | static 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 | |||
133 | static 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 | |||
143 | static const struct inet6_protocol esp6_protocol = { | ||
144 | .handler = xfrm6_esp_rcv, | ||
145 | .err_handler = xfrm6_esp_err, | ||
146 | .flags = INET6_PROTO_NOPOLICY, | ||
147 | }; | ||
148 | |||
149 | static const struct inet6_protocol ah6_protocol = { | ||
150 | .handler = xfrm6_ah_rcv, | ||
151 | .err_handler = xfrm6_ah_err, | ||
152 | .flags = INET6_PROTO_NOPOLICY, | ||
153 | }; | ||
154 | |||
155 | static const struct inet6_protocol ipcomp6_protocol = { | ||
156 | .handler = xfrm6_ipcomp_rcv, | ||
157 | .err_handler = xfrm6_ipcomp_err, | ||
158 | .flags = INET6_PROTO_NOPOLICY, | ||
159 | }; | ||
160 | |||
161 | static struct xfrm_input_afinfo xfrm6_input_afinfo = { | ||
162 | .family = AF_INET6, | ||
163 | .owner = THIS_MODULE, | ||
164 | .callback = xfrm6_rcv_cb, | ||
165 | }; | ||
166 | |||
167 | static 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 | |||
181 | int 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 | |||
212 | err: | ||
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 | } | ||
224 | EXPORT_SYMBOL(xfrm6_protocol_register); | ||
225 | |||
226 | int 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 | } | ||
260 | EXPORT_SYMBOL(xfrm6_protocol_deregister); | ||
261 | |||
262 | int __init xfrm6_protocol_init(void) | ||
263 | { | ||
264 | return xfrm_input_register_afinfo(&xfrm6_input_afinfo); | ||
265 | } | ||
266 | |||
267 | void xfrm6_protocol_fini(void) | ||
268 | { | ||
269 | xfrm_input_unregister_afinfo(&xfrm6_input_afinfo); | ||
270 | } | ||
diff --git a/net/key/af_key.c b/net/key/af_key.c index a50d979b5926..12651b42aad8 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -1799,7 +1799,7 @@ static void pfkey_dump_sa_done(struct pfkey_sock *pfk) | |||
1799 | static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) | 1799 | static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) |
1800 | { | 1800 | { |
1801 | u8 proto; | 1801 | u8 proto; |
1802 | struct xfrm_filter *filter = NULL; | 1802 | struct xfrm_address_filter *filter = NULL; |
1803 | struct pfkey_sock *pfk = pfkey_sk(sk); | 1803 | struct pfkey_sock *pfk = pfkey_sk(sk); |
1804 | 1804 | ||
1805 | if (pfk->dump.dump != NULL) | 1805 | if (pfk->dump.dump != NULL) |
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 4218164f4f5e..85d1d4764612 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
@@ -16,6 +16,81 @@ | |||
16 | 16 | ||
17 | static struct kmem_cache *secpath_cachep __read_mostly; | 17 | static struct kmem_cache *secpath_cachep __read_mostly; |
18 | 18 | ||
19 | static DEFINE_SPINLOCK(xfrm_input_afinfo_lock); | ||
20 | static struct xfrm_input_afinfo __rcu *xfrm_input_afinfo[NPROTO]; | ||
21 | |||
22 | int xfrm_input_register_afinfo(struct xfrm_input_afinfo *afinfo) | ||
23 | { | ||
24 | int err = 0; | ||
25 | |||
26 | if (unlikely(afinfo == NULL)) | ||
27 | return -EINVAL; | ||
28 | if (unlikely(afinfo->family >= NPROTO)) | ||
29 | return -EAFNOSUPPORT; | ||
30 | spin_lock_bh(&xfrm_input_afinfo_lock); | ||
31 | if (unlikely(xfrm_input_afinfo[afinfo->family] != NULL)) | ||
32 | err = -ENOBUFS; | ||
33 | else | ||
34 | rcu_assign_pointer(xfrm_input_afinfo[afinfo->family], afinfo); | ||
35 | spin_unlock_bh(&xfrm_input_afinfo_lock); | ||
36 | return err; | ||
37 | } | ||
38 | EXPORT_SYMBOL(xfrm_input_register_afinfo); | ||
39 | |||
40 | int xfrm_input_unregister_afinfo(struct xfrm_input_afinfo *afinfo) | ||
41 | { | ||
42 | int err = 0; | ||
43 | |||
44 | if (unlikely(afinfo == NULL)) | ||
45 | return -EINVAL; | ||
46 | if (unlikely(afinfo->family >= NPROTO)) | ||
47 | return -EAFNOSUPPORT; | ||
48 | spin_lock_bh(&xfrm_input_afinfo_lock); | ||
49 | if (likely(xfrm_input_afinfo[afinfo->family] != NULL)) { | ||
50 | if (unlikely(xfrm_input_afinfo[afinfo->family] != afinfo)) | ||
51 | err = -EINVAL; | ||
52 | else | ||
53 | RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->family], NULL); | ||
54 | } | ||
55 | spin_unlock_bh(&xfrm_input_afinfo_lock); | ||
56 | synchronize_rcu(); | ||
57 | return err; | ||
58 | } | ||
59 | EXPORT_SYMBOL(xfrm_input_unregister_afinfo); | ||
60 | |||
61 | static struct xfrm_input_afinfo *xfrm_input_get_afinfo(unsigned int family) | ||
62 | { | ||
63 | struct xfrm_input_afinfo *afinfo; | ||
64 | |||
65 | if (unlikely(family >= NPROTO)) | ||
66 | return NULL; | ||
67 | rcu_read_lock(); | ||
68 | afinfo = rcu_dereference(xfrm_input_afinfo[family]); | ||
69 | if (unlikely(!afinfo)) | ||
70 | rcu_read_unlock(); | ||
71 | return afinfo; | ||
72 | } | ||
73 | |||
74 | static void xfrm_input_put_afinfo(struct xfrm_input_afinfo *afinfo) | ||
75 | { | ||
76 | rcu_read_unlock(); | ||
77 | } | ||
78 | |||
79 | static int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, u8 protocol, | ||
80 | int err) | ||
81 | { | ||
82 | int ret; | ||
83 | struct xfrm_input_afinfo *afinfo = xfrm_input_get_afinfo(family); | ||
84 | |||
85 | if (!afinfo) | ||
86 | return -EAFNOSUPPORT; | ||
87 | |||
88 | ret = afinfo->callback(skb, protocol, err); | ||
89 | xfrm_input_put_afinfo(afinfo); | ||
90 | |||
91 | return ret; | ||
92 | } | ||
93 | |||
19 | void __secpath_destroy(struct sec_path *sp) | 94 | void __secpath_destroy(struct sec_path *sp) |
20 | { | 95 | { |
21 | int i; | 96 | int i; |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 06970fee9155..8e9c781a6bba 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -1609,7 +1609,7 @@ unlock: | |||
1609 | EXPORT_SYMBOL(xfrm_alloc_spi); | 1609 | EXPORT_SYMBOL(xfrm_alloc_spi); |
1610 | 1610 | ||
1611 | static bool __xfrm_state_filter_match(struct xfrm_state *x, | 1611 | static bool __xfrm_state_filter_match(struct xfrm_state *x, |
1612 | struct xfrm_filter *filter) | 1612 | struct xfrm_address_filter *filter) |
1613 | { | 1613 | { |
1614 | if (filter) { | 1614 | if (filter) { |
1615 | if ((filter->family == AF_INET || | 1615 | if ((filter->family == AF_INET || |
@@ -1668,7 +1668,7 @@ out: | |||
1668 | EXPORT_SYMBOL(xfrm_state_walk); | 1668 | EXPORT_SYMBOL(xfrm_state_walk); |
1669 | 1669 | ||
1670 | void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, | 1670 | void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, |
1671 | struct xfrm_filter *filter) | 1671 | struct xfrm_address_filter *filter) |
1672 | { | 1672 | { |
1673 | INIT_LIST_HEAD(&walk->all); | 1673 | INIT_LIST_HEAD(&walk->all); |
1674 | walk->proto = proto; | 1674 | walk->proto = proto; |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 195dbe230b98..cdd9e9c7ff0e 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -899,7 +899,7 @@ static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) | |||
899 | 899 | ||
900 | if (!cb->args[0]) { | 900 | if (!cb->args[0]) { |
901 | struct nlattr *attrs[XFRMA_MAX+1]; | 901 | struct nlattr *attrs[XFRMA_MAX+1]; |
902 | struct xfrm_filter *filter = NULL; | 902 | struct xfrm_address_filter *filter = NULL; |
903 | u8 proto = 0; | 903 | u8 proto = 0; |
904 | int err; | 904 | int err; |
905 | 905 | ||
@@ -910,12 +910,12 @@ static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) | |||
910 | if (err < 0) | 910 | if (err < 0) |
911 | return err; | 911 | return err; |
912 | 912 | ||
913 | if (attrs[XFRMA_FILTER]) { | 913 | if (attrs[XFRMA_ADDRESS_FILTER]) { |
914 | filter = kmalloc(sizeof(*filter), GFP_KERNEL); | 914 | filter = kmalloc(sizeof(*filter), GFP_KERNEL); |
915 | if (filter == NULL) | 915 | if (filter == NULL) |
916 | return -ENOMEM; | 916 | return -ENOMEM; |
917 | 917 | ||
918 | memcpy(filter, nla_data(attrs[XFRMA_FILTER]), | 918 | memcpy(filter, nla_data(attrs[XFRMA_ADDRESS_FILTER]), |
919 | sizeof(*filter)); | 919 | sizeof(*filter)); |
920 | } | 920 | } |
921 | 921 | ||
@@ -2329,7 +2329,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | |||
2329 | [XFRMA_REPLAY_ESN_VAL] = { .len = sizeof(struct xfrm_replay_state_esn) }, | 2329 | [XFRMA_REPLAY_ESN_VAL] = { .len = sizeof(struct xfrm_replay_state_esn) }, |
2330 | [XFRMA_SA_EXTRA_FLAGS] = { .type = NLA_U32 }, | 2330 | [XFRMA_SA_EXTRA_FLAGS] = { .type = NLA_U32 }, |
2331 | [XFRMA_PROTO] = { .type = NLA_U8 }, | 2331 | [XFRMA_PROTO] = { .type = NLA_U8 }, |
2332 | [XFRMA_FILTER] = { .len = sizeof(struct xfrm_filter) }, | 2332 | [XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) }, |
2333 | }; | 2333 | }; |
2334 | 2334 | ||
2335 | static const struct xfrm_link { | 2335 | static const struct xfrm_link { |