root/drivers/net/dlci.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. register_frad
  2. unregister_frad
  3. dlci_header
  4. dlci_receive
  5. dlci_transmit
  6. dlci_add
  7. dlci_del
  8. dlci_config
  9. dlci_ioctl
  10. dlci_change_mtu
  11. dlci_open
  12. dlci_close
  13. dlci_get_stats
  14. dlci_init
  15. dlci_setup
  16. init_module
  17. cleanup_module

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

/* [previous][next][first][last][top][bottom][index][help] */