isdn_ppp.c

来自「linux和2410结合开发 用他可以生成2410所需的zImage文件」· C语言 代码 · 共 2,457 行 · 第 1/5 页

C
2,457
字号
   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 doesnt			   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 = jiffies + 5*HZ;			add_timer(&rs->timer);			rs->ta = 1;		}	}}/* An Ack was received for this id. This means we stop the timer and clean   up the state prior to calling the decompressors reset routine. */static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,					unsigned char id){	struct ippp_ccp_reset_state *rs = is->reset->rs[id];	if(rs) {		if(rs->ta && rs->state == CCPResetSentReq) {			/* Great, we are correct */			if(!rs->expra)				printk(KERN_DEBUG "ippp_ccp: ResetAck received"				       " for id %d but not expected\n", id);		} else {			printk(KERN_INFO "ippp_ccp: ResetAck received out of"			       "sync for id %d\n", id);		}		if(rs->ta) {			rs->ta = 0;			del_timer(&rs->timer);		}		isdn_ppp_ccp_reset_free_state(is, id);	} else {		printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id"		       " %d\n", id);	}	/* Make sure the simple reset stuff uses a new id next time */	is->reset->lastid++;}/*  * decompress packet * * if master = 0, we're trying to uncompress an per-link compressed packet, * as opposed to an compressed reconstructed-from-MPPP packet. * proto is updated to protocol field of uncompressed packet. * * retval: decompressed packet, *         same packet if uncompressed, *	   NULL if decompression error */static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master,	int *proto){	void *stat = NULL;	struct isdn_ppp_compressor *ipc = NULL;	struct sk_buff *skb_out;	int len;	struct ippp_struct *ri;	struct isdn_ppp_resetparams rsparm;	unsigned char rsdata[IPPP_RESET_MAXDATABYTES];	if(!master) {		// per-link decompression 		stat = is->link_decomp_stat;		ipc = is->link_decompressor;		ri = is;	} else {		stat = master->decomp_stat;		ipc = master->decompressor;		ri = master;	}	if (!ipc) {		// no decompressor -> we can't decompress.		printk(KERN_DEBUG "ippp: no decompressor defined!\n");		return skb;	}	if (!stat) // if we have a compressor, stat has been set as well		BUG();	if((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG) ) {		// compressed packets are compressed by their protocol type		// Set up reset params for the decompressor  		memset(&rsparm, 0, sizeof(rsparm));  		rsparm.data = rsdata;  		rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;    		skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);		len = ipc->decompress(stat, skb, skb_out, &rsparm);		kfree_skb(skb);		if (len <= 0) {			switch(len) {			case DECOMP_ERROR:				printk(KERN_INFO "ippp: decomp wants reset %s params\n",				       rsparm.valid ? "with" : "without");								isdn_ppp_ccp_reset_trans(ri, &rsparm);				break;			case DECOMP_FATALERROR:				ri->pppcfg |= SC_DC_FERROR;				/* Kick ipppd to recognize the error */				isdn_ppp_ccp_kickup(ri);				break;			}			kfree_skb(skb_out);			return NULL;		}		*proto = isdn_ppp_strip_proto(skb_out);		if (*proto < 0) {			kfree_skb(skb_out);			return NULL;		}		return skb_out;	} else { 		// uncompressed packets are fed through the decompressor to		// update the decompressor state		ipc->incomp(stat, skb, *proto);		return skb;	}}/* * compress a frame  *   type=0: normal/bundle compression *       =1: link compression * returns original skb if we haven't compressed the frame * and a new skb pointer if we've done it */static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,	struct ippp_struct *is,struct ippp_struct *master,int type){    int ret;    int new_proto;    struct isdn_ppp_compressor *compressor;    void *stat;    struct sk_buff *skb_out;	/* we do not compress control protocols */    if(*proto < 0 || *proto > 0x3fff) {	    return skb_in;    }	if(type) { /* type=1 => Link compression */		return skb_in;	}	else {		if(!master) {			compressor = is->compressor;			stat = is->comp_stat;		}		else {			compressor = master->compressor;			stat = master->comp_stat;		}		new_proto = PPP_COMP;	}	if(!compressor) {		printk(KERN_ERR "isdn_ppp: No compressor set!\n");		return skb_in;	}	if(!stat) {		printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n");		return skb_in;	}	/* Allow for at least 150 % expansion (for now) */	skb_out = alloc_skb(skb_in->len + skb_in->len/2 + 32 +		skb_headroom(skb_in), GFP_ATOMIC);	if(!skb_out)		return skb_in;	skb_reserve(skb_out, skb_headroom(skb_in));	ret = (compressor->compress)(stat,skb_in,skb_out,*proto);	if(!ret) {		dev_kfree_skb(skb_out);		return skb_in;	}		dev_kfree_skb(skb_in);	*proto = new_proto;	return skb_out;}/* * we received a CCP frame ..  * not a clean solution, but we MUST handle a few cases in the kernel */static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,	 struct sk_buff *skb,int proto){	struct ippp_struct *is = ippp_table[lp->ppp_slot];	struct ippp_struct *mis;	int len;	struct isdn_ppp_resetparams rsparm;	unsigned char rsdata[IPPP_RESET_MAXDATABYTES];		printk(KERN_DEBUG "Received CCP frame from peer\n");	isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot);	if(lp->master)		mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot];	else		mis = is;	switch(skb->data[0]) {	case CCP_CONFREQ:		if(is->debug & 0x10)			printk(KERN_DEBUG "Disable compression here!\n");		if(proto == PPP_CCP)			mis->compflags &= ~SC_COMP_ON;				else			is->compflags &= ~SC_LINK_COMP_ON;				break;	case CCP_TERMREQ:	case CCP_TERMACK:		if(is->debug & 0x10)			printk(KERN_DEBUG "Disable (de)compression here!\n");		if(proto == 

⌨️ 快捷键说明

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