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

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

diff -u --recursive --new-file v1.3.59/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
@@ -1,5 +1,5 @@
 /*
- *	AX.25 release 030
+ *	AX.25 release 031
  *
  *	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. 
@@ -68,6 +68,10 @@
  *						context, THEN make the sock dead.
  *			Alan(GW4PTS)		Cleaned up for single recvmsg methods.
  *			Alan(GW4PTS)		Fixed not clearing error on connect failure.
+ *	AX.25 031	Jonathan(G4KLX)		Added binding to any device.
+ *			Joerg(DL1BKE)		Added DAMA support, fixed (?) digipeating, fixed buffer locking
+ *						for "virtual connect" mode... Result: Probably the
+ *						"Most Buggiest Code You've Ever Seen" (TM)
  *
  *	To do:
  *		Restructure the ax25_rcv code to be cleaner/faster and
@@ -107,14 +111,13 @@
 #include <net/ip.h>
 #include <net/arp.h>
 
+/*
+ *	The null address is defined as a callsign of all spaces with an
+ *	SSID of zero.
+ */
+ax25_address null_ax25_address = {{0x40,0x40,0x40,0x40,0x40,0x40,0x00}};
 
-/**********************************************************************************************************************\
-*														       *
-*						Handlers for the socket list.					       *
-*														       *
-\**********************************************************************************************************************/
-
-static ax25_cb *volatile ax25_list = NULL;
+ax25_cb *volatile ax25_list = NULL;
 
 /*
  *	ax25 -> ascii conversion
@@ -261,7 +264,7 @@
 }
 
 /*
- *	Find a socket that wants to accept the SABM we just
+ *	Find a socket that wants to accept the SABM we have just
  *	received.
  */
 static struct sock *ax25_find_listener(ax25_address *addr, struct device *dev, int type)
@@ -422,11 +425,6 @@
 		}
 	}
 	
-	if (ax25->digipeat != NULL) {
-		kfree_s(ax25->digipeat, sizeof(ax25_digi));
-		ax25->digipeat = NULL;
-	}
-
 	if (ax25->sk != NULL) {
 		if (ax25->sk->wmem_alloc || ax25->sk->rmem_alloc) { /* Defer: outstanding buffers */
 			init_timer(&ax25->timer);
@@ -435,10 +433,19 @@
 			ax25->timer.data     = (unsigned long)ax25;
 			add_timer(&ax25->timer);
 		} else {
+			if (ax25->digipeat != NULL) {
+				kfree_s(ax25->digipeat, sizeof(ax25_digi));
+				ax25->digipeat = NULL;
+			}
+		
 			kfree_s(ax25->sk, sizeof(*ax25->sk));
 			kfree_s(ax25, sizeof(*ax25));
 		}
 	} else {
+		if (ax25->digipeat != NULL) {
+			kfree_s(ax25->digipeat, sizeof(ax25_digi));
+			ax25->digipeat = NULL;
+		}	
 		kfree_s(ax25, sizeof(*ax25));
 	}
 
@@ -530,6 +537,8 @@
 
 	init_timer(&ax25->timer);
 
+	ax25->dama_slave = 0;	/* dl1bke 951121 */
+
 	ax25->rtt     = (AX25_DEF_T1 * PR_SLOWHZ) / 2;
 	ax25->t1      = AX25_DEF_T1 * PR_SLOWHZ;
 	ax25->t2      = AX25_DEF_T2 * PR_SLOWHZ;
@@ -569,6 +578,28 @@
 }
 
 /*
+ *	Find out if we are a DAMA slave for this device and count the
+ *	number of connections.
+ *
+ *	dl1bke 951121
+ */
+ 
+int ax25_dev_is_dama_slave(struct device *dev)
+{
+	ax25_cb * ax25;
+	int count = 0;
+	
+	for (ax25=ax25_list; ax25 ; ax25 = ax25->next)
+		if ( (ax25->device == dev) && ax25->dama_slave )
+		{
+			count++;
+			break;
+		}
+		
+	return count;
+}
+
+/*
  *	Fill in a created AX.25 created control block with the default
  *	values for a particular device.
  */
