diff options
Diffstat (limited to 'net/x25/af_x25.c')
| -rw-r--r-- | net/x25/af_x25.c | 68 | 
1 files changed, 63 insertions, 5 deletions
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 9796f3ed1ed..cbddd0cb83f 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -47,6 +47,7 @@  #include <linux/netdevice.h>  #include <linux/if_arp.h>  #include <linux/skbuff.h> +#include <linux/slab.h>  #include <net/sock.h>  #include <net/tcp_states.h>  #include <asm/uaccess.h> @@ -82,6 +83,41 @@ struct compat_x25_subscrip_struct {  };  #endif + +int x25_parse_address_block(struct sk_buff *skb, +		struct x25_address *called_addr, +		struct x25_address *calling_addr) +{ +	unsigned char len; +	int needed; +	int rc; + +	if (skb->len < 1) { +		/* packet has no address block */ +		rc = 0; +		goto empty; +	} + +	len = *skb->data; +	needed = 1 + (len >> 4) + (len & 0x0f); + +	if (skb->len < needed) { +		/* packet is too short to hold the addresses it claims +		   to hold */ +		rc = -1; +		goto empty; +	} + +	return x25_addr_ntoa(skb->data, called_addr, calling_addr); + +empty: +	*called_addr->x25_addr = 0; +	*calling_addr->x25_addr = 0; + +	return rc; +} + +  int x25_addr_ntoa(unsigned char *p, struct x25_address *called_addr,  		  struct x25_address *calling_addr)  { @@ -553,7 +589,8 @@ static int x25_create(struct net *net, struct socket *sock, int protocol,  	x25->facilities.winsize_out = X25_DEFAULT_WINDOW_SIZE;  	x25->facilities.pacsize_in  = X25_DEFAULT_PACKET_SIZE;  	x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE; -	x25->facilities.throughput  = X25_DEFAULT_THROUGHPUT; +	x25->facilities.throughput  = 0;	/* by default don't negotiate +						   throughput */  	x25->facilities.reverse     = X25_DEFAULT_REVERSE;  	x25->dte_facilities.calling_len = 0;  	x25->dte_facilities.called_len = 0; @@ -921,16 +958,26 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,  	/*  	 *	Extract the X.25 addresses and convert them to ASCII strings,  	 *	and remove them. +	 * +	 *	Address block is mandatory in call request packets  	 */ -	addr_len = x25_addr_ntoa(skb->data, &source_addr, &dest_addr); +	addr_len = x25_parse_address_block(skb, &source_addr, &dest_addr); +	if (addr_len <= 0) +		goto out_clear_request;  	skb_pull(skb, addr_len);  	/*  	 *	Get the length of the facilities, skip past them for the moment  	 *	get the call user data because this is needed to determine  	 *	the correct listener +	 * +	 *	Facilities length is mandatory in call request packets  	 */ +	if (skb->len < 1) +		goto out_clear_request;  	len = skb->data[0] + 1; +	if (skb->len < len) +		goto out_clear_request;  	skb_pull(skb,len);  	/* @@ -1414,9 +1461,20 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)  			if (facilities.winsize_in < 1 ||  			    facilities.winsize_in > 127)  				break; -			if (facilities.throughput < 0x03 || -			    facilities.throughput > 0xDD) -				break; +			if (facilities.throughput) { +				int out = facilities.throughput & 0xf0; +				int in  = facilities.throughput & 0x0f; +				if (!out) +					facilities.throughput |= +						X25_DEFAULT_THROUGHPUT << 4; +				else if (out < 0x30 || out > 0xD0) +					break; +				if (!in) +					facilities.throughput |= +						X25_DEFAULT_THROUGHPUT; +				else if (in < 0x03 || in > 0x0D) +					break; +			}  			if (facilities.reverse &&  				(facilities.reverse & 0x81) != 0x81)  				break;  |