1ac020a8fSDavid du Colombier /*
2ac020a8fSDavid du Colombier * IPv4 Ethernet bridge
3ac020a8fSDavid du Colombier */
47dd7cddfSDavid du Colombier #include "u.h"
57dd7cddfSDavid du Colombier #include "../port/lib.h"
67dd7cddfSDavid du Colombier #include "mem.h"
77dd7cddfSDavid du Colombier #include "dat.h"
87dd7cddfSDavid du Colombier #include "fns.h"
9ac020a8fSDavid du Colombier #include "../ip/ip.h"
107dd7cddfSDavid du Colombier #include "../port/netif.h"
117dd7cddfSDavid du Colombier #include "../port/error.h"
127dd7cddfSDavid du Colombier
137dd7cddfSDavid du Colombier typedef struct Bridge Bridge;
147dd7cddfSDavid du Colombier typedef struct Port Port;
157dd7cddfSDavid du Colombier typedef struct Centry Centry;
167dd7cddfSDavid du Colombier typedef struct Iphdr Iphdr;
177dd7cddfSDavid du Colombier typedef struct Tcphdr Tcphdr;
187dd7cddfSDavid du Colombier
197dd7cddfSDavid du Colombier enum
207dd7cddfSDavid du Colombier {
217dd7cddfSDavid du Colombier Qtopdir= 1, /* top level directory */
227dd7cddfSDavid du Colombier
237dd7cddfSDavid du Colombier Qbridgedir, /* bridge* directory */
247dd7cddfSDavid du Colombier Qbctl,
257dd7cddfSDavid du Colombier Qstats,
267dd7cddfSDavid du Colombier Qcache,
277dd7cddfSDavid du Colombier Qlog,
287dd7cddfSDavid du Colombier
297dd7cddfSDavid du Colombier Qportdir, /* directory for a protocol */
307dd7cddfSDavid du Colombier Qpctl,
317dd7cddfSDavid du Colombier Qlocal,
327dd7cddfSDavid du Colombier Qstatus,
337dd7cddfSDavid du Colombier
347dd7cddfSDavid du Colombier MaxQ,
357dd7cddfSDavid du Colombier
367dd7cddfSDavid du Colombier Maxbridge= 4,
379a747e4fSDavid du Colombier Maxport= 128, // power of 2
387dd7cddfSDavid du Colombier CacheHash= 257, // prime
397dd7cddfSDavid du Colombier CacheLook= 5, // how many cache entries to examine
407dd7cddfSDavid du Colombier CacheSize= (CacheHash+CacheLook-1),
417dd7cddfSDavid du Colombier CacheTimeout= 5*60, // timeout for cache entry in seconds
42*a129eb93SDavid du Colombier MaxMTU= IP_MAX, // allow for jumbo frames and large UDP
437dd7cddfSDavid du Colombier
447dd7cddfSDavid du Colombier TcpMssMax = 1300, // max desirable Tcp MSS value
457dd7cddfSDavid du Colombier TunnelMtu = 1400,
467dd7cddfSDavid du Colombier };
477dd7cddfSDavid du Colombier
487dd7cddfSDavid du Colombier static Dirtab bridgedirtab[]={
497dd7cddfSDavid du Colombier "ctl", {Qbctl}, 0, 0666,
507dd7cddfSDavid du Colombier "stats", {Qstats}, 0, 0444,
517dd7cddfSDavid du Colombier "cache", {Qcache}, 0, 0444,
527dd7cddfSDavid du Colombier "log", {Qlog}, 0, 0666,
537dd7cddfSDavid du Colombier };
547dd7cddfSDavid du Colombier
557dd7cddfSDavid du Colombier static Dirtab portdirtab[]={
567dd7cddfSDavid du Colombier "ctl", {Qpctl}, 0, 0666,
577dd7cddfSDavid du Colombier "local", {Qlocal}, 0, 0444,
587dd7cddfSDavid du Colombier "status", {Qstatus}, 0, 0444,
597dd7cddfSDavid du Colombier };
607dd7cddfSDavid du Colombier
617dd7cddfSDavid du Colombier enum {
627dd7cddfSDavid du Colombier Logcache= (1<<0),
637dd7cddfSDavid du Colombier Logmcast= (1<<1),
647dd7cddfSDavid du Colombier };
657dd7cddfSDavid du Colombier
667dd7cddfSDavid du Colombier // types of interfaces
677dd7cddfSDavid du Colombier enum
687dd7cddfSDavid du Colombier {
697dd7cddfSDavid du Colombier Tether,
707dd7cddfSDavid du Colombier Ttun,
717dd7cddfSDavid du Colombier };
727dd7cddfSDavid du Colombier
737dd7cddfSDavid du Colombier static Logflag logflags[] =
747dd7cddfSDavid du Colombier {
757dd7cddfSDavid du Colombier { "cache", Logcache, },
767dd7cddfSDavid du Colombier { "multicast", Logmcast, },
777dd7cddfSDavid du Colombier { nil, 0, },
787dd7cddfSDavid du Colombier };
797dd7cddfSDavid du Colombier
807dd7cddfSDavid du Colombier static Dirtab *dirtab[MaxQ];
817dd7cddfSDavid du Colombier
829a747e4fSDavid du Colombier #define TYPE(x) (((ulong)(x).path) & 0xff)
839a747e4fSDavid du Colombier #define PORT(x) ((((ulong)(x).path) >> 8)&(Maxport-1))
847dd7cddfSDavid du Colombier #define QID(x, y) (((x)<<8) | (y))
857dd7cddfSDavid du Colombier
867dd7cddfSDavid du Colombier struct Centry
877dd7cddfSDavid du Colombier {
887dd7cddfSDavid du Colombier uchar d[Eaddrlen];
897dd7cddfSDavid du Colombier int port;
90ac020a8fSDavid du Colombier long expire; // entry expires this many seconds after bootime
917dd7cddfSDavid du Colombier long src;
927dd7cddfSDavid du Colombier long dst;
937dd7cddfSDavid du Colombier };
947dd7cddfSDavid du Colombier
957dd7cddfSDavid du Colombier struct Bridge
967dd7cddfSDavid du Colombier {
977dd7cddfSDavid du Colombier QLock;
987dd7cddfSDavid du Colombier int nport;
997dd7cddfSDavid du Colombier Port *port[Maxport];
1007dd7cddfSDavid du Colombier Centry cache[CacheSize];
1017dd7cddfSDavid du Colombier ulong hit;
1027dd7cddfSDavid du Colombier ulong miss;
1037dd7cddfSDavid du Colombier ulong copy;
1047dd7cddfSDavid du Colombier long delay0; // constant microsecond delay per packet
1057dd7cddfSDavid du Colombier long delayn; // microsecond delay per byte
1067dd7cddfSDavid du Colombier int tcpmss; // modify tcpmss value
1077dd7cddfSDavid du Colombier
1087dd7cddfSDavid du Colombier Log;
1097dd7cddfSDavid du Colombier };
1107dd7cddfSDavid du Colombier
1117dd7cddfSDavid du Colombier struct Port
1127dd7cddfSDavid du Colombier {
113*a129eb93SDavid du Colombier Ref;
1147dd7cddfSDavid du Colombier int id;
1157dd7cddfSDavid du Colombier Bridge *bridge;
1167dd7cddfSDavid du Colombier int closed;
1177dd7cddfSDavid du Colombier
1187dd7cddfSDavid du Colombier Chan *data[2]; // channel to data
1197dd7cddfSDavid du Colombier
1207dd7cddfSDavid du Colombier Proc *readp; // read proc
1217dd7cddfSDavid du Colombier
1227dd7cddfSDavid du Colombier // the following uniquely identifies the port
1237dd7cddfSDavid du Colombier int type;
1249a747e4fSDavid du Colombier char name[KNAMELEN];
1257dd7cddfSDavid du Colombier
1267dd7cddfSDavid du Colombier // owner hash - avoids bind/unbind races
1277dd7cddfSDavid du Colombier ulong ownhash;
1287dd7cddfSDavid du Colombier
1297dd7cddfSDavid du Colombier // various stats
1307dd7cddfSDavid du Colombier int in; // number of packets read
1317dd7cddfSDavid du Colombier int inmulti; // multicast or broadcast
1327dd7cddfSDavid du Colombier int inunknown; // unknown address
1337dd7cddfSDavid du Colombier int out; // number of packets read
1347dd7cddfSDavid du Colombier int outmulti; // multicast or broadcast
1357dd7cddfSDavid du Colombier int outunknown; // unknown address
1367dd7cddfSDavid du Colombier int outfrag; // fragmented the packet
1377dd7cddfSDavid du Colombier int nentry; // number of cache entries for this port
1387dd7cddfSDavid du Colombier };
1397dd7cddfSDavid du Colombier
1407dd7cddfSDavid du Colombier enum {
1417dd7cddfSDavid du Colombier IP_TCPPROTO = 6,
1427dd7cddfSDavid du Colombier EOLOPT = 0,
1437dd7cddfSDavid du Colombier NOOPOPT = 1,
1447dd7cddfSDavid du Colombier MSSOPT = 2,
1457dd7cddfSDavid du Colombier MSS_LENGTH = 4, /* Mean segment size */
1467dd7cddfSDavid du Colombier SYN = 0x02, /* Pkt. is synchronise */
1477dd7cddfSDavid du Colombier IPHDR = 20, /* sizeof(Iphdr) */
1487dd7cddfSDavid du Colombier };
1497dd7cddfSDavid du Colombier
1507dd7cddfSDavid du Colombier struct Iphdr
1517dd7cddfSDavid du Colombier {
1527dd7cddfSDavid du Colombier uchar vihl; /* Version and header length */
1537dd7cddfSDavid du Colombier uchar tos; /* Type of service */
1547dd7cddfSDavid du Colombier uchar length[2]; /* packet length */
1557dd7cddfSDavid du Colombier uchar id[2]; /* ip->identification */
1567dd7cddfSDavid du Colombier uchar frag[2]; /* Fragment information */
1577dd7cddfSDavid du Colombier uchar ttl; /* Time to live */
1587dd7cddfSDavid du Colombier uchar proto; /* Protocol */
1597dd7cddfSDavid du Colombier uchar cksum[2]; /* Header checksum */
1607dd7cddfSDavid du Colombier uchar src[4]; /* IP source */
1617dd7cddfSDavid du Colombier uchar dst[4]; /* IP destination */
1627dd7cddfSDavid du Colombier };
1637dd7cddfSDavid du Colombier
1647dd7cddfSDavid du Colombier struct Tcphdr
1657dd7cddfSDavid du Colombier {
1667dd7cddfSDavid du Colombier uchar sport[2];
1677dd7cddfSDavid du Colombier uchar dport[2];
1687dd7cddfSDavid du Colombier uchar seq[4];
1697dd7cddfSDavid du Colombier uchar ack[4];
1707dd7cddfSDavid du Colombier uchar flag[2];
1717dd7cddfSDavid du Colombier uchar win[2];
1727dd7cddfSDavid du Colombier uchar cksum[2];
1737dd7cddfSDavid du Colombier uchar urg[2];
1747dd7cddfSDavid du Colombier };
1757dd7cddfSDavid du Colombier
1767dd7cddfSDavid du Colombier static Bridge bridgetab[Maxbridge];
1777dd7cddfSDavid du Colombier
1787dd7cddfSDavid du Colombier static int m2p[] = {
1797dd7cddfSDavid du Colombier [OREAD] 4,
1807dd7cddfSDavid du Colombier [OWRITE] 2,
1817dd7cddfSDavid du Colombier [ORDWR] 6
1827dd7cddfSDavid du Colombier };
1837dd7cddfSDavid du Colombier
1849a747e4fSDavid du Colombier static int bridgegen(Chan *c, char*, Dirtab*, int, int s, Dir *dp);
1857dd7cddfSDavid du Colombier static void portbind(Bridge *b, int argc, char *argv[]);
1867dd7cddfSDavid du Colombier static void portunbind(Bridge *b, int argc, char *argv[]);
1877dd7cddfSDavid du Colombier static void etherread(void *a);
1887dd7cddfSDavid du Colombier static char *cachedump(Bridge *b);
1897dd7cddfSDavid du Colombier static void portfree(Port *port);
1907dd7cddfSDavid du Colombier static void cacheflushport(Bridge *b, int port);
1917dd7cddfSDavid du Colombier static void etherwrite(Port *port, Block *bp);
1927dd7cddfSDavid du Colombier
1937dd7cddfSDavid du Colombier static void
bridgeinit(void)1947dd7cddfSDavid du Colombier bridgeinit(void)
1957dd7cddfSDavid du Colombier {
1967dd7cddfSDavid du Colombier int i;
1977dd7cddfSDavid du Colombier Dirtab *dt;
198ac020a8fSDavid du Colombier
1997dd7cddfSDavid du Colombier // setup dirtab with non directory entries
2007dd7cddfSDavid du Colombier for(i=0; i<nelem(bridgedirtab); i++) {
2017dd7cddfSDavid du Colombier dt = bridgedirtab + i;
2027dd7cddfSDavid du Colombier dirtab[TYPE(dt->qid)] = dt;
2037dd7cddfSDavid du Colombier }
2047dd7cddfSDavid du Colombier for(i=0; i<nelem(portdirtab); i++) {
2057dd7cddfSDavid du Colombier dt = portdirtab + i;
2067dd7cddfSDavid du Colombier dirtab[TYPE(dt->qid)] = dt;
2077dd7cddfSDavid du Colombier }
2087dd7cddfSDavid du Colombier }
2097dd7cddfSDavid du Colombier
2107dd7cddfSDavid du Colombier static Chan*
bridgeattach(char * spec)2117dd7cddfSDavid du Colombier bridgeattach(char* spec)
2127dd7cddfSDavid du Colombier {
2137dd7cddfSDavid du Colombier Chan *c;
2147dd7cddfSDavid du Colombier int dev;
2157dd7cddfSDavid du Colombier
2167dd7cddfSDavid du Colombier dev = atoi(spec);
2177dd7cddfSDavid du Colombier if(dev<0 || dev >= Maxbridge)
2187dd7cddfSDavid du Colombier error("bad specification");
2197dd7cddfSDavid du Colombier
2207dd7cddfSDavid du Colombier c = devattach('B', spec);
2219a747e4fSDavid du Colombier mkqid(&c->qid, QID(0, Qtopdir), 0, QTDIR);
2227dd7cddfSDavid du Colombier c->dev = dev;
2237dd7cddfSDavid du Colombier return c;
2247dd7cddfSDavid du Colombier }
2257dd7cddfSDavid du Colombier
2269a747e4fSDavid du Colombier static Walkqid*
bridgewalk(Chan * c,Chan * nc,char ** name,int nname)2279a747e4fSDavid du Colombier bridgewalk(Chan *c, Chan *nc, char **name, int nname)
2287dd7cddfSDavid du Colombier {
2299a747e4fSDavid du Colombier return devwalk(c, nc, name, nname, (Dirtab*)0, 0, bridgegen);
2307dd7cddfSDavid du Colombier }
2317dd7cddfSDavid du Colombier
2329a747e4fSDavid du Colombier static int
bridgestat(Chan * c,uchar * db,int n)2339a747e4fSDavid du Colombier bridgestat(Chan* c, uchar* db, int n)
2347dd7cddfSDavid du Colombier {
2359a747e4fSDavid du Colombier return devstat(c, db, n, (Dirtab *)0, 0L, bridgegen);
2367dd7cddfSDavid du Colombier }
2377dd7cddfSDavid du Colombier
2387dd7cddfSDavid du Colombier static Chan*
bridgeopen(Chan * c,int omode)2397dd7cddfSDavid du Colombier bridgeopen(Chan* c, int omode)
2407dd7cddfSDavid du Colombier {
2417dd7cddfSDavid du Colombier int perm;
2427dd7cddfSDavid du Colombier Bridge *b;
2437dd7cddfSDavid du Colombier
2447dd7cddfSDavid du Colombier omode &= 3;
2457dd7cddfSDavid du Colombier perm = m2p[omode];
2467dd7cddfSDavid du Colombier USED(perm);
2477dd7cddfSDavid du Colombier
2487dd7cddfSDavid du Colombier b = bridgetab + c->dev;
2497dd7cddfSDavid du Colombier USED(b);
2507dd7cddfSDavid du Colombier
2517dd7cddfSDavid du Colombier switch(TYPE(c->qid)) {
2527dd7cddfSDavid du Colombier default:
2537dd7cddfSDavid du Colombier break;
2547dd7cddfSDavid du Colombier case Qlog:
2557dd7cddfSDavid du Colombier logopen(b);
2567dd7cddfSDavid du Colombier break;
2577dd7cddfSDavid du Colombier case Qcache:
2587dd7cddfSDavid du Colombier c->aux = cachedump(b);
2597dd7cddfSDavid du Colombier break;
2607dd7cddfSDavid du Colombier }
2617dd7cddfSDavid du Colombier c->mode = openmode(omode);
2627dd7cddfSDavid du Colombier c->flag |= COPEN;
2637dd7cddfSDavid du Colombier c->offset = 0;
2647dd7cddfSDavid du Colombier return c;
2657dd7cddfSDavid du Colombier }
2667dd7cddfSDavid du Colombier
2677dd7cddfSDavid du Colombier static void
bridgeclose(Chan * c)2687dd7cddfSDavid du Colombier bridgeclose(Chan* c)
2697dd7cddfSDavid du Colombier {
2707dd7cddfSDavid du Colombier Bridge *b = bridgetab + c->dev;
2717dd7cddfSDavid du Colombier
2727dd7cddfSDavid du Colombier switch(TYPE(c->qid)) {
2737dd7cddfSDavid du Colombier case Qcache:
2747dd7cddfSDavid du Colombier if(c->flag & COPEN)
2757dd7cddfSDavid du Colombier free(c->aux);
2767dd7cddfSDavid du Colombier break;
2777dd7cddfSDavid du Colombier case Qlog:
2787dd7cddfSDavid du Colombier if(c->flag & COPEN)
2797dd7cddfSDavid du Colombier logclose(b);
2807dd7cddfSDavid du Colombier break;
2817dd7cddfSDavid du Colombier }
2827dd7cddfSDavid du Colombier }
2837dd7cddfSDavid du Colombier
2847dd7cddfSDavid du Colombier static long
bridgeread(Chan * c,void * a,long n,vlong off)2857dd7cddfSDavid du Colombier bridgeread(Chan *c, void *a, long n, vlong off)
2867dd7cddfSDavid du Colombier {
2877dd7cddfSDavid du Colombier char buf[256];
2887dd7cddfSDavid du Colombier Bridge *b = bridgetab + c->dev;
2897dd7cddfSDavid du Colombier Port *port;
2907dd7cddfSDavid du Colombier int i, ingood, outgood;
2917dd7cddfSDavid du Colombier
2927dd7cddfSDavid du Colombier USED(off);
2937dd7cddfSDavid du Colombier switch(TYPE(c->qid)) {
2947dd7cddfSDavid du Colombier default:
295*a129eb93SDavid du Colombier error(Egreg);
2967dd7cddfSDavid du Colombier case Qtopdir:
2977dd7cddfSDavid du Colombier case Qbridgedir:
2987dd7cddfSDavid du Colombier case Qportdir:
2997dd7cddfSDavid du Colombier return devdirread(c, a, n, 0, 0, bridgegen);
3007dd7cddfSDavid du Colombier case Qlog:
3017dd7cddfSDavid du Colombier return logread(b, a, off, n);
302*a129eb93SDavid du Colombier case Qlocal:
303*a129eb93SDavid du Colombier return 0; /* TO DO */
3047dd7cddfSDavid du Colombier case Qstatus:
3057dd7cddfSDavid du Colombier qlock(b);
306*a129eb93SDavid du Colombier if(waserror()){
307*a129eb93SDavid du Colombier qunlock(b);
308*a129eb93SDavid du Colombier nexterror();
309*a129eb93SDavid du Colombier }
3107dd7cddfSDavid du Colombier port = b->port[PORT(c->qid)];
3117dd7cddfSDavid du Colombier if(port == 0)
3127dd7cddfSDavid du Colombier strcpy(buf, "unbound\n");
3137dd7cddfSDavid du Colombier else {
3147dd7cddfSDavid du Colombier i = 0;
3157dd7cddfSDavid du Colombier switch(port->type) {
316ac020a8fSDavid du Colombier default:
317ac020a8fSDavid du Colombier panic("bridgeread: unknown port type: %d",
318ac020a8fSDavid du Colombier port->type);
3197dd7cddfSDavid du Colombier case Tether:
3207dd7cddfSDavid du Colombier i += snprint(buf+i, sizeof(buf)-i, "ether %s: ", port->name);
3217dd7cddfSDavid du Colombier break;
3227dd7cddfSDavid du Colombier case Ttun:
3237dd7cddfSDavid du Colombier i += snprint(buf+i, sizeof(buf)-i, "tunnel %s: ", port->name);
3247dd7cddfSDavid du Colombier break;
3257dd7cddfSDavid du Colombier }
3267dd7cddfSDavid du Colombier ingood = port->in - port->inmulti - port->inunknown;
3277dd7cddfSDavid du Colombier outgood = port->out - port->outmulti - port->outunknown;
328*a129eb93SDavid du Colombier snprint(buf+i, sizeof(buf)-i,
329ac020a8fSDavid du Colombier "in=%d(%d:%d:%d) out=%d(%d:%d:%d:%d)\n",
3307dd7cddfSDavid du Colombier port->in, ingood, port->inmulti, port->inunknown,
331ac020a8fSDavid du Colombier port->out, outgood, port->outmulti,
332ac020a8fSDavid du Colombier port->outunknown, port->outfrag);
3337dd7cddfSDavid du Colombier }
334*a129eb93SDavid du Colombier poperror();
3357dd7cddfSDavid du Colombier qunlock(b);
336*a129eb93SDavid du Colombier return readstr(off, a, n, buf);
3377dd7cddfSDavid du Colombier case Qbctl:
3386c0968e3SDavid du Colombier snprint(buf, sizeof(buf), "%s tcpmss\ndelay %ld %ld\n",
3396c0968e3SDavid du Colombier b->tcpmss ? "set" : "clear", b->delay0, b->delayn);
3407dd7cddfSDavid du Colombier n = readstr(off, a, n, buf);
3417dd7cddfSDavid du Colombier return n;
3427dd7cddfSDavid du Colombier case Qcache:
3437dd7cddfSDavid du Colombier n = readstr(off, a, n, c->aux);
3447dd7cddfSDavid du Colombier return n;
3457dd7cddfSDavid du Colombier case Qstats:
3467dd7cddfSDavid du Colombier snprint(buf, sizeof(buf), "hit=%uld miss=%uld copy=%uld\n",
3477dd7cddfSDavid du Colombier b->hit, b->miss, b->copy);
3487dd7cddfSDavid du Colombier n = readstr(off, a, n, buf);
3497dd7cddfSDavid du Colombier return n;
3507dd7cddfSDavid du Colombier }
3517dd7cddfSDavid du Colombier }
3527dd7cddfSDavid du Colombier
3537dd7cddfSDavid du Colombier static void
bridgeoption(Bridge * b,char * option,int value)3547dd7cddfSDavid du Colombier bridgeoption(Bridge *b, char *option, int value)
3557dd7cddfSDavid du Colombier {
3567dd7cddfSDavid du Colombier if(strcmp(option, "tcpmss") == 0)
3577dd7cddfSDavid du Colombier b->tcpmss = value;
3587dd7cddfSDavid du Colombier else
3597dd7cddfSDavid du Colombier error("unknown bridge option");
3607dd7cddfSDavid du Colombier }
3617dd7cddfSDavid du Colombier
3627dd7cddfSDavid du Colombier
3637dd7cddfSDavid du Colombier static long
bridgewrite(Chan * c,void * a,long n,vlong off)3647dd7cddfSDavid du Colombier bridgewrite(Chan *c, void *a, long n, vlong off)
3657dd7cddfSDavid du Colombier {
3667dd7cddfSDavid du Colombier Bridge *b = bridgetab + c->dev;
3677dd7cddfSDavid du Colombier Cmdbuf *cb;
368ac020a8fSDavid du Colombier char *arg0, *p;
3697dd7cddfSDavid du Colombier
3707dd7cddfSDavid du Colombier USED(off);
3717dd7cddfSDavid du Colombier switch(TYPE(c->qid)) {
3727dd7cddfSDavid du Colombier default:
3737dd7cddfSDavid du Colombier error(Eperm);
3747dd7cddfSDavid du Colombier case Qbctl:
3757dd7cddfSDavid du Colombier cb = parsecmd(a, n);
3767dd7cddfSDavid du Colombier qlock(b);
3777dd7cddfSDavid du Colombier if(waserror()) {
3787dd7cddfSDavid du Colombier qunlock(b);
3797dd7cddfSDavid du Colombier free(cb);
3807dd7cddfSDavid du Colombier nexterror();
3817dd7cddfSDavid du Colombier }
3827dd7cddfSDavid du Colombier if(cb->nf == 0)
3837dd7cddfSDavid du Colombier error("short write");
3847dd7cddfSDavid du Colombier arg0 = cb->f[0];
3857dd7cddfSDavid du Colombier if(strcmp(arg0, "bind") == 0) {
3867dd7cddfSDavid du Colombier portbind(b, cb->nf-1, cb->f+1);
3877dd7cddfSDavid du Colombier } else if(strcmp(arg0, "unbind") == 0) {
3887dd7cddfSDavid du Colombier portunbind(b, cb->nf-1, cb->f+1);
3897dd7cddfSDavid du Colombier } else if(strcmp(arg0, "cacheflush") == 0) {
3907dd7cddfSDavid du Colombier log(b, Logcache, "cache flush\n");
3917dd7cddfSDavid du Colombier memset(b->cache, 0, CacheSize*sizeof(Centry));
3927dd7cddfSDavid du Colombier } else if(strcmp(arg0, "set") == 0) {
3937dd7cddfSDavid du Colombier if(cb->nf != 2)
3947dd7cddfSDavid du Colombier error("usage: set option");
3957dd7cddfSDavid du Colombier bridgeoption(b, cb->f[1], 1);
3967dd7cddfSDavid du Colombier } else if(strcmp(arg0, "clear") == 0) {
3977dd7cddfSDavid du Colombier if(cb->nf != 2)
3987dd7cddfSDavid du Colombier error("usage: clear option");
3997dd7cddfSDavid du Colombier bridgeoption(b, cb->f[1], 0);
4007dd7cddfSDavid du Colombier } else if(strcmp(arg0, "delay") == 0) {
4017dd7cddfSDavid du Colombier if(cb->nf != 3)
4027dd7cddfSDavid du Colombier error("usage: delay delay0 delayn");
4037dd7cddfSDavid du Colombier b->delay0 = strtol(cb->f[1], nil, 10);
4047dd7cddfSDavid du Colombier b->delayn = strtol(cb->f[2], nil, 10);
4057dd7cddfSDavid du Colombier } else
4067dd7cddfSDavid du Colombier error("unknown control request");
4077dd7cddfSDavid du Colombier poperror();
4087dd7cddfSDavid du Colombier qunlock(b);
4097dd7cddfSDavid du Colombier free(cb);
4107dd7cddfSDavid du Colombier return n;
4117dd7cddfSDavid du Colombier case Qlog:
4127dd7cddfSDavid du Colombier cb = parsecmd(a, n);
4137dd7cddfSDavid du Colombier p = logctl(b, cb->nf, cb->f, logflags);
4147dd7cddfSDavid du Colombier free(cb);
4157dd7cddfSDavid du Colombier if(p != nil)
4167dd7cddfSDavid du Colombier error(p);
4177dd7cddfSDavid du Colombier return n;
4187dd7cddfSDavid du Colombier }
4197dd7cddfSDavid du Colombier }
4207dd7cddfSDavid du Colombier
4217dd7cddfSDavid du Colombier static int
bridgegen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)4229a747e4fSDavid du Colombier bridgegen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
4237dd7cddfSDavid du Colombier {
4247dd7cddfSDavid du Colombier Bridge *b = bridgetab + c->dev;
4257dd7cddfSDavid du Colombier int type = TYPE(c->qid);
4267dd7cddfSDavid du Colombier Dirtab *dt;
4277dd7cddfSDavid du Colombier Qid qid;
4287dd7cddfSDavid du Colombier
4297dd7cddfSDavid du Colombier if(s == DEVDOTDOT){
4307dd7cddfSDavid du Colombier switch(TYPE(c->qid)){
4317dd7cddfSDavid du Colombier case Qtopdir:
4327dd7cddfSDavid du Colombier case Qbridgedir:
4339a747e4fSDavid du Colombier snprint(up->genbuf, sizeof(up->genbuf), "#B%ld", c->dev);
4349a747e4fSDavid du Colombier mkqid(&qid, Qtopdir, 0, QTDIR);
4359a747e4fSDavid du Colombier devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
4367dd7cddfSDavid du Colombier break;
4377dd7cddfSDavid du Colombier case Qportdir:
4389a747e4fSDavid du Colombier snprint(up->genbuf, sizeof(up->genbuf), "bridge%ld", c->dev);
4399a747e4fSDavid du Colombier mkqid(&qid, Qbridgedir, 0, QTDIR);
4409a747e4fSDavid du Colombier devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
4417dd7cddfSDavid du Colombier break;
4427dd7cddfSDavid du Colombier default:
4439a747e4fSDavid du Colombier panic("bridgewalk %llux", c->qid.path);
4447dd7cddfSDavid du Colombier }
4457dd7cddfSDavid du Colombier return 1;
4467dd7cddfSDavid du Colombier }
4477dd7cddfSDavid du Colombier
4487dd7cddfSDavid du Colombier switch(type) {
4497dd7cddfSDavid du Colombier default:
450ac020a8fSDavid du Colombier /* non-directory entries end up here */
4519a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
4527dd7cddfSDavid du Colombier panic("bridgegen: unexpected directory");
4537dd7cddfSDavid du Colombier if(s != 0)
4547dd7cddfSDavid du Colombier return -1;
4557dd7cddfSDavid du Colombier dt = dirtab[TYPE(c->qid)];
4567dd7cddfSDavid du Colombier if(dt == nil)
4579a747e4fSDavid du Colombier panic("bridgegen: unknown type: %lud", TYPE(c->qid));
4587dd7cddfSDavid du Colombier devdir(c, c->qid, dt->name, dt->length, eve, dt->perm, dp);
4597dd7cddfSDavid du Colombier return 1;
4607dd7cddfSDavid du Colombier case Qtopdir:
4617dd7cddfSDavid du Colombier if(s != 0)
4627dd7cddfSDavid du Colombier return -1;
4639a747e4fSDavid du Colombier snprint(up->genbuf, sizeof(up->genbuf), "bridge%ld", c->dev);
4649a747e4fSDavid du Colombier mkqid(&qid, QID(0, Qbridgedir), 0, QTDIR);
4659a747e4fSDavid du Colombier devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
4667dd7cddfSDavid du Colombier return 1;
4677dd7cddfSDavid du Colombier case Qbridgedir:
4687dd7cddfSDavid du Colombier if(s<nelem(bridgedirtab)) {
4697dd7cddfSDavid du Colombier dt = bridgedirtab+s;
4707dd7cddfSDavid du Colombier devdir(c, dt->qid, dt->name, dt->length, eve, dt->perm, dp);
4717dd7cddfSDavid du Colombier return 1;
4727dd7cddfSDavid du Colombier }
4737dd7cddfSDavid du Colombier s -= nelem(bridgedirtab);
4747dd7cddfSDavid du Colombier if(s >= b->nport)
4757dd7cddfSDavid du Colombier return -1;
4769a747e4fSDavid du Colombier mkqid(&qid, QID(s, Qportdir), 0, QTDIR);
4779a747e4fSDavid du Colombier snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
4789a747e4fSDavid du Colombier devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
4797dd7cddfSDavid du Colombier return 1;
4807dd7cddfSDavid du Colombier case Qportdir:
4817dd7cddfSDavid du Colombier if(s>=nelem(portdirtab))
4827dd7cddfSDavid du Colombier return -1;
4837dd7cddfSDavid du Colombier dt = portdirtab+s;
4849a747e4fSDavid du Colombier mkqid(&qid, QID(PORT(c->qid),TYPE(dt->qid)), 0, QTFILE);
4857dd7cddfSDavid du Colombier devdir(c, qid, dt->name, dt->length, eve, dt->perm, dp);
4867dd7cddfSDavid du Colombier return 1;
4877dd7cddfSDavid du Colombier }
4887dd7cddfSDavid du Colombier }
4897dd7cddfSDavid du Colombier
490ac020a8fSDavid du Colombier // parse mac address; also in netif.c
4917dd7cddfSDavid du Colombier static int
parseaddr(uchar * to,char * from,int alen)4927dd7cddfSDavid du Colombier parseaddr(uchar *to, char *from, int alen)
4937dd7cddfSDavid du Colombier {
4947dd7cddfSDavid du Colombier char nip[4];
4957dd7cddfSDavid du Colombier char *p;
4967dd7cddfSDavid du Colombier int i;
4977dd7cddfSDavid du Colombier
4987dd7cddfSDavid du Colombier p = from;
4997dd7cddfSDavid du Colombier for(i = 0; i < alen; i++){
5007dd7cddfSDavid du Colombier if(*p == 0)
5017dd7cddfSDavid du Colombier return -1;
5027dd7cddfSDavid du Colombier nip[0] = *p++;
5037dd7cddfSDavid du Colombier if(*p == 0)
5047dd7cddfSDavid du Colombier return -1;
5057dd7cddfSDavid du Colombier nip[1] = *p++;
5067dd7cddfSDavid du Colombier nip[2] = 0;
5077dd7cddfSDavid du Colombier to[i] = strtoul(nip, 0, 16);
5087dd7cddfSDavid du Colombier if(*p == ':')
5097dd7cddfSDavid du Colombier p++;
5107dd7cddfSDavid du Colombier }
5117dd7cddfSDavid du Colombier return 0;
5127dd7cddfSDavid du Colombier }
5137dd7cddfSDavid du Colombier
5147dd7cddfSDavid du Colombier // assumes b is locked
5157dd7cddfSDavid du Colombier static void
portbind(Bridge * b,int argc,char * argv[])5167dd7cddfSDavid du Colombier portbind(Bridge *b, int argc, char *argv[])
5177dd7cddfSDavid du Colombier {
5187dd7cddfSDavid du Colombier Port *port;
5197dd7cddfSDavid du Colombier Chan *ctl;
5207dd7cddfSDavid du Colombier int type = 0, i, n;
5217dd7cddfSDavid du Colombier ulong ownhash;
522*a129eb93SDavid du Colombier char *dev, *dev2 = nil;
523ac020a8fSDavid du Colombier char buf[100], name[KNAMELEN], path[8*KNAMELEN];
524ac020a8fSDavid du Colombier static char usage[] = "usage: bind ether|tunnel name ownhash dev [dev2]";
5257dd7cddfSDavid du Colombier
5269a747e4fSDavid du Colombier memset(name, 0, KNAMELEN);
5277dd7cddfSDavid du Colombier if(argc < 4)
5287dd7cddfSDavid du Colombier error(usage);
5297dd7cddfSDavid du Colombier if(strcmp(argv[0], "ether") == 0) {
5307dd7cddfSDavid du Colombier if(argc != 4)
5317dd7cddfSDavid du Colombier error(usage);
5327dd7cddfSDavid du Colombier type = Tether;
5339a747e4fSDavid du Colombier strncpy(name, argv[1], KNAMELEN);
5349a747e4fSDavid du Colombier name[KNAMELEN-1] = 0;
5357dd7cddfSDavid du Colombier // parseaddr(addr, argv[1], Eaddrlen);
5367dd7cddfSDavid du Colombier } else if(strcmp(argv[0], "tunnel") == 0) {
5377dd7cddfSDavid du Colombier if(argc != 5)
5387dd7cddfSDavid du Colombier error(usage);
5397dd7cddfSDavid du Colombier type = Ttun;
5409a747e4fSDavid du Colombier strncpy(name, argv[1], KNAMELEN);
5419a747e4fSDavid du Colombier name[KNAMELEN-1] = 0;
5427dd7cddfSDavid du Colombier // parseip(addr, argv[1]);
5437dd7cddfSDavid du Colombier dev2 = argv[4];
5447dd7cddfSDavid du Colombier } else
5457dd7cddfSDavid du Colombier error(usage);
5467dd7cddfSDavid du Colombier ownhash = atoi(argv[2]);
5477dd7cddfSDavid du Colombier dev = argv[3];
5487dd7cddfSDavid du Colombier for(i=0; i<b->nport; i++) {
5497dd7cddfSDavid du Colombier port = b->port[i];
550ac020a8fSDavid du Colombier if(port != nil && port->type == type &&
551ac020a8fSDavid du Colombier memcmp(port->name, name, KNAMELEN) == 0)
5527dd7cddfSDavid du Colombier error("port in use");
5537dd7cddfSDavid du Colombier }
5547dd7cddfSDavid du Colombier for(i=0; i<Maxport; i++)
5557dd7cddfSDavid du Colombier if(b->port[i] == nil)
5567dd7cddfSDavid du Colombier break;
5577dd7cddfSDavid du Colombier if(i == Maxport)
5587dd7cddfSDavid du Colombier error("no more ports");
5597dd7cddfSDavid du Colombier port = smalloc(sizeof(Port));
5607dd7cddfSDavid du Colombier port->ref = 1;
5617dd7cddfSDavid du Colombier port->id = i;
5627dd7cddfSDavid du Colombier port->ownhash = ownhash;
5637dd7cddfSDavid du Colombier
5647dd7cddfSDavid du Colombier if(waserror()) {
5657dd7cddfSDavid du Colombier portfree(port);
5667dd7cddfSDavid du Colombier nexterror();
5677dd7cddfSDavid du Colombier }
5687dd7cddfSDavid du Colombier port->type = type;
5699a747e4fSDavid du Colombier memmove(port->name, name, KNAMELEN);
5707dd7cddfSDavid du Colombier switch(port->type) {
571ac020a8fSDavid du Colombier default:
572ac020a8fSDavid du Colombier panic("portbind: unknown port type: %d", type);
5737dd7cddfSDavid du Colombier case Tether:
5747dd7cddfSDavid du Colombier snprint(path, sizeof(path), "%s/clone", dev);
5757dd7cddfSDavid du Colombier ctl = namec(path, Aopen, ORDWR, 0);
5767dd7cddfSDavid du Colombier if(waserror()) {
5777dd7cddfSDavid du Colombier cclose(ctl);
5787dd7cddfSDavid du Colombier nexterror();
5797dd7cddfSDavid du Colombier }
5807dd7cddfSDavid du Colombier // check addr?
5817dd7cddfSDavid du Colombier
5827dd7cddfSDavid du Colombier // get directory name
583*a129eb93SDavid du Colombier n = devtab[ctl->type]->read(ctl, buf, sizeof(buf)-1, 0);
5847dd7cddfSDavid du Colombier buf[n] = 0;
585*a129eb93SDavid du Colombier snprint(path, sizeof(path), "%s/%lud/data", dev, strtoul(buf, 0, 0));
5867dd7cddfSDavid du Colombier
5877dd7cddfSDavid du Colombier // setup connection to be promiscuous
5887dd7cddfSDavid du Colombier snprint(buf, sizeof(buf), "connect -1");
5897dd7cddfSDavid du Colombier devtab[ctl->type]->write(ctl, buf, strlen(buf), 0);
5907dd7cddfSDavid du Colombier snprint(buf, sizeof(buf), "promiscuous");
5917dd7cddfSDavid du Colombier devtab[ctl->type]->write(ctl, buf, strlen(buf), 0);
5927dd7cddfSDavid du Colombier snprint(buf, sizeof(buf), "bridge");
5937dd7cddfSDavid du Colombier devtab[ctl->type]->write(ctl, buf, strlen(buf), 0);
5947dd7cddfSDavid du Colombier
5957dd7cddfSDavid du Colombier // open data port
5967dd7cddfSDavid du Colombier port->data[0] = namec(path, Aopen, ORDWR, 0);
5977dd7cddfSDavid du Colombier // dup it
5987dd7cddfSDavid du Colombier incref(port->data[0]);
5997dd7cddfSDavid du Colombier port->data[1] = port->data[0];
6007dd7cddfSDavid du Colombier
6017dd7cddfSDavid du Colombier poperror();
6027dd7cddfSDavid du Colombier cclose(ctl);
6037dd7cddfSDavid du Colombier
6047dd7cddfSDavid du Colombier break;
6057dd7cddfSDavid du Colombier case Ttun:
6067dd7cddfSDavid du Colombier port->data[0] = namec(dev, Aopen, OREAD, 0);
6077dd7cddfSDavid du Colombier port->data[1] = namec(dev2, Aopen, OWRITE, 0);
6087dd7cddfSDavid du Colombier break;
6097dd7cddfSDavid du Colombier }
6107dd7cddfSDavid du Colombier
6117dd7cddfSDavid du Colombier poperror();
6127dd7cddfSDavid du Colombier
613ac020a8fSDavid du Colombier /* committed to binding port */
6147dd7cddfSDavid du Colombier b->port[port->id] = port;
6157dd7cddfSDavid du Colombier port->bridge = b;
6167dd7cddfSDavid du Colombier if(b->nport <= port->id)
6177dd7cddfSDavid du Colombier b->nport = port->id+1;
6187dd7cddfSDavid du Colombier
6197dd7cddfSDavid du Colombier // assumes kproc always succeeds
620*a129eb93SDavid du Colombier incref(port);
621*a129eb93SDavid du Colombier snprint(buf, sizeof(buf), "bridge:%s", dev);
622*a129eb93SDavid du Colombier kproc(buf, etherread, port);
6237dd7cddfSDavid du Colombier }
6247dd7cddfSDavid du Colombier
6257dd7cddfSDavid du Colombier // assumes b is locked
6267dd7cddfSDavid du Colombier static void
portunbind(Bridge * b,int argc,char * argv[])6277dd7cddfSDavid du Colombier portunbind(Bridge *b, int argc, char *argv[])
6287dd7cddfSDavid du Colombier {
6297dd7cddfSDavid du Colombier int type = 0, i;
6309a747e4fSDavid du Colombier char name[KNAMELEN];
6317dd7cddfSDavid du Colombier ulong ownhash;
632ac020a8fSDavid du Colombier Port *port = nil;
633ac020a8fSDavid du Colombier static char usage[] = "usage: unbind ether|tunnel addr [ownhash]";
6347dd7cddfSDavid du Colombier
6359a747e4fSDavid du Colombier memset(name, 0, KNAMELEN);
6367dd7cddfSDavid du Colombier if(argc < 2 || argc > 3)
6377dd7cddfSDavid du Colombier error(usage);
6387dd7cddfSDavid du Colombier if(strcmp(argv[0], "ether") == 0) {
6397dd7cddfSDavid du Colombier type = Tether;
6409a747e4fSDavid du Colombier strncpy(name, argv[1], KNAMELEN);
6419a747e4fSDavid du Colombier name[KNAMELEN-1] = 0;
6427dd7cddfSDavid du Colombier // parseaddr(addr, argv[1], Eaddrlen);
6437dd7cddfSDavid du Colombier } else if(strcmp(argv[0], "tunnel") == 0) {
6447dd7cddfSDavid du Colombier type = Ttun;
6459a747e4fSDavid du Colombier strncpy(name, argv[1], KNAMELEN);
6469a747e4fSDavid du Colombier name[KNAMELEN-1] = 0;
6477dd7cddfSDavid du Colombier // parseip(addr, argv[1]);
6487dd7cddfSDavid du Colombier } else
6497dd7cddfSDavid du Colombier error(usage);
6507dd7cddfSDavid du Colombier if(argc == 3)
6517dd7cddfSDavid du Colombier ownhash = atoi(argv[2]);
6527dd7cddfSDavid du Colombier else
6537dd7cddfSDavid du Colombier ownhash = 0;
6547dd7cddfSDavid du Colombier for(i=0; i<b->nport; i++) {
6557dd7cddfSDavid du Colombier port = b->port[i];
656ac020a8fSDavid du Colombier if(port != nil && port->type == type &&
657ac020a8fSDavid du Colombier memcmp(port->name, name, KNAMELEN) == 0)
6587dd7cddfSDavid du Colombier break;
6597dd7cddfSDavid du Colombier }
6607dd7cddfSDavid du Colombier if(i == b->nport)
6617dd7cddfSDavid du Colombier error("port not found");
6627dd7cddfSDavid du Colombier if(ownhash != 0 && port->ownhash != 0 && ownhash != port->ownhash)
6637dd7cddfSDavid du Colombier error("bad owner hash");
6647dd7cddfSDavid du Colombier
6657dd7cddfSDavid du Colombier port->closed = 1;
6667dd7cddfSDavid du Colombier b->port[i] = nil; // port is now unbound
6677dd7cddfSDavid du Colombier cacheflushport(b, i);
6687dd7cddfSDavid du Colombier
6697dd7cddfSDavid du Colombier // try and stop reader
6707dd7cddfSDavid du Colombier if(port->readp)
6717dd7cddfSDavid du Colombier postnote(port->readp, 1, "unbind", 0);
6727dd7cddfSDavid du Colombier portfree(port);
6737dd7cddfSDavid du Colombier }
6747dd7cddfSDavid du Colombier
6757dd7cddfSDavid du Colombier // assumes b is locked
6767dd7cddfSDavid du Colombier static Centry *
cachelookup(Bridge * b,uchar d[Eaddrlen])6777dd7cddfSDavid du Colombier cachelookup(Bridge *b, uchar d[Eaddrlen])
6787dd7cddfSDavid du Colombier {
6797dd7cddfSDavid du Colombier int i;
6807dd7cddfSDavid du Colombier uint h;
6817dd7cddfSDavid du Colombier Centry *p;
6827dd7cddfSDavid du Colombier long sec;
6837dd7cddfSDavid du Colombier
6847dd7cddfSDavid du Colombier // dont cache multicast or broadcast
6857dd7cddfSDavid du Colombier if(d[0] & 1)
6867dd7cddfSDavid du Colombier return 0;
6877dd7cddfSDavid du Colombier
6887dd7cddfSDavid du Colombier h = 0;
6897dd7cddfSDavid du Colombier for(i=0; i<Eaddrlen; i++) {
6907dd7cddfSDavid du Colombier h *= 7;
6917dd7cddfSDavid du Colombier h += d[i];
6927dd7cddfSDavid du Colombier }
6937dd7cddfSDavid du Colombier h %= CacheHash;
6947dd7cddfSDavid du Colombier p = b->cache + h;
6957dd7cddfSDavid du Colombier sec = TK2SEC(m->ticks);
6967dd7cddfSDavid du Colombier for(i=0; i<CacheLook; i++,p++) {
6977dd7cddfSDavid du Colombier if(memcmp(d, p->d, Eaddrlen) == 0) {
6987dd7cddfSDavid du Colombier p->dst++;
6997dd7cddfSDavid du Colombier if(sec >= p->expire) {
7007dd7cddfSDavid du Colombier log(b, Logcache, "expired cache entry: %E %d\n",
7017dd7cddfSDavid du Colombier d, p->port);
7027dd7cddfSDavid du Colombier return nil;
7037dd7cddfSDavid du Colombier }
7047dd7cddfSDavid du Colombier p->expire = sec + CacheTimeout;
7057dd7cddfSDavid du Colombier return p;
7067dd7cddfSDavid du Colombier }
7077dd7cddfSDavid du Colombier }
7087dd7cddfSDavid du Colombier log(b, Logcache, "cache miss: %E\n", d);
7097dd7cddfSDavid du Colombier return nil;
7107dd7cddfSDavid du Colombier }
7117dd7cddfSDavid du Colombier
7127dd7cddfSDavid du Colombier // assumes b is locked
7137dd7cddfSDavid du Colombier static void
cacheupdate(Bridge * b,uchar d[Eaddrlen],int port)7147dd7cddfSDavid du Colombier cacheupdate(Bridge *b, uchar d[Eaddrlen], int port)
7157dd7cddfSDavid du Colombier {
7167dd7cddfSDavid du Colombier int i;
7177dd7cddfSDavid du Colombier uint h;
7187dd7cddfSDavid du Colombier Centry *p, *pp;
7197dd7cddfSDavid du Colombier long sec;
7207dd7cddfSDavid du Colombier
7217dd7cddfSDavid du Colombier // dont cache multicast or broadcast
7227dd7cddfSDavid du Colombier if(d[0] & 1) {
7237dd7cddfSDavid du Colombier log(b, Logcache, "bad source address: %E\n", d);
7247dd7cddfSDavid du Colombier return;
7257dd7cddfSDavid du Colombier }
7267dd7cddfSDavid du Colombier
7277dd7cddfSDavid du Colombier h = 0;
7287dd7cddfSDavid du Colombier for(i=0; i<Eaddrlen; i++) {
7297dd7cddfSDavid du Colombier h *= 7;
7307dd7cddfSDavid du Colombier h += d[i];
7317dd7cddfSDavid du Colombier }
7327dd7cddfSDavid du Colombier h %= CacheHash;
7337dd7cddfSDavid du Colombier p = b->cache + h;
7347dd7cddfSDavid du Colombier pp = p;
7357dd7cddfSDavid du Colombier sec = p->expire;
7367dd7cddfSDavid du Colombier
7377dd7cddfSDavid du Colombier // look for oldest entry
7387dd7cddfSDavid du Colombier for(i=0; i<CacheLook; i++,p++) {
7397dd7cddfSDavid du Colombier if(memcmp(p->d, d, Eaddrlen) == 0) {
7407dd7cddfSDavid du Colombier p->expire = TK2SEC(m->ticks) + CacheTimeout;
7417dd7cddfSDavid du Colombier if(p->port != port) {
7427dd7cddfSDavid du Colombier log(b, Logcache, "NIC changed port %d->%d: %E\n",
7437dd7cddfSDavid du Colombier p->port, port, d);
7447dd7cddfSDavid du Colombier p->port = port;
7457dd7cddfSDavid du Colombier }
7467dd7cddfSDavid du Colombier p->src++;
7477dd7cddfSDavid du Colombier return;
7487dd7cddfSDavid du Colombier }
7497dd7cddfSDavid du Colombier if(p->expire < sec) {
7507dd7cddfSDavid du Colombier sec = p->expire;
7517dd7cddfSDavid du Colombier pp = p;
7527dd7cddfSDavid du Colombier }
7537dd7cddfSDavid du Colombier }
7547dd7cddfSDavid du Colombier if(pp->expire != 0)
7557dd7cddfSDavid du Colombier log(b, Logcache, "bumping from cache: %E %d\n", pp->d, pp->port);
7567dd7cddfSDavid du Colombier pp->expire = TK2SEC(m->ticks) + CacheTimeout;
7577dd7cddfSDavid du Colombier memmove(pp->d, d, Eaddrlen);
7587dd7cddfSDavid du Colombier pp->port = port;
7597dd7cddfSDavid du Colombier pp->src = 1;
7607dd7cddfSDavid du Colombier pp->dst = 0;
7617dd7cddfSDavid du Colombier log(b, Logcache, "adding to cache: %E %d\n", pp->d, pp->port);
7627dd7cddfSDavid du Colombier }
7637dd7cddfSDavid du Colombier
7647dd7cddfSDavid du Colombier // assumes b is locked
7657dd7cddfSDavid du Colombier static void
cacheflushport(Bridge * b,int port)7667dd7cddfSDavid du Colombier cacheflushport(Bridge *b, int port)
7677dd7cddfSDavid du Colombier {
7687dd7cddfSDavid du Colombier Centry *ce;
7697dd7cddfSDavid du Colombier int i;
7707dd7cddfSDavid du Colombier
7717dd7cddfSDavid du Colombier ce = b->cache;
7727dd7cddfSDavid du Colombier for(i=0; i<CacheSize; i++,ce++) {
7737dd7cddfSDavid du Colombier if(ce->port != port)
7747dd7cddfSDavid du Colombier continue;
7757dd7cddfSDavid du Colombier memset(ce, 0, sizeof(Centry));
7767dd7cddfSDavid du Colombier }
7777dd7cddfSDavid du Colombier }
7787dd7cddfSDavid du Colombier
7797dd7cddfSDavid du Colombier static char *
cachedump(Bridge * b)7807dd7cddfSDavid du Colombier cachedump(Bridge *b)
7817dd7cddfSDavid du Colombier {
7827dd7cddfSDavid du Colombier int i, n;
7837dd7cddfSDavid du Colombier long sec, off;
7847dd7cddfSDavid du Colombier char *buf, *p, *ep;
7857dd7cddfSDavid du Colombier Centry *ce;
7867dd7cddfSDavid du Colombier char c;
7877dd7cddfSDavid du Colombier
7887dd7cddfSDavid du Colombier qlock(b);
7897dd7cddfSDavid du Colombier if(waserror()) {
7907dd7cddfSDavid du Colombier qunlock(b);
7917dd7cddfSDavid du Colombier nexterror();
7927dd7cddfSDavid du Colombier }
7937dd7cddfSDavid du Colombier sec = TK2SEC(m->ticks);
7947dd7cddfSDavid du Colombier n = 0;
7957dd7cddfSDavid du Colombier for(i=0; i<CacheSize; i++)
7967dd7cddfSDavid du Colombier if(b->cache[i].expire != 0)
7977dd7cddfSDavid du Colombier n++;
7987dd7cddfSDavid du Colombier
7997dd7cddfSDavid du Colombier n *= 51; // change if print format is changed
8007dd7cddfSDavid du Colombier n += 10; // some slop at the end
8017dd7cddfSDavid du Colombier buf = malloc(n);
802aa72973aSDavid du Colombier if(buf == nil)
803aa72973aSDavid du Colombier error(Enomem);
8047dd7cddfSDavid du Colombier p = buf;
8057dd7cddfSDavid du Colombier ep = buf + n;
8067dd7cddfSDavid du Colombier ce = b->cache;
8077dd7cddfSDavid du Colombier off = seconds() - sec;
8087dd7cddfSDavid du Colombier for(i=0; i<CacheSize; i++,ce++) {
8097dd7cddfSDavid du Colombier if(ce->expire == 0)
8107dd7cddfSDavid du Colombier continue;
8117dd7cddfSDavid du Colombier c = (sec < ce->expire)?'v':'e';
8127dd7cddfSDavid du Colombier p += snprint(p, ep-p, "%E %2d %10ld %10ld %10ld %c\n", ce->d,
8137dd7cddfSDavid du Colombier ce->port, ce->src, ce->dst, ce->expire+off, c);
8147dd7cddfSDavid du Colombier }
8157dd7cddfSDavid du Colombier *p = 0;
8167dd7cddfSDavid du Colombier poperror();
8177dd7cddfSDavid du Colombier qunlock(b);
8187dd7cddfSDavid du Colombier
8197dd7cddfSDavid du Colombier return buf;
8207dd7cddfSDavid du Colombier }
8217dd7cddfSDavid du Colombier
8227dd7cddfSDavid du Colombier
8237dd7cddfSDavid du Colombier
824*a129eb93SDavid du Colombier // assumes b is locked, no error return
8257dd7cddfSDavid du Colombier static void
ethermultiwrite(Bridge * b,Block * bp,Port * port)8267dd7cddfSDavid du Colombier ethermultiwrite(Bridge *b, Block *bp, Port *port)
8277dd7cddfSDavid du Colombier {
8287dd7cddfSDavid du Colombier Port *oport;
8297dd7cddfSDavid du Colombier Etherpkt *ep;
8306c0968e3SDavid du Colombier int i, mcast;
8317dd7cddfSDavid du Colombier
8327dd7cddfSDavid du Colombier ep = (Etherpkt*)bp->rp;
8336c0968e3SDavid du Colombier mcast = ep->d[0] & 1; /* multicast bit of ethernet address */
8347dd7cddfSDavid du Colombier
8357dd7cddfSDavid du Colombier oport = nil;
8367dd7cddfSDavid du Colombier for(i=0; i<b->nport; i++) {
8377dd7cddfSDavid du Colombier if(i == port->id || b->port[i] == nil)
8387dd7cddfSDavid du Colombier continue;
8396c0968e3SDavid du Colombier /*
8406c0968e3SDavid du Colombier * we need to forward multicast packets for ipv6,
8416c0968e3SDavid du Colombier * so always do it.
8426c0968e3SDavid du Colombier */
8437dd7cddfSDavid du Colombier if(mcast)
8447dd7cddfSDavid du Colombier b->port[i]->outmulti++;
8457dd7cddfSDavid du Colombier else
8467dd7cddfSDavid du Colombier b->port[i]->outunknown++;
8477dd7cddfSDavid du Colombier
8487dd7cddfSDavid du Colombier // delay one so that the last write does not copy
8497dd7cddfSDavid du Colombier if(oport != nil) {
8507dd7cddfSDavid du Colombier b->copy++;
851*a129eb93SDavid du Colombier etherwrite(oport, copyblock(bp, blocklen(bp)));
8527dd7cddfSDavid du Colombier }
8537dd7cddfSDavid du Colombier oport = b->port[i];
8547dd7cddfSDavid du Colombier }
8557dd7cddfSDavid du Colombier
8567dd7cddfSDavid du Colombier // last write free block
857*a129eb93SDavid du Colombier if(oport)
858*a129eb93SDavid du Colombier etherwrite(oport, bp);
859*a129eb93SDavid du Colombier else
8607dd7cddfSDavid du Colombier freeb(bp);
8617dd7cddfSDavid du Colombier }
8627dd7cddfSDavid du Colombier
8637dd7cddfSDavid du Colombier static void
tcpmsshack(Etherpkt * epkt,int n)8647dd7cddfSDavid du Colombier tcpmsshack(Etherpkt *epkt, int n)
8657dd7cddfSDavid du Colombier {
866ac020a8fSDavid du Colombier int hl, optlen;
8677dd7cddfSDavid du Colombier Iphdr *iphdr;
8687dd7cddfSDavid du Colombier Tcphdr *tcphdr;
869ac020a8fSDavid du Colombier ulong mss, cksum;
8707dd7cddfSDavid du Colombier uchar *optr;
8717dd7cddfSDavid du Colombier
872ac020a8fSDavid du Colombier /* ignore non-ipv4 packets */
873ac020a8fSDavid du Colombier if(nhgets(epkt->type) != ETIP4)
8747dd7cddfSDavid du Colombier return;
8757dd7cddfSDavid du Colombier iphdr = (Iphdr*)(epkt->data);
8767dd7cddfSDavid du Colombier n -= ETHERHDRSIZE;
8777dd7cddfSDavid du Colombier if(n < IPHDR)
8787dd7cddfSDavid du Colombier return;
8797dd7cddfSDavid du Colombier
880ac020a8fSDavid du Colombier /* ignore bad packets */
881ac020a8fSDavid du Colombier if(iphdr->vihl != (IP_VER4|IP_HLEN4)) {
8827dd7cddfSDavid du Colombier hl = (iphdr->vihl&0xF)<<2;
883ac020a8fSDavid du Colombier if((iphdr->vihl&0xF0) != IP_VER4 || hl < (IP_HLEN4<<2))
8847dd7cddfSDavid du Colombier return;
8857dd7cddfSDavid du Colombier } else
886ac020a8fSDavid du Colombier hl = IP_HLEN4<<2;
8877dd7cddfSDavid du Colombier
888ac020a8fSDavid du Colombier /* ignore non-tcp packets */
8897dd7cddfSDavid du Colombier if(iphdr->proto != IP_TCPPROTO)
8907dd7cddfSDavid du Colombier return;
8917dd7cddfSDavid du Colombier n -= hl;
8927dd7cddfSDavid du Colombier if(n < sizeof(Tcphdr))
8937dd7cddfSDavid du Colombier return;
8947dd7cddfSDavid du Colombier tcphdr = (Tcphdr*)((uchar*)(iphdr) + hl);
8957dd7cddfSDavid du Colombier // MSS can only appear in SYN packet
8967dd7cddfSDavid du Colombier if(!(tcphdr->flag[1] & SYN))
8977dd7cddfSDavid du Colombier return;
8987dd7cddfSDavid du Colombier hl = (tcphdr->flag[0] & 0xf0)>>2;
8997dd7cddfSDavid du Colombier if(n < hl)
9007dd7cddfSDavid du Colombier return;
9017dd7cddfSDavid du Colombier
9027dd7cddfSDavid du Colombier // check for MSS option
903ac020a8fSDavid du Colombier optr = (uchar*)tcphdr + sizeof(Tcphdr);
9047dd7cddfSDavid du Colombier n = hl - sizeof(Tcphdr);
9057dd7cddfSDavid du Colombier for(;;) {
9067dd7cddfSDavid du Colombier if(n <= 0 || *optr == EOLOPT)
9077dd7cddfSDavid du Colombier return;
9087dd7cddfSDavid du Colombier if(*optr == NOOPOPT) {
9097dd7cddfSDavid du Colombier n--;
9107dd7cddfSDavid du Colombier optr++;
9117dd7cddfSDavid du Colombier continue;
9127dd7cddfSDavid du Colombier }
9137dd7cddfSDavid du Colombier optlen = optr[1];
9147dd7cddfSDavid du Colombier if(optlen < 2 || optlen > n)
9157dd7cddfSDavid du Colombier return;
9167dd7cddfSDavid du Colombier if(*optr == MSSOPT && optlen == MSS_LENGTH)
9177dd7cddfSDavid du Colombier break;
9187dd7cddfSDavid du Colombier n -= optlen;
9197dd7cddfSDavid du Colombier optr += optlen;
9207dd7cddfSDavid du Colombier }
9217dd7cddfSDavid du Colombier
9227dd7cddfSDavid du Colombier mss = nhgets(optr+2);
9237dd7cddfSDavid du Colombier if(mss <= TcpMssMax)
9247dd7cddfSDavid du Colombier return;
9257dd7cddfSDavid du Colombier // fit checksum
9267dd7cddfSDavid du Colombier cksum = nhgets(tcphdr->cksum);
9277dd7cddfSDavid du Colombier if(optr-(uchar*)tcphdr & 1) {
9287dd7cddfSDavid du Colombier print("tcpmsshack: odd alignment!\n");
9297dd7cddfSDavid du Colombier // odd alignments are a pain
9307dd7cddfSDavid du Colombier cksum += nhgets(optr+1);
9317dd7cddfSDavid du Colombier cksum -= (optr[1]<<8)|(TcpMssMax>>8);
9327dd7cddfSDavid du Colombier cksum += (cksum>>16);
9337dd7cddfSDavid du Colombier cksum &= 0xffff;
9347dd7cddfSDavid du Colombier cksum += nhgets(optr+3);
9357dd7cddfSDavid du Colombier cksum -= ((TcpMssMax&0xff)<<8)|optr[4];
9367dd7cddfSDavid du Colombier cksum += (cksum>>16);
9377dd7cddfSDavid du Colombier } else {
9387dd7cddfSDavid du Colombier cksum += mss;
9397dd7cddfSDavid du Colombier cksum -= TcpMssMax;
9407dd7cddfSDavid du Colombier cksum += (cksum>>16);
9417dd7cddfSDavid du Colombier }
9427dd7cddfSDavid du Colombier hnputs(tcphdr->cksum, cksum);
9437dd7cddfSDavid du Colombier hnputs(optr+2, TcpMssMax);
9447dd7cddfSDavid du Colombier }
9457dd7cddfSDavid du Colombier
9467dd7cddfSDavid du Colombier /*
9477dd7cddfSDavid du Colombier * process to read from the ethernet
9487dd7cddfSDavid du Colombier */
9497dd7cddfSDavid du Colombier static void
etherread(void * a)9507dd7cddfSDavid du Colombier etherread(void *a)
9517dd7cddfSDavid du Colombier {
9527dd7cddfSDavid du Colombier Port *port = a;
9537dd7cddfSDavid du Colombier Bridge *b = port->bridge;
954*a129eb93SDavid du Colombier Block *bp;
9557dd7cddfSDavid du Colombier Etherpkt *ep;
9567dd7cddfSDavid du Colombier Centry *ce;
957*a129eb93SDavid du Colombier long md, n;
9587dd7cddfSDavid du Colombier
9597dd7cddfSDavid du Colombier qlock(b);
9607dd7cddfSDavid du Colombier port->readp = up; /* hide identity under a rock for unbind */
9617dd7cddfSDavid du Colombier
9627dd7cddfSDavid du Colombier while(!port->closed){
9637dd7cddfSDavid du Colombier // release lock to read - error means it is time to quit
9647dd7cddfSDavid du Colombier qunlock(b);
9657dd7cddfSDavid du Colombier if(waserror()) {
9663ff48bf5SDavid du Colombier print("etherread read error: %s\n", up->errstr);
9677dd7cddfSDavid du Colombier qlock(b);
9687dd7cddfSDavid du Colombier break;
9697dd7cddfSDavid du Colombier }
970*a129eb93SDavid du Colombier bp = devtab[port->data[0]->type]->bread(port->data[0], MaxMTU, 0);
9717dd7cddfSDavid du Colombier poperror();
9727dd7cddfSDavid du Colombier qlock(b);
973*a129eb93SDavid du Colombier if(bp == nil)
9747dd7cddfSDavid du Colombier break;
975*a129eb93SDavid du Colombier n = blocklen(bp);
976*a129eb93SDavid du Colombier if(port->closed || n < ETHERMINTU){
9777dd7cddfSDavid du Colombier freeb(bp);
9787dd7cddfSDavid du Colombier continue;
9797dd7cddfSDavid du Colombier }
980*a129eb93SDavid du Colombier if(waserror()) {
981*a129eb93SDavid du Colombier // print("etherread bridge error\n");
982*a129eb93SDavid du Colombier freeb(bp);
983*a129eb93SDavid du Colombier continue;
984*a129eb93SDavid du Colombier }
9857dd7cddfSDavid du Colombier port->in++;
9867dd7cddfSDavid du Colombier
9877dd7cddfSDavid du Colombier ep = (Etherpkt*)bp->rp;
9887dd7cddfSDavid du Colombier cacheupdate(b, ep->s, port->id);
9897dd7cddfSDavid du Colombier if(b->tcpmss)
990*a129eb93SDavid du Colombier tcpmsshack(ep, n);
9917dd7cddfSDavid du Colombier
9927dd7cddfSDavid du Colombier /*
9937dd7cddfSDavid du Colombier * delay packets to simulate a slow link
9947dd7cddfSDavid du Colombier */
995*a129eb93SDavid du Colombier if(b->delay0 != 0 || b->delayn != 0){
996*a129eb93SDavid du Colombier md = b->delay0 + b->delayn * n;
9977dd7cddfSDavid du Colombier if(md > 0)
9987dd7cddfSDavid du Colombier microdelay(md);
9997dd7cddfSDavid du Colombier }
10007dd7cddfSDavid du Colombier
1001*a129eb93SDavid du Colombier poperror(); /* must now dispose of bp */
1002*a129eb93SDavid du Colombier
10037dd7cddfSDavid du Colombier if(ep->d[0] & 1) {
10046c0968e3SDavid du Colombier log(b, Logmcast, "multicast: port=%d src=%E dst=%E type=%#.4ux\n",
10056c0968e3SDavid du Colombier port->id, ep->s, ep->d, ep->type[0]<<8|ep->type[1]);
10067dd7cddfSDavid du Colombier port->inmulti++;
1007*a129eb93SDavid du Colombier ethermultiwrite(b, bp, port);
10087dd7cddfSDavid du Colombier } else {
10097dd7cddfSDavid du Colombier ce = cachelookup(b, ep->d);
10107dd7cddfSDavid du Colombier if(ce == nil) {
10117dd7cddfSDavid du Colombier b->miss++;
10127dd7cddfSDavid du Colombier port->inunknown++;
1013*a129eb93SDavid du Colombier ethermultiwrite(b, bp, port);
10147dd7cddfSDavid du Colombier }else if(ce->port != port->id){
10157dd7cddfSDavid du Colombier b->hit++;
1016*a129eb93SDavid du Colombier etherwrite(b->port[ce->port], bp);
1017*a129eb93SDavid du Colombier }else
10187dd7cddfSDavid du Colombier freeb(bp);
10197dd7cddfSDavid du Colombier }
1020*a129eb93SDavid du Colombier }
10217dd7cddfSDavid du Colombier // print("etherread: trying to exit\n");
10227dd7cddfSDavid du Colombier port->readp = nil;
10237dd7cddfSDavid du Colombier portfree(port);
10247dd7cddfSDavid du Colombier qunlock(b);
10257dd7cddfSDavid du Colombier pexit("hangup", 1);
10267dd7cddfSDavid du Colombier }
10277dd7cddfSDavid du Colombier
10287dd7cddfSDavid du Colombier static int
fragment(Etherpkt * epkt,int n)10297dd7cddfSDavid du Colombier fragment(Etherpkt *epkt, int n)
10307dd7cddfSDavid du Colombier {
10317dd7cddfSDavid du Colombier Iphdr *iphdr;
10327dd7cddfSDavid du Colombier
10337dd7cddfSDavid du Colombier if(n <= TunnelMtu)
10347dd7cddfSDavid du Colombier return 0;
10357dd7cddfSDavid du Colombier
1036ac020a8fSDavid du Colombier /* ignore non-ipv4 packets */
1037ac020a8fSDavid du Colombier if(nhgets(epkt->type) != ETIP4)
10387dd7cddfSDavid du Colombier return 0;
10397dd7cddfSDavid du Colombier iphdr = (Iphdr*)(epkt->data);
10407dd7cddfSDavid du Colombier n -= ETHERHDRSIZE;
1041ac020a8fSDavid du Colombier /*
1042ac020a8fSDavid du Colombier * ignore: IP runt packets, bad packets (I don't handle IP
1043ac020a8fSDavid du Colombier * options for the moment), packets with don't-fragment set,
1044ac020a8fSDavid du Colombier * and short blocks.
1045ac020a8fSDavid du Colombier */
1046ac020a8fSDavid du Colombier if(n < IPHDR || iphdr->vihl != (IP_VER4|IP_HLEN4) ||
1047ac020a8fSDavid du Colombier iphdr->frag[0] & (IP_DF>>8) || nhgets(iphdr->length) > n)
10487dd7cddfSDavid du Colombier return 0;
10497dd7cddfSDavid du Colombier
10507dd7cddfSDavid du Colombier return 1;
10517dd7cddfSDavid du Colombier }
10527dd7cddfSDavid du Colombier
10537dd7cddfSDavid du Colombier static void
etherwrite(Port * port,Block * bp)10547dd7cddfSDavid du Colombier etherwrite(Port *port, Block *bp)
10557dd7cddfSDavid du Colombier {
10567dd7cddfSDavid du Colombier Iphdr *eh, *feh;
10577dd7cddfSDavid du Colombier Etherpkt *epkt;
10587dd7cddfSDavid du Colombier int n, lid, len, seglen, chunk, dlen, blklen, offset, mf;
10597dd7cddfSDavid du Colombier Block *xp, *nb;
10607dd7cddfSDavid du Colombier ushort fragoff, frag;
10617dd7cddfSDavid du Colombier
10627dd7cddfSDavid du Colombier port->out++;
10637dd7cddfSDavid du Colombier epkt = (Etherpkt*)bp->rp;
10647dd7cddfSDavid du Colombier n = blocklen(bp);
10657dd7cddfSDavid du Colombier if(port->type != Ttun || !fragment(epkt, n)) {
1066*a129eb93SDavid du Colombier if(!waserror()){
10677dd7cddfSDavid du Colombier devtab[port->data[1]->type]->bwrite(port->data[1], bp, 0);
1068*a129eb93SDavid du Colombier poperror();
1069*a129eb93SDavid du Colombier }
10707dd7cddfSDavid du Colombier return;
10717dd7cddfSDavid du Colombier }
10727dd7cddfSDavid du Colombier port->outfrag++;
10737dd7cddfSDavid du Colombier if(waserror()){
10747dd7cddfSDavid du Colombier freeblist(bp);
1075*a129eb93SDavid du Colombier return;
10767dd7cddfSDavid du Colombier }
10777dd7cddfSDavid du Colombier
10787dd7cddfSDavid du Colombier seglen = (TunnelMtu - ETHERHDRSIZE - IPHDR) & ~7;
10797dd7cddfSDavid du Colombier eh = (Iphdr*)(epkt->data);
10807dd7cddfSDavid du Colombier len = nhgets(eh->length);
10817dd7cddfSDavid du Colombier frag = nhgets(eh->frag);
10827dd7cddfSDavid du Colombier mf = frag & IP_MF;
10837dd7cddfSDavid du Colombier frag <<= 3;
10847dd7cddfSDavid du Colombier dlen = len - IPHDR;
10857dd7cddfSDavid du Colombier xp = bp;
10867dd7cddfSDavid du Colombier lid = nhgets(eh->id);
10877dd7cddfSDavid du Colombier offset = ETHERHDRSIZE+IPHDR;
10887dd7cddfSDavid du Colombier while(xp != nil && offset && offset >= BLEN(xp)) {
10897dd7cddfSDavid du Colombier offset -= BLEN(xp);
10907dd7cddfSDavid du Colombier xp = xp->next;
10917dd7cddfSDavid du Colombier }
10927dd7cddfSDavid du Colombier xp->rp += offset;
10937dd7cddfSDavid du Colombier
1094ac020a8fSDavid du Colombier if(0)
1095ac020a8fSDavid du Colombier print("seglen=%d, dlen=%d, mf=%x, frag=%d\n",
1096ac020a8fSDavid du Colombier seglen, dlen, mf, frag);
10977dd7cddfSDavid du Colombier for(fragoff = 0; fragoff < dlen; fragoff += seglen) {
10987dd7cddfSDavid du Colombier nb = allocb(ETHERHDRSIZE+IPHDR+seglen);
10997dd7cddfSDavid du Colombier
11007dd7cddfSDavid du Colombier feh = (Iphdr*)(nb->wp+ETHERHDRSIZE);
11017dd7cddfSDavid du Colombier
11027dd7cddfSDavid du Colombier memmove(nb->wp, epkt, ETHERHDRSIZE+IPHDR);
11037dd7cddfSDavid du Colombier nb->wp += ETHERHDRSIZE+IPHDR;
11047dd7cddfSDavid du Colombier
11057dd7cddfSDavid du Colombier if((fragoff + seglen) >= dlen) {
11067dd7cddfSDavid du Colombier seglen = dlen - fragoff;
11077dd7cddfSDavid du Colombier hnputs(feh->frag, (frag+fragoff)>>3 | mf);
11087dd7cddfSDavid du Colombier }
11097dd7cddfSDavid du Colombier else
11107dd7cddfSDavid du Colombier hnputs(feh->frag, (frag+fragoff>>3) | IP_MF);
11117dd7cddfSDavid du Colombier
11127dd7cddfSDavid du Colombier hnputs(feh->length, seglen + IPHDR);
11137dd7cddfSDavid du Colombier hnputs(feh->id, lid);
11147dd7cddfSDavid du Colombier
11157dd7cddfSDavid du Colombier /* Copy up the data area */
11167dd7cddfSDavid du Colombier chunk = seglen;
11177dd7cddfSDavid du Colombier while(chunk) {
11187dd7cddfSDavid du Colombier blklen = chunk;
11197dd7cddfSDavid du Colombier if(BLEN(xp) < chunk)
11207dd7cddfSDavid du Colombier blklen = BLEN(xp);
11217dd7cddfSDavid du Colombier memmove(nb->wp, xp->rp, blklen);
11227dd7cddfSDavid du Colombier nb->wp += blklen;
11237dd7cddfSDavid du Colombier xp->rp += blklen;
11247dd7cddfSDavid du Colombier chunk -= blklen;
11257dd7cddfSDavid du Colombier if(xp->rp == xp->wp)
11267dd7cddfSDavid du Colombier xp = xp->next;
11277dd7cddfSDavid du Colombier }
11287dd7cddfSDavid du Colombier
11297dd7cddfSDavid du Colombier feh->cksum[0] = 0;
11307dd7cddfSDavid du Colombier feh->cksum[1] = 0;
11317dd7cddfSDavid du Colombier hnputs(feh->cksum, ipcsum(&feh->vihl));
11327dd7cddfSDavid du Colombier
1133ac020a8fSDavid du Colombier /* don't generate small packets */
11347dd7cddfSDavid du Colombier if(BLEN(nb) < ETHERMINTU)
11357dd7cddfSDavid du Colombier nb->wp = nb->rp + ETHERMINTU;
11367dd7cddfSDavid du Colombier devtab[port->data[1]->type]->bwrite(port->data[1], nb, 0);
11377dd7cddfSDavid du Colombier }
11387dd7cddfSDavid du Colombier poperror();
11397dd7cddfSDavid du Colombier freeblist(bp);
11407dd7cddfSDavid du Colombier }
11417dd7cddfSDavid du Colombier
11427dd7cddfSDavid du Colombier // hold b lock
11437dd7cddfSDavid du Colombier static void
portfree(Port * port)11447dd7cddfSDavid du Colombier portfree(Port *port)
11457dd7cddfSDavid du Colombier {
1146*a129eb93SDavid du Colombier if(decref(port) != 0)
11477dd7cddfSDavid du Colombier return;
11487dd7cddfSDavid du Colombier
11497dd7cddfSDavid du Colombier if(port->data[0])
11507dd7cddfSDavid du Colombier cclose(port->data[0]);
11517dd7cddfSDavid du Colombier if(port->data[1])
11527dd7cddfSDavid du Colombier cclose(port->data[1]);
11537dd7cddfSDavid du Colombier memset(port, 0, sizeof(Port));
11547dd7cddfSDavid du Colombier free(port);
11557dd7cddfSDavid du Colombier }
11567dd7cddfSDavid du Colombier
11577dd7cddfSDavid du Colombier Dev bridgedevtab = {
11587dd7cddfSDavid du Colombier 'B',
11597dd7cddfSDavid du Colombier "bridge",
11607dd7cddfSDavid du Colombier
11617dd7cddfSDavid du Colombier devreset,
11627dd7cddfSDavid du Colombier bridgeinit,
11639a747e4fSDavid du Colombier devshutdown,
11647dd7cddfSDavid du Colombier bridgeattach,
11657dd7cddfSDavid du Colombier bridgewalk,
11667dd7cddfSDavid du Colombier bridgestat,
11677dd7cddfSDavid du Colombier bridgeopen,
11687dd7cddfSDavid du Colombier devcreate,
11697dd7cddfSDavid du Colombier bridgeclose,
11707dd7cddfSDavid du Colombier bridgeread,
11717dd7cddfSDavid du Colombier devbread,
11727dd7cddfSDavid du Colombier bridgewrite,
11737dd7cddfSDavid du Colombier devbwrite,
11747dd7cddfSDavid du Colombier devremove,
11757dd7cddfSDavid du Colombier devwstat,
11767dd7cddfSDavid du Colombier };
1177