OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [atm/] [resources.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* 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
 
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
 
43
static void __free_atm_dev(struct atm_dev *dev)
44
{
45
        kfree(dev);
46
}
47
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.