⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 6pack.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 6pack.c	This module implements the 6pack protocol for kernel-based *		devices like TTY. It interfaces between a raw TTY and the *		kernel's AX.25 protocol layers. * * Authors:	Andreas K鰊sgen <ajk@iehk.rwth-aachen.de> *              Ralf Baechle DL5RB <ralf@linux-mips.org> * * Quite a lot of stuff "stolen" by Joerg Reuter from slip.c, written by * *		Laurence Culhane, <loz@holmes.demon.co.uk> *		Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> */#include <linux/config.h>#include <linux/module.h>#include <asm/system.h>#include <asm/uaccess.h>#include <linux/bitops.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/in.h>#include <linux/tty.h>#include <linux/errno.h>#include <linux/netdevice.h>#include <linux/timer.h>#include <net/ax25.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/rtnetlink.h>#include <linux/spinlock.h>#include <linux/if_arp.h>#include <linux/init.h>#include <linux/ip.h>#include <linux/tcp.h>#include <asm/semaphore.h>#include <asm/atomic.h>#define SIXPACK_VERSION    "Revision: 0.3.0"/* sixpack priority commands */#define SIXP_SEOF		0x40	/* start and end of a 6pack frame */#define SIXP_TX_URUN		0x48	/* transmit overrun */#define SIXP_RX_ORUN		0x50	/* receive overrun */#define SIXP_RX_BUF_OVL		0x58	/* receive buffer overflow */#define SIXP_CHKSUM		0xFF	/* valid checksum of a 6pack frame *//* masks to get certain bits out of the status bytes sent by the TNC */#define SIXP_CMD_MASK		0xC0#define SIXP_CHN_MASK		0x07#define SIXP_PRIO_CMD_MASK	0x80#define SIXP_STD_CMD_MASK	0x40#define SIXP_PRIO_DATA_MASK	0x38#define SIXP_TX_MASK		0x20#define SIXP_RX_MASK		0x10#define SIXP_RX_DCD_MASK	0x18#define SIXP_LEDS_ON		0x78#define SIXP_LEDS_OFF		0x60#define SIXP_CON		0x08#define SIXP_STA		0x10#define SIXP_FOUND_TNC		0xe9#define SIXP_CON_ON		0x68#define SIXP_DCD_MASK		0x08#define SIXP_DAMA_OFF		0/* default level 2 parameters */#define SIXP_TXDELAY			(HZ/4)	/* in 1 s */#define SIXP_PERSIST			50	/* in 256ths */#define SIXP_SLOTTIME			(HZ/10)	/* in 1 s */#define SIXP_INIT_RESYNC_TIMEOUT	(3*HZ/2) /* in 1 s */#define SIXP_RESYNC_TIMEOUT		5*HZ	/* in 1 s *//* 6pack configuration. */#define SIXP_NRUNIT			31      /* MAX number of 6pack channels */#define SIXP_MTU			256	/* Default MTU */enum sixpack_flags {	SIXPF_ERROR,	/* Parity, etc. error	*/};struct sixpack {	/* Various fields. */	struct tty_struct	*tty;		/* ptr to TTY structure	*/	struct net_device	*dev;		/* easy for intr handling  */	/* These are pointers to the malloc()ed frame buffers. */	unsigned char		*rbuff;		/* receiver buffer	*/	int			rcount;         /* received chars counter  */	unsigned char		*xbuff;		/* transmitter buffer	*/	unsigned char		*xhead;         /* next byte to XMIT */	int			xleft;          /* bytes left in XMIT queue  */	unsigned char		raw_buf[4];	unsigned char		cooked_buf[400];	unsigned int		rx_count;	unsigned int		rx_count_cooked;	/* 6pack interface statistics. */	struct net_device_stats stats;	int			mtu;		/* Our mtu (to spot changes!) */	int			buffsize;       /* Max buffers sizes */	unsigned long		flags;		/* Flag values/ mode etc */	unsigned char		mode;		/* 6pack mode */	/* 6pack stuff */	unsigned char		tx_delay;	unsigned char		persistence;	unsigned char		slottime;	unsigned char		duplex;	unsigned char		led_state;	unsigned char		status;	unsigned char		status1;	unsigned char		status2;	unsigned char		tx_enable;	unsigned char		tnc_state;	struct timer_list	tx_t;	struct timer_list	resync_t;	atomic_t		refcnt;	struct semaphore	dead_sem;	spinlock_t		lock;};#define AX25_6PACK_HEADER_LEN 0static void sixpack_decode(struct sixpack *, unsigned char[], int);static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char);/* * Perform the persistence/slottime algorithm for CSMA access. If the * persistence check was successful, write the data to the serial driver. * Note that in case of DAMA operation, the data is not sent here. */static void sp_xmit_on_air(unsigned long channel){	struct sixpack *sp = (struct sixpack *) channel;	int actual, when = sp->slottime;	static unsigned char random;	random = random * 17 + 41;	if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) {		sp->led_state = 0x70;		sp->tty->driver->write(sp->tty, &sp->led_state, 1);		sp->tx_enable = 1;		actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2);		sp->xleft -= actual;		sp->xhead += actual;		sp->led_state = 0x60;		sp->tty->driver->write(sp->tty, &sp->led_state, 1);		sp->status2 = 0;	} else		mod_timer(&sp->tx_t, jiffies + ((when + 1) * HZ) / 100);}/* ----> 6pack timer interrupt handler and friends. <---- *//* Encapsulate one AX.25 frame and stuff into a TTY queue. */static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len){	unsigned char *msg, *p = icp;	int actual, count;	if (len > sp->mtu) {	/* sp->mtu = AX25_MTU = max. PACLEN = 256 */		msg = "oversized transmit packet!";		goto out_drop;	}	if (len > sp->mtu) {	/* sp->mtu = AX25_MTU = max. PACLEN = 256 */		msg = "oversized transmit packet!";		goto out_drop;	}	if (p[0] > 5) {		msg = "invalid KISS command";		goto out_drop;	}	if ((p[0] != 0) && (len > 2)) {		msg = "KISS control packet too long";		goto out_drop;	}	if ((p[0] == 0) && (len < 15)) {		msg = "bad AX.25 packet to transmit";		goto out_drop;	}	count = encode_sixpack(p, sp->xbuff, len, sp->tx_delay);	set_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags);	switch (p[0]) {	case 1:	sp->tx_delay = p[1];		return;	case 2:	sp->persistence = p[1];		return;	case 3:	sp->slottime = p[1];		return;	case 4:	/* ignored */		return;	case 5:	sp->duplex = p[1];		return;	}	if (p[0] != 0)		return;	/*	 * In case of fullduplex or DAMA operation, we don't take care about the	 * state of the DCD or of any timers, as the determination of the	 * correct time to send is the job of the AX.25 layer. We send	 * immediately after data has arrived.	 */	if (sp->duplex == 1) {		sp->led_state = 0x70;		sp->tty->driver->write(sp->tty, &sp->led_state, 1);		sp->tx_enable = 1;		actual = sp->tty->driver->write(sp->tty, sp->xbuff, count);		sp->xleft = count - actual;		sp->xhead = sp->xbuff + actual;		sp->led_state = 0x60;		sp->tty->driver->write(sp->tty, &sp->led_state, 1);	} else {		sp->xleft = count;		sp->xhead = sp->xbuff;		sp->status2 = count;		sp_xmit_on_air((unsigned long)sp);	}	return;out_drop:	sp->stats.tx_dropped++;	netif_start_queue(sp->dev);	if (net_ratelimit())		printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg);}/* Encapsulate an IP datagram and kick it into a TTY queue. */static int sp_xmit(struct sk_buff *skb, struct net_device *dev){	struct sixpack *sp = netdev_priv(dev);	spin_lock_bh(&sp->lock);	/* We were not busy, so we are now... :-) */	netif_stop_queue(dev);	sp->stats.tx_bytes += skb->len;	sp_encaps(sp, skb->data, skb->len);	spin_unlock_bh(&sp->lock);	dev_kfree_skb(skb);	return 0;}static int sp_open_dev(struct net_device *dev){	struct sixpack *sp = netdev_priv(dev);	if (sp->tty == NULL)		return -ENODEV;	return 0;}/* Close the low-level part of the 6pack channel. */static int sp_close(struct net_device *dev){	struct sixpack *sp = netdev_priv(dev);	spin_lock_bh(&sp->lock);	if (sp->tty) {		/* TTY discipline is running. */		clear_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags);	}	netif_stop_queue(dev);	spin_unlock_bh(&sp->lock);	return 0;}/* Return the frame type ID */static int sp_header(struct sk_buff *skb, struct net_device *dev,	unsigned short type, void *daddr, void *saddr, unsigned len){#ifdef CONFIG_INET	if (type != htons(ETH_P_AX25))		return ax25_hard_header(skb, dev, type, daddr, saddr, len);#endif	return 0;}static struct net_device_stats *sp_get_stats(struct net_device *dev){	struct sixpack *sp = netdev_priv(dev);	return &sp->stats;}static int sp_set_mac_address(struct net_device *dev, void *addr){	struct sockaddr_ax25 *sa = addr;	spin_lock_irq(&dev->xmit_lock);	memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);	spin_unlock_irq(&dev->xmit_lock);	return 0;}static int sp_rebuild_header(struct sk_buff *skb){#ifdef CONFIG_INET	return ax25_rebuild_header(skb);#else	return 0;#endif}static void sp_setup(struct net_device *dev){	static char ax25_bcast[AX25_ADDR_LEN] =		{'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};	static char ax25_test[AX25_ADDR_LEN] =		{'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};	/* Finish setting up the DEVICE info. */	dev->mtu		= SIXP_MTU;	dev->hard_start_xmit	= sp_xmit;	dev->open		= sp_open_dev;	dev->destructor		= free_netdev;	dev->stop		= sp_close;	dev->hard_header	= sp_header;	dev->get_stats	        = sp_get_stats;	dev->set_mac_address    = sp_set_mac_address;	dev->hard_header_len	= AX25_MAX_HEADER_LEN;	dev->addr_len		= AX25_ADDR_LEN;	dev->type		= ARPHRD_AX25;	dev->tx_queue_len	= 10;	dev->rebuild_header	= sp_rebuild_header;	dev->tx_timeout		= NULL;	/* Only activated in AX.25 mode */	memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);	memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);	SET_MODULE_OWNER(dev);	dev->flags		= 0;}/* Send one completely decapsulated IP datagram to the IP layer. *//* * This is the routine that sends the received data to the kernel AX.25. * 'cmd' is the KISS command. For AX.25 data, it is zero. */static void sp_bump(struct sixpack *sp, char cmd){	struct sk_buff *skb;	int count;	unsigned char *ptr;	count = sp->rcount + 1;	sp->stats.rx_bytes += count;	if ((skb = dev_alloc_skb(count)) == NULL)		goto out_mem;	ptr = skb_put(skb, count);	*ptr++ = cmd;	/* KISS command */	memcpy(ptr, sp->cooked_buf + 1, count);	skb->protocol = ax25_type_trans(skb, sp->dev);	netif_rx(skb);	sp->dev->last_rx = jiffies;	sp->stats.rx_packets++;	return;out_mem:	sp->stats.rx_dropped++;}/* ----------------------------------------------------------------------- *//* * We have a potential race on dereferencing tty->disc_data, because the tty * layer provides no locking at all - thus one cpu could be running * sixpack_receive_buf while another calls sixpack_close, which zeroes * tty->disc_data and frees the memory that sixpack_receive_buf is using.  The * best way to fix this is to use a rwlock in the tty struct, but for now we * use a single global rwlock for all ttys in ppp line discipline. */static DEFINE_RWLOCK(disc_data_lock);                                                                                static struct sixpack *sp_get(struct tty_struct *tty){	struct sixpack *sp;	read_lock(&disc_data_lock);	sp = tty->disc_data;	if (sp)		atomic_inc(&sp->refcnt);	read_unlock(&disc_data_lock);	return sp;}static void sp_put(struct sixpack *sp){	if (atomic_dec_and_test(&sp->refcnt))		up(&sp->dead_sem);}/* * Called by the TTY driver when there's room for more data.  If we have * more packets to send, we send them here. */static void sixpack_write_wakeup(struct tty_struct *tty){	struct sixpack *sp = sp_get(tty);	int actual;	if (!sp)		return;	if (sp->xleft <= 0)  {		/* Now serial buffer is almost free & we can start		 * transmission of another packet */		sp->stats.tx_packets++;		clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);		sp->tx_enable = 0;		netif_wake_queue(sp->dev);		goto out;	}	if (sp->tx_enable) {		actual = tty->driver->write(tty, sp->xhead, sp->xleft);		sp->xleft -= actual;		sp->xhead += actual;	}out:	sp_put(sp);}/* ----------------------------------------------------------------------- */static int sixpack_receive_room(struct tty_struct *tty){	return 65536;  /* We can handle an infinite amount of data. :-) */}/* * Handle the 'receiver data ready' interrupt. * This function is called by the 'tty_io' module in the kernel when * a block of 6pack data has been received, which can now be decapsulated * and sent on to some IP layer for further processing. */static void sixpack_receive_buf(struct tty_struct *tty,	const unsigned char *cp, char *fp, int count){	struct sixpack *sp;	unsigned char buf[512];	int count1;	if (!count)		return;	sp = sp_get(tty);	if (!sp)		return;	memcpy(buf, cp, count < sizeof(buf) ? count : sizeof(buf));	/* Read the characters out of the buffer */	count1 = count;	while (count) {		count--;		if (fp && *fp++) {			if (!test_and_set_bit(SIXPF_ERROR, &sp->flags))				sp->stats.rx_errors++;			continue;		}	}	sixpack_decode(sp, buf, count1);	sp_put(sp);	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)	    && tty->driver->unthrottle)		tty->driver->unthrottle(tty);}/* * Try to resync the TNC. Called by the resync timer defined in * decode_prio_command */#define TNC_UNINITIALIZED	0#define TNC_UNSYNC_STARTUP	1#define TNC_UNSYNCED		2#define TNC_IN_SYNC		3static void __tnc_set_sync_state(struct sixpack *sp, int new_tnc_state){	char *msg;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -