summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-03-22 17:42:57 +0900
committerYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-04-03 10:05:59 +0900
commit3fcfa12904e83cc291cf2b7b05ff2530068920a4 (patch)
treeec1230028db764a9a6a169050bdcd2f7a8793e41 /net
parentfadf6bf06069138f8e97c9a963be38348ba2708b (diff)
downloadlinux-3fcfa12904e83cc291cf2b7b05ff2530068920a4.tar.gz
linux-3fcfa12904e83cc291cf2b7b05ff2530068920a4.tar.bz2
linux-3fcfa12904e83cc291cf2b7b05ff2530068920a4.zip
[IPV6] SIT: Fix locking issues in PRL management.
To protect PRL list, use ipip6_lock. Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/sit.c49
1 files changed, 32 insertions, 17 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 4786419ade0e..ee0cc2851691 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -198,7 +198,7 @@ failed:
}
static struct ip_tunnel_prl_entry *
-ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr)
+__ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr)
{
struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL;
@@ -213,34 +213,46 @@ static int
ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
{
struct ip_tunnel_prl_entry *p;
+ int err = 0;
+
+ write_lock(&ipip6_lock);
for (p = t->prl; p; p = p->next) {
if (p->entry.addr == a->addr) {
- if (chg) {
- p->entry = *a;
- return 0;
- }
- return -EEXIST;
+ if (chg)
+ goto update;
+ err = -EEXIST;
+ goto out;
}
}
- if (chg)
- return -ENXIO;
+ if (chg) {
+ err = -ENXIO;
+ goto out;
+ }
p = kzalloc(sizeof(struct ip_tunnel_prl_entry), GFP_KERNEL);
- if (!p)
- return -ENOBUFS;
+ if (!p) {
+ err = -ENOBUFS;
+ goto out;
+ }
- p->entry = *a;
p->next = t->prl;
t->prl = p;
- return 0;
+update:
+ p->entry = *a;
+out:
+ write_unlock(&ipip6_lock);
+ return err;
}
static int
ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
{
struct ip_tunnel_prl_entry *x, **p;
+ int err = 0;
+
+ write_lock(&ipip6_lock);
if (a) {
for (p = &t->prl; *p; p = &(*p)->next) {
@@ -248,10 +260,10 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
x = *p;
*p = x->next;
kfree(x);
- return 0;
+ goto out;
}
}
- return -ENXIO;
+ err = -ENXIO;
} else {
while (t->prl) {
x = t->prl;
@@ -259,6 +271,8 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
kfree(x);
}
}
+out:
+ write_unlock(&ipip6_lock);
return 0;
}
@@ -290,9 +304,11 @@ ipip6_onlink(struct in6_addr *addr, struct net_device *dev)
static int
isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
{
- struct ip_tunnel_prl_entry *p = ipip6_tunnel_locate_prl(t, iph->saddr);
+ struct ip_tunnel_prl_entry *p;
int ok = 1;
+ read_lock(&ipip6_lock);
+ p = __ipip6_tunnel_locate_prl(t, iph->saddr);
if (p) {
if (p->entry.flags & PRL_DEFAULT)
skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT;
@@ -307,6 +323,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
else
ok = 0;
}
+ read_unlock(&ipip6_lock);
return ok;
}
@@ -895,12 +912,10 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
if (!(t = netdev_priv(dev)))
goto done;
- ipip6_tunnel_unlink(t);
if (cmd == SIOCDELPRL)
err = ipip6_tunnel_del_prl(t, &prl);
else
err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL);
- ipip6_tunnel_link(t);
netdev_state_change(dev);
break;