patch-2.1.44 linux/net/x25/af_x25.c

Next file: linux/net/x25/sysctl_net_x25.c
Previous file: linux/net/unix/sysctl_net_unix.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.43/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
@@ -1,5 +1,5 @@
 /*
- *	X.25 Packet Layer release 001
+ *	X.25 Packet Layer release 002
  *
  *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *	releases, misbehave and/or generally screw up. It might even work. 
@@ -14,6 +14,8 @@
  *
  *	History
  *	X.25 001	Jonathan Naylor	Started coding.
+ *	X.25 002	Jonathan Naylor	Centralised disconnect handling.
+ *					New timer architecture.
  */
 
 #include <linux/config.h>
@@ -54,8 +56,6 @@
 int sysctl_x25_clear_request_timeout   = X25_DEFAULT_T23;
 int sysctl_x25_ack_holdback_timeout    = X25_DEFAULT_T2;
 
-static unsigned int lci = 1;
-
 static struct sock *volatile x25_list = NULL;
 
 static struct proto_ops x25_proto_ops;
@@ -173,16 +173,9 @@
 {
 	struct sock *s;
 
-	for (s = x25_list; s != NULL; s = s->next) {
-		if (s->protinfo.x25->neighbour->dev == dev) {
-			s->protinfo.x25->state  = X25_STATE_0;
-			s->state                = TCP_CLOSE;
-			s->err                  = ENETUNREACH;
-			s->shutdown            |= SEND_SHUTDOWN;
-			s->state_change(s);
-			s->dead                 = 1;
-		}
-	}
+	for (s = x25_list; s != NULL; s = s->next)
+		if (s->protinfo.x25->neighbour->dev == dev)
+			x25_disconnect(s, ENETUNREACH, 0, 0);
 }
 
 /*
@@ -254,9 +247,9 @@
 }
 
 /*
- *	Find a connected X.25 socket given my LCI.
+ *	Find a connected X.25 socket given my LCI and neighbour.
  */