@@ -582,6 +613,8 @@
 	ax25->t3  = ax25_dev_get_value(dev, AX25_VALUES_T3);
 	ax25->n2  = ax25_dev_get_value(dev, AX25_VALUES_N2);
 
+	ax25->dama_slave = 0;
+
 	ax25->modulus = ax25_dev_get_value(dev, AX25_VALUES_AXDEFMODE);
 
 	if (ax25->modulus == MODULUS) {
@@ -628,9 +661,15 @@
 			return 0;
 		}
 		memcpy(ax25->digipeat, digi, sizeof(ax25_digi));
+	} else {
+		ax25_rt_build_path(ax25, dest);
 	}
 
+	if (ax25_dev_is_dama_slave(ax25->device))	/* dl1bke 960116 */
+		dama_establish_data_link(ax25);
+	else
 	ax25_establish_data_link(ax25);
+		
 	ax25_insert_socket(ax25);
 
 	ax25->state = AX25_STATE_1;
@@ -642,12 +681,9 @@
 	return 1;			/* We had to create it */	
 }
 
-/*******************************************************************************************************************\
-*														    *
-*		Routing rules for AX.25: Basically iterate over the active interfaces 				    *
-*														    *
-\*******************************************************************************************************************/
-
+/*
+ *	Find the AX.25 device that matches the hardware address supplied.
+ */
 struct device *ax25rtr_get_dev(ax25_address *addr)
 {
 	struct device *dev;
@@ -678,19 +714,14 @@
 	return NULL;
 }
 
-/*******************************************************************************************************************\
-*													            *
-*	      Handling for system calls applied via the various interfaces to an AX25 socket object		    *
-*														    *
-\*******************************************************************************************************************/
+/*
+ *	Handling for system calls applied via the various interfaces to an
+ *	AX25 socket object
+ */
  
 static int ax25_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
-	switch(cmd)
-	{
-		default:
-			return(-EINVAL);
-	}
+	return -EINVAL;
 }
 
 static int ax25_setsockopt(struct socket *sock, int level, int optname,
@@ -1028,6 +1059,9 @@
 			kfree_s(ax25, sizeof(*ax25));
 			return NULL;
 		}
+		
+		/* dl1bke 960119: we have to copy the old digipeater list! */
+		memcpy(ax25->digipeat, osk->ax25->digipeat, sizeof(ax25_digi));
 	}
 
 	sk->ax25 = ax25;
@@ -1068,6 +1102,9 @@
 				break;
 
 			case AX25_STATE_2:
+				if (sk->ax25->dama_slave)
+					ax25_send_control(sk->ax25, DISC, POLLON, C_COMMAND);
+				else
 				ax25_send_control(sk->ax25, DM, POLLON, C_RESPONSE);
 				sk->ax25->state = AX25_STATE_0;
 				sk->state       = TCP_CLOSE;
@@ -1080,6 +1117,7 @@
 			case AX25_STATE_4:
 				ax25_clear_queues(sk->ax25);
 				sk->ax25->n2count = 0;
+				if (!sk->ax25->dama_slave)
 				ax25_send_control(sk->ax25, DISC, POLLON, C_COMMAND);
 				sk->ax25->t3timer = 0;
 				sk->ax25->t1timer = sk->ax25->t1 = ax25_calculate_t1(sk->ax25);
@@ -1127,14 +1165,6 @@
 	if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
 		return -EINVAL;
 
-#ifdef DONTDO
-	if (ax25_find_socket(&addr->fsa_ax25.sax25_call, sk->type) != NULL) {
-		if (sk->debug)
-			printk("AX25: bind failed: in use\n");
-		return -EADDRINUSE;
-	}
-#endif
-
 	call = ax25_findbyuid(current->euid);
 	if (call == NULL && ax25_uid_policy && !suser())
 		return -EPERM;
@@ -1144,18 +1174,31 @@
 	else
 		memcpy(&sk->ax25->source_addr, call, sizeof(ax25_address));
 
