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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [net/] [dlci.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
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.30    12 Sep 1996
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 whic 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
 *
24
 *              This program is free software; you can redistribute it and/or
25
 *              modify it under the terms of the GNU General Public License
26
 *              as published by the Free Software Foundation; either version
27
 *              2 of the License, or (at your option) any later version.
28
 */
29
 
30
#include <linux/config.h>
31
#include <linux/module.h>
32
 
33
#include <linux/kernel.h>
34
#include <linux/sched.h>
35
#include <linux/types.h>
36
#include <linux/fcntl.h>
37
#include <linux/interrupt.h>
38
#include <linux/ptrace.h>
39
#include <linux/ioport.h>
40
#include <linux/in.h>
41
#include <linux/malloc.h>
42
#include <linux/string.h>
43
#include <asm/system.h>
44
#include <asm/bitops.h>
45
#include <asm/io.h>
46
#include <asm/dma.h>
47
#include <linux/errno.h>
48
 
49
#include <linux/netdevice.h>
50
#include <linux/skbuff.h>
51
#include <linux/if_arp.h>
52
#include <linux/if_frad.h>
53
 
54
#include <net/sock.h>
55
 
56
static const char *devname = "dlci";
57
static const char *version = "DLCI driver v0.30, 12 Sep 1996, mike.mclagan@linux.org";
58
 
59
static struct device *open_dev[CONFIG_DLCI_COUNT];
60
 
61
static char *basename[16];
62
 
63
int dlci_init(struct device *dev);
64
 
65
/* allow FRAD's to register their name as a valid FRAD */
66
int register_frad(const char *name)
67
{
68
   int i;
69
 
70
   if (!name)
71
      return(-EINVAL);
72
 
73
   for (i=0;i<sizeof(basename) / sizeof(char *);i++)
74
   {
75
      if (!basename[i])
76
         break;
77
 
78
      /* take care of multiple registrations */
79
      if (strcmp(basename[i], name) == 0)
80
         return(0);
81
   }
82
 
83
   if (i == sizeof(basename) / sizeof(char *))
84
      return(-EMLINK);
85
 
86
   basename[i] = kmalloc(strlen(name) + 1, GFP_KERNEL);
87
   if (!basename[i])
88
      return(-ENOMEM);
89
 
90
   strcpy(basename[i], name);
91
 
92
   return(0);
93
}
94
 
95
int unregister_frad(const char *name)
96
{
97
   int i;
98
 
99
   if (!name)
100
      return(-EINVAL);
101
 
102
   for (i=0;i<sizeof(basename) / sizeof(char *);i++)
103
      if (basename[i] && (strcmp(basename[i], name) == 0))
104
         break;
105
 
106
   if (i == sizeof(basename) / sizeof(char *))
107
      return(-EINVAL);
108
 
109
   kfree(basename[i]);
110
   basename[i] = NULL;
111
 
112
   return(0);
113
}
114
 
115
/*
116
 * these encapsulate the RFC 1490 requirements as well as
117
 * deal with packet transmission and reception, working with
118
 * the upper network layers
119
 */
120
 
121
static int dlci_header(struct sk_buff *skb, struct device *dev,
122
                           unsigned short type, void *daddr, void *saddr,
123
                           unsigned len)
124
{
125
   struct frhdr      hdr;
126
   struct dlci_local *dlp;
127
   unsigned          hlen;
128
   char              *dest;
129
 
130
   dlp = dev->priv;
131
 
132
   hdr.control = FRAD_I_UI;
133
   switch(type)
134
   {
135
      case ETH_P_IP:
136
         hdr.IP_NLPID = FRAD_P_IP;
137
         hlen = sizeof(hdr.control) + sizeof(hdr.IP_NLPID);
138
         break;
139
 
140
      /* feel free to add other types, if necessary */
141
 
142
      default:
143
         hdr.pad = FRAD_P_PADDING;
144
         hdr.NLPID = FRAD_P_SNAP;
145
         memset(hdr.OUI, 0, sizeof(hdr.OUI));
146
         hdr.PID = htons(type);
147
         hlen = sizeof(hdr);
148
         break;
149
   }
150
 
151
   dest = skb_push(skb, hlen);
152
   if (!dest)
153
      return(0);
154
 
155
   memcpy(dest, &hdr, hlen);
156
 
157
   return(hlen);
158
}
159
 
160
static void dlci_receive(struct sk_buff *skb, struct device *dev)
161
{
162
   struct dlci_local *dlp;
163
   struct frhdr      *hdr;
164
   int               process, header;
165
 
166
   dlp = dev->priv;
167
   hdr = (struct frhdr *) skb->data;
168
   process = 0;
169
   header = 0;
170
   skb->dev = dev;
171
 
172
   if (hdr->control != FRAD_I_UI)
173
   {
174
      printk(KERN_NOTICE "%s: Invalid header flag 0x%02X.\n", dev->name, hdr->control);
175
      dlp->stats.rx_errors++;
176
   }
177
   else
178
      switch(hdr->IP_NLPID)
179
      {
180
         case FRAD_P_PADDING:
181
            if (hdr->NLPID != FRAD_P_SNAP)
182
            {
183
               printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->NLPID);
184
               dlp->stats.rx_errors++;
185
               break;
186
            }
187
 
188
            if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0)
189
            {
190
               printk(KERN_NOTICE "%s: Unsupported organizationally unique identifier 0x%02X-%02X-%02X.\n", dev->name, hdr->OUI[0], hdr->OUI[1], hdr->OUI[2]);
191
               dlp->stats.rx_errors++;
192
               break;
193
            }
194
 
195
            /* at this point, it's an EtherType frame */
196
            header = sizeof(struct frhdr);
197
            /* Already in network order ! */
198
            skb->protocol = hdr->PID;
199
            process = 1;
200
            break;
201
 
202
         case FRAD_P_IP:
203
            header = sizeof(hdr->control) + sizeof(hdr->IP_NLPID);
204
            skb->protocol = htons(ETH_P_IP);
205
            process = 1;
206
            break;
207
 
208
         case FRAD_P_SNAP:
209
         case FRAD_P_Q933:
210
         case FRAD_P_CLNP:
211
            printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->pad);
