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

📄 slip.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
		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->type		= ARPHRD_SLIP + sl->mode;#ifdef SL_CHECK_TRANSMIT	dev->tx_timeout		= sl_tx_timeout;	dev->watchdog_timeo	= 20*HZ;#endif	return 0;}static void sl_uninit(struct net_device *dev){	struct slip *sl = (struct slip*)(dev->priv);	sl_free_bufs(sl);}static void sl_setup(struct net_device *dev){	dev->init		= sl_init;	dev->uninit	  	= sl_uninit;	dev->open		= sl_open;	dev->destructor		= free_netdev;	dev->stop		= sl_close;	dev->get_stats	        = sl_get_stats;	dev->change_mtu		= sl_change_mtu;	dev->hard_start_xmit	= sl_xmit;#ifdef CONFIG_SLIP_SMART	dev->do_ioctl		= sl_ioctl;#endif	dev->hard_header_len	= 0;	dev->addr_len		= 0;	dev->tx_queue_len	= 10;	SET_MODULE_OWNER(dev);	/* New-style flags. */	dev->flags		= IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST;}/******************************************  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. This will not * be re-entered while running but other ldisc functions may be called * in parallel */ 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;	struct net_device *dev;	struct slip	  *sl;	for (i = 0; i < slip_maxdev; i++) {		if ((dev = slip_devs[i]) == NULL)			break;		sl = dev->priv;		if (sl->tty || sl->leased)			continue;		if (dev->flags&IFF_UP)			dev_close(dev);	}}/* Find a free SLIP channel, and link in this `tty' line. */static struct slip *sl_alloc(dev_t line){	int i;	int sel = -1;	int score = -1;	struct net_device *dev = NULL;	struct slip       *sl;	if (slip_devs == NULL) 		return NULL;	/* Master array missing ! */	for (i = 0; i < slip_maxdev; i++) {		dev = slip_devs[i];		if (dev == NULL)			break;		sl = dev->priv;		if (sl->leased) {			if (sl->line != line)				continue;			if (sl->tty)				return NULL;			/* Clear ESCAPE & ERROR flags */			sl->flags &= (1 << SLF_INUSE);			return sl;		}		if (sl->tty)			continue;		if (current->pid == sl->pid) {			if (sl->line == line && score < 3) {				sel = i;				score = 3;				continue;			}			if (score < 2) {				sel = i;				score = 2;			}			continue;		}		if (sl->line == line && score < 1) {			sel = i;			score = 1;			continue;		}		if (score < 0) {			sel = i;			score = 0;		}	}	if (sel >= 0) {		i = sel;		dev = slip_devs[i];		if (score > 1) {			sl = dev->priv;			sl->flags &= (1 << SLF_INUSE);			return sl;		}	}	/* Sorry, too many, all slots in use */	if (i >= slip_maxdev)		return NULL;	if (dev) {		sl = dev->priv;		if (test_bit(SLF_INUSE, &sl->flags)) {			unregister_netdevice(dev);			dev = NULL;			slip_devs[i] = NULL;		}	}		if (!dev) {		char name[IFNAMSIZ];		sprintf(name, "sl%d", i);		dev = alloc_netdev(sizeof(*sl), name, sl_setup);		if (!dev)			return NULL;		dev->base_addr  = i;	}	sl = dev->priv;	/* Initialize channel control data */	sl->magic       = SLIP_MAGIC;	sl->dev	      	= dev;	spin_lock_init(&sl->lock);	sl->mode        = SL_MODE_DEFAULT;#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_devs[i] = dev;				   	return sl;}/* * 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... * * Called in process context serialized from other ldisc calls. */static int slip_open(struct tty_struct *tty){	struct slip *sl;	int err;	if(!capable(CAP_NET_ADMIN))		return -EPERM;			/* 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_devnum(tty))) == NULL)		goto err_exit;	sl->tty = tty;	tty->disc_data = sl;	sl->line = tty_devnum(tty);	sl->pid = current->pid;		/* FIXME: already done before we were called - seems this can go */	if (tty->driver->flush_buffer)		tty->driver->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;		set_bit(SLF_INUSE, &sl->flags);		if ((err = register_netdevice(sl->dev)))			goto err_free_bufs;	}#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_bufs:	sl_free_bufs(sl);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 */	return err;}/*  FIXME: 1,2 are fixed 3 was never true anyway.     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 returning. This * call is serialized against other ldisc functions. */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 = NULL;	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 */} /************************************************************************  *			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);

⌨️ 快捷键说明

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