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

📄 slip.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	spin_lock(&sl->lock);	if (!netif_running(dev))  {		spin_unlock(&sl->lock);		printk("%s: xmit call when iface is down\n", dev->name);		dev_kfree_skb(skb);		return 0;	}	if (sl->tty == NULL) {		spin_unlock(&sl->lock);		dev_kfree_skb(skb);		return 0;	}	sl_lock(sl);	sl->tx_bytes+=skb->len;	sl_encaps(sl, skb->data, skb->len);	spin_unlock(&sl->lock);	dev_kfree_skb(skb);	return 0;}/****************************************** *   Routines looking at netdevice side. ******************************************//* Netdevice UP -> DOWN routine */static intsl_close(struct net_device *dev){	struct slip *sl = (struct slip*)(dev->priv);	spin_lock_bh(&sl->lock);	if (sl->tty) {		/* TTY discipline is running. */		sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);	}	netif_stop_queue(dev);	sl->rcount   = 0;	sl->xleft    = 0;	spin_unlock_bh(&sl->lock);	return 0;}/* Netdevice DOWN -> UP routine */static int sl_open(struct net_device *dev){	struct slip *sl = (struct slip*)(dev->priv);	if (sl->tty==NULL)		return -ENODEV;	sl->flags &= (1 << SLF_INUSE);	netif_start_queue(dev);	return 0;}/* Netdevice change MTU request */static int sl_change_mtu(struct net_device *dev, int new_mtu){	struct slip *sl = (struct slip*)(dev->priv);	if (new_mtu < 68 || new_mtu > 65534)		return -EINVAL;	if (new_mtu != dev->mtu)		return sl_realloc_bufs(sl, new_mtu);	return 0;}/* Netdevice get statistics request */static struct net_device_stats *sl_get_stats(struct net_device *dev){	static struct net_device_stats stats;	struct slip *sl = (struct slip*)(dev->priv);#ifdef SL_INCLUDE_CSLIP	struct slcompress *comp;#endif	memset(&stats, 0, sizeof(struct net_device_stats));	stats.rx_packets     = sl->rx_packets;	stats.tx_packets     = sl->tx_packets;	stats.rx_bytes	     = sl->rx_bytes;	stats.tx_bytes	     = sl->tx_bytes;	stats.rx_dropped     = sl->rx_dropped;	stats.tx_dropped     = sl->tx_dropped;	stats.tx_errors      = sl->tx_errors;	stats.rx_errors      = sl->rx_errors;	stats.rx_over_errors = sl->rx_over_errors;#ifdef SL_INCLUDE_CSLIP	stats.rx_fifo_errors = sl->rx_compressed;	stats.tx_fifo_errors = sl->tx_compressed;	stats.collisions     = sl->tx_misses;	comp = sl->slcomp;	if (comp) {		stats.rx_fifo_errors += comp->sls_i_compressed;		stats.rx_dropped     += comp->sls_i_tossed;		stats.tx_fifo_errors += comp->sls_o_compressed;		stats.collisions     += comp->sls_o_misses;	}#endif /* CONFIG_INET */	return (&stats);}/* Netdevice register callback */static int sl_init(struct net_device *dev){	struct slip *sl = (struct slip*)(dev->priv);	/*	 *	Finish setting up the DEVICE info. 	 */	dev->mtu		= sl->mtu;	dev->hard_start_xmit	= sl_xmit;#ifdef SL_CHECK_TRANSMIT	dev->tx_timeout		= sl_tx_timeout;	dev->watchdog_timeo	= 20*HZ;#endif	dev->open		= sl_open;	dev->stop		= sl_close;	dev->get_stats	        = sl_get_stats;	dev->change_mtu		= sl_change_mtu;#ifdef CONFIG_SLIP_SMART	dev->do_ioctl		= sl_ioctl;#endif	dev->hard_header_len	= 0;	dev->addr_len		= 0;	dev->type		= ARPHRD_SLIP + sl->mode;	dev->tx_queue_len	= 10;	SET_MODULE_OWNER(dev);	dev_init_buffers(dev);	/* New-style flags. */	dev->flags		= IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST;	return 0;}/******************************************  Routines looking at TTY side. ******************************************/static int slip_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 SLIP data has been received, which can now be decapsulated * and sent on to some IP layer for further processing. */ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count){	struct slip *sl = (struct slip *) tty->disc_data;	if (!sl || sl->magic != SLIP_MAGIC ||	    !netif_running(sl->dev))		return;	/* Read the characters out of the buffer */	while (count--) {		if (fp && *fp++) {			if (!test_and_set_bit(SLF_ERROR, &sl->flags))  {				sl->rx_errors++;			}			cp++;			continue;		}#ifdef CONFIG_SLIP_MODE_SLIP6		if (sl->mode & SL_MODE_SLIP6)			slip_unesc6(sl, *cp++);		else#endif			slip_unesc(sl, *cp++);	}}/************************************ *  slip_open helper routines. ************************************//* Collect hanged up channels */static void sl_sync(void){	int i;	for (i = 0; i < slip_maxdev; i++) {		slip_ctrl_t *slp = slip_ctrls[i];		if (slp == NULL)			break;		if (slp->ctrl.tty || slp->ctrl.leased)			continue;		if (slp->dev.flags&IFF_UP)			dev_close(&slp->dev);	}}/* Find a free SLIP channel, and link in this `tty' line. */static struct slip *sl_alloc(kdev_t line){	struct slip *sl;	slip_ctrl_t *slp = NULL;	int i;	int sel = -1;	int score = -1;	if (slip_ctrls == NULL)		return NULL;	/* Master array missing ! */	for (i = 0; i < slip_maxdev; i++) {		slp = slip_ctrls[i];		if (slp == NULL)			break;		if (slp->ctrl.leased) {			if (slp->ctrl.line != line)				continue;			if (slp->ctrl.tty)				return NULL;			/* Clear ESCAPE & ERROR flags */			slp->ctrl.flags &= (1 << SLF_INUSE);			return &slp->ctrl;		}		if (slp->ctrl.tty)			continue;		if (current->pid == slp->ctrl.pid) {			if (slp->ctrl.line == line && score < 3) {				sel = i;				score = 3;				continue;			}			if (score < 2) {				sel = i;				score = 2;			}			continue;		}		if (slp->ctrl.line == line && score < 1) {			sel = i;			score = 1;			continue;		}		if (score < 0) {			sel = i;			score = 0;		}	}	if (sel >= 0) {		i = sel;		slp = slip_ctrls[i];		if (score > 1) {			slp->ctrl.flags &= (1 << SLF_INUSE);			return &slp->ctrl;		}	}	/* Sorry, too many, all slots in use */	if (i >= slip_maxdev)		return NULL;	if (slp) {		if (test_bit(SLF_INUSE, &slp->ctrl.flags)) {			unregister_netdevice(&slp->dev);			sl_free_bufs(&slp->ctrl);		}	} else if ((slp = (slip_ctrl_t *)kmalloc(sizeof(slip_ctrl_t),GFP_KERNEL)) == NULL)		return NULL;	memset(slp, 0, sizeof(slip_ctrl_t));	sl = &slp->ctrl;	/* Initialize channel control data */	sl->magic       = SLIP_MAGIC;	sl->dev	      	= &slp->dev;	spin_lock_init(&sl->lock);	sl->mode        = SL_MODE_DEFAULT;	sprintf(slp->dev.name, "sl%d", i);	slp->dev.base_addr    = i;	slp->dev.priv         = (void*)sl;	slp->dev.init         = sl_init;#ifdef CONFIG_SLIP_SMART	init_timer(&sl->keepalive_timer);	/* initialize timer_list struct */	sl->keepalive_timer.data=(unsigned long)sl;	sl->keepalive_timer.function=sl_keepalive;	init_timer(&sl->outfill_timer);	sl->outfill_timer.data=(unsigned long)sl;	sl->outfill_timer.function=sl_outfill;#endif	slip_ctrls[i] 	      = slp;	return &slp->ctrl;}/* * Open the high-level part of the SLIP channel. * This function is called by the TTY module when the * SLIP line discipline is called for.  Because we are * sure the tty line exists, we only have to link it to * a free SLIP channel... */static intslip_open(struct tty_struct *tty){	struct slip *sl;	int err;	if(!capable(CAP_NET_ADMIN))		return -EPERM;			MOD_INC_USE_COUNT;	/* RTnetlink lock is misused here to serialize concurrent	   opens of slip channels. There are better ways, but it is	   the simplest one.	 */	rtnl_lock();	/* Collect hanged up channels. */	sl_sync();	sl = (struct slip *) tty->disc_data;	err = -EEXIST;	/* First make sure we're not already connected. */	if (sl && sl->magic == SLIP_MAGIC)		goto err_exit;	/* OK.  Find a free SLIP channel to use. */	err = -ENFILE;	if ((sl = sl_alloc(tty->device)) == NULL)		goto err_exit;	sl->tty = tty;	tty->disc_data = sl;	sl->line = tty->device;	sl->pid = current->pid;	if (tty->driver.flush_buffer)		tty->driver.flush_buffer(tty);	if (tty->ldisc.flush_buffer)		tty->ldisc.flush_buffer(tty);	if (!test_bit(SLF_INUSE, &sl->flags)) {		/* Perform the low-level SLIP initialization. */		if ((err = sl_alloc_bufs(sl, SL_MTU)) != 0)			goto err_free_chan;		if (register_netdevice(sl->dev)) {			sl_free_bufs(sl);			goto err_free_chan;		}		set_bit(SLF_INUSE, &sl->flags);	}#ifdef CONFIG_SLIP_SMART	if (sl->keepalive) {		sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ;		add_timer (&sl->keepalive_timer);	}	if (sl->outfill) {		sl->outfill_timer.expires=jiffies+sl->outfill*HZ;		add_timer (&sl->outfill_timer);	}#endif	/* Done.  We have linked the TTY line to a channel. */	rtnl_unlock();	return sl->dev->base_addr;err_free_chan:	sl->tty = NULL;	tty->disc_data = NULL;	clear_bit(SLF_INUSE, &sl->flags);err_exit:	rtnl_unlock();	/* Count references from TTY module */	MOD_DEC_USE_COUNT;	return err;}/*   Let me to blame a bit.   1. TTY module calls this funstion on soft interrupt.   2. TTY module calls this function WITH MASKED INTERRUPTS!   3. TTY module does not notify us about line discipline      shutdown,   Seems, now it is clean. The solution is to consider netdevice and   line discipline sides as two independent threads.   By-product (not desired): sl? does not feel hangups and remains open.   It is supposed, that user level program (dip, diald, slattach...)   will catch SIGHUP and make the rest of work.    I see no way to make more with current tty code. --ANK *//* * Close down a SLIP channel. * This means flushing out any pending queues, and then restoring the * TTY line discipline to what it was before it got hooked to SLIP * (which usually is TTY again). */static voidslip_close(struct tty_struct *tty){	struct slip *sl = (struct slip *) tty->disc_data;	/* First make sure we're connected. */	if (!sl || sl->magic != SLIP_MAGIC || sl->tty != tty)		return;	tty->disc_data = 0;	sl->tty = NULL;	if (!sl->leased)		sl->line = 0;	/* VSV = very important to remove timers */#ifdef CONFIG_SLIP_SMART	del_timer_sync(&sl->keepalive_timer);	del_timer_sync(&sl->outfill_timer);#endif	/* Count references from TTY module */	MOD_DEC_USE_COUNT;} /************************************************************************  *			STANDARD SLIP ENCAPSULATION		  	 *  ************************************************************************/intslip_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;	/*	 * For each byte in the packet, send the appropriate	 * character sequence, according to the SLIP protocol.	 */	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);}static void slip_unesc(struct slip *sl, unsigned char s){	switch(s) {	 case END:#ifdef CONFIG_SLIP_SMART		/* drop keeptest bit = VSV */		if (test_bit(SLF_KEEPTEST, &sl->flags))			clear_bit(SLF_KEEPTEST, &sl->flags);#endif		if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  {			sl_bump(sl);		}

⌨️ 快捷键说明

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