diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-03-22 04:42:57 -0400 |
---|---|---|
committer | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-04-02 21:05:59 -0400 |
commit | 3fcfa12904e83cc291cf2b7b05ff2530068920a4 (patch) | |
tree | ec1230028db764a9a6a169050bdcd2f7a8793e41 /net/ipv6/sit.c | |
parent | fadf6bf06069138f8e97c9a963be38348ba2708b (diff) |
[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/ipv6/sit.c')
-rw-r--r-- | net/ipv6/sit.c | 49 |
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: | |||
198 | } | 198 | } |
199 | 199 | ||
200 | static struct ip_tunnel_prl_entry * | 200 | static struct ip_tunnel_prl_entry * |
201 | ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) | 201 | __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) |
202 | { | 202 | { |
203 | struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL; | 203 | struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL; |
204 | 204 | ||
@@ -213,34 +213,46 @@ static int | |||
213 | ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) | 213 | ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) |
214 | { | 214 | { |
215 | struct ip_tunnel_prl_entry *p; | 215 | struct ip_tunnel_prl_entry *p; |
216 | int err = 0; | ||
217 | |||
218 | write_lock(&ipip6_lock); | ||
216 | 219 | ||
217 | for (p = t->prl; p; p = p->next) { | 220 | for (p = t->prl; p; p = p->next) { |
218 | if (p->entry.addr == a->addr) { | 221 | if (p->entry.addr == a->addr) { |
219 | if (chg) { | 222 | if (chg) |
220 | p->entry = *a; | 223 | goto update; |
221 | return 0; | 224 | err = -EEXIST; |
222 | } | 225 | goto out; |
223 | return -EEXIST; | ||
224 | } | 226 | } |
225 | } | 227 | } |
226 | 228 | ||
227 | if (chg) | 229 | if (chg) { |
228 | return -ENXIO; | 230 | err = -ENXIO; |
231 | goto out; | ||
232 | } | ||
229 | 233 | ||
230 | p = kzalloc(sizeof(struct ip_tunnel_prl_entry), GFP_KERNEL); | 234 | p = kzalloc(sizeof(struct ip_tunnel_prl_entry), GFP_KERNEL); |
231 | if (!p) | 235 | if (!p) { |
232 | return -ENOBUFS; | 236 | err = -ENOBUFS; |
237 | goto out; | ||
238 | } | ||
233 | 239 | ||
234 | p->entry = *a; | ||
235 | p->next = t->prl; | 240 | p->next = t->prl; |
236 | t->prl = p; | 241 | t->prl = p; |
237 | return 0; | 242 | update: |
243 | p->entry = *a; | ||
244 | out: | ||
245 | write_unlock(&ipip6_lock); | ||
246 | return err; | ||
238 | } | 247 | } |
239 | 248 | ||
240 | static int | 249 | static int |
241 | ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) | 250 | ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) |
242 | { | 251 | { |
243 | struct ip_tunnel_prl_entry *x, **p; | 252 | struct ip_tunnel_prl_entry *x, **p; |
253 | int err = 0; | ||
254 | |||
255 | write_lock(&ipip6_lock); | ||
244 | 256 | ||
245 | if (a) { | 257 | if (a) { |
246 | for (p = &t->prl; *p; p = &(*p)->next) { | 258 | 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) | |||
248 | x = *p; | 260 | x = *p; |
249 | *p = x->next; | 261 | *p = x->next; |
250 | kfree(x); | 262 | kfree(x); |
251 | return 0; | 263 | goto out; |
252 | } | 264 | } |
253 | } | 265 | } |
254 | return -ENXIO; | 266 | err = -ENXIO; |
255 | } else { | 267 | } else { |
256 | while (t->prl) { | 268 | while (t->prl) { |
257 | x = t->prl; | 269 | x = t->prl; |
@@ -259,6 +271,8 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) | |||
259 | kfree(x); | 271 | kfree(x); |
260 | } | 272 | } |
261 | } | 273 | } |
274 | out: | ||
275 | write_unlock(&ipip6_lock); | ||
262 | return 0; | 276 | return 0; |
263 | } | 277 | } |
264 | 278 | ||
@@ -290,9 +304,11 @@ ipip6_onlink(struct in6_addr *addr, struct net_device *dev) | |||
290 | static int | 304 | static int |
291 | isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) | 305 | isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) |
292 | { | 306 | { |
293 | struct ip_tunnel_prl_entry *p = ipip6_tunnel_locate_prl(t, iph->saddr); | 307 | struct ip_tunnel_prl_entry *p; |
294 | int ok = 1; | 308 | int ok = 1; |
295 | 309 | ||
310 | read_lock(&ipip6_lock); | ||
311 | p = __ipip6_tunnel_locate_prl(t, iph->saddr); | ||
296 | if (p) { | 312 | if (p) { |
297 | if (p->entry.flags & PRL_DEFAULT) | 313 | if (p->entry.flags & PRL_DEFAULT) |
298 | skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT; | 314 | skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT; |
@@ -307,6 +323,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) | |||
307 | else | 323 | else |
308 | ok = 0; | 324 | ok = 0; |
309 | } | 325 | } |
326 | read_unlock(&ipip6_lock); | ||
310 | return ok; | 327 | return ok; |
311 | } | 328 | } |
312 | 329 | ||
@@ -895,12 +912,10 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
895 | if (!(t = netdev_priv(dev))) | 912 | if (!(t = netdev_priv(dev))) |
896 | goto done; | 913 | goto done; |
897 | 914 | ||
898 | ipip6_tunnel_unlink(t); | ||
899 | if (cmd == SIOCDELPRL) | 915 | if (cmd == SIOCDELPRL) |
900 | err = ipip6_tunnel_del_prl(t, &prl); | 916 | err = ipip6_tunnel_del_prl(t, &prl); |
901 | else | 917 | else |
902 | err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); | 918 | err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); |
903 | ipip6_tunnel_link(t); | ||
904 | netdev_state_change(dev); | 919 | netdev_state_change(dev); |
905 | break; | 920 | break; |
906 | 921 | ||