patch-2.3.99-pre1 linux/net/ax25/af_ax25.c

Next file: linux/net/econet/af_econet.c
Previous file: linux/net/atm/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.51/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
@@ -96,6 +96,10 @@
  *      AX.25 038       Matthias(DG2FEF)        Small fixes to the syscall interface to make kernel
  *                                              independent of AX25_MAX_DIGIS used by applications.
  *                      Tomi(OH2BNS)            Fixed ax25_getname().
+ *			Joerg(DL1BKE)		Starting to phase out the support for full_sockaddr_ax25
+ *						with only 6 digipeaters and sockaddr_ax25 in ax25_bind(),
+ *						ax25_connect() and ax25_sendmsg()
+ *			Joerg(DL1BKE)		Added support for SO_BINDTODEVICE
  */
 
 #include <linux/config.h>
@@ -624,6 +628,8 @@
 static int ax25_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
 {
 	struct sock *sk = sock->sk;
+	struct net_device *dev;
+	char devname[IFNAMSIZ];
 	int opt;
 
 	if (level != SOL_AX25)
@@ -702,6 +708,22 @@
 			sk->protinfo.ax25->paclen = opt;
 			return 0;
 
+		case SO_BINDTODEVICE:
+			if (optlen > IFNAMSIZ) optlen=IFNAMSIZ;
+			if (copy_from_user(devname, optval, optlen))
+				return -EFAULT;
+
+			dev = dev_get_by_name(devname);
+			if (dev == NULL) return -ENODEV;
+
+			if (sk->type == SOCK_SEQPACKET && 
+			   (sock->state != SS_UNCONNECTED || sk->state == TCP_LISTEN))
+				return -EADDRNOTAVAIL;
+		
+			sk->protinfo.ax25->ax25_dev = ax25_dev_ax25dev(dev);
+			ax25_fillin_cb(sk->protinfo.ax25, sk->protinfo.ax25->ax25_dev);
+			return 0;
+
 		default:
 			return -ENOPROTOOPT;
 	}
@@ -710,14 +732,23 @@
 static int ax25_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
 {
 	struct sock *sk = sock->sk;
+	struct ax25_dev *ax25_dev;
+	char devname[IFNAMSIZ];
+	void *valptr;
 	int val = 0;
-	int len;
+	int maxlen, length;
 
 	if (level != SOL_AX25)
 		return -ENOPROTOOPT;
 
-	if (get_user(len, optlen))
+	if (get_user(maxlen, optlen))
 		return -EFAULT;
+		
+	if (maxlen < 1)
+		return -EFAULT;
+
+	valptr = (void *) &val;
+	length = min(maxlen, sizeof(int));
 
 	switch (optname) {
 		case AX25_WINDOW:
@@ -763,17 +794,30 @@
 		case AX25_PACLEN:
 			val = sk->protinfo.ax25->paclen;
 			break;
+			
+		case SO_BINDTODEVICE:
+			ax25_dev = sk->protinfo.ax25->ax25_dev;
+
+			if (ax25_dev != NULL && ax25_dev->dev != NULL) {
+				strncpy(devname, ax25_dev->dev->name, IFNAMSIZ);
+				length = min(strlen(ax25_dev->dev->name)+1, maxlen);
+				devname[length-1] = '\0';
+			} else {
+				*devname = '\0';
+				length = 1;
+			}
+
+			valptr = (void *) devname;
+			break;
 
 		default:
 			return -ENOPROTOOPT;
 	}
 
-	len = min(len, sizeof(int));
-
-	if (put_user(len, optlen))
+	if (put_user(length, optlen))
 		return -EFAULT;
 
-	if (copy_to_user(optval, &val, len))
+	if (copy_to_user(optval, valptr, length))
 		return -EFAULT;
 
 	return 0;
@@ -997,9 +1041,9 @@
 
 /*
  *	We support a funny extension here so you can (as root) give any callsign
- *	digipeated via a local address as source. This is a hack until we add
- *	BSD 4.4 ADDIFADDR type support. It is however small and trivially backward
- *	compatible 8)
+ *	digipeated via a local address as source. This hack is obsolete now
+ *	that we've implemented support for SO_BINDTODEVICE. It is however small 
+ *	and trivially backward compatible.
  */
 static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
@@ -1011,11 +1055,16 @@
 	if (sk->zapped == 0)
 		return -EINVAL;
 
-	if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct full_sockaddr_ax25))
-		return -EINVAL;
+	if (addr_len != sizeof(struct sockaddr_ax25) && 
+	    addr_len != sizeof(struct full_sockaddr_ax25)) {
+		/* support for old structure may go away some time */
+		if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
+		    (addr_len > sizeof(struct full_sockaddr_ax25)))
+			return -EINVAL;
 
-	if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25)))
-		return -EINVAL;
+		printk(KERN_WARNING "ax25_bind(): %s uses old (6 digipeater) socket structure.\n",
+			current->comm);
+	}
 
 	if (addr->fsa_ax25.sax25_family != AF_AX25)
 		return -EINVAL;
@@ -1029,34 +1078,28 @@
 	else
 		sk->protinfo.ax25->source_addr = *call;
 
-	SOCK_DEBUG(sk, "AX25: source address set to %s\n", ax2asc(&sk->protinfo.ax25->source_addr));
+	/*
+	 * User already set interface with SO_BINDTODEVICE
+	 */
+
+	if (sk->protinfo.ax25->ax25_dev != NULL)
+		goto done;
 
 	if (addr_len > sizeof(struct sockaddr_ax25) && addr->fsa_ax25.sax25_ndigis == 1) {
-		if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) == 0) {
-			ax25_dev = NULL;
-			SOCK_DEBUG(sk, "AX25: bound to any device\n");
-		} else {
-			if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL) {
-				SOCK_DEBUG(sk, "AX25: bind failed - no device\n");
-				return -EADDRNOTAVAIL;
-			}
-			SOCK_DEBUG(sk, "AX25: bound to device %s\n", ax25_dev->dev->name);
-		}
-	} else {
-		if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) {
-			SOCK_DEBUG(sk, "AX25: bind failed - no device\n");
+		if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) != 0 &&
+		    (ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL)
+			return -EADDRNOTAVAIL;
+	}  else {
+		if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL)
 			return -EADDRNOTAVAIL;
-		}
-		SOCK_DEBUG(sk, "AX25: bound to device %s\n", ax25_dev->dev->name);
 	}
 
 	if (ax25_dev != NULL)
 		ax25_fillin_cb(sk->protinfo.ax25, ax25_dev);
 
+done:
 	ax25_insert_socket(sk->protinfo.ax25);
-
 	sk->zapped = 0;
-	SOCK_DEBUG(sk, "AX25: socket is bound\n");
 	return 0;
 }
 
@@ -1095,8 +1138,21 @@
 	/*
 	 * some sanity checks. code further down depends on this
 	 */
-	if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct full_sockaddr_ax25))
-		return -EINVAL;
+
+	if (addr_len == sizeof(struct sockaddr_ax25)) {
+		/* support for this will go away in early 2.5.x */
+		printk(KERN_WARNING "ax25_connect(): %s uses obsolete socket structure\n",
+			current->comm);
+	}
+	else if (addr_len != sizeof(struct full_sockaddr_ax25)) {
+		/* support for old structure may go away some time */
+		if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
+		    (addr_len > sizeof(struct full_sockaddr_ax25)))
+			return -EINVAL;
+
+		printk(KERN_WARNING "ax25_connect(): %s uses old (6 digipeater) socket structure.\n",
+			current->comm);
+	}
 
 	if (fsa->fsa_ax25.sax25_family != AF_AX25)
 		return -EINVAL;
@@ -1105,7 +1161,7 @@
 		kfree(sk->protinfo.ax25->digipeat);
 		sk->protinfo.ax25->digipeat = NULL;
 	}
-
+	
 	/*
 	 *	Handle digi-peaters to be used.
 	 */
@@ -1138,6 +1194,9 @@
 	 *	been filled in, error if it hasn't.
 	 */
 	if (sk->zapped) {
+		/* check if we can remove this feature. It is broken. */
+		printk(KERN_WARNING "ax25_connect(): %s uses autobind, please contact jreuter@poboxes.com\n",
+			current->comm);
 		if ((err = ax25_rt_autobind(sk->protinfo.ax25, &fsa->fsa_ax25.sax25_call)) < 0)
 			return err;
 		ax25_fillin_cb(sk->protinfo.ax25, sk->protinfo.ax25->ax25_dev);
@@ -1330,10 +1389,20 @@
 	if (usax != NULL) {
 		if (usax->sax25_family != AF_AX25)
 			return -EINVAL;
-		if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct full_sockaddr_ax25))
-			return -EINVAL;
-		if (addr_len < (usax->sax25_ndigis * AX25_ADDR_LEN + sizeof(struct sockaddr_ax25)))
-			return -EINVAL;
+
+		if (addr_len == sizeof(struct sockaddr_ax25)) {
+			printk(KERN_WARNING "ax25_sendmsg(): %s uses obsolete socket structure\n",
+				current->comm);
+		}
+		else if (addr_len != sizeof(struct full_sockaddr_ax25)) {
+			/* support for old structure may go away some time */
+			if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
+		    	    (addr_len > sizeof(struct full_sockaddr_ax25)))
+		    		return -EINVAL;
+
+			printk(KERN_WARNING "ax25_sendmsg(): %s uses old (6 digipeater) socket structure.\n",
+				current->comm);
+		}
 
 		if (addr_len > sizeof(struct sockaddr_ax25) && usax->sax25_ndigis != 0) {
 			int ct           = 0;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)