aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-05-27 19:56:47 -0400
committerDavid S. Miller <davem@davemloft.net>2009-05-27 19:56:47 -0400
commit5615968a70845157adaffc11062c997d045339ee (patch)
tree36958722da6bbcd2eaec9be90885190e9d96f4f7
parent385a154cac8763284f65cdfa25f6796c9eb1ca21 (diff)
appletalk: Add proper locking around IPDDP routing table.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/appletalk/ipddp.c40
1 files changed, 32 insertions, 8 deletions
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index f939e92fcf8a..9832b757f109 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -39,6 +39,7 @@
39static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n"; 39static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
40 40
41static struct ipddp_route *ipddp_route_list; 41static struct ipddp_route *ipddp_route_list;
42static DEFINE_SPINLOCK(ipddp_route_lock);
42 43
43#ifdef CONFIG_IPDDP_ENCAP 44#ifdef CONFIG_IPDDP_ENCAP
44static int ipddp_mode = IPDDP_ENCAP; 45static int ipddp_mode = IPDDP_ENCAP;
@@ -50,7 +51,7 @@ static int ipddp_mode = IPDDP_DECAP;
50static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev); 51static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev);
51static int ipddp_create(struct ipddp_route *new_rt); 52static int ipddp_create(struct ipddp_route *new_rt);
52static int ipddp_delete(struct ipddp_route *rt); 53static int ipddp_delete(struct ipddp_route *rt);
53static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt); 54static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt);
54static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); 55static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
55 56
56static const struct net_device_ops ipddp_netdev_ops = { 57static const struct net_device_ops ipddp_netdev_ops = {
@@ -119,6 +120,8 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
119 struct ipddp_route *rt; 120 struct ipddp_route *rt;
120 struct atalk_addr *our_addr; 121 struct atalk_addr *our_addr;
121 122
123 spin_lock(&ipddp_route_lock);
124
122 /* 125 /*
123 * Find appropriate route to use, based only on IP number. 126 * Find appropriate route to use, based only on IP number.
124 */ 127 */
@@ -127,8 +130,10 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
127 if(rt->ip == paddr) 130 if(rt->ip == paddr)
128 break; 131 break;
129 } 132 }
130 if(rt == NULL) 133 if(rt == NULL) {
134 spin_unlock(&ipddp_route_lock);
131 return 0; 135 return 0;
136 }
132 137
133 our_addr = atalk_find_dev_addr(rt->dev); 138 our_addr = atalk_find_dev_addr(rt->dev);
134 139
@@ -174,6 +179,8 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
174 if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) 179 if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
175 dev_kfree_skb(skb); 180 dev_kfree_skb(skb);
176 181
182 spin_unlock(&ipddp_route_lock);
183
177 return 0; 184 return 0;
178} 185}
179 186
@@ -196,7 +203,9 @@ static int ipddp_create(struct ipddp_route *new_rt)
196 return -ENETUNREACH; 203 return -ENETUNREACH;
197 } 204 }
198 205
199 if (ipddp_find_route(rt)) { 206 spin_lock_bh(&ipddp_route_lock);
207 if (__ipddp_find_route(rt)) {
208 spin_unlock_bh(&ipddp_route_lock);
200 kfree(rt); 209 kfree(rt);
201 return -EEXIST; 210 return -EEXIST;
202 } 211 }
@@ -204,6 +213,8 @@ static int ipddp_create(struct ipddp_route *new_rt)
204 rt->next = ipddp_route_list; 213 rt->next = ipddp_route_list;
205 ipddp_route_list = rt; 214 ipddp_route_list = rt;
206 215
216 spin_unlock_bh(&ipddp_route_lock);
217
207 return 0; 218 return 0;
208} 219}
209 220
@@ -216,6 +227,7 @@ static int ipddp_delete(struct ipddp_route *rt)
216 struct ipddp_route **r = &ipddp_route_list; 227 struct ipddp_route **r = &ipddp_route_list;
217 struct ipddp_route *tmp; 228 struct ipddp_route *tmp;
218 229
230 spin_lock_bh(&ipddp_route_lock);
219 while((tmp = *r) != NULL) 231 while((tmp = *r) != NULL)
220 { 232 {
221 if(tmp->ip == rt->ip 233 if(tmp->ip == rt->ip
@@ -223,19 +235,21 @@ static int ipddp_delete(struct ipddp_route *rt)
223 && tmp->at.s_node == rt->at.s_node) 235 && tmp->at.s_node == rt->at.s_node)
224 { 236 {
225 *r = tmp->next; 237 *r = tmp->next;
238 spin_unlock_bh(&ipddp_route_lock);
226 kfree(tmp); 239 kfree(tmp);
227 return 0; 240 return 0;
228 } 241 }
229 r = &tmp->next; 242 r = &tmp->next;
230 } 243 }
231 244
245 spin_unlock_bh(&ipddp_route_lock);
232 return (-ENOENT); 246 return (-ENOENT);
233} 247}
234 248
235/* 249/*
236 * Find a routing entry, we only return a FULL match 250 * Find a routing entry, we only return a FULL match
237 */ 251 */
238static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt) 252static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt)
239{ 253{
240 struct ipddp_route *f; 254 struct ipddp_route *f;
241 255
@@ -253,7 +267,7 @@ static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt)
253static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 267static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
254{ 268{
255 struct ipddp_route __user *rt = ifr->ifr_data; 269 struct ipddp_route __user *rt = ifr->ifr_data;
256 struct ipddp_route rcp; 270 struct ipddp_route rcp, rcp2, *rp;
257 271
258 if(!capable(CAP_NET_ADMIN)) 272 if(!capable(CAP_NET_ADMIN))
259 return -EPERM; 273 return -EPERM;
@@ -267,9 +281,19 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
267 return (ipddp_create(&rcp)); 281 return (ipddp_create(&rcp));
268 282
269 case SIOCFINDIPDDPRT: 283 case SIOCFINDIPDDPRT:
270 if(copy_to_user(rt, ipddp_find_route(&rcp), sizeof(struct ipddp_route))) 284 spin_lock_bh(&ipddp_route_lock);
271 return -EFAULT; 285 rp = __ipddp_find_route(&rcp);
272 return 0; 286 if (rp)
287 memcpy(&rcp2, rp, sizeof(rcp2));
288 spin_unlock_bh(&ipddp_route_lock);
289
290 if (rp) {
291 if (copy_to_user(rt, &rcp2,
292 sizeof(struct ipddp_route)))
293 return -EFAULT;
294 return 0;
295 } else
296 return -ENOENT;
273 297
274 case SIOCDELIPDDPRT: 298 case SIOCDELIPDDPRT:
275 return (ipddp_delete(&rcp)); 299 return (ipddp_delete(&rcp));