+	if (sk->debug)
+		printk("AX25: source address set to %s\n", ax2asc(&sk->ax25->source_addr));
+
 	if (addr_len == sizeof(struct full_sockaddr_ax25) && addr->fsa_ax25.sax25_ndigis == 1) {
-		if (!suser())
-			return -EPERM;
-		call = &addr->fsa_digipeater[0];
+		if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) == 0) {
+			dev = NULL;
+			if (sk->debug)
+				printk("AX25: bound to any device\n");
+		} else {
+			if ((dev = ax25rtr_get_dev(&addr->fsa_digipeater[0])) == NULL) {
+				if (sk->debug)
+					printk("AX25: bind failed - no device\n");
+				return -EADDRNOTAVAIL;
+			}
+			if (sk->debug)
+				printk("AX25: bound to device %s\n", dev->name);
+		}
 	} else {
-		call = &addr->fsa_ax25.sax25_call;
-	}
-
-	if ((dev = ax25rtr_get_dev(call)) == NULL) {
+		if ((dev = ax25rtr_get_dev(&addr->fsa_ax25.sax25_call)) == NULL) {
+			if (sk->debug)
+				printk("AX25: bind failed - no device\n");
+			return -EADDRNOTAVAIL;
+		}
 		if (sk->debug)
-			printk("AX25 bind failed: no device\n");
-		return -EADDRNOTAVAIL;
+			printk("AX25: bound to device %s\n", dev->name);
 	}
 
 	ax25_fillin_cb(sk->ax25, dev);
@@ -1194,6 +1237,10 @@
 
 	if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
 		return -EINVAL;
+
+	/*
+	 *	Handle digi-peaters to be used.
+	 */
 	if (addr_len == sizeof(struct full_sockaddr_ax25) && addr->sax25_ndigis != 0) {
 		int ct           = 0;
 		struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)addr;
@@ -1217,11 +1264,26 @@
 
 		sk->ax25->digipeat->lastrepeat = 0;
 	}
+	else
+	{ /* dl1bke 960117 */
+		if (sk->debug)
+			printk("building digipeater path\n");
+		ax25_rt_build_path(sk->ax25, &addr->sax25_call);
+	}
 
-	if (sk->zapped) {	/* Must bind first - autobinding in this may or may not work */
+	/*
+	 *	Must bind first - autobinding in this may or may not work. If
+	 *	the socket is already bound, check to see if the device has
+	 *	been filled in, error if it hasn't.
+	 */
+	if (sk->zapped) {
 		if ((err = ax25_rt_autobind(sk->ax25, &addr->sax25_call)) < 0)
 			return err;
-		ax25_insert_socket(sk->ax25);		/* Finish the bind */
+		ax25_fillin_cb(sk->ax25, sk->ax25->device);
+		ax25_insert_socket(sk->ax25);
+	} else {
+		if (sk->ax25->device == NULL)
+			return -EHOSTUNREACH;
 	}
 		
 	if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->ax25->source_addr, &addr->sax25_call, sk->ax25->device) != NULL)
@@ -1239,7 +1301,12 @@
 	/* Move to connecting socket, ax.25 lapb WAIT_UA.. */	
 	sock->state        = SS_CONNECTING;
 	sk->state          = TCP_SYN_SENT;
+	
+	if (ax25_dev_is_dama_slave(sk->ax25->device))
+		dama_establish_data_link(sk->ax25);
+	else
 	ax25_establish_data_link(sk->ax25);
+		
 	sk->ax25->state     = AX25_STATE_1;
 	ax25_set_timer(sk->ax25);		/* Start going SABM SABM until a UA or a give up and DM */
 	
@@ -1297,8 +1364,10 @@
 	if (sk->state != TCP_LISTEN)
 		return -EINVAL;
 		
-	/* The write queue this time is holding sockets ready to use
-	   hooked into the SABM we saved */
+	/*
+	 *	The write queue this time is holding sockets ready to use
+	 *	hooked into the SABM we saved
+	 */
 	do {
 		cli();
 		if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
@@ -1372,6 +1441,7 @@
 	ax25_address src, dest;
 	struct sock *raw;
 	int mine = 0;
+	int dama;
 
 	/*
 	 *	Process the AX.25/LAPB frame.
@@ -1392,7 +1462,7 @@
 	 *	Parse the address header.
 	 */
 	 
-	if (ax25_parse_addr(skb->data, skb->len, &src, &dest, &dp, &type) == NULL) {
+	if (ax25_parse_addr(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL) {
 		kfree_skb(skb, FREE_READ);
 		return 0;
 	}
@@ -1427,11 +1497,17 @@
 					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);
+					return 0;
+				}
 			}
 
 			if (dev == dev_out && (ax25_dev_get_value(dev, AX25_VALUES_DIGI) & AX25_DIGI_INBAND) == 0)
+			{
 				kfree_skb(skb, FREE_READ);
+				return 0;	/* Hey, Alan: look what you're doing below! You forgot this return! */
+			}
 
 			build_ax25_addr(skb->data, &src, &dest, &dp, type, MODULUS);
 #ifdef CONFIG_FIREWALL
@@ -1530,18 +1606,25 @@
 	}
 	
 	/* LAPB */
+	
+	/* AX.25 state 1-4 */
+	
 	if ((ax25 = ax25_find_cb(&dest, &src, dev)) != NULL) {
 		/*
 		 *	Process the frame. If it is queued up internally it returns one otherwise we 
 		 *	free it immediately. This routine itself wakes the user context layers so we
 		 *	do no further work
 		 */
-		if (ax25_process_rx_frame(ax25, skb, type) == 0)
+		if (ax25_process_rx_frame(ax25, skb, type, dama) == 0)
 			kfree_skb(skb, FREE_READ);
 
 		return 0;
 	}
 
+	/* AX.25 state 0 (disconnected) */
+
+	/* a) received not a SABM(E) */
+	
 	if ((*skb->data & ~PF) != SABM && (*skb->data & ~PF) != SABME) {
 		/*
 		 *	Never reply to a DM. Also ignore any connects for
@@ -1554,6 +1637,8 @@
 		return 0;
 	}
 
+	/* b) received SABM(E) */
+	
 	if ((sk = ax25_find_listener(&dest, dev, SOCK_SEQPACKET)) != NULL) {
 		if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, dev)) == NULL) {
 			if (mine)
@@ -1629,6 +1714,9 @@
 	
 	ax25_send_control(ax25, UA, POLLON, C_RESPONSE);
 
+	if (dama) ax25_dama_on(ax25);	/* bke 951121 */
+
+	ax25->dama_slave = dama;
 	ax25->t3timer = ax25->t3;
 	ax25->state   = AX25_STATE_3;
 
@@ -1743,7 +1831,9 @@
 		if (sk->type == SOCK_SEQPACKET && memcmp(&sk->ax25->dest_addr, &sax.sax25_call, sizeof(ax25_address)) != 0)
 			return -EISCONN;
 		if (usax->sax25_ndigis == 0)
+		{
 			dp = NULL;
+		}
 		else
 			dp = &dtmp;
 	} else {
@@ -1833,6 +1923,7 @@
 	int copied, length;
 	struct sk_buff *skb;
 	int er;
+	int dama;
 
 	if (sk->err) {
 		return sock_error(sk);
@@ -1873,7 +1964,7 @@
 		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);
+		ax25_parse_addr(skb->data, skb->len, NULL, &dest, &digi, NULL, &dama);
 
 		sax->sax25_family = AF_AX25;
 		/* We set this correctly, even though we may not let the
@@ -2099,7 +2190,9 @@
 	ax25_recvmsg
 };
 
-/* Called by socket.c on kernel start up */
+/*
+ *	Called by socket.c on kernel start up
+ */
 
 static struct packet_type ax25_packet_type = 
 {
@@ -2156,7 +2249,7 @@
 		ax25_cs_get_info
 	});
 
