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

📄 isdn_ppp.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
	 *   possible ('start' would be set to NULL)	 *	 * algorightm for this code is derived from code in the book	 * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)	 */  	while (start != NULL || newfrag != NULL) {    		thisseq = MP_SEQ(frag);    		nextf = frag->next;    		/* drop any duplicate fragments */    		if (newfrag != NULL && thisseq == newseq) {      			isdn_ppp_mp_free_skb(mp, newfrag);      			newfrag = NULL;    		}    		/* insert new fragment before next element if possible. */    		if (newfrag != NULL && (nextf == NULL || 						MP_LT(newseq, MP_SEQ(nextf)))) {      			newfrag->next = nextf;      			frag->next = nextf = newfrag;      			newfrag = NULL;    		}    		if (start != NULL) {	    		/* check for misplaced start */      			if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {				printk(KERN_WARNING"isdn_mppp(seq %d): new "				      "BEGIN flag with no prior END", thisseq);				stats->seqerrs++;				stats->frame_drops++;				start = isdn_ppp_mp_discard(mp, start,frag);				nextf = frag->next;      			}    		} else if (MP_LE(thisseq, minseq)) {		      			if (MP_FLAGS(frag) & MP_BEGIN_FRAG)				start = frag;      			else {				if (MP_FLAGS(frag) & MP_END_FRAG)	  				stats->frame_drops++;				if( mp->frags == frag )					mp->frags = nextf;					isdn_ppp_mp_free_skb(mp, frag);				frag = nextf;				continue;      			}		}				/* if start is non-null and we have end fragment, then		 * we have full reassembly sequence -- reassemble 		 * and process packet now		 */    		if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {      			minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;      			/* Reassemble the packet then dispatch it */			isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);            			start = NULL;      			frag = NULL;      			mp->frags = nextf;    		}		/* check if need to update start pointer: if we just		 * reassembled the packet and sequence is contiguous		 * then next fragment should be the start of new reassembly		 * if sequence is contiguous, but we haven't reassembled yet,		 * keep going.		 * if sequence is not contiguous, either clear everyting		 * below low watermark and set start to the next frag or		 * clear start ptr.		 */     		if (nextf != NULL && 		    ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {      			/* if we just reassembled and the next one is here, 			 * then start another reassembly. */      			if (frag == NULL) {				if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)	  				start = nextf;				else				{	  				printk(KERN_WARNING"isdn_mppp(seq %d):"						" END flag with no following "						"BEGIN", thisseq);					stats->seqerrs++;				}			}    		} else {			if ( nextf != NULL && frag != NULL &&						MP_LT(thisseq, minseq)) {				/* we've got a break in the sequence				 * and we not at the end yet				 * and we did not just reassembled				 *(if we did, there wouldn't be anything before)				 * and we below the low watermark 			 	 * discard all the frames below low watermark 				 * and start over */				stats->frame_drops++;				mp->frags = isdn_ppp_mp_discard(mp,start,nextf);			}			/* break in the sequence, no reassembly */      			start = NULL;    		}	  			    		frag = nextf;  	}	/* while -- main loop */	  	if (mp->frags == NULL)    		mp->frags = frag;			/* rather straighforward way to deal with (not very) possible 	 * queue overflow */	if (mp->frames > MP_MAX_QUEUE_LEN) {		stats->overflows++;		while (mp->frames > MP_MAX_QUEUE_LEN) {			frag = mp->frags->next;			isdn_ppp_mp_free_skb(mp, mp->frags);			mp->frags = frag;		}	}	spin_unlock_irqrestore(&mp->lock, flags);}static void isdn_ppp_mp_cleanup( isdn_net_local * lp ){	struct sk_buff * frag = lp->netdev->pb->frags;	struct sk_buff * nextfrag;    	while( frag ) {		nextfrag = frag->next;		isdn_ppp_mp_free_skb(lp->netdev->pb, frag);		frag = nextfrag;	}	lp->netdev->pb->frags = NULL;}static u32 isdn_ppp_mp_get_seq( int short_seq, 					struct sk_buff * skb, u32 last_seq ){	u32 seq;	int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);      	if( !short_seq )	{		seq = ntohl(*(u32*)skb->data) & MP_LONGSEQ_MASK;		skb_push(skb,1);	}	else	{		/* convert 12-bit short seq number to 24-bit long one 	 	*/		seq = ntohs(*(u16*)skb->data) & MP_SHORTSEQ_MASK;			/* check for seqence wrap */		if( !(seq &  MP_SHORTSEQ_MAXBIT) && 		     (last_seq &  MP_SHORTSEQ_MAXBIT) && 		     (unsigned long)last_seq <= MP_LONGSEQ_MAX )			seq |= (last_seq + MP_SHORTSEQ_MAX+1) & 					(~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);		else			seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);				skb_push(skb, 3);	/* put converted seqence back in skb */	}	*(u32*)(skb->data+1) = seq; 	/* put seqence back in _host_ byte					 * order */	skb->data[0] = flags;	        /* restore flags */	return seq;}struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,			struct sk_buff * from, struct sk_buff * to ){	if( from )		while (from != to) {	  		struct sk_buff * next = from->next;			isdn_ppp_mp_free_skb(mp, from);	  		from = next;		}	return from;}void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,				struct sk_buff * from, struct sk_buff * to ){	ippp_bundle * mp = net_dev->pb;	int proto;	struct sk_buff * skb;	unsigned int tot_len;	if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {		if( ippp_table[lp->ppp_slot]->debug & 0x40 )			printk(KERN_DEBUG"isdn_mppp: reassembly: frame %d, "					"len %d\n", MP_SEQ(from), from->len );		skb = from;		skb_pull(skb, MP_HEADER_LEN);		mp->frames--;		} else {		struct sk_buff * frag;		int n;		for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++)			tot_len += frag->len - MP_HEADER_LEN;		if( ippp_table[lp->ppp_slot]->debug & 0x40 )			printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "				"to %d, len %d\n", MP_SEQ(from), 				(MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len );		if( (skb = dev_alloc_skb(tot_len)) == NULL ) {			printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "					"of size %d\n", tot_len);			isdn_ppp_mp_discard(mp, from, to);			return;		}		while( from != to ) {			unsigned int len = from->len - MP_HEADER_LEN;			memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len);			frag = from->next;			isdn_ppp_mp_free_skb(mp, from);			from = frag; 		}	}   	proto = isdn_ppp_strip_proto(skb);	isdn_ppp_push_higher(net_dev, lp, skb, proto);}static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb){	dev_kfree_skb(skb);	mp->frames--;}static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb ){	printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n", 		slot, (int) skb->len, 		(int) skb->data[0], (int) skb->data[1], (int) skb->data[2],		(int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);}static intisdn_ppp_bundle(struct ippp_struct *is, int unit){	char ifn[IFNAMSIZ + 1];	isdn_net_dev *p;	isdn_net_local *lp, *nlp;	int rc;	unsigned long flags;	sprintf(ifn, "ippp%d", unit);	p = isdn_net_findif(ifn);	if (!p) {		printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);		return -EINVAL;	}    	spin_lock_irqsave(&p->pb->lock, flags);	nlp = is->lp;	lp = p->queue;	if( nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||		lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS ) {		printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",			nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ? 			nlp->ppp_slot : lp->ppp_slot );		rc = -EINVAL;		goto out; 	}	isdn_net_add_to_bundle(p, nlp);	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 *res,	 t;	isdn_net_local *lp = (isdn_net_local *) dev->priv;	int err;	res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;	err = verify_area(VERIFY_WRITE, res, sizeof(struct ppp_stats));	if (err)		return err;	/* 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_ierrors = lp->stats.rx_errors;		t.p.ppp_opackets = lp->stats.tx_packets;		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;	char *r;	int len;	isdn_net_local *lp = (isdn_net_local *) dev->priv;	if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)		return -EINVAL;	switch (cmd) {		case SIOCGPPPVER:			r = (char *) ifr->ifr_ifru.ifru_data;			len = strlen(PPP_VERSION) + 1;			if(copy_to_user(r, 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->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.

⌨️ 快捷键说明

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