212
            dlp->stats.rx_errors++;
213
            break;
214
 
215
         default:
216
            printk(KERN_NOTICE "%s: Invalid pad byte 0x%02X.\n", dev->name, hdr->pad);
217
            dlp->stats.rx_errors++;
218
            break;
219
      }
220
 
221
   if (process)
222
   {
223
      /* we've set up the protocol, so discard the header */
224
      skb->mac.raw = skb->data;
225
      skb_pull(skb, header);
226
      netif_rx(skb);
227
      dlp->stats.rx_packets++;
228
   }
229
   else
230
      dev_kfree_skb(skb, FREE_WRITE);
231
}
232
 
233
static int dlci_transmit(struct sk_buff *skb, struct device *dev)
234
{
235
   struct dlci_local *dlp;
236
   int               ret;
237
 
238
   ret = 0;
239
 
240
   if (!skb || !dev)
241
      return(0);
242
 
243
   if (dev->tbusy)
244
      return(1);
245
 
246
   dlp = dev->priv;
247
 
248
   if (set_bit(0, (void*)&dev->tbusy) != 0)
249
      printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
250
   else
251
   {
252
      ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
253
      switch (ret)
254
      {
255
         case DLCI_RET_OK:
256
            dlp->stats.tx_packets++;
257
            ret = 0;
258
            break;
259
 
260
         case DLCI_RET_ERR:
261
            dlp->stats.tx_errors++;
262
            ret = 0;
263
            break;
264
 
265
         case DLCI_RET_DROP:
266
            dlp->stats.tx_dropped++;
267
            ret = 1;
268
            break;
269
      }
270
 
271
      /* Alan Cox recommends always returning 0, and always freeing the packet */
272
      /* experience suggest a slightly more conservative approach */
273
 
274
      if (!ret)
275
         dev_kfree_skb(skb, FREE_WRITE);
276
 
277
      dev->tbusy = 0;
278
   }
279
 
280
   return(ret);
281
}
282
 
