code: plan9front

Download patch

ref: 3e9ae26c2ea9c1b0c1bfcc0ad02c58bc65cb5294
parent: d5fc608059dee5f65ddfdf3e230bb8d458ccf43f
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Apr 6 12:17:40 EDT 2024

devip: handle interface spec correctly for writes to /net/iproute

When the interface is specified as "-",
we should find the interface based on
the gateway and source ip.

As another improvement, also allow
specifying the interface as the bound
device name (for example "/net/ether0").

--- a/sys/man/3/ip
+++ b/sys/man/3/ip
@@ -456,14 +456,21 @@
 .TP
 .BI add\  "target mask nexthop flags interface source smask"
 .TP
-.BI add\  "target mask nexthop flags tag interface source smask"
+.BI add\  "target mask nexthop flags tag interface source smask".
 Add the route to the table.  If one already exists with the
-same target and mask, replace it. The
+same target and mask, replace it. The destination
 .I interface
-can be given as either the interface number or a local
-IP address on the desired interface or as a
+can be specified as either
+the interface's /net/ipifc/n directory number,
+a local IP address on the desired interface,
+its bound device name or as
 .B "-"
-when unspecified.
+when unspecified,
+in which case the interface will be choosen
+based on the
+.I source
+and
+.IR nexthop .
 .TP
 .BI del\  "target mask"
 .TP
--- a/sys/src/9/ip/ip.h
+++ b/sys/src/9/ip/ip.h
@@ -728,6 +728,7 @@
 extern void	ipifcoput(Ipifc *ifc, Block *bp, int version, uchar *ip, Routehint *rh);
 extern int	ipforme(Fs*, uchar *addr);
 extern Ipifc*	findipifc(Fs*, uchar *local, uchar *remote, int type);
+extern Ipifc*	findipifcdev(Fs *f, char *dev);
 extern Ipifc*	findipifcstr(Fs *f, char *s);
 extern void	findlocalip(Fs*, uchar *local, uchar *remote);
 extern int	ipv4local(Ipifc *ifc, uchar *local, int prefixlen, uchar *remote);
--- a/sys/src/9/ip/ipifc.c
+++ b/sys/src/9/ip/ipifc.c
@@ -1279,7 +1279,36 @@
 	return nil;
 }
 
+/*
+ *  find the ifc bound to device name dev.
+ *  returns the rlock'd ifc, otherwise nil.
+ */
 Ipifc*
+findipifcdev(Fs *f, char *dev)
+{
+	Ipifc *ifc;
+	Conv **cp;
+
+	for(cp = f->ipifc->conv; *cp != nil; cp++){
+		ifc = (Ipifc*)(*cp)->ptcl;
+		rlock(ifc);
+		if(ifc->m != nil
+		&& ifc->m != &unboundmedium
+		&& strcmp(ifc->dev, dev) == 0)
+			return ifc;
+		runlock(ifc);
+	}
+	return nil;
+}
+
+/*
+ *  find a ifc based on:
+ *  - its /net/ipifc/X directory number
+ *  - a local ip address on that interface
+ *  - bound device name
+ *  returns the rlock'd ifc, otherwise nil.
+ */
+Ipifc*
 findipifcstr(Fs *f, char *s)
 {
 	uchar ip[IPaddrlen];
@@ -1294,13 +1323,17 @@
 		if(x < 0)
 			return nil;
 		if(x < f->ipifc->nc && (c = f->ipifc->conv[x]) != nil){
-			if(ipifcinuse(c)){
-				ifc = (Ipifc*)c->ptcl;
-				rlock(ifc);
+			ifc = (Ipifc*)c->ptcl;
+			rlock(ifc);
+			if(ifc->m == nil || ifc->m == &unboundmedium){
+				runlock(ifc);
+				ifc = nil;
 			}
 		}
 	} else if(parseip(ip, s) != -1)
 		ifc = findipifc(f, ip, ip, Runi);
+	else
+		ifc = findipifcdev(f, s);
 	return ifc;
 }
 
--- a/sys/src/9/ip/iproute.c
+++ b/sys/src/9/ip/iproute.c
@@ -1129,7 +1129,7 @@
 			error(Ebadip);
 	}
 
-	if(ifcstr != nil)
+	if(ifcstr != nil && strcmp(ifcstr, "-") != 0)
 		ifc = findipifcstr(f, ifcstr);
 	else
 		ifc = findipifc(f, src, gate, type);