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