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.
 
   8  * Version:     @(#)dlci.c      0.35    4 Jan 1997
 
  10  * Author:      Mike McLagan <mike.mclagan@linux.org>
 
  14  *              0.15    Mike Mclagan    Packet freeing, bug in kmalloc call
 
  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
 
  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.
 
  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>
 
  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>
 
  51 #include <asm/system.h>
 
  54 #include <asm/uaccess.h>
 
  56 static const char version[] = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
 
  58 static LIST_HEAD(dlci_devs);
 
  60 static void dlci_setup(struct net_device *);
 
  63  * these encapsulate the RFC 1490 requirements as well as 
 
  64  * deal with packet transmission and reception, working with
 
  65  * the upper network layers 
 
  68 static int dlci_header(struct sk_buff *skb, struct net_device *dev, 
 
  69                            unsigned short type, void *daddr, void *saddr, 
 
  73         struct dlci_local       *dlp;
 
  79         hdr.control = FRAD_I_UI;
 
  83                         hdr.IP_NLPID = FRAD_P_IP;
 
  84                         hlen = sizeof(hdr.control) + sizeof(hdr.IP_NLPID);
 
  87                 /* feel free to add other types, if necessary */
 
  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);
 
  98         dest = skb_push(skb, hlen);
 
 102         memcpy(dest, &hdr, hlen);
 
 107 static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
 
 109         struct dlci_local *dlp;
 
 114         if (!pskb_may_pull(skb, sizeof(*hdr))) {
 
 115                 printk(KERN_NOTICE "%s: invalid data no header\n",
 
 117                 dlp->stats.rx_errors++;
 
 122         hdr = (struct frhdr *) skb->data;
 
 127         if (hdr->control != FRAD_I_UI)
 
 129                 printk(KERN_NOTICE "%s: Invalid header flag 0x%02X.\n", dev->name, hdr->control);
 
 130                 dlp->stats.rx_errors++;
 
 133                 switch(hdr->IP_NLPID)
 
 136                                 if (hdr->NLPID != FRAD_P_SNAP)
 
 138                                         printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->NLPID);
 
 139                                         dlp->stats.rx_errors++;
 
 143                                 if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0)
 
 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++;
 
 150                                 /* at this point, it's an EtherType frame */
 
 151                                 header = sizeof(struct frhdr);
 
 152                                 /* Already in network order ! */
 
 153                                 skb->protocol = hdr->PID;
 
 158                                 header = sizeof(hdr->control) + sizeof(hdr->IP_NLPID);
 
 159                                 skb->protocol = htons(ETH_P_IP);
 
 166                                 printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->pad);
 
 167                                 dlp->stats.rx_errors++;
 
 171                                 printk(KERN_NOTICE "%s: Invalid pad byte 0x%02X.\n", dev->name, hdr->pad);
 
 172                                 dlp->stats.rx_errors++;
 
 178                 /* we've set up the protocol, so discard the header */
 
 179                 skb->mac.raw = skb->data; 
 
 180                 skb_pull(skb, header);
 
 181                 dlp->stats.rx_bytes += skb->len;
 
 183                 dlp->stats.rx_packets++;
 
 184                 dev->last_rx = jiffies;
 
 190 static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
 
 192         struct dlci_local *dlp;
 
 202         netif_stop_queue(dev);
 
 204         ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
 
 208                         dlp->stats.tx_packets++;
 
 212                         dlp->stats.tx_errors++;
 
 216                         dlp->stats.tx_dropped++;
 
 220         /* Alan Cox recommends always returning 0, and always freeing the packet */
 
 221         /* experience suggest a slightly more conservative approach */
 
 226                 netif_wake_queue(dev);
 
 231 static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, int get)
 
 233         struct dlci_conf        config;
 
 234         struct dlci_local       *dlp;
 
 235         struct frad_local       *flp;
 
 240         flp = dlp->slave->priv;
 
 244                 if(copy_from_user(&config, conf, sizeof(struct dlci_conf)))
 
 246                 if (config.flags & ~DLCI_VALID_FLAGS)
 
 248                 memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
 
 252         err = (*flp->dlci_conf)(dlp->slave, dev, get);
 
 258                 if(copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf)))
 
 265 static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
 267         struct dlci_local *dlp;
 
 269         if (!capable(CAP_NET_ADMIN))
 
 277                         if (!*(short *)(dev->dev_addr))
 
 280                         strncpy(ifr->ifr_slave, dlp->slave->name, sizeof(ifr->ifr_slave));
 
 285                         if (!*(short *)(dev->dev_addr))
 
 288                         return(dlci_config(dev, ifr->ifr_data, cmd == DLCI_GET_CONF));
 
 297 static int dlci_change_mtu(struct net_device *dev, int new_mtu)
 
 299         struct dlci_local *dlp;
 
 303         return((*dlp->slave->change_mtu)(dlp->slave, new_mtu));
 
 306 static int dlci_open(struct net_device *dev)
 
 308         struct dlci_local       *dlp;
 
 309         struct frad_local       *flp;
 
 314         if (!*(short *)(dev->dev_addr))
 
 317         if (!netif_running(dlp->slave))
 
 320         flp = dlp->slave->priv;
 
 321         err = (*flp->activate)(dlp->slave, dev);
 
 325         netif_start_queue(dev);
 
 330 static int dlci_close(struct net_device *dev)
 
 332         struct dlci_local       *dlp;
 
 333         struct frad_local       *flp;
 
 336         netif_stop_queue(dev);
 
 340         flp = dlp->slave->priv;
 
 341         err = (*flp->deactivate)(dlp->slave, dev);
 
 346 static struct net_device_stats *dlci_get_stats(struct net_device *dev)
 
 348         struct dlci_local *dlp;
 
 355 static int dlci_add(struct dlci_add *dlci)
 
 357         struct net_device       *master, *slave;
 
 358         struct dlci_local       *dlp;
 
 359         struct frad_local       *flp;
 
 363         /* validate slave device */
 
 364         slave = dev_get_by_name(dlci->devname);
 
 368         if (slave->type != ARPHRD_FRAD || slave->priv == NULL)
 
 371         /* create device name */
 
 372         master = alloc_netdev( sizeof(struct dlci_local), "dlci%d",
 
 379         /* make sure same slave not already registered */
 
 381         list_for_each_entry(dlp, &dlci_devs, list) {
 
 382                 if (dlp->slave == slave) {
 
 388         err = dev_alloc_name(master, master->name);
 
 392         *(short *)(master->dev_addr) = dlci->dlci;
 
 394         dlp = (struct dlci_local *) master->priv;
 
 396         dlp->master = master;
 
 399         err = (*flp->assoc)(slave, master);
 
 403         err = register_netdevice(master);
 
 407         strcpy(dlci->devname, master->name);
 
 409         list_add(&dlp->list, &dlci_devs);
 
 422 static int dlci_del(struct dlci_add *dlci)
 
 424         struct dlci_local       *dlp;
 
 425         struct frad_local       *flp;
 
 426         struct net_device       *master, *slave;
 
 429         /* validate slave device */
 
 430         master = __dev_get_by_name(dlci->devname);
 
 434         if (netif_running(master)) {
 
 443         err = (*flp->deassoc)(slave, master);
 
 445                 list_del(&dlp->list);
 
 447                 unregister_netdevice(master);
 
 456 static int dlci_ioctl(unsigned int cmd, void __user *arg)
 
 461         if (!capable(CAP_NET_ADMIN))
 
 464         if(copy_from_user(&add, arg, sizeof(struct dlci_add)))
 
 470                         err = dlci_add(&add);
 
 473                                 if(copy_to_user(arg, &add, sizeof(struct dlci_add)))
 
 478                         err = dlci_del(&add);
 
 488 static void dlci_setup(struct net_device *dev)
 
 490         struct dlci_local *dlp = dev->priv;
 
 493         dev->open               = dlci_open;
 
 494         dev->stop               = dlci_close;
 
 495         dev->do_ioctl           = dlci_dev_ioctl;
 
 496         dev->hard_start_xmit    = dlci_transmit;
 
 497         dev->hard_header        = dlci_header;
 
 498         dev->get_stats          = dlci_get_stats;
 
 499         dev->change_mtu         = dlci_change_mtu;
 
 500         dev->destructor         = free_netdev;
 
 502         dlp->receive            = dlci_receive;
 
 504         dev->type               = ARPHRD_DLCI;
 
 505         dev->hard_header_len    = sizeof(struct frhdr);
 
 506         dev->addr_len           = sizeof(short);
 
 510 /* if slave is unregistering, then cleanup master */
 
 511 static int dlci_dev_event(struct notifier_block *unused,
 
 512                           unsigned long event, void *ptr)
 
 514         struct net_device *dev = (struct net_device *) ptr;
 
 516         if (event == NETDEV_UNREGISTER) {
 
 517                 struct dlci_local *dlp;
 
 519                 list_for_each_entry(dlp, &dlci_devs, list) {
 
 520                         if (dlp->slave == dev) {
 
 521                                 list_del(&dlp->list);
 
 522                                 unregister_netdevice(dlp->master);
 
 531 static struct notifier_block dlci_notifier = {
 
 532         .notifier_call = dlci_dev_event,
 
 535 static int __init init_dlci(void)
 
 537         dlci_ioctl_set(dlci_ioctl);
 
 538         register_netdevice_notifier(&dlci_notifier);
 
 540         printk("%s.\n", version);
 
 545 static void __exit dlci_exit(void)
 
 547         struct dlci_local       *dlp, *nxt;
 
 549         dlci_ioctl_set(NULL);
 
 550         unregister_netdevice_notifier(&dlci_notifier);
 
 553         list_for_each_entry_safe(dlp, nxt, &dlci_devs, list) {
 
 554                 unregister_netdevice(dlp->master);
 
 560 module_init(init_dlci);
 
 561 module_exit(dlci_exit);
 
 563 MODULE_AUTHOR("Mike McLagan");
 
 564 MODULE_DESCRIPTION("Frame Relay DLCI layer");
 
 565 MODULE_LICENSE("GPL");