283
int dlci_config(struct device *dev, struct dlci_conf *conf, int get)
284
{
285
   struct dlci_conf  config;
286
   struct dlci_local *dlp;
287
   struct frad_local *flp;
288
   int               err;
289
 
290
   dlp = dev->priv;
291
 
292
   flp = dlp->slave->priv;
293
 
294
   if (!get)
295
   {
296
      err = verify_area(VERIFY_READ, conf, sizeof(struct dlci_conf));
297
      if (err)
298
         return(err);
299
 
300
      memcpy_fromfs(&config, conf, sizeof(struct dlci_conf));
301
      if (config.flags & ~DLCI_VALID_FLAGS)
302
         return(-EINVAL);
303
      memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
304
      dlp->configured = 1;
305
   }
306
 
307
   err = (*flp->dlci_conf)(dlp->slave, dev, get);
308
   if (err)
309
      return(err);
310
 
311
   if (get)
312
   {
313
      err = verify_area(VERIFY_WRITE, conf, sizeof(struct dlci_conf));
314
      if (err)
315
         return(err);
316
 
317
      memcpy_tofs(conf, &dlp->config, sizeof(struct dlci_conf));
318
   }
319
 
320
   return(0);
321
}
322
 
323
int dlci_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
324
{
325
   struct dlci_local *dlp;
326
   int               err, len;
327
 
328
   if (!suser())
329
      return(-EPERM);
330
 
331
   dlp = dev->priv;
332
 
333
   switch(cmd)
334
   {
335
      case DLCI_GET_SLAVE:
336
         if (!*(short *)(dev->dev_addr))
337
            return(-EINVAL);
338
 
339
         len = strlen(dlp->slave->name) + 1;
340
         err = verify_area(VERIFY_WRITE, ifr->ifr_slave, len);
341
         if (err)
342
            return err;
343
 
344
         memcpy_tofs(ifr->ifr_slave, dlp->slave->name, len);
345
         break;
346
 
347
      case DLCI_GET_CONF:
348
      case DLCI_SET_CONF:
349
         if (!*(short *)(dev->dev_addr))
350
            return(-EINVAL);
351
 
352
         return(dlci_config(dev, (struct dlci_conf *) ifr->ifr_data, cmd == DLCI_GET_CONF));
353
         break;
354
 
355
      default:
356
         return(-EOPNOTSUPP);
357
   }
358
   return(0);
359
}
360
 
361
static int dlci_change_mtu(struct device *dev, int new_mtu)
362
{
363
   struct dlci_local *dlp;
364
 
365
   dlp = dev->priv;
366
 
367
   return((*dlp->slave->change_mtu)(dlp->slave, new_mtu));
368
}
369
 
370
static int dlci_open(struct device *dev)
371
{
372
   struct dlci_local *dlp;
373
   struct frad_local *flp;
374
   int               err;
375
 
376
   dlp = dev->priv;
377
 
378
   if (!*(short *)(dev->dev_addr))
379
      return(-EINVAL);
380
 
381
   if (!dlp->slave->start)
382
      return(-ENOTCONN);
383
 
384
   dev->flags = 0;
385
   dev->tbusy = 0;
386
   dev->interrupt = 0;
387
   dev->start = 1;
388
 
389
   flp = dlp->slave->priv;
390
   err = (*flp->activate)(dlp->slave, dev);
391
   if (err)
392
      return(err);
393
 
394
   return 0;
395
}
396
 
