diff options
-rw-r--r-- | drivers/net/ipvlan/ipvlan_main.c | 69 | ||||
-rw-r--r-- | include/linux/inetdevice.h | 7 | ||||
-rw-r--r-- | include/net/addrconf.h | 10 | ||||
-rw-r--r-- | net/ipv4/devinet.c | 33 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 17 | ||||
-rw-r--r-- | net/ipv6/addrconf_core.c | 19 |
6 files changed, 153 insertions, 2 deletions
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 618ed88fad0f..e4141d62b5c3 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c | |||
@@ -824,6 +824,33 @@ static int ipvlan_addr6_event(struct notifier_block *unused, | |||
824 | return NOTIFY_OK; | 824 | return NOTIFY_OK; |
825 | } | 825 | } |
826 | 826 | ||
827 | static int ipvlan_addr6_validator_event(struct notifier_block *unused, | ||
828 | unsigned long event, void *ptr) | ||
829 | { | ||
830 | struct in6_validator_info *i6vi = (struct in6_validator_info *)ptr; | ||
831 | struct net_device *dev = (struct net_device *)i6vi->i6vi_dev->dev; | ||
832 | struct ipvl_dev *ipvlan = netdev_priv(dev); | ||
833 | |||
834 | /* FIXME IPv6 autoconf calls us from bh without RTNL */ | ||
835 | if (in_softirq()) | ||
836 | return NOTIFY_DONE; | ||
837 | |||
838 | if (!netif_is_ipvlan(dev)) | ||
839 | return NOTIFY_DONE; | ||
840 | |||
841 | if (!ipvlan || !ipvlan->port) | ||
842 | return NOTIFY_DONE; | ||
843 | |||
844 | switch (event) { | ||
845 | case NETDEV_UP: | ||
846 | if (ipvlan_addr_busy(ipvlan->port, &i6vi->i6vi_addr, true)) | ||
847 | return notifier_from_errno(-EADDRINUSE); | ||
848 | break; | ||
849 | } | ||
850 | |||
851 | return NOTIFY_OK; | ||
852 | } | ||
853 | |||
827 | static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) | 854 | static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) |
828 | { | 855 | { |
829 | if (ipvlan_addr_busy(ipvlan->port, ip4_addr, false)) { | 856 | if (ipvlan_addr_busy(ipvlan->port, ip4_addr, false)) { |
@@ -871,10 +898,37 @@ static int ipvlan_addr4_event(struct notifier_block *unused, | |||
871 | return NOTIFY_OK; | 898 | return NOTIFY_OK; |
872 | } | 899 | } |
873 | 900 | ||
901 | static int ipvlan_addr4_validator_event(struct notifier_block *unused, | ||
902 | unsigned long event, void *ptr) | ||
903 | { | ||
904 | struct in_validator_info *ivi = (struct in_validator_info *)ptr; | ||
905 | struct net_device *dev = (struct net_device *)ivi->ivi_dev->dev; | ||
906 | struct ipvl_dev *ipvlan = netdev_priv(dev); | ||
907 | |||
908 | if (!netif_is_ipvlan(dev)) | ||
909 | return NOTIFY_DONE; | ||
910 | |||
911 | if (!ipvlan || !ipvlan->port) | ||
912 | return NOTIFY_DONE; | ||
913 | |||
914 | switch (event) { | ||
915 | case NETDEV_UP: | ||
916 | if (ipvlan_addr_busy(ipvlan->port, &ivi->ivi_addr, false)) | ||
917 | return notifier_from_errno(-EADDRINUSE); | ||
918 | break; | ||
919 | } | ||
920 | |||
921 | return NOTIFY_OK; | ||
922 | } | ||
923 | |||
874 | static struct notifier_block ipvlan_addr4_notifier_block __read_mostly = { | 924 | static struct notifier_block ipvlan_addr4_notifier_block __read_mostly = { |
875 | .notifier_call = ipvlan_addr4_event, | 925 | .notifier_call = ipvlan_addr4_event, |
876 | }; | 926 | }; |
877 | 927 | ||
928 | static struct notifier_block ipvlan_addr4_vtor_notifier_block __read_mostly = { | ||
929 | .notifier_call = ipvlan_addr4_validator_event, | ||
930 | }; | ||
931 | |||
878 | static struct notifier_block ipvlan_notifier_block __read_mostly = { | 932 | static struct notifier_block ipvlan_notifier_block __read_mostly = { |
879 | .notifier_call = ipvlan_device_event, | 933 | .notifier_call = ipvlan_device_event, |
880 | }; | 934 | }; |
@@ -883,6 +937,10 @@ static struct notifier_block ipvlan_addr6_notifier_block __read_mostly = { | |||
883 | .notifier_call = ipvlan_addr6_event, | 937 | .notifier_call = ipvlan_addr6_event, |
884 | }; | 938 | }; |
885 | 939 | ||
940 | static struct notifier_block ipvlan_addr6_vtor_notifier_block __read_mostly = { | ||
941 | .notifier_call = ipvlan_addr6_validator_event, | ||
942 | }; | ||
943 | |||
886 | static void ipvlan_ns_exit(struct net *net) | 944 | static void ipvlan_ns_exit(struct net *net) |
887 | { | 945 | { |
888 | struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid); | 946 | struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid); |
@@ -907,7 +965,10 @@ static int __init ipvlan_init_module(void) | |||
907 | ipvlan_init_secret(); | 965 | ipvlan_init_secret(); |
908 | register_netdevice_notifier(&ipvlan_notifier_block); | 966 | register_netdevice_notifier(&ipvlan_notifier_block); |
909 | register_inet6addr_notifier(&ipvlan_addr6_notifier_block); | 967 | register_inet6addr_notifier(&ipvlan_addr6_notifier_block); |
968 | register_inet6addr_validator_notifier( | ||
969 | &ipvlan_addr6_vtor_notifier_block); | ||
910 | register_inetaddr_notifier(&ipvlan_addr4_notifier_block); | 970 | register_inetaddr_notifier(&ipvlan_addr4_notifier_block); |
971 | register_inetaddr_validator_notifier(&ipvlan_addr4_vtor_notifier_block); | ||
911 | 972 | ||
912 | err = register_pernet_subsys(&ipvlan_net_ops); | 973 | err = register_pernet_subsys(&ipvlan_net_ops); |
913 | if (err < 0) | 974 | if (err < 0) |
@@ -922,7 +983,11 @@ static int __init ipvlan_init_module(void) | |||
922 | return 0; | 983 | return 0; |
923 | error: | 984 | error: |
924 | unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); | 985 | unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); |
986 | unregister_inetaddr_validator_notifier( | ||
987 | &ipvlan_addr4_vtor_notifier_block); | ||
925 | unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); | 988 | unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); |
989 | unregister_inet6addr_validator_notifier( | ||
990 | &ipvlan_addr6_vtor_notifier_block); | ||
926 | unregister_netdevice_notifier(&ipvlan_notifier_block); | 991 | unregister_netdevice_notifier(&ipvlan_notifier_block); |
927 | return err; | 992 | return err; |
928 | } | 993 | } |
@@ -933,7 +998,11 @@ static void __exit ipvlan_cleanup_module(void) | |||
933 | unregister_pernet_subsys(&ipvlan_net_ops); | 998 | unregister_pernet_subsys(&ipvlan_net_ops); |
934 | unregister_netdevice_notifier(&ipvlan_notifier_block); | 999 | unregister_netdevice_notifier(&ipvlan_notifier_block); |
935 | unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); | 1000 | unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); |
1001 | unregister_inetaddr_validator_notifier( | ||
1002 | &ipvlan_addr4_vtor_notifier_block); | ||
936 | unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); | 1003 | unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); |
1004 | unregister_inet6addr_validator_notifier( | ||
1005 | &ipvlan_addr6_vtor_notifier_block); | ||
937 | } | 1006 | } |
938 | 1007 | ||
939 | module_init(ipvlan_init_module); | 1008 | module_init(ipvlan_init_module); |
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index a2e9d6ea1349..e7c04c4e4bcd 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h | |||
@@ -150,8 +150,15 @@ struct in_ifaddr { | |||
150 | unsigned long ifa_tstamp; /* updated timestamp */ | 150 | unsigned long ifa_tstamp; /* updated timestamp */ |
151 | }; | 151 | }; |
152 | 152 | ||
153 | struct in_validator_info { | ||
154 | __be32 ivi_addr; | ||
155 | struct in_device *ivi_dev; | ||
156 | }; | ||
157 | |||
153 | int register_inetaddr_notifier(struct notifier_block *nb); | 158 | int register_inetaddr_notifier(struct notifier_block *nb); |
154 | int unregister_inetaddr_notifier(struct notifier_block *nb); | 159 | int unregister_inetaddr_notifier(struct notifier_block *nb); |
160 | int register_inetaddr_validator_notifier(struct notifier_block *nb); | ||
161 | int unregister_inetaddr_validator_notifier(struct notifier_block *nb); | ||
155 | 162 | ||
156 | void inet_netconf_notify_devconf(struct net *net, int event, int type, | 163 | void inet_netconf_notify_devconf(struct net *net, int event, int type, |
157 | int ifindex, struct ipv4_devconf *devconf); | 164 | int ifindex, struct ipv4_devconf *devconf); |
diff --git a/include/net/addrconf.h b/include/net/addrconf.h index b43a4eec3cec..d0889cb50172 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h | |||
@@ -48,11 +48,15 @@ struct prefix_info { | |||
48 | struct in6_addr prefix; | 48 | struct in6_addr prefix; |
49 | }; | 49 | }; |
50 | 50 | ||
51 | |||
52 | #include <linux/netdevice.h> | 51 | #include <linux/netdevice.h> |
53 | #include <net/if_inet6.h> | 52 | #include <net/if_inet6.h> |
54 | #include <net/ipv6.h> | 53 | #include <net/ipv6.h> |
55 | 54 | ||
55 | struct in6_validator_info { | ||
56 | struct in6_addr i6vi_addr; | ||
57 | struct inet6_dev *i6vi_dev; | ||
58 | }; | ||
59 | |||
56 | #define IN6_ADDR_HSIZE_SHIFT 4 | 60 | #define IN6_ADDR_HSIZE_SHIFT 4 |
57 | #define IN6_ADDR_HSIZE (1 << IN6_ADDR_HSIZE_SHIFT) | 61 | #define IN6_ADDR_HSIZE (1 << IN6_ADDR_HSIZE_SHIFT) |
58 | 62 | ||
@@ -278,6 +282,10 @@ int register_inet6addr_notifier(struct notifier_block *nb); | |||
278 | int unregister_inet6addr_notifier(struct notifier_block *nb); | 282 | int unregister_inet6addr_notifier(struct notifier_block *nb); |
279 | int inet6addr_notifier_call_chain(unsigned long val, void *v); | 283 | int inet6addr_notifier_call_chain(unsigned long val, void *v); |
280 | 284 | ||
285 | int register_inet6addr_validator_notifier(struct notifier_block *nb); | ||
286 | int unregister_inet6addr_validator_notifier(struct notifier_block *nb); | ||
287 | int inet6addr_validator_notifier_call_chain(unsigned long val, void *v); | ||
288 | |||
281 | void inet6_netconf_notify_devconf(struct net *net, int event, int type, | 289 | void inet6_netconf_notify_devconf(struct net *net, int event, int type, |
282 | int ifindex, struct ipv6_devconf *devconf); | 290 | int ifindex, struct ipv6_devconf *devconf); |
283 | 291 | ||
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index df14815a3b8c..a7dd088d5fc9 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -176,6 +176,7 @@ EXPORT_SYMBOL(__ip_dev_find); | |||
176 | static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32); | 176 | static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32); |
177 | 177 | ||
178 | static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); | 178 | static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); |
179 | static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain); | ||
179 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | 180 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
180 | int destroy); | 181 | int destroy); |
181 | #ifdef CONFIG_SYSCTL | 182 | #ifdef CONFIG_SYSCTL |
@@ -441,6 +442,8 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, | |||
441 | { | 442 | { |
442 | struct in_device *in_dev = ifa->ifa_dev; | 443 | struct in_device *in_dev = ifa->ifa_dev; |
443 | struct in_ifaddr *ifa1, **ifap, **last_primary; | 444 | struct in_ifaddr *ifa1, **ifap, **last_primary; |
445 | struct in_validator_info ivi; | ||
446 | int ret; | ||
444 | 447 | ||
445 | ASSERT_RTNL(); | 448 | ASSERT_RTNL(); |
446 | 449 | ||
@@ -471,6 +474,23 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, | |||
471 | } | 474 | } |
472 | } | 475 | } |
473 | 476 | ||
477 | /* Allow any devices that wish to register ifaddr validtors to weigh | ||
478 | * in now, before changes are committed. The rntl lock is serializing | ||
479 | * access here, so the state should not change between a validator call | ||
480 | * and a final notify on commit. This isn't invoked on promotion under | ||
481 | * the assumption that validators are checking the address itself, and | ||
482 | * not the flags. | ||
483 | */ | ||
484 | ivi.ivi_addr = ifa->ifa_address; | ||
485 | ivi.ivi_dev = ifa->ifa_dev; | ||
486 | ret = blocking_notifier_call_chain(&inetaddr_validator_chain, | ||
487 | NETDEV_UP, &ivi); | ||
488 | ret = notifier_to_errno(ret); | ||
489 | if (ret) { | ||
490 | inet_free_ifa(ifa); | ||
491 | return ret; | ||
492 | } | ||
493 | |||
474 | if (!(ifa->ifa_flags & IFA_F_SECONDARY)) { | 494 | if (!(ifa->ifa_flags & IFA_F_SECONDARY)) { |
475 | prandom_seed((__force u32) ifa->ifa_local); | 495 | prandom_seed((__force u32) ifa->ifa_local); |
476 | ifap = last_primary; | 496 | ifap = last_primary; |
@@ -1356,6 +1376,19 @@ int unregister_inetaddr_notifier(struct notifier_block *nb) | |||
1356 | } | 1376 | } |
1357 | EXPORT_SYMBOL(unregister_inetaddr_notifier); | 1377 | EXPORT_SYMBOL(unregister_inetaddr_notifier); |
1358 | 1378 | ||
1379 | int register_inetaddr_validator_notifier(struct notifier_block *nb) | ||
1380 | { | ||
1381 | return blocking_notifier_chain_register(&inetaddr_validator_chain, nb); | ||
1382 | } | ||
1383 | EXPORT_SYMBOL(register_inetaddr_validator_notifier); | ||
1384 | |||
1385 | int unregister_inetaddr_validator_notifier(struct notifier_block *nb) | ||
1386 | { | ||
1387 | return blocking_notifier_chain_unregister(&inetaddr_validator_chain, | ||
1388 | nb); | ||
1389 | } | ||
1390 | EXPORT_SYMBOL(unregister_inetaddr_validator_notifier); | ||
1391 | |||
1359 | /* Rename ifa_labels for a device name change. Make some effort to preserve | 1392 | /* Rename ifa_labels for a device name change. Make some effort to preserve |
1360 | * existing alias numbering and to create unique labels if possible. | 1393 | * existing alias numbering and to create unique labels if possible. |
1361 | */ | 1394 | */ |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 25443fd946a8..0aa36b093013 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -963,6 +963,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
963 | struct net *net = dev_net(idev->dev); | 963 | struct net *net = dev_net(idev->dev); |
964 | struct inet6_ifaddr *ifa = NULL; | 964 | struct inet6_ifaddr *ifa = NULL; |
965 | struct rt6_info *rt; | 965 | struct rt6_info *rt; |
966 | struct in6_validator_info i6vi; | ||
966 | unsigned int hash; | 967 | unsigned int hash; |
967 | int err = 0; | 968 | int err = 0; |
968 | int addr_type = ipv6_addr_type(addr); | 969 | int addr_type = ipv6_addr_type(addr); |
@@ -974,6 +975,9 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
974 | return ERR_PTR(-EADDRNOTAVAIL); | 975 | return ERR_PTR(-EADDRNOTAVAIL); |
975 | 976 | ||
976 | rcu_read_lock_bh(); | 977 | rcu_read_lock_bh(); |
978 | |||
979 | in6_dev_hold(idev); | ||
980 | |||
977 | if (idev->dead) { | 981 | if (idev->dead) { |
978 | err = -ENODEV; /*XXX*/ | 982 | err = -ENODEV; /*XXX*/ |
979 | goto out2; | 983 | goto out2; |
@@ -984,6 +988,17 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
984 | goto out2; | 988 | goto out2; |
985 | } | 989 | } |
986 | 990 | ||
991 | i6vi.i6vi_addr = *addr; | ||
992 | i6vi.i6vi_dev = idev; | ||
993 | rcu_read_unlock_bh(); | ||
994 | |||
995 | err = inet6addr_validator_notifier_call_chain(NETDEV_UP, &i6vi); | ||
996 | |||
997 | rcu_read_lock_bh(); | ||
998 | err = notifier_to_errno(err); | ||
999 | if (err) | ||
1000 | goto out2; | ||
1001 | |||
987 | spin_lock(&addrconf_hash_lock); | 1002 | spin_lock(&addrconf_hash_lock); |
988 | 1003 | ||
989 | /* Ignore adding duplicate addresses on an interface */ | 1004 | /* Ignore adding duplicate addresses on an interface */ |
@@ -1034,7 +1049,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
1034 | ifa->rt = rt; | 1049 | ifa->rt = rt; |
1035 | 1050 | ||
1036 | ifa->idev = idev; | 1051 | ifa->idev = idev; |
1037 | in6_dev_hold(idev); | ||
1038 | /* For caller */ | 1052 | /* For caller */ |
1039 | in6_ifa_hold(ifa); | 1053 | in6_ifa_hold(ifa); |
1040 | 1054 | ||
@@ -1062,6 +1076,7 @@ out2: | |||
1062 | inet6addr_notifier_call_chain(NETDEV_UP, ifa); | 1076 | inet6addr_notifier_call_chain(NETDEV_UP, ifa); |
1063 | else { | 1077 | else { |
1064 | kfree(ifa); | 1078 | kfree(ifa); |
1079 | in6_dev_put(idev); | ||
1065 | ifa = ERR_PTR(err); | 1080 | ifa = ERR_PTR(err); |
1066 | } | 1081 | } |
1067 | 1082 | ||
diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c index bfa941fc1165..9e3488d50b15 100644 --- a/net/ipv6/addrconf_core.c +++ b/net/ipv6/addrconf_core.c | |||
@@ -88,6 +88,7 @@ int __ipv6_addr_type(const struct in6_addr *addr) | |||
88 | EXPORT_SYMBOL(__ipv6_addr_type); | 88 | EXPORT_SYMBOL(__ipv6_addr_type); |
89 | 89 | ||
90 | static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); | 90 | static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); |
91 | static ATOMIC_NOTIFIER_HEAD(inet6addr_validator_chain); | ||
91 | 92 | ||
92 | int register_inet6addr_notifier(struct notifier_block *nb) | 93 | int register_inet6addr_notifier(struct notifier_block *nb) |
93 | { | 94 | { |
@@ -107,6 +108,24 @@ int inet6addr_notifier_call_chain(unsigned long val, void *v) | |||
107 | } | 108 | } |
108 | EXPORT_SYMBOL(inet6addr_notifier_call_chain); | 109 | EXPORT_SYMBOL(inet6addr_notifier_call_chain); |
109 | 110 | ||
111 | int register_inet6addr_validator_notifier(struct notifier_block *nb) | ||
112 | { | ||
113 | return atomic_notifier_chain_register(&inet6addr_validator_chain, nb); | ||
114 | } | ||
115 | EXPORT_SYMBOL(register_inet6addr_validator_notifier); | ||
116 | |||
117 | int unregister_inet6addr_validator_notifier(struct notifier_block *nb) | ||
118 | { | ||
119 | return atomic_notifier_chain_unregister(&inet6addr_validator_chain, nb); | ||
120 | } | ||
121 | EXPORT_SYMBOL(unregister_inet6addr_validator_notifier); | ||
122 | |||
123 | int inet6addr_validator_notifier_call_chain(unsigned long val, void *v) | ||
124 | { | ||
125 | return atomic_notifier_call_chain(&inet6addr_validator_chain, val, v); | ||
126 | } | ||
127 | EXPORT_SYMBOL(inet6addr_validator_notifier_call_chain); | ||
128 | |||
110 | static int eafnosupport_ipv6_dst_lookup(struct net *net, struct sock *u1, | 129 | static int eafnosupport_ipv6_dst_lookup(struct net *net, struct sock *u1, |
111 | struct dst_entry **u2, | 130 | struct dst_entry **u2, |
112 | struct flowi6 *u3) | 131 | struct flowi6 *u3) |