-struct sock *x25_find_socket(unsigned int lci)
+struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *neigh)
 {
 	struct sock *s;
 	unsigned long flags;
@@ -265,7 +258,7 @@
 	cli();
 
 	for (s = x25_list; s != NULL; s = s->next) {
-		if (s->protinfo.x25->lci == lci) {
+		if (s->protinfo.x25->lci == lci && s->protinfo.x25->neighbour == neigh) {
 			restore_flags(flags);
 			return s;
 		}
@@ -278,14 +271,13 @@
 /*
  *	Find a unique LCI for a given device.
  */
-unsigned int x25_new_lci(void)
+unsigned int x25_new_lci(struct x25_neigh *neigh)
 {
-	lci++;
-	if (lci > 4095) lci = 1;
+	unsigned int lci = 1;
 
-	while (x25_find_socket(lci) != NULL) {
+	while (x25_find_socket(lci, neigh) != NULL) {
 		lci++;
-		if (lci > 4095) lci = 1;
+		if (lci == 4096) return 0;
 	}
 
 	return lci;
@@ -318,7 +310,8 @@
 	save_flags(flags);
 	cli();
 
-	del_timer(&sk->timer);
+	x25_stop_heartbeat(sk);
+	x25_stop_timer(sk);
 
 	x25_remove_socket(sk);
 	x25_clear_queues(sk);		/* Flush the queues */
@@ -326,7 +319,7 @@
 	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
 		if (skb->sk != sk) {		/* A pending connection */
 			skb->sk->dead = 1;	/* Queue the unaccepted socket for death */
-			x25_set_timer(skb->sk);
+			x25_start_heartbeat(skb->sk);
 			skb->sk->protinfo.x25->state = X25_STATE_0;
 		}
 
@@ -469,6 +462,8 @@
 
 	sock_init_data(sock, sk);
 
+	init_timer(&x25->timer);
+
 	sock->ops    = &x25_proto_ops;
 	sk->protocol = protocol;
 	sk->mtu      = X25_DEFAULT_PACKET_SIZE;	/* X25_PS128 */
@@ -523,6 +518,8 @@
 
 	x25->qbitincl   = osk->protinfo.x25->qbitincl;
 
+	init_timer(&x25->timer);
+
 	return sk;
 }
 
@@ -545,28 +542,17 @@
 	switch (sk->protinfo.x25->state) {
 
 		case X25_STATE_0:
-			sk->state     = TCP_CLOSE;
-			sk->shutdown |= SEND_SHUTDOWN;
-			sk->state_change(sk);
-			sk->dead      = 1;
-			x25_destroy_socket(sk);
-			break;
-
 		case X25_STATE_2:
-			sk->protinfo.x25->state = X25_STATE_0;
-			sk->state               = TCP_CLOSE;
-			sk->shutdown           |= SEND_SHUTDOWN;
-			sk->state_change(sk);
-			sk->dead                = 1;
+			x25_disconnect(sk, 0, 0, 0);
 			x25_destroy_socket(sk);
-			break;			
+			break;
 
 		case X25_STATE_1:
 		case X25_STATE_3:
 		case X25_STATE_4:
 			x25_clear_queues(sk);
 			x25_write_internal(sk, X25_CLEAR_REQUEST);
-			sk->protinfo.x25->timer = sk->protinfo.x25->t23;
+			x25_start_t23timer(sk);
 			sk->protinfo.x25->state = X25_STATE_2;
 			sk->state               = TCP_CLOSE;
 			sk->shutdown           |= SEND_SHUTDOWN;
@@ -644,6 +630,9 @@
 	if ((sk->protinfo.x25->neighbour = x25_get_neigh(dev)) == NULL)
 		return -ENETUNREACH;
 
+	if ((sk->protinfo.x25->lci = x25_new_lci(sk->protinfo.x25->neighbour)) == 0)
+		return -ENETUNREACH;
+
 	if (sk->zapped)		/* Must bind first - autobinding does not work */
 		return -EINVAL;
 
@@ -651,17 +640,17 @@
 		memset(&sk->protinfo.x25->source_addr, '\0', X25_ADDR_LEN);
 
 	sk->protinfo.x25->dest_addr = addr->sx25_addr;
-	sk->protinfo.x25->lci       = x25_new_lci();
 
 	/* Move to connecting socket, start sending Connect Requests */
 	sock->state   = SS_CONNECTING;
 	sk->state     = TCP_SYN_SENT;
 
 	sk->protinfo.x25->state = X25_STATE_1;
-	sk->protinfo.x25->timer = sk->protinfo.x25->t21;
+
 	x25_write_internal(sk, X25_CALL_REQUEST);
 
-	x25_set_timer(sk);
+	x25_start_heartbeat(sk);
+	x25_start_t21timer(sk);
 
 	/* Now the loop */
 	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
@@ -850,7 +839,7 @@
 
 	skb_queue_head(&sk->receive_queue, skb);
 
-	x25_set_timer(make);
+	x25_start_heartbeat(make);
 
 	if (!sk->dead)
 		sk->data_ready(sk, skb->len);
@@ -987,8 +976,7 @@
 		x25_output(sk, skb);
 	}
 
-	if (sk->protinfo.x25->state == X25_STATE_3)
-		x25_kick(sk);
+	x25_kick(sk);
 
 	return len;
 }
@@ -1072,30 +1060,27 @@
 
 static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
-	struct x25_facilities facilities;
-	struct x25_calluserdata calluserdata;
 	struct sock *sk = sock->sk;
-	int err;
-	long amount = 0;
 
 	switch (cmd) {
-		case TIOCOUTQ:
-			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned long))) != 0)
-				return err;
+		case TIOCOUTQ: {
+			long amount;
 			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
 			if (amount < 0)
 				amount = 0;
-			put_user(amount, (unsigned long *)arg);
+			if (put_user(amount, (unsigned long *)arg))
+				return -EFAULT;
 			return 0;
+		}
 
 		case TIOCINQ: {
 			struct sk_buff *skb;
+			long amount = 0L;
 			/* These two are safe on a single CPU system as only user tasks fiddle here */
 			if ((skb = skb_peek(&sk->receive_queue)) != NULL)
-				amount = skb->len - 20;
-			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned long))) != 0)
-				return err;
-			put_user(amount, (unsigned long *)arg);
+				amount = skb->len;
+			if (put_user(amount, (unsigned long *)arg))
+				return -EFAULT;
 			return 0;
 		}
 
@@ -1103,9 +1088,8 @@
 			if (sk != NULL) {
 				if (sk->stamp.tv_sec == 0)
 					return -ENOENT;
-				if ((err = verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval))) != 0)
-					return err;
-				copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval));
+				if (copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)))
+					return -EFAULT;
 				return 0;
 			}
 			return -EINVAL;
@@ -1134,17 +1118,18 @@
 			if (!suser()) return -EPERM;
 			return x25_subscr_ioctl(cmd, (void *)arg);
 
