diff options
-rw-r--r-- | drivers/infiniband/hw/i40iw/i40iw_utils.c | 12 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes.c | 8 | ||||
-rw-r--r-- | drivers/infiniband/hw/usnic/usnic_ib_main.c | 15 | ||||
-rw-r--r-- | drivers/net/ethernet/via/via-velocity.h | 2 | ||||
-rw-r--r-- | drivers/net/plip/plip.c | 4 | ||||
-rw-r--r-- | drivers/net/vmxnet3/vmxnet3_drv.c | 19 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/marvell/mwifiex/cfg80211.c | 2 | ||||
-rw-r--r-- | drivers/staging/isdn/hysdn/hysdn_net.c | 6 | ||||
-rw-r--r-- | include/linux/inetdevice.h | 21 | ||||
-rw-r--r-- | net/core/netpoll.c | 10 | ||||
-rw-r--r-- | net/core/pktgen.c | 8 | ||||
-rw-r--r-- | net/ipv4/devinet.c | 88 | ||||
-rw-r--r-- | net/mac80211/main.c | 4 | ||||
-rw-r--r-- | net/netfilter/nf_nat_redirect.c | 12 |
15 files changed, 134 insertions, 81 deletions
diff --git a/drivers/infiniband/hw/i40iw/i40iw_utils.c b/drivers/infiniband/hw/i40iw/i40iw_utils.c index 337410f40860..016524683e17 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_utils.c +++ b/drivers/infiniband/hw/i40iw/i40iw_utils.c | |||
@@ -174,10 +174,14 @@ int i40iw_inetaddr_event(struct notifier_block *notifier, | |||
174 | rcu_read_lock(); | 174 | rcu_read_lock(); |
175 | in = __in_dev_get_rcu(upper_dev); | 175 | in = __in_dev_get_rcu(upper_dev); |
176 | 176 | ||
177 | if (!in->ifa_list) | 177 | local_ipaddr = 0; |
178 | local_ipaddr = 0; | 178 | if (in) { |
179 | else | 179 | struct in_ifaddr *ifa; |
180 | local_ipaddr = ntohl(in->ifa_list->ifa_address); | 180 | |
181 | ifa = rcu_dereference(in->ifa_list); | ||
182 | if (ifa) | ||
183 | local_ipaddr = ntohl(ifa->ifa_address); | ||
184 | } | ||
181 | 185 | ||
182 | rcu_read_unlock(); | 186 | rcu_read_unlock(); |
183 | } else { | 187 | } else { |
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index e00add6d78ec..29b324726ea6 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c | |||
@@ -183,7 +183,13 @@ static int nes_inetaddr_event(struct notifier_block *notifier, | |||
183 | 183 | ||
184 | rcu_read_lock(); | 184 | rcu_read_lock(); |
185 | in = __in_dev_get_rcu(upper_dev); | 185 | in = __in_dev_get_rcu(upper_dev); |
186 | nesvnic->local_ipaddr = in->ifa_list->ifa_address; | 186 | if (in) { |
187 | struct in_ifaddr *ifa; | ||
188 | |||
189 | ifa = rcu_dereference(in->ifa_list); | ||
190 | if (ifa) | ||
191 | nesvnic->local_ipaddr = ifa->ifa_address; | ||
192 | } | ||
187 | rcu_read_unlock(); | 193 | rcu_read_unlock(); |
188 | } else { | 194 | } else { |
189 | nesvnic->local_ipaddr = ifa->ifa_address; | 195 | nesvnic->local_ipaddr = ifa->ifa_address; |
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_main.c b/drivers/infiniband/hw/usnic/usnic_ib_main.c index d88d9f8a7f9a..34c1f9d6c915 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_main.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_main.c | |||
@@ -427,11 +427,16 @@ static void *usnic_ib_device_add(struct pci_dev *dev) | |||
427 | if (netif_carrier_ok(us_ibdev->netdev)) | 427 | if (netif_carrier_ok(us_ibdev->netdev)) |
428 | usnic_fwd_carrier_up(us_ibdev->ufdev); | 428 | usnic_fwd_carrier_up(us_ibdev->ufdev); |
429 | 429 | ||
430 | ind = in_dev_get(netdev); | 430 | rcu_read_lock(); |
431 | if (ind->ifa_list) | 431 | ind = __in_dev_get_rcu(netdev); |
432 | usnic_fwd_add_ipaddr(us_ibdev->ufdev, | 432 | if (ind) { |
433 | ind->ifa_list->ifa_address); | 433 | const struct in_ifaddr *ifa; |
434 | in_dev_put(ind); | 434 | |
435 | ifa = rcu_dereference(ind->ifa_list); | ||
436 | if (ifa) | ||
437 | usnic_fwd_add_ipaddr(us_ibdev->ufdev, ifa->ifa_address); | ||
438 | } | ||
439 | rcu_read_unlock(); | ||
435 | 440 | ||
436 | usnic_mac_ip_to_gid(us_ibdev->netdev->perm_addr, | 441 | usnic_mac_ip_to_gid(us_ibdev->netdev->perm_addr, |
437 | us_ibdev->ufdev->inaddr, &gid.raw[0]); | 442 | us_ibdev->ufdev->inaddr, &gid.raw[0]); |
diff --git a/drivers/net/ethernet/via/via-velocity.h b/drivers/net/ethernet/via/via-velocity.h index c0ecc6c7b5e0..cdfe7809e3c1 100644 --- a/drivers/net/ethernet/via/via-velocity.h +++ b/drivers/net/ethernet/via/via-velocity.h | |||
@@ -1509,7 +1509,7 @@ static inline int velocity_get_ip(struct velocity_info *vptr) | |||
1509 | rcu_read_lock(); | 1509 | rcu_read_lock(); |
1510 | in_dev = __in_dev_get_rcu(vptr->netdev); | 1510 | in_dev = __in_dev_get_rcu(vptr->netdev); |
1511 | if (in_dev != NULL) { | 1511 | if (in_dev != NULL) { |
1512 | ifa = (struct in_ifaddr *) in_dev->ifa_list; | 1512 | ifa = rcu_dereference(in_dev->ifa_list); |
1513 | if (ifa != NULL) { | 1513 | if (ifa != NULL) { |
1514 | memcpy(vptr->ip_addr, &ifa->ifa_address, 4); | 1514 | memcpy(vptr->ip_addr, &ifa->ifa_address, 4); |
1515 | res = 0; | 1515 | res = 0; |
diff --git a/drivers/net/plip/plip.c b/drivers/net/plip/plip.c index feb92ecd1880..3e3ac2e496a1 100644 --- a/drivers/net/plip/plip.c +++ b/drivers/net/plip/plip.c | |||
@@ -1012,7 +1012,7 @@ plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth) | |||
1012 | in_dev = __in_dev_get_rcu(dev); | 1012 | in_dev = __in_dev_get_rcu(dev); |
1013 | if (in_dev) { | 1013 | if (in_dev) { |
1014 | /* Any address will do - we take the first */ | 1014 | /* Any address will do - we take the first */ |
1015 | const struct in_ifaddr *ifa = in_dev->ifa_list; | 1015 | const struct in_ifaddr *ifa = rcu_dereference(in_dev->ifa_list); |
1016 | if (ifa) { | 1016 | if (ifa) { |
1017 | memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); | 1017 | memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); |
1018 | memset(eth->h_dest, 0xfc, 2); | 1018 | memset(eth->h_dest, 0xfc, 2); |
@@ -1107,7 +1107,7 @@ plip_open(struct net_device *dev) | |||
1107 | /* Any address will do - we take the first. We already | 1107 | /* Any address will do - we take the first. We already |
1108 | have the first two bytes filled with 0xfc, from | 1108 | have the first two bytes filled with 0xfc, from |
1109 | plip_init_dev(). */ | 1109 | plip_init_dev(). */ |
1110 | struct in_ifaddr *ifa=in_dev->ifa_list; | 1110 | const struct in_ifaddr *ifa = rcu_dereference(in_dev->ifa_list); |
1111 | if (ifa != NULL) { | 1111 | if (ifa != NULL) { |
1112 | memcpy(dev->dev_addr+2, &ifa->ifa_local, 4); | 1112 | memcpy(dev->dev_addr+2, &ifa->ifa_local, 4); |
1113 | } | 1113 | } |
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 89984fcab01e..1b2a18ea855c 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c | |||
@@ -3651,13 +3651,19 @@ vmxnet3_suspend(struct device *device) | |||
3651 | } | 3651 | } |
3652 | 3652 | ||
3653 | if (adapter->wol & WAKE_ARP) { | 3653 | if (adapter->wol & WAKE_ARP) { |
3654 | in_dev = in_dev_get(netdev); | 3654 | rcu_read_lock(); |
3655 | if (!in_dev) | 3655 | |
3656 | in_dev = __in_dev_get_rcu(netdev); | ||
3657 | if (!in_dev) { | ||
3658 | rcu_read_unlock(); | ||
3656 | goto skip_arp; | 3659 | goto skip_arp; |
3660 | } | ||
3657 | 3661 | ||
3658 | ifa = (struct in_ifaddr *)in_dev->ifa_list; | 3662 | ifa = rcu_dereference(in_dev->ifa_list); |
3659 | if (!ifa) | 3663 | if (!ifa) { |
3664 | rcu_read_unlock(); | ||
3660 | goto skip_arp; | 3665 | goto skip_arp; |
3666 | } | ||
3661 | 3667 | ||
3662 | pmConf->filters[i].patternSize = ETH_HLEN + /* Ethernet header*/ | 3668 | pmConf->filters[i].patternSize = ETH_HLEN + /* Ethernet header*/ |
3663 | sizeof(struct arphdr) + /* ARP header */ | 3669 | sizeof(struct arphdr) + /* ARP header */ |
@@ -3677,7 +3683,9 @@ vmxnet3_suspend(struct device *device) | |||
3677 | 3683 | ||
3678 | /* The Unicast IPv4 address in 'tip' field. */ | 3684 | /* The Unicast IPv4 address in 'tip' field. */ |
3679 | arpreq += 2 * ETH_ALEN + sizeof(u32); | 3685 | arpreq += 2 * ETH_ALEN + sizeof(u32); |
3680 | *(u32 *)arpreq = ifa->ifa_address; | 3686 | *(__be32 *)arpreq = ifa->ifa_address; |
3687 | |||
3688 | rcu_read_unlock(); | ||
3681 | 3689 | ||
3682 | /* The mask for the relevant bits. */ | 3690 | /* The mask for the relevant bits. */ |
3683 | pmConf->filters[i].mask[0] = 0x00; | 3691 | pmConf->filters[i].mask[0] = 0x00; |
@@ -3686,7 +3694,6 @@ vmxnet3_suspend(struct device *device) | |||
3686 | pmConf->filters[i].mask[3] = 0x00; | 3694 | pmConf->filters[i].mask[3] = 0x00; |
3687 | pmConf->filters[i].mask[4] = 0xC0; /* IPv4 TIP */ | 3695 | pmConf->filters[i].mask[4] = 0xC0; /* IPv4 TIP */ |
3688 | pmConf->filters[i].mask[5] = 0x03; /* IPv4 TIP */ | 3696 | pmConf->filters[i].mask[5] = 0x03; /* IPv4 TIP */ |
3689 | in_dev_put(in_dev); | ||
3690 | 3697 | ||
3691 | pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_FILTER; | 3698 | pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_FILTER; |
3692 | i++; | 3699 | i++; |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 5477a014e1fb..37cf602d8adf 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -2194,13 +2194,13 @@ static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif, | |||
2194 | if (!in_dev) | 2194 | if (!in_dev) |
2195 | return 0; | 2195 | return 0; |
2196 | 2196 | ||
2197 | ifa = in_dev->ifa_list; | 2197 | ifa = rtnl_dereference(in_dev->ifa_list); |
2198 | memset(&ips, 0, sizeof(ips)); | 2198 | memset(&ips, 0, sizeof(ips)); |
2199 | 2199 | ||
2200 | /* Configure IP addr only if IP address count < MAX_IP_ADDRS */ | 2200 | /* Configure IP addr only if IP address count < MAX_IP_ADDRS */ |
2201 | while (index < MAX_IP_ADDRS && ifa) { | 2201 | while (index < MAX_IP_ADDRS && ifa) { |
2202 | ips[index] = ifa->ifa_local; | 2202 | ips[index] = ifa->ifa_local; |
2203 | ifa = ifa->ifa_next; | 2203 | ifa = rtnl_dereference(ifa->ifa_next); |
2204 | index++; | 2204 | index++; |
2205 | } | 2205 | } |
2206 | 2206 | ||
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index e11a4bb67172..5a7cdb981789 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c | |||
@@ -3268,7 +3268,7 @@ static void mwifiex_set_auto_arp_mef_entry(struct mwifiex_private *priv, | |||
3268 | in_dev = __in_dev_get_rtnl(adapter->priv[i]->netdev); | 3268 | in_dev = __in_dev_get_rtnl(adapter->priv[i]->netdev); |
3269 | if (!in_dev) | 3269 | if (!in_dev) |
3270 | continue; | 3270 | continue; |
3271 | ifa = in_dev->ifa_list; | 3271 | ifa = rtnl_dereference(in_dev->ifa_list); |
3272 | if (!ifa || !ifa->ifa_local) | 3272 | if (!ifa || !ifa->ifa_local) |
3273 | continue; | 3273 | continue; |
3274 | ips[i] = ifa->ifa_local; | 3274 | ips[i] = ifa->ifa_local; |
diff --git a/drivers/staging/isdn/hysdn/hysdn_net.c b/drivers/staging/isdn/hysdn/hysdn_net.c index 8e9c34f33d86..bea37ae30ebb 100644 --- a/drivers/staging/isdn/hysdn/hysdn_net.c +++ b/drivers/staging/isdn/hysdn/hysdn_net.c | |||
@@ -70,9 +70,13 @@ net_open(struct net_device *dev) | |||
70 | for (i = 0; i < ETH_ALEN; i++) | 70 | for (i = 0; i < ETH_ALEN; i++) |
71 | dev->dev_addr[i] = 0xfc; | 71 | dev->dev_addr[i] = 0xfc; |
72 | if ((in_dev = dev->ip_ptr) != NULL) { | 72 | if ((in_dev = dev->ip_ptr) != NULL) { |
73 | struct in_ifaddr *ifa = in_dev->ifa_list; | 73 | const struct in_ifaddr *ifa; |
74 | |||
75 | rcu_read_lock(); | ||
76 | ifa = rcu_dereference(in_dev->ifa_list); | ||
74 | if (ifa != NULL) | 77 | if (ifa != NULL) |
75 | memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ifa->ifa_local)), &ifa->ifa_local, sizeof(ifa->ifa_local)); | 78 | memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ifa->ifa_local)), &ifa->ifa_local, sizeof(ifa->ifa_local)); |
79 | rcu_read_unlock(); | ||
76 | } | 80 | } |
77 | } else | 81 | } else |
78 | memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN); | 82 | memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN); |
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index d5d05503a04b..3515ca64e638 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h | |||
@@ -26,7 +26,7 @@ struct in_device { | |||
26 | struct net_device *dev; | 26 | struct net_device *dev; |
27 | refcount_t refcnt; | 27 | refcount_t refcnt; |
28 | int dead; | 28 | int dead; |
29 | struct in_ifaddr *ifa_list; /* IP ifaddr chain */ | 29 | struct in_ifaddr __rcu *ifa_list;/* IP ifaddr chain */ |
30 | 30 | ||
31 | struct ip_mc_list __rcu *mc_list; /* IP multicast filter chain */ | 31 | struct ip_mc_list __rcu *mc_list; /* IP multicast filter chain */ |
32 | struct ip_mc_list __rcu * __rcu *mc_hash; | 32 | struct ip_mc_list __rcu * __rcu *mc_hash; |
@@ -136,7 +136,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev) | |||
136 | 136 | ||
137 | struct in_ifaddr { | 137 | struct in_ifaddr { |
138 | struct hlist_node hash; | 138 | struct hlist_node hash; |
139 | struct in_ifaddr *ifa_next; | 139 | struct in_ifaddr __rcu *ifa_next; |
140 | struct in_device *ifa_dev; | 140 | struct in_device *ifa_dev; |
141 | struct rcu_head rcu_head; | 141 | struct rcu_head rcu_head; |
142 | __be32 ifa_local; | 142 | __be32 ifa_local; |
@@ -206,22 +206,13 @@ static __inline__ bool bad_mask(__be32 mask, __be32 addr) | |||
206 | return false; | 206 | return false; |
207 | } | 207 | } |
208 | 208 | ||
209 | #define for_primary_ifa(in_dev) { struct in_ifaddr *ifa; \ | ||
210 | for (ifa = (in_dev)->ifa_list; ifa && !(ifa->ifa_flags&IFA_F_SECONDARY); ifa = ifa->ifa_next) | ||
211 | |||
212 | #define for_ifa(in_dev) { struct in_ifaddr *ifa; \ | ||
213 | for (ifa = (in_dev)->ifa_list; ifa; ifa = ifa->ifa_next) | ||
214 | |||
215 | |||
216 | #define endfor_ifa(in_dev) } | ||
217 | |||
218 | #define in_dev_for_each_ifa_rtnl(ifa, in_dev) \ | 209 | #define in_dev_for_each_ifa_rtnl(ifa, in_dev) \ |
219 | for (ifa = (in_dev)->ifa_list; ifa; \ | 210 | for (ifa = rtnl_dereference((in_dev)->ifa_list); ifa; \ |
220 | ifa = ifa->ifa_next) | 211 | ifa = rtnl_dereference(ifa->ifa_next)) |
221 | 212 | ||
222 | #define in_dev_for_each_ifa_rcu(ifa, in_dev) \ | 213 | #define in_dev_for_each_ifa_rcu(ifa, in_dev) \ |
223 | for (ifa = (in_dev)->ifa_list; ifa; \ | 214 | for (ifa = rcu_dereference((in_dev)->ifa_list); ifa; \ |
224 | ifa = ifa->ifa_next) | 215 | ifa = rcu_dereference(ifa->ifa_next)) |
225 | 216 | ||
226 | static inline struct in_device *__in_dev_get_rcu(const struct net_device *dev) | 217 | static inline struct in_device *__in_dev_get_rcu(const struct net_device *dev) |
227 | { | 218 | { |
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index dd8b1a460d64..2cf27da1baeb 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
@@ -696,16 +696,22 @@ int netpoll_setup(struct netpoll *np) | |||
696 | 696 | ||
697 | if (!np->local_ip.ip) { | 697 | if (!np->local_ip.ip) { |
698 | if (!np->ipv6) { | 698 | if (!np->ipv6) { |
699 | const struct in_ifaddr *ifa; | ||
700 | |||
699 | in_dev = __in_dev_get_rtnl(ndev); | 701 | in_dev = __in_dev_get_rtnl(ndev); |
702 | if (!in_dev) | ||
703 | goto put_noaddr; | ||
700 | 704 | ||
701 | if (!in_dev || !in_dev->ifa_list) { | 705 | ifa = rtnl_dereference(in_dev->ifa_list); |
706 | if (!ifa) { | ||
707 | put_noaddr: | ||
702 | np_err(np, "no IP address for %s, aborting\n", | 708 | np_err(np, "no IP address for %s, aborting\n", |
703 | np->dev_name); | 709 | np->dev_name); |
704 | err = -EDESTADDRREQ; | 710 | err = -EDESTADDRREQ; |
705 | goto put; | 711 | goto put; |
706 | } | 712 | } |
707 | 713 | ||
708 | np->local_ip.ip = in_dev->ifa_list->ifa_local; | 714 | np->local_ip.ip = ifa->ifa_local; |
709 | np_info(np, "local IP %pI4\n", &np->local_ip.ip); | 715 | np_info(np, "local IP %pI4\n", &np->local_ip.ip); |
710 | } else { | 716 | } else { |
711 | #if IS_ENABLED(CONFIG_IPV6) | 717 | #if IS_ENABLED(CONFIG_IPV6) |
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 319ad5490fb3..4cd120dc30ad 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -2125,9 +2125,11 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) | |||
2125 | rcu_read_lock(); | 2125 | rcu_read_lock(); |
2126 | in_dev = __in_dev_get_rcu(pkt_dev->odev); | 2126 | in_dev = __in_dev_get_rcu(pkt_dev->odev); |
2127 | if (in_dev) { | 2127 | if (in_dev) { |
2128 | if (in_dev->ifa_list) { | 2128 | const struct in_ifaddr *ifa; |
2129 | pkt_dev->saddr_min = | 2129 | |
2130 | in_dev->ifa_list->ifa_address; | 2130 | ifa = rcu_dereference(in_dev->ifa_list); |
2131 | if (ifa) { | ||
2132 | pkt_dev->saddr_min = ifa->ifa_address; | ||
2131 | pkt_dev->saddr_max = pkt_dev->saddr_min; | 2133 | pkt_dev->saddr_max = pkt_dev->saddr_min; |
2132 | } | 2134 | } |
2133 | } | 2135 | } |
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index b45421b2b734..ebaea05b4033 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -194,7 +194,8 @@ static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32); | |||
194 | 194 | ||
195 | static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); | 195 | static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); |
196 | static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain); | 196 | static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain); |
197 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | 197 | static void inet_del_ifa(struct in_device *in_dev, |
198 | struct in_ifaddr __rcu **ifap, | ||
198 | int destroy); | 199 | int destroy); |
199 | #ifdef CONFIG_SYSCTL | 200 | #ifdef CONFIG_SYSCTL |
200 | static int devinet_sysctl_register(struct in_device *idev); | 201 | static int devinet_sysctl_register(struct in_device *idev); |
@@ -300,8 +301,8 @@ static void in_dev_rcu_put(struct rcu_head *head) | |||
300 | 301 | ||
301 | static void inetdev_destroy(struct in_device *in_dev) | 302 | static void inetdev_destroy(struct in_device *in_dev) |
302 | { | 303 | { |
303 | struct in_ifaddr *ifa; | ||
304 | struct net_device *dev; | 304 | struct net_device *dev; |
305 | struct in_ifaddr *ifa; | ||
305 | 306 | ||
306 | ASSERT_RTNL(); | 307 | ASSERT_RTNL(); |
307 | 308 | ||
@@ -311,7 +312,7 @@ static void inetdev_destroy(struct in_device *in_dev) | |||
311 | 312 | ||
312 | ip_mc_destroy_dev(in_dev); | 313 | ip_mc_destroy_dev(in_dev); |
313 | 314 | ||
314 | while ((ifa = in_dev->ifa_list) != NULL) { | 315 | while ((ifa = rtnl_dereference(in_dev->ifa_list)) != NULL) { |
315 | inet_del_ifa(in_dev, &in_dev->ifa_list, 0); | 316 | inet_del_ifa(in_dev, &in_dev->ifa_list, 0); |
316 | inet_free_ifa(ifa); | 317 | inet_free_ifa(ifa); |
317 | } | 318 | } |
@@ -342,17 +343,20 @@ int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b) | |||
342 | return 0; | 343 | return 0; |
343 | } | 344 | } |
344 | 345 | ||
345 | static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | 346 | static void __inet_del_ifa(struct in_device *in_dev, |
346 | int destroy, struct nlmsghdr *nlh, u32 portid) | 347 | struct in_ifaddr __rcu **ifap, |
348 | int destroy, struct nlmsghdr *nlh, u32 portid) | ||
347 | { | 349 | { |
348 | struct in_ifaddr *promote = NULL; | 350 | struct in_ifaddr *promote = NULL; |
349 | struct in_ifaddr *ifa, *ifa1 = *ifap; | 351 | struct in_ifaddr *ifa, *ifa1; |
350 | struct in_ifaddr *last_prim = in_dev->ifa_list; | 352 | struct in_ifaddr *last_prim; |
351 | struct in_ifaddr *prev_prom = NULL; | 353 | struct in_ifaddr *prev_prom = NULL; |
352 | int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev); | 354 | int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev); |
353 | 355 | ||
354 | ASSERT_RTNL(); | 356 | ASSERT_RTNL(); |
355 | 357 | ||
358 | ifa1 = rtnl_dereference(*ifap); | ||
359 | last_prim = rtnl_dereference(in_dev->ifa_list); | ||
356 | if (in_dev->dead) | 360 | if (in_dev->dead) |
357 | goto no_promotions; | 361 | goto no_promotions; |
358 | 362 | ||
@@ -361,9 +365,9 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
361 | **/ | 365 | **/ |
362 | 366 | ||
363 | if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) { | 367 | if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) { |
364 | struct in_ifaddr **ifap1 = &ifa1->ifa_next; | 368 | struct in_ifaddr __rcu **ifap1 = &ifa1->ifa_next; |
365 | 369 | ||
366 | while ((ifa = *ifap1) != NULL) { | 370 | while ((ifa = rtnl_dereference(*ifap1)) != NULL) { |
367 | if (!(ifa->ifa_flags & IFA_F_SECONDARY) && | 371 | if (!(ifa->ifa_flags & IFA_F_SECONDARY) && |
368 | ifa1->ifa_scope <= ifa->ifa_scope) | 372 | ifa1->ifa_scope <= ifa->ifa_scope) |
369 | last_prim = ifa; | 373 | last_prim = ifa; |
@@ -396,7 +400,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
396 | * and later to add them back with new prefsrc. Do this | 400 | * and later to add them back with new prefsrc. Do this |
397 | * while all addresses are on the device list. | 401 | * while all addresses are on the device list. |
398 | */ | 402 | */ |
399 | for (ifa = promote; ifa; ifa = ifa->ifa_next) { | 403 | for (ifa = promote; ifa; ifa = rtnl_dereference(ifa->ifa_next)) { |
400 | if (ifa1->ifa_mask == ifa->ifa_mask && | 404 | if (ifa1->ifa_mask == ifa->ifa_mask && |
401 | inet_ifa_match(ifa1->ifa_address, ifa)) | 405 | inet_ifa_match(ifa1->ifa_address, ifa)) |
402 | fib_del_ifaddr(ifa, ifa1); | 406 | fib_del_ifaddr(ifa, ifa1); |
@@ -422,19 +426,24 @@ no_promotions: | |||
422 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); | 426 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); |
423 | 427 | ||
424 | if (promote) { | 428 | if (promote) { |
425 | struct in_ifaddr *next_sec = promote->ifa_next; | 429 | struct in_ifaddr *next_sec; |
426 | 430 | ||
431 | next_sec = rtnl_dereference(promote->ifa_next); | ||
427 | if (prev_prom) { | 432 | if (prev_prom) { |
428 | prev_prom->ifa_next = promote->ifa_next; | 433 | struct in_ifaddr *last_sec; |
429 | promote->ifa_next = last_prim->ifa_next; | 434 | |
430 | last_prim->ifa_next = promote; | 435 | last_sec = rtnl_dereference(last_prim->ifa_next); |
436 | rcu_assign_pointer(prev_prom->ifa_next, next_sec); | ||
437 | rcu_assign_pointer(promote->ifa_next, last_sec); | ||
438 | rcu_assign_pointer(last_prim->ifa_next, promote); | ||
431 | } | 439 | } |
432 | 440 | ||
433 | promote->ifa_flags &= ~IFA_F_SECONDARY; | 441 | promote->ifa_flags &= ~IFA_F_SECONDARY; |
434 | rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid); | 442 | rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid); |
435 | blocking_notifier_call_chain(&inetaddr_chain, | 443 | blocking_notifier_call_chain(&inetaddr_chain, |
436 | NETDEV_UP, promote); | 444 | NETDEV_UP, promote); |
437 | for (ifa = next_sec; ifa; ifa = ifa->ifa_next) { | 445 | for (ifa = next_sec; ifa; |
446 | ifa = rtnl_dereference(ifa->ifa_next)) { | ||
438 | if (ifa1->ifa_mask != ifa->ifa_mask || | 447 | if (ifa1->ifa_mask != ifa->ifa_mask || |
439 | !inet_ifa_match(ifa1->ifa_address, ifa)) | 448 | !inet_ifa_match(ifa1->ifa_address, ifa)) |
440 | continue; | 449 | continue; |
@@ -446,7 +455,8 @@ no_promotions: | |||
446 | inet_free_ifa(ifa1); | 455 | inet_free_ifa(ifa1); |
447 | } | 456 | } |
448 | 457 | ||
449 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | 458 | static void inet_del_ifa(struct in_device *in_dev, |
459 | struct in_ifaddr __rcu **ifap, | ||
450 | int destroy) | 460 | int destroy) |
451 | { | 461 | { |
452 | __inet_del_ifa(in_dev, ifap, destroy, NULL, 0); | 462 | __inet_del_ifa(in_dev, ifap, destroy, NULL, 0); |
@@ -459,9 +469,10 @@ static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime); | |||
459 | static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, | 469 | static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, |
460 | u32 portid, struct netlink_ext_ack *extack) | 470 | u32 portid, struct netlink_ext_ack *extack) |
461 | { | 471 | { |
472 | struct in_ifaddr __rcu **last_primary, **ifap; | ||
462 | struct in_device *in_dev = ifa->ifa_dev; | 473 | struct in_device *in_dev = ifa->ifa_dev; |
463 | struct in_ifaddr *ifa1, **ifap, **last_primary; | ||
464 | struct in_validator_info ivi; | 474 | struct in_validator_info ivi; |
475 | struct in_ifaddr *ifa1; | ||
465 | int ret; | 476 | int ret; |
466 | 477 | ||
467 | ASSERT_RTNL(); | 478 | ASSERT_RTNL(); |
@@ -474,8 +485,10 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, | |||
474 | ifa->ifa_flags &= ~IFA_F_SECONDARY; | 485 | ifa->ifa_flags &= ~IFA_F_SECONDARY; |
475 | last_primary = &in_dev->ifa_list; | 486 | last_primary = &in_dev->ifa_list; |
476 | 487 | ||
477 | for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL; | 488 | ifap = &in_dev->ifa_list; |
478 | ifap = &ifa1->ifa_next) { | 489 | ifa1 = rtnl_dereference(*ifap); |
490 | |||
491 | while (ifa1) { | ||
479 | if (!(ifa1->ifa_flags & IFA_F_SECONDARY) && | 492 | if (!(ifa1->ifa_flags & IFA_F_SECONDARY) && |
480 | ifa->ifa_scope <= ifa1->ifa_scope) | 493 | ifa->ifa_scope <= ifa1->ifa_scope) |
481 | last_primary = &ifa1->ifa_next; | 494 | last_primary = &ifa1->ifa_next; |
@@ -491,6 +504,9 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, | |||
491 | } | 504 | } |
492 | ifa->ifa_flags |= IFA_F_SECONDARY; | 505 | ifa->ifa_flags |= IFA_F_SECONDARY; |
493 | } | 506 | } |
507 | |||
508 | ifap = &ifa1->ifa_next; | ||
509 | ifa1 = rtnl_dereference(*ifap); | ||
494 | } | 510 | } |
495 | 511 | ||
496 | /* Allow any devices that wish to register ifaddr validtors to weigh | 512 | /* Allow any devices that wish to register ifaddr validtors to weigh |
@@ -516,8 +532,8 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, | |||
516 | ifap = last_primary; | 532 | ifap = last_primary; |
517 | } | 533 | } |
518 | 534 | ||
519 | ifa->ifa_next = *ifap; | 535 | rcu_assign_pointer(ifa->ifa_next, *ifap); |
520 | *ifap = ifa; | 536 | rcu_assign_pointer(*ifap, ifa); |
521 | 537 | ||
522 | inet_hash_insert(dev_net(in_dev->dev), ifa); | 538 | inet_hash_insert(dev_net(in_dev->dev), ifa); |
523 | 539 | ||
@@ -617,10 +633,12 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
617 | struct netlink_ext_ack *extack) | 633 | struct netlink_ext_ack *extack) |
618 | { | 634 | { |
619 | struct net *net = sock_net(skb->sk); | 635 | struct net *net = sock_net(skb->sk); |
636 | struct in_ifaddr __rcu **ifap; | ||
620 | struct nlattr *tb[IFA_MAX+1]; | 637 | struct nlattr *tb[IFA_MAX+1]; |
621 | struct in_device *in_dev; | 638 | struct in_device *in_dev; |
622 | struct ifaddrmsg *ifm; | 639 | struct ifaddrmsg *ifm; |
623 | struct in_ifaddr *ifa, **ifap; | 640 | struct in_ifaddr *ifa; |
641 | |||
624 | int err = -EINVAL; | 642 | int err = -EINVAL; |
625 | 643 | ||
626 | ASSERT_RTNL(); | 644 | ASSERT_RTNL(); |
@@ -637,7 +655,7 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
637 | goto errout; | 655 | goto errout; |
638 | } | 656 | } |
639 | 657 | ||
640 | for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; | 658 | for (ifap = &in_dev->ifa_list; (ifa = rtnl_dereference(*ifap)) != NULL; |
641 | ifap = &ifa->ifa_next) { | 659 | ifap = &ifa->ifa_next) { |
642 | if (tb[IFA_LOCAL] && | 660 | if (tb[IFA_LOCAL] && |
643 | ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL])) | 661 | ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL])) |
@@ -725,15 +743,20 @@ static void check_lifetime(struct work_struct *work) | |||
725 | 743 | ||
726 | if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME && | 744 | if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME && |
727 | age >= ifa->ifa_valid_lft) { | 745 | age >= ifa->ifa_valid_lft) { |
728 | struct in_ifaddr **ifap; | 746 | struct in_ifaddr __rcu **ifap; |
729 | 747 | struct in_ifaddr *tmp; | |
730 | for (ifap = &ifa->ifa_dev->ifa_list; | 748 | |
731 | *ifap != NULL; ifap = &(*ifap)->ifa_next) { | 749 | ifap = &ifa->ifa_dev->ifa_list; |
732 | if (*ifap == ifa) { | 750 | tmp = rtnl_dereference(*ifap); |
751 | while (tmp) { | ||
752 | tmp = rtnl_dereference(tmp->ifa_next); | ||
753 | if (rtnl_dereference(*ifap) == ifa) { | ||
733 | inet_del_ifa(ifa->ifa_dev, | 754 | inet_del_ifa(ifa->ifa_dev, |
734 | ifap, 1); | 755 | ifap, 1); |
735 | break; | 756 | break; |
736 | } | 757 | } |
758 | ifap = &tmp->ifa_next; | ||
759 | tmp = rtnl_dereference(*ifap); | ||
737 | } | 760 | } |
738 | } else if (ifa->ifa_preferred_lft != | 761 | } else if (ifa->ifa_preferred_lft != |
739 | INFINITY_LIFE_TIME && | 762 | INFINITY_LIFE_TIME && |
@@ -977,8 +1000,8 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr) | |||
977 | { | 1000 | { |
978 | struct sockaddr_in sin_orig; | 1001 | struct sockaddr_in sin_orig; |
979 | struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr; | 1002 | struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr; |
1003 | struct in_ifaddr __rcu **ifap = NULL; | ||
980 | struct in_device *in_dev; | 1004 | struct in_device *in_dev; |
981 | struct in_ifaddr **ifap = NULL; | ||
982 | struct in_ifaddr *ifa = NULL; | 1005 | struct in_ifaddr *ifa = NULL; |
983 | struct net_device *dev; | 1006 | struct net_device *dev; |
984 | char *colon; | 1007 | char *colon; |
@@ -1049,7 +1072,9 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr) | |||
1049 | /* note: we only do this for a limited set of ioctls | 1072 | /* note: we only do this for a limited set of ioctls |
1050 | and only if the original address family was AF_INET. | 1073 | and only if the original address family was AF_INET. |
1051 | This is checked above. */ | 1074 | This is checked above. */ |
1052 | for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; | 1075 | |
1076 | for (ifap = &in_dev->ifa_list; | ||
1077 | (ifa = rtnl_dereference(*ifap)) != NULL; | ||
1053 | ifap = &ifa->ifa_next) { | 1078 | ifap = &ifa->ifa_next) { |
1054 | if (!strcmp(ifr->ifr_name, ifa->ifa_label) && | 1079 | if (!strcmp(ifr->ifr_name, ifa->ifa_label) && |
1055 | sin_orig.sin_addr.s_addr == | 1080 | sin_orig.sin_addr.s_addr == |
@@ -1062,7 +1087,8 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr) | |||
1062 | 4.3BSD-style and passed in junk so we fall back to | 1087 | 4.3BSD-style and passed in junk so we fall back to |
1063 | comparing just the label */ | 1088 | comparing just the label */ |
1064 | if (!ifa) { | 1089 | if (!ifa) { |
1065 | for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; | 1090 | for (ifap = &in_dev->ifa_list; |
1091 | (ifa = rtnl_dereference(*ifap)) != NULL; | ||
1066 | ifap = &ifa->ifa_next) | 1092 | ifap = &ifa->ifa_next) |
1067 | if (!strcmp(ifr->ifr_name, ifa->ifa_label)) | 1093 | if (!strcmp(ifr->ifr_name, ifa->ifa_label)) |
1068 | break; | 1094 | break; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 2b608044ae23..1f11907dc528 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -354,11 +354,11 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, | |||
354 | sdata_lock(sdata); | 354 | sdata_lock(sdata); |
355 | 355 | ||
356 | /* Copy the addresses to the bss_conf list */ | 356 | /* Copy the addresses to the bss_conf list */ |
357 | ifa = idev->ifa_list; | 357 | ifa = rtnl_dereference(idev->ifa_list); |
358 | while (ifa) { | 358 | while (ifa) { |
359 | if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN) | 359 | if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN) |
360 | bss_conf->arp_addr_list[c] = ifa->ifa_address; | 360 | bss_conf->arp_addr_list[c] = ifa->ifa_address; |
361 | ifa = ifa->ifa_next; | 361 | ifa = rtnl_dereference(ifa->ifa_next); |
362 | c++; | 362 | c++; |
363 | } | 363 | } |
364 | 364 | ||
diff --git a/net/netfilter/nf_nat_redirect.c b/net/netfilter/nf_nat_redirect.c index 78a9e6454ff3..8598e80968e0 100644 --- a/net/netfilter/nf_nat_redirect.c +++ b/net/netfilter/nf_nat_redirect.c | |||
@@ -47,15 +47,17 @@ nf_nat_redirect_ipv4(struct sk_buff *skb, | |||
47 | if (hooknum == NF_INET_LOCAL_OUT) { | 47 | if (hooknum == NF_INET_LOCAL_OUT) { |
48 | newdst = htonl(0x7F000001); | 48 | newdst = htonl(0x7F000001); |
49 | } else { | 49 | } else { |
50 | struct in_device *indev; | 50 | const struct in_device *indev; |
51 | struct in_ifaddr *ifa; | ||
52 | 51 | ||
53 | newdst = 0; | 52 | newdst = 0; |
54 | 53 | ||
55 | indev = __in_dev_get_rcu(skb->dev); | 54 | indev = __in_dev_get_rcu(skb->dev); |
56 | if (indev && indev->ifa_list) { | 55 | if (indev) { |
57 | ifa = indev->ifa_list; | 56 | const struct in_ifaddr *ifa; |
58 | newdst = ifa->ifa_local; | 57 | |
58 | ifa = rcu_dereference(indev->ifa_list); | ||
59 | if (ifa) | ||
60 | newdst = ifa->ifa_local; | ||
59 | } | 61 | } |
60 | 62 | ||
61 | if (!newdst) | 63 | if (!newdst) |