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

📄 slip.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		clear_bit(SLF_ESCAPE, &sl->flags);		sl->rcount = 0;		return;	 case ESC:		set_bit(SLF_ESCAPE, &sl->flags);		return;	 case ESC_ESC:		if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))  {			s = ESC;		}		break;	 case ESC_END:		if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))  {			s = END;		}		break;	}	if (!test_bit(SLF_ERROR, &sl->flags))  {		if (sl->rcount < sl->buffsize)  {			sl->rbuff[sl->rcount++] = s;			return;		}		sl->rx_over_errors++;		set_bit(SLF_ERROR, &sl->flags);	}}#ifdef CONFIG_SLIP_MODE_SLIP6/************************************************************************ *			 6 BIT SLIP ENCAPSULATION			* ************************************************************************/intslip_esc6(unsigned char *s, unsigned char *d, int len){	unsigned char *ptr = d;	unsigned char c;	int i;	unsigned short v = 0;	short bits = 0;	/*	 * Send an initial END character to flush out any	 * data that may have accumulated in the receiver	 * due to line noise.	 */	*ptr++ = 0x70;	/*	 * Encode the packet into printable ascii characters	 */	for (i = 0; i < len; ++i) {		v = (v << 8) | s[i];		bits += 8;		while (bits >= 6) {			bits -= 6;			c = 0x30 + ((v >> bits) & 0x3F);			*ptr++ = c;		}	}	if (bits) {		c = 0x30 + ((v << (6 - bits)) & 0x3F);		*ptr++ = c;	}	*ptr++ = 0x70;	return ptr - d;}voidslip_unesc6(struct slip *sl, unsigned char s){	unsigned char c;	if (s == 0x70) {#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);		}		sl->rcount = 0;		sl->xbits = 0;		sl->xdata = 0; 	} else if (s >= 0x30 && s < 0x70) {		sl->xdata = (sl->xdata << 6) | ((s - 0x30) & 0x3F);		sl->xbits += 6;		if (sl->xbits >= 8) {			sl->xbits -= 8;			c = (unsigned char)(sl->xdata >> sl->xbits);			if (!test_bit(SLF_ERROR, &sl->flags))  {				if (sl->rcount < sl->buffsize)  {					sl->rbuff[sl->rcount++] = c;					return;				}				sl->rx_over_errors++;				set_bit(SLF_ERROR, &sl->flags);			}		} 	}}#endif /* CONFIG_SLIP_MODE_SLIP6 *//* Perform I/O control on an active SLIP channel. */static intslip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg){	struct slip *sl = (struct slip *) tty->disc_data;	unsigned int tmp;	/* First make sure we're connected. */	if (!sl || sl->magic != SLIP_MAGIC) {		return -EINVAL;	}	switch(cmd) {	 case SIOCGIFNAME:		/* Please, do not put this line under copy_to_user,		   it breaks my old poor gcc on alpha --ANK		 */		tmp = strlen(sl->dev->name) + 1;		if (copy_to_user(arg, sl->dev->name, tmp))			return -EFAULT;		return 0;	case SIOCGIFENCAP:		if (put_user(sl->mode, (int *)arg))			return -EFAULT;		return 0;	case SIOCSIFENCAP:		if (get_user(tmp,(int *)arg))			return -EFAULT;#ifndef SL_INCLUDE_CSLIP		if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE))  {			return -EINVAL;		}#else		if ((tmp & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) ==		    (SL_MODE_ADAPTIVE | SL_MODE_CSLIP))  {			/* return -EINVAL; */			tmp &= ~SL_MODE_ADAPTIVE;		}#endif#ifndef CONFIG_SLIP_MODE_SLIP6		if (tmp & SL_MODE_SLIP6)  {			return -EINVAL;		}#endif		sl->mode = tmp;		sl->dev->type = ARPHRD_SLIP+sl->mode;		return 0;	 case SIOCSIFHWADDR:		return -EINVAL;#ifdef CONFIG_SLIP_SMART	/* VSV changes start here */        case SIOCSKEEPALIVE:		if (get_user(tmp,(int *)arg))			return -EFAULT;                if (tmp > 255) /* max for unchar */			return -EINVAL;		spin_lock_bh(&sl->lock);		if (!sl->tty) {			spin_unlock_bh(&sl->lock);			return -ENODEV;		}		if ((sl->keepalive = (unchar) tmp) != 0) {			mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ);			set_bit(SLF_KEEPTEST, &sl->flags);                } else {                        del_timer (&sl->keepalive_timer);		}		spin_unlock_bh(&sl->lock);		return 0;        case SIOCGKEEPALIVE:		if (put_user(sl->keepalive, (int *)arg))			return -EFAULT;		return 0;        case SIOCSOUTFILL:		if (get_user(tmp,(int *)arg))			return -EFAULT;                if (tmp > 255) /* max for unchar */			return -EINVAL;		spin_lock_bh(&sl->lock);		if (!sl->tty) {			spin_unlock_bh(&sl->lock);			return -ENODEV;		}                if ((sl->outfill = (unchar) tmp) != 0){			mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ);			set_bit(SLF_OUTWAIT, &sl->flags);		} else {                        del_timer (&sl->outfill_timer);		}		spin_unlock_bh(&sl->lock);                return 0;        case SIOCGOUTFILL:		if (put_user(sl->outfill, (int *)arg))			return -EFAULT;		return 0;	/* VSV changes end */#endif	/* Allow stty to read, but not set, the serial port */	case TCGETS:	case TCGETA:		return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg);	default:		return -ENOIOCTLCMD;	}}/* VSV changes start here */#ifdef CONFIG_SLIP_SMART/* function do_ioctl called from net/core/dev.c   to allow get/set outfill/keepalive parameter   by ifconfig                                 */static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd){	struct slip *sl = (struct slip*)(dev->priv);	if (sl == NULL)		/* Allocation failed ?? */		return -ENODEV;	spin_lock_bh(&sl->lock);	if (!sl->tty) {		spin_unlock_bh(&sl->lock);		return -ENODEV;	}	switch(cmd){        case SIOCSKEEPALIVE:		/* max for unchar */                if (((unsigned int)((unsigned long)rq->ifr_data)) > 255) {			spin_unlock_bh(&sl->lock);			return -EINVAL;		}		sl->keepalive = (unchar) ((unsigned long)rq->ifr_data);		if (sl->keepalive != 0) {			sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ;			mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ);			set_bit(SLF_KEEPTEST, &sl->flags);                } else {                        del_timer(&sl->keepalive_timer);		}		break;        case SIOCGKEEPALIVE:		rq->ifr_data=(caddr_t)((unsigned long)sl->keepalive);		break;        case SIOCSOUTFILL:                if (((unsigned)((unsigned long)rq->ifr_data)) > 255) { /* max for unchar */			spin_unlock_bh(&sl->lock);			return -EINVAL;		}                if ((sl->outfill = (unchar)((unsigned long) rq->ifr_data)) != 0){			mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ);			set_bit(SLF_OUTWAIT, &sl->flags);		} else {                        del_timer (&sl->outfill_timer);		}                break;        case SIOCGOUTFILL:		rq->ifr_data=(caddr_t)((unsigned long)sl->outfill);		break;        case SIOCSLEASE:		/* Resolve race condition, when ioctl'ing hanged up 		   and opened by another process device.		 */		if (sl->tty != current->tty && sl->pid != current->pid) {			spin_unlock_bh(&sl->lock);			return -EPERM;		}		sl->leased = 0;                if ((unsigned long)rq->ifr_data)			sl->leased = 1;                break;        case SIOCGLEASE:		rq->ifr_data=(caddr_t)((unsigned long)sl->leased);	};	spin_unlock_bh(&sl->lock);	return 0;}#endif/* VSV changes end *//* Initialize SLIP control device -- register SLIP line discipline */int __init slip_init_ctrl_dev(void){	int status;	if (slip_maxdev < 4) slip_maxdev = 4; /* Sanity */	printk(KERN_INFO "SLIP: version %s (dynamic channels, max=%d)"#ifdef CONFIG_SLIP_MODE_SLIP6	       " (6 bit encapsulation enabled)"#endif	       ".\n",	       SLIP_VERSION, slip_maxdev );#if defined(SL_INCLUDE_CSLIP) && !defined(MODULE)	printk("CSLIP: code copyright 1989 Regents of the University of California.\n");#endif#ifdef CONFIG_SLIP_SMART	printk(KERN_INFO "SLIP linefill/keepalive option.\n");#endif	slip_ctrls = (slip_ctrl_t **) kmalloc(sizeof(void*)*slip_maxdev, GFP_KERNEL);	if (slip_ctrls == NULL)	{		printk("SLIP: Can't allocate slip_ctrls[] array!  Uaargh! (-> No SLIP available)\n");		return -ENOMEM;	}	/* Clear the pointer array, we allocate devices when we need them */	memset(slip_ctrls, 0, sizeof(void*)*slip_maxdev); /* Pointers */	/* Fill in our line protocol discipline, and register it */	memset(&sl_ldisc, 0, sizeof(sl_ldisc));	sl_ldisc.magic  = TTY_LDISC_MAGIC;	sl_ldisc.name   = "slip";	sl_ldisc.flags  = 0;	sl_ldisc.open   = slip_open;	sl_ldisc.close  = slip_close;	sl_ldisc.read   = NULL;	sl_ldisc.write  = NULL;	sl_ldisc.ioctl  = (int (*)(struct tty_struct *, struct file *,				   unsigned int, unsigned long)) slip_ioctl;	sl_ldisc.poll   = NULL;	sl_ldisc.receive_buf = slip_receive_buf;	sl_ldisc.receive_room = slip_receive_room;	sl_ldisc.write_wakeup = slip_write_wakeup;	if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0)  {		printk("SLIP: can't register line discipline (err = %d)\n", status);	}	return status;}#ifdef MODULEintinit_module(void){	return slip_init_ctrl_dev();}voidcleanup_module(void){	int i;	if (slip_ctrls != NULL) {		unsigned long start = jiffies;		int busy = 0;		/* First of all: check for active disciplines and hangup them.		 */		do {			if (busy) {				current->counter = 0;				schedule();			}			busy = 0;			local_bh_disable();			for (i = 0; i < slip_maxdev; i++) {				struct slip_ctrl *slc = slip_ctrls[i];				if (!slc)					continue;				spin_lock(&slc->ctrl.lock);				if (slc->ctrl.tty) {					busy++;					tty_hangup(slc->ctrl.tty);				}				spin_unlock(&slc->ctrl.lock);			}			local_bh_enable();		} while (busy && jiffies - start < 1*HZ);		busy = 0;		for (i = 0; i < slip_maxdev; i++) {			struct slip_ctrl *slc = slip_ctrls[i];			if (slc) {				unregister_netdev(&slc->dev);				if (slc->ctrl.tty) {					printk("%s: tty discipline is still running\n", slc->dev.name);					/* Pin module forever */					MOD_INC_USE_COUNT;					busy++;					continue;				}				sl_free_bufs(&slc->ctrl);				kfree(slc);				slip_ctrls[i] = NULL;			}		}		if (!busy) {			kfree(slip_ctrls);			slip_ctrls = NULL;		}	}	if ((i = tty_register_ldisc(N_SLIP, NULL)))	{		printk("SLIP: can't unregister line discipline (err = %d)\n", i);	}}#endif /* MODULE */#ifdef CONFIG_SLIP_SMART/* * This is start of the code for multislip style line checking * added by Stanislav Voronyi. All changes before marked VSV */static void sl_outfill(unsigned long sls){	struct slip *sl=(struct slip *)sls;	spin_lock(&sl->lock);	if (sl->tty == NULL)		goto out;	if(sl->outfill)	{		if( test_bit(SLF_OUTWAIT, &sl->flags) )		{			/* no packets were transmitted, do outfill */#ifdef CONFIG_SLIP_MODE_SLIP6			unsigned char s = (sl->mode & SL_MODE_SLIP6)?0x70:END;#else			unsigned char s = END;#endif			/* put END into tty queue. Is it right ??? */			if (!netif_queue_stopped(sl->dev))			{				/* if device busy no outfill */				sl->tty->driver.write(sl->tty, 0, &s, 1);			}		}		else			set_bit(SLF_OUTWAIT, &sl->flags);		mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ);	}out:	spin_unlock(&sl->lock);}static void sl_keepalive(unsigned long sls){	struct slip *sl=(struct slip *)sls;	spin_lock(&sl->lock);	if (sl->tty == NULL)		goto out;	if( sl->keepalive)	{		if(test_bit(SLF_KEEPTEST, &sl->flags))		{			/* keepalive still high :(, we must hangup */			if( sl->outfill ) /* outfill timer must be deleted too */				(void)del_timer(&sl->outfill_timer);			printk("%s: no packets received during keepalive timeout, hangup.\n", sl->dev->name);			tty_hangup(sl->tty); /* this must hangup tty & close slip */			/* I think we need not something else */			goto out;		}		else			set_bit(SLF_KEEPTEST, &sl->flags);		mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ);	}out:	spin_unlock(&sl->lock);}#endif

⌨️ 快捷键说明

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