397
static int dlci_close(struct device *dev)
398
{
399
   struct dlci_local *dlp;
400
   struct frad_local *flp;
401
   int               err;
402
 
403
   dlp = dev->priv;
404
 
405
   flp = dlp->slave->priv;
406
   err = (*flp->deactivate)(dlp->slave, dev);
407
 
408
   dev->start = 0;
409
   dev->tbusy = 1;
410
 
411
   return 0;
412
}
413
 
414
static struct enet_statistics *dlci_get_stats(struct device *dev)
415
{
416
   struct dlci_local *dlp;
417
 
418
   dlp = dev->priv;
419
 
420
   return(&dlp->stats);
421
}
422
 
423
int dlci_add(struct dlci_add *dlci)
424
{
425
   struct device       *master, *slave;
426
   struct dlci_local   *dlp;
427
   struct frad_local   *flp;
428
   int                 err, i;
429
   char                buf[10];
430
 
431
   /* validate slave device */
432
   slave = dev_get(dlci->devname);
433
   if (!slave)
434
      return(-ENODEV);
435
 
436
   if (slave->type != ARPHRD_FRAD)
437
      return(-EINVAL);
438
 
439
   /* check for registration */
440
   for (i=0;i<sizeof(basename) / sizeof(char *); i++)
441
      if ((basename[i]) &&
442
          (strncmp(dlci->devname, basename[i], strlen(basename[i])) == 0) &&
443
          (strlen(dlci->devname) > strlen(basename[i])))
444
         break;
445
 
446
   if (i == sizeof(basename) / sizeof(char *))
447
      return(-EINVAL);
448
 
449
   /* check for too many open devices : should this be dynamic ? */
450
   for(i=0;i<CONFIG_DLCI_COUNT;i++)
451
      if (!open_dev[i])
452
         break;
453
 
454
   if (i == CONFIG_DLCI_COUNT)
455
      return(-ENOSPC);  /*  #### Alan: Comments on this?? */
456
 
457
   /* create device name */
458
   sprintf(buf, "%s%02i", devname, i);
459
 
460
   master = kmalloc(sizeof(*master), GFP_KERNEL);
461
   if (!master)
462
      return(-ENOMEM);
463
 
464
   memset(master, 0, sizeof(*master));
465
   master->name = kmalloc(strlen(buf) + 1, GFP_KERNEL);
466
 
467
   if (!master->name)
468
   {
469
      kfree(master);
470
      return(-ENOMEM);
471
   }
472
 
473
   strcpy(master->name, buf);
474
   master->init = dlci_init;
475
   master->flags = 0;
476
 
477
   err = register_netdev(master);
478
   if (err < 0)
479
   {
480
      kfree(master->name);
481
      kfree(master);
482
      return(err);
483
   }
484
 
485
   *(short *)(master->dev_addr) = dlci->dlci;
486
 
487
   dlp = (struct dlci_local *) master->priv;
488
   dlp->slave = slave;
489
 
490
   flp = slave->priv;
491
   err = flp ? (*flp->assoc)(slave, master) : -EINVAL;
492
   if (err < 0)
493
   {
494
      unregister_netdev(master);
495
      kfree(master->priv);
496
      kfree(master->name);
497
      kfree(master);
498
      return(err);
499
   }
500
 
501
   strcpy(dlci->devname, buf);
502
   open_dev[i] = master;
503
   MOD_INC_USE_COUNT;
504
   return(0);
505
}
506
 
507
int dlci_del(struct dlci_add *dlci)
508
{
509
   struct dlci_local *dlp;
510
   struct frad_local *flp;
511
   struct device     *master, *slave;
512
   int               i, err;
513
 
514
   /* validate slave device */
515
   master = dev_get(dlci->devname);
516
   if (!master)
517
      return(-ENODEV);
518
 
519
   if (master->start)
520
      return(-EBUSY);
521
 
522
   dlp = master->priv;
523
   slave = dlp->slave;
524
   flp = slave->priv;
525
 
526
   err = (*flp->deassoc)(slave, master);
527
   if (err)
528
      return(err);
529
 
530
   unregister_netdev(master);
531
 
532
   for(i=0;i<CONFIG_DLCI_COUNT;i++)
533
      if (master == open_dev[i])
534
         break;
535
 
536
   if (i<CONFIG_DLCI_COUNT)
537
      open_dev[i] = NULL;
538
 
539
   kfree(master->priv);
540
   kfree(master->name);
541
   kfree(master);
542
 
543
   MOD_DEC_USE_COUNT;
544
 
545
   return(0);
546
}
547
 
