diff options
Diffstat (limited to 'net/x25/af_x25.c')
| -rw-r--r-- | net/x25/af_x25.c | 594 | 
1 files changed, 298 insertions, 296 deletions
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();  | 
