shithub: riscv

Download patch

ref: c45766fb054e3c82fe7be6cd5da2e6ff58e534e3
parent: d4ce962fe33f3eca8da0b4ab2b5a81cc5359b71f
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue May 16 18:16:12 EDT 2023

devip: address some ipv6 issues on pkt interface

relax the maclen check as v6 neighbour disicovery might
give bigger buffers as the medium uses for the mac
address size, as the packet does not contain exact byte
count but rounds all the options to multiples of 8.

drop neighbour discovery packets coming from interfaces
with zero-length maclen.

when dialing icmpv6 protocol with link-local address
for the local ip address, filter any packets to it that
come from a different interface. otherwise ipconfig
would see router advertisements from other interfaces.

fix the locking for ipifc ctl messages: properly
acquire the wlock and check that the interface is still
bound for every ctl messages touching the interface.

make add6 ipifc ctl message work for media with
zero-length maclen by using the interface identier
from pre-existing link-local address when available.

--- a/sys/src/9/ip/arp.c
+++ b/sys/src/9/ip/arp.c
@@ -324,7 +324,7 @@
 }
 
 int
-arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, uchar *ia, Ipifc *ifc, int refresh)
+arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int maclen, uchar *ia, Ipifc *ifc, int refresh)
 {
 	Routehint rh;
 	uchar v6ip[IPaddrlen];
@@ -333,7 +333,7 @@
 	Route *r;
 	Arp *arp;
 
-	if(ifc->m == nil || ifc->m->maclen != n || ifc->m->maclen == 0)
+	if(ifc->m == nil || maclen < ifc->m->maclen || ifc->m->maclen == 0)
 		return -1;
 
 	rh.r = nil;
@@ -597,7 +597,7 @@
 		return;
 send:
 	if(!waserror()){
-		icmpns6(f, src, SRC_UNI, targ, TARG_MULTI, ifc->mac);
+		icmpns6(f, src, SRC_UNI, targ, TARG_MULTI, ifc->mac, ifc->m->maclen);
 		poperror();
 	}
 }
--- a/sys/src/9/ip/ethermedium.c
+++ b/sys/src/9/ip/ethermedium.c
@@ -708,7 +708,7 @@
 		return;
 
 	if(!lifc->tentative){
-		icmpna6(f, lifc->local, v6allnodesL, ip, ifc->mac, 1<<5);
+		icmpna6(f, lifc->local, v6allnodesL, ip, ifc->mac, 6, 1<<5);
 		return;
 	}
 
@@ -722,7 +722,7 @@
 		remroute(f, a, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad);
 		nexterror();
 	}
-	icmpns6(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
+	icmpns6(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac, 6);
 	poperror();
 	remroute(f, a, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad);
 }
--- a/sys/src/9/ip/icmp6.c
+++ b/sys/src/9/ip/icmp6.c
@@ -118,12 +118,9 @@
 	uchar	otype;
 	uchar	olen;		/* length in units of 8 octets(incl type, code),
 				 * 1 for IEEE 802 addresses */
-	uchar	lnaddr[6];	/* link-layer address */
-	uchar	payload[];
+	uchar	lnaddr[];	/* link-layer address */
 };
 
-#define NDPKTSZ offsetof(Ndpkt, payload[0])
-
 typedef struct Icmppriv6
 {
 	ulong	stats[Nstats6];
@@ -310,7 +307,7 @@
 }
 
 static void
-goticmpkt6(Proto *icmp, Block *bp, int muxkey)
+goticmpkt6(Proto *icmp, Ipifc *ifc, Block *bp, int muxkey)
 {
 	ushort recid;
 	uchar *addr;
@@ -327,6 +324,7 @@
 	for(c = icmp->conv; (s = *c) != nil; c++){
 		if(s->lport == recid)
 		if(ipcmp(s->laddr, p->dst) == 0 || ipcmp(s->raddr, addr) == 0)
+		if(!islinklocal(s->laddr) || iplocalonifc(ifc, s->laddr) != nil)
 			qpass(s->rq, copyblock(bp, blocklen(bp)));
 	}
 	freeblist(bp);
@@ -358,14 +356,15 @@
  * 	and tuni == TARG_UNI => neighbor reachability.
  */
 void
-icmpns6(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac)
+icmpns6(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac, int maclen)
 {
 	Block *nbp;
 	Ndpkt *np;
 	Proto *icmp = f->t2p[ICMPv6];
 	Icmppriv6 *ipriv = icmp->priv;
+	int olen = (2+maclen+7)/8;
 
-	nbp = newIPICMP(NDPKTSZ);
+	nbp = newIPICMP(NDISCSZ + olen*8);
 	np = (Ndpkt*) nbp->rp;
 
 	if(suni == SRC_UNSPEC)
@@ -383,10 +382,10 @@
 	ipmove(np->target, targ);
 	if(suni != SRC_UNSPEC) {
 		np->otype = SRC_LLADDR;
-		np->olen = 1;		/* 1+1+6 = 8 = 1 8-octet */
-		memmove(np->lnaddr, mac, sizeof(np->lnaddr));
+		np->olen = olen;
+		memmove(np->lnaddr, mac, maclen);
 	} else
-		nbp->wp -= NDPKTSZ - NDISCSZ;
+		nbp->wp -= olen*8;
 
 	set_cksum(nbp);
 	ipriv->out[NbrSolicit]++;
@@ -398,14 +397,15 @@
  * sends out an ICMPv6 neighbor advertisement. pktflags == RSO flags.
  */
 void
-icmpna6(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags)
+icmpna6(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, int maclen, uchar flags)
 {
 	Block *nbp;
 	Ndpkt *np;
 	Proto *icmp = f->t2p[ICMPv6];
 	Icmppriv6 *ipriv = icmp->priv;
+	int olen = (2+maclen+7)/8;
 
-	nbp = newIPICMP(NDPKTSZ);
+	nbp = newIPICMP(NDISCSZ + olen*8);
 	np = (Ndpkt*)nbp->rp;
 
 	ipmove(np->src, src);
@@ -417,8 +417,8 @@
 	ipmove(np->target, targ);
 
 	np->otype = TARGET_LLADDR;
-	np->olen = 1;
-	memmove(np->lnaddr, mac, sizeof(np->lnaddr));
+	np->olen = olen;
+	memmove(np->lnaddr, mac, maclen);
 
 	set_cksum(nbp);
 	ipriv->out[NbrAdvert]++;
@@ -700,7 +700,7 @@
 			}
 		}
 		bp->rp -= IPICMPSZ;
-		goticmpkt6(icmp, bp, 0);
+		goticmpkt6(icmp, ifc, bp, 0);
 		break;
 
 	case TimeExceedV6:
@@ -712,7 +712,7 @@
 			snprint(msg = m2, sizeof m2, "frag time exceeded at %I", p->src);
 			goto Advise;
 		}
-		goticmpkt6(icmp, bp, 0);
+		goticmpkt6(icmp, ifc, bp, 0);
 		break;
 
 	case PacketTooBigV6:
@@ -722,10 +722,12 @@
 
 	case RouterAdvert:
 	case RouterSolicit:
-		goticmpkt6(icmp, bp, p->type);
+		goticmpkt6(icmp, ifc, bp, p->type);
 		break;
 
 	case NbrSolicit:
+		if(ifc->m->maclen == 0)
+			goto raise;
 		np = (Ndpkt*)p;
 		pktflags = 0;
 		if(ifc->sendra6)
@@ -742,7 +744,7 @@
 			} else
 				ipmove(ia, np->target);
 			icmpna6(icmp->f, ia, (pktflags & Sflag)? np->src: v6allnodesL,
-				np->target, ifc->mac, pktflags);
+				np->target, ifc->mac, ifc->m->maclen, pktflags);
 			break;
 		}
 		freeblist(bp);
@@ -749,8 +751,9 @@
 		break;
 
 	case NbrAdvert:
+		if(ifc->m->maclen == 0)
+			goto raise;
 		np = (Ndpkt*)p;
-
 		/*
 		 * if the target address matches one of the local interface
 		 * addresses and the local interface address has tentative bit
@@ -767,7 +770,7 @@
 		break;
 
 	default:
-		goticmpkt6(icmp, bp, 0);
+		goticmpkt6(icmp, ifc, bp, 0);
 		break;
 	}
 	return;
--- a/sys/src/9/ip/ip.h
+++ b/sys/src/9/ip/ip.h
@@ -667,7 +667,7 @@
 extern void	arprelease(Arp*, Arpent *a);
 extern void	arpcontinue(Arp*, Arpent *a);
 extern Block*	arpresolve(Arp*, Arpent *a, uchar *mac, Routehint *rh);
-extern int	arpenter(Fs*, int version, uchar *ip, uchar *mac, int n, uchar *ia, Ipifc *ifc, int refresh);
+extern int	arpenter(Fs*, int version, uchar *ip, uchar *mac, int maclen, uchar *ia, Ipifc *ifc, int refresh);
 extern int	arpforme(Fs*, int version, uchar *targ, uchar *src, Ipifc *ifc);
 extern void	ndpsendsol(Fs*, Arpent*);
 
--- a/sys/src/9/ip/ipifc.c
+++ b/sys/src/9/ip/ipifc.c
@@ -317,6 +317,10 @@
 	ifc->burst = burst;
 }
 
+/*
+ *  change an interface's burst delay
+ *  ifc must be bound and wlock'd
+ */
 static void
 ipifcsetdelay(Ipifc *ifc, int delay)
 {
@@ -328,6 +332,10 @@
 	ipifcadjustburst(ifc);
 }
 
+/*
+ *  change an interface's baud rate
+ *  ifc must be bound and wlock'd
+ */
 static void
 ipifcsetspeed(Ipifc *ifc, int speed)
 {
@@ -338,6 +346,20 @@
 	ipifcadjustburst(ifc);
 }
 
+/*
+ *  change an interface's mtu
+ *  ifc must be bound and wlock'd
+ */
+static char*
+ipifcsetmtu(Ipifc *ifc, int mtu)
+{
+	if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu)
+		return Ebadarg;
+	ifc->maxtu = mtu;
+	ipifcadjustburst(ifc);
+	return nil;
+}
+
 void
 ipifcoput(Ipifc *ifc, Block *bp, int version, uchar *ip, Routehint *rh)
 {
@@ -421,23 +443,6 @@
 }
 
 /*
- *  change an interface's mtu
- */
-static char*
-ipifcsetmtu(Ipifc *ifc, int mtu)
-{
-	Medium *m = ifc->m;
-
-	if(m == nil)
-		return Eunbound;
-	if(mtu < m->mintu || mtu > m->maxtu)
-		return Ebadarg;
-	ifc->maxtu = mtu;
-	ipifcadjustburst(ifc);
-	return nil;
-}
-
-/*
  *  add an address to an interface.
  */
 char*
@@ -761,7 +766,11 @@
 	return nil;
 }
 
-char*
+/*
+ *  change ipv6 router parameters
+ *  ifc must be bound and wlock'd
+ */
+static char*
 ipifcra6(Ipifc *ifc, char **argv, int argc)
 {
 	int i, argsleft;
@@ -802,7 +811,6 @@
 			rp.routerlt = atoi(argv[i+1]);
 		else
 			return Ebadarg;
-
 		argsleft -= 2;
 		i += 2;
 	}
@@ -825,44 +833,45 @@
 ipifcctl(Conv* c, char **argv, int argc)
 {
 	Ipifc *ifc = (Ipifc*)c->ptcl;
+	char *err = nil;
 
-	if(strcmp(argv[0], "add") == 0)
-		return ipifcadd(ifc, argv, argc, 0, nil);
+	if(strcmp(argv[0], "iprouting") == 0)
+		iprouting(c->p->f, argc>1? atoi(argv[1]): 1);
+	else if(strcmp(argv[0], "add") == 0)
+		err = ipifcadd(ifc, argv, argc, 0, nil);
 	else if(strcmp(argv[0], "try") == 0)
-		return ipifcadd(ifc, argv, argc, 1, nil);
+		err = ipifcadd(ifc, argv, argc, 1, nil);
 	else if(strcmp(argv[0], "remove") == 0)
-		return ipifcrem(ifc, argv, argc);
+		err = ipifcrem(ifc, argv, argc);
 	else if(strcmp(argv[0], "unbind") == 0)
-		return ipifcunbind(ifc);
-	else if(strcmp(argv[0], "mtu") == 0)
-		return ipifcsetmtu(ifc, argc>1? strtoul(argv[1], 0, 0): 0);
-	else if(strcmp(argv[0], "speed") == 0){
-		ipifcsetspeed(ifc, argc>1? atoi(argv[1]): 0);
-		return nil;
-	}
-	else if(strcmp(argv[0], "delay") == 0){
-		ipifcsetdelay(ifc, argc>1? atoi(argv[1]): 0);
-		return nil;
-	}
-	else if(strcmp(argv[0], "iprouting") == 0){
-		iprouting(c->p->f, argc>1? atoi(argv[1]): 1);
-		return nil;
-	}
-	else if(strcmp(argv[0], "reflect") == 0){
-		ifc->reflect = argc>1? atoi(argv[1]): 1;
-		return nil;
-	}
-	else if(strcmp(argv[0], "reassemble") == 0){
-		ifc->reassemble = argc>1? atoi(argv[1]): 1;
-		return nil;
-	}
+		err = ipifcunbind(ifc);
 	else if(strcmp(argv[0], "add6") == 0)
-		return ipifcadd6(ifc, argv, argc);
+		err = ipifcadd6(ifc, argv, argc);
 	else if(strcmp(argv[0], "remove6") == 0)
-		return ipifcremove6(ifc, argv, argc);
-	else if(strcmp(argv[0], "ra6") == 0)
-		return ipifcra6(ifc, argv, argc);
-	return "unsupported ctl";
+		err = ipifcremove6(ifc, argv, argc);
+	else {
+		wlock(ifc);
+		if(ifc->m == nil){
+			wunlock(ifc);
+			return Eunbound;
+		}
+		if(strcmp(argv[0], "mtu") == 0)
+			err = ipifcsetmtu(ifc, argc>1? strtoul(argv[1], 0, 0): 0);
+		else if(strcmp(argv[0], "speed") == 0)
+			ipifcsetspeed(ifc, argc>1? atoi(argv[1]): 0);
+		else if(strcmp(argv[0], "delay") == 0)
+			ipifcsetdelay(ifc, argc>1? atoi(argv[1]): 0);
+		else if(strcmp(argv[0], "reflect") == 0)
+			ifc->reflect = argc>1? atoi(argv[1]): 1;
+		else if(strcmp(argv[0], "reassemble") == 0)
+			ifc->reassemble = argc>1? atoi(argv[1]): 1;
+		else if(strcmp(argv[0], "ra6") == 0)
+			err = ipifcra6(ifc, argv, argc);
+		else
+			err = "unsupported ctl";
+		wunlock(ifc);
+	}
+	return err;
 }
 
 int
@@ -1661,7 +1670,6 @@
 	char *params[3];
 	uchar prefix[IPaddrlen];
 	Iplifc lifc;
-	Medium *m;
 
 	lifc.onlink = 1;
 	lifc.autoflag = 1;
@@ -1694,14 +1702,28 @@
 	    plen > 64 || islinklocal(prefix))
 		return Ebadarg;
 
-	/* issue "add" ctl msg for v6 link-local addr and prefix len */
-	m = ifc->m;
-	if(m == nil || m->pref2addr == nil)
+	rlock(ifc);
+	if(ifc->m == nil){
+		runlock(ifc);
 		return Eunbound;
-	(*m->pref2addr)(prefix, ifc->mac);	/* mac → v6 link-local addr */
+	}
+	if(ifc->m->pref2addr != nil && ifc->m->maclen > 0) {
+		/* mac → v6 link-local addr */
+		(*ifc->m->pref2addr)(prefix, ifc->mac);
+	} else {
+		/* copy from existing v6 link-local address */
+		Iplifc *llifc = iplinklocalifc(ifc);
+		if(llifc == nil){
+			runlock(ifc);
+			return Eunbound;
+		}
+		memmove(prefix+8, llifc->local+8, 8);
+	}
+	runlock(ifc);
 
-	sprint(addr, "%I", prefix);
-	sprint(preflen, "/%d", plen);
+	/* issue "add" ctl msg for v6 link-local addr and prefix len */
+	snprint(addr, sizeof addr, "%I", prefix);
+	snprint(preflen, sizeof preflen, "/%d", plen);
 	params[0] = "add";
 	params[1] = addr;
 	params[2] = preflen;
--- a/sys/src/9/ip/ipv6.h
+++ b/sys/src/9/ip/ipv6.h
@@ -165,8 +165,8 @@
 extern int v6aLpreflen;
 
 void ipv62smcast(uchar *, uchar *);
-void icmpns6(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac);
-void icmpna6(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags);
+void icmpns6(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac, int maclen);
+void icmpna6(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, int maclen, uchar flags);
 void icmpnohost6(Fs *f, Ipifc *ifc, Block *bp, Routehint *rh);
 void icmpnoconv6(Fs *f, Ipifc *ifc, Block *bp);
 void icmpttlexceeded6(Fs *f, Ipifc *ifc, Block *bp);