1 /* net/atm/resources.c - Staticly allocated resources */
2 
3 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
4 
5 
6 #include <linux/config.h>
7 #include <linux/ctype.h>
8 #include <linux/string.h>
9 #include <linux/atmdev.h>
10 #include <linux/sonet.h>
11 #include <linux/kernel.h> /* for barrier */
12 #include <linux/module.h>
13 #include <linux/bitops.h>
14 #include <net/sock.h>	 /* for struct sock */
15 #include <asm/segment.h> /* for get_fs_long and put_fs_long */
16 
17 #include "common.h"
18 #include "resources.h"
19 #include "addr.h"
20 
21 
22 LIST_HEAD(atm_devs);
23 spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
24 
25 
__alloc_atm_dev(const char * type)26 static struct atm_dev *__alloc_atm_dev(const char *type)
27 {
28 	struct atm_dev *dev;
29 
30 	dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
31 	if (!dev)
32 		return NULL;
33 	memset(dev, 0, sizeof(*dev));
34 	dev->type = type;
35 	dev->signal = ATM_PHY_SIG_UNKNOWN;
36 	dev->link_rate = ATM_OC3_PCR;
37 	spin_lock_init(&dev->lock);
38 
39 	return dev;
40 }
41 
42 
__free_atm_dev(struct atm_dev * dev)43 static void __free_atm_dev(struct atm_dev *dev)
44 {
45 	kfree(dev);
46 }
47 
__atm_dev_lookup(int number)48 static struct atm_dev *__atm_dev_lookup(int number)
49 {
50 	struct atm_dev *dev;
51 	struct list_head *p;
52 
53 	list_for_each(p, &atm_devs) {
54 		dev = list_entry(p, struct atm_dev, dev_list);
55 		if ((dev->ops) && (dev->number == number)) {
56 			atm_dev_hold(dev);
57 			return dev;
58 		}
59 	}
60 	return NULL;
61 }
62 
atm_dev_lookup(int number)63 struct atm_dev *atm_dev_lookup(int number)
64 {
65 	struct atm_dev *dev;
66 
67 	spin_lock(&atm_dev_lock);
68 	dev = __atm_dev_lookup(number);
69 	spin_unlock(&atm_dev_lock);
70 	return dev;
71 }
72 
atm_dev_register(const char * type,const struct atmdev_ops * ops,int number,atm_dev_flags_t * flags)73 struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
74 				 int number, atm_dev_flags_t *flags)
75 {
76 	struct atm_dev *dev, *inuse;
77 
78 
79 	dev = __alloc_atm_dev(type);
80 	if (!dev) {
81 		printk(KERN_ERR "atm_dev_register: no space for dev %s\n",
82 		    type);
83 		return NULL;
84 	}
85 	spin_lock(&atm_dev_lock);
86 	if (number != -1) {
87 		if ((inuse = __atm_dev_lookup(number))) {
88 			atm_dev_put(inuse);
89 			spin_unlock(&atm_dev_lock);
90 			__free_atm_dev(dev);
91 			return NULL;
92 		}
93 		dev->number = number;
94 	} else {
95 		dev->number = 0;
96 		while ((inuse = __atm_dev_lookup(dev->number))) {
97 			atm_dev_put(inuse);
98 			dev->number++;
99 		}
100 	}
101 
102 	dev->ops = ops;
103 	if (flags)
104 		dev->flags = *flags;
105 	else
106 		memset(&dev->flags, 0, sizeof(dev->flags));
107 	memset(&dev->stats, 0, sizeof(dev->stats));
108 	atomic_set(&dev->refcnt, 1);
109 	list_add_tail(&dev->dev_list, &atm_devs);
110 	spin_unlock(&atm_dev_lock);
111 
112 #ifdef CONFIG_PROC_FS
113 	if (ops->proc_read) {
114 		if (atm_proc_dev_register(dev) < 0) {
115 			printk(KERN_ERR "atm_dev_register: "
116 			       "atm_proc_dev_register failed for dev %s\n",
117 			       type);
118 			spin_lock(&atm_dev_lock);
119 			list_del(&dev->dev_list);
120 			spin_unlock(&atm_dev_lock);
121 			__free_atm_dev(dev);
122 			return NULL;
123 		}
124 	}
125 #endif
126 
127 	return dev;
128 }
129 
130 
atm_dev_deregister(struct atm_dev * dev)131 void atm_dev_deregister(struct atm_dev *dev)
132 {
133 	unsigned long warning_time;
134 
135 #ifdef CONFIG_PROC_FS
136 	if (dev->ops->proc_read)
137 		atm_proc_dev_deregister(dev);
138 #endif
139 	spin_lock(&atm_dev_lock);
140 	list_del(&dev->dev_list);
141 	spin_unlock(&atm_dev_lock);
142 
143 	warning_time = jiffies;
144 	while (atomic_read(&dev->refcnt) != 1) {
145 		current->state = TASK_INTERRUPTIBLE;
146 		schedule_timeout(HZ / 4);
147 		current->state = TASK_RUNNING;
148 		if ((jiffies - warning_time) > 10 * HZ) {
149 			printk(KERN_EMERG "atm_dev_deregister: waiting for "
150 			       "dev %d to become free. Usage count = %d\n",
151 			       dev->number, atomic_read(&dev->refcnt));
152 			warning_time = jiffies;
153 		}
154 	}
155 
156 	__free_atm_dev(dev);
157 }
158 
shutdown_atm_dev(struct atm_dev * dev)159 void shutdown_atm_dev(struct atm_dev *dev)
160 {
161 	if (atomic_read(&dev->refcnt) > 1) {
162 		set_bit(ATM_DF_CLOSE, &dev->flags);
163 		return;
164 	}
165 	if (dev->ops->dev_close)
166 		dev->ops->dev_close(dev);
167 	atm_dev_deregister(dev);
168 }
169 
170 
copy_aal_stats(struct k_atm_aal_stats * from,struct atm_aal_stats * to)171 static void copy_aal_stats(struct k_atm_aal_stats *from,
172     struct atm_aal_stats *to)
173 {
174 #define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
175 	__AAL_STAT_ITEMS
176 #undef __HANDLE_ITEM
177 }
178 
179 
subtract_aal_stats(struct k_atm_aal_stats * from,struct atm_aal_stats * to)180 static void subtract_aal_stats(struct k_atm_aal_stats *from,
181     struct atm_aal_stats *to)
182 {
183 #define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i)
184 	__AAL_STAT_ITEMS
185 #undef __HANDLE_ITEM
186 }
187 
188 
fetch_stats(struct atm_dev * dev,struct atm_dev_stats * arg,int zero)189 static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats *arg, int zero)
190 {
191 	struct atm_dev_stats tmp;
192 	int error = 0;
193 
194 	copy_aal_stats(&dev->stats.aal0, &tmp.aal0);
195 	copy_aal_stats(&dev->stats.aal34, &tmp.aal34);
196 	copy_aal_stats(&dev->stats.aal5, &tmp.aal5);
197 	if (arg)
198 		error = copy_to_user(arg, &tmp, sizeof(tmp));
199 	if (zero && !error) {
200 		subtract_aal_stats(&dev->stats.aal0, &tmp.aal0);
201 		subtract_aal_stats(&dev->stats.aal34, &tmp.aal34);
202 		subtract_aal_stats(&dev->stats.aal5, &tmp.aal5);
203 	}
204 	return error ? -EFAULT : 0;
205 }
206 
207 
atm_dev_ioctl(unsigned int cmd,unsigned long arg)208 int atm_dev_ioctl(unsigned int cmd, unsigned long arg)
209 {
210 	void *buf;
211 	int error = 0, len, number, size = 0;
212 	struct atm_dev *dev;
213 
214 	if (cmd == ATM_GETNAMES) {
215 		int *tmp_buf, *tmp_bufp;
216 		struct list_head *p;
217 		/*
218 		 * ATM_GETNAMES is a special case: it doesn't require a
219 		 * device number argument
220 		 */
221 		if (get_user(buf, &((struct atm_iobuf *) arg)->buffer))
222 			return -EFAULT;
223 		if (get_user(len, &((struct atm_iobuf *) arg)->length))
224 			return -EFAULT;
225 		spin_lock(&atm_dev_lock);
226 		list_for_each(p, &atm_devs)
227 			size += sizeof(int);
228 		if (size > len) {
229 			spin_unlock(&atm_dev_lock);
230 			return -E2BIG;
231 		}
232 		tmp_buf = tmp_bufp = kmalloc(size, GFP_ATOMIC);
233 		if (!tmp_buf) {
234 			spin_unlock(&atm_dev_lock);
235 			return -ENOMEM;
236 		}
237 		list_for_each(p, &atm_devs) {
238 			dev = list_entry(p, struct atm_dev, dev_list);
239 			*tmp_bufp++ = dev->number;
240 		}
241 		spin_unlock(&atm_dev_lock);
242 	        error = (copy_to_user(buf, tmp_buf, size) ||
243 				put_user(size, &((struct atm_iobuf *) arg)->length))
244 					? -EFAULT : 0;
245 		kfree(tmp_buf);
246 		return error;
247 	}
248 
249 	if (get_user(buf, &((struct atmif_sioc *) arg)->arg))
250 		return -EFAULT;
251 	if (get_user(len, &((struct atmif_sioc *) arg)->length))
252 		return -EFAULT;
253 	if (get_user(number, &((struct atmif_sioc *) arg)->number))
254 		return -EFAULT;
255 
256 	if (!(dev = atm_dev_lookup(number)))
257 		return -ENODEV;
258 
259 	switch (cmd) {
260 		case ATM_GETTYPE:
261 			size = strlen(dev->type) + 1;
262 			if (copy_to_user(buf, dev->type, size)) {
263 				error = -EFAULT;
264 				goto done;
265 			}
266 			break;
267 		case ATM_GETESI:
268 			size = ESI_LEN;
269 			if (copy_to_user(buf, dev->esi, size)) {
270 				error = -EFAULT;
271 				goto done;
272 			}
273 			break;
274 		case ATM_SETESI:
275 			{
276 				int i;
277 
278 				for (i = 0; i < ESI_LEN; i++)
279 					if (dev->esi[i]) {
280 						error = -EEXIST;
281 						goto done;
282 					}
283 			}
284 			/* fall through */
285 		case ATM_SETESIF:
286 			{
287 				unsigned char esi[ESI_LEN];
288 
289 				if (!capable(CAP_NET_ADMIN)) {
290 					error = -EPERM;
291 					goto done;
292 				}
293 				if (copy_from_user(esi, buf, ESI_LEN)) {
294 					error = -EFAULT;
295 					goto done;
296 				}
297 				memcpy(dev->esi, esi, ESI_LEN);
298 				error =  ESI_LEN;
299 				goto done;
300 			}
301 		case ATM_GETSTATZ:
302 			if (!capable(CAP_NET_ADMIN)) {
303 				error = -EPERM;
304 				goto done;
305 			}
306 			/* fall through */
307 		case ATM_GETSTAT:
308 			size = sizeof(struct atm_dev_stats);
309 			error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ);
310 			if (error)
311 				goto done;
312 			break;
313 		case ATM_GETCIRANGE:
314 			size = sizeof(struct atm_cirange);
315 			if (copy_to_user(buf, &dev->ci_range, size)) {
316 				error = -EFAULT;
317 				goto done;
318 			}
319 			break;
320 		case ATM_GETLINKRATE:
321 			size = sizeof(int);
322 			if (copy_to_user(buf, &dev->link_rate, size)) {
323 				error = -EFAULT;
324 				goto done;
325 			}
326 			break;
327 		case ATM_RSTADDR:
328 			if (!capable(CAP_NET_ADMIN)) {
329 				error = -EPERM;
330 				goto done;
331 			}
332 			atm_reset_addr(dev);
333 			break;
334 		case ATM_ADDADDR:
335 		case ATM_DELADDR:
336 			if (!capable(CAP_NET_ADMIN)) {
337 				error = -EPERM;
338 				goto done;
339 			}
340 			{
341 				struct sockaddr_atmsvc addr;
342 
343 				if (copy_from_user(&addr, buf, sizeof(addr))) {
344 					error = -EFAULT;
345 					goto done;
346 				}
347 				if (cmd == ATM_ADDADDR)
348 					error = atm_add_addr(dev, &addr);
349 				else
350 					error = atm_del_addr(dev, &addr);
351 				goto done;
352 			}
353 		case ATM_GETADDR:
354 			error = atm_get_addr(dev, buf, len);
355 			if (error < 0)
356 				goto done;
357 			size = error;
358 			/* write back size even if it's zero */
359 			goto write_size;
360 		case ATM_SETLOOP:
361 			if (__ATM_LM_XTRMT((int) (long) buf) &&
362 			    __ATM_LM_XTLOC((int) (long) buf) >
363 			    __ATM_LM_XTRMT((int) (long) buf)) {
364 				error = -EINVAL;
365 				goto done;
366 			}
367 			/* fall through */
368 		case ATM_SETCIRANGE:
369 		case SONET_GETSTATZ:
370 		case SONET_SETDIAG:
371 		case SONET_CLRDIAG:
372 		case SONET_SETFRAMING:
373 			if (!capable(CAP_NET_ADMIN)) {
374 				error = -EPERM;
375 				goto done;
376 			}
377 			/* fall through */
378 		default:
379 			if (!dev->ops->ioctl) {
380 				error = -EINVAL;
381 				goto done;
382 			}
383 			size = dev->ops->ioctl(dev, cmd, buf);
384 			if (size < 0) {
385 				error = (size == -ENOIOCTLCMD ? -EINVAL : size);
386 				goto done;
387 			}
388 	}
389 
390 	if (size) {
391 write_size:
392 		error = put_user(size,
393 			  &((struct atmif_sioc *) arg)->length)
394 			  ? -EFAULT : 0;
395 	}
396 done:
397 	atm_dev_put(dev);
398 	return error;
399 }
400 
401 
402 EXPORT_SYMBOL(atm_dev_register);
403 EXPORT_SYMBOL(atm_dev_deregister);
404 EXPORT_SYMBOL(atm_dev_lookup);
405 EXPORT_SYMBOL(shutdown_atm_dev);
406