patch-1.3.20 linux/net/ax25/ax25_route.c

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

diff -u --recursive --new-file v1.3.19/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c
@@ -24,6 +24,9 @@
  *					removes the heard structure.
  *	AX.25 029	Steven(GW7RRM)	Added /proc information for uid/callsign mapping.
  *			Jonathan(G4KLX)	Handling of IP mode in the routing list and /proc entry.
+ *	AX.25 030	Jonathan(G4KLX)	Added digi-peaters to routing table, and
+ *					ioctls to manipulate them. Added port
+ *					configuration.
  */
  
 #include <linux/config.h>
@@ -55,12 +58,19 @@
 	struct ax25_route *next;
 	ax25_address callsign;
 	struct device *dev;
+	ax25_digi *digipeat;
 	struct timeval stamp;
 	int n;
 	char ip_mode;
 } *ax25_route = NULL;
 
-void ax25_rt_rx_frame(ax25_address *src, struct device *dev)
+static struct ax25_dev {
+	struct ax25_dev *next;
+	struct device *dev;
+	unsigned short values[AX25_MAX_VALUES];
+} *ax25_device = NULL;
+
+void ax25_rt_rx_frame(ax25_address *src, struct device *dev, ax25_digi *digi)
 {
 	unsigned long flags;
 	extern struct timeval xtime;
@@ -72,11 +82,12 @@
 	oldest = NULL;
 
 	for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
-		if (count == 0 || ax25_rt->stamp.tv_sec < oldest->stamp.tv_sec)
+		if (count == 0 || (ax25_rt->stamp.tv_sec != 0 && ax25_rt->stamp.tv_sec < oldest->stamp.tv_sec))
 			oldest = ax25_rt;
 		
 		if (ax25cmp(&ax25_rt->callsign, src) == 0 && ax25_rt->dev == dev) {
-			ax25_rt->stamp = xtime;
+			if (ax25_rt->stamp.tv_sec != 0)
+				ax25_rt->stamp = xtime;
 			ax25_rt->n++;
 			return;			
 		}
@@ -87,6 +98,10 @@
 	if (count > AX25_ROUTE_MAX) {
 		oldest->callsign = *src;
 		oldest->dev      = dev;
+		if (oldest->digipeat != NULL) {
+			kfree_s(oldest->digipeat, sizeof(ax25_digi));
+			oldest->digipeat = NULL;
+		}
 		oldest->stamp    = xtime;
 		oldest->n        = 1;
 		oldest->ip_mode  = ' ';
@@ -98,10 +113,19 @@
 
 	ax25_rt->callsign = *src;
 	ax25_rt->dev      = dev;
+	ax25_rt->digipeat = NULL;
 	ax25_rt->stamp    = xtime;
 	ax25_rt->n        = 1;
 	ax25_rt->ip_mode  = ' ';
 
+	if (digi != NULL) {
+		if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
+			kfree_s(ax25_rt, sizeof(struct ax25_route));
+			return;
+		}
+		memcpy(ax25_rt->digipeat, digi, sizeof(ax25_digi));
+	}
+
 	save_flags(flags);
 	cli();
 
@@ -122,11 +146,15 @@
 		if (s->dev == dev) {
 			if (ax25_route == s) {
 				ax25_route = s->next;
+				if (s->digipeat != NULL)
+					kfree_s((void *)s->digipeat, sizeof(ax25_digi));
 				kfree_s((void *)s, (sizeof *s));
 			} else {
 				for (t = ax25_route; t != NULL; t = t->next) {
 					if (t->next == s) {
 						t->next = s->next;
+						if (s->digipeat != NULL)
+							kfree_s((void *)s->digipeat, sizeof(ax25_digi));
 						kfree_s((void *)s, sizeof(*s));
 						break;
 					}
@@ -136,16 +164,116 @@
 	}
 }
 
+int ax25_rt_ioctl(unsigned int cmd, void *arg)
+{
+	unsigned long flags;
+	struct ax25_route *s, *t, *ax25_rt;
+	struct ax25_routes_struct route;
+	struct device *dev;
+	int i, err;
+
+	switch (cmd) {
+		case SIOCADDRT:
+			if ((err = verify_area(VERIFY_READ, arg, sizeof(route))) != 0)
+				return err;		
+			memcpy_fromfs(&route, arg, sizeof(route));
+			if ((dev = ax25rtr_get_dev(&route.port_addr)) == NULL)
+				return -EINVAL;
+			if (route.digi_count > 6)
+				return -EINVAL;
+			for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
+				if (ax25cmp(&ax25_rt->callsign, &route.dest_addr) == 0 && ax25_rt->dev == dev) {
+					if (ax25_rt->digipeat != NULL) {
+						kfree_s(ax25_rt->digipeat, sizeof(ax25_digi));
+						ax25_rt->digipeat = NULL;
+					}
+					if (route.digi_count != 0) {
+						if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
+							return -ENOMEM;
+						ax25_rt->digipeat->lastrepeat = 0;
+						ax25_rt->digipeat->ndigi      = route.digi_count;
+						for (i = 0; i < route.digi_count; i++) {
+							ax25_rt->digipeat->repeated[i] = 0;
+							ax25_rt->digipeat->calls[i]    = route.digi_addr[i];
+						}
+					}
+					ax25_rt->stamp.tv_sec = 0;
+					return 0;
+				}
+			}
+			if ((ax25_rt = (struct ax25_route *)kmalloc(sizeof(struct ax25_route), GFP_ATOMIC)) == NULL)
+				return -ENOMEM;
+			ax25_rt->callsign     = route.dest_addr;
+			ax25_rt->dev          = dev;
+			ax25_rt->digipeat     = NULL;
+			ax25_rt->stamp.tv_sec = 0;
+			ax25_rt->n            = 0;
+			ax25_rt->ip_mode      = ' ';
+			if (route.digi_count != 0) {
+				if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
+					kfree_s(ax25_rt, sizeof(struct ax25_route));
+					return -ENOMEM;
+				}
+				ax25_rt->digipeat->lastrepeat = 0;
+				ax25_rt->digipeat->ndigi      = route.digi_count;
+				for (i = 0; i < route.digi_count; i++) {
+					ax25_rt->digipeat->repeated[i] = 0;
+					ax25_rt->digipeat->calls[i]    = route.digi_addr[i];
+				}
+			}
+			save_flags(flags);
+			cli();
+			ax25_rt->next = ax25_route;
+			ax25_route    = ax25_rt;
+			restore_flags(flags);
+			break;
+
+		case SIOCDELRT:
+			if ((err = verify_area(VERIFY_READ, arg, sizeof(route))) != 0)
+				return err;
+			memcpy_fromfs(&route, arg, sizeof(route));
+			if ((dev = ax25rtr_get_dev(&route.port_addr)) == NULL)
+				return -EINVAL;
+			ax25_rt = ax25_route;
+			while (ax25_rt != NULL) {
+				s       = ax25_rt;
+				ax25_rt = ax25_rt->next;
+				if (s->dev == dev && ax25cmp(&route.dest_addr, &s->callsign) == 0) {
+					if (ax25_route == s) {
+						ax25_route = s->next;
+						if (s->digipeat != NULL)
+							kfree_s((void *)s->digipeat, sizeof(ax25_digi));
+						kfree_s((void *)s, (sizeof *s));
+					} else {
+						for (t = ax25_route; t != NULL; t = t->next) {
+							if (t->next == s) {
+								t->next = s->next;
+								if (s->digipeat != NULL)
+									kfree_s((void *)s->digipeat, sizeof(ax25_digi));
+								kfree_s((void *)s, sizeof(*s));
+								break;
+							}
+						}				
+					}
+				}
+			}
+			break;
+	}
+
+	return 0;
+}
+
 int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
 {
 	struct ax25_route *ax25_rt;
 	int len     = 0;
 	off_t pos   = 0;
 	off_t begin = 0;
+	int i;
   
 	cli();
 
-	len += sprintf(buffer, "callsign  dev  count time      mode\n");
+	len += sprintf(buffer, "callsign  dev  count time      mode digipeaters\n");
 
 	for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
 		len += sprintf(buffer + len, "%-9s %-4s %5d %9d",
@@ -157,16 +285,22 @@
 		switch (ax25_rt->ip_mode) {
 			case 'V':
 			case 'v':
-				len += sprintf(buffer + len, "   vc\n");
+				len += sprintf(buffer + len, "   vc");
 				break;
 			case 'D':
 			case 'd':
-				len += sprintf(buffer + len, "   dg\n");
+				len += sprintf(buffer + len, "   dg");
 				break;
 			default:
-				len += sprintf(buffer + len, "\n");
+				len += sprintf(buffer + len, "     ");
 				break;
 		}
+
+		if (ax25_rt->digipeat != NULL)
+			for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
+				len += sprintf(buffer + len, " %s", ax2asc(&ax25_rt->digipeat->calls[i]));
+		
+		len += sprintf(buffer + len, "\n");
 				
 		pos = begin + len;
 
@@ -245,6 +379,11 @@
 				call = (ax25_address *)ax25->device->dev_addr;
 			}
 			memcpy(&ax25->source_addr, call, sizeof(ax25_address));
+			if (ax25_rt->digipeat != NULL) {
+				if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
+					return -ENOMEM;
+				memcpy(ax25->digipeat, ax25_rt->digipeat, sizeof(ax25_digi));
+			}
 			if (ax25->sk != NULL)
 				ax25->sk->zapped = 0;
 
@@ -283,6 +422,169 @@
 			return ax25_rt->ip_mode;
 
 	return ' ';
+}
+
+static struct ax25_dev *ax25_dev_get_dev(struct device *dev)
+{
+	struct ax25_dev *s;
+
+	for (s = ax25_device; s != NULL; s = s->next)
+		if (s->dev == dev)
+			return s;
+	
+	return NULL;
+}
+
+/*
+ *	Wow, a bit of data hiding. Is this C++ or what ?
+ */
+unsigned short ax25_dev_get_value(struct device *dev, int valueno)
+{
+	struct ax25_dev *ax25_dev;
+
+	if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL) {
+		printk("ax25_dev_get_flag called with invalid device\n");
+		return 1;
+	}
+
+	return ax25_dev->values[valueno];
+}
+
+/*
+ *	This is called when an interface is brought up. These are
+ *	reasonable defaults.
+ */
+void ax25_dev_device_up(struct device *dev)
+{
+	unsigned long flags;
+	struct ax25_dev *ax25_dev;
+	
+	if ((ax25_dev = (struct ax25_dev *)kmalloc(sizeof(struct ax25_dev), GFP_ATOMIC)) == NULL)
+		return;		/* No space */
+
+	ax25_dev->dev        = dev;
+
+	ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE;
+	ax25_dev->values[AX25_VALUES_AXDEFMODE] = AX25_DEF_AXDEFMODE;
+	ax25_dev->values[AX25_VALUES_NETROM]    = AX25_DEF_NETROM;
+	ax25_dev->values[AX25_VALUES_TEXT]      = AX25_DEF_TEXT;
+	ax25_dev->values[AX25_VALUES_BACKOFF]   = AX25_DEF_BACKOFF;
+	ax25_dev->values[AX25_VALUES_CONMODE]   = AX25_DEF_CONMODE;
+	ax25_dev->values[AX25_VALUES_WINDOW]    = AX25_DEF_WINDOW;
+	ax25_dev->values[AX25_VALUES_EWINDOW]   = AX25_DEF_EWINDOW;
+	ax25_dev->values[AX25_VALUES_T1]        = (AX25_DEF_T1 * PR_SLOWHZ) / 2;
+	ax25_dev->values[AX25_VALUES_T2]        = AX25_DEF_T2 * PR_SLOWHZ;
+	ax25_dev->values[AX25_VALUES_T3]        = AX25_DEF_T3 * PR_SLOWHZ;
+	ax25_dev->values[AX25_VALUES_N2]        = AX25_DEF_N2;
+
+	save_flags(flags);
+	cli();
+
+	ax25_dev->next = ax25_device;
+	ax25_device    = ax25_dev;
+
+	restore_flags(flags);
+}
+
+void ax25_dev_device_down(struct device *dev)
+{
+	struct ax25_dev *s, *t, *ax25_dev = ax25_device;
+	
+	while (ax25_dev != NULL) {
+		s        = ax25_dev;
+		ax25_dev = ax25_dev->next;
+
+		if (s->dev == dev) {
+			if (ax25_device == s) {
+				ax25_device = s->next;
+				kfree_s((void *)s, (sizeof *s));
+			} else {
+				for (t = ax25_device; t != NULL; t = t->next) {
+					if (t->next == s) {
+						t->next = s->next;
+						kfree_s((void *)s, sizeof(*s));
+						break;
+					}
+				}				
+			}
+		}
+	}
+}
+
+int ax25_dev_ioctl(unsigned int cmd, void *arg)
+{
+	struct ax25_parms_struct ax25_parms;
+	struct device *dev;
+	struct ax25_dev *ax25_dev;
+	int err;
+
+	switch (cmd) {
+		case SIOCAX25SETPARMS:
+			if (!suser())
+				return -EPERM;
+			if ((err = verify_area(VERIFY_READ, arg, sizeof(ax25_parms))) != 0)
+				return err;
+			memcpy_fromfs(&ax25_parms, arg, sizeof(ax25_parms));
+			if ((dev = ax25rtr_get_dev(&ax25_parms.port_addr)) == NULL)
+				return -EINVAL;
+			if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL)
+				return -EINVAL;
+			if (ax25_parms.values[AX25_VALUES_IPDEFMODE] != 'D' &&
+			    ax25_parms.values[AX25_VALUES_IPDEFMODE] != 'V')
+				return -EINVAL;
+			if (ax25_parms.values[AX25_VALUES_AXDEFMODE] != MODULUS &&
+			    ax25_parms.values[AX25_VALUES_AXDEFMODE] != EMODULUS)
+				return -EINVAL;
+			if (ax25_parms.values[AX25_VALUES_NETROM] != 0 &&
+			    ax25_parms.values[AX25_VALUES_NETROM] != 1)
+				return -EINVAL;
+			if (ax25_parms.values[AX25_VALUES_TEXT] != 0 &&
+			    ax25_parms.values[AX25_VALUES_TEXT] != 1)
+				return -EINVAL;
+			if (ax25_parms.values[AX25_VALUES_BACKOFF] != 'E' &&
+			    ax25_parms.values[AX25_VALUES_BACKOFF] != 'L')
+				return -EINVAL;
+			if (ax25_parms.values[AX25_VALUES_CONMODE] != 0 &&
+			    ax25_parms.values[AX25_VALUES_CONMODE] != 1)
+				return -EINVAL;
+			if (ax25_parms.values[AX25_VALUES_WINDOW] < 1 ||
+			    ax25_parms.values[AX25_VALUES_WINDOW] > 7)
+				return -EINVAL;
+			if (ax25_parms.values[AX25_VALUES_EWINDOW] < 1 ||
+			    ax25_parms.values[AX25_VALUES_EWINDOW] > 63)
+				return -EINVAL;
+			if (ax25_parms.values[AX25_VALUES_T1] < 1)
+				return -EINVAL;
+			if (ax25_parms.values[AX25_VALUES_T2] < 1)
+				return -EINVAL;
+			if (ax25_parms.values[AX25_VALUES_T3] < 1)
+				return -EINVAL;
+			if (ax25_parms.values[AX25_VALUES_N2] < 1 ||
+			    ax25_parms.values[AX25_VALUES_N2] > 31)
+				return -EINVAL;
+			memcpy(ax25_dev->values, ax25_parms.values, AX25_MAX_VALUES * sizeof(short));
+			ax25_dev->values[AX25_VALUES_T1] *= (PR_SLOWHZ / 2);
+			ax25_dev->values[AX25_VALUES_T2] *= PR_SLOWHZ;
+			ax25_dev->values[AX25_VALUES_T3] *= PR_SLOWHZ;
+			break;
+
+		case SIOCAX25GETPARMS:
+			if ((err = verify_area(VERIFY_WRITE, arg, sizeof(struct ax25_parms_struct))) != 0)
+				return err;
+			memcpy_fromfs(&ax25_parms, arg, sizeof(ax25_parms));
+			if ((dev = ax25rtr_get_dev(&ax25_parms.port_addr)) == NULL)
+				return -EINVAL;
+			if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL)
+				return -EINVAL;
+			memcpy(ax25_parms.values, ax25_dev->values, AX25_MAX_VALUES * sizeof(short));
+			ax25_parms.values[AX25_VALUES_T1] /= (PR_SLOWHZ * 2);
+			ax25_parms.values[AX25_VALUES_T2] /= PR_SLOWHZ;
+			ax25_parms.values[AX25_VALUES_T3] /= PR_SLOWHZ;
+			memcpy_tofs(arg, &ax25_parms, sizeof(ax25_parms));
+			break;
+	}
+
+	return 0;
 }
 
 #endif

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