diff options
Diffstat (limited to 'drivers/net/appletalk')
-rw-r--r-- | drivers/net/appletalk/ipddp.c | 43 |
1 files changed, 34 insertions, 9 deletions
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index da64ba88d7f8..78cea5e80b1d 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c | |||
@@ -39,6 +39,7 @@ | |||
39 | static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n"; | 39 | static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n"; |
40 | 40 | ||
41 | static struct ipddp_route *ipddp_route_list; | 41 | static struct ipddp_route *ipddp_route_list; |
42 | static DEFINE_SPINLOCK(ipddp_route_lock); | ||
42 | 43 | ||
43 | #ifdef CONFIG_IPDDP_ENCAP | 44 | #ifdef CONFIG_IPDDP_ENCAP |
44 | static int ipddp_mode = IPDDP_ENCAP; | 45 | static int ipddp_mode = IPDDP_ENCAP; |
@@ -50,7 +51,7 @@ static int ipddp_mode = IPDDP_DECAP; | |||
50 | static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev); | 51 | static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev); |
51 | static int ipddp_create(struct ipddp_route *new_rt); | 52 | static int ipddp_create(struct ipddp_route *new_rt); |
52 | static int ipddp_delete(struct ipddp_route *rt); | 53 | static int ipddp_delete(struct ipddp_route *rt); |
53 | static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt); | 54 | static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt); |
54 | static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); | 55 | static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); |
55 | 56 | ||
56 | static const struct net_device_ops ipddp_netdev_ops = { | 57 | static const struct net_device_ops ipddp_netdev_ops = { |
@@ -71,6 +72,7 @@ static struct net_device * __init ipddp_init(void) | |||
71 | if (!dev) | 72 | if (!dev) |
72 | return ERR_PTR(-ENOMEM); | 73 | return ERR_PTR(-ENOMEM); |
73 | 74 | ||
75 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | ||
74 | strcpy(dev->name, "ipddp%d"); | 76 | strcpy(dev->name, "ipddp%d"); |
75 | 77 | ||
76 | if (version_printed++ == 0) | 78 | if (version_printed++ == 0) |
@@ -113,11 +115,13 @@ static struct net_device * __init ipddp_init(void) | |||
113 | */ | 115 | */ |
114 | static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) | 116 | static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) |
115 | { | 117 | { |
116 | __be32 paddr = ((struct rtable*)skb->dst)->rt_gateway; | 118 | __be32 paddr = skb_rtable(skb)->rt_gateway; |
117 | struct ddpehdr *ddp; | 119 | struct ddpehdr *ddp; |
118 | struct ipddp_route *rt; | 120 | struct ipddp_route *rt; |
119 | struct atalk_addr *our_addr; | 121 | struct atalk_addr *our_addr; |
120 | 122 | ||
123 | spin_lock(&ipddp_route_lock); | ||
124 | |||
121 | /* | 125 | /* |
122 | * Find appropriate route to use, based only on IP number. | 126 | * Find appropriate route to use, based only on IP number. |
123 | */ | 127 | */ |
@@ -126,8 +130,10 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) | |||
126 | if(rt->ip == paddr) | 130 | if(rt->ip == paddr) |
127 | break; | 131 | break; |
128 | } | 132 | } |
129 | if(rt == NULL) | 133 | if(rt == NULL) { |
134 | spin_unlock(&ipddp_route_lock); | ||
130 | return 0; | 135 | return 0; |
136 | } | ||
131 | 137 | ||
132 | our_addr = atalk_find_dev_addr(rt->dev); | 138 | our_addr = atalk_find_dev_addr(rt->dev); |
133 | 139 | ||
@@ -173,6 +179,8 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) | |||
173 | if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) | 179 | if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) |
174 | dev_kfree_skb(skb); | 180 | dev_kfree_skb(skb); |
175 | 181 | ||
182 | spin_unlock(&ipddp_route_lock); | ||
183 | |||
176 | return 0; | 184 | return 0; |
177 | } | 185 | } |
178 | 186 | ||
@@ -195,7 +203,9 @@ static int ipddp_create(struct ipddp_route *new_rt) | |||
195 | return -ENETUNREACH; | 203 | return -ENETUNREACH; |
196 | } | 204 | } |
197 | 205 | ||
198 | 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); | ||
199 | kfree(rt); | 209 | kfree(rt); |
200 | return -EEXIST; | 210 | return -EEXIST; |
201 | } | 211 | } |
@@ -203,6 +213,8 @@ static int ipddp_create(struct ipddp_route *new_rt) | |||
203 | rt->next = ipddp_route_list; | 213 | rt->next = ipddp_route_list; |
204 | ipddp_route_list = rt; | 214 | ipddp_route_list = rt; |
205 | 215 | ||
216 | spin_unlock_bh(&ipddp_route_lock); | ||
217 | |||
206 | return 0; | 218 | return 0; |
207 | } | 219 | } |
208 | 220 | ||
@@ -215,6 +227,7 @@ static int ipddp_delete(struct ipddp_route *rt) | |||
215 | struct ipddp_route **r = &ipddp_route_list; | 227 | struct ipddp_route **r = &ipddp_route_list; |
216 | struct ipddp_route *tmp; | 228 | struct ipddp_route *tmp; |
217 | 229 | ||
230 | spin_lock_bh(&ipddp_route_lock); | ||
218 | while((tmp = *r) != NULL) | 231 | while((tmp = *r) != NULL) |
219 | { | 232 | { |
220 | if(tmp->ip == rt->ip | 233 | if(tmp->ip == rt->ip |
@@ -222,19 +235,21 @@ static int ipddp_delete(struct ipddp_route *rt) | |||
222 | && tmp->at.s_node == rt->at.s_node) | 235 | && tmp->at.s_node == rt->at.s_node) |
223 | { | 236 | { |
224 | *r = tmp->next; | 237 | *r = tmp->next; |
238 | spin_unlock_bh(&ipddp_route_lock); | ||
225 | kfree(tmp); | 239 | kfree(tmp); |
226 | return 0; | 240 | return 0; |
227 | } | 241 | } |
228 | r = &tmp->next; | 242 | r = &tmp->next; |
229 | } | 243 | } |
230 | 244 | ||
245 | spin_unlock_bh(&ipddp_route_lock); | ||
231 | return (-ENOENT); | 246 | return (-ENOENT); |
232 | } | 247 | } |
233 | 248 | ||
234 | /* | 249 | /* |
235 | * Find a routing entry, we only return a FULL match | 250 | * Find a routing entry, we only return a FULL match |
236 | */ | 251 | */ |
237 | static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt) | 252 | static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt) |
238 | { | 253 | { |
239 | struct ipddp_route *f; | 254 | struct ipddp_route *f; |
240 | 255 | ||
@@ -252,7 +267,7 @@ static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt) | |||
252 | static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | 267 | static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
253 | { | 268 | { |
254 | struct ipddp_route __user *rt = ifr->ifr_data; | 269 | struct ipddp_route __user *rt = ifr->ifr_data; |
255 | struct ipddp_route rcp; | 270 | struct ipddp_route rcp, rcp2, *rp; |
256 | 271 | ||
257 | if(!capable(CAP_NET_ADMIN)) | 272 | if(!capable(CAP_NET_ADMIN)) |
258 | return -EPERM; | 273 | return -EPERM; |
@@ -266,9 +281,19 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
266 | return (ipddp_create(&rcp)); | 281 | return (ipddp_create(&rcp)); |
267 | 282 | ||
268 | case SIOCFINDIPDDPRT: | 283 | case SIOCFINDIPDDPRT: |
269 | if(copy_to_user(rt, ipddp_find_route(&rcp), sizeof(struct ipddp_route))) | 284 | spin_lock_bh(&ipddp_route_lock); |
270 | return -EFAULT; | 285 | rp = __ipddp_find_route(&rcp); |
271 | 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; | ||
272 | 297 | ||
273 | case SIOCDELIPDDPRT: | 298 | case SIOCDELIPDDPRT: |
274 | return (ipddp_delete(&rcp)); | 299 | return (ipddp_delete(&rcp)); |