patch-1.3.30 linux/net/ax25/af_ax25.c

Next file: linux/net/ax25/ax25_in.c
Previous file: linux/net/Changes
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.29/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
@@ -61,13 +61,16 @@
  *			Steven(GW7RRM)		Added digi-peating control ioctl.
  *						Added extended AX.25 support.
  *						Added AX.25 frame segmentation.
+ *			Darryl(G7LED)		Changed connect(), recvfrom(), sendto() sockaddr/addrlen to
+ *						fall inline with bind() and new policy.
+ *						Moved digipeating ctl to new ax25_dev structs.
+ *						Fixed ax25_release(), set TCP_CLOSE, wakeup app
+ *						context, THEN make the sock dead.
  *
  *	To do:
  *		Restructure the ax25_rcv code to be cleaner/faster and
  *		copy only when needed.
  *		Consider better arbitary protocol support.
- *		Fix non-blocking connect failure.
- *		Settable protocol id for SEQPACKET sockets
  */
  
 #include <linux/config.h>
@@ -101,9 +104,6 @@
 #include <net/ip.h>
 #include <net/arp.h>
 
-static int ax25_digi_on = 1;
-
-#define	CONFIG_AX25_XDIGI	/* Cross port (band) digi stuff */
 
 /**********************************************************************************************************************\
 *														       *
@@ -140,7 +140,10 @@
 	*s++ = n + '0';
 	*s++ = '\0';
 
-	return(buf);
+	if (*buf == '\0' || *buf == '-')
+	   return "*";
+
+	return buf;
 
 }
 
@@ -853,35 +856,50 @@
 	struct sock *sk;
 	ax25_cb *ax25;
 
-	if ((sk = (struct sock *)kmalloc(sizeof(*sk), GFP_ATOMIC)) == NULL)
-		return -ENOMEM;
-
-	if ((ax25 = ax25_create_cb()) == NULL) {
-		kfree_s(sk, sizeof(*sk));
-		return -ENOMEM;
-	}
-
-	sk->type = sock->type;
-
 	switch (sock->type) {
 		case SOCK_DGRAM:
-		case SOCK_SEQPACKET:
-			if (protocol == 0)
+			if (protocol == 0 || protocol == AF_AX25)
 				protocol = AX25_P_TEXT;
 			break;
+		case SOCK_SEQPACKET:
+			switch (protocol) {
+				case 0:
+				case AF_AX25:	/* For CLX */
+					protocol = AX25_P_TEXT;
+					break;
+				case AX25_P_SEGMENT:
+#ifdef CONFIG_INET
+				case AX25_P_ARP:
+				case AX25_P_IP:
+#endif
+#ifdef CONFIG_NETROM
+				case AX25_P_NETROM:
+#endif
+					return -ESOCKTNOSUPPORT;
+				default:
+					break;
+			}
+			break;
 		case SOCK_RAW:
 			break;
 		default:
-			kfree_s((void *)sk, sizeof(*sk));
-			kfree_s((void *)ax25, sizeof(*ax25));
 			return -ESOCKTNOSUPPORT;
 	}
 
+	if ((sk = (struct sock *)kmalloc(sizeof(*sk), GFP_ATOMIC)) == NULL)
+		return -ENOMEM;
+
+	if ((ax25 = ax25_create_cb()) == NULL) {
+		kfree_s(sk, sizeof(*sk));
+		return -ENOMEM;
+	}
+
 	skb_queue_head_init(&sk->receive_queue);
 	skb_queue_head_init(&sk->write_queue);
 	skb_queue_head_init(&sk->back_log);
 
 	sk->socket        = sock;
+	sk->type          = sock->type;
 	sk->protocol      = protocol;
 	sk->dead          = 0;
 	sk->next          = NULL;
@@ -893,6 +911,7 @@
 	sk->rmem_alloc    = 0;
 	sk->inuse         = 0;
 	sk->debug         = 0;
+	sk->destroy       = 0;
 	sk->prot          = NULL;	/* So we use default free mechanisms */
 	sk->err           = 0;
 	sk->localroute    = 0;
@@ -965,6 +984,7 @@
 	sk->rmem_alloc  = 0;
 	sk->inuse       = 0;
 	sk->ack_backlog = 0;
+	sk->destroy     = 0;
 	sk->prot        = NULL;	/* So we use default free mechanisms */
 	sk->err         = 0;
 	sk->localroute  = 0;
