Commit 95ae6b22 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

ipv4: ip_ptr cleanups

dev->ip_ptr is protected by rtnl and rcu.

Yet some places dont use appropriate primitives and/or locking rules.
Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9e0064a5
...@@ -995,8 +995,10 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev) ...@@ -995,8 +995,10 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
static void static void
plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth) plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth)
{ {
const struct in_device *in_dev = dev->ip_ptr; const struct in_device *in_dev;
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
if (in_dev) { if (in_dev) {
/* Any address will do - we take the first */ /* Any address will do - we take the first */
const struct in_ifaddr *ifa = in_dev->ifa_list; const struct in_ifaddr *ifa = in_dev->ifa_list;
...@@ -1006,6 +1008,7 @@ plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth) ...@@ -1006,6 +1008,7 @@ plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth)
memcpy(eth->h_dest+2, &ifa->ifa_address, 4); memcpy(eth->h_dest+2, &ifa->ifa_address, 4);
} }
} }
rcu_read_unlock();
} }
static int static int
...@@ -1088,7 +1091,8 @@ plip_open(struct net_device *dev) ...@@ -1088,7 +1091,8 @@ plip_open(struct net_device *dev)
when the device address isn't identical to the address of a when the device address isn't identical to the address of a
received frame, the kernel incorrectly drops it). */ received frame, the kernel incorrectly drops it). */
if ((in_dev=dev->ip_ptr) != NULL) { in_dev=__in_dev_get_rtnl(dev);
if (in_dev) {
/* Any address will do - we take the first. We already /* Any address will do - we take the first. We already
have the first two bytes filled with 0xfc, from have the first two bytes filled with 0xfc, from
plip_init_dev(). */ plip_init_dev(). */
......
...@@ -1504,22 +1504,25 @@ struct velocity_info { ...@@ -1504,22 +1504,25 @@ struct velocity_info {
* addresses on this chain then we use the first - multi-IP WOL is not * addresses on this chain then we use the first - multi-IP WOL is not
* supported. * supported.
* *
* CHECK ME: locking
*/ */
static inline int velocity_get_ip(struct velocity_info *vptr) static inline int velocity_get_ip(struct velocity_info *vptr)
{ {
struct in_device *in_dev = (struct in_device *) vptr->dev->ip_ptr; struct in_device *in_dev;
struct in_ifaddr *ifa; struct in_ifaddr *ifa;
int res = -ENOENT;
rcu_read_lock();
in_dev = __in_dev_get_rcu(vptr->dev);
if (in_dev != NULL) { if (in_dev != NULL) {
ifa = (struct in_ifaddr *) in_dev->ifa_list; ifa = (struct in_ifaddr *) in_dev->ifa_list;
if (ifa != NULL) { if (ifa != NULL) {
memcpy(vptr->ip_addr, &ifa->ifa_address, 4); memcpy(vptr->ip_addr, &ifa->ifa_address, 4);
return 0; res = 0;
} }
} }
return -ENOENT; rcu_read_unlock();
return res;
} }
/** /**
......
...@@ -191,7 +191,8 @@ static int cisco_rx(struct sk_buff *skb) ...@@ -191,7 +191,8 @@ static int cisco_rx(struct sk_buff *skb)
switch (ntohl (cisco_data->type)) { switch (ntohl (cisco_data->type)) {
case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */ case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
in_dev = dev->ip_ptr; rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
addr = 0; addr = 0;
mask = ~cpu_to_be32(0); /* is the mask correct? */ mask = ~cpu_to_be32(0); /* is the mask correct? */
...@@ -211,6 +212,7 @@ static int cisco_rx(struct sk_buff *skb) ...@@ -211,6 +212,7 @@ static int cisco_rx(struct sk_buff *skb)
cisco_keepalive_send(dev, CISCO_ADDR_REPLY, cisco_keepalive_send(dev, CISCO_ADDR_REPLY,
addr, mask); addr, mask);
} }
rcu_read_unlock();
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
return NET_RX_SUCCESS; return NET_RX_SUCCESS;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/rtnetlink.h>
enum enum
{ {
...@@ -198,14 +199,10 @@ static __inline__ int bad_mask(__be32 mask, __be32 addr) ...@@ -198,14 +199,10 @@ static __inline__ int bad_mask(__be32 mask, __be32 addr)
static inline struct in_device *__in_dev_get_rcu(const struct net_device *dev) static inline struct in_device *__in_dev_get_rcu(const struct net_device *dev)
{ {
struct in_device *in_dev = dev->ip_ptr; return rcu_dereference(dev->ip_ptr);
if (in_dev)
in_dev = rcu_dereference(in_dev);
return in_dev;
} }
static __inline__ struct in_device * static inline struct in_device *in_dev_get(const struct net_device *dev)
in_dev_get(const struct net_device *dev)
{ {
struct in_device *in_dev; struct in_device *in_dev;
...@@ -217,10 +214,9 @@ in_dev_get(const struct net_device *dev) ...@@ -217,10 +214,9 @@ in_dev_get(const struct net_device *dev)
return in_dev; return in_dev;
} }
static __inline__ struct in_device * static inline struct in_device *__in_dev_get_rtnl(const struct net_device *dev)
__in_dev_get_rtnl(const struct net_device *dev)
{ {
return (struct in_device*)dev->ip_ptr; return rcu_dereference_check(dev->ip_ptr, lockdep_rtnl_is_held());
} }
extern void in_dev_finish_destroy(struct in_device *idev); extern void in_dev_finish_destroy(struct in_device *idev);
......
...@@ -942,7 +942,7 @@ struct net_device { ...@@ -942,7 +942,7 @@ struct net_device {
void *dsa_ptr; /* dsa specific data */ void *dsa_ptr; /* dsa specific data */
#endif #endif
void *atalk_ptr; /* AppleTalk link */ void *atalk_ptr; /* AppleTalk link */
void *ip_ptr; /* IPv4 specific data */ struct in_device __rcu *ip_ptr; /* IPv4 specific data */
void *dn_ptr; /* DECnet specific data */ void *dn_ptr; /* DECnet specific data */
void *ip6_ptr; /* IPv6 specific data */ void *ip6_ptr; /* IPv6 specific data */
void *ec_ptr; /* Econet specific data */ void *ec_ptr; /* Econet specific data */
......
...@@ -5286,7 +5286,7 @@ void netdev_run_todo(void) ...@@ -5286,7 +5286,7 @@ void netdev_run_todo(void)
/* paranoia */ /* paranoia */
BUG_ON(atomic_read(&dev->refcnt)); BUG_ON(atomic_read(&dev->refcnt));
WARN_ON(dev->ip_ptr); WARN_ON(rcu_dereference_raw(dev->ip_ptr));
WARN_ON(dev->ip6_ptr); WARN_ON(dev->ip6_ptr);
WARN_ON(dev->dn_ptr); WARN_ON(dev->dn_ptr);
......
...@@ -209,7 +209,7 @@ static void inetdev_destroy(struct in_device *in_dev) ...@@ -209,7 +209,7 @@ static void inetdev_destroy(struct in_device *in_dev)
inet_free_ifa(ifa); inet_free_ifa(ifa);
} }
dev->ip_ptr = NULL; rcu_assign_pointer(dev->ip_ptr, NULL);
devinet_sysctl_unregister(in_dev); devinet_sysctl_unregister(in_dev);
neigh_parms_release(&arp_tbl, in_dev->arp_parms); neigh_parms_release(&arp_tbl, in_dev->arp_parms);
...@@ -1059,7 +1059,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, ...@@ -1059,7 +1059,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
switch (event) { switch (event) {
case NETDEV_REGISTER: case NETDEV_REGISTER:
printk(KERN_DEBUG "inetdev_event: bug\n"); printk(KERN_DEBUG "inetdev_event: bug\n");
dev->ip_ptr = NULL; rcu_assign_pointer(dev->ip_ptr, NULL);
break; break;
case NETDEV_UP: case NETDEV_UP:
if (!inetdev_valid_mtu(dev->mtu)) if (!inetdev_valid_mtu(dev->mtu))
......
...@@ -724,7 +724,7 @@ static int vif_add(struct net *net, struct mr_table *mrt, ...@@ -724,7 +724,7 @@ static int vif_add(struct net *net, struct mr_table *mrt,
case 0: case 0:
if (vifc->vifc_flags == VIFF_USE_IFINDEX) { if (vifc->vifc_flags == VIFF_USE_IFINDEX) {
dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex); dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex);
if (dev && dev->ip_ptr == NULL) { if (dev && __in_dev_get_rtnl(dev) == NULL) {
dev_put(dev); dev_put(dev);
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
} }
......
...@@ -362,7 +362,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, ...@@ -362,7 +362,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
if (sdata->vif.type != NL80211_IFTYPE_STATION) if (sdata->vif.type != NL80211_IFTYPE_STATION)
return NOTIFY_DONE; return NOTIFY_DONE;
idev = sdata->dev->ip_ptr; idev = __in_dev_get_rtnl(sdata->dev);
if (!idev) if (!idev)
return NOTIFY_DONE; return NOTIFY_DONE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment