diff options
Diffstat (limited to 'net/x25/x25_subr.c')
| -rw-r--r-- | net/x25/x25_subr.c | 96 | 
1 files changed, 54 insertions, 42 deletions
diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c index dc20cf12f39..6b5af65f491 100644 --- a/net/x25/x25_subr.c +++ b/net/x25/x25_subr.c @@ -23,6 +23,8 @@   *						restriction on response.   */ +#define pr_fmt(fmt) "X25: " fmt +  #include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/string.h> @@ -126,32 +128,30 @@ void x25_write_internal(struct sock *sk, int frametype)  	 *	Adjust frame size.  	 */  	switch (frametype) { -		case X25_CALL_REQUEST: -			len += 1 + X25_ADDR_LEN + X25_MAX_FAC_LEN + -			       X25_MAX_CUD_LEN; -			break; -		case X25_CALL_ACCEPTED: /* fast sel with no restr on resp */ -			if(x25->facilities.reverse & 0x80) { -				len += 1 + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN; -			} else { -				len += 1 + X25_MAX_FAC_LEN; -			} -			break; -		case X25_CLEAR_REQUEST: -		case X25_RESET_REQUEST: -			len += 2; -			break; -		case X25_RR: -		case X25_RNR: -		case X25_REJ: -		case X25_CLEAR_CONFIRMATION: -		case X25_INTERRUPT_CONFIRMATION: -		case X25_RESET_CONFIRMATION: -			break; -		default: -			printk(KERN_ERR "X.25: invalid frame type %02X\n", -			       frametype); -			return; +	case X25_CALL_REQUEST: +		len += 1 + X25_ADDR_LEN + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN; +		break; +	case X25_CALL_ACCEPTED: /* fast sel with no restr on resp */ +		if (x25->facilities.reverse & 0x80) { +			len += 1 + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN; +		} else { +			len += 1 + X25_MAX_FAC_LEN; +		} +		break; +	case X25_CLEAR_REQUEST: +	case X25_RESET_REQUEST: +		len += 2; +		break; +	case X25_RR: +	case X25_RNR: +	case X25_REJ: +	case X25_CLEAR_CONFIRMATION: +	case X25_INTERRUPT_CONFIRMATION: +	case X25_RESET_CONFIRMATION: +		break; +	default: +		pr_err("invalid frame type %02X\n", frametype); +		return;  	}  	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL) @@ -271,31 +271,39 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,  	       int *d, int *m)  {  	struct x25_sock *x25 = x25_sk(sk); -	unsigned char *frame = skb->data; +	unsigned char *frame; + +	if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) +		return X25_ILLEGAL; +	frame = skb->data;  	*ns = *nr = *q = *d = *m = 0;  	switch (frame[2]) { -		case X25_CALL_REQUEST: -		case X25_CALL_ACCEPTED: -		case X25_CLEAR_REQUEST: -		case X25_CLEAR_CONFIRMATION: -		case X25_INTERRUPT: -		case X25_INTERRUPT_CONFIRMATION: -		case X25_RESET_REQUEST: -		case X25_RESET_CONFIRMATION: -		case X25_RESTART_REQUEST: -		case X25_RESTART_CONFIRMATION: -		case X25_REGISTRATION_REQUEST: -		case X25_REGISTRATION_CONFIRMATION: -		case X25_DIAGNOSTIC: -			return frame[2]; +	case X25_CALL_REQUEST: +	case X25_CALL_ACCEPTED: +	case X25_CLEAR_REQUEST: +	case X25_CLEAR_CONFIRMATION: +	case X25_INTERRUPT: +	case X25_INTERRUPT_CONFIRMATION: +	case X25_RESET_REQUEST: +	case X25_RESET_CONFIRMATION: +	case X25_RESTART_REQUEST: +	case X25_RESTART_CONFIRMATION: +	case X25_REGISTRATION_REQUEST: +	case X25_REGISTRATION_CONFIRMATION: +	case X25_DIAGNOSTIC: +		return frame[2];  	}  	if (x25->neighbour->extended) {  		if (frame[2] == X25_RR  ||  		    frame[2] == X25_RNR ||  		    frame[2] == X25_REJ) { +			if (!pskb_may_pull(skb, X25_EXT_MIN_LEN)) +				return X25_ILLEGAL; +			frame = skb->data; +  			*nr = (frame[3] >> 1) & 0x7F;  			return frame[2];  		} @@ -310,6 +318,10 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,  	if (x25->neighbour->extended) {  		if ((frame[2] & 0x01) == X25_DATA) { +			if (!pskb_may_pull(skb, X25_EXT_MIN_LEN)) +				return X25_ILLEGAL; +			frame = skb->data; +  			*q  = (frame[0] & X25_Q_BIT) == X25_Q_BIT;  			*d  = (frame[0] & X25_D_BIT) == X25_D_BIT;  			*m  = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT; @@ -328,7 +340,7 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,  		}  	} -	printk(KERN_DEBUG "X.25: invalid PLP frame %02X %02X %02X\n", +	pr_debug("invalid PLP frame %02X %02X %02X\n",  	       frame[0], frame[1], frame[2]);  	return X25_ILLEGAL;  | 
