xref: /openbmc/linux/net/atm/resources.c (revision 1fa6ac37)
1 /* net/atm/resources.c - Statically allocated resources */
2 
3 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
4 
5 /* Fixes
6  * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
7  * 2002/01 - don't free the whole struct sock on sk->destruct time,
8  * 	     use the default destruct function initialized by sock_init_data */
9 
10 #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
11 
12 #include <linux/ctype.h>
13 #include <linux/string.h>
14 #include <linux/atmdev.h>
15 #include <linux/sonet.h>
16 #include <linux/kernel.h> /* for barrier */
17 #include <linux/module.h>
18 #include <linux/bitops.h>
19 #include <linux/capability.h>
20 #include <linux/delay.h>
21 #include <linux/mutex.h>
22 #include <linux/slab.h>
23 
24 #include <net/sock.h>	 /* for struct sock */
25 
26 #include "common.h"
27 #include "resources.h"
28 #include "addr.h"
29 
30 
31 LIST_HEAD(atm_devs);
32 DEFINE_MUTEX(atm_dev_mutex);
33 
34 static struct atm_dev *__alloc_atm_dev(const char *type)
35 {
36 	struct atm_dev *dev;
37 
38 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
39 	if (!dev)
40 		return NULL;
41 	dev->type = type;
42 	dev->signal = ATM_PHY_SIG_UNKNOWN;
43 	dev->link_rate = ATM_OC3_PCR;
44 	spin_lock_init(&dev->lock);
45 	INIT_LIST_HEAD(&dev->local);
46 	INIT_LIST_HEAD(&dev->lecs);
47 
48 	return dev;
49 }
50 
51 static struct atm_dev *__atm_dev_lookup(int number)
52 {
53 	struct atm_dev *dev;
54 	struct list_head *p;
55 
56 	list_for_each(p, &atm_devs) {
57 		dev = list_entry(p, struct atm_dev, dev_list);
58 		if (dev->number == number) {
59 			atm_dev_hold(dev);
60 			return dev;
61 		}
62 	}
63 	return NULL;
64 }
65 
66 struct atm_dev *atm_dev_lookup(int number)
67 {
68 	struct atm_dev *dev;
69 
70 	mutex_lock(&atm_dev_mutex);
71 	dev = __atm_dev_lookup(number);
72 	mutex_unlock(&atm_dev_mutex);
73 	return dev;
74 }
75 EXPORT_SYMBOL(atm_dev_lookup);
76 
77 struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
78 				 int number, unsigned long *flags)
79 {
80 	struct atm_dev *dev, *inuse;
81 
82 	dev = __alloc_atm_dev(type);
83 	if (!dev) {
84 		pr_err("no space for dev %s\n", type);
85 		return NULL;
86 	}
87 	mutex_lock(&atm_dev_mutex);
88 	if (number != -1) {
89 		inuse = __atm_dev_lookup(number);
90 		if (inuse) {
91 			atm_dev_put(inuse);
92 			mutex_unlock(&atm_dev_mutex);
93 			kfree(dev);
94 			return NULL;
95 		}
96 		dev->number = number;
97 	} else {
98 		dev->number = 0;
99 		while ((inuse = __atm_dev_lookup(dev->number))) {
100 			atm_dev_put(inuse);
101 			dev->number++;
102 		}
103 	}
104 
105 	dev->ops = ops;
106 	if (flags)
107 		dev->flags = *flags;
108 	else
109 		memset(&dev->flags, 0, sizeof(dev->flags));
110 	memset(&dev->stats, 0, sizeof(dev->stats));
111 	atomic_set(&dev->refcnt, 1);
112 
113 	if (atm_proc_dev_register(dev) < 0) {
114 		pr_err("atm_proc_dev_register failed for dev %s\n", type);
115 		goto out_fail;
116 	}
117 
118 	if (atm_register_sysfs(dev) < 0) {
119 		pr_err("atm_register_sysfs failed for dev %s\n", type);
120 		atm_proc_dev_deregister(dev);
121 		goto out_fail;
122 	}
123 
124 	list_add_tail(&dev->dev_list, &atm_devs);
125 
126 out:
127 	mutex_unlock(&atm_dev_mutex);
128 	return dev;
129 
130 out_fail:
131 	kfree(dev);
132 	dev = NULL;
133 	goto out;
134 }
135 EXPORT_SYMBOL(atm_dev_register);
136 
137 void atm_dev_deregister(struct atm_dev *dev)
138 {
139 	BUG_ON(test_bit(ATM_DF_REMOVED, &dev->flags));
140 	set_bit(ATM_DF_REMOVED, &dev->flags);
141 
142 	/*
143 	 * if we remove current device from atm_devs list, new device
144 	 * with same number can appear, such we need deregister proc,
145 	 * release async all vccs and remove them from vccs list too
146 	 */
147 	mutex_lock(&atm_dev_mutex);
148 	list_del(&dev->dev_list);
149 	mutex_unlock(&atm_dev_mutex);
150 
151 	atm_dev_release_vccs(dev);
152 	atm_unregister_sysfs(dev);
153 	atm_proc_dev_deregister(dev);
154 
155 	atm_dev_put(dev);
156 }
157 EXPORT_SYMBOL(atm_dev_deregister);
158 
159 static void copy_aal_stats(struct k_atm_aal_stats *from,
160     struct atm_aal_stats *to)
161 {
162 #define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
163 	__AAL_STAT_ITEMS
164 #undef __HANDLE_ITEM
165 }
166 
167 static void subtract_aal_stats(struct k_atm_aal_stats *from,
168     struct atm_aal_stats *to)
169 {
170 #define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i)
171 	__AAL_STAT_ITEMS
172 #undef __HANDLE_ITEM
173 }
174 
175 static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg,
176 		       int zero)
177 {
178 	struct atm_dev_stats tmp;
179 	int error = 0;
180 
181 	copy_aal_stats(&dev->stats.aal0, &tmp.aal0);
182 	copy_aal_stats(&dev->stats.aal34, &tmp.aal34);
183 	copy_aal_stats(&dev->stats.aal5, &tmp.aal5);
184 	if (arg)
185 		error = copy_to_user(arg, &tmp, sizeof(tmp));
186 	if (zero && !error) {
187 		subtract_aal_stats(&dev->stats.aal0, &tmp.aal0);
188 		subtract_aal_stats(&dev->stats.aal34, &tmp.aal34);
189 		subtract_aal_stats(&dev->stats.aal5, &tmp.aal5);
190 	}
191 	return error ? -EFAULT : 0;
192 }
193 
194 int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat)
195 {
196 	void __user *buf;
197 	int error, len, number, size = 0;
198 	struct atm_dev *dev;
199 	struct list_head *p;
200 	int *tmp_buf, *tmp_p;
201 	int __user *sioc_len;
202 	int __user *iobuf_len;
203 
204 #ifndef CONFIG_COMPAT
205 	compat = 0; /* Just so the compiler _knows_ */
206 #endif
207 
208 	switch (cmd) {
209 	case ATM_GETNAMES:
210 		if (compat) {
211 #ifdef CONFIG_COMPAT
212 			struct compat_atm_iobuf __user *ciobuf = arg;
213 			compat_uptr_t cbuf;
214 			iobuf_len = &ciobuf->length;
215 			if (get_user(cbuf, &ciobuf->buffer))
216 				return -EFAULT;
217 			buf = compat_ptr(cbuf);
218 #endif
219 		} else {
220 			struct atm_iobuf __user *iobuf = arg;
221 			iobuf_len = &iobuf->length;
222 			if (get_user(buf, &iobuf->buffer))
223 				return -EFAULT;
224 		}
225 		if (get_user(len, iobuf_len))
226 			return -EFAULT;
227 		mutex_lock(&atm_dev_mutex);
228 		list_for_each(p, &atm_devs)
229 			size += sizeof(int);
230 		if (size > len) {
231 			mutex_unlock(&atm_dev_mutex);
232 			return -E2BIG;
233 		}
234 		tmp_buf = kmalloc(size, GFP_ATOMIC);
235 		if (!tmp_buf) {
236 			mutex_unlock(&atm_dev_mutex);
237 			return -ENOMEM;
238 		}
239 		tmp_p = tmp_buf;
240 		list_for_each(p, &atm_devs) {
241 			dev = list_entry(p, struct atm_dev, dev_list);
242 			*tmp_p++ = dev->number;
243 		}
244 		mutex_unlock(&atm_dev_mutex);
245 		error = ((copy_to_user(buf, tmp_buf, size)) ||
246 			 put_user(size, iobuf_len))
247 			? -EFAULT : 0;
248 		kfree(tmp_buf);
249 		return error;
250 	default:
251 		break;
252 	}
253 
254 	if (compat) {
255 #ifdef CONFIG_COMPAT
256 		struct compat_atmif_sioc __user *csioc = arg;
257 		compat_uptr_t carg;
258 
259 		sioc_len = &csioc->length;
260 		if (get_user(carg, &csioc->arg))
261 			return -EFAULT;
262 		buf = compat_ptr(carg);
263 
264 		if (get_user(len, &csioc->length))
265 			return -EFAULT;
266 		if (get_user(number, &csioc->number))
267 			return -EFAULT;
268 #endif
269 	} else {
270 		struct atmif_sioc __user *sioc = arg;
271 
272 		sioc_len = &sioc->length;
273 		if (get_user(buf, &sioc->arg))
274 			return -EFAULT;
275 		if (get_user(len, &sioc->length))
276 			return -EFAULT;
277 		if (get_user(number, &sioc->number))
278 			return -EFAULT;
279 	}
280 
281 	dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d",
282 				      number);
283 	if (!dev)
284 		return -ENODEV;
285 
286 	switch (cmd) {
287 	case ATM_GETTYPE:
288 		size = strlen(dev->type) + 1;
289 		if (copy_to_user(buf, dev->type, size)) {
290 			error = -EFAULT;
291 			goto done;
292 		}
293 		break;
294 	case ATM_GETESI:
295 		size = ESI_LEN;
296 		if (copy_to_user(buf, dev->esi, size)) {
297 			error = -EFAULT;
298 			goto done;
299 		}
300 		break;
301 	case ATM_SETESI:
302 	{
303 		int i;
304 
305 		for (i = 0; i < ESI_LEN; i++)
306 			if (dev->esi[i]) {
307 				error = -EEXIST;
308 				goto done;
309 			}
310 	}
311 	/* fall through */
312 	case ATM_SETESIF:
313 	{
314 		unsigned char esi[ESI_LEN];
315 
316 		if (!capable(CAP_NET_ADMIN)) {
317 			error = -EPERM;
318 			goto done;
319 		}
320 		if (copy_from_user(esi, buf, ESI_LEN)) {
321 			error = -EFAULT;
322 			goto done;
323 		}
324 		memcpy(dev->esi, esi, ESI_LEN);
325 		error =  ESI_LEN;
326 		goto done;
327 	}
328 	case ATM_GETSTATZ:
329 		if (!capable(CAP_NET_ADMIN)) {
330 			error = -EPERM;
331 			goto done;
332 		}
333 		/* fall through */
334 	case ATM_GETSTAT:
335 		size = sizeof(struct atm_dev_stats);
336 		error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ);
337 		if (error)
338 			goto done;
339 		break;
340 	case ATM_GETCIRANGE:
341 		size = sizeof(struct atm_cirange);
342 		if (copy_to_user(buf, &dev->ci_range, size)) {
343 			error = -EFAULT;
344 			goto done;
345 		}
346 		break;
347 	case ATM_GETLINKRATE:
348 		size = sizeof(int);
349 		if (copy_to_user(buf, &dev->link_rate, size)) {
350 			error = -EFAULT;
351 			goto done;
352 		}
353 		break;
354 	case ATM_RSTADDR:
355 		if (!capable(CAP_NET_ADMIN)) {
356 			error = -EPERM;
357 			goto done;
358 		}
359 		atm_reset_addr(dev, ATM_ADDR_LOCAL);
360 		break;
361 	case ATM_ADDADDR:
362 	case ATM_DELADDR:
363 	case ATM_ADDLECSADDR:
364 	case ATM_DELLECSADDR:
365 	{
366 		struct sockaddr_atmsvc addr;
367 
368 		if (!capable(CAP_NET_ADMIN)) {
369 			error = -EPERM;
370 			goto done;
371 		}
372 
373 		if (copy_from_user(&addr, buf, sizeof(addr))) {
374 			error = -EFAULT;
375 			goto done;
376 		}
377 		if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR)
378 			error = atm_add_addr(dev, &addr,
379 					     (cmd == ATM_ADDADDR ?
380 					      ATM_ADDR_LOCAL : ATM_ADDR_LECS));
381 		else
382 			error = atm_del_addr(dev, &addr,
383 					     (cmd == ATM_DELADDR ?
384 					      ATM_ADDR_LOCAL : ATM_ADDR_LECS));
385 		goto done;
386 	}
387 	case ATM_GETADDR:
388 	case ATM_GETLECSADDR:
389 		error = atm_get_addr(dev, buf, len,
390 				     (cmd == ATM_GETADDR ?
391 				      ATM_ADDR_LOCAL : ATM_ADDR_LECS));
392 		if (error < 0)
393 			goto done;
394 		size = error;
395 		/* may return 0, but later on size == 0 means "don't
396 		   write the length" */
397 		error = put_user(size, sioc_len) ? -EFAULT : 0;
398 		goto done;
399 	case ATM_SETLOOP:
400 		if (__ATM_LM_XTRMT((int) (unsigned long) buf) &&
401 		    __ATM_LM_XTLOC((int) (unsigned long) buf) >
402 		    __ATM_LM_XTRMT((int) (unsigned long) buf)) {
403 			error = -EINVAL;
404 			goto done;
405 		}
406 		/* fall through */
407 	case ATM_SETCIRANGE:
408 	case SONET_GETSTATZ:
409 	case SONET_SETDIAG:
410 	case SONET_CLRDIAG:
411 	case SONET_SETFRAMING:
412 		if (!capable(CAP_NET_ADMIN)) {
413 			error = -EPERM;
414 			goto done;
415 		}
416 		/* fall through */
417 	default:
418 		if (compat) {
419 #ifdef CONFIG_COMPAT
420 			if (!dev->ops->compat_ioctl) {
421 				error = -EINVAL;
422 				goto done;
423 			}
424 			size = dev->ops->compat_ioctl(dev, cmd, buf);
425 #endif
426 		} else {
427 			if (!dev->ops->ioctl) {
428 				error = -EINVAL;
429 				goto done;
430 			}
431 			size = dev->ops->ioctl(dev, cmd, buf);
432 		}
433 		if (size < 0) {
434 			error = (size == -ENOIOCTLCMD ? -EINVAL : size);
435 			goto done;
436 		}
437 	}
438 
439 	if (size)
440 		error = put_user(size, sioc_len) ? -EFAULT : 0;
441 	else
442 		error = 0;
443 done:
444 	atm_dev_put(dev);
445 	return error;
446 }
447 
448 void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos)
449 {
450 	mutex_lock(&atm_dev_mutex);
451 	return seq_list_start_head(&atm_devs, *pos);
452 }
453 
454 void atm_dev_seq_stop(struct seq_file *seq, void *v)
455 {
456 	mutex_unlock(&atm_dev_mutex);
457 }
458 
459 void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
460 {
461 	return seq_list_next(v, &atm_devs, pos);
462 }
463