linux/drivers/net/hamradio/6pack.c
<<
>>
Prefs
   1/*
   2 * 6pack.c      This module implements the 6pack protocol for kernel-based
   3 *              devices like TTY. It interfaces between a raw TTY and the
   4 *              kernel's AX.25 protocol layers.
   5 *
   6 * Authors:     Andreas Könsgen <ajk@comnets.uni-bremen.de>
   7 *              Ralf Baechle DL5RB <ralf@linux-mips.org>
   8 *
   9 * Quite a lot of stuff "stolen" by Joerg Reuter from slip.c, written by
  10 *
  11 *              Laurence Culhane, <loz@holmes.demon.co.uk>
  12 *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  13 */
  14
  15#include <linux/module.h>
  16#include <asm/system.h>
  17#include <asm/uaccess.h>
  18#include <linux/bitops.h>
  19#include <linux/string.h>
  20#include <linux/mm.h>
  21#include <linux/interrupt.h>
  22#include <linux/in.h>
  23#include <linux/tty.h>
  24#include <linux/errno.h>
  25#include <linux/netdevice.h>
  26#include <linux/timer.h>
  27#include <net/ax25.h>
  28#include <linux/etherdevice.h>
  29#include <linux/skbuff.h>
  30#include <linux/rtnetlink.h>
  31#include <linux/spinlock.h>
  32#include <linux/if_arp.h>
  33#include <linux/init.h>
  34#include <linux/ip.h>
  35#include <linux/tcp.h>
  36#include <linux/semaphore.h>
  37#include <asm/atomic.h>
  38
  39#define SIXPACK_VERSION    "Revision: 0.3.0"
  40
  41/* sixpack priority commands */
  42#define SIXP_SEOF               0x40    /* start and end of a 6pack frame */
  43#define SIXP_TX_URUN            0x48    /* transmit overrun */
  44#define SIXP_RX_ORUN            0x50    /* receive overrun */
  45#define SIXP_RX_BUF_OVL         0x58    /* receive buffer overflow */
  46
  47#define SIXP_CHKSUM             0xFF    /* valid checksum of a 6pack frame */
  48
  49/* masks to get certain bits out of the status bytes sent by the TNC */
  50
  51#define SIXP_CMD_MASK           0xC0
  52#define SIXP_CHN_MASK           0x07
  53#define SIXP_PRIO_CMD_MASK      0x80
  54#define SIXP_STD_CMD_MASK       0x40
  55#define SIXP_PRIO_DATA_MASK     0x38
  56#define SIXP_TX_MASK            0x20
  57#define SIXP_RX_MASK            0x10
  58#define SIXP_RX_DCD_MASK        0x18
  59#define SIXP_LEDS_ON            0x78
  60#define SIXP_LEDS_OFF           0x60
  61#define SIXP_CON                0x08
  62#define SIXP_STA                0x10
  63
  64#define SIXP_FOUND_TNC          0xe9
  65#define SIXP_CON_ON             0x68
  66#define SIXP_DCD_MASK           0x08
  67#define SIXP_DAMA_OFF           0
  68
  69/* default level 2 parameters */
  70#define SIXP_TXDELAY                    (HZ/4)  /* in 1 s */
  71#define SIXP_PERSIST                    50      /* in 256ths */
  72#define SIXP_SLOTTIME                   (HZ/10) /* in 1 s */
  73#define SIXP_INIT_RESYNC_TIMEOUT        (3*HZ/2) /* in 1 s */
  74#define SIXP_RESYNC_TIMEOUT             5*HZ    /* in 1 s */
  75
  76/* 6pack configuration. */
  77#define SIXP_NRUNIT                     31      /* MAX number of 6pack channels */
  78#define SIXP_MTU                        256     /* Default MTU */
  79
  80enum sixpack_flags {
  81        SIXPF_ERROR,    /* Parity, etc. error   */
  82};
  83
  84struct sixpack {
  85        /* Various fields. */
  86        struct tty_struct       *tty;           /* ptr to TTY structure */
  87        struct net_device       *dev;           /* easy for intr handling  */
  88
  89        /* These are pointers to the malloc()ed frame buffers. */
  90        unsigned char           *rbuff;         /* receiver buffer      */
  91        int                     rcount;         /* received chars counter  */
  92        unsigned char           *xbuff;         /* transmitter buffer   */
  93        unsigned char           *xhead;         /* next byte to XMIT */
  94        int                     xleft;          /* bytes left in XMIT queue  */
  95
  96        unsigned char           raw_buf[4];
  97        unsigned char           cooked_buf[400];
  98
  99        unsigned int            rx_count;
 100        unsigned int            rx_count_cooked;
 101
 102        int                     mtu;            /* Our mtu (to spot changes!) */
 103        int                     buffsize;       /* Max buffers sizes */
 104
 105        unsigned long           flags;          /* Flag values/ mode etc */
 106        unsigned char           mode;           /* 6pack mode */
 107
 108        /* 6pack stuff */
 109        unsigned char           tx_delay;
 110        unsigned char           persistence;
 111        unsigned char           slottime;
 112        unsigned char           duplex;
 113        unsigned char           led_state;
 114        unsigned char           status;
 115        unsigned char           status1;
 116        unsigned char           status2;
 117        unsigned char           tx_enable;
 118        unsigned char           tnc_state;
 119
 120        struct timer_list       tx_t;
 121        struct timer_list       resync_t;
 122        atomic_t                refcnt;
 123        struct semaphore        dead_sem;
 124        spinlock_t              lock;
 125};
 126
 127#define AX25_6PACK_HEADER_LEN 0
 128
 129static void sixpack_decode(struct sixpack *, unsigned char[], int);
 130static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char);
 131
 132/*
 133 * Perform the persistence/slottime algorithm for CSMA access. If the
 134 * persistence check was successful, write the data to the serial driver.
 135 * Note that in case of DAMA operation, the data is not sent here.
 136 */
 137
 138static void sp_xmit_on_air(unsigned long channel)
 139{
 140        struct sixpack *sp = (struct sixpack *) channel;
 141        int actual, when = sp->slottime;
 142        static unsigned char random;
 143
 144        random = random * 17 + 41;
 145
 146        if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) {
 147                sp->led_state = 0x70;
 148                sp->tty->ops->write(sp->tty, &sp->led_state, 1);
 149                sp->tx_enable = 1;
 150                actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2);
 151                sp->xleft -= actual;
 152                sp->xhead += actual;
 153                sp->led_state = 0x60;
 154                sp->tty->ops->write(sp->tty, &sp->led_state, 1);
 155                sp->status2 = 0;
 156        } else
 157                mod_timer(&sp->tx_t, jiffies + ((when + 1) * HZ) / 100);
 158}
 159
 160/* ----> 6pack timer interrupt handler and friends. <---- */
 161
 162/* Encapsulate one AX.25 frame and stuff into a TTY queue. */
 163static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
 164{
 165        unsigned char *msg, *p = icp;
 166        int actual, count;
 167
 168        if (len > sp->mtu) {    /* sp->mtu = AX25_MTU = max. PACLEN = 256 */
 169                msg = "oversized transmit packet!";
 170                goto out_drop;
 171        }
 172
 173        if (len > sp->mtu) {    /* sp->mtu = AX25_MTU = max. PACLEN = 256 */
 174                msg = "oversized transmit packet!";
 175                goto out_drop;
 176        }
 177
 178        if (p[0] > 5) {
 179                msg = "invalid KISS command";
 180                goto out_drop;
 181        }
 182
 183        if ((p[0] != 0) && (len > 2)) {
 184                msg = "KISS control packet too long";
 185                goto out_drop;
 186        }
 187
 188        if ((p[0] == 0) && (len < 15)) {
 189                msg = "bad AX.25 packet to transmit";
 190                goto out_drop;
 191        }
 192
 193        count = encode_sixpack(p, sp->xbuff, len, sp->tx_delay);
 194        set_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags);
 195
 196        switch (p[0]) {
 197        case 1: sp->tx_delay = p[1];
 198                return;
 199        case 2: sp->persistence = p[1];
 200                return;
 201        case 3: sp->slottime = p[1];
 202                return;
 203        case 4: /* ignored */
 204                return;
 205        case 5: sp->duplex = p[1];
 206                return;
 207        }
 208
 209        if (p[0] != 0)
 210                return;
 211
 212        /*
 213         * In case of fullduplex or DAMA operation, we don't take care about the
 214         * state of the DCD or of any timers, as the determination of the
 215         * correct time to send is the job of the AX.25 layer. We send
 216         * immediately after data has arrived.
 217         */
 218        if (sp->duplex == 1) {
 219                sp->led_state = 0x70;
 220                sp->tty->ops->write(sp->tty, &sp->led_state, 1);
 221                sp->tx_enable = 1;
 222                actual = sp->tty->ops->write(sp->tty, sp->xbuff, count);
 223                sp->xleft = count - actual;
 224                sp->xhead = sp->xbuff + actual;
 225                sp->led_state = 0x60;
 226                sp->tty->ops->write(sp->tty, &sp->led_state, 1);
 227        } else {
 228                sp->xleft = count;
 229                sp->xhead = sp->xbuff;
 230                sp->status2 = count;
 231                sp_xmit_on_air((unsigned long)sp);
 232        }
 233
 234        return;
 235
 236out_drop:
 237        sp->dev->stats.tx_dropped++;
 238        netif_start_queue(sp->dev);
 239        if (net_ratelimit())
 240                printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg);
 241}
 242
 243/* Encapsulate an IP datagram and kick it into a TTY queue. */
 244
 245static netdev_tx_t sp_xmit(struct sk_buff *skb, struct net_device *dev)
 246{
 247        struct sixpack *sp = netdev_priv(dev);
 248
 249        spin_lock_bh(&sp->lock);
 250        /* We were not busy, so we are now... :-) */
 251        netif_stop_queue(dev);
 252        dev->stats.tx_bytes += skb->len;
 253        sp_encaps(sp, skb->data, skb->len);
 254        spin_unlock_bh(&sp->lock);
 255
 256        dev_kfree_skb(skb);
 257
 258        return NETDEV_TX_OK;
 259}
 260
 261static int sp_open_dev(struct net_device *dev)
 262{
 263        struct sixpack *sp = netdev_priv(dev);
 264
 265        if (sp->tty == NULL)
 266                return -ENODEV;
 267        return 0;
 268}
 269
 270/* Close the low-level part of the 6pack channel. */
 271static int sp_close(struct net_device *dev)
 272{
 273        struct sixpack *sp = netdev_priv(dev);
 274
 275        spin_lock_bh(&sp->lock);
 276        if (sp->tty) {
 277                /* TTY discipline is running. */
 278                clear_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags);
 279        }
 280        netif_stop_queue(dev);
 281        spin_unlock_bh(&sp->lock);
 282
 283        return 0;
 284}
 285
 286/* Return the frame type ID */
 287static int sp_header(struct sk_buff *skb, struct net_device *dev,
 288                     unsigned short type, const void *daddr,
 289                     const void *saddr, unsigned len)
 290{
 291#ifdef CONFIG_INET
 292        if (type != ETH_P_AX25)
 293                return ax25_hard_header(skb, dev, type, daddr, saddr, len);
 294#endif
 295        return 0;
 296}
 297
 298static int sp_set_mac_address(struct net_device *dev, void *addr)
 299{
 300        struct sockaddr_ax25 *sa = addr;
 301
 302        netif_tx_lock_bh(dev);
 303        netif_addr_lock(dev);
 304        memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
 305        netif_addr_unlock(dev);
 306        netif_tx_unlock_bh(dev);
 307
 308        return 0;
 309}
 310
 311static int sp_rebuild_header(struct sk_buff *skb)
 312{
 313#ifdef CONFIG_INET
 314        return ax25_rebuild_header(skb);
 315#else
 316        return 0;
 317#endif
 318}
 319
 320static const struct header_ops sp_header_ops = {
 321        .create         = sp_header,
 322        .rebuild        = sp_rebuild_header,
 323};
 324
 325static const struct net_device_ops sp_netdev_ops = {
 326        .ndo_open               = sp_open_dev,
 327        .ndo_stop               = sp_close,
 328        .ndo_start_xmit         = sp_xmit,
 329        .ndo_set_mac_address    = sp_set_mac_address,
 330};
 331
 332static void sp_setup(struct net_device *dev)
 333{
 334        /* Finish setting up the DEVICE info. */
 335        dev->netdev_ops         = &sp_netdev_ops;
 336        dev->destructor         = free_netdev;
 337        dev->mtu                = SIXP_MTU;
 338        dev->hard_header_len    = AX25_MAX_HEADER_LEN;
 339        dev->header_ops         = &sp_header_ops;
 340
 341        dev->addr_len           = AX25_ADDR_LEN;
 342        dev->type               = ARPHRD_AX25;
 343        dev->tx_queue_len       = 10;
 344
 345        /* Only activated in AX.25 mode */
 346        memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
 347        memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
 348
 349        dev->flags              = 0;
 350}
 351
 352/* Send one completely decapsulated IP datagram to the IP layer. */
 353
 354/*
 355 * This is the routine that sends the received data to the kernel AX.25.
 356 * 'cmd' is the KISS command. For AX.25 data, it is zero.
 357 */
 358
 359static void sp_bump(struct sixpack *sp, char cmd)
 360{
 361        struct sk_buff *skb;
 362        int count;
 363        unsigned char *ptr;
 364
 365        count = sp->rcount + 1;
 366
 367        sp->dev->stats.rx_bytes += count;
 368
 369        if ((skb = dev_alloc_skb(count)) == NULL)
 370                goto out_mem;
 371
 372        ptr = skb_put(skb, count);
 373        *ptr++ = cmd;   /* KISS command */
 374
 375        memcpy(ptr, sp->cooked_buf + 1, count);
 376        skb->protocol = ax25_type_trans(skb, sp->dev);
 377        netif_rx(skb);
 378        sp->dev->stats.rx_packets++;
 379
 380        return;
 381
 382out_mem:
 383        sp->dev->stats.rx_dropped++;
 384}
 385
 386
 387/* ----------------------------------------------------------------------- */
 388
 389/*
 390 * We have a potential race on dereferencing tty->disc_data, because the tty
 391 * layer provides no locking at all - thus one cpu could be running
 392 * sixpack_receive_buf while another calls sixpack_close, which zeroes
 393 * tty->disc_data and frees the memory that sixpack_receive_buf is using.  The
 394 * best way to fix this is to use a rwlock in the tty struct, but for now we
 395 * use a single global rwlock for all ttys in ppp line discipline.
 396 */
 397static DEFINE_RWLOCK(disc_data_lock);
 398                                                                                
 399static struct sixpack *sp_get(struct tty_struct *tty)
 400{
 401        struct sixpack *sp;
 402
 403        read_lock(&disc_data_lock);
 404        sp = tty->disc_data;
 405        if (sp)
 406                atomic_inc(&sp->refcnt);
 407        read_unlock(&disc_data_lock);
 408
 409        return sp;
 410}
 411
 412static void sp_put(struct sixpack *sp)
 413{
 414        if (atomic_dec_and_test(&sp->refcnt))
 415                up(&sp->dead_sem);
 416}
 417
 418/*
 419 * Called by the TTY driver when there's room for more data.  If we have
 420 * more packets to send, we send them here.
 421 */
 422static void sixpack_write_wakeup(struct tty_struct *tty)
 423{
 424        struct sixpack *sp = sp_get(tty);
 425        int actual;
 426
 427        if (!sp)
 428                return;
 429        if (sp->xleft <= 0)  {
 430                /* Now serial buffer is almost free & we can start
 431                 * transmission of another packet */
 432                sp->dev->stats.tx_packets++;
 433                clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 434                sp->tx_enable = 0;
 435                netif_wake_queue(sp->dev);
 436                goto out;
 437        }
 438
 439        if (sp->tx_enable) {
 440                actual = tty->ops->write(tty, sp->xhead, sp->xleft);
 441                sp->xleft -= actual;
 442                sp->xhead += actual;
 443        }
 444
 445out:
 446        sp_put(sp);
 447}
 448
 449/* ----------------------------------------------------------------------- */
 450
 451/*
 452 * Handle the 'receiver data ready' interrupt.
 453 * This function is called by the 'tty_io' module in the kernel when
 454 * a block of 6pack data has been received, which can now be decapsulated
 455 * and sent on to some IP layer for further processing.
 456 */
 457static void sixpack_receive_buf(struct tty_struct *tty,
 458        const unsigned char *cp, char *fp, int count)
 459{
 460        struct sixpack *sp;
 461        unsigned char buf[512];
 462        int count1;
 463
 464        if (!count)
 465                return;
 466
 467        sp = sp_get(tty);
 468        if (!sp)
 469                return;
 470
 471        memcpy(buf, cp, count < sizeof(buf) ? count : sizeof(buf));
 472
 473        /* Read the characters out of the buffer */
 474
 475        count1 = count;
 476        while (count) {
 477                count--;
 478                if (fp && *fp++) {
 479                        if (!test_and_set_bit(SIXPF_ERROR, &sp->flags))
 480                                sp->dev->stats.rx_errors++;
 481                        continue;
 482                }
 483        }
 484        sixpack_decode(sp, buf, count1);
 485
 486        sp_put(sp);
 487        tty_unthrottle(tty);
 488}
 489
 490/*
 491 * Try to resync the TNC. Called by the resync timer defined in
 492 * decode_prio_command
 493 */
 494
 495#define TNC_UNINITIALIZED       0
 496#define TNC_UNSYNC_STARTUP      1
 497#define TNC_UNSYNCED            2
 498#define TNC_IN_SYNC             3
 499
 500static void __tnc_set_sync_state(struct sixpack *sp, int new_tnc_state)
 501{
 502        char *msg;
 503
 504        switch (new_tnc_state) {
 505        default:                        /* gcc oh piece-o-crap ... */
 506        case TNC_UNSYNC_STARTUP:
 507                msg = "Synchronizing with TNC";
 508                break;
 509        case TNC_UNSYNCED:
 510                msg = "Lost synchronization with TNC\n";
 511                break;
 512        case TNC_IN_SYNC:
 513                msg = "Found TNC";
 514                break;
 515        }
 516
 517        sp->tnc_state = new_tnc_state;
 518        printk(KERN_INFO "%s: %s\n", sp->dev->name, msg);
 519}
 520
 521static inline void tnc_set_sync_state(struct sixpack *sp, int new_tnc_state)
 522{
 523        int old_tnc_state = sp->tnc_state;
 524
 525        if (old_tnc_state != new_tnc_state)
 526                __tnc_set_sync_state(sp, new_tnc_state);
 527}
 528
 529static void resync_tnc(unsigned long channel)
 530{
 531        struct sixpack *sp = (struct sixpack *) channel;
 532        static char resync_cmd = 0xe8;
 533
 534        /* clear any data that might have been received */
 535
 536        sp->rx_count = 0;
 537        sp->rx_count_cooked = 0;
 538
 539        /* reset state machine */
 540
 541        sp->status = 1;
 542        sp->status1 = 1;
 543        sp->status2 = 0;
 544
 545        /* resync the TNC */
 546
 547        sp->led_state = 0x60;
 548        sp->tty->ops->write(sp->tty, &sp->led_state, 1);
 549        sp->tty->ops->write(sp->tty, &resync_cmd, 1);
 550
 551
 552        /* Start resync timer again -- the TNC might be still absent */
 553
 554        del_timer(&sp->resync_t);
 555        sp->resync_t.data       = (unsigned long) sp;
 556        sp->resync_t.function   = resync_tnc;
 557        sp->resync_t.expires    = jiffies + SIXP_RESYNC_TIMEOUT;
 558        add_timer(&sp->resync_t);
 559}
 560
 561static inline int tnc_init(struct sixpack *sp)
 562{
 563        unsigned char inbyte = 0xe8;
 564
 565        tnc_set_sync_state(sp, TNC_UNSYNC_STARTUP);
 566
 567        sp->tty->ops->write(sp->tty, &inbyte, 1);
 568
 569        del_timer(&sp->resync_t);
 570        sp->resync_t.data = (unsigned long) sp;
 571        sp->resync_t.function = resync_tnc;
 572        sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
 573        add_timer(&sp->resync_t);
 574
 575        return 0;
 576}
 577
 578/*
 579 * Open the high-level part of the 6pack channel.
 580 * This function is called by the TTY module when the
 581 * 6pack line discipline is called for.  Because we are
 582 * sure the tty line exists, we only have to link it to
 583 * a free 6pcack channel...
 584 */
 585static int sixpack_open(struct tty_struct *tty)
 586{
 587        char *rbuff = NULL, *xbuff = NULL;
 588        struct net_device *dev;
 589        struct sixpack *sp;
 590        unsigned long len;
 591        int err = 0;
 592
 593        if (!capable(CAP_NET_ADMIN))
 594                return -EPERM;
 595        if (tty->ops->write == NULL)
 596                return -EOPNOTSUPP;
 597
 598        dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup);
 599        if (!dev) {
 600                err = -ENOMEM;
 601                goto out;
 602        }
 603
 604        sp = netdev_priv(dev);
 605        sp->dev = dev;
 606
 607        spin_lock_init(&sp->lock);
 608        atomic_set(&sp->refcnt, 1);
 609        init_MUTEX_LOCKED(&sp->dead_sem);
 610
 611        /* !!! length of the buffers. MTU is IP MTU, not PACLEN!  */
 612
 613        len = dev->mtu * 2;
 614
 615        rbuff = kmalloc(len + 4, GFP_KERNEL);
 616        xbuff = kmalloc(len + 4, GFP_KERNEL);
 617
 618        if (rbuff == NULL || xbuff == NULL) {
 619                err = -ENOBUFS;
 620                goto out_free;
 621        }
 622
 623        spin_lock_bh(&sp->lock);
 624
 625        sp->tty = tty;
 626
 627        sp->rbuff       = rbuff;
 628        sp->xbuff       = xbuff;
 629
 630        sp->mtu         = AX25_MTU + 73;
 631        sp->buffsize    = len;
 632        sp->rcount      = 0;
 633        sp->rx_count    = 0;
 634        sp->rx_count_cooked = 0;
 635        sp->xleft       = 0;
 636
 637        sp->flags       = 0;            /* Clear ESCAPE & ERROR flags */
 638
 639        sp->duplex      = 0;
 640        sp->tx_delay    = SIXP_TXDELAY;
 641        sp->persistence = SIXP_PERSIST;
 642        sp->slottime    = SIXP_SLOTTIME;
 643        sp->led_state   = 0x60;
 644        sp->status      = 1;
 645        sp->status1     = 1;
 646        sp->status2     = 0;
 647        sp->tx_enable   = 0;
 648
 649        netif_start_queue(dev);
 650
 651        init_timer(&sp->tx_t);
 652        sp->tx_t.function = sp_xmit_on_air;
 653        sp->tx_t.data = (unsigned long) sp;
 654
 655        init_timer(&sp->resync_t);
 656
 657        spin_unlock_bh(&sp->lock);
 658
 659        /* Done.  We have linked the TTY line to a channel. */
 660        tty->disc_data = sp;
 661        tty->receive_room = 65536;
 662
 663        /* Now we're ready to register. */
 664        if (register_netdev(dev))
 665                goto out_free;
 666
 667        tnc_init(sp);
 668
 669        return 0;
 670
 671out_free:
 672        kfree(xbuff);
 673        kfree(rbuff);
 674
 675        if (dev)
 676                free_netdev(dev);
 677
 678out:
 679        return err;
 680}
 681
 682
 683/*
 684 * Close down a 6pack channel.
 685 * This means flushing out any pending queues, and then restoring the
 686 * TTY line discipline to what it was before it got hooked to 6pack
 687 * (which usually is TTY again).
 688 */
 689static void sixpack_close(struct tty_struct *tty)
 690{
 691        struct sixpack *sp;
 692
 693        write_lock(&disc_data_lock);
 694        sp = tty->disc_data;
 695        tty->disc_data = NULL;
 696        write_unlock(&disc_data_lock);
 697        if (!sp)
 698                return;
 699
 700        /*
 701         * We have now ensured that nobody can start using ap from now on, but
 702         * we have to wait for all existing users to finish.
 703         */
 704        if (!atomic_dec_and_test(&sp->refcnt))
 705                down(&sp->dead_sem);
 706
 707        unregister_netdev(sp->dev);
 708
 709        del_timer(&sp->tx_t);
 710        del_timer(&sp->resync_t);
 711
 712        /* Free all 6pack frame buffers. */
 713        kfree(sp->rbuff);
 714        kfree(sp->xbuff);
 715}
 716
 717/* Perform I/O control on an active 6pack channel. */
 718static int sixpack_ioctl(struct tty_struct *tty, struct file *file,
 719        unsigned int cmd, unsigned long arg)
 720{
 721        struct sixpack *sp = sp_get(tty);
 722        struct net_device *dev;
 723        unsigned int tmp, err;
 724
 725        if (!sp)
 726                return -ENXIO;
 727        dev = sp->dev;
 728
 729        switch(cmd) {
 730        case SIOCGIFNAME:
 731                err = copy_to_user((void __user *) arg, dev->name,
 732                                   strlen(dev->name) + 1) ? -EFAULT : 0;
 733                break;
 734
 735        case SIOCGIFENCAP:
 736                err = put_user(0, (int __user *) arg);
 737                break;
 738
 739        case SIOCSIFENCAP:
 740                if (get_user(tmp, (int __user *) arg)) {
 741                        err = -EFAULT;
 742                        break;
 743                }
 744
 745                sp->mode = tmp;
 746                dev->addr_len        = AX25_ADDR_LEN;
 747                dev->hard_header_len = AX25_KISS_HEADER_LEN +
 748                                       AX25_MAX_HEADER_LEN + 3;
 749                dev->type            = ARPHRD_AX25;
 750
 751                err = 0;
 752                break;
 753
 754         case SIOCSIFHWADDR: {
 755                char addr[AX25_ADDR_LEN];
 756
 757                if (copy_from_user(&addr,
 758                                   (void __user *) arg, AX25_ADDR_LEN)) {
 759                                err = -EFAULT;
 760                                break;
 761                        }
 762
 763                        netif_tx_lock_bh(dev);
 764                        memcpy(dev->dev_addr, &addr, AX25_ADDR_LEN);
 765                        netif_tx_unlock_bh(dev);
 766
 767                        err = 0;
 768                        break;
 769                }
 770
 771        default:
 772                err = tty_mode_ioctl(tty, file, cmd, arg);
 773        }
 774
 775        sp_put(sp);
 776
 777        return err;
 778}
 779
 780static struct tty_ldisc_ops sp_ldisc = {
 781        .owner          = THIS_MODULE,
 782        .magic          = TTY_LDISC_MAGIC,
 783        .name           = "6pack",
 784        .open           = sixpack_open,
 785        .close          = sixpack_close,
 786        .ioctl          = sixpack_ioctl,
 787        .receive_buf    = sixpack_receive_buf,
 788        .write_wakeup   = sixpack_write_wakeup,
 789};
 790
 791/* Initialize 6pack control device -- register 6pack line discipline */
 792
 793static const char msg_banner[]  __initdata = KERN_INFO \
 794        "AX.25: 6pack driver, " SIXPACK_VERSION "\n";
 795static const char msg_regfail[] __initdata = KERN_ERR  \
 796        "6pack: can't register line discipline (err = %d)\n";
 797
 798static int __init sixpack_init_driver(void)
 799{
 800        int status;
 801
 802        printk(msg_banner);
 803
 804        /* Register the provided line protocol discipline */
 805        if ((status = tty_register_ldisc(N_6PACK, &sp_ldisc)) != 0)
 806                printk(msg_regfail, status);
 807
 808        return status;
 809}
 810
 811static const char msg_unregfail[] __exitdata = KERN_ERR \
 812        "6pack: can't unregister line discipline (err = %d)\n";
 813
 814static void __exit sixpack_exit_driver(void)
 815{
 816        int ret;
 817
 818        if ((ret = tty_unregister_ldisc(N_6PACK)))
 819                printk(msg_unregfail, ret);
 820}
 821
 822/* encode an AX.25 packet into 6pack */
 823
 824static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw,
 825        int length, unsigned char tx_delay)
 826{
 827        int count = 0;
 828        unsigned char checksum = 0, buf[400];
 829        int raw_count = 0;
 830
 831        tx_buf_raw[raw_count++] = SIXP_PRIO_CMD_MASK | SIXP_TX_MASK;
 832        tx_buf_raw[raw_count++] = SIXP_SEOF;
 833
 834        buf[0] = tx_delay;
 835        for (count = 1; count < length; count++)
 836                buf[count] = tx_buf[count];
 837
 838        for (count = 0; count < length; count++)
 839                checksum += buf[count];
 840        buf[length] = (unsigned char) 0xff - checksum;
 841
 842        for (count = 0; count <= length; count++) {
 843                if ((count % 3) == 0) {
 844                        tx_buf_raw[raw_count++] = (buf[count] & 0x3f);
 845                        tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x30);
 846                } else if ((count % 3) == 1) {
 847                        tx_buf_raw[raw_count++] |= (buf[count] & 0x0f);
 848                        tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x3c);
 849                } else {
 850                        tx_buf_raw[raw_count++] |= (buf[count] & 0x03);
 851                        tx_buf_raw[raw_count++] = (buf[count] >> 2);
 852                }
 853        }
 854        if ((length % 3) != 2)
 855                raw_count++;
 856        tx_buf_raw[raw_count++] = SIXP_SEOF;
 857        return raw_count;
 858}
 859
 860/* decode 4 sixpack-encoded bytes into 3 data bytes */
 861
 862static void decode_data(struct sixpack *sp, unsigned char inbyte)
 863{
 864        unsigned char *buf;
 865
 866        if (sp->rx_count != 3) {
 867                sp->raw_buf[sp->rx_count++] = inbyte;
 868
 869                return;
 870        }
 871
 872        buf = sp->raw_buf;
 873        sp->cooked_buf[sp->rx_count_cooked++] =
 874                buf[0] | ((buf[1] << 2) & 0xc0);
 875        sp->cooked_buf[sp->rx_count_cooked++] =
 876                (buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0);
 877        sp->cooked_buf[sp->rx_count_cooked++] =
 878                (buf[2] & 0x03) | (inbyte << 2);
 879        sp->rx_count = 0;
 880}
 881
 882/* identify and execute a 6pack priority command byte */
 883
 884static void decode_prio_command(struct sixpack *sp, unsigned char cmd)
 885{
 886        unsigned char channel;
 887        int actual;
 888
 889        channel = cmd & SIXP_CHN_MASK;
 890        if ((cmd & SIXP_PRIO_DATA_MASK) != 0) {     /* idle ? */
 891
 892        /* RX and DCD flags can only be set in the same prio command,
 893           if the DCD flag has been set without the RX flag in the previous
 894           prio command. If DCD has not been set before, something in the
 895           transmission has gone wrong. In this case, RX and DCD are
 896           cleared in order to prevent the decode_data routine from
 897           reading further data that might be corrupt. */
 898
 899                if (((sp->status & SIXP_DCD_MASK) == 0) &&
 900                        ((cmd & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)) {
 901                                if (sp->status != 1)
 902                                        printk(KERN_DEBUG "6pack: protocol violation\n");
 903                                else
 904                                        sp->status = 0;
 905                                cmd &= ~SIXP_RX_DCD_MASK;
 906                }
 907                sp->status = cmd & SIXP_PRIO_DATA_MASK;
 908        } else { /* output watchdog char if idle */
 909                if ((sp->status2 != 0) && (sp->duplex == 1)) {
 910                        sp->led_state = 0x70;
 911                        sp->tty->ops->write(sp->tty, &sp->led_state, 1);
 912                        sp->tx_enable = 1;
 913                        actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2);
 914                        sp->xleft -= actual;
 915                        sp->xhead += actual;
 916                        sp->led_state = 0x60;
 917                        sp->status2 = 0;
 918
 919                }
 920        }
 921
 922        /* needed to trigger the TNC watchdog */
 923        sp->tty->ops->write(sp->tty, &sp->led_state, 1);
 924
 925        /* if the state byte has been received, the TNC is present,
 926           so the resync timer can be reset. */
 927
 928        if (sp->tnc_state == TNC_IN_SYNC) {
 929                del_timer(&sp->resync_t);
 930                sp->resync_t.data       = (unsigned long) sp;
 931                sp->resync_t.function   = resync_tnc;
 932                sp->resync_t.expires    = jiffies + SIXP_INIT_RESYNC_TIMEOUT;
 933                add_timer(&sp->resync_t);
 934        }
 935
 936        sp->status1 = cmd & SIXP_PRIO_DATA_MASK;
 937}
 938
 939/* identify and execute a standard 6pack command byte */
 940
 941static void decode_std_command(struct sixpack *sp, unsigned char cmd)
 942{
 943        unsigned char checksum = 0, rest = 0, channel;
 944        short i;
 945
 946        channel = cmd & SIXP_CHN_MASK;
 947        switch (cmd & SIXP_CMD_MASK) {     /* normal command */
 948        case SIXP_SEOF:
 949                if ((sp->rx_count == 0) && (sp->rx_count_cooked == 0)) {
 950                        if ((sp->status & SIXP_RX_DCD_MASK) ==
 951                                SIXP_RX_DCD_MASK) {
 952                                sp->led_state = 0x68;
 953                                sp->tty->ops->write(sp->tty, &sp->led_state, 1);
 954                        }
 955                } else {
 956                        sp->led_state = 0x60;
 957                        /* fill trailing bytes with zeroes */
 958                        sp->tty->ops->write(sp->tty, &sp->led_state, 1);
 959                        rest = sp->rx_count;
 960                        if (rest != 0)
 961                                 for (i = rest; i <= 3; i++)
 962                                        decode_data(sp, 0);
 963                        if (rest == 2)
 964                                sp->rx_count_cooked -= 2;
 965                        else if (rest == 3)
 966                                sp->rx_count_cooked -= 1;
 967                        for (i = 0; i < sp->rx_count_cooked; i++)
 968                                checksum += sp->cooked_buf[i];
 969                        if (checksum != SIXP_CHKSUM) {
 970                                printk(KERN_DEBUG "6pack: bad checksum %2.2x\n", checksum);
 971                        } else {
 972                                sp->rcount = sp->rx_count_cooked-2;
 973                                sp_bump(sp, 0);
 974                        }
 975                        sp->rx_count_cooked = 0;
 976                }
 977                break;
 978        case SIXP_TX_URUN: printk(KERN_DEBUG "6pack: TX underrun\n");
 979                break;
 980        case SIXP_RX_ORUN: printk(KERN_DEBUG "6pack: RX overrun\n");
 981                break;
 982        case SIXP_RX_BUF_OVL:
 983                printk(KERN_DEBUG "6pack: RX buffer overflow\n");
 984        }
 985}
 986
 987/* decode a 6pack packet */
 988
 989static void
 990sixpack_decode(struct sixpack *sp, unsigned char *pre_rbuff, int count)
 991{
 992        unsigned char inbyte;
 993        int count1;
 994
 995        for (count1 = 0; count1 < count; count1++) {
 996                inbyte = pre_rbuff[count1];
 997                if (inbyte == SIXP_FOUND_TNC) {
 998                        tnc_set_sync_state(sp, TNC_IN_SYNC);
 999                        del_timer(&sp->resync_t);
1000                }
1001                if ((inbyte & SIXP_PRIO_CMD_MASK) != 0)
1002                        decode_prio_command(sp, inbyte);
1003                else if ((inbyte & SIXP_STD_CMD_MASK) != 0)
1004                        decode_std_command(sp, inbyte);
1005                else if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)
1006                        decode_data(sp, inbyte);
1007        }
1008}
1009
1010MODULE_AUTHOR("Ralf Baechle DO1GRB <ralf@linux-mips.org>");
1011MODULE_DESCRIPTION("6pack driver for AX.25");
1012MODULE_LICENSE("GPL");
1013MODULE_ALIAS_LDISC(N_6PACK);
1014
1015module_init(sixpack_init_driver);
1016module_exit(sixpack_exit_driver);
1017
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.