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

📄 isdn_ppp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;	/* maybe also SC_CCP stuff */	ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &		(SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);	ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &		(SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);	rc = isdn_ppp_mp_init(nlp, p->pb);out:	spin_unlock_irqrestore(&p->pb->lock, flags);	return rc;}  #endif /* CONFIG_ISDN_MPP */  /* * network device ioctl handlers */static intisdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev){	struct ppp_stats __user *res = ifr->ifr_data;	struct ppp_stats t;	isdn_net_local *lp = (isdn_net_local *) dev->priv;	if (!access_ok(VERIFY_WRITE, res, sizeof(struct ppp_stats)))		return -EFAULT;	/* build a temporary stat struct and copy it to user space */	memset(&t, 0, sizeof(struct ppp_stats));	if (dev->flags & IFF_UP) {		t.p.ppp_ipackets = lp->stats.rx_packets;		t.p.ppp_ibytes = lp->stats.rx_bytes;		t.p.ppp_ierrors = lp->stats.rx_errors;		t.p.ppp_opackets = lp->stats.tx_packets;		t.p.ppp_obytes = lp->stats.tx_bytes;		t.p.ppp_oerrors = lp->stats.tx_errors;#ifdef CONFIG_ISDN_PPP_VJ		if (slot >= 0 && ippp_table[slot]->slcomp) {			struct slcompress *slcomp = ippp_table[slot]->slcomp;			t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;			t.vj.vjs_compressed = slcomp->sls_o_compressed;			t.vj.vjs_searches = slcomp->sls_o_searches;			t.vj.vjs_misses = slcomp->sls_o_misses;			t.vj.vjs_errorin = slcomp->sls_i_error;			t.vj.vjs_tossed = slcomp->sls_i_tossed;			t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed;			t.vj.vjs_compressedin = slcomp->sls_i_compressed;		}#endif	}	if (copy_to_user(res, &t, sizeof(struct ppp_stats)))		return -EFAULT;	return 0;}intisdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){	int error=0;	int len;	isdn_net_local *lp = (isdn_net_local *) dev->priv;	if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)		return -EINVAL;	switch (cmd) {#define PPP_VERSION "2.3.7"		case SIOCGPPPVER:			len = strlen(PPP_VERSION) + 1;			if (copy_to_user(ifr->ifr_data, PPP_VERSION, len))				error = -EFAULT;			break;		case SIOCGPPPSTATS:			error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);			break;		default:			error = -EINVAL;			break;	}	return error;}static intisdn_ppp_if_get_unit(char *name){	int len,	 i,	 unit = 0,	 deci;	len = strlen(name);	if (strncmp("ippp", name, 4) || len > 8)		return -1;	for (i = 0, deci = 1; i < len; i++, deci *= 10) {		char a = name[len - i - 1];		if (a >= '0' && a <= '9')			unit += (a - '0') * deci;		else			break;	}	if (!i || len - i != 4)		unit = -1;	return unit;}intisdn_ppp_dial_slave(char *name){#ifdef CONFIG_ISDN_MPP	isdn_net_dev *ndev;	isdn_net_local *lp;	struct net_device *sdev;	if (!(ndev = isdn_net_findif(name)))		return 1;	lp = ndev->local;	if (!(lp->flags & ISDN_NET_CONNECTED))		return 5;	sdev = lp->slave;	while (sdev) {		isdn_net_local *mlp = (isdn_net_local *) sdev->priv;		if (!(mlp->flags & ISDN_NET_CONNECTED))			break;		sdev = mlp->slave;	}	if (!sdev)		return 2;	isdn_net_dial_req((isdn_net_local *) sdev->priv);	return 0;#else	return -1;#endif}intisdn_ppp_hangup_slave(char *name){#ifdef CONFIG_ISDN_MPP	isdn_net_dev *ndev;	isdn_net_local *lp;	struct net_device *sdev;	if (!(ndev = isdn_net_findif(name)))		return 1;	lp = ndev->local;	if (!(lp->flags & ISDN_NET_CONNECTED))		return 5;	sdev = lp->slave;	while (sdev) {		isdn_net_local *mlp = (isdn_net_local *) sdev->priv;		if (mlp->slave) { /* find last connected link in chain */			isdn_net_local *nlp = (isdn_net_local *) mlp->slave->priv;			if (!(nlp->flags & ISDN_NET_CONNECTED))				break;		} else if (mlp->flags & ISDN_NET_CONNECTED)			break;				sdev = mlp->slave;	}	if (!sdev)		return 2;	isdn_net_hangup(sdev);	return 0;#else	return -1;#endif}/* * PPP compression stuff *//* Push an empty CCP Data Frame up to the daemon to wake it up and let it   generate a CCP Reset-Request or tear down CCP altogether */static void isdn_ppp_ccp_kickup(struct ippp_struct *is){	isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot);}/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary,   but absolutely nontrivial. The most abstruse problem we are facing is   that the generation, reception and all the handling of timeouts and   resends including proper request id management should be entirely left   to the (de)compressor, but indeed is not covered by the current API to   the (de)compressor. The API is a prototype version from PPP where only   some (de)compressors have yet been implemented and all of them are   rather simple in their reset handling. Especially, their is only one   outstanding ResetAck at a time with all of them and ResetReq/-Acks do   not have parameters. For this very special case it was sufficient to   just return an error code from the decompressor and have a single   reset() entry to communicate all the necessary information between   the framework and the (de)compressor. Bad enough, LZS is different   (and any other compressor may be different, too). It has multiple   histories (eventually) and needs to Reset each of them independently   and thus uses multiple outstanding Acks and history numbers as an   additional parameter to Reqs/Acks.   All that makes it harder to port the reset state engine into the   kernel because it is not just the same simple one as in (i)pppd but   it must be able to pass additional parameters and have multiple out-   standing Acks. We are trying to achieve the impossible by handling   reset transactions independent by their id. The id MUST change when   the data portion changes, thus any (de)compressor who uses more than   one resettable state must provide and recognize individual ids for   each individual reset transaction. The framework itself does _only_   differentiate them by id, because it has no other semantics like the   (de)compressor might.   This looks like a major redesign of the interface would be nice,   but I don't have an idea how to do it better. *//* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is   getting that lengthy because there is no simple "send-this-frame-out"   function above but every wrapper does a bit different. Hope I guess   correct in this hack... */static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,				    unsigned char code, unsigned char id,				    unsigned char *data, int len){	struct sk_buff *skb;	unsigned char *p;	int hl;	int cnt = 0;	isdn_net_local *lp = is->lp;	/* Alloc large enough skb */	hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;	skb = alloc_skb(len + hl + 16,GFP_ATOMIC);	if(!skb) {		printk(KERN_WARNING		       "ippp: CCP cannot send reset - out of memory\n");		return;	}	skb_reserve(skb, hl);	/* We may need to stuff an address and control field first */	if(!(is->pppcfg & SC_COMP_AC)) {		p = skb_put(skb, 2);		*p++ = 0xff;		*p++ = 0x03;	}	/* Stuff proto, code, id and length */	p = skb_put(skb, 6);	*p++ = (proto >> 8);	*p++ = (proto & 0xff);	*p++ = code;	*p++ = id;	cnt = 4 + len;	*p++ = (cnt >> 8);	*p++ = (cnt & 0xff);	/* Now stuff remaining bytes */	if(len) {		p = skb_put(skb, len);		memcpy(p, data, len);	}	/* skb is now ready for xmit */	printk(KERN_DEBUG "Sending CCP Frame:\n");	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);	isdn_net_write_super(lp, skb);}/* Allocate the reset state vector */static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is){	struct ippp_ccp_reset *r;	r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);	if(!r) {		printk(KERN_ERR "ippp_ccp: failed to allocate reset data"		       " structure - no mem\n");		return NULL;	}	memset(r, 0, sizeof(struct ippp_ccp_reset));	printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);	is->reset = r;	return r;}/* Destroy the reset state vector. Kill all pending timers first. */static void isdn_ppp_ccp_reset_free(struct ippp_struct *is){	unsigned int id;	printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n",	       is->reset);	for(id = 0; id < 256; id++) {		if(is->reset->rs[id]) {			isdn_ppp_ccp_reset_free_state(is, (unsigned char)id);		}	}	kfree(is->reset);	is->reset = NULL;}/* Free a given state and clear everything up for later reallocation */static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,					  unsigned char id){	struct ippp_ccp_reset_state *rs;	if(is->reset->rs[id]) {		printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id);		rs = is->reset->rs[id];		/* Make sure the kernel will not call back later */		if(rs->ta)			del_timer(&rs->timer);		is->reset->rs[id] = NULL;		kfree(rs);	} else {		printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id);	}}/* The timer callback function which is called when a ResetReq has timed out,   aka has never been answered by a ResetAck */static void isdn_ppp_ccp_timer_callback(unsigned long closure){	struct ippp_ccp_reset_state *rs =		(struct ippp_ccp_reset_state *)closure;	if(!rs) {		printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n");		return;	}	if(rs->ta && rs->state == CCPResetSentReq) {		/* We are correct here */		if(!rs->expra) {			/* Hmm, there is no Ack really expected. We can clean			   up the state now, it will be reallocated if the			   decompressor insists on another reset */			rs->ta = 0;			isdn_ppp_ccp_reset_free_state(rs->is, rs->id);			return;		}		printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n",		       rs->id);		/* Push it again */		isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id,					rs->data, rs->dlen);		/* Restart timer */		rs->timer.expires = jiffies + HZ*5;		add_timer(&rs->timer);	} else {		printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n",		       rs->state);	}}/* Allocate a new reset transaction state */static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,						      unsigned char id){	struct ippp_ccp_reset_state *rs;	if(is->reset->rs[id]) {		printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n",		       id);		return NULL;	} else {		rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);		if(!rs)			return NULL;		memset(rs, 0, sizeof(struct ippp_ccp_reset_state));		rs->state = CCPResetIdle;		rs->is = is;		rs->id = id;		rs->timer.data = (unsigned long)rs;		rs->timer.function = isdn_ppp_ccp_timer_callback;		is->reset->rs[id] = rs;	}	return rs;}/* A decompressor wants a reset with a set of parameters - do what is   necessary to fulfill it */static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,				     struct isdn_ppp_resetparams *rp){	struct ippp_ccp_reset_state *rs;	if(rp->valid) {		/* The decompressor defines parameters by itself */		if(rp->rsend) {			/* And he wants us to send a request */			if(!(rp->idval)) {				printk(KERN_ERR "ippp_ccp: decompressor must"				       " specify reset id\n");				return;			}			if(is->reset->rs[rp->id]) {				/* There is already a transaction in existence				   for this id. May be still waiting for a				   Ack or may be wrong. */				rs = is->reset->rs[rp->id];				if(rs->state == CCPResetSentReq && rs->ta) {					printk(KERN_DEBUG "ippp_ccp: reset"					       " trans still in progress"					       " for id %d\n", rp->id);				} else {					printk(KERN_WARNING "ippp_ccp: reset"					       " trans in wrong state %d for"					       " id %d\n", rs->state, rp->id);				}			} else {				/* Ok, this is a new transaction */				printk(KERN_DEBUG "ippp_ccp: new trans for id"				       " %d to be started\n", rp->id);				rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id);				if(!rs) {					printk(KERN_ERR "ippp_ccp: out of mem"					       " allocing ccp trans\n");					return;				}				rs->state = CCPResetSentReq;				rs->expra = rp->expra;				if(rp->dtval) {					rs->dlen = rp->dlen;					memcpy(rs->data, rp->data, rp->dlen);				}				/* HACK TODO - add link comp here */				isdn_ppp_ccp_xmit_reset(is, PPP_CCP,							CCP_RESETREQ, rs->id,							rs->data, rs->dlen);				/* Start the timer */				rs->timer.expires = jiffies + 5*HZ;				add_timer(&rs->timer);				rs->ta = 1;			}		} else {			printk(KERN_DEBUG "ippp_ccp: no reset sent\n");		}	} else {		/* The reset params are invalid. The decompressor does not		   care about them, so we just send the minimal requests		   and increase ids only when an Ack is received for a		   given id */		if(is->reset->rs[is->reset->lastid]) {			/* There is already a transaction in existence			   for this id. May be still waiting for a			   Ack or may be wrong. */			rs = is->reset->rs[is->reset->lastid];			if(rs->state == CCPResetSentReq && rs->ta) {				printk(KERN_DEBUG "ippp_ccp: reset"				       " trans still in progress"				       " for id %d\n", rp->id);			} else {				printk(KERN_WARNING "ippp_ccp: reset"				       " trans in wrong state %d for"				       " id %d\n", rs->state, rp->id);			}		} else {			printk(KERN_DEBUG "ippp_ccp: new trans for id"			       " %d to be started\n", is->reset->lastid);			rs = isdn_ppp_ccp_reset_alloc_state(is,							    is->reset->lastid);			if(!rs) {				printk(KERN_ERR "ippp_ccp: out of mem"				       " allocing ccp trans\n");				return;			}			rs->state = CCPResetSentReq;			/* We always expect an Ack if the decompressor doesn't			   know	better */			rs->expra = 1;			rs->dlen = 0;			/* HACK TODO - add link comp here */			isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ,						rs->id, NULL, 0);			/* Start the timer */			rs->timer.expires = j

⌨️ 快捷键说明

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