[IPV6] SIT: Fix locking issues in PRL management.

To protect PRL list, use ipip6_lock.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
This commit is contained in:
YOSHIFUJI Hideaki 2008-03-22 17:42:57 +09:00
parent fadf6bf060
commit 3fcfa12904

View File

@ -198,7 +198,7 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int
} }
static struct ip_tunnel_prl_entry * 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; 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) ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
{ {
struct ip_tunnel_prl_entry *p; struct ip_tunnel_prl_entry *p;
int err = 0;
write_lock(&ipip6_lock);
for (p = t->prl; p; p = p->next) { for (p = t->prl; p; p = p->next) {
if (p->entry.addr == a->addr) { if (p->entry.addr == a->addr) {
if (chg) { if (chg)
p->entry = *a; goto update;
return 0; err = -EEXIST;
} goto out;
return -EEXIST;
} }
} }
if (chg) if (chg) {
return -ENXIO; err = -ENXIO;
goto out;
}
p = kzalloc(sizeof(struct ip_tunnel_prl_entry), GFP_KERNEL); p = kzalloc(sizeof(struct ip_tunnel_prl_entry), GFP_KERNEL);
if (!p) if (!p) {
return -ENOBUFS; err = -ENOBUFS;
goto out;
}
p->entry = *a;
p->next = t->prl; p->next = t->prl;
t->prl = p; t->prl = p;
return 0; update:
p->entry = *a;
out:
write_unlock(&ipip6_lock);
return err;
} }
static int static int
ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
{ {
struct ip_tunnel_prl_entry *x, **p; struct ip_tunnel_prl_entry *x, **p;
int err = 0;
write_lock(&ipip6_lock);
if (a) { if (a) {
for (p = &t->prl; *p; p = &(*p)->next) { 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; x = *p;
*p = x->next; *p = x->next;
kfree(x); kfree(x);
return 0; goto out;
} }
} }
return -ENXIO; err = -ENXIO;
} else { } else {
while (t->prl) { while (t->prl) {
x = t->prl; x = t->prl;
@ -259,6 +271,8 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
kfree(x); kfree(x);
} }
} }
out:
write_unlock(&ipip6_lock);
return 0; return 0;
} }
@ -290,9 +304,11 @@ ipip6_onlink(struct in6_addr *addr, struct net_device *dev)
static int static int
isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) 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; int ok = 1;
read_lock(&ipip6_lock);
p = __ipip6_tunnel_locate_prl(t, iph->saddr);
if (p) { if (p) {
if (p->entry.flags & PRL_DEFAULT) if (p->entry.flags & PRL_DEFAULT)
skb->ndisc_nodetype = NDISC_NODETYPE_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 else
ok = 0; ok = 0;
} }
read_unlock(&ipip6_lock);
return ok; return ok;
} }
@ -895,12 +912,10 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
if (!(t = netdev_priv(dev))) if (!(t = netdev_priv(dev)))
goto done; goto done;
ipip6_tunnel_unlink(t);
if (cmd == SIOCDELPRL) if (cmd == SIOCDELPRL)
err = ipip6_tunnel_del_prl(t, &prl); err = ipip6_tunnel_del_prl(t, &prl);
else else
err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL);
ipip6_tunnel_link(t);
netdev_state_change(dev); netdev_state_change(dev);
break; break;