projects/linux·blob master · refs

363 lines · 7.6 KiB

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 <[email protected]>
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/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
29
30LIST_HEAD(atm_devs);
31DEFINE_MUTEX(atm_dev_mutex);
32
33static struct atm_dev *__alloc_atm_dev(const char *type)
34{
35 struct atm_dev *dev;
36
37 dev = kzalloc_obj(*dev);
38 if (!dev)
39 return NULL;
40 dev->type = type;
41 dev->signal = ATM_PHY_SIG_UNKNOWN;
42 dev->link_rate = ATM_OC3_PCR;
43
44 return dev;
45}
46
47static struct atm_dev *__atm_dev_lookup(int number)
48{
49 struct atm_dev *dev;
50
51 list_for_each_entry(dev, &atm_devs, dev_list) {
52 if (dev->number == number) {
53 atm_dev_hold(dev);
54 return dev;
55 }
56 }
57 return NULL;
58}
59
60struct atm_dev *atm_dev_lookup(int number)
61{
62 struct atm_dev *dev;
63
64 mutex_lock(&atm_dev_mutex);
65 dev = __atm_dev_lookup(number);
66 mutex_unlock(&atm_dev_mutex);
67 return dev;
68}
69EXPORT_SYMBOL(atm_dev_lookup);
70
71struct atm_dev *atm_dev_register(const char *type, struct device *parent,
72 const struct atmdev_ops *ops, int number,
73 unsigned long *flags)
74{
75 struct atm_dev *dev, *inuse;
76
77 dev = __alloc_atm_dev(type);
78 if (!dev) {
79 pr_err("no space for dev %s\n", type);
80 return NULL;
81 }
82 mutex_lock(&atm_dev_mutex);
83 if (number != -1) {
84 inuse = __atm_dev_lookup(number);
85 if (inuse) {
86 atm_dev_put(inuse);
87 mutex_unlock(&atm_dev_mutex);
88 kfree(dev);
89 return NULL;
90 }
91 dev->number = number;
92 } else {
93 dev->number = 0;
94 while ((inuse = __atm_dev_lookup(dev->number))) {
95 atm_dev_put(inuse);
96 dev->number++;
97 }
98 }
99
100 dev->ops = ops;
101 if (flags)
102 dev->flags = *flags;
103 else
104 memset(&dev->flags, 0, sizeof(dev->flags));
105 memset(&dev->stats, 0, sizeof(dev->stats));
106 refcount_set(&dev->refcnt, 1);
107
108 if (atm_proc_dev_register(dev) < 0) {
109 pr_err("atm_proc_dev_register failed for dev %s\n", type);
110 mutex_unlock(&atm_dev_mutex);
111 kfree(dev);
112 return NULL;
113 }
114
115 if (atm_register_sysfs(dev, parent) < 0) {
116 pr_err("atm_register_sysfs failed for dev %s\n", type);
117 atm_proc_dev_deregister(dev);
118 goto out_fail;
119 }
120
121 list_add_tail(&dev->dev_list, &atm_devs);
122
123out:
124 mutex_unlock(&atm_dev_mutex);
125 return dev;
126
127out_fail:
128 put_device(&dev->class_dev);
129 dev = NULL;
130 goto out;
131}
132EXPORT_SYMBOL(atm_dev_register);
133
134void atm_dev_deregister(struct atm_dev *dev)
135{
136 BUG_ON(test_bit(ATM_DF_REMOVED, &dev->flags));
137 set_bit(ATM_DF_REMOVED, &dev->flags);
138
139 /*
140 * if we remove current device from atm_devs list, new device
141 * with same number can appear, such we need deregister proc,
142 * release async all vccs and remove them from vccs list too
143 */
144 mutex_lock(&atm_dev_mutex);
145 list_del(&dev->dev_list);
146 atm_dev_release_vccs(dev);
147 atm_unregister_sysfs(dev);
148 atm_proc_dev_deregister(dev);
149 mutex_unlock(&atm_dev_mutex);
150
151 atm_dev_put(dev);
152}
153EXPORT_SYMBOL(atm_dev_deregister);
154
155static void copy_aal_stats(struct k_atm_aal_stats *from,
156 struct atm_aal_stats *to)
157{
158#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
159 __AAL_STAT_ITEMS
160#undef __HANDLE_ITEM
161}
162
163static void subtract_aal_stats(struct k_atm_aal_stats *from,
164 struct atm_aal_stats *to)
165{
166#define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i)
167 __AAL_STAT_ITEMS
168#undef __HANDLE_ITEM
169}
170
171static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg,
172 int zero)
173{
174 struct atm_dev_stats tmp;
175 int error = 0;
176
177 copy_aal_stats(&dev->stats.aal0, &tmp.aal0);
178 copy_aal_stats(&dev->stats.aal34, &tmp.aal34);
179 copy_aal_stats(&dev->stats.aal5, &tmp.aal5);
180 if (arg)
181 error = copy_to_user(arg, &tmp, sizeof(tmp));
182 if (zero && !error) {
183 subtract_aal_stats(&dev->stats.aal0, &tmp.aal0);
184 subtract_aal_stats(&dev->stats.aal34, &tmp.aal34);
185 subtract_aal_stats(&dev->stats.aal5, &tmp.aal5);
186 }
187 return error ? -EFAULT : 0;
188}
189
190int atm_getnames(void __user *buf, int __user *iobuf_len)
191{
192 int error, len, size = 0;
193 struct atm_dev *dev;
194 struct list_head *p;
195 int *tmp_buf, *tmp_p;
196
197 if (get_user(len, iobuf_len))
198 return -EFAULT;
199 mutex_lock(&atm_dev_mutex);
200 list_for_each(p, &atm_devs)
201 size += sizeof(int);
202 if (size > len) {
203 mutex_unlock(&atm_dev_mutex);
204 return -E2BIG;
205 }
206 tmp_buf = kmalloc(size, GFP_ATOMIC);
207 if (!tmp_buf) {
208 mutex_unlock(&atm_dev_mutex);
209 return -ENOMEM;
210 }
211 tmp_p = tmp_buf;
212 list_for_each_entry(dev, &atm_devs, dev_list) {
213 *tmp_p++ = dev->number;
214 }
215 mutex_unlock(&atm_dev_mutex);
216 error = ((copy_to_user(buf, tmp_buf, size)) ||
217 put_user(size, iobuf_len))
218 ? -EFAULT : 0;
219 kfree(tmp_buf);
220 return error;
221}
222
223int atm_dev_ioctl(unsigned int cmd, void __user *buf, int __user *sioc_len,
224 int number, int compat)
225{
226 struct atm_dev *dev;
227 int error, size = 0;
228
229 dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d",
230 number);
231 if (!dev)
232 return -ENODEV;
233
234 switch (cmd) {
235 case ATM_GETTYPE:
236 size = strlen(dev->type) + 1;
237 if (copy_to_user(buf, dev->type, size)) {
238 error = -EFAULT;
239 goto done;
240 }
241 break;
242 case ATM_GETESI:
243 size = ESI_LEN;
244 if (copy_to_user(buf, dev->esi, size)) {
245 error = -EFAULT;
246 goto done;
247 }
248 break;
249 case ATM_SETESI:
250 {
251 int i;
252
253 for (i = 0; i < ESI_LEN; i++)
254 if (dev->esi[i]) {
255 error = -EEXIST;
256 goto done;
257 }
258 }
259 fallthrough;
260 case ATM_SETESIF:
261 {
262 unsigned char esi[ESI_LEN];
263
264 if (!capable(CAP_NET_ADMIN)) {
265 error = -EPERM;
266 goto done;
267 }
268 if (copy_from_user(esi, buf, ESI_LEN)) {
269 error = -EFAULT;
270 goto done;
271 }
272 memcpy(dev->esi, esi, ESI_LEN);
273 error = ESI_LEN;
274 goto done;
275 }
276 case ATM_GETSTATZ:
277 if (!capable(CAP_NET_ADMIN)) {
278 error = -EPERM;
279 goto done;
280 }
281 fallthrough;
282 case ATM_GETSTAT:
283 size = sizeof(struct atm_dev_stats);
284 error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ);
285 if (error)
286 goto done;
287 break;
288 case ATM_GETCIRANGE:
289 size = sizeof(struct atm_cirange);
290 if (copy_to_user(buf, &dev->ci_range, size)) {
291 error = -EFAULT;
292 goto done;
293 }
294 break;
295 case ATM_GETLINKRATE:
296 size = sizeof(int);
297 if (copy_to_user(buf, &dev->link_rate, size)) {
298 error = -EFAULT;
299 goto done;
300 }
301 break;
302 case ATM_SETLOOP:
303 if (__ATM_LM_XTRMT((int) (unsigned long) buf) &&
304 __ATM_LM_XTLOC((int) (unsigned long) buf) >
305 __ATM_LM_XTRMT((int) (unsigned long) buf)) {
306 error = -EINVAL;
307 goto done;
308 }
309 fallthrough;
310 case ATM_SETCIRANGE:
311 if (!capable(CAP_NET_ADMIN)) {
312 error = -EPERM;
313 goto done;
314 }
315 fallthrough;
316 default:
317 if (IS_ENABLED(CONFIG_COMPAT) && compat) {
318#ifdef CONFIG_COMPAT
319 if (!dev->ops->compat_ioctl) {
320 error = -EINVAL;
321 goto done;
322 }
323 size = dev->ops->compat_ioctl(dev, cmd, buf);
324#endif
325 } else {
326 if (!dev->ops->ioctl) {
327 error = -EINVAL;
328 goto done;
329 }
330 size = dev->ops->ioctl(dev, cmd, buf);
331 }
332 if (size < 0) {
333 error = (size == -ENOIOCTLCMD ? -ENOTTY : size);
334 goto done;
335 }
336 }
337
338 if (size)
339 error = put_user(size, sioc_len) ? -EFAULT : 0;
340 else
341 error = 0;
342done:
343 atm_dev_put(dev);
344 return error;
345}
346
347#ifdef CONFIG_PROC_FS
348void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos)
349{
350 mutex_lock(&atm_dev_mutex);
351 return seq_list_start_head(&atm_devs, *pos);
352}
353
354void atm_dev_seq_stop(struct seq_file *seq, void *v)
355{
356 mutex_unlock(&atm_dev_mutex);
357}
358
359void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
360{
361 return seq_list_next(v, &atm_devs, pos);
362}
363#endif