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

📄 x25_asy.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	Things to sort out: * *	o	tbusy handling *	o	allow users to set the parameters *	o	sync/async switching ? * *	Note: This does _not_ implement CCITT X.25 asynchronous framing *	recommendations. Its primarily for testing purposes. If you wanted *	to do CCITT then in theory all you need is to nick the HDLC async *	checksum routines from ppp.c *      Changes: * *	2000-10-29	Henner Eisen	lapb_data_indication() return status. */#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/etherdevice.h>#include <linux/skbuff.h>#include <linux/if_arp.h>#include <linux/x25.h>#include <linux/lapb.h>#include <linux/init.h>#include "x25_asy.h"#include <net/x25device.h>static struct net_device **x25_asy_devs;static int x25_asy_maxdev = SL_NRUNIT;module_param(x25_asy_maxdev, int, 0);MODULE_LICENSE("GPL");static int x25_asy_esc(unsigned char *p, unsigned char *d, int len);static void x25_asy_unesc(struct x25_asy *sl, unsigned char c);static void x25_asy_setup(struct net_device *dev);/* Find a free X.25 channel, and link in this `tty' line. */static struct x25_asy *x25_asy_alloc(void){	struct net_device *dev = NULL;	struct x25_asy *sl;	int i;	if (x25_asy_devs == NULL)		return NULL;	/* Master array missing ! */	for (i = 0; i < x25_asy_maxdev; i++) {		dev = x25_asy_devs[i];		/* Not allocated ? */		if (dev == NULL)			break;		sl = dev->priv;		/* Not in use ? */		if (!test_and_set_bit(SLF_INUSE, &sl->flags))			return sl;	}	/* Sorry, too many, all slots in use */	if (i >= x25_asy_maxdev)		return NULL;	/* If no channels are available, allocate one */	if (!dev) {		char name[IFNAMSIZ];		sprintf(name, "x25asy%d", i);		dev = alloc_netdev(sizeof(struct x25_asy),				   name, x25_asy_setup);		if (!dev)			return NULL;		/* Initialize channel control data */		sl = dev->priv;		dev->base_addr    = i;		/* register device so that it can be ifconfig'ed       */		if (register_netdev(dev) == 0) {			/* (Re-)Set the INUSE bit.   Very Important! */			set_bit(SLF_INUSE, &sl->flags);			x25_asy_devs[i] = dev;			return sl;		} else {			printk("x25_asy_alloc() - register_netdev() failure.\n");			free_netdev(dev);		}	}	return NULL;}/* Free an X.25 channel. */static void x25_asy_free(struct x25_asy *sl){	/* Free all X.25 frame buffers. */	kfree(sl->rbuff);	sl->rbuff = NULL;	kfree(sl->xbuff);	sl->xbuff = NULL;	if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {		printk("%s: x25_asy_free for already free unit.\n", sl->dev->name);	}}static int x25_asy_change_mtu(struct net_device *dev, int newmtu){	struct x25_asy *sl = dev->priv;	unsigned char *xbuff, *rbuff;	int len = 2* newmtu;	xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);	rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);	if (xbuff == NULL || rbuff == NULL)  	{		printk("%s: unable to grow X.25 buffers, MTU change cancelled.\n",		       dev->name);		kfree(xbuff);		kfree(rbuff);		return -ENOMEM;	}	spin_lock_bh(&sl->lock);	xbuff    = xchg(&sl->xbuff, xbuff);	if (sl->xleft)  {		if (sl->xleft <= len)  {			memcpy(sl->xbuff, sl->xhead, sl->xleft);		} else  {			sl->xleft = 0;			sl->stats.tx_dropped++;		}	}	sl->xhead = sl->xbuff;	rbuff	 = xchg(&sl->rbuff, rbuff);	if (sl->rcount)  {		if (sl->rcount <= len) {			memcpy(sl->rbuff, rbuff, sl->rcount);		} else  {			sl->rcount = 0;			sl->stats.rx_over_errors++;			set_bit(SLF_ERROR, &sl->flags);		}	}	dev->mtu    = newmtu;	sl->buffsize = len;	spin_unlock_bh(&sl->lock);	kfree(xbuff);	kfree(rbuff);	return 0;}/* Set the "sending" flag.  This must be atomic, hence the ASM. */static inline void x25_asy_lock(struct x25_asy *sl){	netif_stop_queue(sl->dev);}/* Clear the "sending" flag.  This must be atomic, hence the ASM. */static inline void x25_asy_unlock(struct x25_asy *sl){	netif_wake_queue(sl->dev);}/* Send one completely decapsulated IP datagram to the IP layer. */static void x25_asy_bump(struct x25_asy *sl){	struct sk_buff *skb;	int count;	int err;	count = sl->rcount;	sl->stats.rx_bytes+=count;		skb = dev_alloc_skb(count+1);	if (skb == NULL)  	{		printk("%s: memory squeeze, dropping packet.\n", sl->dev->name);		sl->stats.rx_dropped++;		return;	}	skb_push(skb,1);	/* LAPB internal control */	memcpy(skb_put(skb,count), sl->rbuff, count);	skb->protocol = x25_type_trans(skb, sl->dev);	if((err=lapb_data_received(skb->dev, skb))!=LAPB_OK)	{		kfree_skb(skb);		printk(KERN_DEBUG "x25_asy: data received err - %d\n",err);	}	else	{		netif_rx(skb);		sl->dev->last_rx = jiffies;		sl->stats.rx_packets++;	}}/* Encapsulate one IP datagram and stuff into a TTY queue. */static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len){	unsigned char *p;	int actual, count, mtu = sl->dev->mtu;	if (len > mtu) 	{		/* Sigh, shouldn't occur BUT ... */		len = mtu;		printk ("%s: truncating oversized transmit packet!\n", sl->dev->name);		sl->stats.tx_dropped++;		x25_asy_unlock(sl);		return;	}	p = icp;	count = x25_asy_esc(p, (unsigned char *) sl->xbuff, len);	/* Order of next two lines is *very* important.	 * When we are sending a little amount of data,	 * the transfer may be completed inside driver.write()	 * routine, because it's running with interrupts enabled.	 * In this case we *never* got WRITE_WAKEUP event,	 * if we did not request it before write operation.	 *       14 Oct 1994  Dmitry Gorodchanin.	 */	sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);	actual = sl->tty->driver->write(sl->tty, sl->xbuff, count);	sl->xleft = count - actual;	sl->xhead = sl->xbuff + actual;	/* VSV */	clear_bit(SLF_OUTWAIT, &sl->flags);	/* reset outfill flag */}/* * Called by the driver when there's room for more data.  If we have * more packets to send, we send them here. */static void x25_asy_write_wakeup(struct tty_struct *tty){	int actual;	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;	/* First make sure we're connected. */	if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))		return;	if (sl->xleft <= 0)  	{		/* Now serial buffer is almost free & we can start		 * transmission of another packet */		sl->stats.tx_packets++;		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);		x25_asy_unlock(sl);		return;	}	actual = tty->driver->write(tty, sl->xhead, sl->xleft);	sl->xleft -= actual;	sl->xhead += actual;}static void x25_asy_timeout(struct net_device *dev){	struct x25_asy *sl = (struct x25_asy*)(dev->priv);	spin_lock(&sl->lock);	if (netif_queue_stopped(dev)) {		/* May be we must check transmitter timeout here ?		 *      14 Oct 1994 Dmitry Gorodchanin.		 */		printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,		       (sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ?		       "bad line quality" : "driver error");		sl->xleft = 0;		sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);		x25_asy_unlock(sl);	}	spin_unlock(&sl->lock);}/* Encapsulate an IP datagram and kick it into a TTY queue. */static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev){	struct x25_asy *sl = (struct x25_asy*)(dev->priv);	int err;	if (!netif_running(sl->dev)) {		printk("%s: xmit call when iface is down\n", dev->name);		kfree_skb(skb);		return 0;	}		switch(skb->data[0])	{		case 0x00:break;		case 0x01: /* Connection request .. do nothing */			if((err=lapb_connect_request(dev))!=LAPB_OK)				printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);			kfree_skb(skb);			return 0;		case 0x02: /* Disconnect request .. do nothing - hang up ?? */			if((err=lapb_disconnect_request(dev))!=LAPB_OK)				printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);		default:			kfree_skb(skb);			return  0;	}	skb_pull(skb,1);	/* Remove control byte */	/*	 * If we are busy already- too bad.  We ought to be able	 * to queue things at this point, to allow for a little	 * frame buffer.  Oh well...	 * -----------------------------------------------------	 * I hate queues in X.25 driver. May be it's efficient,	 * but for me latency is more important. ;)	 * So, no queues !	 *        14 Oct 1994  Dmitry Gorodchanin.	 */		if((err=lapb_data_request(dev,skb))!=LAPB_OK)	{		printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);		kfree_skb(skb);		return 0;	}	return 0;}/* *	LAPB interface boilerplate *//* *	Called when I frame data arrives. We did the work above - throw it *	at the net layer. */  static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb){	skb->dev->last_rx = jiffies;	return netif_rx(skb);}/* *	Data has emerged from the LAPB protocol machine. We don't handle *	busy cases too well. Its tricky to see how to do this nicely - *	perhaps lapb should allow us to bounce this ? */ static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb){	struct x25_asy *sl=dev->priv;		spin_lock(&sl->lock);	if (netif_queue_stopped(sl->dev) || sl->tty == NULL)	{		spin_unlock(&sl->lock);		printk(KERN_ERR "x25_asy: tbusy drop\n");		kfree_skb(skb);		return;	}	/* We were not busy, so we are now... :-) */	if (skb != NULL) 	{		x25_asy_lock(sl);		sl->stats.tx_bytes+=skb->len;		x25_asy_encaps(sl, skb->data, skb->len);		dev_kfree_skb(skb);	}	spin_unlock(&sl->lock);}/* *	LAPB connection establish/down information. */ static void x25_asy_connected(struct net_device *dev, int reason){	struct x25_asy *sl = dev->priv;	struct sk_buff *skb;	unsigned char *ptr;	if ((skb = dev_alloc_skb(1)) == NULL) {		printk(KERN_ERR "lapbeth: out of memory\n");		return;	}	ptr  = skb_put(skb, 1);	*ptr = 0x01;	skb->protocol = x25_type_trans(skb, sl->dev);	netif_rx(skb);	sl->dev->last_rx = jiffies;}static void x25_asy_disconnected(struct net_device *dev, int reason)

⌨️ 快捷键说明

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