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

📄 ppp_generic.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
}/* No kernel lock - fine */unsigned intppp_channel_poll(struct ppp_channel *chan, struct file *file, poll_table *wait){	unsigned int mask;	struct channel *pch = chan->ppp;	mask = POLLOUT | POLLWRNORM;	if (pch != 0) {		poll_wait(file, &pch->file.rwait, wait);		if (skb_peek(&pch->file.rq) != 0)			mask |= POLLIN | POLLRDNORM;	}	return mask;}int ppp_channel_ioctl(struct ppp_channel *chan, unsigned int cmd,		      unsigned long arg){	struct channel *pch = chan->ppp;	int err = -ENOTTY;	int unit;	if (!capable(CAP_NET_ADMIN))		return -EPERM;	if (pch == 0)		return -EINVAL;	switch (cmd) {	case PPPIOCATTACH:		if (get_user(unit, (int *) arg))			break;		err = ppp_connect_channel(pch, unit);		break;	case PPPIOCDETACH:		err = ppp_disconnect_channel(pch);		break;	}	return err;}/* * Compression control. *//* Process the PPPIOCSCOMPRESS ioctl. */static intppp_set_compress(struct ppp *ppp, unsigned long arg){	int err;	struct compressor *cp;	struct ppp_option_data data;	void *state;	unsigned char ccp_option[CCP_MAX_OPTION_LENGTH];#ifdef CONFIG_KMOD	char modname[32];#endif	err = -EFAULT;	if (copy_from_user(&data, (void *) arg, sizeof(data))	    || (data.length <= CCP_MAX_OPTION_LENGTH		&& copy_from_user(ccp_option, data.ptr, data.length)))		goto out;	err = -EINVAL;	if (data.length > CCP_MAX_OPTION_LENGTH	    || ccp_option[1] < 2 || ccp_option[1] > data.length)		goto out;	cp = find_compressor(ccp_option[0]);#ifdef CONFIG_KMOD	if (cp == 0) {		sprintf(modname, "ppp-compress-%d", ccp_option[0]);		request_module(modname);		cp = find_compressor(ccp_option[0]);	}#endif /* CONFIG_KMOD */	if (cp == 0)		goto out;	err = -ENOBUFS;	if (data.transmit) {		ppp_xmit_lock(ppp);		ppp->xstate &= ~SC_COMP_RUN;		if (ppp->xc_state != 0) {			ppp->xcomp->comp_free(ppp->xc_state);			ppp->xc_state = 0;		}		ppp_xmit_unlock(ppp);		state = cp->comp_alloc(ccp_option, data.length);		if (state != 0) {			ppp_xmit_lock(ppp);			ppp->xcomp = cp;			ppp->xc_state = state;			ppp_xmit_unlock(ppp);			err = 0;		}	} else {		ppp_recv_lock(ppp);		ppp->rstate &= ~SC_DECOMP_RUN;		if (ppp->rc_state != 0) {			ppp->rcomp->decomp_free(ppp->rc_state);			ppp->rc_state = 0;		}		ppp_recv_unlock(ppp);		state = cp->decomp_alloc(ccp_option, data.length);		if (state != 0) {			ppp_recv_lock(ppp);			ppp->rcomp = cp;			ppp->rc_state = state;			ppp_recv_unlock(ppp);			err = 0;		}	} out:	return err;}/* * Look at a CCP packet and update our state accordingly. * We assume the caller has the xmit or recv path locked. */static voidppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound){	unsigned char *dp = skb->data + 2;	int len;	if (skb->len < CCP_HDRLEN + 2	    || skb->len < (len = CCP_LENGTH(dp)) + 2)		return;		/* too short */	switch (CCP_CODE(dp)) {	case CCP_CONFREQ:	case CCP_TERMREQ:	case CCP_TERMACK:		/*		 * CCP is going down - disable compression.		 */		if (inbound)			ppp->rstate &= ~SC_DECOMP_RUN;		else			ppp->xstate &= ~SC_COMP_RUN;		break;	case CCP_CONFACK:		if ((ppp->flags & (SC_CCP_OPEN | SC_CCP_UP)) != SC_CCP_OPEN)			break;		dp += CCP_HDRLEN;		len -= CCP_HDRLEN;		if (len < CCP_OPT_MINLEN || len < CCP_OPT_LENGTH(dp))			break;		if (inbound) {			/* we will start receiving compressed packets */			if (ppp->rc_state == 0)				break;			if (ppp->rcomp->decomp_init(ppp->rc_state, dp, len,					ppp->file.index, 0, ppp->mru, ppp->debug)) {				ppp->rstate |= SC_DECOMP_RUN;				ppp->rstate &= ~(SC_DC_ERROR | SC_DC_FERROR);			}		} else {			/* we will soon start sending compressed packets */			if (ppp->xc_state == 0)				break;			if (ppp->xcomp->comp_init(ppp->xc_state, dp, len,					ppp->file.index, 0, ppp->debug))				ppp->xstate |= SC_COMP_RUN;		}		break;	case CCP_RESETACK:		/* reset the [de]compressor */		if ((ppp->flags & SC_CCP_UP) == 0)			break;		if (inbound) {			if (ppp->rc_state && (ppp->rstate & SC_DECOMP_RUN)) {				ppp->rcomp->decomp_reset(ppp->rc_state);				ppp->rstate &= ~SC_DC_ERROR;			}		} else {			if (ppp->xc_state && (ppp->xstate & SC_COMP_RUN))				ppp->xcomp->comp_reset(ppp->xc_state);		}		break;	}}/* Free up compression resources. */static voidppp_ccp_closed(struct ppp *ppp){	ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP);	ppp->xstate &= ~SC_COMP_RUN;	if (ppp->xc_state) {		ppp->xcomp->comp_free(ppp->xc_state);		ppp->xc_state = 0;	}	ppp->xstate &= ~SC_DECOMP_RUN;	if (ppp->rc_state) {		ppp->rcomp->decomp_free(ppp->rc_state);		ppp->rc_state = 0;	}}/* List of compressors. */static LIST_HEAD(compressor_list);static spinlock_t compressor_list_lock = SPIN_LOCK_UNLOCKED;struct compressor_entry {	struct list_head list;	struct compressor *comp;};static struct compressor_entry *find_comp_entry(int proto){	struct compressor_entry *ce;	struct list_head *list = &compressor_list;	while ((list = list->next) != &compressor_list) {		ce = list_entry(list, struct compressor_entry, list);		if (ce->comp->compress_proto == proto)			return ce;	}	return 0;}/* Register a compressor */intppp_register_compressor(struct compressor *cp){	struct compressor_entry *ce;	int ret;	spin_lock(&compressor_list_lock);	ret = -EEXIST;	if (find_comp_entry(cp->compress_proto) != 0)		goto out;	ret = -ENOMEM;	ce = kmalloc(sizeof(struct compressor_entry), GFP_KERNEL);	if (ce == 0)		goto out;	ret = 0;	ce->comp = cp;	list_add(&ce->list, &compressor_list); out:	spin_unlock(&compressor_list_lock);	return ret;}/* Unregister a compressor */voidppp_unregister_compressor(struct compressor *cp){	struct compressor_entry *ce;	spin_lock(&compressor_list_lock);	ce = find_comp_entry(cp->compress_proto);	if (ce != 0 && ce->comp == cp) {		list_del(&ce->list);		kfree(ce);	}	spin_unlock(&compressor_list_lock);}/* Find a compressor. */static struct compressor *find_compressor(int type){	struct compressor_entry *ce;	struct compressor *cp = 0;	spin_lock(&compressor_list_lock);	ce = find_comp_entry(type);	if (ce != 0)		cp = ce->comp;	spin_unlock(&compressor_list_lock);	return cp;}/* * Miscelleneous stuff. */static voidppp_get_stats(struct ppp *ppp, struct ppp_stats *st){	struct slcompress *vj = ppp->vj;	memset(st, 0, sizeof(*st));	st->p.ppp_ipackets = ppp->stats.rx_packets;	st->p.ppp_ierrors = ppp->stats.rx_errors;	st->p.ppp_ibytes = ppp->stats.rx_bytes;	st->p.ppp_opackets = ppp->stats.tx_packets;	st->p.ppp_oerrors = ppp->stats.tx_errors;	st->p.ppp_obytes = ppp->stats.tx_bytes;	if (vj == 0)		return;	st->vj.vjs_packets = vj->sls_o_compressed + vj->sls_o_uncompressed;	st->vj.vjs_compressed = vj->sls_o_compressed;	st->vj.vjs_searches = vj->sls_o_searches;	st->vj.vjs_misses = vj->sls_o_misses;	st->vj.vjs_errorin = vj->sls_i_error;	st->vj.vjs_tossed = vj->sls_i_tossed;	st->vj.vjs_uncompressedin = vj->sls_i_uncompressed;	st->vj.vjs_compressedin = vj->sls_i_compressed;}/* * Stuff for handling the lists of ppp units and channels * and for initialization. *//* * Create a new ppp interface unit.  Fails if it can't allocate memory * or if there is already a unit with the requested number. * unit == -1 means allocate a new number. */static struct ppp *ppp_create_interface(int unit, int *retp){	struct ppp *ppp;	struct net_device *dev;	struct list_head *list;	int last_unit = -1;	int ret = -EEXIST;	int i;	spin_lock(&all_ppp_lock);	list = &all_ppp_units;	while ((list = list->next) != &all_ppp_units) {		ppp = list_entry(list, struct ppp, file.list);		if ((unit < 0 && ppp->file.index > last_unit + 1)		    || (unit >= 0 && unit < ppp->file.index))			break;		if (unit == ppp->file.index)			goto out;	/* unit already exists */		last_unit = ppp->file.index;	}	if (unit < 0)		unit = last_unit + 1;	/* Create a new ppp structure and link it before `list'. */	ret = -ENOMEM;	ppp = kmalloc(sizeof(struct ppp), GFP_KERNEL);	if (ppp == 0)		goto out;	memset(ppp, 0, sizeof(struct ppp));	dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);	if (dev == 0) {		kfree(ppp);		goto out;	}	memset(dev, 0, sizeof(struct net_device));	ppp->file.index = unit;	ppp->mru = PPP_MRU;	init_ppp_file(&ppp->file, INTERFACE);	for (i = 0; i < NUM_NP; ++i)		ppp->npmode[i] = NPMODE_PASS;	INIT_LIST_HEAD(&ppp->channels);	spin_lock_init(&ppp->rlock);	spin_lock_init(&ppp->wlock);#ifdef CONFIG_PPP_MULTILINK	ppp->minseq = -1;	skb_queue_head_init(&ppp->mrq);#endif /* CONFIG_PPP_MULTILINK */	ppp->dev = dev;	dev->init = ppp_net_init;	sprintf(dev->name, "ppp%d", unit);	dev->priv = ppp;	dev->features |= NETIF_F_DYNALLOC;	rtnl_lock();	ret = register_netdevice(dev);	rtnl_unlock();	if (ret != 0) {		printk(KERN_ERR "PPP: couldn't register device (%d)\n", ret);		kfree(dev);		kfree(ppp);		goto out;	}	list_add(&ppp->file.list, list->prev); out:	spin_unlock(&all_ppp_lock);	*retp = ret;	if (ret != 0)		ppp = 0;	return ppp;}/* * Initialize a ppp_file structure. */static voidinit_ppp_file(struct ppp_file *pf, int kind){	pf->kind = kind;	skb_queue_head_init(&pf->xq);	skb_queue_head_init(&pf->rq);	atomic_set(&pf->refcnt, 1);	init_waitqueue_head(&pf->rwait);}/* * Free up all the resources used by a ppp interface unit. */static void ppp_destroy_interface(struct ppp *ppp){	struct net_device *dev;	spin_lock(&all_ppp_lock);	list_del(&ppp->file.list);	/* Last fd open to this ppp unit is being closed or detached:	   mark the interface down, free the ppp unit */	ppp_lock(ppp);	ppp_ccp_closed(ppp);	if (ppp->vj) {		slhc_free(ppp->vj);		ppp->vj = 0;	}	skb_queue_purge(&ppp->file.xq);	skb_queue_purge(&ppp->file.rq);#ifdef CONFIG_PPP_MULTILINK	skb_queue_purge(&ppp->mrq);#endif /* CONFIG_PPP_MULTILINK */	dev = ppp->dev;	ppp->dev = 0;	ppp_unlock(ppp);	if (dev) {		rtnl_lock();		dev_close(dev);		unregister_netdevice(dev);		rtnl_unlock();	}	/*	 * We can't acquire any new channels (since we have the	 * all_ppp_lock) so if n_channels is 0, we can free the	 * ppp structure.  Otherwise we leave it around until the	 * last channel disconnects from it.	 */	if (ppp->n_channels == 0)		kfree(ppp);	spin_unlock(&all_ppp_lock);}/* * Locate an existing ppp unit. * The caller should have locked the all_ppp_lock. */static struct ppp *ppp_find_unit(int unit){	struct ppp *ppp;	struct list_head *list;	list = &all_ppp_units;	while ((list = list->next) != &all_ppp_units) {		ppp = list_entry(list, struct ppp, file.list);		if (ppp->file.index == unit)			return ppp;	}	return 0;}/* * Locate an existing ppp channel. * The caller should have locked the all_channels_lock. */static struct channel *ppp_find_channel(int unit){	struct channel *pch;	struct list_head *list;	list = &all_channels;	while ((list = list->next) != &all_channels) {		pch = list_entry(list, struct channel, file.list);		if (pch->file.index == unit)			return pch;	}	return 0;}/* * Connect a PPP channel to a PPP interface unit. */static intppp_connect_channel(struct channel *pch, int unit){	struct ppp *ppp;	int ret = -ENXIO;	int hdrlen;	spin_lock(&all_ppp_lock);	ppp = ppp_find_unit(unit);	if (ppp == 0)		goto out;	write_lock_bh(&pch->upl);	ret = -EINVAL;	if (pch->ppp != 0)		goto outw;	ppp_lock(ppp);	spin_lock_bh(&pch->downl);	if (pch->chan == 0)		/* need to check this?? */		goto outr;	if (pch->file.hdrlen > ppp->file.hdrlen)		ppp->file.hdrlen = pch->file.hdrlen;	hdrlen = pch->file.hdrlen + 2;	/* for protocol bytes */	if (ppp->dev && hdrlen > ppp->dev->hard_header_len)		ppp->dev->hard_header_len = hdrlen;	list_add_tail(&pch->clist, &ppp->channels);	++ppp->n_channels;	pch->ppp = ppp;	ret = 0; outr:	spin_unlock_bh(&pch->downl);	ppp_unlock(ppp); outw:	write_unlock_bh(&pch->upl); out:	spin_unlock(&all_ppp_lock);	return ret;}/* * Disconnect a channel from its ppp unit. */static intppp_disconnect_channel(struct channel *pch){	struct ppp *ppp;	int err = -EINVAL;	int dead;	write_lock_bh(&pch->upl);	ppp = pch->ppp;	if (ppp != 0) {		/* remove it from the ppp unit's list */		pch->ppp = NULL;		ppp_lock(ppp);		list_del(&pch->clist);		--ppp->n_channels;		dead = ppp->dev == 0 && ppp->n_channels == 0;		ppp_unlock(ppp);		if (dead)			/* Last disconnect from a ppp unit			   that is already dead: free it. */			kfree(ppp);		err = 0;	}	write_unlock_bh(&pch->upl);	return err;}/* * Free up the resources used by a ppp channel. */static void ppp_destroy_channel(struct channel *pch){	skb_queue_purge(&pch->file.xq);	skb_queue_purge(&pch->file.rq);	kfree(pch);}void __exit ppp_cleanup(void){	/* should never happen */	if (!list_empty(&all_ppp_units) || !list_empty(&all_channels))		printk(KERN_ERR "PPP: removing module but units remain!\n");	if (devfs_unregister_chrdev(PPP_MAJOR, "ppp") != 0)		printk(KERN_ERR "PPP: failed to unregister PPP device\n");	devfs_unregister(devfs_handle);}module_init(ppp_init);module_exit(ppp_cleanup);EXPORT_SYMBOL(ppp_register_channel);EXPORT_SYMBOL(ppp_unregister_channel);EXPORT_SYMBOL(ppp_channel_index);EXPORT_SYMBOL(ppp_unit_number);EXPORT_SYMBOL(ppp_input);EXPORT_SYMBOL(ppp_input_error);EXPORT_SYMBOL(ppp_output_wakeup);EXPORT_SYMBOL(ppp_register_compressor);EXPORT_SYMBOL(ppp_unregister_compressor);EXPORT_SYMBOL(ppp_channel_read);EXPORT_SYMBOL(ppp_channel_write);EXPORT_SYMBOL(ppp_channel_poll);EXPORT_SYMBOL(ppp_channel_ioctl);EXPORT_SYMBOL(all_ppp_units); /* for debugging */EXPORT_SYMBOL(all_channels); /* for debugging */

⌨️ 快捷键说明

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