appletalk: Add proper locking around IPDDP routing table.
Signed-off-by: David S. Miller <davem@davemloft.net>hifive-unleashed-5.1
parent
385a154cac
commit
5615968a70
|
@ -39,6 +39,7 @@
|
||||||
static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
|
static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
|
||||||
|
|
||||||
static struct ipddp_route *ipddp_route_list;
|
static struct ipddp_route *ipddp_route_list;
|
||||||
|
static DEFINE_SPINLOCK(ipddp_route_lock);
|
||||||
|
|
||||||
#ifdef CONFIG_IPDDP_ENCAP
|
#ifdef CONFIG_IPDDP_ENCAP
|
||||||
static int ipddp_mode = IPDDP_ENCAP;
|
static int ipddp_mode = IPDDP_ENCAP;
|
||||||
|
@ -50,7 +51,7 @@ static int ipddp_mode = IPDDP_DECAP;
|
||||||
static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev);
|
static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev);
|
||||||
static int ipddp_create(struct ipddp_route *new_rt);
|
static int ipddp_create(struct ipddp_route *new_rt);
|
||||||
static int ipddp_delete(struct ipddp_route *rt);
|
static int ipddp_delete(struct ipddp_route *rt);
|
||||||
static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt);
|
static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt);
|
||||||
static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
|
static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
|
||||||
|
|
||||||
static const struct net_device_ops ipddp_netdev_ops = {
|
static const struct net_device_ops ipddp_netdev_ops = {
|
||||||
|
@ -119,6 +120,8 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
struct ipddp_route *rt;
|
struct ipddp_route *rt;
|
||||||
struct atalk_addr *our_addr;
|
struct atalk_addr *our_addr;
|
||||||
|
|
||||||
|
spin_lock(&ipddp_route_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find appropriate route to use, based only on IP number.
|
* Find appropriate route to use, based only on IP number.
|
||||||
*/
|
*/
|
||||||
|
@ -127,8 +130,10 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
if(rt->ip == paddr)
|
if(rt->ip == paddr)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(rt == NULL)
|
if(rt == NULL) {
|
||||||
|
spin_unlock(&ipddp_route_lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
our_addr = atalk_find_dev_addr(rt->dev);
|
our_addr = atalk_find_dev_addr(rt->dev);
|
||||||
|
|
||||||
|
@ -174,6 +179,8 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
|
if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
|
||||||
dev_kfree_skb(skb);
|
dev_kfree_skb(skb);
|
||||||
|
|
||||||
|
spin_unlock(&ipddp_route_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +203,9 @@ static int ipddp_create(struct ipddp_route *new_rt)
|
||||||
return -ENETUNREACH;
|
return -ENETUNREACH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ipddp_find_route(rt)) {
|
spin_lock_bh(&ipddp_route_lock);
|
||||||
|
if (__ipddp_find_route(rt)) {
|
||||||
|
spin_unlock_bh(&ipddp_route_lock);
|
||||||
kfree(rt);
|
kfree(rt);
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
}
|
}
|
||||||
|
@ -204,6 +213,8 @@ static int ipddp_create(struct ipddp_route *new_rt)
|
||||||
rt->next = ipddp_route_list;
|
rt->next = ipddp_route_list;
|
||||||
ipddp_route_list = rt;
|
ipddp_route_list = rt;
|
||||||
|
|
||||||
|
spin_unlock_bh(&ipddp_route_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,6 +227,7 @@ static int ipddp_delete(struct ipddp_route *rt)
|
||||||
struct ipddp_route **r = &ipddp_route_list;
|
struct ipddp_route **r = &ipddp_route_list;
|
||||||
struct ipddp_route *tmp;
|
struct ipddp_route *tmp;
|
||||||
|
|
||||||
|
spin_lock_bh(&ipddp_route_lock);
|
||||||
while((tmp = *r) != NULL)
|
while((tmp = *r) != NULL)
|
||||||
{
|
{
|
||||||
if(tmp->ip == rt->ip
|
if(tmp->ip == rt->ip
|
||||||
|
@ -223,19 +235,21 @@ static int ipddp_delete(struct ipddp_route *rt)
|
||||||
&& tmp->at.s_node == rt->at.s_node)
|
&& tmp->at.s_node == rt->at.s_node)
|
||||||
{
|
{
|
||||||
*r = tmp->next;
|
*r = tmp->next;
|
||||||
|
spin_unlock_bh(&ipddp_route_lock);
|
||||||
kfree(tmp);
|
kfree(tmp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
r = &tmp->next;
|
r = &tmp->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_unlock_bh(&ipddp_route_lock);
|
||||||
return (-ENOENT);
|
return (-ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find a routing entry, we only return a FULL match
|
* Find a routing entry, we only return a FULL match
|
||||||
*/
|
*/
|
||||||
static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt)
|
static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt)
|
||||||
{
|
{
|
||||||
struct ipddp_route *f;
|
struct ipddp_route *f;
|
||||||
|
|
||||||
|
@ -253,7 +267,7 @@ static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt)
|
||||||
static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||||
{
|
{
|
||||||
struct ipddp_route __user *rt = ifr->ifr_data;
|
struct ipddp_route __user *rt = ifr->ifr_data;
|
||||||
struct ipddp_route rcp;
|
struct ipddp_route rcp, rcp2, *rp;
|
||||||
|
|
||||||
if(!capable(CAP_NET_ADMIN))
|
if(!capable(CAP_NET_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
@ -267,9 +281,19 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||||
return (ipddp_create(&rcp));
|
return (ipddp_create(&rcp));
|
||||||
|
|
||||||
case SIOCFINDIPDDPRT:
|
case SIOCFINDIPDDPRT:
|
||||||
if(copy_to_user(rt, ipddp_find_route(&rcp), sizeof(struct ipddp_route)))
|
spin_lock_bh(&ipddp_route_lock);
|
||||||
return -EFAULT;
|
rp = __ipddp_find_route(&rcp);
|
||||||
return 0;
|
if (rp)
|
||||||
|
memcpy(&rcp2, rp, sizeof(rcp2));
|
||||||
|
spin_unlock_bh(&ipddp_route_lock);
|
||||||
|
|
||||||
|
if (rp) {
|
||||||
|
if (copy_to_user(rt, &rcp2,
|
||||||
|
sizeof(struct ipddp_route)))
|
||||||
|
return -EFAULT;
|
||||||
|
return 0;
|
||||||
|
} else
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
case SIOCDELIPDDPRT:
|
case SIOCDELIPDDPRT:
|
||||||
return (ipddp_delete(&rcp));
|
return (ipddp_delete(&rcp));
|
||||||
|
|
Loading…
Reference in New Issue