1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/module.h>
17#include <linux/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 <linux/slab.h>
28#include <net/ax25.h>
29#include <linux/etherdevice.h>
30#include <linux/skbuff.h>
31#include <linux/rtnetlink.h>
32#include <linux/spinlock.h>
33#include <linux/if_arp.h>
34#include <linux/init.h>
35#include <linux/ip.h>
36#include <linux/tcp.h>
37#include <linux/semaphore.h>
38#include <linux/refcount.h>
39
40#define SIXPACK_VERSION "Revision: 0.3.0"
41
42
43#define SIXP_SEOF 0x40
44#define SIXP_TX_URUN 0x48
45#define SIXP_RX_ORUN 0x50
46#define SIXP_RX_BUF_OVL 0x58
47
48#define SIXP_CHKSUM 0xFF
49
50
51
52#define SIXP_CMD_MASK 0xC0
53#define SIXP_CHN_MASK 0x07
54#define SIXP_PRIO_CMD_MASK 0x80
55#define SIXP_STD_CMD_MASK 0x40
56#define SIXP_PRIO_DATA_MASK 0x38
57#define SIXP_TX_MASK 0x20
58#define SIXP_RX_MASK 0x10
59#define SIXP_RX_DCD_MASK 0x18
60#define SIXP_LEDS_ON 0x78
61#define SIXP_LEDS_OFF 0x60
62#define SIXP_CON 0x08
63#define SIXP_STA 0x10
64
65#define SIXP_FOUND_TNC 0xe9
66#define SIXP_CON_ON 0x68
67#define SIXP_DCD_MASK 0x08
68#define SIXP_DAMA_OFF 0
69
70
71#define SIXP_TXDELAY 25
72#define SIXP_PERSIST 50
73#define SIXP_SLOTTIME 10
74#define SIXP_INIT_RESYNC_TIMEOUT (3*HZ/2)
75#define SIXP_RESYNC_TIMEOUT 5*HZ
76
77
78#define SIXP_NRUNIT 31
79#define SIXP_MTU 256
80
81enum sixpack_flags {
82 SIXPF_ERROR,
83};
84
85struct sixpack {
86
87 struct tty_struct *tty;
88 struct net_device *dev;
89
90
91 unsigned char *rbuff;
92 int rcount;
93 unsigned char *xbuff;
94 unsigned char *xhead;
95 int xleft;
96
97 unsigned char raw_buf[4];
98 unsigned char cooked_buf[400];
99
100 unsigned int rx_count;
101 unsigned int rx_count_cooked;
102 spinlock_t rxlock;
103
104 int mtu;
105 int buffsize;
106
107 unsigned long flags;
108 unsigned char mode;
109
110
111 unsigned char tx_delay;
112 unsigned char persistence;
113 unsigned char slottime;
114 unsigned char duplex;
115 unsigned char led_state;
116 unsigned char status;
117 unsigned char status1;
118 unsigned char status2;
119 unsigned char tx_enable;
120 unsigned char tnc_state;
121
122 struct timer_list tx_t;
123 struct timer_list resync_t;
124 refcount_t refcnt;
125 struct completion dead;
126 spinlock_t lock;
127};
128
129#define AX25_6PACK_HEADER_LEN 0
130
131static void sixpack_decode(struct sixpack *, const unsigned char[], int);
132static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char);
133
134
135
136
137
138
139
140static void sp_xmit_on_air(struct timer_list *t)
141{
142 struct sixpack *sp = from_timer(sp, t, tx_t);
143 int actual, when = sp->slottime;
144 static unsigned char random;
145
146 random = random * 17 + 41;
147
148 if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) {
149 sp->led_state = 0x70;
150 sp->tty->ops->write(sp->tty, &sp->led_state, 1);
151 sp->tx_enable = 1;
152 actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2);
153 sp->xleft -= actual;
154 sp->xhead += actual;
155 sp->led_state = 0x60;
156 sp->tty->ops->write(sp->tty, &sp->led_state, 1);
157 sp->status2 = 0;
158 } else
159 mod_timer(&sp->tx_t, jiffies + ((when + 1) * HZ) / 100);
160}
161
162
163
164
165static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
166{
167 unsigned char *msg, *p = icp;
168 int actual, count;
169
170 if (len > sp->mtu) {
171 msg = "oversized transmit packet!";
172 goto out_drop;
173 }
174
175 if (p[0] > 5) {
176 msg = "invalid KISS command";
177 goto out_drop;
178 }
179
180 if ((p[0] != 0) && (len > 2)) {
181 msg = "KISS control packet too long";
182 goto out_drop;
183 }
184
185 if ((p[0] == 0) && (len < 15)) {
186 msg = "bad AX.25 packet to transmit";
187 goto out_drop;
188 }
189
190 count = encode_sixpack(p, sp->xbuff, len, sp->tx_delay);
191 set_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags);
192
193 switch (p[0]) {
194 case 1: sp->tx_delay = p[1];
195 return;
196 case 2: sp->persistence = p[1];
197 return;
198 case 3: sp->slottime = p[1];
199 return;
200 case 4:
201 return;
202 case 5: sp->duplex = p[1];
203 return;
204 }
205
206 if (p[0] != 0)
207 return;
208
209
210
211
212
213
214
215 if (sp->duplex == 1) {
216 sp->led_state = 0x70;
217 sp->tty->ops->write(sp->tty, &sp->led_state, 1);
218 sp->tx_enable = 1;
219 actual = sp->tty->ops->write(sp->tty, sp->xbuff, count);
220 sp->xleft = count - actual;
221 sp->xhead = sp->xbuff + actual;
222 sp->led_state = 0x60;
223 sp->tty->ops->write(sp->tty, &sp->led_state, 1);
224 } else {
225 sp->xleft = count;
226 sp->xhead = sp->xbuff;
227 sp->status2 = count;
228 sp_xmit_on_air(&sp->tx_t);
229 }
230
231 return;
232
233out_drop:
234 sp->dev->stats.tx_dropped++;
235 netif_start_queue(sp->dev);
236 if (net_ratelimit())
237 printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg);
238}
239
240
241
242static netdev_tx_t sp_xmit(struct sk_buff *skb, struct net_device *dev)
243{
244 struct sixpack *sp = netdev_priv(dev);
245
246 if (skb->protocol == htons(ETH_P_IP))
247 return ax25_ip_xmit(skb);
248
249 spin_lock_bh(&sp->lock);
250
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
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
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
286static int sp_set_mac_address(struct net_device *dev, void *addr)
287{
288 struct sockaddr_ax25 *sa = addr;
289
290 netif_tx_lock_bh(dev);
291 netif_addr_lock(dev);
292 __dev_addr_set(dev, &sa->sax25_call, AX25_ADDR_LEN);
293 netif_addr_unlock(dev);
294 netif_tx_unlock_bh(dev);
295
296 return 0;
297}
298
299static const struct net_device_ops sp_netdev_ops = {
300 .ndo_open = sp_open_dev,
301 .ndo_stop = sp_close,
302 .ndo_start_xmit = sp_xmit,
303 .ndo_set_mac_address = sp_set_mac_address,
304};
305
306static void sp_setup(struct net_device *dev)
307{
308
309 dev->netdev_ops = &sp_netdev_ops;
310 dev->mtu = SIXP_MTU;
311 dev->hard_header_len = AX25_MAX_HEADER_LEN;
312 dev->header_ops = &ax25_header_ops;
313
314 dev->addr_len = AX25_ADDR_LEN;
315 dev->type = ARPHRD_AX25;
316 dev->tx_queue_len = 10;
317
318
319 memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
320 dev_addr_set(dev, (u8 *)&ax25_defaddr);
321
322 dev->flags = 0;
323}
324
325
326
327
328
329
330
331
332static void sp_bump(struct sixpack *sp, char cmd)
333{
334 struct sk_buff *skb;
335 int count;
336 unsigned char *ptr;
337
338 count = sp->rcount + 1;
339
340 sp->dev->stats.rx_bytes += count;
341
342 if ((skb = dev_alloc_skb(count + 1)) == NULL)
343 goto out_mem;
344
345 ptr = skb_put(skb, count + 1);
346 *ptr++ = cmd;
347
348 memcpy(ptr, sp->cooked_buf + 1, count);
349 skb->protocol = ax25_type_trans(skb, sp->dev);
350 netif_rx(skb);
351 sp->dev->stats.rx_packets++;
352
353 return;
354
355out_mem:
356 sp->dev->stats.rx_dropped++;
357}
358
359
360
361
362
363
364
365
366
367
368
369
370static DEFINE_RWLOCK(disc_data_lock);
371
372static struct sixpack *sp_get(struct tty_struct *tty)
373{
374 struct sixpack *sp;
375
376 read_lock(&disc_data_lock);
377 sp = tty->disc_data;
378 if (sp)
379 refcount_inc(&sp->refcnt);
380 read_unlock(&disc_data_lock);
381
382 return sp;
383}
384
385static void sp_put(struct sixpack *sp)
386{
387 if (refcount_dec_and_test(&sp->refcnt))
388 complete(&sp->dead);
389}
390
391
392
393
394
395static void sixpack_write_wakeup(struct tty_struct *tty)
396{
397 struct sixpack *sp = sp_get(tty);
398 int actual;
399
400 if (!sp)
401 return;
402 if (sp->xleft <= 0) {
403
404
405 sp->dev->stats.tx_packets++;
406 clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
407 sp->tx_enable = 0;
408 netif_wake_queue(sp->dev);
409 goto out;
410 }
411
412 if (sp->tx_enable) {
413 actual = tty->ops->write(tty, sp->xhead, sp->xleft);
414 sp->xleft -= actual;
415 sp->xhead += actual;
416 }
417
418out:
419 sp_put(sp);
420}
421
422
423
424
425
426
427
428
429
430static void sixpack_receive_buf(struct tty_struct *tty,
431 const unsigned char *cp, const char *fp, int count)
432{
433 struct sixpack *sp;
434 int count1;
435
436 if (!count)
437 return;
438
439 sp = sp_get(tty);
440 if (!sp)
441 return;
442
443
444 count1 = count;
445 while (count) {
446 count--;
447 if (fp && *fp++) {
448 if (!test_and_set_bit(SIXPF_ERROR, &sp->flags))
449 sp->dev->stats.rx_errors++;
450 continue;
451 }
452 }
453 sixpack_decode(sp, cp, count1);
454
455 sp_put(sp);
456 tty_unthrottle(tty);
457}
458
459
460
461
462
463
464#define TNC_UNINITIALIZED 0
465#define TNC_UNSYNC_STARTUP 1
466#define TNC_UNSYNCED 2
467#define TNC_IN_SYNC 3
468
469static void __tnc_set_sync_state(struct sixpack *sp, int new_tnc_state)
470{
471 char *msg;
472
473 switch (new_tnc_state) {
474 default:
475 case TNC_UNSYNC_STARTUP:
476 msg = "Synchronizing with TNC";
477 break;
478 case TNC_UNSYNCED:
479 msg = "Lost synchronization with TNC\n";
480 break;
481 case TNC_IN_SYNC:
482 msg = "Found TNC";
483 break;
484 }
485
486 sp->tnc_state = new_tnc_state;
487 printk(KERN_INFO "%s: %s\n", sp->dev->name, msg);
488}
489
490static inline void tnc_set_sync_state(struct sixpack *sp, int new_tnc_state)
491{
492 int old_tnc_state = sp->tnc_state;
493
494 if (old_tnc_state != new_tnc_state)
495 __tnc_set_sync_state(sp, new_tnc_state);
496}
497
498static void resync_tnc(struct timer_list *t)
499{
500 struct sixpack *sp = from_timer(sp, t, resync_t);
501 static char resync_cmd = 0xe8;
502
503
504
505 sp->rx_count = 0;
506 sp->rx_count_cooked = 0;
507
508
509
510 sp->status = 1;
511 sp->status1 = 1;
512 sp->status2 = 0;
513
514
515
516 sp->led_state = 0x60;
517 sp->tty->ops->write(sp->tty, &sp->led_state, 1);
518 sp->tty->ops->write(sp->tty, &resync_cmd, 1);
519
520
521
522 mod_timer(&sp->resync_t, jiffies + SIXP_RESYNC_TIMEOUT);
523}
524
525static inline int tnc_init(struct sixpack *sp)
526{
527 unsigned char inbyte = 0xe8;
528
529 tnc_set_sync_state(sp, TNC_UNSYNC_STARTUP);
530
531 sp->tty->ops->write(sp->tty, &inbyte, 1);
532
533 mod_timer(&sp->resync_t, jiffies + SIXP_RESYNC_TIMEOUT);
534
535 return 0;
536}
537
538
539
540
541
542
543
544
545static int sixpack_open(struct tty_struct *tty)
546{
547 char *rbuff = NULL, *xbuff = NULL;
548 struct net_device *dev;
549 struct sixpack *sp;
550 unsigned long len;
551 int err = 0;
552
553 if (!capable(CAP_NET_ADMIN))
554 return -EPERM;
555 if (tty->ops->write == NULL)
556 return -EOPNOTSUPP;
557
558 dev = alloc_netdev(sizeof(struct sixpack), "sp%d", NET_NAME_UNKNOWN,
559 sp_setup);
560 if (!dev) {
561 err = -ENOMEM;
562 goto out;
563 }
564
565 sp = netdev_priv(dev);
566 sp->dev = dev;
567
568 spin_lock_init(&sp->lock);
569 spin_lock_init(&sp->rxlock);
570 refcount_set(&sp->refcnt, 1);
571 init_completion(&sp->dead);
572
573
574
575 len = dev->mtu * 2;
576
577 rbuff = kmalloc(len + 4, GFP_KERNEL);
578 xbuff = kmalloc(len + 4, GFP_KERNEL);
579
580 if (rbuff == NULL || xbuff == NULL) {
581 err = -ENOBUFS;
582 goto out_free;
583 }
584
585 spin_lock_bh(&sp->lock);
586
587 sp->tty = tty;
588
589 sp->rbuff = rbuff;
590 sp->xbuff = xbuff;
591
592 sp->mtu = AX25_MTU + 73;
593 sp->buffsize = len;
594 sp->rcount = 0;
595 sp->rx_count = 0;
596 sp->rx_count_cooked = 0;
597 sp->xleft = 0;
598
599 sp->flags = 0;
600
601 sp->duplex = 0;
602 sp->tx_delay = SIXP_TXDELAY;
603 sp->persistence = SIXP_PERSIST;
604 sp->slottime = SIXP_SLOTTIME;
605 sp->led_state = 0x60;
606 sp->status = 1;
607 sp->status1 = 1;
608 sp->status2 = 0;
609 sp->tx_enable = 0;
610
611 netif_start_queue(dev);
612
613 timer_setup(&sp->tx_t, sp_xmit_on_air, 0);
614
615 timer_setup(&sp->resync_t, resync_tnc, 0);
616
617 spin_unlock_bh(&sp->lock);
618
619
620 tty->disc_data = sp;
621 tty->receive_room = 65536;
622
623
624 err = register_netdev(dev);
625 if (err)
626 goto out_free;
627
628 tnc_init(sp);
629
630 return 0;
631
632out_free:
633 kfree(xbuff);
634 kfree(rbuff);
635
636 free_netdev(dev);
637
638out:
639 return err;
640}
641
642
643
644
645
646
647
648
649static void sixpack_close(struct tty_struct *tty)
650{
651 struct sixpack *sp;
652
653 write_lock_irq(&disc_data_lock);
654 sp = tty->disc_data;
655 tty->disc_data = NULL;
656 write_unlock_irq(&disc_data_lock);
657 if (!sp)
658 return;
659
660
661
662
663
664 if (!refcount_dec_and_test(&sp->refcnt))
665 wait_for_completion(&sp->dead);
666
667
668
669
670
671 netif_stop_queue(sp->dev);
672
673 unregister_netdev(sp->dev);
674
675 del_timer_sync(&sp->tx_t);
676 del_timer_sync(&sp->resync_t);
677
678
679 kfree(sp->rbuff);
680 kfree(sp->xbuff);
681
682 free_netdev(sp->dev);
683}
684
685
686static int sixpack_ioctl(struct tty_struct *tty, unsigned int cmd,
687 unsigned long arg)
688{
689 struct sixpack *sp = sp_get(tty);
690 struct net_device *dev;
691 unsigned int tmp, err;
692
693 if (!sp)
694 return -ENXIO;
695 dev = sp->dev;
696
697 switch(cmd) {
698 case SIOCGIFNAME:
699 err = copy_to_user((void __user *) arg, dev->name,
700 strlen(dev->name) + 1) ? -EFAULT : 0;
701 break;
702
703 case SIOCGIFENCAP:
704 err = put_user(0, (int __user *) arg);
705 break;
706
707 case SIOCSIFENCAP:
708 if (get_user(tmp, (int __user *) arg)) {
709 err = -EFAULT;
710 break;
711 }
712
713 sp->mode = tmp;
714 dev->addr_len = AX25_ADDR_LEN;
715 dev->hard_header_len = AX25_KISS_HEADER_LEN +
716 AX25_MAX_HEADER_LEN + 3;
717 dev->type = ARPHRD_AX25;
718
719 err = 0;
720 break;
721
722 case SIOCSIFHWADDR: {
723 char addr[AX25_ADDR_LEN];
724
725 if (copy_from_user(&addr,
726 (void __user *)arg, AX25_ADDR_LEN)) {
727 err = -EFAULT;
728 break;
729 }
730
731 netif_tx_lock_bh(dev);
732 __dev_addr_set(dev, &addr, AX25_ADDR_LEN);
733 netif_tx_unlock_bh(dev);
734 err = 0;
735 break;
736 }
737 default:
738 err = tty_mode_ioctl(tty, cmd, arg);
739 }
740
741 sp_put(sp);
742
743 return err;
744}
745
746static struct tty_ldisc_ops sp_ldisc = {
747 .owner = THIS_MODULE,
748 .num = N_6PACK,
749 .name = "6pack",
750 .open = sixpack_open,
751 .close = sixpack_close,
752 .ioctl = sixpack_ioctl,
753 .receive_buf = sixpack_receive_buf,
754 .write_wakeup = sixpack_write_wakeup,
755};
756
757
758
759static const char msg_banner[] __initconst = KERN_INFO \
760 "AX.25: 6pack driver, " SIXPACK_VERSION "\n";
761static const char msg_regfail[] __initconst = KERN_ERR \
762 "6pack: can't register line discipline (err = %d)\n";
763
764static int __init sixpack_init_driver(void)
765{
766 int status;
767
768 printk(msg_banner);
769
770
771 status = tty_register_ldisc(&sp_ldisc);
772 if (status)
773 printk(msg_regfail, status);
774
775 return status;
776}
777
778static void __exit sixpack_exit_driver(void)
779{
780 tty_unregister_ldisc(&sp_ldisc);
781}
782
783
784
785static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw,
786 int length, unsigned char tx_delay)
787{
788 int count = 0;
789 unsigned char checksum = 0, buf[400];
790 int raw_count = 0;
791
792 tx_buf_raw[raw_count++] = SIXP_PRIO_CMD_MASK | SIXP_TX_MASK;
793 tx_buf_raw[raw_count++] = SIXP_SEOF;
794
795 buf[0] = tx_delay;
796 for (count = 1; count < length; count++)
797 buf[count] = tx_buf[count];
798
799 for (count = 0; count < length; count++)
800 checksum += buf[count];
801 buf[length] = (unsigned char) 0xff - checksum;
802
803 for (count = 0; count <= length; count++) {
804 if ((count % 3) == 0) {
805 tx_buf_raw[raw_count++] = (buf[count] & 0x3f);
806 tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x30);
807 } else if ((count % 3) == 1) {
808 tx_buf_raw[raw_count++] |= (buf[count] & 0x0f);
809 tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x3c);
810 } else {
811 tx_buf_raw[raw_count++] |= (buf[count] & 0x03);
812 tx_buf_raw[raw_count++] = (buf[count] >> 2);
813 }
814 }
815 if ((length % 3) != 2)
816 raw_count++;
817 tx_buf_raw[raw_count++] = SIXP_SEOF;
818 return raw_count;
819}
820
821
822
823static void decode_data(struct sixpack *sp, unsigned char inbyte)
824{
825 unsigned char *buf;
826
827 if (sp->rx_count != 3) {
828 sp->raw_buf[sp->rx_count++] = inbyte;
829
830 return;
831 }
832
833 if (sp->rx_count_cooked + 2 >= sizeof(sp->cooked_buf)) {
834 pr_err("6pack: cooked buffer overrun, data loss\n");
835 sp->rx_count = 0;
836 return;
837 }
838
839 buf = sp->raw_buf;
840 sp->cooked_buf[sp->rx_count_cooked++] =
841 buf[0] | ((buf[1] << 2) & 0xc0);
842 sp->cooked_buf[sp->rx_count_cooked++] =
843 (buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0);
844 sp->cooked_buf[sp->rx_count_cooked++] =
845 (buf[2] & 0x03) | (inbyte << 2);
846 sp->rx_count = 0;
847}
848
849
850
851static void decode_prio_command(struct sixpack *sp, unsigned char cmd)
852{
853 int actual;
854
855 if ((cmd & SIXP_PRIO_DATA_MASK) != 0) {
856
857
858
859
860
861
862
863
864 if (((sp->status & SIXP_DCD_MASK) == 0) &&
865 ((cmd & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)) {
866 if (sp->status != 1)
867 printk(KERN_DEBUG "6pack: protocol violation\n");
868 else
869 sp->status = 0;
870 cmd &= ~SIXP_RX_DCD_MASK;
871 }
872 sp->status = cmd & SIXP_PRIO_DATA_MASK;
873 } else {
874 if ((sp->status2 != 0) && (sp->duplex == 1)) {
875 sp->led_state = 0x70;
876 sp->tty->ops->write(sp->tty, &sp->led_state, 1);
877 sp->tx_enable = 1;
878 actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2);
879 sp->xleft -= actual;
880 sp->xhead += actual;
881 sp->led_state = 0x60;
882 sp->status2 = 0;
883
884 }
885 }
886
887
888 sp->tty->ops->write(sp->tty, &sp->led_state, 1);
889
890
891
892
893 if (sp->tnc_state == TNC_IN_SYNC)
894 mod_timer(&sp->resync_t, jiffies + SIXP_INIT_RESYNC_TIMEOUT);
895
896 sp->status1 = cmd & SIXP_PRIO_DATA_MASK;
897}
898
899
900
901static void decode_std_command(struct sixpack *sp, unsigned char cmd)
902{
903 unsigned char checksum = 0, rest = 0;
904 short i;
905
906 switch (cmd & SIXP_CMD_MASK) {
907 case SIXP_SEOF:
908 if ((sp->rx_count == 0) && (sp->rx_count_cooked == 0)) {
909 if ((sp->status & SIXP_RX_DCD_MASK) ==
910 SIXP_RX_DCD_MASK) {
911 sp->led_state = 0x68;
912 sp->tty->ops->write(sp->tty, &sp->led_state, 1);
913 }
914 } else {
915 sp->led_state = 0x60;
916
917 sp->tty->ops->write(sp->tty, &sp->led_state, 1);
918 spin_lock_bh(&sp->rxlock);
919 rest = sp->rx_count;
920 if (rest != 0)
921 for (i = rest; i <= 3; i++)
922 decode_data(sp, 0);
923 if (rest == 2)
924 sp->rx_count_cooked -= 2;
925 else if (rest == 3)
926 sp->rx_count_cooked -= 1;
927 for (i = 0; i < sp->rx_count_cooked; i++)
928 checksum += sp->cooked_buf[i];
929 if (checksum != SIXP_CHKSUM) {
930 printk(KERN_DEBUG "6pack: bad checksum %2.2x\n", checksum);
931 } else {
932 sp->rcount = sp->rx_count_cooked-2;
933 sp_bump(sp, 0);
934 }
935 sp->rx_count_cooked = 0;
936 spin_unlock_bh(&sp->rxlock);
937 }
938 break;
939 case SIXP_TX_URUN: printk(KERN_DEBUG "6pack: TX underrun\n");
940 break;
941 case SIXP_RX_ORUN: printk(KERN_DEBUG "6pack: RX overrun\n");
942 break;
943 case SIXP_RX_BUF_OVL:
944 printk(KERN_DEBUG "6pack: RX buffer overflow\n");
945 }
946}
947
948
949
950static void
951sixpack_decode(struct sixpack *sp, const unsigned char *pre_rbuff, int count)
952{
953 unsigned char inbyte;
954 int count1;
955
956 for (count1 = 0; count1 < count; count1++) {
957 inbyte = pre_rbuff[count1];
958 if (inbyte == SIXP_FOUND_TNC) {
959 tnc_set_sync_state(sp, TNC_IN_SYNC);
960 del_timer(&sp->resync_t);
961 }
962 if ((inbyte & SIXP_PRIO_CMD_MASK) != 0)
963 decode_prio_command(sp, inbyte);
964 else if ((inbyte & SIXP_STD_CMD_MASK) != 0)
965 decode_std_command(sp, inbyte);
966 else if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK) {
967 spin_lock_bh(&sp->rxlock);
968 decode_data(sp, inbyte);
969 spin_unlock_bh(&sp->rxlock);
970 }
971 }
972}
973
974MODULE_AUTHOR("Ralf Baechle DO1GRB <ralf@linux-mips.org>");
975MODULE_DESCRIPTION("6pack driver for AX.25");
976MODULE_LICENSE("GPL");
977MODULE_ALIAS_LDISC(N_6PACK);
978
979module_init(sixpack_init_driver);
980module_exit(sixpack_exit_driver);
981