root/drivers/net/slip.c

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

DEFINITIONS

This source file includes following definitions.
  1. sl_alloc
  2. sl_free
  3. sl_changedmtu
  4. sl_lock
  5. sl_unlock
  6. sl_bump
  7. sl_encaps
  8. slip_write_wakeup
  9. sl_xmit
  10. sl_header
  11. sl_rebuild_header
  12. sl_open
  13. sl_close
  14. slip_receive_room
  15. slip_receive_buf
  16. slip_open
  17. slip_close
  18. sl_get_stats
  19. slip_esc
  20. slip_unesc
  21. slip_esc6
  22. slip_unesc6
  23. sl_set_mac_address
  24. sl_set_dev_mac_address
  25. sl_get_ax25_mode
  26. slip_ioctl
  27. sl_open_dev
  28. slip_init
  29. init_module
  30. cleanup_module

   1 /*
   2  * slip.c       This module implements the SLIP protocol for kernel-based
   3  *              devices like TTY.  It interfaces between a raw TTY, and the
   4  *              kernel's INET protocol layers.
   5  *
   6  * Version:     @(#)slip.c      0.8.3   12/24/94
   7  *
   8  * Authors:     Laurence Culhane, <loz@holmes.demon.co.uk>
   9  *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  10  *
  11  * Fixes:
  12  *              Alan Cox        :       Sanity checks and avoid tx overruns.
  13  *                                      Has a new sl->mtu field.
  14  *              Alan Cox        :       Found cause of overrun. ifconfig sl0 mtu upwards.
  15  *                                      Driver now spots this and grows/shrinks its buffers(hack!).
  16  *                                      Memory leak if you run out of memory setting up a slip driver fixed.
  17  *              Matt Dillon     :       Printable slip (borrowed from NET2E)
  18  *      Pauline Middelink       :       Slip driver fixes.
  19  *              Alan Cox        :       Honours the old SL_COMPRESSED flag
  20  *              Alan Cox        :       KISS AX.25 and AXUI IP support
  21  *              Michael Riepe   :       Automatic CSLIP recognition added
  22  *              Charles Hedrick :       CSLIP header length problem fix.
  23  *              Alan Cox        :       Corrected non-IP cases of the above.
  24  *              Alan Cox        :       Now uses hardware type as per FvK.
  25  *              Alan Cox        :       Default to 192.168.0.0 (RFC 1597)
  26  *              A.N.Kuznetsov   :       dev_tint() recursion fix.
  27  *      Dmitry Gorodchanin      :       SLIP memory leaks
  28  *      Dmitry Gorodchanin      :       Code cleanup. Reduce tty driver
  29  *                                      buffering from 4096 to 256 bytes.
  30  *                                      Improving SLIP response time.
  31  *                                      CONFIG_SLIP_MODE_SLIP6.
  32  *                                      ifconfig sl? up & down now works correctly.
  33  *                                      Modularization.
  34  *              Alan Cox        :       Oops - fix AX.25 buffer lengths
  35  *      Dmitry Gorodchanin      :       Even more cleanups. Preserve CSLIP
  36  *                                      statistics. Include CSLIP code only
  37  *                                      if it really needed.
  38  *              Alan Cox        :       Free slhc buffers in the right place.
  39  *
  40  *
  41  *
  42  *      FIXME:  This driver still makes some IP'ish assumptions. It should build cleanly KISS TNC only without
  43  *      CONFIG_INET defined.
  44  *      I hope now it is fixed ;)
  45  */
  46 
  47 #define SL_CHECK_TRANSMIT
  48 #include <linux/config.h>
  49 #ifdef MODULE
  50 #include <linux/module.h>
  51 #include <linux/version.h>
  52 #endif
  53 
  54 /* Undef this, if you don't need 6bit encapsulation code in the driver */
  55 #define CONFIG_SLIP_MODE_SLIP6
  56 
  57 #include <asm/system.h>
  58 #include <asm/segment.h>
  59 #include <asm/bitops.h>
  60 #include <linux/string.h>
  61 #include <linux/mm.h>
  62 #include <linux/interrupt.h>
  63 #include <linux/in.h>
  64 #include <linux/tty.h>
  65 #include <linux/errno.h>
  66 #include <linux/netdevice.h>
  67 #ifdef CONFIG_AX25
  68 #include <linux/timer.h>
  69 #include <net/ax25.h>
  70 #endif
  71 #include <linux/etherdevice.h>
  72 #include <linux/skbuff.h>
  73 #include <linux/if_arp.h>
  74 #include "slip.h"
  75 #ifdef CONFIG_INET
  76 #include <linux/ip.h>
  77 #include <linux/tcp.h>
  78 #include "slhc.h"
  79 #endif
  80 
  81 #ifdef MODULE
  82 #define SLIP_VERSION    "0.8.3-NET3.019-NEWTTY-MODULAR"
  83 #else
  84 #define SLIP_VERSION    "0.8.3-NET3.019-NEWTTY"
  85 #endif
  86 
  87 
  88 static struct slip      sl_ctrl[SL_NRUNIT];
  89 static struct tty_ldisc sl_ldisc;
  90 static int              already = 0;
  91 
  92 static int slip_esc(unsigned char *p, unsigned char *d, int len);
  93 static void slip_unesc(struct slip *sl, unsigned char c);
  94 #ifdef CONFIG_SLIP_MODE_SLIP6
  95 static int slip_esc6(unsigned char *p, unsigned char *d, int len);
  96 static void slip_unesc6(struct slip *sl, unsigned char c);
  97 #endif
  98 
  99 
 100 /* Find a free SLIP channel, and link in this `tty' line. */
 101 static inline struct slip *
 102 sl_alloc(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104         struct slip *sl;
 105         int i;
 106 
 107         for (i = 0; i < SL_NRUNIT; i++) {
 108                 sl = &sl_ctrl[i];
 109                 if (!set_bit(SLF_INUSE, &sl->flags)) {
 110                         return sl;
 111                 }
 112         }
 113         return NULL;
 114 }
 115 
 116 
 117 /* Free a SLIP channel. */
 118 static inline void
 119 sl_free(struct slip *sl)
     /* [previous][next][first][last][top][bottom][index][help] */
 120 {
 121         /* Free all SLIP frame buffers. */
 122         if (sl->rbuff)  {
 123                 kfree(sl->rbuff);
 124         }
 125         sl->rbuff = NULL;
 126         if (sl->xbuff)  {
 127                 kfree(sl->xbuff);
 128         }
 129         sl->xbuff = NULL;
 130 #ifdef SL_INCLUDE_CSLIP
 131         /* Save CSLIP statistics */
 132         if (sl->slcomp)  {
 133                 sl->rx_compressed += sl->slcomp->sls_i_compressed;
 134                 sl->rx_dropped    += sl->slcomp->sls_i_tossed;
 135                 sl->tx_compressed += sl->slcomp->sls_o_compressed;
 136                 sl->tx_misses     += sl->slcomp->sls_o_misses;
 137         }
 138         if (sl->cbuff)  {
 139                 kfree(sl->cbuff);
 140         }
 141         sl->cbuff = NULL;
 142         if(sl->slcomp)
 143                 slhc_free(sl->slcomp);
 144         sl->slcomp = NULL;
 145 #endif
 146 
 147         if (!clear_bit(SLF_INUSE, &sl->flags)) {
 148                 printk("%s: sl_free for already free unit.\n", sl->dev->name);
 149         }
 150 }
 151 
 152 /* MTU has been changed by the IP layer. Unfortunately we are not told about this, but
 153    we spot it ourselves and fix things up. We could be in an upcall from the tty
 154    driver, or in an ip packet queue. */
 155 
 156 static void sl_changedmtu(struct slip *sl)
     /* [previous][next][first][last][top][bottom][index][help] */
 157 {
 158         struct device *dev = sl->dev;
 159         unsigned char *xbuff, *rbuff, *oxbuff, *orbuff;
 160 #ifdef SL_INCLUDE_CSLIP
 161         unsigned char *cbuff, *ocbuff;
 162 #endif
 163         int len;
 164         unsigned long flags;
 165 
 166         len = dev->mtu * 2;
 167 /*
 168  * allow for arrival of larger UDP packets, even if we say not to
 169  * also fixes a bug in which SunOS sends 512-byte packets even with
 170  * an MSS of 128
 171  */
 172         if (len < 576 * 2)  {
 173                 len = 576 * 2;
 174         }
 175 
 176         xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
 177         rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
 178 #ifdef SL_INCLUDE_CSLIP
 179         cbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
 180 #endif
 181 
 182 #ifdef SL_INCLUDE_CSLIP
 183         if (xbuff == NULL || rbuff == NULL || cbuff == NULL)  {
 184 #else
 185         if (xbuff == NULL || rbuff == NULL)  {
 186 #endif
 187                 printk("%s: unable to grow slip buffers, MTU change cancelled.\n",
 188                        sl->dev->name);
 189                 dev->mtu = sl->mtu;
 190                 if (xbuff != NULL)  {
 191                         kfree(xbuff);
 192                 }
 193                 if (rbuff != NULL)  {
 194                         kfree(rbuff);
 195                 }
 196 #ifdef SL_INCLUDE_CSLIP
 197                 if (cbuff != NULL)  {
 198                         kfree(cbuff);
 199                 }
 200 #endif
 201                 return;
 202         }
 203 
 204         save_flags(flags); cli();
 205 
 206         oxbuff    = sl->xbuff;
 207         sl->xbuff = xbuff;
 208         orbuff    = sl->rbuff;
 209         sl->rbuff = rbuff;
 210 #ifdef SL_INCLUDE_CSLIP
 211         ocbuff    = sl->cbuff;
 212         sl->cbuff = cbuff;
 213 #endif
 214         if (sl->xleft)  {
 215                 if (sl->xleft <= len)  {
 216                         memcpy(sl->xbuff, sl->xhead, sl->xleft);
 217                 } else  {
 218                         sl->xleft = 0;
 219                         sl->tx_dropped++;
 220                 }
 221         }
 222         sl->xhead = sl->xbuff;
 223 
 224         if (sl->rcount)  {
 225                 if (sl->rcount <= len) {
 226                         memcpy(sl->rbuff, orbuff, sl->rcount);
 227                 } else  {
 228                         sl->rcount = 0;
 229                         sl->rx_over_errors++;
 230                         set_bit(SLF_ERROR, &sl->flags);
 231                 }
 232         }
 233 #ifdef CONFIG_AX25
 234         sl->mtu      = dev->mtu + 73;
 235 #else
 236         sl->mtu      = dev->mtu;
 237 #endif
 238         sl->buffsize = len;
 239 
 240         restore_flags(flags);
 241 
 242         if (oxbuff != NULL)   {
 243                 kfree(oxbuff);
 244         }
 245         if (orbuff != NULL)    {
 246                 kfree(orbuff);
 247         }
 248 #ifdef SL_INCLUDE_CSLIP
 249         if (ocbuff != NULL)  {
 250                 kfree(ocbuff);
 251         }
 252 #endif
 253 }
 254 
 255 
 256 /* Set the "sending" flag.  This must be atomic, hence the ASM. */
 257 static inline void
 258 sl_lock(struct slip *sl)
     /* [previous][next][first][last][top][bottom][index][help] */
 259 {
 260         if (set_bit(0, (void *) &sl->dev->tbusy))  {
 261                 printk("%s: trying to lock already locked device!\n", sl->dev->name);
 262         }
 263 }
 264 
 265 
 266 /* Clear the "sending" flag.  This must be atomic, hence the ASM. */
 267 static inline void
 268 sl_unlock(struct slip *sl)
     /* [previous][next][first][last][top][bottom][index][help] */
 269 {
 270         if (!clear_bit(0, (void *)&sl->dev->tbusy))  {
 271                 printk("%s: trying to unlock already unlocked device!\n", sl->dev->name);
 272         }
 273 }
 274 
 275 /* Send one completely decapsulated IP datagram to the IP layer. */
 276 static void
 277 sl_bump(struct slip *sl)
     /* [previous][next][first][last][top][bottom][index][help] */
 278 {
 279         struct sk_buff *skb;
 280         int count;
 281 
 282         count = sl->rcount;
 283 #ifdef SL_INCLUDE_CSLIP
 284         if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) {
 285                 unsigned char c;
 286                 if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) {
 287                         /* ignore compressed packets when CSLIP is off */
 288                         if (!(sl->mode & SL_MODE_CSLIP)) {
 289                                 printk("%s: compressed packet ignored\n", sl->dev->name);
 290                                 return;
 291                         }
 292                         /* make sure we've reserved enough space for uncompress to use */
 293                         if (count + 80 > sl->buffsize) {
 294                                 sl->rx_over_errors++;
 295                                 return;
 296                         }
 297                         count = slhc_uncompress(sl->slcomp, sl->rbuff, count);
 298                         if (count <= 0) {
 299                                 return;
 300                         }
 301                 } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) {
 302                         if (!(sl->mode & SL_MODE_CSLIP)) {
 303                                 /* turn on header compression */
 304                                 sl->mode |= SL_MODE_CSLIP;
 305                                 sl->mode &= ~SL_MODE_ADAPTIVE;
 306                                 printk("%s: header compression turned on\n", sl->dev->name);
 307                         }
 308                         sl->rbuff[0] &= 0x4f;
 309                         if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) {
 310                                 return;
 311                         }
 312                 }
 313         }
 314 #endif  /* SL_INCLUDE_CSLIP */
 315 
 316         skb = dev_alloc_skb(count);
 317         if (skb == NULL)  {
 318                 printk("%s: memory squeeze, dropping packet.\n", sl->dev->name);
 319                 sl->rx_dropped++;
 320                 return;
 321         }
 322         skb->dev = sl->dev;
 323         memcpy(skb_put(skb,count), sl->rbuff, count);
 324         skb->mac.raw=skb->data;
 325         if(sl->mode&(SL_MODE_AX25|SL_MODE_AX25VC))
 326                 skb->protocol=htons(ETH_P_AX25);
 327         else
 328                 skb->protocol=htons(ETH_P_IP);
 329         netif_rx(skb);
 330         sl->rx_packets++;
 331 }
 332 
 333 /* Encapsulate one IP datagram and stuff into a TTY queue. */
 334 static void
 335 sl_encaps(struct slip *sl, unsigned char *icp, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 336 {
 337         unsigned char *p;
 338         int actual, count;
 339 
 340 
 341 #ifdef CONFIG_AX25
 342         if (sl->mtu != sl->dev->mtu + 73) {     /* Someone has been ifconfigging */
 343 #else
 344         if (sl->mtu != sl->dev->mtu) {  /* Someone has been ifconfigging */
 345 #endif
 346                 sl_changedmtu(sl);
 347         }
 348 
 349         if (len > sl->mtu) {            /* Sigh, shouldn't occur BUT ... */
 350                 len = sl->mtu;
 351                 printk ("%s: truncating oversized transmit packet!\n", sl->dev->name);
 352                 sl->tx_dropped++;
 353                 sl_unlock(sl);
 354                 return;
 355         }
 356 
 357         p = icp;
 358 #ifdef SL_INCLUDE_CSLIP
 359         if (sl->mode & SL_MODE_CSLIP)  {
 360                 len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1);
 361         }
 362 #endif
 363 #ifdef CONFIG_SLIP_MODE_SLIP6
 364         if(sl->mode & SL_MODE_SLIP6)
 365                 count = slip_esc6(p, (unsigned char *) sl->xbuff, len);
 366         else
 367 #endif
 368                 count = slip_esc(p, (unsigned char *) sl->xbuff, len);
 369 
 370         /* Order of next two lines is *very* important.
 371          * When we are sending a little amount of data,
 372          * the transfer may be completed inside driver.write()
 373          * routine, because it's running with interrupts enabled.
 374          * In this case we *never* got WRITE_WAKEUP event,
 375          * if we did not request it before write operation.
 376          *       14 Oct 1994  Dmitry Gorodchanin.
 377          */
 378         sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
 379         actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count);
 380 #ifdef SL_CHECK_TRANSMIT
 381         sl->dev->trans_start = jiffies;
 382 #endif
 383         sl->xleft = count - actual;
 384         sl->xhead = sl->xbuff + actual;
 385 }
 386 
 387 /*
 388  * Called by the driver when there's room for more data.  If we have
 389  * more packets to send, we send them here.
 390  */
 391 static void slip_write_wakeup(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 392 {
 393         int actual;
 394         struct slip *sl = (struct slip *) tty->disc_data;
 395 
 396         /* First make sure we're connected. */
 397         if (!sl || sl->magic != SLIP_MAGIC || !sl->dev->start) {
 398                 return;
 399         }
 400 
 401         if (sl->xleft <= 0)  {
 402                 /* Now serial buffer is almost free & we can start
 403                  * transmission of another packet */
 404                 sl->tx_packets++;
 405                 tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 406                 sl_unlock(sl);
 407                 mark_bh(NET_BH);
 408                 return;
 409         }
 410 
 411         actual = tty->driver.write(tty, 0, sl->xhead, sl->xleft);
 412         sl->xleft -= actual;
 413         sl->xhead += actual;
 414 }
 415 
 416 /* Encapsulate an IP datagram and kick it into a TTY queue. */
 417 static int
 418 sl_xmit(struct sk_buff *skb, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 419 {
 420         struct slip *sl = &sl_ctrl[dev->base_addr];
 421 
 422         if (!dev->start)  {
 423                 printk("%s: xmit call when iface is down\n", dev->name);
 424                 return 1;
 425         }
 426         /*
 427          * If we are busy already- too bad.  We ought to be able
 428          * to queue things at this point, to allow for a little
 429          * frame buffer.  Oh well...
 430          * -----------------------------------------------------
 431          * I hate queues in SLIP driver. May be it's efficient,
 432          * but for me latency is more important. ;)
 433          * So, no queues !
 434          *        14 Oct 1994  Dmitry Gorodchanin.
 435          */
 436         if (dev->tbusy) {
 437                 /* May be we must check transmitter timeout here ?
 438                  *      14 Oct 1994 Dmitry Gorodchanin.
 439                  */
 440 #ifdef SL_CHECK_TRANSMIT
 441                 if (jiffies - dev->trans_start  < 20 * HZ)  {
 442                         /* 20 sec timeout not reached */
 443                         return 1;
 444                 }
 445                 printk("%s: transmit timed out, %s?\n", dev->name,
 446                        (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ?
 447                        "bad line quality" : "driver error");
 448                 sl->xleft = 0;
 449                 sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 450                 sl_unlock(sl);
 451 #else
 452                 return 1;
 453 #endif
 454         }
 455 
 456         /* We were not busy, so we are now... :-) */
 457         if (skb != NULL) {
 458                 sl_lock(sl);
 459                 sl_encaps(sl, skb->data, skb->len);
 460                 dev_kfree_skb(skb, FREE_WRITE);
 461         }
 462         return 0;
 463 }
 464 
 465 
 466 /* Return the frame type ID.  This is normally IP but maybe be AX.25. */
 467 
 468 /* Fill in the MAC-level header. Not used by SLIP. */
 469 static int
 470 sl_header(struct sk_buff *skb, struct device *dev, unsigned short type,
     /* [previous][next][first][last][top][bottom][index][help] */
 471           void *daddr, void *saddr, unsigned len)
 472 {
 473 #ifdef CONFIG_AX25
 474 #ifdef CONFIG_INET
 475         struct slip *sl = &sl_ctrl[dev->base_addr];
 476 
 477         if (((sl->mode & SL_MODE_AX25) || (sl->mode & SL_MODE_AX25VC)) && type != htons(ETH_P_AX25))  {
 478                 return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
 479         }
 480 #endif
 481 #endif
 482         return 0;
 483 }
 484 
 485 
 486 /* Rebuild the MAC-level header.  Not used by SLIP. */
 487 static int
 488 sl_rebuild_header(void *buff, struct device *dev, unsigned long raddr,
     /* [previous][next][first][last][top][bottom][index][help] */
 489                   struct sk_buff *skb)
 490 {
 491 #ifdef CONFIG_AX25
 492 #ifdef CONFIG_INET
 493         struct slip *sl = &sl_ctrl[dev->base_addr];
 494 
 495         if ((sl->mode & SL_MODE_AX25) || (sl->mode & SL_MODE_AX25VC)) {
 496                 return ax25_rebuild_header(buff, dev, raddr, skb);
 497         }
 498 #endif
 499 #endif
 500         return 0;
 501 }
 502 
 503 
 504 /* Open the low-level part of the SLIP channel. Easy! */
 505 static int
 506 sl_open(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 507 {
 508         struct slip *sl = &sl_ctrl[dev->base_addr];
 509         unsigned long len;
 510 
 511         if (sl->tty == NULL) {
 512                 return -ENODEV;
 513         }
 514 
 515         /*
 516          * Allocate the SLIP frame buffers:
 517          *
 518          * rbuff        Receive buffer.
 519          * xbuff        Transmit buffer.
 520          * cbuff        Temporary compression buffer.
 521          */
 522         len = dev->mtu * 2;
 523         /*
 524          * allow for arrival of larger UDP packets, even if we say not to
 525          * also fixes a bug in which SunOS sends 512-byte packets even with
 526          * an MSS of 128
 527          */
 528         if (len < 576 * 2)  {
 529                 len = 576 * 2;
 530         }
 531         sl->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
 532         if (sl->rbuff == NULL)   {
 533                 goto norbuff;
 534         }
 535         sl->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
 536         if (sl->xbuff == NULL)   {
 537                 goto noxbuff;
 538         }
 539 #ifdef SL_INCLUDE_CSLIP
 540         sl->cbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
 541         if (sl->cbuff == NULL)   {
 542                 goto nocbuff;
 543         }
 544         sl->slcomp = slhc_init(16, 16);
 545         if (sl->slcomp == NULL)  {
 546                 goto noslcomp;
 547         }
 548 #endif
 549 
 550 #ifdef CONFIG_AX25
 551         sl->mtu      = dev->mtu + 73;
 552 #else
 553         sl->mtu      = dev->mtu;
 554 #endif
 555         sl->buffsize = len;
 556         sl->rcount   = 0;
 557         sl->xleft    = 0;
 558 #ifdef CONFIG_SLIP_MODE_SLIP6
 559         sl->xdata    = 0;
 560         sl->xbits    = 0;
 561 #endif
 562         sl->flags   &= (1 << SLF_INUSE);      /* Clear ESCAPE & ERROR flags */
 563 
 564         /* Needed because address '0' is special */
 565         if (dev->pa_addr == 0)  {
 566                 dev->pa_addr=ntohl(0xC0A80001);
 567         }
 568         dev->tbusy  = 0;
 569 /*      dev->flags |= IFF_UP; */
 570         dev->start  = 1;
 571 
 572         return 0;
 573 
 574         /* Cleanup */
 575 #ifdef SL_INCLUDE_CSLIP
 576 noslcomp:
 577         kfree(sl->cbuff);
 578 nocbuff:
 579 #endif
 580         kfree(sl->xbuff);
 581 noxbuff:
 582         kfree(sl->rbuff);
 583 norbuff:
 584         return -ENOMEM;
 585 }
 586 
 587 
 588 /* Close the low-level part of the SLIP channel. Easy! */
 589 static int
 590 sl_close(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 591 {
 592         struct slip *sl = &sl_ctrl[dev->base_addr];
 593 
 594         if (sl->tty == NULL) {
 595                 return -EBUSY;
 596         }
 597         sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 598         dev->tbusy = 1;
 599         dev->start = 0;
 600         
 601 /*      dev->flags &= ~IFF_UP; */
 602 
 603         return 0;
 604 }
 605 
 606 static int
 607 slip_receive_room(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 608 {
 609         return 65536;  /* We can handle an infinite amount of data. :-) */
 610 }
 611 
 612 /*
 613  * Handle the 'receiver data ready' interrupt.
 614  * This function is called by the 'tty_io' module in the kernel when
 615  * a block of SLIP data has been received, which can now be decapsulated
 616  * and sent on to some IP layer for further processing.
 617  */
 618 static void
 619 slip_receive_buf(struct tty_struct *tty, unsigned char *cp, char *fp, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 620 {
 621         struct slip *sl = (struct slip *) tty->disc_data;
 622 
 623         if (!sl || sl->magic != SLIP_MAGIC || !sl->dev->start)
 624                 return;
 625 
 626         /*
 627          * Argh! mtu change time! - costs us the packet part received
 628          * at the change
 629          */
 630 #ifdef CONFIG_AX25
 631         if (sl->mtu != sl->dev->mtu + 73)  {
 632 #else
 633         if (sl->mtu != sl->dev->mtu)  {
 634 #endif
 635                 sl_changedmtu(sl);
 636         }
 637 
 638         /* Read the characters out of the buffer */
 639         while (count--) {
 640                 if (fp && *fp++) {
 641                         if (!set_bit(SLF_ERROR, &sl->flags))  {
 642                                 sl->rx_errors++;
 643                         }
 644                         cp++;
 645                         continue;
 646                 }
 647 #ifdef CONFIG_SLIP_MODE_SLIP6
 648                 if (sl->mode & SL_MODE_SLIP6)
 649                         slip_unesc6(sl, *cp++);
 650                 else
 651 #endif
 652                         slip_unesc(sl, *cp++);
 653         }
 654 }
 655 
 656 /*
 657  * Open the high-level part of the SLIP channel.
 658  * This function is called by the TTY module when the
 659  * SLIP line discipline is called for.  Because we are
 660  * sure the tty line exists, we only have to link it to
 661  * a free SLIP channel...
 662  */
 663 static int
 664 slip_open(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 665 {
 666         struct slip *sl = (struct slip *) tty->disc_data;
 667         int err;
 668 
 669         /* First make sure we're not already connected. */
 670         if (sl && sl->magic == SLIP_MAGIC) {
 671                 return -EEXIST;
 672         }
 673 
 674         /* OK.  Find a free SLIP channel to use. */
 675         if ((sl = sl_alloc()) == NULL) {
 676                 return -ENFILE;
 677         }
 678 
 679         sl->tty = tty;
 680         tty->disc_data = sl;
 681         if (tty->driver.flush_buffer)  {
 682                 tty->driver.flush_buffer(tty);
 683         }
 684         if (tty->ldisc.flush_buffer)  {
 685                 tty->ldisc.flush_buffer(tty);
 686         }
 687 
 688         /* Restore default settings */
 689         sl->mode      = SL_MODE_DEFAULT;
 690         sl->dev->type = ARPHRD_SLIP + sl->mode;
 691 #ifdef CONFIG_AX25      
 692         if (sl->dev->type == 260 || sl->dev->type == 272) {     /* KISS */
 693                 sl->dev->type = ARPHRD_AX25;
 694         }
 695 #endif  
 696         /* Perform the low-level SLIP initialization. */
 697         if ((err = sl_open(sl->dev)))  {
 698                 return err;
 699         }
 700         
 701 #ifdef MODULE
 702         MOD_INC_USE_COUNT;
 703 #endif
 704 
 705         /* Done.  We have linked the TTY line to a channel. */
 706         return sl->dev->base_addr;
 707 }
 708 
 709 
 710 /*
 711  * Close down a SLIP channel.
 712  * This means flushing out any pending queues, and then restoring the
 713  * TTY line discipline to what it was before it got hooked to SLIP
 714  * (which usually is TTY again).
 715  */
 716 static void
 717 slip_close(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 718 {
 719         struct slip *sl = (struct slip *) tty->disc_data;
 720 
 721         /* First make sure we're connected. */
 722         if (!sl || sl->magic != SLIP_MAGIC) {
 723                 return;
 724         }
 725 
 726         (void) dev_close(sl->dev);
 727         
 728         tty->disc_data = 0;
 729         sl->tty = NULL;
 730         sl_free(sl);
 731 #ifdef MODULE
 732         MOD_DEC_USE_COUNT;
 733 #endif
 734 }
 735 
 736 
 737 static struct enet_statistics *
 738 sl_get_stats(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 739 {
 740         static struct enet_statistics stats;
 741         struct slip *sl = &sl_ctrl[dev->base_addr];
 742 #ifdef SL_INCLUDE_CSLIP
 743         struct slcompress *comp;
 744 #endif
 745 
 746         memset(&stats, 0, sizeof(struct enet_statistics));
 747 
 748         stats.rx_packets     = sl->rx_packets;
 749         stats.tx_packets     = sl->tx_packets;
 750         stats.rx_dropped     = sl->rx_dropped;
 751         stats.tx_dropped     = sl->tx_dropped;
 752         stats.tx_errors      = sl->tx_errors;
 753         stats.rx_errors      = sl->rx_errors;
 754         stats.rx_over_errors = sl->rx_over_errors;
 755 #ifdef SL_INCLUDE_CSLIP
 756         stats.rx_fifo_errors = sl->rx_compressed;
 757         stats.tx_fifo_errors = sl->tx_compressed;
 758         stats.collisions     = sl->tx_misses;
 759         comp = sl->slcomp;
 760         if (comp) {
 761                 stats.rx_fifo_errors += comp->sls_i_compressed;
 762                 stats.rx_dropped     += comp->sls_i_tossed;
 763                 stats.tx_fifo_errors += comp->sls_o_compressed;
 764                 stats.collisions     += comp->sls_o_misses;
 765         }
 766 #endif /* CONFIG_INET */
 767         return (&stats);
 768 }
 769 
 770 
 771  /************************************************************************
 772   *                     STANDARD SLIP ENCAPSULATION                      *
 773   ************************************************************************/
 774 
 775 int
 776 slip_esc(unsigned char *s, unsigned char *d, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 777 {
 778         unsigned char *ptr = d;
 779         unsigned char c;
 780 
 781         /*
 782          * Send an initial END character to flush out any
 783          * data that may have accumulated in the receiver
 784          * due to line noise.
 785          */
 786 
 787         *ptr++ = END;
 788 
 789         /*
 790          * For each byte in the packet, send the appropriate
 791          * character sequence, according to the SLIP protocol.
 792          */
 793 
 794         while (len-- > 0) {
 795                 switch(c = *s++) {
 796                  case END:
 797                         *ptr++ = ESC;
 798                         *ptr++ = ESC_END;
 799                         break;
 800                  case ESC:
 801                         *ptr++ = ESC;
 802                         *ptr++ = ESC_ESC;
 803                         break;
 804                  default:
 805                         *ptr++ = c;
 806                         break;
 807                 }
 808         }
 809         *ptr++ = END;
 810         return (ptr - d);
 811 }
 812 
 813 static void
 814 slip_unesc(struct slip *sl, unsigned char s)
     /* [previous][next][first][last][top][bottom][index][help] */
 815 {
 816 
 817         switch(s) {
 818          case END:
 819                 if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  {
 820                         sl_bump(sl);
 821                 }
 822                 clear_bit(SLF_ESCAPE, &sl->flags);
 823                 sl->rcount = 0;
 824                 return;
 825 
 826          case ESC:
 827                 set_bit(SLF_ESCAPE, &sl->flags);
 828                 return;
 829          case ESC_ESC:
 830                 if (clear_bit(SLF_ESCAPE, &sl->flags))  {
 831                         s = ESC;
 832                 }
 833                 break;
 834          case ESC_END:
 835                 if (clear_bit(SLF_ESCAPE, &sl->flags))  {
 836                         s = END;
 837                 }
 838                 break;
 839         }
 840         if (!test_bit(SLF_ERROR, &sl->flags))  {
 841                 if (sl->rcount < sl->buffsize)  {
 842                         sl->rbuff[sl->rcount++] = s;
 843                         return;
 844                 }
 845                 sl->rx_over_errors++;
 846                 set_bit(SLF_ERROR, &sl->flags);
 847         }
 848 }
 849 
 850 
 851 #ifdef CONFIG_SLIP_MODE_SLIP6
 852 /************************************************************************
 853  *                       6 BIT SLIP ENCAPSULATION                       *
 854  ************************************************************************/
 855 
 856 int
 857 slip_esc6(unsigned char *s, unsigned char *d, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 858 {
 859         unsigned char *ptr = d;
 860         unsigned char c;
 861         int i;
 862         unsigned short v = 0;
 863         short bits = 0;
 864 
 865         /*
 866          * Send an initial END character to flush out any
 867          * data that may have accumulated in the receiver
 868          * due to line noise.
 869          */
 870 
 871         *ptr++ = 0x70;
 872 
 873         /*
 874          * Encode the packet into printable ascii characters
 875          */
 876 
 877         for (i = 0; i < len; ++i) {
 878                 v = (v << 8) | s[i];
 879                 bits += 8;
 880                 while (bits >= 6) {
 881                         bits -= 6;
 882                         c = 0x30 + ((v >> bits) & 0x3F);
 883                         *ptr++ = c;
 884                 }
 885         }
 886         if (bits) {
 887                 c = 0x30 + ((v << (6 - bits)) & 0x3F);
 888                 *ptr++ = c;
 889         }
 890         *ptr++ = 0x70;
 891         return ptr - d;
 892 }
 893 
 894 void
 895 slip_unesc6(struct slip *sl, unsigned char s)
     /* [previous][next][first][last][top][bottom][index][help] */
 896 {
 897         unsigned char c;
 898 
 899         if (s == 0x70) {
 900                 if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  {
 901                         sl_bump(sl);
 902                 }
 903                 sl->rcount = 0;
 904                 sl->xbits = 0;
 905                 sl->xdata = 0;
 906         } else if (s >= 0x30 && s < 0x70) {
 907                 sl->xdata = (sl->xdata << 6) | ((s - 0x30) & 0x3F);
 908                 sl->xbits += 6;
 909                 if (sl->xbits >= 8) {
 910                         sl->xbits -= 8;
 911                         c = (unsigned char)(sl->xdata >> sl->xbits);
 912                         if (!test_bit(SLF_ERROR, &sl->flags))  {
 913                                 if (sl->rcount < sl->buffsize)  {
 914                                         sl->rbuff[sl->rcount++] = c;
 915                                         return;
 916                                 }
 917                                 sl->rx_over_errors++;
 918                                 set_bit(SLF_ERROR, &sl->flags);
 919                         }
 920                 }
 921         }
 922 }
 923 #endif /* CONFIG_SLIP_MODE_SLIP6 */
 924 
 925 #ifdef CONFIG_AX25
 926 int
 927 sl_set_mac_address(struct device *dev, void *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 928 {
 929         int err;
 930 
 931         err = verify_area(VERIFY_READ, addr, AX25_ADDR_LEN);
 932         if (err)  {
 933                 return err;
 934         }
 935 
 936         memcpy_fromfs(dev->dev_addr, addr, AX25_ADDR_LEN);      /* addr is an AX.25 shifted ASCII mac address */
 937 
 938         return 0;
 939 }
 940 
 941 static int
 942 sl_set_dev_mac_address(struct device *dev, void *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 943 {
 944         memcpy(dev->dev_addr, addr, AX25_ADDR_LEN);
 945         return 0;
 946 }
 947 
 948 int sl_get_ax25_mode(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 949 {
 950         struct slip *sl = &sl_ctrl[dev->base_addr];
 951 
 952         return sl->mode & SL_MODE_AX25VC;
 953 }
 954 
 955 #endif /* CONFIG_AX25 */
 956 
 957 
 958 /* Perform I/O control on an active SLIP channel. */
 959 static int
 960 slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 961 {
 962         struct slip *sl = (struct slip *) tty->disc_data;
 963         int err;
 964         unsigned int tmp;
 965 
 966         /* First make sure we're connected. */
 967         if (!sl || sl->magic != SLIP_MAGIC) {
 968                 return -EINVAL;
 969         }
 970 
 971         switch(cmd) {
 972          case SIOCGIFNAME:
 973                 err = verify_area(VERIFY_WRITE, arg, strlen(sl->dev->name) + 1);
 974                 if (err)  {
 975                         return -err;
 976                 }
 977                 memcpy_tofs(arg, sl->dev->name, strlen(sl->dev->name) + 1);
 978                 return 0;
 979 
 980         case SIOCGIFENCAP:
 981                 err = verify_area(VERIFY_WRITE, arg, sizeof(int));
 982                 if (err)  {
 983                         return -err;
 984                 }
 985                 put_user(sl->mode, (int *)arg);
 986                 return 0;
 987 
 988         case SIOCSIFENCAP:
 989                 err = verify_area(VERIFY_READ, arg, sizeof(int));
 990                 if (err)  {
 991                         return -err;
 992                 }
 993                 tmp = get_user((int *)arg);
 994 #ifndef SL_INCLUDE_CSLIP
 995                 if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE))  {
 996                         return -EINVAL;
 997                 }
 998 #else
 999                 if ((tmp & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) ==
1000                     (SL_MODE_ADAPTIVE | SL_MODE_CSLIP))  {
1001                         /* return -EINVAL; */
1002                         tmp &= ~SL_MODE_ADAPTIVE;
1003                 }
1004 #endif
1005 #ifndef CONFIG_SLIP_MODE_SLIP6
1006                 if (tmp & SL_MODE_SLIP6)  {
1007                         return -EINVAL;
1008                 }
1009 #endif
1010 #ifndef CONFIG_AX25
1011                 if ((tmp & SL_MODE_AX25) || (tmp & SL_MODE_AX25VC)) {
1012                         return -EINVAL;
1013                 }
1014 #else
1015                 if ((tmp & SL_MODE_AX25) || (tmp & SL_MODE_AX25VC)) {
1016                         sl->dev->addr_len=AX25_ADDR_LEN;          /* sizeof an AX.25 addr */
1017                         sl->dev->hard_header_len=AX25_HEADER_LEN; /* We don't do digipeaters */
1018                 } else  {
1019                         sl->dev->addr_len=0;    /* No mac addr in slip mode */
1020                         sl->dev->hard_header_len=0;
1021                 }
1022 #endif
1023                 sl->mode = tmp;
1024                 sl->dev->type = ARPHRD_SLIP+sl->mode;
1025 #ifdef CONFIG_AX25              
1026                 if (sl->dev->type == 260 || sl->dev->type == 272)  {
1027                         sl->dev->type = ARPHRD_AX25;
1028                 }
1029 #endif          
1030                 return 0;
1031 
1032          case SIOCSIFHWADDR:
1033 #ifdef CONFIG_AX25
1034                 return sl_set_mac_address(sl->dev, arg);
1035 #else
1036                 return -EINVAL;
1037 #endif
1038 
1039         /* Allow stty to read, but not set, the serial port */
1040         case TCGETS:
1041         case TCGETA:
1042                 return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg);
1043 
1044         default:
1045                 return -ENOIOCTLCMD;
1046         }
1047 }
1048 
1049 static int sl_open_dev(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
1050 {
1051         struct slip *sl = &sl_ctrl[dev->base_addr];
1052         if(sl->tty==NULL)
1053                 return -ENODEV;
1054         return 0;
1055 }
1056 
1057 /* Initialize the SLIP driver.  Called by DDI. */
1058 int
1059 slip_init(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
1060 {
1061         struct slip *sl = &sl_ctrl[dev->base_addr];
1062         int i;
1063 #ifdef CONFIG_AX25
1064         static char ax25_bcast[AX25_ADDR_LEN] =
1065                 {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
1066         static char ax25_test[AX25_ADDR_LEN] =
1067                 {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
1068 #endif
1069 
1070         if (already++ == 0) {
1071                 printk("SLIP: version %s (%d channels) %s\n",
1072                        SLIP_VERSION, SL_NRUNIT,
1073 #ifdef CONFIG_SLIP_MODE_SLIP6
1074                        "(6 bit encapsulation enabled)"
1075 #else
1076                        ""
1077 #endif
1078                        );
1079 #if defined(SL_INCLUDE_CSLIP) && !defined(MODULE)
1080                 printk("CSLIP: code copyright 1989 Regents of the University of California\n");
1081 #endif
1082 #ifdef CONFIG_AX25
1083                 printk("AX25: KISS encapsulation enabled\n");
1084 #endif
1085                 /* Fill in our LDISC request block. */
1086                 memset(&sl_ldisc, 0, sizeof(sl_ldisc));
1087                 sl_ldisc.magic  = TTY_LDISC_MAGIC;
1088                 sl_ldisc.flags  = 0;
1089                 sl_ldisc.open   = slip_open;
1090                 sl_ldisc.close  = slip_close;
1091                 sl_ldisc.read   = NULL;
1092                 sl_ldisc.write  = NULL;
1093                 sl_ldisc.ioctl  = (int (*)(struct tty_struct *, struct file *,
1094                                            unsigned int, unsigned long)) slip_ioctl;
1095                 sl_ldisc.select = NULL;
1096                 sl_ldisc.receive_buf = slip_receive_buf;
1097                 sl_ldisc.receive_room = slip_receive_room;
1098                 sl_ldisc.write_wakeup = slip_write_wakeup;
1099                 if ((i = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0)  {
1100                         printk("SLIP: can't register line discipline (err = %d)\n", i);
1101                 }
1102         }
1103 
1104         /* Set up the "SLIP Control Block". (And clear statistics) */
1105         
1106         memset(sl, 0, sizeof (struct slip));
1107         sl->magic  = SLIP_MAGIC;
1108         sl->dev    = dev;
1109         
1110         /* Finish setting up the DEVICE info. */
1111         dev->mtu                = SL_MTU;
1112         dev->hard_start_xmit    = sl_xmit;
1113         dev->open               = sl_open_dev;
1114         dev->stop               = sl_close;
1115         dev->hard_header        = sl_header;
1116         dev->get_stats          = sl_get_stats;
1117 #ifdef HAVE_SET_MAC_ADDR
1118 #ifdef CONFIG_AX25
1119         dev->set_mac_address    = sl_set_dev_mac_address;
1120 #endif
1121 #endif
1122         dev->hard_header_len    = 0;
1123         dev->addr_len           = 0;
1124         dev->type               = ARPHRD_SLIP + SL_MODE_DEFAULT;
1125 #ifdef CONFIG_AX25
1126         if (sl->dev->type == 260 || sl->dev->type == 272)  {
1127                 sl->dev->type = ARPHRD_AX25;
1128         }
1129         memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);      /* Only activated in AX.25 mode */
1130         memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);        /*    ""      ""       ""    "" */
1131 #endif
1132         dev->rebuild_header     = sl_rebuild_header;
1133 
1134         for (i = 0; i < DEV_NUMBUFFS; i++)  {
1135                 skb_queue_head_init(&dev->buffs[i]);
1136         }
1137 
1138         /* New-style flags. */
1139         dev->flags              = 0;
1140         dev->family             = AF_INET;
1141         dev->pa_addr            = 0;
1142         dev->pa_brdaddr         = 0;
1143         dev->pa_mask            = 0;
1144         dev->pa_alen            = sizeof(unsigned long);
1145 
1146         return 0;
1147 }
1148 #ifdef MODULE
1149 char kernel_version[] = UTS_RELEASE;
1150 
1151 static struct device dev_slip[SL_NRUNIT] =  {
1152         {
1153                 "sl0",          /* slip */
1154                 0, 0, 0, 0,     /* memory */
1155                 0, 0,           /* base, irq */
1156                 0, 0, 0, NULL, slip_init,
1157         },
1158         { "sl1" , 0, 0, 0, 0,  1, 0, 0, 0, 0, NULL, slip_init },
1159         { "sl2" , 0, 0, 0, 0,  2, 0, 0, 0, 0, NULL, slip_init },
1160         { "sl3" , 0, 0, 0, 0,  3, 0, 0, 0, 0, NULL, slip_init },
1161 #ifdef SL_SLIP_LOTS
1162         { "sl4" , 0, 0, 0, 0,  4, 0, 0, 0, 0, NULL, slip_init },
1163         { "sl5" , 0, 0, 0, 0,  5, 0, 0, 0, 0, NULL, slip_init },
1164         { "sl6" , 0, 0, 0, 0,  6, 0, 0, 0, 0, NULL, slip_init },
1165         { "sl7" , 0, 0, 0, 0,  7, 0, 0, 0, 0, NULL, slip_init },
1166         { "sl8" , 0, 0, 0, 0,  8, 0, 0, 0, 0, NULL, slip_init },
1167         { "sl9" , 0, 0, 0, 0,  9, 0, 0, 0, 0, NULL, slip_init },
1168         { "sl10", 0, 0, 0, 0, 10, 0, 0, 0, 0, NULL, slip_init },
1169         { "sl11", 0, 0, 0, 0, 11, 0, 0, 0, 0, NULL, slip_init },
1170         { "sl12", 0, 0, 0, 0, 12, 0, 0, 0, 0, NULL, slip_init },
1171         { "sl13", 0, 0, 0, 0, 13, 0, 0, 0, 0, NULL, slip_init },
1172         { "sl14", 0, 0, 0, 0, 14, 0, 0, 0, 0, NULL, slip_init },
1173         { "sl15", 0, 0, 0, 0, 15, 0, 0, 0, 0, NULL, slip_init },
1174 #endif /* SL_SLIP_LOTS */
1175 };
1176 
1177 int
1178 init_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1179 {
1180         int err;
1181         int i;
1182 
1183         for (i = 0; i < SL_NRUNIT; i++)  {
1184                 if ((err = register_netdev(&dev_slip[i])))  {
1185                         if (err == -EEXIST)  {
1186                                 printk("SLIP: devices already present. Module not loaded.\n");
1187                         }
1188                         return err;
1189                 }
1190         }
1191         return 0;
1192 }
1193 
1194 void
1195 cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1196 {
1197         int i;
1198 
1199         if (MOD_IN_USE)  {
1200                 printk("SLIP: device busy, remove delayed\n");
1201                 return;
1202         }
1203         for (i = 0; i < SL_NRUNIT; i++)  {
1204                 unregister_netdev(&dev_slip[i]);
1205         }
1206         if ((i = tty_register_ldisc(N_SLIP, NULL)))  {
1207                 printk("SLIP: can't unregister line discipline (err = %d)\n", i);
1208         }
1209         already = 0;
1210 }
1211 #endif /* MODULE */

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