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

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

diff -u --recursive --new-file v1.3.74/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
@@ -524,7 +524,123 @@
 	}
 
 	return -EINVAL;	/*NOTREACHED */
-}	
+}
+
+/*
+ * dl1bke 960311: set parameters for existing AX.25 connections,
+ *		  includes a KILL command to abort any connection.
+ *		  VERY useful for debugging ;-)
+ */
+
+static int ax25_ctl_ioctl(const unsigned int cmd, const unsigned long arg)
+{
+	struct ax25_ctl_struct ax25_ctl;
+	struct device *dev;
+	ax25_cb *ax25;
+	unsigned long flags;
+	int err;
+	
+	if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(ax25_ctl))) != 0)
+		return err;
+
+	memcpy_fromfs(&ax25_ctl, (void *) arg, sizeof(ax25_ctl));
+	
+	if ((dev = ax25rtr_get_dev(&ax25_ctl.port_addr)) == NULL)
+		return -ENODEV;
+
+	if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, dev)) == NULL)
+		return -ENOTCONN;
+
+	switch (ax25_ctl.cmd) {
+		case AX25_KILL:
+#ifdef CONFIG_NETROM
+			nr_link_failed(&ax25->dest_addr, ax25->device);
+#endif
+			ax25_clear_queues(ax25);
+			ax25_send_control(ax25, DISC, POLLON, C_COMMAND);
+				
+			ax25->state = AX25_STATE_0;
+			if (ax25->sk != NULL) {
+				ax25->sk->state = TCP_CLOSE;
+				ax25->sk->err   = ENETRESET;
+				if (!ax25->sk->dead)
+					ax25->sk->state_change(ax25->sk);
+				ax25->sk->dead  = 1;
+			}
+
+			ax25_dama_off(ax25);
+			ax25_set_timer(ax25);
+	  		break;
+	  	case AX25_WINDOW:
+	  		if (ax25->modulus == MODULUS) {
+	  			if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7) 
+	  				return -EINVAL;
+	  		} else {
+	  			if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63) 
+	  				return -EINVAL;
+	  		}
+	  		ax25->window = ax25_ctl.arg;
+	  		break;
+	  	case AX25_T1:
+  			if (ax25_ctl.arg < 1) 
+  				return -EINVAL;
+  			ax25->rtt = (ax25_ctl.arg * PR_SLOWHZ) / 2;
+  			ax25->t1 = ax25_ctl.arg * PR_SLOWHZ;
+  			save_flags(flags); cli();
+  			if (ax25->t1timer > ax25->t1)
+  				ax25->t1timer = ax25->t1;
+  			restore_flags(flags);
+  			break;
+	  	case AX25_T2:
+	  		if (ax25_ctl.arg < 1) 
+	  			return -EINVAL;
+	  		save_flags(flags); cli();
+	  		ax25->t2 = ax25_ctl.arg * PR_SLOWHZ;
+	  		if (ax25->t2timer > ax25->t2)
+	  			ax25->t2timer = ax25->t2;
+	  		restore_flags(flags);
+	  		break;
+	  	case AX25_N2:
+	  		if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31) 
+	  			return -EINVAL;
+	  		ax25->n2count = 0;
+	  		ax25->n2 = ax25_ctl.arg;
+	  		break;
+	  	case AX25_T3:
+	  		if (ax25_ctl.arg < 1) 
+	  			return -EINVAL;
+	  		save_flags(flags); cli();
+	  		ax25->t3 = ax25_ctl.arg * PR_SLOWHZ;
+	  		if (ax25->t3timer != 0)
+	  			ax25->t3timer = ax25->t3;
+	  		restore_flags(flags);
+	  		break;
+	  	case AX25_IDLE:
+	  		if (ax25_ctl.arg < 1) 
+	  			return -EINVAL;
+	  		if (ax25->idle == 0)
+	  			return 0;
+			save_flags(flags); cli();
+	  		ax25->idle = ax25_ctl.arg * PR_SLOWHZ * 60;
+	  		if (ax25->idletimer != 0)
+	  			ax25->idletimer = ax25->idle;
+	  		restore_flags(flags);
+	  		break;
+	  	case AX25_PACLEN:
+	  		if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535) 
+	  			return -EINVAL;
+
+	  		if (ax25_ctl.arg > 256) /* we probably want this */
+	  			printk("ax25_ctl_ioctl(): Warning --- huge paclen %d", (int) ax25_ctl.arg);
+	  		ax25->paclen = ax25_ctl.arg;
+	  		break;
+	  	default:
+	  		return -EINVAL;
+	  }
+	  
+	  return 0;
+}
+
 
 /*
  * Create an empty AX.25 control block.
@@ -1501,7 +1617,9 @@
 	/*
 	 *	Send the frame to the AX.25 auto-router
 	 */
+#ifdef notdef	/* dl1bke 960310 */
 	ax25_rt_rx_frame(&src, dev, &dp);
+#endif
 	
 	/*
 	 *	Ours perhaps ?
@@ -1532,16 +1650,19 @@
 
 			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! */
+				return 0;
 			}
 
+			ax25_rt_rx_frame(&src, dev, &dp);
+
 			build_ax25_addr(skb->data, &src, &dest, &dp, type, MODULUS);
 #ifdef CONFIG_FIREWALL
 			if (call_fw_firewall(PF_AX25, skb, skb->data) != FW_ACCEPT) {
 				kfree_skb(skb, FREE_READ);
 				return 0;
 			}
-#endif						
+#endif
+
 			skb->arp = 1;
 			ax25_queue_xmit(skb, dev_out, SOPRI_NORMAL);
 		} else {
@@ -1581,12 +1702,14 @@
 		switch (skb->data[1]) {
 #ifdef CONFIG_INET		
 			case AX25_P_IP:
+				ax25_rt_rx_frame(&src, dev, &dp);
 				skb_pull(skb,2);		/* drop PID/CTRL */
 				ax25_ip_mode_set(&src, dev, 'D');
 				ip_rcv(skb, dev, ptype);	/* Note ptype here is the wrong one, fix me later */
 				break;
 
 			case AX25_P_ARP:
+				ax25_rt_rx_frame(&src, dev, &dp);
 				skb_pull(skb,2);
 				arp_rcv(skb, dev, ptype);	/* Note ptype here is wrong... */
 				break;
@@ -1597,6 +1720,7 @@
 					if (sk->rmem_alloc >= sk->rcvbuf) {
 						kfree_skb(skb, FREE_READ);
 					} else {
+						ax25_rt_rx_frame(&src, dev, &dp);
 						/*
 						 *	Remove the control and PID.
 						 */
@@ -1640,6 +1764,7 @@
 		 *	free it immediately. This routine itself wakes the user context layers so we
 		 *	do no further work
 		 */
+		ax25_rt_rx_frame(&src, dev, &dp);
 		if (ax25_process_rx_frame(ax25, skb, type, dama) == 0)
 			kfree_skb(skb, FREE_READ);
 
@@ -1665,6 +1790,7 @@
 	/* b) received SABM(E) */
 	
 	if ((sk = ax25_find_listener(&dest, dev, SOCK_SEQPACKET)) != NULL) {
+		ax25_rt_rx_frame(&src, dev, &dp);
 		if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, dev)) == NULL) {
 			if (mine)
 				ax25_return_dm(dev, &src, &dest, &dp);
@@ -1688,6 +1814,8 @@
 			kfree_skb(skb, FREE_READ);
 			return 0;
 		}
+		
+		ax25_rt_rx_frame(&src, dev, &dp);
 
 		if ((ax25 = ax25_create_cb()) == NULL) {
 			ax25_return_dm(dev, &src, &dest, &dp);
@@ -1698,8 +1826,10 @@
 		ax25_fillin_cb(ax25, dev);
 		ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
 #else
-		if (mine)
+		if (mine) {
+			ax25_rt_rx_frame(&src, dev, &dp);
 			ax25_return_dm(dev, &src, &dest, &dp);
+		}
 
 		kfree_skb(skb, FREE_READ);
 		return 0;
@@ -2104,9 +2234,15 @@
 
 		case SIOCADDRT:
 		case SIOCDELRT:
+		case SIOCAX25OPTRT:
 			if (!suser())
 				return -EPERM;
 			return ax25_rt_ioctl(cmd, (void *)arg);
+			
+		case SIOCAX25CTLCON:
+			if (!suser())
+				return -EPERM;
+			return ax25_ctl_ioctl(cmd, arg);
 
 		case SIOCGIFADDR:
 		case SIOCSIFADDR:
@@ -2128,6 +2264,7 @@
 	return(0);
 }
 
+
 static int ax25_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
 {
 	ax25_cb *ax25;
@@ -2136,7 +2273,8 @@
 	int len = 0;
 	off_t pos = 0;
 	off_t begin = 0;
-  
+	int idletimer;
+
 	cli();
 
 	len += sprintf(buffer, "dest_addr src_addr  dev  st  vs  vr  va    t1     t2     t3      idle   n2  rtt wnd paclen   dama Snd-Q Rcv-Q\n");
@@ -2146,6 +2284,9 @@
 			devname = "???";
 		else
 			devname = dev->name;
+			
+		idletimer = ax25->idletimer / (PR_SLOWHZ * 60);
+		idletimer += (ax25->idletimer && ax25->idletimer < ax25->idle)? 1:0;
 
 		len += sprintf(buffer + len, "%-9s ",
 			ax2asc(&ax25->dest_addr));
@@ -2159,7 +2300,7 @@
 			ax25->t2      / PR_SLOWHZ,
 			ax25->t3timer / PR_SLOWHZ,
 			ax25->t3      / PR_SLOWHZ,
-			(ax25->idletimer / (PR_SLOWHZ*60))+1,
+			idletimer,
 			ax25->idle      / (PR_SLOWHZ*60),
 			ax25->n2count, ax25->n2,
 			ax25->rtt     / PR_SLOWHZ,
@@ -2427,10 +2568,27 @@
 
 	if (bp[16] == AX25_P_IP) {
 		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); *//* Don't unlock - it might vanish.. TCP will respond correctly to this lock holding */
-			skb_pull(skb, AX25_HEADER_LEN - 1);	/* Keep PID */
-			ax25_send_frame(skb, (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev);
+		if (mode == 'V' || mode == 'v' || (mode == ' ' && ax25_dev_get_value(dev, AX25_VALUES_IPDEFMODE) == 'V')) 
+		{
+			/*
+			 *	This is a workaround to try and keep the device locking
+			 *	straight until skb->free=0 is abolished post 1.4.
+			 *
+			 *	We clone the buffer and release the original thereby
+			 *	keeping it straight
+			 *
+			 *	Note: we report 1 back so the caller will
+			 *	not feed the frame direct to the physical device
+			 *	We don't want that to happen. (It won't be upset
+			 *	as we have pulled the frame from the queue by
+			 *	freeing it).
+			 */
+			struct sk_buff *ourskb=skb_clone(skb, GFP_ATOMIC);
+			dev_kfree_skb(skb, FREE_READ);
+			if(ourskb==NULL)
+				return 1;			
+			skb_pull(ourskb, AX25_HEADER_LEN - 1);	/* Keep PID */
+			ax25_send_frame(ourskb, (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