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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [net/] [wan/] [dlci.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * DLCI         Implementation of Frame Relay protocol for Linux, according to
3
 *              RFC 1490.  This generic device provides en/decapsulation for an
4
 *              underlying hardware driver.  Routes & IPs are assigned to these
5
 *              interfaces.  Requires 'dlcicfg' program to create usable
6
 *              interfaces, the initial one, 'dlci' is for IOCTL use only.
7
 *
8
 * Version:     @(#)dlci.c      0.35    4 Jan 1997
9
 *
10
 * Author:      Mike McLagan <mike.mclagan@linux.org>
11
 *
12
 * Changes:
13
 *
14
 *              0.15    Mike Mclagan    Packet freeing, bug in kmalloc call
15
 *                                      DLCI_RET handling
16
 *              0.20    Mike McLagan    More conservative on which packets
17
 *                                      are returned for retry and which are
18
 *                                      are dropped.  If DLCI_RET_DROP is
19
 *                                      returned from the FRAD, the packet is
20
 *                                      sent back to Linux for re-transmission
21
 *              0.25    Mike McLagan    Converted to use SIOC IOCTL calls
22
 *              0.30    Jim Freeman     Fixed to allow IPX traffic
23
 *              0.35    Michael Elizabeth       Fixed incorrect memcpy_fromfs
24
 *
25
 *              This program is free software; you can redistribute it and/or
26
 *              modify it under the terms of the GNU General Public License
27
 *              as published by the Free Software Foundation; either version
28
 *              2 of the License, or (at your option) any later version.
29
 */
30
 
31
#include <linux/module.h>
32
#include <linux/kernel.h>
33
#include <linux/types.h>
34
#include <linux/fcntl.h>
35
#include <linux/interrupt.h>
36
#include <linux/ptrace.h>
37
#include <linux/ioport.h>
38
#include <linux/in.h>
39
#include <linux/init.h>
40
#include <linux/slab.h>
41
#include <linux/string.h>
42
#include <linux/errno.h>
43
#include <linux/netdevice.h>
44
#include <linux/skbuff.h>
45
#include <linux/if_arp.h>
46
#include <linux/if_frad.h>
47
#include <linux/bitops.h>
48
 
49
#include <net/sock.h>
50
 
51
#include <asm/system.h>
52
#include <asm/io.h>
53
#include <asm/dma.h>
54
#include <asm/uaccess.h>
55
 
56
static const char version[] = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
57
 
58
static LIST_HEAD(dlci_devs);
59
 
60
static void dlci_setup(struct net_device *);
61
 
62
/*
63
 * these encapsulate the RFC 1490 requirements as well as
64
 * deal with packet transmission and reception, working with
65
 * the upper network layers
66
 */
67
 
68
static int dlci_header(struct sk_buff *skb, struct net_device *dev,
69
                       unsigned short type, const void *daddr,
70
                       const void *saddr, unsigned len)
71
{
72
        struct frhdr            hdr;
73
        struct dlci_local       *dlp;
74
        unsigned int            hlen;
75
        char                    *dest;
76
 
77
        dlp = dev->priv;
78
 
79
        hdr.control = FRAD_I_UI;
80
        switch(type)
81
        {
82
                case ETH_P_IP:
83
                        hdr.IP_NLPID = FRAD_P_IP;
84
                        hlen = sizeof(hdr.control) + sizeof(hdr.IP_NLPID);
85
                        break;
86
 
87
                /* feel free to add other types, if necessary */
88
 
89
                default:
90
                        hdr.pad = FRAD_P_PADDING;
91
                        hdr.NLPID = FRAD_P_SNAP;
92
                        memset(hdr.OUI, 0, sizeof(hdr.OUI));
93
                        hdr.PID = htons(type);
94
                        hlen = sizeof(hdr);
95
                        break;
96
        }
97
 
98
        dest = skb_push(skb, hlen);
99
        if (!dest)
100
                return(0);
101
 
102
        memcpy(dest, &hdr, hlen);
103
 
104
        return(hlen);
105
}
106
 
107
static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
108
{
109
        struct dlci_local *dlp;
110
        struct frhdr            *hdr;
111
        int                                     process, header;
112
 
113
        dlp = dev->priv;
114
        if (!pskb_may_pull(skb, sizeof(*hdr))) {
115
                printk(KERN_NOTICE "%s: invalid data no header\n",
116
                       dev->name);
117
                dlp->stats.rx_errors++;
118
                kfree_skb(skb);
119
                return;
120
        }
121
 
122
        hdr = (struct frhdr *) skb->data;
123
        process = 0;
124
        header = 0;
125
        skb->dev = dev;
126
 
127
        if (hdr->control != FRAD_I_UI)
128
        {
129
                printk(KERN_NOTICE "%s: Invalid header flag 0x%02X.\n", dev->name, hdr->control);
130
                dlp->stats.rx_errors++;
131
        }
132
        else
133
                switch(hdr->IP_NLPID)
134
                {
135
                        case FRAD_P_PADDING:
136
                                if (hdr->NLPID != FRAD_P_SNAP)
137
                                {
138
                                        printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->NLPID);
139
                                        dlp->stats.rx_errors++;
140
                                        break;
141
                                }
142
 
143
                                if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0)
144
                                {
145
                                        printk(KERN_NOTICE "%s: Unsupported organizationally unique identifier 0x%02X-%02X-%02X.\n", dev->name, hdr->OUI[0], hdr->OUI[1], hdr->OUI[2]);
146
                                        dlp->stats.rx_errors++;
147
                                        break;
148
                                }
149
 
150
                                /* at this point, it's an EtherType frame */
151
                                header = sizeof(struct frhdr);
152
                                /* Already in network order ! */
153
                                skb->protocol = hdr->PID;
154
                                process = 1;
155
                                break;
156
 
157
                        case FRAD_P_IP:
158
                                header = sizeof(hdr->control) + sizeof(hdr->IP_NLPID);
159
                                skb->protocol = htons(ETH_P_IP);
160
                                process = 1;
161
                                break;
162
 
163
                        case FRAD_P_SNAP:
164
                        case FRAD_P_Q933:
165
                        case FRAD_P_CLNP:
166
                                printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->pad);
167
                                dlp->stats.rx_errors++;
168
                                break;
169
 
170
                        default:
171
                                printk(KERN_NOTICE "%s: Invalid pad byte 0x%02X.\n", dev->name, hdr->pad);
172
                                dlp->stats.rx_errors++;
173
                                break;
174
                }
