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

📄 isdn_ppp.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
   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 */		printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n",		       rs->id);		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;		}		/* 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;  		/* !!!HACK,HACK,HACK!!! 2048 is only assumed */  		skb_out = dev_alloc_skb(2048);		len = ipc->decompress(stat, skb, skb_out, &rsparm);		kfree_skb(skb);		if (len <= 0) {			switch(len) {			case DECOMP_ERROR:				ri->pppcfg |= SC_DC_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;		}		if (isdn_ppp_skip_ac(ri, skb) < 0) {			kfree_skb(skb);			return NULL;		}		*proto = isdn_ppp_strip_proto(skb);		if (*proto < 0) {			kfree_skb(skb);			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:	case CCP_TERMREQ:	case CCP_TERMACK:		if(is->debug & 0x10)			printk(KERN_DEBUG "Disable (de)compression here!\n");		if(proto == PPP_CCP)			mis->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON);				else			is->compflags &= ~(SC_LINK_DECOMP_ON|SC

⌨️ 快捷键说明

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