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

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