* [9front] ethernet over gre
@ 2023-09-23 14:26 Arne Meyer
2023-09-23 15:32 ` Jacob Moody
2023-09-23 19:50 ` Steve Simon
0 siblings, 2 replies; 7+ messages in thread
From: Arne Meyer @ 2023-09-23 14:26 UTC (permalink / raw)
To: 9front
[-- Attachment #1: Type: text/plain, Size: 526 bytes --]
Hello,
i finally found the time to polish up my implementation of ethernet over gre for 9front.
This is based on nusb/ether. It uses gre from the ip stack. I tested it with OpenBSD egre.
For now only ipv4 is supported for the outside of the tunnel.
9front:
ip address is 192.168.178.21
egre 192.168.178.20
ip/ipconfig -m 1400 ether /net/etherG0 10.0.0.1 255.255.255.0
OpenBSD:
ifconfig egre0 create
ifconfig egre0 tunnel 192.168.178.20 192.168.178.21
ifconfig egre0 10.0.0.2/24 mtu 1400
ifconfig egre0 up
Greetings,
Arne
[-- Attachment #2.1: Type: text/plain, Size: 331 bytes --]
from postmaster@9front:
The following attachment had content that we can't
prove to be harmless. To avoid possible automatic
execution, we changed the content headers.
The original header was:
Content-Type: text/x-c; charset=UTF-8; name=egre.c
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=egre.c
[-- Attachment #2.2: egre.c.suspect --]
[-- Type: application/octet-stream, Size: 14401 bytes --]
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <libsec.h>
//#include "usb.h"
#include "dat.h"
#include <fcall.h>
#include <9p.h>
#include <ip.h>
typedef struct Tab Tab;
typedef struct Dq Dq;
typedef struct Conn Conn;
typedef struct Stats Stats;
enum
{
Qroot,
Qiface,
Qclone,
Qstats,
Qaddr,
Qndir,
Qctl,
Qdata,
Qtype,
Qmax,
};
struct Tab
{
char *name;
ulong mode;
};
Tab tab[] =
{
"/", DMDIR|0555,
"etherG", DMDIR|0555, /* calling it *ether* makes snoopy(8) happy */
"clone", 0666,
"stats", 0666,
"addr", 0444,
"%ud", DMDIR|0555,
"ctl", 0666,
"data", 0666,
"type", 0444,
};
struct Dq
{
QLock;
Dq *next;
Req *r;
Req **rt;
Block *q;
Block **qt;
int size;
};
struct Conn
{
QLock;
int used;
int type;
int prom;
int bridge;
int headersonly;
Dq *dq;
};
struct Stats
{
int in;
int out;
int bogus;
};
uchar bcast[Eaddrlen] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
Stats stats;
Conn conn[32];
int nconn = 0;
int nprom = 0;
int nmulti = 0;
//Dev *epctl;
//Dev *epin;
//Dev *epout;
ulong time0;
static char *uname;
#define PATH(type, n) ((type)|((n)<<8))
#define TYPE(path) (((uint)(path) & 0x000000FF)>>0)
#define NUM(path) (((uint)(path) & 0xFFFFFF00)>>8)
#define NUMCONN(c) (((uintptr)(c)-(uintptr)&conn[0])/sizeof(conn[0]))
static void
fillstat(Dir *d, uvlong path)
{
Tab *t;
memset(d, 0, sizeof(*d));
d->uid = estrdup9p(uname);
d->gid = estrdup9p(uname);
d->qid.path = path;
d->atime = d->mtime = time0;
t = &tab[TYPE(path)];
d->name = smprint(t->name, NUM(path));
d->qid.type = t->mode>>24;
d->mode = t->mode;
}
static void
fsattach(Req *r)
{
if(r->ifcall.aname && r->ifcall.aname[0]){
respond(r, "invalid attach specifier");
return;
}
if(uname == nil)
uname = estrdup9p(r->ifcall.uname);
r->fid->qid.path = PATH(Qroot, 0);
r->fid->qid.type = QTDIR;
r->fid->qid.vers = 0;
r->ofcall.qid = r->fid->qid;
respond(r, nil);
}
static void
fsstat(Req *r)
{
fillstat(&r->d, r->fid->qid.path);
respond(r, nil);
}
static int
rootgen(int i, Dir *d, void*)
{
i += Qroot+1;
if(i == Qiface){
fillstat(d, i);
return 0;
}
return -1;
}
static int
ifacegen(int i, Dir *d, void*)
{
i += Qiface+1;
if(i < Qndir){
fillstat(d, i);
return 0;
}
i -= Qndir;
if(i < nconn){
fillstat(d, PATH(Qndir, i));
return 0;
}
return -1;
}
static int
ndirgen(int i, Dir *d, void *aux)
{
i += Qndir+1;
if(i < Qmax){
fillstat(d, PATH(i, NUMCONN(aux)));
return 0;
}
return -1;
}
static char*
fswalk1(Fid *fid, char *name, Qid *qid)
{
int i, n;
char buf[32];
ulong path;
path = fid->qid.path;
if(!(fid->qid.type&QTDIR))
return "walk in non-directory";
if(strcmp(name, "..") == 0){
switch(TYPE(path)){
case Qroot:
return nil;
case Qiface:
qid->path = PATH(Qroot, 0);
qid->type = tab[Qroot].mode>>24;
return nil;
case Qndir:
qid->path = PATH(Qiface, 0);
qid->type = tab[Qiface].mode>>24;
return nil;
default:
return "bug in fswalk1";
}
}
for(i = TYPE(path)+1; i<nelem(tab); i++){
if(i==Qndir){
n = atoi(name);
snprint(buf, sizeof buf, "%d", n);
if(n < nconn && strcmp(buf, name) == 0){
qid->path = PATH(i, n);
qid->type = tab[i].mode>>24;
return nil;
}
break;
}
if(strcmp(name, tab[i].name) == 0){
qid->path = PATH(i, NUM(path));
qid->type = tab[i].mode>>24;
return nil;
}
if(tab[i].mode&DMDIR)
break;
}
return "directory entry not found";
}
static void
matchrq(Dq *d)
{
Req *r;
Block *b;
while(r = d->r){
int n;
if((b = d->q) == nil)
break;
d->size -= BLEN(b);
if((d->q = b->next) == nil)
d->qt = &d->q;
if((d->r = (Req*)r->aux) == nil)
d->rt = &d->r;
n = r->ifcall.count;
if(n > BLEN(b))
n = BLEN(b);
memmove(r->ofcall.data, b->rp, n);
r->ofcall.count = n;
freeb(b);
respond(r, nil);
}
}
static void
readconndata(Req *r)
{
Dq *d;
d = r->fid->aux;
qlock(d);
r->aux = nil;
*d->rt = r;
d->rt = (Req**)&r->aux;
matchrq(d);
qunlock(d);
}
static void
etheroq(Block*, Conn*);
static void
writeconndata(Req *r)
{
void *p;
int n;
Block *b;
p = r->ifcall.data;
n = r->ifcall.count;
/* minimum frame length for rtl8150 */
if(n < 60)
n = 60;
/* slack space for header and trailers */
n += 44+16;
b = allocb(n);
/* header space */
b->wp += 44;
b->rp = b->wp;
/* copy in the ethernet packet */
memmove(b->wp, p, r->ifcall.count);
b->wp += r->ifcall.count;
etheroq(b, &conn[NUM(r->fid->qid.path)]);
r->ofcall.count = r->ifcall.count;
respond(r, nil);
}
static void
fsread(Req *r)
{
char buf[200];
char e[ERRMAX];
ulong path;
path = r->fid->qid.path;
switch(TYPE(path)){
default:
snprint(e, sizeof e, "bug in fsread path=%lux", path);
respond(r, e);
break;
case Qroot:
dirread9p(r, rootgen, nil);
respond(r, nil);
break;
case Qiface:
dirread9p(r, ifacegen, nil);
respond(r, nil);
break;
case Qstats:
snprint(buf, sizeof(buf),
"in: %d\n"
"out: %d\n"
"bogus: %d\n"
"mbps: %d\n"
"addr: %E\n",
stats.in, stats.out, stats.bogus, 10, macaddr);
readstr(r, buf);
respond(r, nil);
break;
case Qaddr:
snprint(buf, sizeof(buf), "%E", macaddr);
readstr(r, buf);
respond(r, nil);
break;
case Qndir:
dirread9p(r, ndirgen, &conn[NUM(path)]);
respond(r, nil);
break;
case Qctl:
snprint(buf, sizeof(buf), "%11d ", NUM(path));
readstr(r, buf);
respond(r, nil);
break;
case Qtype:
snprint(buf, sizeof(buf), "%11d ", conn[NUM(path)].type);
readstr(r, buf);
respond(r, nil);
break;
case Qdata:
readconndata(r);
break;
}
}
static int
activemulti(uchar *ea)
{
int i;
for(i=0; i<nmulti; i++)
if(memcmp(ea, multiaddr[i], Eaddrlen) == 0)
return i;
return -1;
}
static void
fswrite(Req *r)
{
char e[ERRMAX];
ulong path;
char *p;
int n;
path = r->fid->qid.path;
switch(TYPE(path)){
case Qctl:
n = r->ifcall.count;
p = (char*)r->ifcall.data;
if(n >= 6 && memcmp(p, "bridge", 6)==0){
conn[NUM(path)].bridge = 1;
} else if(n >= 11 && memcmp(p, "headersonly", 11)==0){
conn[NUM(path)].headersonly = 1;
} else if(n >= 11 && memcmp(p, "promiscuous", 11)==0){
if(conn[NUM(path)].prom == 0){
conn[NUM(path)].prom = 1;
//if(nprom++ == 0 && eppromiscuous != nil)
//(*eppromiscuous)(epctl, 1);
}
} else if(n >= 9+12 && (memcmp(p, "addmulti ", 9)==0 || memcmp(p, "remmulti ", 9)==0)){
uchar ea[Eaddrlen];
int i;
if(parseether(ea, p+9) < 0){
respond(r, "bad ether address");
return;
}
i = activemulti(ea);
if(i >= 0){
if(*p == 'r'){
memmove(multiaddr[i], multiaddr[--nmulti], Eaddrlen);
//if(epmulticast != nil)
// (*epmulticast)(epctl, ea, 0);
}
} else if(nmulti < nelem(multiaddr)){
if(*p == 'a'){
memmove(multiaddr[nmulti++], ea, Eaddrlen);
//if(epmulticast != nil)
// (*epmulticast)(epctl, ea, 1);
}
}
} else if(n > 8 && memcmp(p, "connect ", 8)==0){
char x[12];
if(n - 8 >= sizeof(x)){
respond(r, "invalid control msg");
return;
}
p += 8;
memcpy(x, p, n-8);
x[n-8] = 0;
conn[NUM(path)].type = strtoul(x, nil, 0);
}
r->ofcall.count = n;
respond(r, nil);
break;
case Qdata:
writeconndata(r);
break;
default:
snprint(e, sizeof e, "bug in fswrite path=%lux", path);
respond(r, e);
}
}
static void
fsopen(Req *r)
{
static int need[4] = { 4, 2, 6, 1 };
ulong path;
int i, n;
Tab *t;
Dq *d;
Conn *c;
/*
* lib9p already handles the blatantly obvious.
* we just have to enforce the permissions we have set.
*/
path = r->fid->qid.path;
t = &tab[TYPE(path)];
n = need[r->ifcall.mode&3];
if((n&t->mode) != n){
respond(r, "permission denied");
return;
}
d = nil;
r->fid->aux = nil;
switch(TYPE(path)){
case Qclone:
for(i=0; i<nelem(conn); i++){
if(conn[i].used)
continue;
if(i >= nconn)
nconn = i+1;
path = PATH(Qctl, i);
goto CaseConn;
}
respond(r, "out of connections");
return;
case Qdata:
d = emalloc9p(sizeof(*d));
memset(d, 0, sizeof(*d));
d->qt = &d->q;
d->rt = &d->r;
r->fid->aux = d;
case Qndir:
case Qctl:
case Qtype:
CaseConn:
c = &conn[NUM(path)];
qlock(c);
if(c->used++ == 0){
c->type = 0;
c->prom = 0;
c->bridge = 0;
c->headersonly = 0;
}
if(d != nil){
d->next = c->dq;
c->dq = d;
}
qunlock(c);
break;
}
r->fid->qid.path = path;
r->ofcall.qid.path = path;
respond(r, nil);
}
static void
fsflush(Req *r)
{
Req *o, **p;
Fid *f;
Dq *d;
o = r->oldreq;
f = o->fid;
if(TYPE(f->qid.path) == Qdata){
d = f->aux;
qlock(d);
for(p=&d->r; *p; p=(Req**)&((*p)->aux)){
if(*p == o){
if((*p = (Req*)o->aux) == nil)
d->rt = p;
r->oldreq = nil;
respond(o, "interrupted");
break;
}
}
qunlock(d);
}
respond(r, nil);
}
static void
fsdestroyfid(Fid *fid)
{
Conn *c;
Dq **x, *d;
Block *b;
if(TYPE(fid->qid.path) >= Qndir){
c = &conn[NUM(fid->qid.path)];
qlock(c);
if(d = fid->aux){
fid->aux = nil;
for(x=&c->dq; *x; x=&((*x)->next)){
if(*x == d){
*x = d->next;
break;
}
}
while(b = d->q){
d->q = b->next;
freeb(b);
}
free(d);
}
if(TYPE(fid->qid.path) == Qctl){
if(c->prom){
c->prom = 0;
//if(--nprom == 0 && eppromiscuous != nil)
// (*eppromiscuous)(epctl, 0);
}
}
if(TYPE(fid->qid.path) == Qdata && c->bridge)
memset(mactab, 0, sizeof(mactab));
c->used--;
qunlock(c);
}
}
static int
inote(void *, char *msg)
{
if(strstr(msg, "interrupt"))
return 1;
return 0;
}
static void
cpass(Conn *c, Block *bp)
{
Dq *d;
qlock(c);
for(d = c->dq; d != nil; d = d->next){
qlock(d);
if(d->size < 100000){
Block *q;
if(d->next == nil) {
q = bp;
bp = nil;
} else
q = copyblock(bp, BLEN(bp));
q->next = nil;
*d->qt = q;
d->qt = &q->next;
d->size += BLEN(q);
matchrq(d);
}
qunlock(d);
}
qunlock(c);
if(bp != nil)
freeb(bp);
}
static void
etherrtrace(Conn *c, Etherpkt *pkt, int len)
{
Block *bp;
bp = allocb(64);
memmove(bp->wp, pkt, len < 64 ? len : 64);
if(c->type != -2){
u32int ms = nsec()/1000000LL;
bp->wp[58] = len>>8;
bp->wp[59] = len;
bp->wp[60] = ms>>24;
bp->wp[61] = ms>>16;
bp->wp[62] = ms>>8;
bp->wp[63] = ms;
}
bp->wp += 64;
cpass(c, bp);
}
static Macent*
macent(uchar *ea)
{
u32int h = (ea[0] | ea[1]<<8 | ea[2]<<16 | ea[3]<<24) ^ (ea[4] | ea[5]<<8);
return &mactab[h % nelem(mactab)];
}
static Block*
ethermux(Block *bp, Conn *from)
{
Etherpkt *pkt;
Conn *c, *x;
int len, multi, tome, port, type, dispose;
len = BLEN(bp);
if(len < ETHERHDRSIZE)
goto Drop;
pkt = (Etherpkt*)bp->rp;
if(!(multi = pkt->d[0] & 1)){
tome = memcmp(pkt->d, macaddr, Eaddrlen) == 0;
if(!tome && from != nil && nprom == 0)
return bp;
} else {
tome = 0;
if(from == nil && nprom == 0
&& memcmp(pkt->d, bcast, Eaddrlen) != 0
&& activemulti(pkt->d) < 0)
goto Drop;
}
port = -1;
if(nprom){
if((from == nil || from->bridge) && (pkt->s[0] & 1) == 0){
Macent *t = macent(pkt->s);
t->port = from == nil ? 0 : 1+(from - conn);
memmove(t->ea, pkt->s, Eaddrlen);
}
if(!tome && !multi){
Macent *t = macent(pkt->d);
if(memcmp(t->ea, pkt->d, Eaddrlen) == 0)
port = t->port;
}
}
x = nil;
type = (pkt->type[0]<<8)|pkt->type[1];
dispose = tome || from == nil || port > 0;
for(c = conn; c < &conn[nconn]; c++){
if(!c->used)
continue;
if(c->type != type && c->type >= 0)
continue;
if(!tome && !multi && !c->prom)
continue;
if(c->bridge){
if(tome || c == from)
continue;
if(port >= 0 && port != 1+(c - conn))
continue;
}
if(c->headersonly || c->type == -2){
etherrtrace(c, pkt, len);
continue;
}
if(dispose && x == nil)
x = c;
else
cpass(c, copyblock(bp, len));
}
if(x != nil){
cpass(x, bp);
return nil;
}
if(dispose){
Drop: freeb(bp);
return nil;
}
return bp;
}
void
etheriq(Block *bp)
{
stats.in++;
ethermux(bp, nil);
}
static void
etheroq(Block *bp, Conn *from)
{
if(!from->bridge)
memmove(((Etherpkt*)bp->rp)->s, macaddr, Eaddrlen);
bp = ethermux(bp, from);
if(bp == nil)
return;
stats.out++;
/* transmit frees buffer */
bp->rp-=12;
memset(bp->rp, 0, 12);
write(grecon, bp->rp, BLEN(bp));
freeb(bp);
}
static void
grereadproc(void *)
{
char err[ERRMAX];
uchar buf[1600];
int nerr;
int len;
Block *b;
ushort flags;
atnotify(inote, 1);
threadsetname("grereadproc");
nerr = 0;
for(;;){
/* receive allocates buffer and calls etheriq(b, 1); */
if((len = read(grecon, buf, 1600)) < 0){
fprint(2, "got packet!\n");
rerrstr(err, sizeof(err));
if(strstr(err, "interrupted") || strstr(err, "timed out"))
continue;
fprint(2, "grereadproc: %s\n", err);
if(++nerr < 3)
continue;
threadexitsall(err);
}
nerr = 0;
flags = nhgets(buf+8);
if(flags){
stats.bogus++;
continue;
}
b = allocb(1600);
memcpy(b->wp, buf+12, len-12);
b->wp+=(len-12);
etheriq(b);
}
}
Srv fs =
{
.attach= fsattach,
.destroyfid= fsdestroyfid,
.walk1= fswalk1,
.open= fsopen,
.read= fsread,
.write= fswrite,
.stat= fsstat,
.flush= fsflush,
};
static void
usage(void)
{
fprint(2, "usage: %s [-dD] [-i index] [-a addr] remote\n", argv0);
exits("usage");
}
void
threadmain(int argc, char **argv)
{
char s[64], *t, *d;
int idx = 0;
fmtinstall('E', eipfmt);
ARGBEGIN {
case 'd':
debug = 1;
break;
case 'D':
chatty9p++;
break;
case 'i':
idx = atoi(EARGF(usage()));
case 'a':
setmac = 1;
if(parseether(macaddr, EARGF(usage())) != 0)
usage();
break;
default:
usage();
} ARGEND;
if(argc != 1)
usage();
if(!setmac){
genrandom(macaddr, Eaddrlen);
macaddr[0] &= 0xfe;
}
d = smprint("gre!%s!25944", argv[0]);
grecon = dial(d, nil, nil, nil);
if(grecon == -1)
sysfatal("%r");
werrstr("");
proccreate(grereadproc, nil, 8*1024);
atnotify(inote, 1);
time0 = time(0);
tab[Qiface].name = smprint("etherG%d", idx);
snprint(s, sizeof(s), "%d.ugre", idx);
threadpostmountsrv(&fs, s, "/net/", MAFTER);
threadexits(0);
}
Block*
allocb(int size)
{
Block *b;
b = emalloc9p(sizeof(*b) + size);
b->lim = b->base + size;
b->rp = b->base;
b->wp = b->base;
b->next = nil;
return b;
}
Block*
copyblock(Block *b, int count)
{
Block *nb;
if(count > BLEN(b))
count = BLEN(b);
nb = allocb(count);
memmove(nb->wp, b->rp, count);
nb->wp += count;
return nb;
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [9front] ethernet over gre
2023-09-23 14:26 [9front] ethernet over gre Arne Meyer
@ 2023-09-23 15:32 ` Jacob Moody
2023-09-23 15:46 ` Arne Meyer
2023-09-23 19:50 ` Steve Simon
1 sibling, 1 reply; 7+ messages in thread
From: Jacob Moody @ 2023-09-23 15:32 UTC (permalink / raw)
To: 9front
This is pretty cool, could you write up a man page for it perhaps?
Thanks,
Jacob Moody
On 9/23/23 09:26, Arne Meyer wrote:
> Hello,
>
> i finally found the time to polish up my implementation of ethernet over gre for 9front.
> This is based on nusb/ether. It uses gre from the ip stack. I tested it with OpenBSD egre.
> For now only ipv4 is supported for the outside of the tunnel.
>
> 9front:
> ip address is 192.168.178.21
>
> egre 192.168.178.20
> ip/ipconfig -m 1400 ether /net/etherG0 10.0.0.1 255.255.255.0
>
> OpenBSD:
>
> ifconfig egre0 create
> ifconfig egre0 tunnel 192.168.178.20 192.168.178.21
> ifconfig egre0 10.0.0.2/24 mtu 1400
> ifconfig egre0 up
>
> Greetings,
> Arne
>
>
> from postmaster@9front:
> The following attachment had content that we can't
> prove to be harmless. To avoid possible automatic
> execution, we changed the content headers.
> The original header was:
>
> Content-Type: text/x-c; charset=UTF-8; name=egre.c
> Content-Transfer-Encoding: base64
> Content-Disposition: attachment; filename=egre.c
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [9front] ethernet over gre
2023-09-23 15:32 ` Jacob Moody
@ 2023-09-23 15:46 ` Arne Meyer
2023-09-23 15:56 ` Jacob Moody
0 siblings, 1 reply; 7+ messages in thread
From: Arne Meyer @ 2023-09-23 15:46 UTC (permalink / raw)
To: 9front
I have no clue how to write a man page but I'll give it a try for sure!
> Jacob Moody <moody@posixcafe.org> hat am 23.09.2023 17:32 CEST geschrieben:
>
>
> This is pretty cool, could you write up a man page for it perhaps?
>
> Thanks,
> Jacob Moody
>
> On 9/23/23 09:26, Arne Meyer wrote:
> > Hello,
> >
> > i finally found the time to polish up my implementation of ethernet over gre for 9front.
> > This is based on nusb/ether. It uses gre from the ip stack. I tested it with OpenBSD egre.
> > For now only ipv4 is supported for the outside of the tunnel.
> >
> > 9front:
> > ip address is 192.168.178.21
> >
> > egre 192.168.178.20
> > ip/ipconfig -m 1400 ether /net/etherG0 10.0.0.1 255.255.255.0
> >
> > OpenBSD:
> >
> > ifconfig egre0 create
> > ifconfig egre0 tunnel 192.168.178.20 192.168.178.21
> > ifconfig egre0 10.0.0.2/24 mtu 1400
> > ifconfig egre0 up
> >
> > Greetings,
> > Arne
> >
> >
> > from postmaster@9front:
> > The following attachment had content that we can't
> > prove to be harmless. To avoid possible automatic
> > execution, we changed the content headers.
> > The original header was:
> >
> > Content-Type: text/x-c; charset=UTF-8; name=egre.c
> > Content-Transfer-Encoding: base64
> > Content-Disposition: attachment; filename=egre.c
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [9front] ethernet over gre
2023-09-23 15:46 ` Arne Meyer
@ 2023-09-23 15:56 ` Jacob Moody
2023-09-23 20:33 ` Arne Meyer
0 siblings, 1 reply; 7+ messages in thread
From: Jacob Moody @ 2023-09-23 15:56 UTC (permalink / raw)
To: 9front
My advice is to read around the other man pages to get a broad idea of the format,
and if you have any questions about what a macro specifically does man(6) explains them
all in more detail. That's how I learned anyway. Feel free to ask if you run in to any issues.
Thanks!
moody
On 9/23/23 10:46, Arne Meyer wrote:
> I have no clue how to write a man page but I'll give it a try for sure!
>
>> Jacob Moody <moody@posixcafe.org> hat am 23.09.2023 17:32 CEST geschrieben:
>>
>>
>> This is pretty cool, could you write up a man page for it perhaps?
>>
>> Thanks,
>> Jacob Moody
>>
>> On 9/23/23 09:26, Arne Meyer wrote:
>>> Hello,
>>>
>>> i finally found the time to polish up my implementation of ethernet over gre for 9front.
>>> This is based on nusb/ether. It uses gre from the ip stack. I tested it with OpenBSD egre.
>>> For now only ipv4 is supported for the outside of the tunnel.
>>>
>>> 9front:
>>> ip address is 192.168.178.21
>>>
>>> egre 192.168.178.20
>>> ip/ipconfig -m 1400 ether /net/etherG0 10.0.0.1 255.255.255.0
>>>
>>> OpenBSD:
>>>
>>> ifconfig egre0 create
>>> ifconfig egre0 tunnel 192.168.178.20 192.168.178.21
>>> ifconfig egre0 10.0.0.2/24 mtu 1400
>>> ifconfig egre0 up
>>>
>>> Greetings,
>>> Arne
>>>
>>>
>>> from postmaster@9front:
>>> The following attachment had content that we can't
>>> prove to be harmless. To avoid possible automatic
>>> execution, we changed the content headers.
>>> The original header was:
>>>
>>> Content-Type: text/x-c; charset=UTF-8; name=egre.c
>>> Content-Transfer-Encoding: base64
>>> Content-Disposition: attachment; filename=egre.c
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [9front] ethernet over gre
2023-09-23 14:26 [9front] ethernet over gre Arne Meyer
2023-09-23 15:32 ` Jacob Moody
@ 2023-09-23 19:50 ` Steve Simon
2023-09-23 20:41 ` Arne Meyer
1 sibling, 1 reply; 7+ messages in thread
From: Steve Simon @ 2023-09-23 19:50 UTC (permalink / raw)
To: 9front
just a suggestion…
you could refactor a bit to take the ip address in the dialstring, as implemented in telco(1).
i am not sure how much more useful that would really be but it might be classed as a slightly more plan9-ey implementation.
-Steve
> On 23 Sep 2023, at 3:30 pm, Arne Meyer <meyer.arne83@netcologne.de> wrote:
>
> Hello,
>
> i finally found the time to polish up my implementation of ethernet over gre for 9front.
> This is based on nusb/ether. It uses gre from the ip stack. I tested it with OpenBSD egre.
> For now only ipv4 is supported for the outside of the tunnel.
>
> 9front:
> ip address is 192.168.178.21
>
> egre 192.168.178.20
> ip/ipconfig -m 1400 ether /net/etherG0 10.0.0.1 255.255.255.0
>
> OpenBSD:
>
> ifconfig egre0 create
> ifconfig egre0 tunnel 192.168.178.20 192.168.178.21
> ifconfig egre0 10.0.0.2/24 mtu 1400
> ifconfig egre0 up
>
> Greetings,
> Arnefrom postmaster@9front:
> The following attachment had content that we can't
> prove to be harmless. To avoid possible automatic
> execution, we changed the content headers.
> The original header was:
>
> Content-Type: text/x-c; charset=UTF-8; name=egre.c
> Content-Transfer-Encoding: base64
> Content-Disposition: attachment; filename=egre.c
> <egre.c.suspect>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [9front] ethernet over gre
2023-09-23 15:56 ` Jacob Moody
@ 2023-09-23 20:33 ` Arne Meyer
0 siblings, 0 replies; 7+ messages in thread
From: Arne Meyer @ 2023-09-23 20:33 UTC (permalink / raw)
To: 9front
[-- Attachment #1: Type: text/plain, Size: 1851 bytes --]
Here is a patch for 9front with my first try for a man page.
> Jacob Moody <moody@posixcafe.org> hat am 23.09.2023 17:56 CEST geschrieben:
>
>
> My advice is to read around the other man pages to get a broad idea of the format,
> and if you have any questions about what a macro specifically does man(6) explains them
> all in more detail. That's how I learned anyway. Feel free to ask if you run in to any issues.
>
> Thanks!
> moody
>
> On 9/23/23 10:46, Arne Meyer wrote:
> > I have no clue how to write a man page but I'll give it a try for sure!
> >
> >> Jacob Moody <moody@posixcafe.org> hat am 23.09.2023 17:32 CEST geschrieben:
> >>
> >>
> >> This is pretty cool, could you write up a man page for it perhaps?
> >>
> >> Thanks,
> >> Jacob Moody
> >>
> >> On 9/23/23 09:26, Arne Meyer wrote:
> >>> Hello,
> >>>
> >>> i finally found the time to polish up my implementation of ethernet over gre for 9front.
> >>> This is based on nusb/ether. It uses gre from the ip stack. I tested it with OpenBSD egre.
> >>> For now only ipv4 is supported for the outside of the tunnel.
> >>>
> >>> 9front:
> >>> ip address is 192.168.178.21
> >>>
> >>> egre 192.168.178.20
> >>> ip/ipconfig -m 1400 ether /net/etherG0 10.0.0.1 255.255.255.0
> >>>
> >>> OpenBSD:
> >>>
> >>> ifconfig egre0 create
> >>> ifconfig egre0 tunnel 192.168.178.20 192.168.178.21
> >>> ifconfig egre0 10.0.0.2/24 mtu 1400
> >>> ifconfig egre0 up
> >>>
> >>> Greetings,
> >>> Arne
> >>>
> >>>
> >>> from postmaster@9front:
> >>> The following attachment had content that we can't
> >>> prove to be harmless. To avoid possible automatic
> >>> execution, we changed the content headers.
> >>> The original header was:
> >>>
> >>> Content-Type: text/x-c; charset=UTF-8; name=egre.c
> >>> Content-Transfer-Encoding: base64
> >>> Content-Disposition: attachment; filename=egre.c
[-- Attachment #2: egre.patch --]
[-- Type: application/octet-stream, Size: 17182 bytes --]
diff 44a2f89a03c370940fa0f4747c2357c73984d653 uncommitted
--- /dev/null
+++ b/./sys/man/8/egre
@@ -1,0 +1,42 @@
+.TH egre 8
+.SH NAME
+egre \- ethernet over gre
+.SH SYNOPSYS
+.B ip/egre
+[
+.B -ai
+] [
+.B -a
+.I mac
+] [
+.B -i
+.I index
+]
+.I remote
+.SH DESCRIPTION
+GRE is a tunneling protocol that can encapsulate a variety of network protocols inside an ip tunnel.
+.I egre
+creates an ethernet connection over ip to a remote host. The file system provided is compatible with ether(3) and is bound after /net so the device will appear as /net/etherGN.
+.PP
+With no option
+.I egre
+creates an ethernet tunnel to
+.I remote
+with a random source mac and binds to /net/etherG0.
+.PP
+.I Egre
+supports the following options:
+.TP 3
+.B a
+set the source mac address
+.TP
+.B i
+set the interface to /net/etherG[index]
+.SH SOURCE
+.B /sys/src/cmp/ip/egre.c
+.SH SEE ALSO
+.IR ipconfig (8),
+.I gre
+in
+.IR ip(3)
+
--- /dev/null
+++ b/./sys/src/cmd/ip/egre.c
@@ -1,0 +1,952 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <libsec.h>
+
+#include <fcall.h>
+#include <9p.h>
+#include <ip.h>
+
+typedef struct Tab Tab;
+typedef struct Dq Dq;
+typedef struct Conn Conn;
+typedef struct Stats Stats;
+
+typedef struct Block Block;
+struct Block
+{
+ Block *next;
+
+ uchar *rp;
+ uchar *wp;
+ uchar *lim;
+
+ uchar base[];
+};
+
+#define BLEN(s) ((s)->wp - (s)->rp)
+
+Block* allocb(int size);
+Block* copyblock(Block*, int);
+#define freeb(b) free(b)
+
+enum {
+ Eaddrlen= 6,
+ ETHERHDRSIZE= 14, /* size of an ethernet header */
+ Maxpkt= 2000,
+};
+
+typedef struct Macent Macent;
+struct Macent
+{
+ uchar ea[Eaddrlen];
+ ushort port;
+};
+
+typedef struct Etherpkt Etherpkt;
+struct Etherpkt
+{
+ uchar d[Eaddrlen];
+ uchar s[Eaddrlen];
+ uchar type[2];
+ uchar data[1500];
+};
+
+enum
+{
+ Cdcunion = 6,
+ Scether = 6,
+ Fnether = 15,
+};
+
+int debug;
+int setmac;
+
+int nprom;
+int nmulti;
+uchar multiaddr[32][Eaddrlen];
+
+/* to be filled in by *init() */
+uchar macaddr[Eaddrlen];
+
+Macent mactab[127];
+
+int grecon;
+int grectl;
+
+void etheriq(Block*);
+
+
+enum
+{
+ Qroot,
+ Qiface,
+ Qclone,
+ Qstats,
+ Qaddr,
+ Qndir,
+ Qctl,
+ Qdata,
+ Qtype,
+ Qmax,
+};
+
+struct Tab
+{
+ char *name;
+ ulong mode;
+};
+
+Tab tab[] =
+{
+ "/", DMDIR|0555,
+ "etherG", DMDIR|0555, /* calling it *ether* makes snoopy(8) happy */
+ "clone", 0666,
+ "stats", 0666,
+ "addr", 0444,
+ "%ud", DMDIR|0555,
+ "ctl", 0666,
+ "data", 0666,
+ "type", 0444,
+};
+
+struct Dq
+{
+ QLock;
+
+ Dq *next;
+ Req *r;
+ Req **rt;
+ Block *q;
+ Block **qt;
+
+ int size;
+};
+
+struct Conn
+{
+ QLock;
+
+ int used;
+ int type;
+ int prom;
+ int bridge;
+ int headersonly;
+
+ Dq *dq;
+};
+
+struct Stats
+{
+ int in;
+ int out;
+ int bogus;
+};
+
+uchar bcast[Eaddrlen] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+Stats stats;
+Conn conn[32];
+int nconn = 0;
+
+int nprom = 0;
+int nmulti = 0;
+
+ulong time0;
+static char *uname;
+
+#define PATH(type, n) ((type)|((n)<<8))
+#define TYPE(path) (((uint)(path) & 0x000000FF)>>0)
+#define NUM(path) (((uint)(path) & 0xFFFFFF00)>>8)
+#define NUMCONN(c) (((uintptr)(c)-(uintptr)&conn[0])/sizeof(conn[0]))
+
+static void
+fillstat(Dir *d, uvlong path)
+{
+ Tab *t;
+
+ memset(d, 0, sizeof(*d));
+ d->uid = estrdup9p(uname);
+ d->gid = estrdup9p(uname);
+ d->qid.path = path;
+ d->atime = d->mtime = time0;
+ t = &tab[TYPE(path)];
+ d->name = smprint(t->name, NUM(path));
+ d->qid.type = t->mode>>24;
+ d->mode = t->mode;
+}
+
+static void
+fsattach(Req *r)
+{
+ if(r->ifcall.aname && r->ifcall.aname[0]){
+ respond(r, "invalid attach specifier");
+ return;
+ }
+ if(uname == nil)
+ uname = estrdup9p(r->ifcall.uname);
+ r->fid->qid.path = PATH(Qroot, 0);
+ r->fid->qid.type = QTDIR;
+ r->fid->qid.vers = 0;
+ r->ofcall.qid = r->fid->qid;
+ respond(r, nil);
+}
+
+static void
+fsstat(Req *r)
+{
+ fillstat(&r->d, r->fid->qid.path);
+ respond(r, nil);
+}
+
+static int
+rootgen(int i, Dir *d, void*)
+{
+ i += Qroot+1;
+ if(i == Qiface){
+ fillstat(d, i);
+ return 0;
+ }
+ return -1;
+}
+
+static int
+ifacegen(int i, Dir *d, void*)
+{
+ i += Qiface+1;
+ if(i < Qndir){
+ fillstat(d, i);
+ return 0;
+ }
+ i -= Qndir;
+ if(i < nconn){
+ fillstat(d, PATH(Qndir, i));
+ return 0;
+ }
+ return -1;
+}
+
+static int
+ndirgen(int i, Dir *d, void *aux)
+{
+ i += Qndir+1;
+ if(i < Qmax){
+ fillstat(d, PATH(i, NUMCONN(aux)));
+ return 0;
+ }
+ return -1;
+}
+
+static char*
+fswalk1(Fid *fid, char *name, Qid *qid)
+{
+ int i, n;
+ char buf[32];
+ ulong path;
+
+ path = fid->qid.path;
+ if(!(fid->qid.type&QTDIR))
+ return "walk in non-directory";
+
+ if(strcmp(name, "..") == 0){
+ switch(TYPE(path)){
+ case Qroot:
+ return nil;
+ case Qiface:
+ qid->path = PATH(Qroot, 0);
+ qid->type = tab[Qroot].mode>>24;
+ return nil;
+ case Qndir:
+ qid->path = PATH(Qiface, 0);
+ qid->type = tab[Qiface].mode>>24;
+ return nil;
+ default:
+ return "bug in fswalk1";
+ }
+ }
+
+ for(i = TYPE(path)+1; i<nelem(tab); i++){
+ if(i==Qndir){
+ n = atoi(name);
+ snprint(buf, sizeof buf, "%d", n);
+ if(n < nconn && strcmp(buf, name) == 0){
+ qid->path = PATH(i, n);
+ qid->type = tab[i].mode>>24;
+ return nil;
+ }
+ break;
+ }
+ if(strcmp(name, tab[i].name) == 0){
+ qid->path = PATH(i, NUM(path));
+ qid->type = tab[i].mode>>24;
+ return nil;
+ }
+ if(tab[i].mode&DMDIR)
+ break;
+ }
+ return "directory entry not found";
+}
+
+static void
+matchrq(Dq *d)
+{
+ Req *r;
+ Block *b;
+
+ while(r = d->r){
+ int n;
+
+ if((b = d->q) == nil)
+ break;
+
+ d->size -= BLEN(b);
+ if((d->q = b->next) == nil)
+ d->qt = &d->q;
+ if((d->r = (Req*)r->aux) == nil)
+ d->rt = &d->r;
+
+ n = r->ifcall.count;
+ if(n > BLEN(b))
+ n = BLEN(b);
+ memmove(r->ofcall.data, b->rp, n);
+ r->ofcall.count = n;
+ freeb(b);
+
+ respond(r, nil);
+ }
+}
+
+static void
+readconndata(Req *r)
+{
+ Dq *d;
+
+ d = r->fid->aux;
+ qlock(d);
+ r->aux = nil;
+ *d->rt = r;
+ d->rt = (Req**)&r->aux;
+ matchrq(d);
+ qunlock(d);
+}
+
+static void
+etheroq(Block*, Conn*);
+
+static void
+writeconndata(Req *r)
+{
+ void *p;
+ int n;
+ Block *b;
+
+ p = r->ifcall.data;
+ n = r->ifcall.count;
+
+ /* minimum frame length for rtl8150 */
+ if(n < 60)
+ n = 60;
+
+ /* slack space for header and trailers */
+ n += 44+16;
+
+ b = allocb(n);
+
+ /* header space */
+ b->wp += 44;
+ b->rp = b->wp;
+
+ /* copy in the ethernet packet */
+ memmove(b->wp, p, r->ifcall.count);
+ b->wp += r->ifcall.count;
+
+ etheroq(b, &conn[NUM(r->fid->qid.path)]);
+
+ r->ofcall.count = r->ifcall.count;
+ respond(r, nil);
+}
+
+static void
+fsread(Req *r)
+{
+ char buf[200];
+ char e[ERRMAX];
+ ulong path;
+
+ path = r->fid->qid.path;
+
+ switch(TYPE(path)){
+ default:
+ snprint(e, sizeof e, "bug in fsread path=%lux", path);
+ respond(r, e);
+ break;
+
+ case Qroot:
+ dirread9p(r, rootgen, nil);
+ respond(r, nil);
+ break;
+
+ case Qiface:
+ dirread9p(r, ifacegen, nil);
+ respond(r, nil);
+ break;
+
+ case Qstats:
+ snprint(buf, sizeof(buf),
+ "in: %d\n"
+ "out: %d\n"
+ "bogus: %d\n"
+ "mbps: %d\n"
+ "addr: %E\n",
+ stats.in, stats.out, stats.bogus, 10, macaddr);
+ readstr(r, buf);
+ respond(r, nil);
+ break;
+
+ case Qaddr:
+ snprint(buf, sizeof(buf), "%E", macaddr);
+ readstr(r, buf);
+ respond(r, nil);
+ break;
+
+ case Qndir:
+ dirread9p(r, ndirgen, &conn[NUM(path)]);
+ respond(r, nil);
+ break;
+
+ case Qctl:
+ snprint(buf, sizeof(buf), "%11d ", NUM(path));
+ readstr(r, buf);
+ respond(r, nil);
+ break;
+
+ case Qtype:
+ snprint(buf, sizeof(buf), "%11d ", conn[NUM(path)].type);
+ readstr(r, buf);
+ respond(r, nil);
+ break;
+
+ case Qdata:
+ readconndata(r);
+ break;
+ }
+}
+
+static int
+activemulti(uchar *ea)
+{
+ int i;
+
+ for(i=0; i<nmulti; i++)
+ if(memcmp(ea, multiaddr[i], Eaddrlen) == 0)
+ return i;
+ return -1;
+}
+
+static void
+fswrite(Req *r)
+{
+ char e[ERRMAX];
+ ulong path;
+ char *p;
+ int n;
+
+ path = r->fid->qid.path;
+ switch(TYPE(path)){
+ case Qctl:
+ n = r->ifcall.count;
+ p = (char*)r->ifcall.data;
+ if(n >= 6 && memcmp(p, "bridge", 6)==0){
+ conn[NUM(path)].bridge = 1;
+ } else if(n >= 11 && memcmp(p, "headersonly", 11)==0){
+ conn[NUM(path)].headersonly = 1;
+ } else if(n >= 11 && memcmp(p, "promiscuous", 11)==0){
+ if(conn[NUM(path)].prom == 0){
+ conn[NUM(path)].prom = 1;
+ //if(nprom++ == 0 && eppromiscuous != nil)
+ //(*eppromiscuous)(epctl, 1);
+ }
+ } else if(n >= 9+12 && (memcmp(p, "addmulti ", 9)==0 || memcmp(p, "remmulti ", 9)==0)){
+ uchar ea[Eaddrlen];
+ int i;
+
+ if(parseether(ea, p+9) < 0){
+ respond(r, "bad ether address");
+ return;
+ }
+ i = activemulti(ea);
+ if(i >= 0){
+ if(*p == 'r'){
+ memmove(multiaddr[i], multiaddr[--nmulti], Eaddrlen);
+ //if(epmulticast != nil)
+ // (*epmulticast)(epctl, ea, 0);
+ }
+ } else if(nmulti < nelem(multiaddr)){
+ if(*p == 'a'){
+ memmove(multiaddr[nmulti++], ea, Eaddrlen);
+ //if(epmulticast != nil)
+ // (*epmulticast)(epctl, ea, 1);
+ }
+ }
+ } else if(n > 8 && memcmp(p, "connect ", 8)==0){
+ char x[12];
+
+ if(n - 8 >= sizeof(x)){
+ respond(r, "invalid control msg");
+ return;
+ }
+
+ p += 8;
+ memcpy(x, p, n-8);
+ x[n-8] = 0;
+
+ conn[NUM(path)].type = strtoul(x, nil, 0);
+ }
+ r->ofcall.count = n;
+ respond(r, nil);
+ break;
+ case Qdata:
+ writeconndata(r);
+ break;
+ default:
+ snprint(e, sizeof e, "bug in fswrite path=%lux", path);
+ respond(r, e);
+ }
+}
+
+static void
+fsopen(Req *r)
+{
+ static int need[4] = { 4, 2, 6, 1 };
+ ulong path;
+ int i, n;
+ Tab *t;
+ Dq *d;
+ Conn *c;
+
+ /*
+ * lib9p already handles the blatantly obvious.
+ * we just have to enforce the permissions we have set.
+ */
+ path = r->fid->qid.path;
+ t = &tab[TYPE(path)];
+ n = need[r->ifcall.mode&3];
+ if((n&t->mode) != n){
+ respond(r, "permission denied");
+ return;
+ }
+
+ d = nil;
+ r->fid->aux = nil;
+
+ switch(TYPE(path)){
+ case Qclone:
+ for(i=0; i<nelem(conn); i++){
+ if(conn[i].used)
+ continue;
+ if(i >= nconn)
+ nconn = i+1;
+ path = PATH(Qctl, i);
+ goto CaseConn;
+ }
+ respond(r, "out of connections");
+ return;
+ case Qdata:
+ d = emalloc9p(sizeof(*d));
+ memset(d, 0, sizeof(*d));
+ d->qt = &d->q;
+ d->rt = &d->r;
+ r->fid->aux = d;
+ case Qndir:
+ case Qctl:
+ case Qtype:
+ CaseConn:
+ c = &conn[NUM(path)];
+ qlock(c);
+ if(c->used++ == 0){
+ c->type = 0;
+ c->prom = 0;
+ c->bridge = 0;
+ c->headersonly = 0;
+ }
+ if(d != nil){
+ d->next = c->dq;
+ c->dq = d;
+ }
+ qunlock(c);
+ break;
+ }
+
+ r->fid->qid.path = path;
+ r->ofcall.qid.path = path;
+ respond(r, nil);
+}
+
+static void
+fsflush(Req *r)
+{
+ Req *o, **p;
+ Fid *f;
+ Dq *d;
+
+ o = r->oldreq;
+ f = o->fid;
+ if(TYPE(f->qid.path) == Qdata){
+ d = f->aux;
+ qlock(d);
+ for(p=&d->r; *p; p=(Req**)&((*p)->aux)){
+ if(*p == o){
+ if((*p = (Req*)o->aux) == nil)
+ d->rt = p;
+ r->oldreq = nil;
+ respond(o, "interrupted");
+ break;
+ }
+ }
+ qunlock(d);
+ }
+ respond(r, nil);
+}
+
+
+static void
+fsdestroyfid(Fid *fid)
+{
+ Conn *c;
+ Dq **x, *d;
+ Block *b;
+
+ if(TYPE(fid->qid.path) >= Qndir){
+ c = &conn[NUM(fid->qid.path)];
+ qlock(c);
+ if(d = fid->aux){
+ fid->aux = nil;
+ for(x=&c->dq; *x; x=&((*x)->next)){
+ if(*x == d){
+ *x = d->next;
+ break;
+ }
+ }
+ while(b = d->q){
+ d->q = b->next;
+ freeb(b);
+ }
+ free(d);
+ }
+ if(TYPE(fid->qid.path) == Qctl){
+ if(c->prom){
+ c->prom = 0;
+ //if(--nprom == 0 && eppromiscuous != nil)
+ // (*eppromiscuous)(epctl, 0);
+ }
+ }
+ if(TYPE(fid->qid.path) == Qdata && c->bridge)
+ memset(mactab, 0, sizeof(mactab));
+ c->used--;
+ qunlock(c);
+ }
+}
+
+static int
+inote(void *, char *msg)
+{
+ if(strstr(msg, "interrupt"))
+ return 1;
+ return 0;
+}
+
+static void
+cpass(Conn *c, Block *bp)
+{
+ Dq *d;
+
+ qlock(c);
+ for(d = c->dq; d != nil; d = d->next){
+ qlock(d);
+ if(d->size < 100000){
+ Block *q;
+
+ if(d->next == nil) {
+ q = bp;
+ bp = nil;
+ } else
+ q = copyblock(bp, BLEN(bp));
+ q->next = nil;
+ *d->qt = q;
+ d->qt = &q->next;
+ d->size += BLEN(q);
+ matchrq(d);
+ }
+ qunlock(d);
+ }
+ qunlock(c);
+
+ if(bp != nil)
+ freeb(bp);
+}
+
+static void
+etherrtrace(Conn *c, Etherpkt *pkt, int len)
+{
+ Block *bp;
+
+ bp = allocb(64);
+ memmove(bp->wp, pkt, len < 64 ? len : 64);
+ if(c->type != -2){
+ u32int ms = nsec()/1000000LL;
+ bp->wp[58] = len>>8;
+ bp->wp[59] = len;
+ bp->wp[60] = ms>>24;
+ bp->wp[61] = ms>>16;
+ bp->wp[62] = ms>>8;
+ bp->wp[63] = ms;
+ }
+ bp->wp += 64;
+ cpass(c, bp);
+}
+
+static Macent*
+macent(uchar *ea)
+{
+ u32int h = (ea[0] | ea[1]<<8 | ea[2]<<16 | ea[3]<<24) ^ (ea[4] | ea[5]<<8);
+ return &mactab[h % nelem(mactab)];
+}
+
+static Block*
+ethermux(Block *bp, Conn *from)
+{
+ Etherpkt *pkt;
+ Conn *c, *x;
+ int len, multi, tome, port, type, dispose;
+
+ len = BLEN(bp);
+ if(len < ETHERHDRSIZE)
+ goto Drop;
+ pkt = (Etherpkt*)bp->rp;
+ if(!(multi = pkt->d[0] & 1)){
+ tome = memcmp(pkt->d, macaddr, Eaddrlen) == 0;
+ if(!tome && from != nil && nprom == 0)
+ return bp;
+ } else {
+ tome = 0;
+ if(from == nil && nprom == 0
+ && memcmp(pkt->d, bcast, Eaddrlen) != 0
+ && activemulti(pkt->d) < 0)
+ goto Drop;
+ }
+
+ port = -1;
+ if(nprom){
+ if((from == nil || from->bridge) && (pkt->s[0] & 1) == 0){
+ Macent *t = macent(pkt->s);
+ t->port = from == nil ? 0 : 1+(from - conn);
+ memmove(t->ea, pkt->s, Eaddrlen);
+ }
+ if(!tome && !multi){
+ Macent *t = macent(pkt->d);
+ if(memcmp(t->ea, pkt->d, Eaddrlen) == 0)
+ port = t->port;
+ }
+ }
+
+ x = nil;
+ type = (pkt->type[0]<<8)|pkt->type[1];
+ dispose = tome || from == nil || port > 0;
+
+ for(c = conn; c < &conn[nconn]; c++){
+ if(!c->used)
+ continue;
+ if(c->type != type && c->type >= 0)
+ continue;
+ if(!tome && !multi && !c->prom)
+ continue;
+ if(c->bridge){
+ if(tome || c == from)
+ continue;
+ if(port >= 0 && port != 1+(c - conn))
+ continue;
+ }
+ if(c->headersonly || c->type == -2){
+ etherrtrace(c, pkt, len);
+ continue;
+ }
+ if(dispose && x == nil)
+ x = c;
+ else
+ cpass(c, copyblock(bp, len));
+ }
+ if(x != nil){
+ cpass(x, bp);
+ return nil;
+ }
+
+ if(dispose){
+Drop: freeb(bp);
+ return nil;
+ }
+ return bp;
+}
+
+void
+etheriq(Block *bp)
+{
+ stats.in++;
+ ethermux(bp, nil);
+}
+
+static void
+etheroq(Block *bp, Conn *from)
+{
+ if(!from->bridge)
+ memmove(((Etherpkt*)bp->rp)->s, macaddr, Eaddrlen);
+ bp = ethermux(bp, from);
+ if(bp == nil)
+ return;
+ stats.out++;
+ /* transmit frees buffer */
+ bp->rp-=12;
+ memset(bp->rp, 0, 12);
+ write(grecon, bp->rp, BLEN(bp));
+ freeb(bp);
+}
+
+static void
+grereadproc(void *)
+{
+ char err[ERRMAX];
+ uchar buf[1600];
+ int nerr;
+ int len;
+ Block *b;
+ ushort flags;
+
+ atnotify(inote, 1);
+
+ threadsetname("grereadproc");
+
+ nerr = 0;
+ for(;;){
+ /* receive allocates buffer and calls etheriq(b, 1); */
+ if((len = read(grecon, buf, 1600)) < 0){
+ rerrstr(err, sizeof(err));
+ if(strstr(err, "interrupted") || strstr(err, "timed out"))
+ continue;
+ fprint(2, "grereadproc: %s\n", err);
+ if(++nerr < 3)
+ continue;
+ threadexitsall(err);
+ }
+ nerr = 0;
+
+ flags = nhgets(buf+8);
+ if(flags){
+ stats.bogus++;
+ continue;
+ }
+
+ b = allocb(1600);
+ memcpy(b->wp, buf+12, len-12);
+ b->wp+=(len-12);
+ etheriq(b);
+ }
+}
+
+Srv fs =
+{
+.attach= fsattach,
+.destroyfid= fsdestroyfid,
+.walk1= fswalk1,
+.open= fsopen,
+.read= fsread,
+.write= fswrite,
+.stat= fsstat,
+.flush= fsflush,
+};
+
+static void
+usage(void)
+{
+ fprint(2, "usage: %s [-dD] [-i index] [-a addr] remote\n", argv0);
+ exits("usage");
+}
+
+void
+threadmain(int argc, char **argv)
+{
+ char s[64], *t, *d;
+ int idx = 0;
+
+ fmtinstall('E', eipfmt);
+
+
+ ARGBEGIN {
+ case 'd':
+ debug = 1;
+ break;
+ case 'D':
+ chatty9p++;
+ break;
+ case 'i':
+ idx = atoi(EARGF(usage()));
+ case 'a':
+ setmac = 1;
+ if(parseether(macaddr, EARGF(usage())) != 0)
+ usage();
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if(argc != 1)
+ usage();
+
+ if(!setmac){
+ genrandom(macaddr, Eaddrlen);
+ macaddr[0] &= 0xfe;
+ }
+
+ d = smprint("gre!%s!25944", argv[0]);
+ grecon = dial(d, nil, nil, nil);
+
+ if(grecon == -1)
+ sysfatal("%r");
+
+ werrstr("");
+
+ proccreate(grereadproc, nil, 8*1024);
+
+ atnotify(inote, 1);
+ time0 = time(0);
+
+ tab[Qiface].name = smprint("etherG%d", idx);
+ snprint(s, sizeof(s), "%d.ugre", idx);
+ threadpostmountsrv(&fs, s, "/net/", MAFTER);
+
+ threadexits(0);
+}
+
+Block*
+allocb(int size)
+{
+ Block *b;
+
+ b = emalloc9p(sizeof(*b) + size);
+ b->lim = b->base + size;
+ b->rp = b->base;
+ b->wp = b->base;
+ b->next = nil;
+ return b;
+}
+
+Block*
+copyblock(Block *b, int count)
+{
+ Block *nb;
+
+ if(count > BLEN(b))
+ count = BLEN(b);
+ nb = allocb(count);
+ memmove(nb->wp, b->rp, count);
+ nb->wp += count;
+ return nb;
+}
--- a/./sys/src/cmd/ip/mkfile
+++ b/./sys/src/cmd/ip/mkfile
@@ -4,6 +4,7 @@
ayiya\
dhcp6d\
dhcpclient\
+ egre\
ftpd\
gping\
hogports\
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [9front] ethernet over gre
2023-09-23 19:50 ` Steve Simon
@ 2023-09-23 20:41 ` Arne Meyer
0 siblings, 0 replies; 7+ messages in thread
From: Arne Meyer @ 2023-09-23 20:41 UTC (permalink / raw)
To: 9front
hey Steve,
yes there is some refactoring to be done. the gre code in 9front is quite crufty and doesn't support ipv6 right now. It's next on my list.
> Steve Simon <steve@quintile.net> hat am 23.09.2023 21:50 CEST geschrieben:
>
>
> just a suggestion…
> you could refactor a bit to take the ip address in the dialstring, as implemented in telco(1).
>
> i am not sure how much more useful that would really be but it might be classed as a slightly more plan9-ey implementation.
>
> -Steve
>
>
>
>
> > On 23 Sep 2023, at 3:30 pm, Arne Meyer <meyer.arne83@netcologne.de> wrote:
> >
> > Hello,
> >
> > i finally found the time to polish up my implementation of ethernet over gre for 9front.
> > This is based on nusb/ether. It uses gre from the ip stack. I tested it with OpenBSD egre.
> > For now only ipv4 is supported for the outside of the tunnel.
> >
> > 9front:
> > ip address is 192.168.178.21
> >
> > egre 192.168.178.20
> > ip/ipconfig -m 1400 ether /net/etherG0 10.0.0.1 255.255.255.0
> >
> > OpenBSD:
> >
> > ifconfig egre0 create
> > ifconfig egre0 tunnel 192.168.178.20 192.168.178.21
> > ifconfig egre0 10.0.0.2/24 mtu 1400
> > ifconfig egre0 up
> >
> > Greetings,
> > Arnefrom postmaster@9front:
> > The following attachment had content that we can't
> > prove to be harmless. To avoid possible automatic
> > execution, we changed the content headers.
> > The original header was:
> >
> > Content-Type: text/x-c; charset=UTF-8; name=egre.c
> > Content-Transfer-Encoding: base64
> > Content-Disposition: attachment; filename=egre.c
> > <egre.c.suspect>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2023-09-23 20:43 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-23 14:26 [9front] ethernet over gre Arne Meyer
2023-09-23 15:32 ` Jacob Moody
2023-09-23 15:46 ` Arne Meyer
2023-09-23 15:56 ` Jacob Moody
2023-09-23 20:33 ` Arne Meyer
2023-09-23 19:50 ` Steve Simon
2023-09-23 20:41 ` Arne Meyer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).