diff options
Diffstat (limited to 'drivers/net/ppp_generic.c')
| -rw-r--r-- | drivers/net/ppp_generic.c | 88 | 
1 files changed, 64 insertions, 24 deletions
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index d3c9958b00d..50430f79f8c 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -137,13 +137,14 @@ struct ppp {  /*   * Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC, - * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP. + * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP, + * SC_MUST_COMP   * Bits in rstate: SC_DECOMP_RUN, SC_DC_ERROR, SC_DC_FERROR.   * Bits in xstate: SC_COMP_RUN   */  #define SC_FLAG_BITS	(SC_NO_TCP_CCID|SC_CCP_OPEN|SC_CCP_UP|SC_LOOP_TRAFFIC \  			 |SC_MULTILINK|SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ \ -			 |SC_COMP_TCP|SC_REJ_COMP_TCP) +			 |SC_COMP_TCP|SC_REJ_COMP_TCP|SC_MUST_COMP)  /*   * Private data structure for each channel. @@ -1027,6 +1028,56 @@ ppp_xmit_process(struct ppp *ppp)  	ppp_xmit_unlock(ppp);  } +static inline struct sk_buff * +pad_compress_skb(struct ppp *ppp, struct sk_buff *skb) +{ +	struct sk_buff *new_skb; +	int len; +	int new_skb_size = ppp->dev->mtu + +		ppp->xcomp->comp_extra + ppp->dev->hard_header_len; +	int compressor_skb_size = ppp->dev->mtu + +		ppp->xcomp->comp_extra + PPP_HDRLEN; +	new_skb = alloc_skb(new_skb_size, GFP_ATOMIC); +	if (!new_skb) { +		if (net_ratelimit()) +			printk(KERN_ERR "PPP: no memory (comp pkt)\n"); +		return NULL; +	} +	if (ppp->dev->hard_header_len > PPP_HDRLEN) +		skb_reserve(new_skb, +			    ppp->dev->hard_header_len - PPP_HDRLEN); + +	/* compressor still expects A/C bytes in hdr */ +	len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2, +				   new_skb->data, skb->len + 2, +				   compressor_skb_size); +	if (len > 0 && (ppp->flags & SC_CCP_UP)) { +		kfree_skb(skb); +		skb = new_skb; +		skb_put(skb, len); +		skb_pull(skb, 2);	/* pull off A/C bytes */ +	} else if (len == 0) { +		/* didn't compress, or CCP not up yet */ +		kfree_skb(new_skb); +		new_skb = skb; +	} else { +		/* +		 * (len < 0) +		 * MPPE requires that we do not send unencrypted +		 * frames.  The compressor will return -1 if we +		 * should drop the frame.  We cannot simply test +		 * the compress_proto because MPPE and MPPC share +		 * the same number. +		 */ +		if (net_ratelimit()) +			printk(KERN_ERR "ppp: compressor dropped pkt\n"); +		kfree_skb(skb); +		kfree_skb(new_skb); +		new_skb = NULL; +	} +	return new_skb; +} +  /*   * Compress and send a frame.   * The caller should have locked the xmit path, @@ -1113,29 +1164,14 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)  	/* try to do packet compression */  	if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0  	    && proto != PPP_LCP && proto != PPP_CCP) { -		new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len, -				    GFP_ATOMIC); -		if (new_skb == 0) { -			printk(KERN_ERR "PPP: no memory (comp pkt)\n"); +		if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) { +			if (net_ratelimit()) +				printk(KERN_ERR "ppp: compression required but down - pkt dropped.\n");  			goto drop;  		} -		if (ppp->dev->hard_header_len > PPP_HDRLEN) -			skb_reserve(new_skb, -				    ppp->dev->hard_header_len - PPP_HDRLEN); - -		/* compressor still expects A/C bytes in hdr */ -		len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2, -					   new_skb->data, skb->len + 2, -					   ppp->dev->mtu + PPP_HDRLEN); -		if (len > 0 && (ppp->flags & SC_CCP_UP)) { -			kfree_skb(skb); -			skb = new_skb; -			skb_put(skb, len); -			skb_pull(skb, 2);	/* pull off A/C bytes */ -		} else { -			/* didn't compress, or CCP not up yet */ -			kfree_skb(new_skb); -		} +		skb = pad_compress_skb(ppp, skb); +		if (!skb) +			goto drop;  	}  	/* @@ -1155,7 +1191,8 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)  	return;   drop: -	kfree_skb(skb); +	if (skb) +		kfree_skb(skb);  	++ppp->stats.tx_errors;  } @@ -1552,6 +1589,9 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)  	    && (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0)  		skb = ppp_decompress_frame(ppp, skb); +	if (ppp->flags & SC_MUST_COMP && ppp->rstate & SC_DC_FERROR) +		goto err; +  	proto = PPP_PROTO(skb);  	switch (proto) {  	case PPP_VJC_COMP:  |