548
int dlci_ioctl(unsigned int cmd, void *arg)
549
{
550
   int             err;
551
   struct dlci_add add;
552
 
553
   if (!suser())
554
      return(-EPERM);
555
 
556
   err=verify_area(VERIFY_READ, arg, sizeof(struct dlci_add));
557
   if (err)
558
      return(err);
559
 
560
   memcpy_fromfs(&add, arg, sizeof(struct dlci_add));
561
 
562
   switch (cmd)
563
   {
564
      case SIOCADDDLCI:
565
         err = verify_area(VERIFY_WRITE, arg, sizeof(struct dlci_add));
566
         if (err)
567
            return(err);
568
 
569
         err = dlci_add(&add);
570
 
571
         if (!err)
572
            memcpy_tofs(arg, &add, sizeof(struct dlci_add));
573
         break;
574
 
575
      case SIOCDELDLCI:
576
         err = dlci_del(&add);
577
         break;
578
 
579
      default:
580
         err = -EINVAL;
581
   }
582
 
583
   return(err);
584
}
585
 
586
int dlci_init(struct device *dev)
587
{
588
   struct dlci_local *dlp;
589
   int i;
590
 
591
   dev->priv = kmalloc(sizeof(struct dlci_local), GFP_KERNEL);
592
   if (!dev->priv)
593
      return(-ENOMEM);
594
 
595
   memset(dev->priv, 0, sizeof(struct dlci_local));
596
   dlp = dev->priv;
597
 
598
   dev->flags           = 0;
599
   dev->open            = dlci_open;
600
   dev->stop            = dlci_close;
601
   dev->do_ioctl        = dlci_dev_ioctl;
602
   dev->hard_start_xmit = dlci_transmit;
603
   dev->hard_header     = dlci_header;
604
   dev->get_stats       = dlci_get_stats;
605
   dev->change_mtu      = dlci_change_mtu;
606
 
607
   dlp->receive         = dlci_receive;
608
 
609
   dev->type            = ARPHRD_DLCI;
610
   dev->family          = AF_INET;
611
   dev->hard_header_len = sizeof(struct frhdr);
612
   dev->pa_alen         = sizeof(unsigned long);
613
   dev->addr_len        = sizeof(short);
614
   memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
615
 
616
   dev->pa_addr         = 0;
617
   dev->pa_dstaddr      = 0;
618
   dev->pa_brdaddr      = 0;
619
   dev->pa_mask         = 0;
620
 
621
   for (i = 0; i < DEV_NUMBUFFS; i++)
622
      skb_queue_head_init(&dev->buffs[i]);
623
 
624
   return(0);
625
}
626
 
627
int dlci_setup(void)
628
{
629
   int i;
630
 
631
   printk("%s.\n", version);
632
 
633
   for(i=0;i<CONFIG_DLCI_COUNT;i++)
634
      open_dev[i] = NULL;
635
 
636
   for(i=0;i<sizeof(basename) / sizeof(char *);i++)
637
      basename[i] = NULL;
638
 
639
   return(0);
640
}
641
 
642
#ifdef MODULE
643
 
644
extern int (*dlci_ioctl_hook)(unsigned int, void *);
645
 
646
int init_module(void)
647
{
648
   dlci_ioctl_hook = dlci_ioctl;
649
 
650
   return(dlci_setup());
651
}
652
 
653
void cleanup_module(void)
654
{
655
   dlci_ioctl_hook = NULL;
656
}
657
#endif /* MODULE */

powered by: WebSVN 2.1.0

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