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

📄 mkiss.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
			count = kiss_esc(p, (unsigned char *)ax->xbuff, len);		}  	}	spin_unlock_bh(&ax->buflock);	set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);	actual = ax->tty->driver->write(ax->tty, ax->xbuff, count);	ax->stats.tx_packets++;	ax->stats.tx_bytes += actual;	ax->dev->trans_start = jiffies;	ax->xleft = count - actual;	ax->xhead = ax->xbuff + actual;}/* Encapsulate an AX.25 packet and kick it into a TTY queue. */static int ax_xmit(struct sk_buff *skb, struct net_device *dev){	struct mkiss *ax = netdev_priv(dev);	if (!netif_running(dev))  {		printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name);		return 1;	}	if (netif_queue_stopped(dev)) {		/*		 * May be we must check transmitter timeout here ?		 *      14 Oct 1994 Dmitry Gorodchanin.		 */		if (time_before(jiffies, dev->trans_start + 20 * HZ)) {			/* 20 sec timeout not reached */			return 1;		}		printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name,		       (ax->tty->driver->chars_in_buffer(ax->tty) || ax->xleft) ?		       "bad line quality" : "driver error");		ax->xleft = 0;		clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);		netif_start_queue(dev);	}	/* We were not busy, so we are now... :-) */	if (skb != NULL) {		netif_stop_queue(dev);		ax_encaps(dev, skb->data, skb->len);		kfree_skb(skb);	}	return 0;}static int ax_open_dev(struct net_device *dev){	struct mkiss *ax = netdev_priv(dev);	if (ax->tty == NULL)		return -ENODEV;	return 0;}#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)/* Return the frame type ID */static int ax_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 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 mkiss *ax = netdev_priv(dev);	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 */	spin_lock_init(&ax->buflock);	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 mkiss *ax = netdev_priv(dev);	if (ax->tty)		clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);	netif_stop_queue(dev);	return 0;}static struct net_device_stats *ax_get_stats(struct net_device *dev){	struct mkiss *ax = netdev_priv(dev);	return &ax->stats;}static void ax_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             = 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_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);	dev->flags      = IFF_BROADCAST | IFF_MULTICAST;}/* * 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 mkiss *mkiss_get(struct tty_struct *tty){	struct mkiss *ax;	read_lock(&disc_data_lock);	ax = tty->disc_data;	if (ax)		atomic_inc(&ax->refcnt);	read_unlock(&disc_data_lock);	return ax;}static void mkiss_put(struct mkiss *ax){	if (atomic_dec_and_test(&ax->refcnt))		up(&ax->dead_sem);}static int crc_force = 0;	/* Can be overridden with insmod */static int mkiss_open(struct tty_struct *tty){	struct net_device *dev;	struct mkiss *ax;	int err;	if (!capable(CAP_NET_ADMIN))		return -EPERM;	dev = alloc_netdev(sizeof(struct mkiss), "ax%d", ax_setup);	if (!dev) {		err = -ENOMEM;		goto out;	}	ax = netdev_priv(dev);	ax->dev = dev;	spin_lock_init(&ax->buflock);	atomic_set(&ax->refcnt, 1);	init_MUTEX_LOCKED(&ax->dead_sem);	ax->tty = tty;	tty->disc_data = ax;	if (tty->driver->flush_buffer)		tty->driver->flush_buffer(tty);	/* Restore default settings */	dev->type = ARPHRD_AX25;	/* Perform the low-level AX25 initialization. */	if ((err = ax_open(ax->dev))) {		goto out_free_netdev;	}	if (register_netdev(dev))		goto out_free_buffers;	/* after register_netdev() - because else printk smashes the kernel */	switch (crc_force) {	case 3:		ax->crcmode  = CRC_MODE_SMACK;		printk(KERN_INFO "mkiss: %s: crc mode smack forced.\n",		       ax->dev->name);		break;	case 2:		ax->crcmode  = CRC_MODE_FLEX;		printk(KERN_INFO "mkiss: %s: crc mode flexnet forced.\n",		       ax->dev->name);		break;	case 1:		ax->crcmode  = CRC_MODE_NONE;		printk(KERN_INFO "mkiss: %s: crc mode disabled.\n",		       ax->dev->name);		break;	case 0:		/* fall through */	default:		crc_force = 0;		printk(KERN_INFO "mkiss: %s: crc mode is auto.\n",		       ax->dev->name);		ax->crcmode  = CRC_MODE_SMACK_TEST;	}	ax->crcauto = (crc_force ? 0 : 1);	netif_start_queue(dev);	/* Done.  We have linked the TTY line to a channel. */	return 0;out_free_buffers:	kfree(ax->rbuff);	kfree(ax->xbuff);out_free_netdev:	free_netdev(dev);out:	return err;}static void mkiss_close(struct tty_struct *tty){	struct mkiss *ax;	write_lock(&disc_data_lock);	ax = tty->disc_data;	tty->disc_data = NULL;	write_unlock(&disc_data_lock);	if (ax == 0)		return;	/*	 * We have now ensured that nobody can start using ap from now on, but	 * we have to wait for all existing users to finish.	 */	if (!atomic_dec_and_test(&ax->refcnt))		down(&ax->dead_sem);	unregister_netdev(ax->dev);	/* Free all AX25 frame buffers. */	kfree(ax->rbuff);	kfree(ax->xbuff);	ax->tty = NULL;}/* Perform I/O control on an active ax25 channel. */static int mkiss_ioctl(struct tty_struct *tty, struct file *file,	unsigned int cmd, unsigned long arg){	struct mkiss *ax = mkiss_get(tty);	struct net_device *dev = ax->dev;	unsigned int tmp, err;	/* First make sure we're connected. */	if (ax == NULL)		return -ENXIO;	switch (cmd) { 	case SIOCGIFNAME:		err = copy_to_user((void __user *) arg, ax->dev->name,		                   strlen(ax->dev->name) + 1) ? -EFAULT : 0;		break;	case SIOCGIFENCAP:		err = put_user(4, (int __user *) arg);		break;	case SIOCSIFENCAP:		if (get_user(tmp, (int __user *) arg)) {			err = -EFAULT;			break;		}		ax->mode = tmp;		dev->addr_len        = AX25_ADDR_LEN;		dev->hard_header_len = AX25_KISS_HEADER_LEN +		                       AX25_MAX_HEADER_LEN + 3;		dev->type            = ARPHRD_AX25;		err = 0;		break;	case SIOCSIFHWADDR: {		char addr[AX25_ADDR_LEN];		if (copy_from_user(&addr,		                   (void __user *) arg, AX25_ADDR_LEN)) {			err = -EFAULT;			break;		}		spin_lock_irq(&dev->xmit_lock);		memcpy(dev->dev_addr, addr, AX25_ADDR_LEN);		spin_unlock_irq(&dev->xmit_lock);		err = 0;		break;	}	default:		err = -ENOIOCTLCMD;	}	mkiss_put(ax);	return err;}/* * 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 mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,	char *fp, int count){	struct mkiss *ax = mkiss_get(tty);	if (!ax)		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->stats.rx_errors++;			cp++;			continue;		}		kiss_unesc(ax, *cp++);	}	mkiss_put(ax);	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)	    && tty->driver->unthrottle)		tty->driver->unthrottle(tty);}static int mkiss_receive_room(struct tty_struct *tty){	return 65536;  /* We can handle an infinite amount of data. :-) */}/* * Called by the driver when there's room for more data.  If we have * more packets to send, we send them here. */static void mkiss_write_wakeup(struct tty_struct *tty){	struct mkiss *ax = mkiss_get(tty);	int actual;	if (!ax)		return;	if (ax->xleft <= 0)  {		/* Now serial buffer is almost free & we can start		 * transmission of another packet		 */		clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);		netif_wake_queue(ax->dev);		goto out;	}	actual = tty->driver->write(tty, ax->xhead, ax->xleft);	ax->xleft -= actual;	ax->xhead += actual;out:	mkiss_put(ax);}static struct tty_ldisc ax_ldisc = {	.owner		= THIS_MODULE,	.magic		= TTY_LDISC_MAGIC,	.name		= "mkiss",	.open		= mkiss_open,	.close		= mkiss_close,	.ioctl		= mkiss_ioctl,	.receive_buf	= mkiss_receive_buf,	.receive_room	= mkiss_receive_room,	.write_wakeup	= mkiss_write_wakeup};static char banner[] __initdata = KERN_INFO \	"mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n";static char msg_regfail[] __initdata = KERN_ERR \	"mkiss: can't register line discipline (err = %d)\n";static int __init mkiss_init_driver(void){	int status;	printk(banner);	if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0)		printk(msg_regfail);	return status;}static const char msg_unregfail[] __exitdata = KERN_ERR \	"mkiss: can't unregister line discipline (err = %d)\n";static void __exit mkiss_exit_driver(void){	int ret;	if ((ret = tty_unregister_ldisc(N_AX25)))		printk(msg_unregfail, ret);}MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>");MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs");MODULE_PARM(crc_force, "i");MODULE_PARM_DESC(crc_force, "crc [0 = auto | 1 = none | 2 = flexnet | 3 = smack]");MODULE_LICENSE("GPL");MODULE_ALIAS_LDISC(N_AX25);module_init(mkiss_init_driver);module_exit(mkiss_exit_driver);

⌨️ 快捷键说明

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