/* * ethernet specific multiplexor for nonet * * this line discipline gets pushed onto an ethernet channel * to demultiplex/multiplex nonet conversations. */ #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "errno.h" #define DPRINT if(pnonet)print extern int pnonet; static void etherparse(uchar*, char*); static void noetherclose(Queue*); static void noetheriput(Queue*, Block*); static void noetheropen(Queue*, Stream*); static void noetheroput(Queue*, Block*); /* * ethernet header of a packet */ typedef struct Etherhdr Etherhdr; struct Etherhdr { uchar d[6]; uchar s[6]; uchar type[2]; uchar circuit[3]; /* circuit number */ uchar flag; uchar mid; /* message id */ uchar ack; /* piggy back ack */ uchar remain[2]; /* count of remaing bytes of data */ uchar sum[2]; /* checksum (0 means none) */ }; #define EHDRSIZE 24 #define EMAXBODY (1514-HDRSIZE) /* maximum ethernet packet body */ #define ETHER_TYPE 0x900 /* most significant byte last */ /* * the ethernet multiplexor stream module definition */ Qinfo noetherinfo = { noetheriput, noetheroput, noetheropen, noetherclose, "noether" }; /* * perform the ether specific part of nonetconnect. just stick * the address into the prototype header. */ void noetherconnect(Noconv *cp, char *ea) { Etherhdr *eh; eh = (Etherhdr *)cp->media->rptr; etherparse(eh->d, ea); eh->type[0] = ETHER_TYPE>>8; eh->type[1] = ETHER_TYPE & 0xff; } /* * set up an ether interface */ static void noetheropen(Queue *q, Stream *s) { nonetnewifc(q, s, 1514, 60, 14, noetherconnect); } /* * tear down an ether interface */ static void noetherclose(Queue *q) { Noifc *ifc; ifc = (Noifc *)(q->ptr); nonetfreeifc(ifc); } /* * configure the system */ static void noetheroput(Queue *q, Block *bp) { Noifc *ifc; ifc = (Noifc *)(q->ptr); if(bp->type != M_DATA){ if(streamparse("config", bp)){ if(*bp->rptr == 0) strcpy(ifc->name, "nonet"); else strncpy(ifc->name, (char *)bp->rptr, sizeof(ifc->name)); } else PUTNEXT(q, bp); return; } PUTNEXT(q, bp); } /* * respond to a misaddressed message with a close */ void noetherbad(Noifc *ifc, Block *bp) { Etherhdr *eh, *neh; int circuit; Block *nbp; int r; /* * crack the packet header */ eh = (Etherhdr *)bp->rptr; print("bad %.2ux%.2ux%.2ux%.2ux%.2ux%.2ux c %d m %d f %d\n", eh->s[0], eh->s[1], eh->s[2], eh->s[3], eh->s[4], eh->s[5], eh->circuit[0], eh->mid, eh->flag); if(eh->flag & NO_RESET) goto out; /* * only one reset per message */ r = (eh->remain[1]<<8) | eh->remain[0]; if(r<0) goto out; /* * craft an error reply */ print("sending reset\n"); nbp = allocb(60); nbp->flags |= S_DELIM; nbp->wptr = nbp->rptr + 60; memset(bp->rptr, 0, 60); neh = (Etherhdr *)nbp->rptr; memcpy(neh, eh, sizeof(Etherhdr)); neh->circuit[0] ^= 1; neh->remain[0] = neh->remain[1] = 0; neh->flag = NO_HANGUP | NO_RESET; neh->ack = eh->mid; neh->mid = eh->ack; memcpy(neh->s, eh->d, sizeof(neh->s)); memcpy(neh->d, eh->s, sizeof(neh->d)); nonetcksum(nbp, 14); PUTNEXT(ifc->wq, nbp); out: freeb(bp); } /* * Input a packet and use the ether address to select the correct * nonet device to pass it to. * * Simplifying assumption: one put == one packet && the complete header * is in the first block. If this isn't true, demultiplexing will not work. */ static void noetheriput(Queue *q, Block *bp) { Noifc *ifc; int circuit; Noconv *cp, *ep; Etherhdr *h; Etherhdr *ph; ulong s; Block *nbp; int next; Nocall *clp; if(bp->type != M_DATA){ PUTNEXT(q, bp); return; } ifc = (Noifc *)(q->ptr); h = (Etherhdr *)(bp->rptr); circuit = (h->circuit[2]<<16) | (h->circuit[1]<<8) | h->circuit[0]; s = (h->sum[1]<<8) | h->sum[0]; if(s && s!=nonetcksum(bp, 14)){ print("checksum error %ux %ux\n", s, (h->sum[1]<<8) | h->sum[0]); freeb(bp); return; } /* * look for an existing circuit. */ ep = &ifc->conv[conf.nnoconv]; for(cp = &ifc->conv[0]; cp < ep; cp++){ if(circuit==cp->rcvcircuit){ qlock(cp); ph = (Etherhdr *)(cp->media->rptr); if(circuit == cp->rcvcircuit && memcmp(ph->d, h->s, sizeof(h->s)) == 0){ bp->rptr += ifc->hsize; nonetrcvmsg(cp, bp); qunlock(cp); return; } qunlock(cp); } } /* * if not a new call, then its misaddressed */ if((h->flag & NO_NEWCALL) == 0){ noetherbad(ifc, bp); return; } /* * Queue call in a circular queue and wakeup a listener. */ DPRINT("call in\n"); lock(&ifc->lock); next = (ifc->wptr + 1) % Nnocalls; if(next == ifc->rptr){ /* no room in the queue */ unlock(&ifc->lock); freeb(bp); return; } clp = &ifc->call[ifc->wptr]; sprint(clp->raddr, "%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux", h->s[0], h->s[1], h->s[2], h->s[3], h->s[4], h->s[5]); clp->circuit = circuit^1; bp->rptr += ifc->hsize; clp->msg = bp; ifc->wptr = next; unlock(&ifc->lock); wakeup(&ifc->listenr); } /* * parse an ethernet address (assumed to be 12 ascii hex digits) */ static void etherparse(uchar *to, char *from) { int tdig; int fdig; int i; if(strlen(from) != 12) error(Ebadnet); for(i = 0; i < 6; i++){ fdig = *from++; tdig = fdig > 'a' ? (fdig - 'a' + 10) : (fdig > 'A' ? (fdig - 'A' + 10) : (fdig - '0')); fdig = *from++; tdig <<= 4; tdig |= fdig > 'a' ? (fdig - 'a' + 10) : (fdig > 'A' ? (fdig - 'A' + 10) : (fdig - '0')); *to++ = tdig; } }