File Index
Files and directories
Sign in
FILE

6pack.c

File preview with syntax highlighting.

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