diff options
Diffstat (limited to 'net/x25/x25_in.c')
| -rw-r--r-- | net/x25/x25_in.c | 167 | 
1 files changed, 105 insertions, 62 deletions
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c index f729f022be6..7ac50098a37 100644 --- a/net/x25/x25_in.c +++ b/net/x25/x25_in.c @@ -23,6 +23,8 @@   *					  i-frames.   */ +#define pr_fmt(fmt) "X25: " fmt +  #include <linux/slab.h>  #include <linux/errno.h>  #include <linux/kernel.h> @@ -77,7 +79,7 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)  	skb_set_owner_r(skbn, sk);  	skb_queue_tail(&sk->sk_receive_queue, skbn);  	if (!sock_flag(sk, SOCK_DEAD)) -		sk->sk_data_ready(sk, skbn->len); +		sk->sk_data_ready(sk);  	return 0;  } @@ -91,59 +93,74 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp  {  	struct x25_address source_addr, dest_addr;  	int len; +	struct x25_sock *x25 = x25_sk(sk);  	switch (frametype) { -		case X25_CALL_ACCEPTED: { -			struct x25_sock *x25 = x25_sk(sk); - -			x25_stop_timer(sk); -			x25->condition = 0x00; -			x25->vs        = 0; -			x25->va        = 0; -			x25->vr        = 0; -			x25->vl        = 0; -			x25->state     = X25_STATE_3; -			sk->sk_state   = TCP_ESTABLISHED; -			/* -			 *	Parse the data in the frame. -			 */ -			skb_pull(skb, X25_STD_MIN_LEN); - -			len = x25_parse_address_block(skb, &source_addr, -						&dest_addr); -			if (len > 0) -				skb_pull(skb, len); - -			len = x25_parse_facilities(skb, &x25->facilities, -						&x25->dte_facilities, -						&x25->vc_facil_mask); -			if (len > 0) -				skb_pull(skb, len); -			else -				return -1; -			/* -			 *	Copy any Call User Data. -			 */ -			if (skb->len > 0) { -				skb_copy_from_linear_data(skb, -					      x25->calluserdata.cuddata, -					      skb->len); -				x25->calluserdata.cudlength = skb->len; -			} -			if (!sock_flag(sk, SOCK_DEAD)) -				sk->sk_state_change(sk); -			break; +	case X25_CALL_ACCEPTED: { + +		x25_stop_timer(sk); +		x25->condition = 0x00; +		x25->vs        = 0; +		x25->va        = 0; +		x25->vr        = 0; +		x25->vl        = 0; +		x25->state     = X25_STATE_3; +		sk->sk_state   = TCP_ESTABLISHED; +		/* +		 *	Parse the data in the frame. +		 */ +		if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) +			goto out_clear; +		skb_pull(skb, X25_STD_MIN_LEN); + +		len = x25_parse_address_block(skb, &source_addr, +					      &dest_addr); +		if (len > 0) +			skb_pull(skb, len); +		else if (len < 0) +			goto out_clear; + +		len = x25_parse_facilities(skb, &x25->facilities, +					   &x25->dte_facilities, +					   &x25->vc_facil_mask); +		if (len > 0) +			skb_pull(skb, len); +		else if (len < 0) +			goto out_clear; +		/* +		 *	Copy any Call User Data. +		 */ +		if (skb->len > 0) { +			if (skb->len > X25_MAX_CUD_LEN) +				goto out_clear; + +			skb_copy_bits(skb, 0, x25->calluserdata.cuddata, +				skb->len); +			x25->calluserdata.cudlength = skb->len;  		} -		case X25_CLEAR_REQUEST: -			x25_write_internal(sk, X25_CLEAR_CONFIRMATION); -			x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); -			break; +		if (!sock_flag(sk, SOCK_DEAD)) +			sk->sk_state_change(sk); +		break; +	} +	case X25_CLEAR_REQUEST: +		if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) +			goto out_clear; -		default: -			break; +		x25_write_internal(sk, X25_CLEAR_CONFIRMATION); +		x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); +		break; + +	default: +		break;  	}  	return 0; + +out_clear: +	x25_write_internal(sk, X25_CLEAR_REQUEST); +	x25->state = X25_STATE_2; +	x25_start_t23timer(sk); +	return 0;  }  /* @@ -156,6 +173,9 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp  	switch (frametype) {  		case X25_CLEAR_REQUEST: +			if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) +				goto out_clear; +  			x25_write_internal(sk, X25_CLEAR_CONFIRMATION);  			x25_disconnect(sk, 0, skb->data[3], skb->data[4]);  			break; @@ -169,6 +189,11 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp  	}  	return 0; + +out_clear: +	x25_write_internal(sk, X25_CLEAR_REQUEST); +	x25_start_t23timer(sk); +	return 0;  }  /* @@ -198,6 +223,9 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp  			break;  		case X25_CLEAR_REQUEST: +			if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) +				goto out_clear; +  			x25_write_internal(sk, X25_CLEAR_CONFIRMATION);  			x25_disconnect(sk, 0, skb->data[3], skb->data[4]);  			break; @@ -291,11 +319,17 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp  			break;  		default: -			printk(KERN_WARNING "x25: unknown %02X in state 3\n", frametype); +			pr_warn("unknown %02X in state 3\n", frametype);  			break;  	}  	return queued; + +out_clear: +	x25_write_internal(sk, X25_CLEAR_REQUEST); +	x25->state = X25_STATE_2; +	x25_start_t23timer(sk); +	return 0;  }  /* @@ -305,13 +339,13 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp   */  static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)  { +	struct x25_sock *x25 = x25_sk(sk); +  	switch (frametype) {  		case X25_RESET_REQUEST:  			x25_write_internal(sk, X25_RESET_CONFIRMATION);  		case X25_RESET_CONFIRMATION: { -			struct x25_sock *x25 = x25_sk(sk); -  			x25_stop_timer(sk);  			x25->condition = 0x00;  			x25->va        = 0; @@ -323,6 +357,9 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp  			break;  		}  		case X25_CLEAR_REQUEST: +			if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) +				goto out_clear; +  			x25_write_internal(sk, X25_CLEAR_CONFIRMATION);  			x25_disconnect(sk, 0, skb->data[3], skb->data[4]);  			break; @@ -332,6 +369,12 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp  	}  	return 0; + +out_clear: +	x25_write_internal(sk, X25_CLEAR_REQUEST); +	x25->state = X25_STATE_2; +	x25_start_t23timer(sk); +	return 0;  }  /* Higher level upcall for a LAPB frame */ @@ -346,18 +389,18 @@ int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)  	frametype = x25_decode(sk, skb, &ns, &nr, &q, &d, &m);  	switch (x25->state) { -		case X25_STATE_1: -			queued = x25_state1_machine(sk, skb, frametype); -			break; -		case X25_STATE_2: -			queued = x25_state2_machine(sk, skb, frametype); -			break; -		case X25_STATE_3: -			queued = x25_state3_machine(sk, skb, frametype, ns, nr, q, d, m); -			break; -		case X25_STATE_4: -			queued = x25_state4_machine(sk, skb, frametype); -			break; +	case X25_STATE_1: +		queued = x25_state1_machine(sk, skb, frametype); +		break; +	case X25_STATE_2: +		queued = x25_state2_machine(sk, skb, frametype); +		break; +	case X25_STATE_3: +		queued = x25_state3_machine(sk, skb, frametype, ns, nr, q, d, m); +		break; +	case X25_STATE_4: +		queued = x25_state4_machine(sk, skb, frametype); +		break;  	}  	x25_kick(sk);  | 