175
 
176
        if (process)
177
        {
178
                /* we've set up the protocol, so discard the header */
179
                skb_reset_mac_header(skb);
180
                skb_pull(skb, header);
181
                dlp->stats.rx_bytes += skb->len;
182
                netif_rx(skb);
183
                dlp->stats.rx_packets++;
184
                dev->last_rx = jiffies;
185
        }
186
        else
187
                dev_kfree_skb(skb);
188
}
189
 
190
static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
191
{
192
        struct dlci_local *dlp;
193
        int                                     ret;
194
 
195
        ret = 0;
196
 
197
        if (!skb || !dev)
198
                return(0);
199
 
200
        dlp = dev->priv;
201
 
202
        netif_stop_queue(dev);
203
 
204
        ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
205
        switch (ret)
206
        {
207
                case DLCI_RET_OK:
208
                        dlp->stats.tx_packets++;
209
                        ret = 0;
210
                        break;
211
                        case DLCI_RET_ERR:
212
                        dlp->stats.tx_errors++;
213
                        ret = 0;
214
                        break;
215
                        case DLCI_RET_DROP:
216
                        dlp->stats.tx_dropped++;
217
                        ret = 1;
218
                        break;
219
        }
220
        /* Alan Cox recommends always returning 0, and always freeing the packet */
221
        /* experience suggest a slightly more conservative approach */
222
 
223
        if (!ret)
224
        {
225
                dev_kfree_skb(skb);
226
                netif_wake_queue(dev);
227
        }
228
        return(ret);
229
}
230
 
231
static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, int get)
232
{
233
        struct dlci_conf        config;
234
        struct dlci_local       *dlp;
235
        struct frad_local       *flp;
236
        int                     err;
237
 
238
        dlp = dev->priv;
239
 
240
        flp = dlp->slave->priv;
241
 
242
        if (!get)
243
        {
244
                if(copy_from_user(&config, conf, sizeof(struct dlci_conf)))
245
                        return -EFAULT;
246
                if (config.flags & ~DLCI_VALID_FLAGS)
247
                        return(-EINVAL);
248
                memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
249
                dlp->configured = 1;
250
        }
251
 
252
        err = (*flp->dlci_conf)(dlp->slave, dev, get);
253
        if (err)
254
                return(err);
255
 
256
        if (get)
257
        {
258
                if(copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf)))
259
                        return -EFAULT;
260
        }
261
 
262
        return(0);
263
}
264
 