-		case SIOCX25GFACILITIES:
-			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(facilities))) != 0)
-				return err;
+		case SIOCX25GFACILITIES: {
+			struct x25_facilities facilities;
 			facilities = sk->protinfo.x25->facilities;
-			copy_to_user((void *)arg, &facilities, sizeof(facilities));
+			if (copy_to_user((void *)arg, &facilities, sizeof(facilities)))
+				return -EFAULT;
 			return 0;
+		}
 
-		case SIOCX25SFACILITIES:
-			if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(facilities))) != 0)
-				return err;
-			copy_from_user(&facilities, (void *)arg, sizeof(facilities));
+		case SIOCX25SFACILITIES: {
+			struct x25_facilities facilities;
+			if (copy_from_user(&facilities, (void *)arg, sizeof(facilities)))
+				return -EFAULT;
 			if (sk->state != TCP_LISTEN)
 				return -EINVAL;
 			if (facilities.pacsize_in < X25_PS16 || facilities.pacsize_in > X25_PS4096)
@@ -1168,22 +1153,33 @@
 				return -EINVAL;
 			sk->protinfo.x25->facilities = facilities;
 			return 0;
+		}
 
-		case SIOCX25GCALLUSERDATA:
-			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(calluserdata))) != 0)
-				return err;
+		case SIOCX25GCALLUSERDATA: {
+			struct x25_calluserdata calluserdata;
 			calluserdata = sk->protinfo.x25->calluserdata;
-			copy_to_user((void *)arg, &calluserdata, sizeof(calluserdata));
+			if (copy_to_user((void *)arg, &calluserdata, sizeof(calluserdata)))
+				return -EFAULT;
 			return 0;
+		}
 
-		case SIOCX25SCALLUSERDATA:
-			if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(calluserdata))) != 0)
-				return err;
-			copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata));
+		case SIOCX25SCALLUSERDATA: {
+			struct x25_calluserdata calluserdata;
+			if (copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata)))
+				return -EFAULT;
 			if (calluserdata.cudlength > X25_MAX_CUD_LEN)
 				return -EINVAL;
 			sk->protinfo.x25->calluserdata = calluserdata;
 			return 0;
+		}
+
+		case SIOCX25GCAUSEDIAG: {
+			struct x25_causediag causediag;
+			causediag = sk->protinfo.x25->causediag;
+			if (copy_to_user((void *)arg, &causediag, sizeof(causediag)))
+				return -EFAULT;
+			return 0;
+		}
 
  		default:
 			return dev_ioctl(cmd, (void *)arg);
@@ -1212,18 +1208,22 @@
 		else
 			devname = s->protinfo.x25->neighbour->dev->name;
 
-		len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X  %d  %d  %d  %d %3d %3d %3d %3d %3d %5d %5d\n",
+		len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %5d %5d\n",
 			(s->protinfo.x25->dest_addr.x25_addr[0] == '\0')   ? "*" : s->protinfo.x25->dest_addr.x25_addr,
 			(s->protinfo.x25->source_addr.x25_addr[0] == '\0') ? "*" : s->protinfo.x25->source_addr.x25_addr,
-			devname,  s->protinfo.x25->lci & 0x0FFF,
+			devname, 
+			s->protinfo.x25->lci & 0x0FFF,
 			s->protinfo.x25->state,
-			s->protinfo.x25->vs, s->protinfo.x25->vr, s->protinfo.x25->va,
-			s->protinfo.x25->timer / X25_SLOWHZ,
-			s->protinfo.x25->t2    / X25_SLOWHZ,
-			s->protinfo.x25->t21   / X25_SLOWHZ,
-			s->protinfo.x25->t22   / X25_SLOWHZ,
-			s->protinfo.x25->t23   / X25_SLOWHZ,
-			atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc));
+			s->protinfo.x25->vs,
+			s->protinfo.x25->vr,
+			s->protinfo.x25->va,
+			x25_display_timer(s) / HZ,
+			s->protinfo.x25->t2  / HZ,
+			s->protinfo.x25->t21 / HZ,
+			s->protinfo.x25->t22 / HZ,
+			s->protinfo.x25->t23 / HZ,
+			atomic_read(&s->wmem_alloc),
+			atomic_read(&s->rmem_alloc));
 
 		pos = begin + len;
 
@@ -1310,7 +1310,7 @@
 
 	register_netdevice_notifier(&x25_dev_notifier);
 
-	printk(KERN_INFO "X.25 for Linux. Version 0.1 for Linux 2.1.15\n");
+	printk(KERN_INFO "X.25 for Linux. Version 0.2 for Linux 2.1.15\n");
 
 #ifdef CONFIG_SYSCTL
 	x25_register_sysctl();

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov