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

📄 ppp.c

📁 unix and linux net driver
💻 C
📖 第 1 页 / 共 5 页
字号:
{	unsigned long flags;	save_flags(flags);	cli();	ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN);	restore_flags(flags);	if (ppp->flags & SC_DEBUG)		printk(KERN_DEBUG "%s: ccp closed\n", ppp->name);	if (ppp->sc_xc_state) {		(*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state);		ppp->sc_xc_state = NULL;	}	if (ppp->sc_rc_state) {		(*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state);		ppp->sc_rc_state = NULL;	}}/************************************************************* * RECEIVE-SIDE ROUTINES *************************************************************//* * On entry, a received frame is in skb. * Check it and dispose as appropriate. */static intppp_receive_frame(struct ppp *ppp, struct sk_buff *skb){	__u8	*data;	int	count;	int	proto;	int	new_count;	struct sk_buff *new_skb;	ppp_proto_type	*proto_ptr;	/*	 * An empty frame is ignored. This occurs if the FLAG sequence	 * precedes and follows each frame.	 */	if (skb == NULL)		return 1;	if (skb->len == 0) {		KFREE_SKB(skb);		return 1;	}	data = skb->data;	count = skb->len;	/*	 * Generate an error if the frame is too small.	 */	if (count < PPP_HDRLEN + 2) {		if (ppp->flags & SC_DEBUG)			printk(KERN_DEBUG			       "ppp: got runt ppp frame, %d chars\n", count);		++ppp->estats.rx_length_errors;		return 0;	}	if ( !(ppp->flags & SC_SYNC) ) { 		/*		 * Verify the FCS of the frame and discard the FCS characters		 * from the end of the buffer.		 */		if (ppp->rfcs != PPP_GOODFCS) {			if (ppp->flags & SC_DEBUG) {				printk(KERN_DEBUG				       "ppp: frame with bad fcs, length = %d\n",				       count);				ppp_print_buffer("bad frame", data, count);			}			++ppp->estats.rx_crc_errors;			return 0;		}		count -= 2;		/* ignore the fcs characters */		skb_trim(skb, count);	}		/*	 * Process the active decompressor.	 */	if (ppp->sc_rc_state != NULL &&	    (ppp->flags & SC_DECOMP_RUN) &&	    ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) {		if (PPP_PROTOCOL(data) == PPP_COMP) {			/*			 * If the frame is compressed then decompress it.			 */			new_skb = dev_alloc_skb(ppp->mru + 128 + PPP_HDRLEN);			if (new_skb == NULL) {				printk(KERN_ERR "ppp_recv_frame: no memory\n");				new_count = DECOMP_ERROR;			} else {				LIBERATE_SKB(new_skb);				new_count = (*ppp->sc_rcomp->decompress)					(ppp->sc_rc_state, data, count,					 new_skb->data, ppp->mru + PPP_HDRLEN);			}			if (new_count > 0) {				/* Frame was decompressed OK */				KFREE_SKB(skb);				skb = new_skb;				count = new_count;				data = skb_put(skb, count);			} else {				/*				 * On a decompression error, we pass the				 * compressed frame up to pppd as an				 * error indication.				 */				if (ppp->flags & SC_DEBUG)					printk(KERN_INFO "%s: decomp err %d\n",					       ppp->name, new_count);				if (new_skb != 0)					KFREE_SKB(new_skb);				if (ppp->slcomp != 0)					slhc_toss(ppp->slcomp);				++ppp->stats.ppp_ierrors;				if (new_count == DECOMP_FATALERROR) {					ppp->flags |= SC_DC_FERROR;				} else {					ppp->flags |= SC_DC_ERROR;				}			}		} else {			/*			 * The frame is not compressed. Pass it to the			 * decompression code so it can update its			 * dictionary if necessary.			 */			(*ppp->sc_rcomp->incomp)(ppp->sc_rc_state,						 data, count);		}	}	else if (PPP_PROTOCOL(data) == PPP_COMP && (ppp->flags & SC_DEBUG))		printk(KERN_INFO "%s: not decomp, rc_state=%p flags=%x\n",		       ppp->name, ppp->sc_rc_state, ppp->flags);	/*	 * Count the frame and print it	 */	++ppp->stats.ppp_ipackets;	ppp->stats.ppp_ioctects += count;	if (ppp->flags & SC_LOG_INPKT)		ppp_print_buffer ("receive frame", data, count);	/*	 * Find the procedure to handle this protocol.	 * The last one is marked as protocol 0 which is the 'catch-all'	 * to feed it to the pppd daemon.	 */	proto = PPP_PROTOCOL(data);	proto_ptr = proto_list;	while (proto_ptr->proto != 0 && proto_ptr->proto != proto)		++proto_ptr;	/*	 * Update the appropriate statistic counter.	 */	if (!(*proto_ptr->func)(ppp, skb)) {		KFREE_SKB(skb);		++ppp->stats.ppp_discards;	}	return 1;}/* * An input error has been detected, so we need to inform * the VJ decompressor. */static voidppp_receive_error(struct ppp *ppp){	CHECK_PPP_VOID();	if (ppp->slcomp != 0)		slhc_toss(ppp->slcomp);}/* * Put the input frame into the networking system for the indicated protocol */static intppp_rcv_rx(struct ppp *ppp, __u16 proto, struct sk_buff *skb){	/*	 * Fill in a few fields of the skb and give it to netif_rx().	 */	skb->dev      = ppp2dev(ppp);	/* We are the device */	skb->protocol = htons(proto);	skb_pull(skb, PPP_HDRLEN);	/* pull off ppp header */	skb->mac.raw   = skb->data;	ppp->last_recv = jiffies;	netif_rx (skb);	return 1;}/* * Process the receipt of an IP frame */static intrcv_proto_ip(struct ppp *ppp, struct sk_buff *skb){	CHECK_PPP(0);	if ((ppp2dev(ppp)->flags & IFF_UP) && (skb->len > 0)	    && ppp->sc_npmode[NP_IP] == NPMODE_PASS)		return ppp_rcv_rx(ppp, ETH_P_IP, skb);	return 0;}/* * Process the receipt of an IPv6 frame */static intrcv_proto_ipv6(struct ppp *ppp, struct sk_buff *skb){	CHECK_PPP(0);	if ((ppp2dev(ppp)->flags & IFF_UP) && (skb->len > 0)	    && ppp->sc_npmode[NP_IPV6] == NPMODE_PASS)		return ppp_rcv_rx(ppp, ETH_P_IPV6, skb);	return 0;}/* * Process the receipt of an IPX frame */static intrcv_proto_ipx(struct ppp *ppp, struct sk_buff *skb){	CHECK_PPP(0);	if (((ppp2dev(ppp)->flags & IFF_UP) != 0) && (skb->len > 0)	    && ppp->sc_npmode[NP_IPX] == NPMODE_PASS)		return ppp_rcv_rx(ppp, ETH_P_IPX, skb);	return 0;}/* * Process the receipt of an Appletalk frame */static intrcv_proto_at(struct ppp *ppp, struct sk_buff *skb){	CHECK_PPP(0);	if ((ppp2dev(ppp)->flags & IFF_UP) && (skb->len > 0)	    && ppp->sc_npmode[NP_AT] == NPMODE_PASS)		return ppp_rcv_rx(ppp, ETH_P_PPPTALK, skb);	return 0;}/* * Process the receipt of an VJ Compressed frame */static intrcv_proto_vjc_comp(struct ppp *ppp, struct sk_buff *skb){	int new_count;	CHECK_PPP(0);	if ((ppp->flags & SC_REJ_COMP_TCP) || ppp->slcomp == NULL)		return 0;	new_count = slhc_uncompress(ppp->slcomp, skb->data + PPP_HDRLEN,				    skb->len - PPP_HDRLEN);	if (new_count <= 0) {		if (ppp->flags & SC_DEBUG)			printk(KERN_NOTICE			       "ppp: error in VJ decompression\n");		return 0;	}	new_count += PPP_HDRLEN;	if (new_count > skb->len)		skb_put(skb, new_count - skb->len);	else		skb_trim(skb, new_count);	return rcv_proto_ip(ppp, skb);}/* * Process the receipt of an VJ Un-compressed frame */static intrcv_proto_vjc_uncomp(struct ppp *ppp, struct sk_buff *skb){	CHECK_PPP(0);	if ((ppp->flags & SC_REJ_COMP_TCP) || ppp->slcomp == NULL)		return 0;	if (slhc_remember(ppp->slcomp, skb->data + PPP_HDRLEN,			  skb->len - PPP_HDRLEN) <= 0) {		if (ppp->flags & SC_DEBUG)			printk(KERN_NOTICE "ppp: error in VJ memorizing\n");		return 0;	}	return rcv_proto_ip(ppp, skb);}static intrcv_proto_ccp(struct ppp *ppp, struct sk_buff *skb){	CHECK_PPP(0);	ppp_proto_ccp (ppp, skb->data + PPP_HDRLEN, skb->len - PPP_HDRLEN, 1);	return rcv_proto_unknown(ppp, skb);}/* * Receive all unclassified protocols. */static intrcv_proto_unknown(struct ppp *ppp, struct sk_buff *skb){	CHECK_PPP(0);	/*	 * Limit queue length by dropping old frames.	 */	skb_queue_tail(&ppp->rcv_q, skb);	while (ppp->rcv_q.qlen > PPP_MAX_RCV_QLEN) {		struct sk_buff *skb = skb_dequeue(&ppp->rcv_q);		if (skb)			KFREE_SKB(skb);	}	wake_up_interruptible (&ppp->read_wait);	if (ppp->tty->fasync != NULL)		kill_fasync (ppp->tty->fasync, SIGIO);	return 1;}/************************************************************* * TRANSMIT-SIDE ROUTINES *************************************************************//* local function to store a value into the LQR frame */extern inline __u8 * store_long (register __u8 *p, register int value) {	*p++ = (__u8) (value >> 24);	*p++ = (__u8) (value >> 16);	*p++ = (__u8) (value >>	 8);	*p++ = (__u8) value;	return p;}/* * Compress and send an frame to the peer. * Should be called with xmit_busy == 1, having been set by the caller. * That is, we use xmit_busy as a lock to prevent reentry of this * procedure. */static voidppp_send_frame(struct ppp *ppp, struct sk_buff *skb){	int	proto;	__u8	*data;	int	count;	__u8	*p;	int	ret;	CHECK_PPP_VOID();	data = skb->data;	count = skb->len;	/* dump the buffer */	if (ppp->flags & SC_LOG_OUTPKT)		ppp_print_buffer ("write frame", data, count);	/*	 * Handle various types of protocol-specific compression	 * and other processing, including:	 * - VJ TCP header compression	 * - updating LQR packets	 * - updating CCP state on CCP packets	 */	proto = PPP_PROTOCOL(data);	switch (proto) {	case PPP_IP:		if ((ppp->flags & SC_COMP_TCP) && ppp->slcomp != NULL)			skb = ppp_vj_compress(ppp, skb);		break;	case PPP_LQR:		/*		 * Update the LQR frame with the current MIB information.		 * This way the information is accurate and up-to-date.		 */		if (count < 48)			break;		p = data + 40;	/* Point to last two items. */		p = store_long(p, ppp->stats.ppp_opackets + 1);		p = store_long(p, ppp->stats.ppp_ooctects + count);		++ppp->stats.ppp_olqrs;		break;	case PPP_CCP:		/*		 * Outbound compression control frames		 */		ppp_proto_ccp(ppp, data + PPP_HDRLEN, count - PPP_HDRLEN, 0);		break;	}	data = skb->data;	count = skb->len;	/*	 * Compress the whole frame if possible.	 */	if (((ppp->flags & SC_COMP_RUN) != 0)	&&	    (ppp->sc_xc_state != (void *) 0)	&&	    (proto != PPP_LCP)			&&	    (proto != PPP_CCP)) {		struct sk_buff *new_skb;		int new_count;		/* Allocate an skb for the compressed frame. */		new_skb = alloc_skb(ppp->mtu + PPP_HDRLEN, GFP_ATOMIC);		if (new_skb == NULL) {			printk(KERN_ERR "ppp_send_frame: no memory\n");			KFREE_SKB(skb);			ppp->xmit_busy = 0;			return;		}		LIBERATE_SKB(new_skb);		/* Compress the frame. */		new_count = (*ppp->sc_xcomp->compress)			(ppp->sc_xc_state, data, new_skb->data,			 count, ppp->mtu + PPP_HDRLEN);		/* Did it compress? */		if (new_count > 0 && (ppp->flags & SC_CCP_UP)) {			skb_put(new_skb, new_count);			KFREE_SKB(skb);			skb = new_skb;		} else {			/*			 * The frame could not be compressed, or it could not			 * be sent in compressed form because CCP is down.			 */			KFREE_SKB(new_skb);		}	}	/*	 * Send the frame	 */	if ( ppp->flags & SC_SYNC ) 		ret = ppp_sync_send(ppp, skb);	else		ret = ppp_async_send(ppp, skb);	if (ret > 0) {		/* we can release the lock */		ppp->xmit_busy = 0;	} else if (ret < 0) {		/* can't happen, since the caller got the xmit_busy lock */		printk(KERN_ERR "ppp: ppp_async_send didn't accept pkt\n");	}}/* * Apply VJ TCP header compression to a packet. */static struct sk_buff *ppp_vj_compress(struct ppp *ppp, struct sk_buff *skb){	__u8 *orig_data, *data;	struct sk_buff *new_skb;	int len, proto;	new_skb = alloc_skb(skb->len, GFP_ATOMIC);	if (new_skb == NULL) {		printk(KERN_ERR "ppp: no memory for vj compression\n");		return skb;	}	LIBERATE_SKB(new_skb);	orig_data = data = skb->data + PPP_HDRLEN;	len = slhc_compress(ppp->slcomp, data, skb->len - PPP_HDRLEN,			    new_skb->data + PPP_HDRLEN, &data,			    (ppp->flags & SC_NO_TCP_CCID) == 0);	if (data == orig_data) {		/* Couldn't compress the data */		KFREE_SKB(new_skb);		return skb;	}	/* The data has been changed */	if (data[0] & SL_TYPE_COMPRESSED_TCP) {		proto = PPP_VJC_COMP;		data[0] ^= SL_TYPE_COMPRESSED_TCP;	} else {		if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP)			proto = PPP_VJC_UNCOMP;		else			proto = PPP_IP;		data[0] = orig_data[0];	}	data = skb_put(new_skb, len + PPP_HDRLEN);	data[0] = PPP_ALLSTATIONS;	data[1] = PPP_UI;	data[2] = 0;	data[3] = proto;	KFREE_SKB(skb);	return new_skb;}static inline voidppp_send_frames(struct ppp *ppp){	struct sk_buff *skb;	while (!test_and_set_bit(0, &ppp->xmit_busy)) {		skb = skb_dequeue(&ppp->xmt_q);		if (skb == NULL) {			ppp->xmit_busy = 0;			break;		}		ppp_send_frame(ppp, skb);	}	if (!ppp->xmit_busy && ppp->dev.tbusy) {		ppp->dev.tbusy = 0;		mark_bh(NET_BH);	}}/* * Called from the hardware (tty) layer when it can accept * another packet. */static voidppp_output_wakeup(struct ppp *ppp){	CHECK_PPP_VOID();	if (!ppp->xmit_busy) {		printk(KERN_ERR "ppp_output_wakeup called but xmit_busy==0\n");		return;	}	ppp->xmit_busy = 0;	ppp_send_frames(ppp);}/* * Send a control frame (from pppd). */static voidppp_send_ctrl(struct ppp *ppp, struct sk_buff *skb)

⌨️ 快捷键说明

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