265
static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
266
{
267
        struct dlci_local *dlp;
268
 
269
        if (!capable(CAP_NET_ADMIN))
270
                return(-EPERM);
271
 
272
        dlp = dev->priv;
273
 
274
        switch(cmd)
275
        {
276
                case DLCI_GET_SLAVE:
277
                        if (!*(short *)(dev->dev_addr))
278
                                return(-EINVAL);
279
 
280
                        strncpy(ifr->ifr_slave, dlp->slave->name, sizeof(ifr->ifr_slave));
281
                        break;
282
 
283
                case DLCI_GET_CONF:
284
                case DLCI_SET_CONF:
285
                        if (!*(short *)(dev->dev_addr))
286
                                return(-EINVAL);
287
 
288
                        return(dlci_config(dev, ifr->ifr_data, cmd == DLCI_GET_CONF));
289
                        break;
290
 
291
                default:
292
                        return(-EOPNOTSUPP);
293
        }
294
        return(0);
295
}
296
 
297
static int dlci_change_mtu(struct net_device *dev, int new_mtu)
298
{
299
        struct dlci_local *dlp;
300
 
301
        dlp = dev->priv;
302
 
303
        return((*dlp->slave->change_mtu)(dlp->slave, new_mtu));
304
}
305
 
306
static int dlci_open(struct net_device *dev)
307
{
308
        struct dlci_local       *dlp;
309
        struct frad_local       *flp;
310
        int                     err;
311
 
312
        dlp = dev->priv;
313
 
314
        if (!*(short *)(dev->dev_addr))
315
                return(-EINVAL);
316
 
317
        if (!netif_running(dlp->slave))
318
                return(-ENOTCONN);
319
 
320
        flp = dlp->slave->priv;
321
        err = (*flp->activate)(dlp->slave, dev);
322
        if (err)
323
                return(err);
324
 
325
        netif_start_queue(dev);
326
 
327
        return 0;
328
}
329
 
330
static int dlci_close(struct net_device *dev)
331
{
332
        struct dlci_local       *dlp;
333
        struct frad_local       *flp;
334
        int                     err;
335
 
336
        netif_stop_queue(dev);
337
 
338
        dlp = dev->priv;
339
 
340
        flp = dlp->slave->priv;
341
        err = (*flp->deactivate)(dlp->slave, dev);
342
 
343
        return 0;
344
}
345
 
346
static struct net_device_stats *dlci_get_stats(struct net_device *dev)
347
{
348
        struct dlci_local *dlp;
349
 
350
        dlp = dev->priv;
351
 
352
        return(&dlp->stats);
353
}
354
 
355
static int dlci_add(struct dlci_add *dlci)
356
{
357
        struct net_device       *master, *slave;
358
        struct dlci_local       *dlp;
359
        struct frad_local       *flp;
360
        int                     err = -EINVAL;
361
 
362
 
363
        /* validate slave device */
364
        slave = dev_get_by_name(&init_net, dlci->devname);
365
        if (!slave)
366
                return -ENODEV;
367
 
368
        if (slave->type != ARPHRD_FRAD || slave->priv == NULL)
369
                goto err1;
370
 
371
        /* create device name */
372
        master = alloc_netdev( sizeof(struct dlci_local), "dlci%d",
373
                              dlci_setup);
374
        if (!master) {
375
                err = -ENOMEM;
376
                goto err1;
377
        }
378
 
379
        /* make sure same slave not already registered */
380
        rtnl_lock();
381
        list_for_each_entry(dlp, &dlci_devs, list) {
382
                if (dlp->slave == slave) {
383
                        err = -EBUSY;
384
                        goto err2;
385
                }
386
        }
387
 
388
        err = dev_alloc_name(master, master->name);
389
        if (err < 0)
390
                goto err2;
391
 
392
        *(short *)(master->dev_addr) = dlci->dlci;
393
 
394
        dlp = (struct dlci_local *) master->priv;
395
        dlp->slave = slave;
396
        dlp->master = master;
397
 
398
        flp = slave->priv;
399
        err = (*flp->assoc)(slave, master);
400
        if (err < 0)
401
                goto err2;
402
 
403
        err = register_netdevice(master);
404
        if (err < 0)
405
                goto err2;
406
 
407
        strcpy(dlci->devname, master->name);
408
 
409
        list_add(&dlp->list, &dlci_devs);
410
        rtnl_unlock();
411
 
412
        return(0);
413
 
414
 err2:
415
        rtnl_unlock();
416
        free_netdev(master);
417
 err1:
418
        dev_put(slave);
419
        return(err);
420
}
421
 