@@ -1025,24 +1045,27 @@
 	if (sk->type == SOCK_SEQPACKET) {
 		switch (sk->ax25->state) {
 			case AX25_STATE_0:
-				sk->dead        = 1;
+				sk->state       = TCP_CLOSE;
 				sk->state_change(sk);
+				sk->dead        = 1;
 				ax25_destroy_socket(sk->ax25);
 				break;
 
 			case AX25_STATE_1:
 				ax25_send_control(sk->ax25, DISC, POLLON, C_COMMAND);
 				sk->ax25->state = AX25_STATE_0;
-				sk->dead        = 1;
+				sk->state       = TCP_CLOSE;
 				sk->state_change(sk);
+				sk->dead        = 1;
 				ax25_destroy_socket(sk->ax25);
 				break;
 
 			case AX25_STATE_2:
 				ax25_send_control(sk->ax25, DM, POLLON, C_RESPONSE);
 				sk->ax25->state = AX25_STATE_0;
-				sk->dead        = 1;
+				sk->state       = TCP_CLOSE;
 				sk->state_change(sk);
+				sk->dead        = 1;
 				ax25_destroy_socket(sk->ax25);
 				break;			
 
@@ -1054,20 +1077,24 @@
 				sk->ax25->t3timer = 0;
 				sk->ax25->t1timer = sk->ax25->t1 = ax25_calculate_t1(sk->ax25);
 				sk->ax25->state   = AX25_STATE_2;
+				sk->state         = TCP_CLOSE;
 				sk->state_change(sk);
-				sk->dead         = 1;
+				sk->dead          = 1;
+				sk->destroy       = 1;
 				break;
 
 			default:
 				break;
 		}
 	} else {
-		sk->dead = 1;
+		sk->state       = TCP_CLOSE;
 		sk->state_change(sk);
+		sk->dead = 1;
 		ax25_destroy_socket(sk->ax25);
 	}
 
 	sock->data = NULL;	
+	sk->socket = NULL;	/* Not used, but we should do this. **/
 
 	return 0;
 }
@@ -1158,19 +1185,14 @@
 	sk->state   = TCP_CLOSE;	
 	sock->state = SS_UNCONNECTED;
 
-	if (addr_len > sizeof(*addr)) {
+	if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
+		return -EINVAL;
+	if (addr_len == sizeof(struct full_sockaddr_ax25) && addr->sax25_ndigis != 0) {
 		int ct           = 0;
-		int ndigi        = addr_len - sizeof(*addr);
-		ax25_address *ap = (ax25_address *)(((char *)addr) + sizeof(*addr));
-
-		/* Size is an exact number of digipeaters ? */
-		if (ndigi % sizeof(ax25_address))
-			return -EINVAL;
-
-		ndigi /= sizeof(ax25_address);
+		struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)addr;
 
 		/* Valid number of digipeaters ? */
-		if (ndigi < 1 || ndigi > 6)
+		if (addr->sax25_ndigis < 1 || addr->sax25_ndigis > AX25_MAX_DIGIS)
 			return -EINVAL;
 
 		if (sk->ax25->digipeat == NULL) {
@@ -1178,21 +1200,17 @@
 				return -ENOMEM;
 		}
 
-		sk->ax25->digipeat->ndigi = ndigi;
+		sk->ax25->digipeat->ndigi = addr->sax25_ndigis;
 
-		while (ct < ndigi) {
+		while (ct < addr->sax25_ndigis) {
 			sk->ax25->digipeat->repeated[ct] = 0;
-			memcpy(&sk->ax25->digipeat->calls[ct], &ap[ct], sizeof(ax25_address));
+			memcpy(&sk->ax25->digipeat->calls[ct], &fsa->fsa_digipeater[ct], sizeof(ax25_address));
 			ct++;
 		}
 
 		sk->ax25->digipeat->lastrepeat = 0;
-		addr_len -= ndigi * sizeof(ax25_address);	
 	}
 
-	if (addr_len != sizeof(struct sockaddr_ax25))
-		return -EINVAL;
-
 	if (sk->zapped) {	/* Must bind first - autobinding in this may or may not work */
 		if ((err = ax25_rt_autobind(sk->ax25, &addr->sax25_call)) < 0)
 			return err;
@@ -1201,7 +1219,7 @@
 		
 	if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->ax25->source_addr, &addr->sax25_call, sk->ax25->device) != NULL)
 		return -EBUSY;				/* Already such a connection */
-		
+
 	memcpy(&sk->ax25->dest_addr, &addr->sax25_call, sizeof(ax25_address));
 	
 	/* First the easy one */
@@ -1369,27 +1387,32 @@
 	 */
 	if (dp.lastrepeat + 1 < dp.ndigi) {		/* Not yet digipeated completely */
 		if (ax25cmp(&dp.calls[dp.lastrepeat + 1], dev_addr) == 0) {
+			struct device *dev_out = dev;
+
 			/* We are the digipeater. Mark ourselves as repeated
 			   and throw the packet back out of the same device */
 			dp.lastrepeat++;
 			dp.repeated[(int)dp.lastrepeat] = 1;
-#ifdef CONFIG_AX25_XDIGI
-			while (dp.lastrepeat + 1 < dp.ndigi) {
-				struct device *dev_scan;
-				if ((dev_scan = ax25rtr_get_dev(&dp.calls[dp.lastrepeat + 1])) == NULL)
-					break;
-				dp.lastrepeat++;
-				dp.repeated[(int)dp.lastrepeat] = 1;
-				dev = dev_scan;
+
+			if (ax25_dev_get_value(dev, AX25_VALUES_DIGI) & AX25_DIGI_XBAND) {
+				while (dp.lastrepeat + 1 < dp.ndigi) {
+					struct device *dev_scan;
+					if ((dev_scan = ax25rtr_get_dev(&dp.calls[dp.lastrepeat + 1])) == NULL)
+						break;
+					dp.lastrepeat++;
+					dp.repeated[(int)dp.lastrepeat] = 1;
+					dev_out = dev_scan;
+				}
+				if (dev != dev_out && (ax25_dev_get_value(dev_out, AX25_VALUES_DIGI) & AX25_DIGI_XBAND) == 0)
+					kfree_skb(skb, FREE_READ);
 			}
-#endif
+
+			if (dev == dev_out && (ax25_dev_get_value(dev, AX25_VALUES_DIGI) & AX25_DIGI_INBAND) == 0)
+				kfree_skb(skb, FREE_READ);
+
 			build_ax25_addr(skb->data, &src, &dest, &dp, type, MODULUS);
 			skb->arp = 1;
-			if (ax25_digi_on) {
-				ax25_queue_xmit(skb, dev, SOPRI_NORMAL);
-			} else {
-				kfree_skb(skb, FREE_READ);
-			}
+			ax25_queue_xmit(skb, dev_out, SOPRI_NORMAL);
 		} else {
 			kfree_skb(skb, FREE_READ);
 		}
@@ -1637,7 +1660,6 @@
 {
 	struct sock *sk = (struct sock *)sock->data;
 	struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;
-	unsigned char *uaddr = (unsigned char *)msg->msg_name;
 	int err;
 	struct sockaddr_ax25 sax;
 	struct sk_buff *skb;
@@ -1666,45 +1688,36 @@
 		return -ENETUNREACH;
 		
 	if (usax) {
-		int ndigi = addr_len - sizeof(sax);
-		if (addr_len < sizeof(sax))
+		if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
 			return -EINVAL;
-
-		/* Trailing digipeaters on address ?? */
-		if (addr_len > sizeof(sax)) {
-			int ct = 0;
-
-			ax25_address *ap = (ax25_address *)(((char *)uaddr) + sizeof(sax));
-			/* Size is an exact number of digipeaters ? */
-			if (ndigi % sizeof(ax25_address))
-				return -EINVAL;
-			ndigi /= sizeof(ax25_address);
+		if (usax->sax25_family != AF_AX25)
+			return -EINVAL;
+		if (addr_len == sizeof(struct full_sockaddr_ax25) && usax->sax25_ndigis != 0) {
+			int ct           = 0;
+			struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax;
 
 			/* Valid number of digipeaters ? */
-			if (ndigi < 1 || ndigi > 6)
+			if (usax->sax25_ndigis < 1 || usax->sax25_ndigis > AX25_MAX_DIGIS)
 				return -EINVAL;
 
-			/* Copy data into digipeat structure */
-			while (ct < ndigi) {
+			dtmp.ndigi      = usax->sax25_ndigis;
+
+			while (ct < usax->sax25_ndigis) {
 				dtmp.repeated[ct] = 0;
-				memcpy(&dtmp.calls[ct], &ap[ct], sizeof(ax25_address));
+				memcpy(&dtmp.calls[ct], &fsa->fsa_digipeater[ct], sizeof(ax25_address));
 				ct++;
 			}
 
 			dtmp.lastrepeat = 0;
-			dtmp.ndigi      = ndigi;
-			addr_len -= ndigi * sizeof(ax25_address);	
 		}
 
 		memcpy(&sax, usax, sizeof(sax));
 		if (sk->type == SOCK_SEQPACKET && memcmp(&sk->ax25->dest_addr, &sax.sax25_call, sizeof(ax25_address)) != 0)
 			return -EISCONN;
-		if (sax.sax25_family != AF_AX25)
-			return -EINVAL;
-		if (ndigi != 0)
-			dp = &dtmp;
-		else
+		if (usax->sax25_ndigis == 0)
 			dp = NULL;
+		else
+			dp = &dtmp;
 	} else {
 		if (sk->state != TCP_ESTABLISHED)
 			return -ENOTCONN;
@@ -1790,16 +1803,18 @@
 {
 	struct iovec iov;
 	struct msghdr msg;
-	iov.iov_base=(void *)ubuf;
-	iov.iov_len=size;
-	msg.msg_name=(void *)sa;
-	msg.msg_namelen=addr_len;
-	msg.msg_accrights=NULL;
-	msg.msg_iov=&iov;
-	msg.msg_iovlen=1;
-	return ax25_sendmsg(sock,&msg,size,noblock,flags);	
-}
 
+	iov.iov_base = (void *)ubuf;
+	iov.iov_len  = size;
+
+	msg.msg_name      = (void *)sa;
+	msg.msg_namelen   = addr_len;
+	msg.msg_accrights = NULL;
+	msg.msg_iov       = &iov;
+	msg.msg_iovlen    = 1;
+
+	return ax25_sendmsg(sock, &msg, size, noblock, flags);
+}
 
 static int ax25_send(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags)
 {
@@ -1815,7 +1830,6 @@
 {
 	struct sock *sk = (struct sock *)sock->data;
 	struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name;
-	char *addrptr = (char *)msg->msg_name;
 	int copied, length;
 	struct sk_buff *skb;
 	int er;
@@ -1855,25 +1869,36 @@
 	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	
 	if (sax) {
-		struct sockaddr_ax25 addr;
 		ax25_digi digi;
 		ax25_address dest;
-		unsigned char *dp = skb->data;
-		int ct = 0;
-		
-		ax25_parse_addr(dp, skb->len, NULL, &dest, &digi, NULL);
-		addr.sax25_family = AF_AX25;
-		memcpy(&addr.sax25_call, &dest, sizeof(ax25_address));
-		memcpy(sax,&addr, sizeof(*sax));
-		addrptr += sizeof(*sax);
-
-		while (ct < digi.ndigi) {
-			memcpy(addrptr, &digi. calls[ct], AX25_ADDR_LEN);
-			addrptr += AX25_ADDR_LEN;
-			ct++;
+
+		if (addr_len == (int *)0)
+			return -EINVAL;
+		if (*addr_len != sizeof(struct sockaddr_ax25) && *addr_len != sizeof(struct full_sockaddr_ax25))
+			return -EINVAL;
+
+		ax25_parse_addr(skb->data, skb->len, NULL, &dest, &digi, NULL);
+
+		sax->sax25_family = AF_AX25;
+		/* We set this correctly, even though we may not let the
+		   application know the digi calls further down (because it
+		   did NOT ask to know them).  This could get political... **/
+		sax->sax25_ndigis = digi.ndigi;
+		memcpy(&sax->sax25_call, &dest, sizeof(ax25_address));
+
+		*addr_len = sizeof(struct sockaddr_ax25);
+
+		if (*addr_len == sizeof(struct full_sockaddr_ax25) && sax->sax25_ndigis != 0) {
+			int ct           = 0;
+			struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)sax;
+
+			while (ct < digi.ndigi) {
+				memcpy(&fsa->fsa_digipeater[ct], &digi.calls[ct], sizeof(ax25_address));
+				ct++;
+			}
+
+			*addr_len = sizeof(struct full_sockaddr_ax25);
 		}
-		if (addr_len)
-			*addr_len = sizeof(*sax) + AX25_ADDR_LEN * digi.ndigi;
 	}
 
 	skb_free_datagram(skb);
@@ -1886,16 +1911,19 @@
 {
 	struct iovec iov;
 	struct msghdr msg;
-	iov.iov_base=ubuf;
-	iov.iov_len=size;
-	msg.msg_name=(void *)sa;
-	msg.msg_namelen=0;
+
+	iov.iov_base = ubuf;
+	iov.iov_len  = size;
+
+	msg.msg_name      = (void *)sa;
+	msg.msg_namelen   = 0;
 	if (addr_len)
 		msg.msg_namelen = *addr_len;
-	msg.msg_accrights=NULL;
-	msg.msg_iov=&iov;
-	msg.msg_iovlen=1;
-	return ax25_recvmsg(sock,&msg,size,noblock,flags,addr_len);	
+	msg.msg_accrights = NULL;
+	msg.msg_iov       = &iov;
+	msg.msg_iovlen    = 1;
+
+	return ax25_recvmsg(sock, &msg, size, noblock, flags, addr_len);
 }
 
 static int ax25_recv(struct socket *sock, void *ubuf, int size , int noblock,
@@ -1986,15 +2014,6 @@
 			if (amount > AX25_NOUID_BLOCK)
 				return -EINVAL;
 			ax25_uid_policy = amount;
-			return 0;
-
-		case SIOCAX25DIGCTL:
-			if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(int))) != 0)
-				return err;
-			if (!suser())
-				return -EPERM;
-			amount = get_fs_long((void *)arg);
-			ax25_digi_on = amount ? 1 : 0;
 			return 0;
 
 		case SIOCAX25GETPARMS:

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this