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

📄 mkiss.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (type != htons(ETH_P_AX25))		return ax25_encapsulate(skb, dev, type, daddr, saddr, len);#endif	return 0;}static int ax_rebuild_header(struct sk_buff *skb){#ifdef CONFIG_INET	return ax25_rebuild_header(skb);#else	return 0;#endif}#endif	/* CONFIG_{AX25,AX25_MODULE} *//* Open the low-level part of the AX25 channel. Easy! */static int ax_open(struct net_device *dev){	struct ax_disp *ax = (struct ax_disp *) dev->priv;	unsigned long len;	if (ax->tty == NULL)		return -ENODEV;	/*	 * Allocate the frame buffers:	 *	 * rbuff	Receive buffer.	 * xbuff	Transmit buffer.	 */	len = dev->mtu * 2;	/*	 * allow for arrival of larger UDP packets, even if we say not to	 * also fixes a bug in which SunOS sends 512-byte packets even with	 * an MSS of 128	 */	if (len < 576 * 2)		len = 576 * 2;	if ((ax->rbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL)		goto norbuff;	if ((ax->xbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL)		goto noxbuff;	ax->mtu	     = dev->mtu + 73;	ax->buffsize = len;	ax->rcount   = 0;	ax->xleft    = 0;	ax->flags   &= (1 << AXF_INUSE);      /* Clear ESCAPE & ERROR flags */	netif_start_queue(dev);	return 0;noxbuff:	kfree(ax->rbuff);norbuff:	return -ENOMEM;}/* Close the low-level part of the AX25 channel. Easy! */static int ax_close(struct net_device *dev){	struct ax_disp *ax = (struct ax_disp *) dev->priv;	if (ax->tty == NULL)		return -EBUSY;	ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);	netif_stop_queue(dev);	return 0;}static int ax25_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 data has been received, which can now be decapsulated * and sent on to the AX.25 layer for further processing. */static void ax25_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count){	struct ax_disp *ax = (struct ax_disp *) tty->disc_data;	if (ax == NULL || ax->magic != AX25_MAGIC || !netif_running(ax->dev))		return;	/*	 * Argh! mtu change time! - costs us the packet part received	 * at the change	 */	if (ax->mtu != ax->dev->mtu + 73)		ax_changedmtu(ax);	/* Read the characters out of the buffer */	while (count--) {		if (fp != NULL && *fp++) {			if (!test_and_set_bit(AXF_ERROR, &ax->flags))				ax->rx_errors++;			cp++;			continue;		}		kiss_unesc(ax, *cp++);	}}static int ax25_open(struct tty_struct *tty){	struct ax_disp *ax = (struct ax_disp *) tty->disc_data;	struct ax_disp *tmp_ax;	struct mkiss_channel *mkiss;	int err, cnt;	/* First make sure we're not already connected. */	if (ax && ax->magic == AX25_MAGIC)		return -EEXIST;	/* OK.  Find a free AX25 channel to use. */	if ((ax = ax_alloc()) == NULL)		return -ENFILE;	ax->tty = tty;	tty->disc_data = ax;	ax->mkiss = NULL;	tmp_ax    = NULL;	if (tty->driver.flush_buffer)		tty->driver.flush_buffer(tty);	tty_ldisc_flush(tty);	/* Restore default settings */	ax->dev->type = ARPHRD_AX25;	/* Perform the low-level AX25 initialization. */	if ((err = ax_open(ax->dev)))		return err;	mkiss = ax->tty->driver_data;	if (mkiss->magic  == MKISS_DRIVER_MAGIC) {		for (cnt = 1; cnt < ax25_maxdev; cnt++) {			if (ax25_ctrls[cnt]) {				if (netif_running(&ax25_ctrls[cnt]->dev)) {					if (ax == &ax25_ctrls[cnt]->ctrl) {						cnt--;						tmp_ax = &ax25_ctrls[cnt]->ctrl;						break;					}				}			}		}	}	if (tmp_ax != NULL) {		ax->mkiss     = tmp_ax;		tmp_ax->mkiss = ax;	}	MOD_INC_USE_COUNT;	/* Done.  We have linked the TTY line to a channel. */	return ax->dev->base_addr;}static void ax25_close(struct tty_struct *tty){	struct ax_disp *ax = (struct ax_disp *) tty->disc_data;	/* First make sure we're connected. */	if (ax == NULL || ax->magic != AX25_MAGIC)		return;	unregister_netdev(ax->dev);	tty->disc_data = 0;	ax->tty        = NULL;	ax_free(ax);	MOD_DEC_USE_COUNT;}static struct net_device_stats *ax_get_stats(struct net_device *dev){	static struct net_device_stats stats;	struct ax_disp *ax = (struct ax_disp *) dev->priv;	memset(&stats, 0, sizeof(struct net_device_stats));	stats.rx_packets     = ax->rx_packets;	stats.tx_packets     = ax->tx_packets;	stats.rx_bytes	     = ax->rx_bytes;	stats.tx_bytes       = ax->tx_bytes;	stats.rx_dropped     = ax->rx_dropped;	stats.tx_dropped     = ax->tx_dropped;	stats.tx_errors      = ax->tx_errors;	stats.rx_errors      = ax->rx_errors;	stats.rx_over_errors = ax->rx_over_errors;	return &stats;}/************************************************************************ *			   STANDARD ENCAPSULATION	        	 * ************************************************************************/static int kiss_esc(unsigned char *s, unsigned char *d, int len){	unsigned char *ptr = d;	unsigned char c;	/*	 * Send an initial END character to flush out any	 * data that may have accumulated in the receiver	 * due to line noise.	 */	*ptr++ = END;	while (len-- > 0) {		switch (c = *s++) {			case END:				*ptr++ = ESC;				*ptr++ = ESC_END;				break;			case ESC:				*ptr++ = ESC;				*ptr++ = ESC_ESC;				break;			default:				*ptr++ = c;				break;		}	}	*ptr++ = END;	return ptr - d;}/* * MW: * OK its ugly, but tell me a better solution without copying the * packet to a temporary buffer :-) */static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, int len){	unsigned char *ptr = d;	unsigned char c=0;	*ptr++ = END;	while (len > 0) {		if (len > 2) 			c = *s++;		else if (len > 1)			c = crc >> 8;		else if (len > 0)			c = crc & 0xff;		len--;		switch (c) {                        case END:                                *ptr++ = ESC;                                *ptr++ = ESC_END;                                break;                        case ESC:                                *ptr++ = ESC;                                *ptr++ = ESC_ESC;                                break;                        default:                                *ptr++ = c;                                break;		}	}	*ptr++ = END;	return ptr - d;		}static void kiss_unesc(struct ax_disp *ax, unsigned char s){	switch (s) {		case END:			/* drop keeptest bit = VSV */			if (test_bit(AXF_KEEPTEST, &ax->flags))				clear_bit(AXF_KEEPTEST, &ax->flags);			if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2))				ax_bump(ax);			clear_bit(AXF_ESCAPE, &ax->flags);			ax->rcount = 0;			return;		case ESC:			set_bit(AXF_ESCAPE, &ax->flags);			return;		case ESC_ESC:			if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))				s = ESC;			break;		case ESC_END:			if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))				s = END;			break;	}	if (!test_bit(AXF_ERROR, &ax->flags)) {		if (ax->rcount < ax->buffsize) {			ax->rbuff[ax->rcount++] = s;			return;		}		ax->rx_over_errors++;		set_bit(AXF_ERROR, &ax->flags);	}}static int ax_set_mac_address(struct net_device *dev, void *addr){	if (copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN))		return -EFAULT;	return 0;}static int ax_set_dev_mac_address(struct net_device *dev, void *addr){	struct sockaddr *sa = addr;	memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN);	return 0;}/* Perform I/O control on an active ax25 channel. */static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg){	struct ax_disp *ax = (struct ax_disp *) tty->disc_data;	unsigned int tmp;	/* First make sure we're connected. */	if (ax == NULL || ax->magic != AX25_MAGIC)		return -EINVAL;	switch (cmd) {	 	case SIOCGIFNAME:			if (copy_to_user(arg, ax->dev->name, strlen(ax->dev->name) + 1))				return -EFAULT;			return 0;		case SIOCGIFENCAP:			return put_user(4, (int *)arg);		case SIOCSIFENCAP:			if (get_user(tmp, (int *)arg))				return -EFAULT;			ax->mode = tmp;			ax->dev->addr_len        = AX25_ADDR_LEN;	  /* sizeof an AX.25 addr */			ax->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3;			ax->dev->type            = ARPHRD_AX25;			return 0;		 case SIOCSIFHWADDR:			return ax_set_mac_address(ax->dev, arg);		default:			return -ENOIOCTLCMD;	}}static int ax_open_dev(struct net_device *dev){	struct ax_disp *ax = (struct ax_disp *) dev->priv;	if (ax->tty == NULL)		return -ENODEV;	return 0;}/* Initialize the driver.  Called by network startup. */static int ax25_init(struct net_device *dev){	struct ax_disp *ax = (struct ax_disp *) dev->priv;	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};	if (ax == NULL)		/* Allocation failed ?? */		return -ENODEV;	/* Set up the "AX25 Control Block". (And clear statistics) */	memset(ax, 0, sizeof (struct ax_disp));	ax->magic  = AX25_MAGIC;	ax->dev	   = dev;	/* Finish setting up the DEVICE info. */	dev->mtu             = AX_MTU;	dev->hard_start_xmit = ax_xmit;	dev->open            = ax_open_dev;	dev->stop            = ax_close;	dev->get_stats	     = ax_get_stats;	dev->set_mac_address = ax_set_dev_mac_address;	dev->hard_header_len = 0;	dev->addr_len        = 0;	dev->type            = ARPHRD_AX25;	dev->tx_queue_len    = 10;	dev->hard_header     = ax_header;	dev->rebuild_header  = ax_rebuild_header;	memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);	memcpy(dev->dev_addr,  ax25_test,  AX25_ADDR_LEN);	/* New-style flags. */	dev->flags      = IFF_BROADCAST | IFF_MULTICAST;	return 0;}/* ******************************************************************** *//* *			Init MKISS driver			      * *//* ******************************************************************** */static int __init mkiss_init_driver(void){	int status;	printk(banner);	if (ax25_maxdev < 4)	  ax25_maxdev = 4; /* Sanity */	if ((ax25_ctrls = kmalloc(sizeof(void *) * ax25_maxdev, GFP_KERNEL)) == NULL) {		printk(KERN_ERR "mkiss: Can't allocate ax25_ctrls[] array!\n");		return -ENOMEM;	}	/* Clear the pointer array, we allocate devices when we need them */	memset(ax25_ctrls, 0, sizeof(void*) * ax25_maxdev); /* Pointers */	/* Fill in our line protocol discipline, and register it */	ax_ldisc.magic		= TTY_LDISC_MAGIC;	ax_ldisc.name		= "mkiss";	ax_ldisc.open		= ax25_open;	ax_ldisc.close		= ax25_close;	ax_ldisc.ioctl		= (int (*)(struct tty_struct *, struct file *,					unsigned int, unsigned long))ax25_disp_ioctl;	ax_ldisc.receive_buf	= ax25_receive_buf;	ax_ldisc.receive_room	= ax25_receive_room;	ax_ldisc.write_wakeup	= ax25_write_wakeup;	if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0) {		printk(KERN_ERR "mkiss: can't register line discipline (err = %d)\n", status);		kfree(ax25_ctrls);	}	return status;}static void __exit mkiss_exit_driver(void){	int i;	for (i = 0; i < ax25_maxdev; i++) {		if (ax25_ctrls[i]) {			/*			* VSV = if dev->start==0, then device			* unregistered while close proc.			*/			if (netif_running(&ax25_ctrls[i]->dev))				unregister_netdev(&ax25_ctrls[i]->dev);			kfree(ax25_ctrls[i]);		}	}	kfree(ax25_ctrls);	ax25_ctrls = NULL;	if ((i = tty_register_ldisc(N_AX25, NULL)))		printk(KERN_ERR "mkiss: can't unregister line discipline (err = %d)\n", i);}MODULE_AUTHOR("Hans Albas PE1AYX <hans@esrac.ele.tue.nl>");MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs");MODULE_PARM(ax25_maxdev, "i");MODULE_PARM_DESC(ax25_maxdev, "number of MKISS devices");MODULE_LICENSE("GPL");module_init(mkiss_init_driver);module_exit(mkiss_exit_driver);

⌨️ 快捷键说明

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