diff options
Diffstat (limited to 'net/x25')
| -rw-r--r-- | net/x25/Kconfig | 8 | ||||
| -rw-r--r-- | net/x25/af_x25.c | 594 | ||||
| -rw-r--r-- | net/x25/sysctl_net_x25.c | 10 | ||||
| -rw-r--r-- | net/x25/x25_dev.c | 68 | ||||
| -rw-r--r-- | net/x25/x25_facilities.c | 60 | ||||
| -rw-r--r-- | net/x25/x25_forward.c | 9 | ||||
| -rw-r--r-- | net/x25/x25_in.c | 167 | ||||
| -rw-r--r-- | net/x25/x25_link.c | 90 | ||||
| -rw-r--r-- | net/x25/x25_out.c | 7 | ||||
| -rw-r--r-- | net/x25/x25_proc.c | 48 | ||||
| -rw-r--r-- | net/x25/x25_route.c | 4 | ||||
| -rw-r--r-- | net/x25/x25_subr.c | 96 | 
12 files changed, 616 insertions, 545 deletions
diff --git a/net/x25/Kconfig b/net/x25/Kconfig index 2196e55e4f6..e2fa133f9fb 100644 --- a/net/x25/Kconfig +++ b/net/x25/Kconfig @@ -3,9 +3,7 @@  #  config X25 -	tristate "CCITT X.25 Packet Layer (EXPERIMENTAL)" -	depends on EXPERIMENTAL -	depends on BKL # should be fixable +	tristate "CCITT X.25 Packet Layer"  	---help---  	  X.25 is a set of standardized network protocols, similar in scope to  	  frame relay; the one physical line from your box to the X.25 network @@ -18,8 +16,8 @@ config X25  	  if you want that) and the lower level data link layer protocol LAPB  	  (say Y to "LAPB Data Link Driver" below if you want that). -	  You can read more about X.25 at <http://www.sangoma.com/x25.htm> and -	  <http://www.cisco.com/univercd/cc/td/doc/product/software/ios11/cbook/cx25.htm>. +	  You can read more about X.25 at <http://www.sangoma.com/tutorials/x25/> and +	  <http://docwiki.cisco.com/wiki/X.25>.  	  Information about X.25 for Linux is contained in the files  	  <file:Documentation/networking/x25.txt> and  	  <file:Documentation/networking/x25-iface.txt>. diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index ad96ee90fe2..5ad4418ef09 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -35,12 +35,13 @@   *					response   */ +#define pr_fmt(fmt) "X25: " fmt +  #include <linux/module.h>  #include <linux/capability.h>  #include <linux/errno.h>  #include <linux/kernel.h>  #include <linux/sched.h> -#include <linux/smp_lock.h>  #include <linux/timer.h>  #include <linux/string.h>  #include <linux/net.h> @@ -92,7 +93,7 @@ int x25_parse_address_block(struct sk_buff *skb,  	int needed;  	int rc; -	if (skb->len < 1) { +	if (!pskb_may_pull(skb, 1)) {  		/* packet has no address block */  		rc = 0;  		goto empty; @@ -101,7 +102,7 @@ int x25_parse_address_block(struct sk_buff *skb,  	len = *skb->data;  	needed = 1 + (len >> 4) + (len & 0x0f); -	if (skb->len < needed) { +	if (!pskb_may_pull(skb, needed)) {  		/* packet is too short to hold the addresses it claims  		   to hold */  		rc = -1; @@ -209,11 +210,10 @@ static void x25_remove_socket(struct sock *sk)  static void x25_kill_by_device(struct net_device *dev)  {  	struct sock *s; -	struct hlist_node *node;  	write_lock_bh(&x25_list_lock); -	sk_for_each(s, node, &x25_list) +	sk_for_each(s, &x25_list)  		if (x25_sk(s)->neighbour && x25_sk(s)->neighbour->dev == dev)  			x25_disconnect(s, ENETUNREACH, 0, 0); @@ -226,33 +226,33 @@ static void x25_kill_by_device(struct net_device *dev)  static int x25_device_event(struct notifier_block *this, unsigned long event,  			    void *ptr)  { -	struct net_device *dev = ptr; +	struct net_device *dev = netdev_notifier_info_to_dev(ptr);  	struct x25_neigh *nb;  	if (!net_eq(dev_net(dev), &init_net))  		return NOTIFY_DONE;  	if (dev->type == ARPHRD_X25 -#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) +#if IS_ENABLED(CONFIG_LLC)  	 || dev->type == ARPHRD_ETHER  #endif  	 ) {  		switch (event) { -			case NETDEV_UP: -				x25_link_device_up(dev); -				break; -			case NETDEV_GOING_DOWN: -				nb = x25_get_neigh(dev); -				if (nb) { -					x25_terminate_link(nb); -					x25_neigh_put(nb); -				} -				break; -			case NETDEV_DOWN: -				x25_kill_by_device(dev); -				x25_route_device_down(dev); -				x25_link_device_down(dev); -				break; +		case NETDEV_UP: +			x25_link_device_up(dev); +			break; +		case NETDEV_GOING_DOWN: +			nb = x25_get_neigh(dev); +			if (nb) { +				x25_terminate_link(nb); +				x25_neigh_put(nb); +			} +			break; +		case NETDEV_DOWN: +			x25_kill_by_device(dev); +			x25_route_device_down(dev); +			x25_link_device_down(dev); +			break;  		}  	} @@ -281,12 +281,11 @@ static struct sock *x25_find_listener(struct x25_address *addr,  {  	struct sock *s;  	struct sock *next_best; -	struct hlist_node *node;  	read_lock_bh(&x25_list_lock);  	next_best = NULL; -	sk_for_each(s, node, &x25_list) +	sk_for_each(s, &x25_list)  		if ((!strcmp(addr->x25_addr,  			x25_sk(s)->source_addr.x25_addr) ||  				!strcmp(addr->x25_addr, @@ -296,7 +295,8 @@ static struct sock *x25_find_listener(struct x25_address *addr,  			 * Found a listening socket, now check the incoming  			 * call user data vs this sockets call user data  			 */ -			if(skb->len > 0 && x25_sk(s)->cudmatchlength > 0) { +			if (x25_sk(s)->cudmatchlength > 0 && +				skb->len >= x25_sk(s)->cudmatchlength) {  				if((memcmp(x25_sk(s)->calluserdata.cuddata,  					skb->data,  					x25_sk(s)->cudmatchlength)) == 0) { @@ -323,9 +323,8 @@ found:  static struct sock *__x25_find_socket(unsigned int lci, struct x25_neigh *nb)  {  	struct sock *s; -	struct hlist_node *node; -	sk_for_each(s, node, &x25_list) +	sk_for_each(s, &x25_list)  		if (x25_sk(s)->lci == lci && x25_sk(s)->neighbour == nb) {  			sock_hold(s);  			goto found; @@ -432,15 +431,6 @@ void x25_destroy_socket_from_timer(struct sock *sk)  	sock_put(sk);  } -static void x25_destroy_socket(struct sock *sk) -{ -	sock_hold(sk); -	lock_sock(sk); -	__x25_destroy_socket(sk); -	release_sock(sk); -	sock_put(sk); -} -  /*   *	Handling for system calls applied via the various interfaces to a   *	X.25 socket object. @@ -647,18 +637,19 @@ static int x25_release(struct socket *sock)  	struct sock *sk = sock->sk;  	struct x25_sock *x25; -	lock_kernel();  	if (!sk) -		goto out; +		return 0;  	x25 = x25_sk(sk); +	sock_hold(sk); +	lock_sock(sk);  	switch (x25->state) {  		case X25_STATE_0:  		case X25_STATE_2:  			x25_disconnect(sk, 0, 0, 0); -			x25_destroy_socket(sk); +			__x25_destroy_socket(sk);  			goto out;  		case X25_STATE_1: @@ -678,7 +669,8 @@ static int x25_release(struct socket *sock)  	sock_orphan(sk);  out: -	unlock_kernel(); +	release_sock(sk); +	sock_put(sk);  	return 0;  } @@ -959,14 +951,27 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,  	 *  	 *	Facilities length is mandatory in call request packets  	 */ -	if (skb->len < 1) +	if (!pskb_may_pull(skb, 1))  		goto out_clear_request;  	len = skb->data[0] + 1; -	if (skb->len < len) +	if (!pskb_may_pull(skb, len))  		goto out_clear_request;  	skb_pull(skb,len);  	/* +	 *	Ensure that the amount of call user data is valid. +	 */ +	if (skb->len > X25_MAX_CUD_LEN) +		goto out_clear_request; + +	/* +	 *	Get all the call user data so it can be used in +	 *	x25_find_listener and skb_copy_from_linear_data up ahead. +	 */ +	if (!pskb_may_pull(skb, skb->len)) +		goto out_clear_request; + +	/*  	 *	Find a listener for the particular address/cud pair.  	 */  	sk = x25_find_listener(&source_addr,skb); @@ -1059,7 +1064,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,  	x25_start_heartbeat(make);  	if (!sock_flag(sk, SOCK_DEAD)) -		sk->sk_data_ready(sk, skb->len); +		sk->sk_data_ready(sk);  	rc = 1;  	sock_put(sk);  out: @@ -1077,7 +1082,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,  {  	struct sock *sk = sock->sk;  	struct x25_sock *x25 = x25_sk(sk); -	struct sockaddr_x25 *usx25 = (struct sockaddr_x25 *)msg->msg_name; +	DECLARE_SOCKADDR(struct sockaddr_x25 *, usx25, msg->msg_name);  	struct sockaddr_x25 sx25;  	struct sk_buff *skb;  	unsigned char *asmptr; @@ -1085,7 +1090,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,  	size_t size;  	int qbit = 0, rc = -EINVAL; -	lock_kernel(); +	lock_sock(sk);  	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_OOB|MSG_EOR|MSG_CMSG_COMPAT))  		goto out; @@ -1148,7 +1153,9 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,  	size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN; +	release_sock(sk);  	skb = sock_alloc_send_skb(sk, size, noblock, &rc); +	lock_sock(sk);  	if (!skb)  		goto out;  	X25_SKB_CB(skb)->flags = msg->msg_flags; @@ -1172,6 +1179,9 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,  	 *	byte of the user data is the logical value of the Q Bit.  	 */  	if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) { +		if (!pskb_may_pull(skb, 1)) +			goto out_kfree_skb; +  		qbit = skb->data[0];  		skb_pull(skb, 1);  	} @@ -1231,26 +1241,10 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,  			len++;  	} -	/* -	 * lock_sock() is currently only used to serialize this x25_kick() -	 * against input-driven x25_kick() calls. It currently only blocks -	 * incoming packets for this socket and does not protect against -	 * any other socket state changes and is not called from anywhere -	 * else. As x25_kick() cannot block and as long as all socket -	 * operations are BKL-wrapped, we don't need take to care about -	 * purging the backlog queue in x25_release(). -	 * -	 * Using lock_sock() to protect all socket operations entirely -	 * (and making the whole x25 stack SMP aware) unfortunately would -	 * require major changes to {send,recv}msg and skb allocation methods. -	 * -> 2.5 ;) -	 */ -	lock_sock(sk);  	x25_kick(sk); -	release_sock(sk);  	rc = len;  out: -	unlock_kernel(); +	release_sock(sk);  	return rc;  out_kfree_skb:  	kfree_skb(skb); @@ -1264,14 +1258,21 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,  {  	struct sock *sk = sock->sk;  	struct x25_sock *x25 = x25_sk(sk); -	struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name; +	DECLARE_SOCKADDR(struct sockaddr_x25 *, sx25, msg->msg_name);  	size_t copied; -	int qbit; +	int qbit, header_len;  	struct sk_buff *skb;  	unsigned char *asmptr;  	int rc = -ENOTCONN; -	lock_kernel(); +	lock_sock(sk); + +	if (x25->neighbour == NULL) +		goto out; + +	header_len = x25->neighbour->extended ? +		X25_EXT_MIN_LEN : X25_STD_MIN_LEN; +  	/*  	 * This works for seqpacket too. The receiver has ordered the queue for  	 * us! We do one quick check first though @@ -1287,6 +1288,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,  		skb = skb_dequeue(&x25->interrupt_in_queue); +		if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) +			goto out_free_dgram; +  		skb_pull(skb, X25_STD_MIN_LEN);  		/* @@ -1300,15 +1304,19 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,  		msg->msg_flags |= MSG_OOB;  	} else {  		/* Now we can treat all alike */ +		release_sock(sk);  		skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,  					flags & MSG_DONTWAIT, &rc); +		lock_sock(sk);  		if (!skb)  			goto out; +		if (!pskb_may_pull(skb, header_len)) +			goto out_free_dgram; +  		qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT; -		skb_pull(skb, x25->neighbour->extended ? -				X25_EXT_MIN_LEN : X25_STD_MIN_LEN); +		skb_pull(skb, header_len);  		if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) {  			asmptr  = skb_push(skb, 1); @@ -1334,18 +1342,15 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,  	if (sx25) {  		sx25->sx25_family = AF_X25;  		sx25->sx25_addr   = x25->dest_addr; +		msg->msg_namelen = sizeof(*sx25);  	} -	msg->msg_namelen = sizeof(struct sockaddr_x25); - -	lock_sock(sk);  	x25_check_rbuf(sk); -	release_sock(sk);  	rc = copied;  out_free_dgram:  	skb_free_datagram(sk, skb);  out: -	unlock_kernel(); +	release_sock(sk);  	return rc;  } @@ -1358,256 +1363,254 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)  	int rc;  	switch (cmd) { -		case TIOCOUTQ: { -			int amount; +	case TIOCOUTQ: { +		int amount; -			amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); -			if (amount < 0) -				amount = 0; -			rc = put_user(amount, (unsigned int __user *)argp); -			break; -		} +		amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); +		if (amount < 0) +			amount = 0; +		rc = put_user(amount, (unsigned int __user *)argp); +		break; +	} -		case TIOCINQ: { -			struct sk_buff *skb; -			int amount = 0; -			/* -			 * These two are safe on a single CPU system as -			 * only user tasks fiddle here -			 */ -			lock_sock(sk); -			if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) -				amount = skb->len; -			release_sock(sk); -			rc = put_user(amount, (unsigned int __user *)argp); -			break; -		} +	case TIOCINQ: { +		struct sk_buff *skb; +		int amount = 0; +		/* +		 * These two are safe on a single CPU system as +		 * only user tasks fiddle here +		 */ +		lock_sock(sk); +		if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) +			amount = skb->len; +		release_sock(sk); +		rc = put_user(amount, (unsigned int __user *)argp); +		break; +	} -		case SIOCGSTAMP: -			rc = -EINVAL; -			if (sk) -				rc = sock_get_timestamp(sk, +	case SIOCGSTAMP: +		rc = -EINVAL; +		if (sk) +			rc = sock_get_timestamp(sk,  						(struct timeval __user *)argp); +		break; +	case SIOCGSTAMPNS: +		rc = -EINVAL; +		if (sk) +			rc = sock_get_timestampns(sk, +					(struct timespec __user *)argp); +		break; +	case SIOCGIFADDR: +	case SIOCSIFADDR: +	case SIOCGIFDSTADDR: +	case SIOCSIFDSTADDR: +	case SIOCGIFBRDADDR: +	case SIOCSIFBRDADDR: +	case SIOCGIFNETMASK: +	case SIOCSIFNETMASK: +	case SIOCGIFMETRIC: +	case SIOCSIFMETRIC: +		rc = -EINVAL; +		break; +	case SIOCADDRT: +	case SIOCDELRT: +		rc = -EPERM; +		if (!capable(CAP_NET_ADMIN))  			break; -		case SIOCGSTAMPNS: -			rc = -EINVAL; -			if (sk) -				rc = sock_get_timestampns(sk, -						(struct timespec __user *)argp); -			break; -		case SIOCGIFADDR: -		case SIOCSIFADDR: -		case SIOCGIFDSTADDR: -		case SIOCSIFDSTADDR: -		case SIOCGIFBRDADDR: -		case SIOCSIFBRDADDR: -		case SIOCGIFNETMASK: -		case SIOCSIFNETMASK: -		case SIOCGIFMETRIC: -		case SIOCSIFMETRIC: -			rc = -EINVAL; -			break; -		case SIOCADDRT: -		case SIOCDELRT: -			rc = -EPERM; -			if (!capable(CAP_NET_ADMIN)) -				break; -			rc = x25_route_ioctl(cmd, argp); -			break; -		case SIOCX25GSUBSCRIP: -			rc = x25_subscr_ioctl(cmd, argp); -			break; -		case SIOCX25SSUBSCRIP: -			rc = -EPERM; -			if (!capable(CAP_NET_ADMIN)) -				break; -			rc = x25_subscr_ioctl(cmd, argp); -			break; -		case SIOCX25GFACILITIES: { -			lock_sock(sk); -			rc = copy_to_user(argp, &x25->facilities, -						sizeof(x25->facilities)) -						? -EFAULT : 0; -			release_sock(sk); +		rc = x25_route_ioctl(cmd, argp); +		break; +	case SIOCX25GSUBSCRIP: +		rc = x25_subscr_ioctl(cmd, argp); +		break; +	case SIOCX25SSUBSCRIP: +		rc = -EPERM; +		if (!capable(CAP_NET_ADMIN))  			break; -		} +		rc = x25_subscr_ioctl(cmd, argp); +		break; +	case SIOCX25GFACILITIES: { +		lock_sock(sk); +		rc = copy_to_user(argp, &x25->facilities, +				  sizeof(x25->facilities)) +			? -EFAULT : 0; +		release_sock(sk); +		break; +	} -		case SIOCX25SFACILITIES: { -			struct x25_facilities facilities; -			rc = -EFAULT; -			if (copy_from_user(&facilities, argp, -					   sizeof(facilities))) -				break; -			rc = -EINVAL; -			lock_sock(sk); -			if (sk->sk_state != TCP_LISTEN && -			    sk->sk_state != TCP_CLOSE) -				goto out_fac_release; -			if (facilities.pacsize_in < X25_PS16 || -			    facilities.pacsize_in > X25_PS4096) -				goto out_fac_release; -			if (facilities.pacsize_out < X25_PS16 || -			    facilities.pacsize_out > X25_PS4096) -				goto out_fac_release; -			if (facilities.winsize_in < 1 || -			    facilities.winsize_in > 127) +	case SIOCX25SFACILITIES: { +		struct x25_facilities facilities; +		rc = -EFAULT; +		if (copy_from_user(&facilities, argp, sizeof(facilities))) +			break; +		rc = -EINVAL; +		lock_sock(sk); +		if (sk->sk_state != TCP_LISTEN && +		    sk->sk_state != TCP_CLOSE) +			goto out_fac_release; +		if (facilities.pacsize_in < X25_PS16 || +		    facilities.pacsize_in > X25_PS4096) +			goto out_fac_release; +		if (facilities.pacsize_out < X25_PS16 || +		    facilities.pacsize_out > X25_PS4096) +			goto out_fac_release; +		if (facilities.winsize_in < 1 || +		    facilities.winsize_in > 127) +			goto out_fac_release; +		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)  				goto out_fac_release; -			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) -					goto out_fac_release; -				if (!in) -					facilities.throughput |= -						X25_DEFAULT_THROUGHPUT; -				else if (in < 0x03 || in > 0x0D) -					goto out_fac_release; -			} -			if (facilities.reverse && -				(facilities.reverse & 0x81) != 0x81) +			if (!in) +				facilities.throughput |= +					X25_DEFAULT_THROUGHPUT; +			else if (in < 0x03 || in > 0x0D)  				goto out_fac_release; -			x25->facilities = facilities; -			rc = 0; -out_fac_release: -			release_sock(sk); -			break; -		} - -		case SIOCX25GDTEFACILITIES: { -			lock_sock(sk); -			rc = copy_to_user(argp, &x25->dte_facilities, -						sizeof(x25->dte_facilities)); -			release_sock(sk); -			if (rc) -				rc = -EFAULT; -			break;  		} +		if (facilities.reverse && +		    (facilities.reverse & 0x81) != 0x81) +			goto out_fac_release; +		x25->facilities = facilities; +		rc = 0; +out_fac_release: +		release_sock(sk); +		break; +	} -		case SIOCX25SDTEFACILITIES: { -			struct x25_dte_facilities dtefacs; +	case SIOCX25GDTEFACILITIES: { +		lock_sock(sk); +		rc = copy_to_user(argp, &x25->dte_facilities, +				  sizeof(x25->dte_facilities)); +		release_sock(sk); +		if (rc)  			rc = -EFAULT; -			if (copy_from_user(&dtefacs, argp, sizeof(dtefacs))) -				break; -			rc = -EINVAL; -			lock_sock(sk); -			if (sk->sk_state != TCP_LISTEN && -					sk->sk_state != TCP_CLOSE) -				goto out_dtefac_release; -			if (dtefacs.calling_len > X25_MAX_AE_LEN) -				goto out_dtefac_release; -			if (dtefacs.calling_ae == NULL) -				goto out_dtefac_release; -			if (dtefacs.called_len > X25_MAX_AE_LEN) -				goto out_dtefac_release; -			if (dtefacs.called_ae == NULL) -				goto out_dtefac_release; -			x25->dte_facilities = dtefacs; -			rc = 0; -out_dtefac_release: -			release_sock(sk); -			break; -		} +		break; +	} -		case SIOCX25GCALLUSERDATA: { -			lock_sock(sk); -			rc = copy_to_user(argp, &x25->calluserdata, -					sizeof(x25->calluserdata)) -					? -EFAULT : 0; -			release_sock(sk); +	case SIOCX25SDTEFACILITIES: { +		struct x25_dte_facilities dtefacs; +		rc = -EFAULT; +		if (copy_from_user(&dtefacs, argp, sizeof(dtefacs)))  			break; -		} +		rc = -EINVAL; +		lock_sock(sk); +		if (sk->sk_state != TCP_LISTEN && +		    sk->sk_state != TCP_CLOSE) +			goto out_dtefac_release; +		if (dtefacs.calling_len > X25_MAX_AE_LEN) +			goto out_dtefac_release; +		if (dtefacs.calling_ae == NULL) +			goto out_dtefac_release; +		if (dtefacs.called_len > X25_MAX_AE_LEN) +			goto out_dtefac_release; +		if (dtefacs.called_ae == NULL) +			goto out_dtefac_release; +		x25->dte_facilities = dtefacs; +		rc = 0; +out_dtefac_release: +		release_sock(sk); +		break; +	} -		case SIOCX25SCALLUSERDATA: { -			struct x25_calluserdata calluserdata; +	case SIOCX25GCALLUSERDATA: { +		lock_sock(sk); +		rc = copy_to_user(argp, &x25->calluserdata, +				  sizeof(x25->calluserdata)) +			? -EFAULT : 0; +		release_sock(sk); +		break; +	} -			rc = -EFAULT; -			if (copy_from_user(&calluserdata, argp, -					   sizeof(calluserdata))) -				break; -			rc = -EINVAL; -			if (calluserdata.cudlength > X25_MAX_CUD_LEN) -				break; -			lock_sock(sk); -			x25->calluserdata = calluserdata; -			release_sock(sk); -			rc = 0; -			break; -		} +	case SIOCX25SCALLUSERDATA: { +		struct x25_calluserdata calluserdata; -		case SIOCX25GCAUSEDIAG: { -			lock_sock(sk); -			rc = copy_to_user(argp, &x25->causediag, -					sizeof(x25->causediag)) -					? -EFAULT : 0; -			release_sock(sk); +		rc = -EFAULT; +		if (copy_from_user(&calluserdata, argp, sizeof(calluserdata)))  			break; -		} +		rc = -EINVAL; +		if (calluserdata.cudlength > X25_MAX_CUD_LEN) +			break; +		lock_sock(sk); +		x25->calluserdata = calluserdata; +		release_sock(sk); +		rc = 0; +		break; +	} -		case SIOCX25SCAUSEDIAG: { -			struct x25_causediag causediag; -			rc = -EFAULT; -			if (copy_from_user(&causediag, argp, sizeof(causediag))) -				break; -			lock_sock(sk); -			x25->causediag = causediag; -			release_sock(sk); -			rc = 0; +	case SIOCX25GCAUSEDIAG: { +		lock_sock(sk); +		rc = copy_to_user(argp, &x25->causediag, sizeof(x25->causediag)) +			? -EFAULT : 0; +		release_sock(sk); +		break; +	} + +	case SIOCX25SCAUSEDIAG: { +		struct x25_causediag causediag; +		rc = -EFAULT; +		if (copy_from_user(&causediag, argp, sizeof(causediag)))  			break; +		lock_sock(sk); +		x25->causediag = causediag; +		release_sock(sk); +		rc = 0; +		break; -		} +	} -		case SIOCX25SCUDMATCHLEN: { -			struct x25_subaddr sub_addr; -			rc = -EINVAL; -			lock_sock(sk); -			if(sk->sk_state != TCP_CLOSE) -				goto out_cud_release; -			rc = -EFAULT; -			if (copy_from_user(&sub_addr, argp, -					sizeof(sub_addr))) -				goto out_cud_release; -			rc = -EINVAL; -			if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN) -				goto out_cud_release; -			x25->cudmatchlength = sub_addr.cudmatchlength; -			rc = 0; +	case SIOCX25SCUDMATCHLEN: { +		struct x25_subaddr sub_addr; +		rc = -EINVAL; +		lock_sock(sk); +		if(sk->sk_state != TCP_CLOSE) +			goto out_cud_release; +		rc = -EFAULT; +		if (copy_from_user(&sub_addr, argp, +				   sizeof(sub_addr))) +			goto out_cud_release; +		rc = -EINVAL; +		if (sub_addr.cudmatchlength > X25_MAX_CUD_LEN) +			goto out_cud_release; +		x25->cudmatchlength = sub_addr.cudmatchlength; +		rc = 0;  out_cud_release: -			release_sock(sk); -			break; -		} +		release_sock(sk); +		break; +	} -		case SIOCX25CALLACCPTAPPRV: { -			rc = -EINVAL; -			lock_kernel(); -			if (sk->sk_state != TCP_CLOSE) -				break; +	case SIOCX25CALLACCPTAPPRV: { +		rc = -EINVAL; +		lock_sock(sk); +		if (sk->sk_state == TCP_CLOSE) {  			clear_bit(X25_ACCPT_APPRV_FLAG, &x25->flags); -			unlock_kernel();  			rc = 0; -			break;  		} +		release_sock(sk); +		break; +	} -		case SIOCX25SENDCALLACCPT:  { -			rc = -EINVAL; -			lock_kernel(); -			if (sk->sk_state != TCP_ESTABLISHED) -				break; -			/* must call accptapprv above */ -			if (test_bit(X25_ACCPT_APPRV_FLAG, &x25->flags)) -				break; -			x25_write_internal(sk, X25_CALL_ACCEPTED); -			x25->state = X25_STATE_3; -			unlock_kernel(); -			rc = 0; -			break; -		} +	case SIOCX25SENDCALLACCPT:  { +		rc = -EINVAL; +		lock_sock(sk); +		if (sk->sk_state != TCP_ESTABLISHED) +			goto out_sendcallaccpt_release; +		/* must call accptapprv above */ +		if (test_bit(X25_ACCPT_APPRV_FLAG, &x25->flags)) +			goto out_sendcallaccpt_release; +		x25_write_internal(sk, X25_CALL_ACCEPTED); +		x25->state = X25_STATE_3; +		rc = 0; +out_sendcallaccpt_release: +		release_sock(sk); +		break; +	} -		default: -			rc = -ENOIOCTLCMD; -			break; +	default: +		rc = -ENOIOCTLCMD; +		break;  	}  	return rc; @@ -1778,11 +1781,10 @@ static struct notifier_block x25_dev_notifier = {  void x25_kill_by_neigh(struct x25_neigh *nb)  {  	struct sock *s; -	struct hlist_node *node;  	write_lock_bh(&x25_list_lock); -	sk_for_each(s, node, &x25_list) +	sk_for_each(s, &x25_list)  		if (x25_sk(s)->neighbour == nb)  			x25_disconnect(s, ENETUNREACH, 0, 0); @@ -1809,7 +1811,7 @@ static int __init x25_init(void)  	if (rc != 0)  		goto out_sock; -	printk(KERN_INFO "X.25 for Linux Version 0.2\n"); +	pr_info("Linux Version 0.2\n");  	x25_register_sysctl();  	rc = x25_proc_init(); diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c index d2efd29f434..43239527a20 100644 --- a/net/x25/sysctl_net_x25.c +++ b/net/x25/sysctl_net_x25.c @@ -73,18 +73,12 @@ static struct ctl_table x25_table[] = {  	{ 0, },  }; -static struct ctl_path x25_path[] = { -	{ .procname = "net", }, -	{ .procname = "x25", }, -	{ } -}; -  void __init x25_register_sysctl(void)  { -	x25_table_header = register_sysctl_paths(x25_path, x25_table); +	x25_table_header = register_net_sysctl(&init_net, "net/x25", x25_table);  }  void x25_unregister_sysctl(void)  { -	unregister_sysctl_table(x25_table_header); +	unregister_net_sysctl_table(x25_table_header);  } diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c index 9005f6daeab..39231237e1c 100644 --- a/net/x25/x25_dev.c +++ b/net/x25/x25_dev.c @@ -17,6 +17,8 @@   *      2000-09-04	Henner Eisen	Prevent freeing a dangling skb.   */ +#define pr_fmt(fmt) "X25: " fmt +  #include <linux/kernel.h>  #include <linux/netdevice.h>  #include <linux/skbuff.h> @@ -32,6 +34,9 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)  	unsigned short frametype;  	unsigned int lci; +	if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) +		return 0; +  	frametype = skb->data[2];  	lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); @@ -55,7 +60,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)  		if (!sock_owned_by_user(sk)) {  			queued = x25_process_rx_frame(sk, skb);  		} else { -			queued = !sk_add_backlog(sk, skb); +			queued = !sk_add_backlog(sk, skb, sk->sk_rcvbuf);  		}  		bh_unlock_sock(sk);  		sock_put(sk); @@ -86,7 +91,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)  */  	if (frametype != X25_CLEAR_CONFIRMATION) -		printk(KERN_DEBUG "x25_receive_data(): unknown frame type %2x\n",frametype); +		pr_debug("x25_receive_data(): unknown frame type %2x\n",frametype);  	return 0;  } @@ -111,10 +116,13 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev,  	 */  	nb = x25_get_neigh(dev);  	if (!nb) { -		printk(KERN_DEBUG "X.25: unknown neighbour - %s\n", dev->name); +		pr_debug("unknown neighbour - %s\n", dev->name);  		goto drop;  	} +	if (!pskb_may_pull(skb, 1)) +		return 0; +  	switch (skb->data[0]) {  	case X25_IFACE_DATA: @@ -146,21 +154,21 @@ void x25_establish_link(struct x25_neigh *nb)  	unsigned char *ptr;  	switch (nb->dev->type) { -		case ARPHRD_X25: -			if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) { -				printk(KERN_ERR "x25_dev: out of memory\n"); -				return; -			} -			ptr  = skb_put(skb, 1); -			*ptr = X25_IFACE_CONNECT; -			break; - -#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) -		case ARPHRD_ETHER: +	case ARPHRD_X25: +		if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) { +			pr_err("x25_dev: out of memory\n");  			return; +		} +		ptr  = skb_put(skb, 1); +		*ptr = X25_IFACE_CONNECT; +		break; + +#if IS_ENABLED(CONFIG_LLC) +	case ARPHRD_ETHER: +		return;  #endif -		default: -			return; +	default: +		return;  	}  	skb->protocol = htons(ETH_P_X25); @@ -174,7 +182,7 @@ void x25_terminate_link(struct x25_neigh *nb)  	struct sk_buff *skb;  	unsigned char *ptr; -#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) +#if IS_ENABLED(CONFIG_LLC)  	if (nb->dev->type == ARPHRD_ETHER)  		return;  #endif @@ -183,7 +191,7 @@ void x25_terminate_link(struct x25_neigh *nb)  	skb = alloc_skb(1, GFP_ATOMIC);  	if (!skb) { -		printk(KERN_ERR "x25_dev: out of memory\n"); +		pr_err("x25_dev: out of memory\n");  		return;  	} @@ -202,19 +210,19 @@ void x25_send_frame(struct sk_buff *skb, struct x25_neigh *nb)  	skb_reset_network_header(skb);  	switch (nb->dev->type) { -		case ARPHRD_X25: -			dptr  = skb_push(skb, 1); -			*dptr = X25_IFACE_DATA; -			break; - -#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) -		case ARPHRD_ETHER: -			kfree_skb(skb); -			return; +	case ARPHRD_X25: +		dptr  = skb_push(skb, 1); +		*dptr = X25_IFACE_DATA; +		break; + +#if IS_ENABLED(CONFIG_LLC) +	case ARPHRD_ETHER: +		kfree_skb(skb); +		return;  #endif -		default: -			kfree_skb(skb); -			return; +	default: +		kfree_skb(skb); +		return;  	}  	skb->protocol = htons(ETH_P_X25); diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c index 55187c8f642..7ecd04c2136 100644 --- a/net/x25/x25_facilities.c +++ b/net/x25/x25_facilities.c @@ -21,20 +21,32 @@   *					on response.   */ +#define pr_fmt(fmt) "X25: " fmt +  #include <linux/kernel.h>  #include <linux/string.h>  #include <linux/skbuff.h>  #include <net/sock.h>  #include <net/x25.h> -/* - * Parse a set of facilities into the facilities structures. Unrecognised - *	facilities are written to the debug log file. +/** + * x25_parse_facilities - Parse facilities from skb into the facilities structs + * + * @skb: sk_buff to parse + * @facilities: Regular facilities, updated as facilities are found + * @dte_facs: ITU DTE facilities, updated as DTE facilities are found + * @vc_fac_mask: mask is updated with all facilities found + * + * Return codes: + *  -1 - Parsing error, caller should drop call and clean up + *   0 - Parse OK, this skb has no facilities + *  >0 - Parse OK, returns the length of the facilities header + *   */  int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,  		struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask)  { -	unsigned char *p = skb->data; +	unsigned char *p;  	unsigned int len;  	*vc_fac_mask = 0; @@ -50,19 +62,21 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,  	memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae));  	memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae)); -	if (skb->len < 1) +	if (!pskb_may_pull(skb, 1))  		return 0; -	len = *p++; +	len = skb->data[0]; -	if (len >= skb->len) +	if (!pskb_may_pull(skb, 1 + len))  		return -1; +	p = skb->data + 1; +  	while (len > 0) {  		switch (*p & X25_FAC_CLASS_MASK) {  		case X25_FAC_CLASS_A:  			if (len < 2) -				return 0; +				return -1;  			switch (*p) {  			case X25_FAC_REVERSE:  				if((p[1] & 0x81) == 0x81) { @@ -97,7 +111,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,  			case X25_MARKER:  				break;  			default: -				printk(KERN_DEBUG "X.25: unknown facility " +				pr_debug("unknown facility "  				       "%02X, value %02X\n",  				       p[0], p[1]);  				break; @@ -107,7 +121,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,  			break;  		case X25_FAC_CLASS_B:  			if (len < 3) -				return 0; +				return -1;  			switch (*p) {  			case X25_FAC_PACKET_SIZE:  				facilities->pacsize_in  = p[1]; @@ -120,7 +134,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,  				*vc_fac_mask |= X25_MASK_WINDOW_SIZE;  				break;  			default: -				printk(KERN_DEBUG "X.25: unknown facility " +				pr_debug("unknown facility "  				       "%02X, values %02X, %02X\n",  				       p[0], p[1], p[2]);  				break; @@ -130,8 +144,8 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,  			break;  		case X25_FAC_CLASS_C:  			if (len < 4) -				return 0; -			printk(KERN_DEBUG "X.25: unknown facility %02X, " +				return -1; +			pr_debug("unknown facility %02X, "  			       "values %02X, %02X, %02X\n",  			       p[0], p[1], p[2], p[3]);  			p   += 4; @@ -139,24 +153,28 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,  			break;  		case X25_FAC_CLASS_D:  			if (len < p[1] + 2) -				return 0; +				return -1;  			switch (*p) {  			case X25_FAC_CALLING_AE:  				if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1) -					return 0; +					return -1; +				if (p[2] > X25_MAX_AE_LEN) +					return -1;  				dte_facs->calling_len = p[2];  				memcpy(dte_facs->calling_ae, &p[3], p[1] - 1);  				*vc_fac_mask |= X25_MASK_CALLING_AE;  				break;  			case X25_FAC_CALLED_AE:  				if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1) -					return 0; +					return -1; +				if (p[2] > X25_MAX_AE_LEN) +					return -1;  				dte_facs->called_len = p[2];  				memcpy(dte_facs->called_ae, &p[3], p[1] - 1);  				*vc_fac_mask |= X25_MASK_CALLED_AE;  				break;  			default: -				printk(KERN_DEBUG "X.25: unknown facility %02X," +				pr_debug("unknown facility %02X,"  					"length %d\n", p[0], p[1]);  				break;  			} @@ -219,7 +237,7 @@ int x25_create_facilities(unsigned char *buffer,  	}  	if (dte_facs->calling_len && (facil_mask & X25_MASK_CALLING_AE)) { -		unsigned bytecount = (dte_facs->calling_len + 1) >> 1; +		unsigned int bytecount = (dte_facs->calling_len + 1) >> 1;  		*p++ = X25_FAC_CALLING_AE;  		*p++ = 1 + bytecount;  		*p++ = dte_facs->calling_len; @@ -228,7 +246,7 @@ int x25_create_facilities(unsigned char *buffer,  	}  	if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) { -		unsigned bytecount = (dte_facs->called_len % 2) ? +		unsigned int bytecount = (dte_facs->called_len % 2) ?  		dte_facs->called_len / 2 + 1 :  		dte_facs->called_len / 2;  		*p++ = X25_FAC_CALLED_AE; @@ -325,12 +343,12 @@ void x25_limit_facilities(struct x25_facilities *facilities,  	if (!nb->extended) {  		if (facilities->winsize_in  > 7) { -			printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n"); +			pr_debug("incoming winsize limited to 7\n");  			facilities->winsize_in = 7;  		}  		if (facilities->winsize_out > 7) {  			facilities->winsize_out = 7; -			printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n"); +			pr_debug("outgoing winsize limited to 7\n");  		}  	}  } diff --git a/net/x25/x25_forward.c b/net/x25/x25_forward.c index 25a81079396..cf561f1613e 100644 --- a/net/x25/x25_forward.c +++ b/net/x25/x25_forward.c @@ -8,6 +8,9 @@   *	History   *	03-01-2007	Added forwarding for x.25	Andrew Hendry   */ + +#define pr_fmt(fmt) "X25: " fmt +  #include <linux/if_arp.h>  #include <linux/init.h>  #include <linux/slab.h> @@ -31,7 +34,7 @@ int x25_forward_call(struct x25_address *dest_addr, struct x25_neigh *from,  		goto out_no_route;  	if ((neigh_new = x25_get_neigh(rt->dev)) == NULL) { -		/* This shouldnt happen, if it occurs somehow +		/* This shouldn't happen, if it occurs somehow  		 * do something sensible  		 */  		goto out_put_route; @@ -45,13 +48,13 @@ int x25_forward_call(struct x25_address *dest_addr, struct x25_neigh *from,  	}  	/* Remote end sending a call request on an already -	 * established LCI? It shouldnt happen, just in case.. +	 * established LCI? It shouldn't happen, just in case..  	 */  	read_lock_bh(&x25_forward_list_lock);  	list_for_each(entry, &x25_forward_list) {  		x25_frwd = list_entry(entry, struct x25_forward, node);  		if (x25_frwd->lci == lci) { -			printk(KERN_WARNING "X.25: call request for lci which is already registered!, transmitting but not registering new pair\n"); +			pr_warn("call request for lci which is already registered!, transmitting but not registering new pair\n");  			same_lci = 1;  		}  	} 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); diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c index 4c81f6abb65..fd5ffb25873 100644 --- a/net/x25/x25_link.c +++ b/net/x25/x25_link.c @@ -21,6 +21,8 @@   *	2000-09-04	Henner Eisen	  dev_hold() / dev_put() for x25_neigh.   */ +#define pr_fmt(fmt) "X25: " fmt +  #include <linux/kernel.h>  #include <linux/jiffies.h>  #include <linux/timer.h> @@ -76,30 +78,32 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb,  	int confirm;  	switch (frametype) { -		case X25_RESTART_REQUEST: -			confirm = !x25_t20timer_pending(nb); -			x25_stop_t20timer(nb); -			nb->state = X25_LINK_STATE_3; -			if (confirm) -				x25_transmit_restart_confirmation(nb); -			break; - -		case X25_RESTART_CONFIRMATION: -			x25_stop_t20timer(nb); -			nb->state = X25_LINK_STATE_3; +	case X25_RESTART_REQUEST: +		confirm = !x25_t20timer_pending(nb); +		x25_stop_t20timer(nb); +		nb->state = X25_LINK_STATE_3; +		if (confirm) +			x25_transmit_restart_confirmation(nb); +		break; + +	case X25_RESTART_CONFIRMATION: +		x25_stop_t20timer(nb); +		nb->state = X25_LINK_STATE_3; +		break; + +	case X25_DIAGNOSTIC: +		if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 4))  			break; -		case X25_DIAGNOSTIC: -			printk(KERN_WARNING "x25: diagnostic #%d - " -			       "%02X %02X %02X\n", -			       skb->data[3], skb->data[4], -			       skb->data[5], skb->data[6]); -			break; +		pr_warn("diagnostic #%d - %02X %02X %02X\n", +		       skb->data[3], skb->data[4], +		       skb->data[5], skb->data[6]); +		break; -		default: -			printk(KERN_WARNING "x25: received unknown %02X " -			       "with LCI 000\n", frametype); -			break; +	default: +		pr_warn("received unknown %02X with LCI 000\n", +		       frametype); +		break;  	}  	if (nb->state == X25_LINK_STATE_3) @@ -193,18 +197,18 @@ void x25_transmit_clear_request(struct x25_neigh *nb, unsigned int lci,  void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *nb)  {  	switch (nb->state) { -		case X25_LINK_STATE_0: -			skb_queue_tail(&nb->queue, skb); -			nb->state = X25_LINK_STATE_1; -			x25_establish_link(nb); -			break; -		case X25_LINK_STATE_1: -		case X25_LINK_STATE_2: -			skb_queue_tail(&nb->queue, skb); -			break; -		case X25_LINK_STATE_3: -			x25_send_frame(skb, nb); -			break; +	case X25_LINK_STATE_0: +		skb_queue_tail(&nb->queue, skb); +		nb->state = X25_LINK_STATE_1; +		x25_establish_link(nb); +		break; +	case X25_LINK_STATE_1: +	case X25_LINK_STATE_2: +		skb_queue_tail(&nb->queue, skb); +		break; +	case X25_LINK_STATE_3: +		x25_send_frame(skb, nb); +		break;  	}  } @@ -214,14 +218,14 @@ void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *nb)  void x25_link_established(struct x25_neigh *nb)  {  	switch (nb->state) { -		case X25_LINK_STATE_0: -			nb->state = X25_LINK_STATE_2; -			break; -		case X25_LINK_STATE_1: -			x25_transmit_restart_request(nb); -			nb->state = X25_LINK_STATE_2; -			x25_start_t20timer(nb); -			break; +	case X25_LINK_STATE_0: +		nb->state = X25_LINK_STATE_2; +		break; +	case X25_LINK_STATE_1: +		x25_transmit_restart_request(nb); +		nb->state = X25_LINK_STATE_2; +		x25_start_t20timer(nb); +		break;  	}  } @@ -396,8 +400,12 @@ void __exit x25_link_free(void)  	write_lock_bh(&x25_neigh_list_lock);  	list_for_each_safe(entry, tmp, &x25_neigh_list) { +		struct net_device *dev; +  		nb = list_entry(entry, struct x25_neigh, node); +		dev = nb->dev;  		__x25_remove_neigh(nb); +		dev_put(dev);  	}  	write_unlock_bh(&x25_neigh_list_lock);  } diff --git a/net/x25/x25_out.c b/net/x25/x25_out.c index d00649fb251..0144271d218 100644 --- a/net/x25/x25_out.c +++ b/net/x25/x25_out.c @@ -68,8 +68,11 @@ int x25_output(struct sock *sk, struct sk_buff *skb)  		frontlen = skb_headroom(skb);  		while (skb->len > 0) { -			if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, -							noblock, &err)) == NULL){ +			release_sock(sk); +			skbn = sock_alloc_send_skb(sk, frontlen + max_len, +						   noblock, &err); +			lock_sock(sk); +			if (!skbn) {  				if (err == -EWOULDBLOCK && noblock){  					kfree_skb(skb);  					return sent; diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c index 7ff37379232..0917f047f2c 100644 --- a/net/x25/x25_proc.c +++ b/net/x25/x25_proc.c @@ -20,6 +20,7 @@  #include <linux/init.h>  #include <linux/proc_fs.h>  #include <linux/seq_file.h> +#include <linux/export.h>  #include <net/net_namespace.h>  #include <net/sock.h>  #include <net/x25.h> @@ -186,7 +187,6 @@ static int x25_seq_forward_open(struct inode *inode, struct file *file)  }  static const struct file_operations x25_seq_socket_fops = { -	.owner		= THIS_MODULE,  	.open		= x25_seq_socket_open,  	.read		= seq_read,  	.llseek		= seq_lseek, @@ -194,7 +194,6 @@ static const struct file_operations x25_seq_socket_fops = {  };  static const struct file_operations x25_seq_route_fops = { -	.owner		= THIS_MODULE,  	.open		= x25_seq_route_open,  	.read		= seq_read,  	.llseek		= seq_lseek, @@ -202,55 +201,38 @@ static const struct file_operations x25_seq_route_fops = {  };  static const struct file_operations x25_seq_forward_fops = { -	.owner		= THIS_MODULE,  	.open		= x25_seq_forward_open,  	.read		= seq_read,  	.llseek		= seq_lseek,  	.release	= seq_release,  }; -static struct proc_dir_entry *x25_proc_dir; -  int __init x25_proc_init(void)  { -	struct proc_dir_entry *p; -	int rc = -ENOMEM; +	if (!proc_mkdir("x25", init_net.proc_net)) +		return -ENOMEM; -	x25_proc_dir = proc_mkdir("x25", init_net.proc_net); -	if (!x25_proc_dir) +	if (!proc_create("x25/route", S_IRUGO, init_net.proc_net, +			&x25_seq_route_fops))  		goto out; -	p = proc_create("route", S_IRUGO, x25_proc_dir, &x25_seq_route_fops); -	if (!p) -		goto out_route; - -	p = proc_create("socket", S_IRUGO, x25_proc_dir, &x25_seq_socket_fops); -	if (!p) -		goto out_socket; +	if (!proc_create("x25/socket", S_IRUGO, init_net.proc_net, +			&x25_seq_socket_fops)) +		goto out; -	p = proc_create("forward", S_IRUGO, x25_proc_dir, -			&x25_seq_forward_fops); -	if (!p) -		goto out_forward; -	rc = 0; +	if (!proc_create("x25/forward", S_IRUGO, init_net.proc_net, +			&x25_seq_forward_fops)) +		goto out; +	return 0;  out: -	return rc; -out_forward: -	remove_proc_entry("socket", x25_proc_dir); -out_socket: -	remove_proc_entry("route", x25_proc_dir); -out_route: -	remove_proc_entry("x25", init_net.proc_net); -	goto out; +	remove_proc_subtree("x25", init_net.proc_net); +	return -ENOMEM;  }  void __exit x25_proc_exit(void)  { -	remove_proc_entry("forward", x25_proc_dir); -	remove_proc_entry("route", x25_proc_dir); -	remove_proc_entry("socket", x25_proc_dir); -	remove_proc_entry("x25", init_net.proc_net); +	remove_proc_subtree("x25", init_net.proc_net);  }  #else /* CONFIG_PROC_FS */ diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c index 97d77c532d8..277c8d2448d 100644 --- a/net/x25/x25_route.c +++ b/net/x25/x25_route.c @@ -66,7 +66,7 @@ out:  /**   * __x25_remove_route - remove route from x25_route_list - * @rt - route to remove + * @rt: route to remove   *   * Remove route from x25_route_list. If it was there.   * Caller must hold x25_route_list_lock. @@ -134,7 +134,7 @@ struct net_device *x25_dev_get(char *devname)  	if (dev &&  	    (!(dev->flags & IFF_UP) || (dev->type != ARPHRD_X25 -#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) +#if IS_ENABLED(CONFIG_LLC)  					&& dev->type != ARPHRD_ETHER  #endif  					))){ 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;  | 
