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: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
9e0064a545
commit
95ae6b228f
@@ -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)
|
|||||||
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)
|
|||||||
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 {
|
|||||||
* 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)
|
|||||||
|
|
||||||
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)
|
|||||||
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 @@
|
|||||||
#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)
|
|||||||
|
|
||||||
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)
|
|||||||
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 {
|
|||||||
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)
|
|||||||
|
|
||||||
/* 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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user