422
static int dlci_del(struct dlci_add *dlci)
423
{
424
        struct dlci_local       *dlp;
425
        struct frad_local       *flp;
426
        struct net_device       *master, *slave;
427
        int                     err;
428
 
429
        /* validate slave device */
430
        master = __dev_get_by_name(&init_net, dlci->devname);
431
        if (!master)
432
                return(-ENODEV);
433
 
434
        if (netif_running(master)) {
435
                return(-EBUSY);
436
        }
437
 
438
        dlp = master->priv;
439
        slave = dlp->slave;
440
        flp = slave->priv;
441
 
442
        rtnl_lock();
443
        err = (*flp->deassoc)(slave, master);
444
        if (!err) {
445
                list_del(&dlp->list);
446
 
447
                unregister_netdevice(master);
448
 
449
                dev_put(slave);
450
        }
451
        rtnl_unlock();
452
 
453
        return(err);
454
}
455
 
456
static int dlci_ioctl(unsigned int cmd, void __user *arg)
457
{
458
        struct dlci_add add;
459
        int err;
460
 
461
        if (!capable(CAP_NET_ADMIN))
462
                return(-EPERM);
463
 
464
        if(copy_from_user(&add, arg, sizeof(struct dlci_add)))
465
                return -EFAULT;
466
 
467
        switch (cmd)
468
        {
469
                case SIOCADDDLCI:
470
                        err = dlci_add(&add);
471
 
472
                        if (!err)
473
                                if(copy_to_user(arg, &add, sizeof(struct dlci_add)))
474
                                        return -EFAULT;
475
                        break;
476
 
477
                case SIOCDELDLCI:
478
                        err = dlci_del(&add);
479
                        break;
480
 
481
                default:
482
                        err = -EINVAL;
483
        }
484
 
485
        return(err);
486
}
487
 
488
static const struct header_ops dlci_header_ops = {
489
        .create = dlci_header,
490
};
491
 
492
static void dlci_setup(struct net_device *dev)
493
{
494
        struct dlci_local *dlp = dev->priv;
495
 
496
        dev->flags              = 0;
497
        dev->open               = dlci_open;
498
        dev->stop               = dlci_close;
499
        dev->do_ioctl           = dlci_dev_ioctl;
500
        dev->hard_start_xmit    = dlci_transmit;
501
        dev->header_ops         = &dlci_header_ops;
502
        dev->get_stats          = dlci_get_stats;
503
        dev->change_mtu         = dlci_change_mtu;
504
        dev->destructor         = free_netdev;
505
 
506
        dlp->receive            = dlci_receive;
507
 
508
        dev->type               = ARPHRD_DLCI;
509
        dev->hard_header_len    = sizeof(struct frhdr);
510
        dev->addr_len           = sizeof(short);
511
 
512
}
513
 
514
/* if slave is unregistering, then cleanup master */
515
static int dlci_dev_event(struct notifier_block *unused,
516
                          unsigned long event, void *ptr)
517
{
518
        struct net_device *dev = (struct net_device *) ptr;
519
 
520
        if (dev->nd_net != &init_net)
521
                return NOTIFY_DONE;
522
 
523
        if (event == NETDEV_UNREGISTER) {
524
                struct dlci_local *dlp;
525
 
526
                list_for_each_entry(dlp, &dlci_devs, list) {
527
                        if (dlp->slave == dev) {
528
                                list_del(&dlp->list);
529
                                unregister_netdevice(dlp->master);
530
                                dev_put(dlp->slave);
531
                                break;
532
                        }
533
                }
534
        }
535
        return NOTIFY_DONE;
536
}
537
 
538
static struct notifier_block dlci_notifier = {
539
        .notifier_call = dlci_dev_event,
540
};
541
 
542
static int __init init_dlci(void)
543
{
544
        dlci_ioctl_set(dlci_ioctl);
545
        register_netdevice_notifier(&dlci_notifier);
546
 
547
        printk("%s.\n", version);
548
 
549
        return 0;
550
}
551
 
552
static void __exit dlci_exit(void)
553
{
554
        struct dlci_local       *dlp, *nxt;
555
 
556
        dlci_ioctl_set(NULL);
557
        unregister_netdevice_notifier(&dlci_notifier);
558
 
559
        rtnl_lock();
560
        list_for_each_entry_safe(dlp, nxt, &dlci_devs, list) {
561
                unregister_netdevice(dlp->master);
562
                dev_put(dlp->slave);
563
        }
564
        rtnl_unlock();
565
}
566
 
567
module_init(init_dlci);
568
module_exit(dlci_exit);
569
 
570
MODULE_AUTHOR("Mike McLagan");
571
MODULE_DESCRIPTION("Frame Relay DLCI layer");
572
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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