-	printk("G4KLX/GW4PTS AX.25 for Linux. Version 0.30 BETA for Linux NET3.032 (Linux 1.3.35)\n");
+	printk("G4KLX/GW4PTS AX.25 for Linux. Version 0.31 BETA for Linux NET3.032 (Linux 1.3.53)\n");
 
 #ifdef CONFIG_BPQETHER
 	proc_net_register(&(struct proc_dir_entry) {
@@ -2178,17 +2271,18 @@
 void ax25_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
 {
 	unsigned char *ptr;
+	int was_locked;
 	
 #ifdef CONFIG_FIREWALL
-
 	if(call_out_firewall(PF_AX25, skb, skb->data)!=FW_ACCEPT)
 	{
 		kfree_skb(skb, FREE_WRITE);
 		return;
-	}	
-	
+	}
 #endif	
+
 	skb->protocol = htons (ETH_P_AX25);
+
 #ifdef CONFIG_BPQETHER
 	if(dev->type == ARPHRD_ETHER)
 	{
@@ -2211,7 +2305,14 @@
 
 		dev->hard_header(skb, dev, ETH_P_BPQ, bcast_addr, NULL, 0);
 
+		/* dl1bke 960201: see below. Note that the device driver should 
+		 * 		  copy the data into its own buffers, or strange
+		 *                things will happen again.
+		 */
+
+		was_locked = skb_device_locked(skb);
 		dev_queue_xmit(skb, dev, pri);
+		if (was_locked) skb_device_unlock(skb);
 
 		return;
 	} 
@@ -2220,15 +2321,20 @@
 	ptr = skb_push(skb, 1);
 	*ptr++ = 0;			/* KISS */
 
+/* dl1bke 960201: dev_queue_xmit() will free the skb if it's not locked, so
+ *                we need an additional variable to store its status.
+ *		  sl_xmit() copies the data before returning, we can
+ *		  remove the lock savely.
+ */
+
+	was_locked = skb_device_locked(skb);
 	dev_queue_xmit(skb, dev, pri);
+	if (was_locked) skb_device_unlock(skb);
 }
 
-/*******************************************************************************************************************\
-*														    *
-*		Driver encapsulation support: Moved out of SLIP because a) it should be here 			    *
-*									b) for HDLC cards			    *
-*														    *
-\*******************************************************************************************************************/
+/*
+ *	IP over AX.25 encapsulation.
+ */
 
 /*
  *	Shove an AX.25 UI header on an IP packet and handle ARP
@@ -2274,6 +2380,7 @@
   			*buff++ = AX25_P_ARP;
   			break;
   		default:
+  			printk("wrong protocol type 0x%x2.2\n", type);
   			*buff++ = 0;
   			break;
  	}
@@ -2296,8 +2403,22 @@
 		mode = ax25_ip_mode_get((ax25_address *)(bp + 1), dev);
 		if (mode == 'V' || mode == 'v' || (mode == ' ' && ax25_dev_get_value(dev, AX25_VALUES_IPDEFMODE) == 'V')) 
 		{
-			skb_device_unlock(skb);
+/*			skb_device_unlock(skb); *//* Don't unlock - it might vanish.. TCP will respond correctly to this lock holding */
 			skb_pull(skb, AX25_HEADER_LEN - 1);	/* Keep PID */
+#ifdef HUNTING_FOR_ENCAP_BUG
+		/* dl1bke 960131: This is a weird bug: the AX.25 frame is encapsulated */
+		/* 		  twice... We'll try a work-around here and hope for   */
+		/* 		  the best.                                            */
+
+			if ( !(ax25cmp((ax25_address *) (bp + 8), (ax25_address *) (skb->data + 8)) ||
+			       ax25cmp((ax25_address *) (bp + 1), (ax25_address *) (skb->data + 1)) ) )
+			{
+				printk("ax25_rebuild_header(): encap bug...\n");
+				skb_pull(skb, AX25_HEADER_LEN);
+			} else
+				if (!*skb->data)
+					printk("ax25_rebuild_header(): probably encap bug...\n");
+#endif
 			ax25_send_frame(skb, (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev);
 			return 1;
 		}

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