123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "../port/error.h"
- #include "../port/netif.h"
- #include "ip.h"
- #include "ipv6.h"
- typedef struct Etherhdr Etherhdr;
- struct Etherhdr
- {
- uchar d[6];
- uchar s[6];
- uchar t[2];
- };
- static uchar ipbroadcast[IPaddrlen] = {
- 0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,
- };
- static uchar etherbroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- static void etherread4(void *a);
- static void etherread6(void *a);
- static void etherbind(Ipifc *ifc, int argc, char **argv);
- static void etherunbind(Ipifc *ifc);
- static void etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
- static void etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia);
- static void etherremmulti(Ipifc *ifc, uchar *a, uchar *ia);
- static Block* multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac);
- static void sendarp(Ipifc *ifc, Arpent *a);
- static void sendgarp(Ipifc *ifc, uchar*);
- static int multicastea(uchar *ea, uchar *ip);
- static void recvarpproc(void*);
- static void resolveaddr6(Ipifc *ifc, Arpent *a);
- static void etherpref2addr(uchar *pref, uchar *ea);
- Medium ethermedium =
- {
- .name= "ether",
- .hsize= 14,
- .mintu= 60,
- .maxtu= 1514,
- .maclen= 6,
- .bind= etherbind,
- .unbind= etherunbind,
- .bwrite= etherbwrite,
- .addmulti= etheraddmulti,
- .remmulti= etherremmulti,
- .ares= arpenter,
- .areg= sendgarp,
- .pref2addr= etherpref2addr,
- };
- Medium gbemedium =
- {
- .name= "gbe",
- .hsize= 14,
- .mintu= 60,
- .maxtu= 9014,
- .maclen= 6,
- .bind= etherbind,
- .unbind= etherunbind,
- .bwrite= etherbwrite,
- .addmulti= etheraddmulti,
- .remmulti= etherremmulti,
- .ares= arpenter,
- .areg= sendgarp,
- .pref2addr= etherpref2addr,
- };
- typedef struct Etherrock Etherrock;
- struct Etherrock
- {
- Fs *f; /* file system we belong to */
- Proc *arpp; /* arp process */
- Proc *read4p; /* reading process (v4)*/
- Proc *read6p; /* reading process (v6)*/
- Chan *mchan4; /* Data channel for v4 */
- Chan *achan; /* Arp channel */
- Chan *cchan4; /* Control channel for v4 */
- Chan *mchan6; /* Data channel for v6 */
- Chan *cchan6; /* Control channel for v6 */
- };
- /*
- * ethernet arp request
- */
- enum
- {
- ARPREQUEST = 1,
- ARPREPLY = 2,
- };
- typedef struct Etherarp Etherarp;
- struct Etherarp
- {
- uchar d[6];
- uchar s[6];
- uchar type[2];
- uchar hrd[2];
- uchar pro[2];
- uchar hln;
- uchar pln;
- uchar op[2];
- uchar sha[6];
- uchar spa[4];
- uchar tha[6];
- uchar tpa[4];
- };
- static char *nbmsg = "nonblocking";
- /*
- * called to bind an IP ifc to an ethernet device
- * called with ifc wlock'd
- */
- static void
- etherbind(Ipifc *ifc, int argc, char **argv)
- {
- Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6, *schan;
- char addr[Maxpath]; //char addr[2*KNAMELEN];
- char dir[Maxpath]; //char dir[2*KNAMELEN];
- char *buf;
- int n;
- char *ptr;
- Etherrock *er;
- if(argc < 2)
- error(Ebadarg);
- mchan4 = cchan4 = achan = mchan6 = cchan6 = nil;
- buf = nil;
- if(waserror()){
- if(mchan4 != nil)
- cclose(mchan4);
- if(cchan4 != nil)
- cclose(cchan4);
- if(achan != nil)
- cclose(achan);
- if(mchan6 != nil)
- cclose(mchan6);
- if(cchan6 != nil)
- cclose(cchan6);
- if(buf != nil)
- free(buf);
- nexterror();
- }
- /*
- * open ipv4 conversation
- *
- * the dial will fail if the type is already open on
- * this device.
- */
- snprint(addr, sizeof(addr), "%s!0x800", argv[2]); /* ETIP4 */
- mchan4 = chandial(addr, nil, dir, &cchan4);
- /*
- * make it non-blocking
- */
- devtab[cchan4->type]->write(cchan4, nbmsg, strlen(nbmsg), 0);
- /*
- * get mac address and speed
- */
- snprint(addr, sizeof(addr), "%s/stats", argv[2]);
- buf = smalloc(512);
- schan = namec(addr, Aopen, OREAD, 0);
- if(waserror()){
- cclose(schan);
- nexterror();
- }
- n = devtab[schan->type]->read(schan, buf, 511, 0);
- cclose(schan);
- poperror();
- buf[n] = 0;
- ptr = strstr(buf, "addr: ");
- if(!ptr)
- error(Eio);
- ptr += 6;
- parsemac(ifc->mac, ptr, 6);
- ptr = strstr(buf, "mbps: ");
- if(ptr){
- ptr += 6;
- ifc->mbps = atoi(ptr);
- } else
- ifc->mbps = 100;
- /*
- * open arp conversation
- */
- snprint(addr, sizeof(addr), "%s!0x806", argv[2]); /* ETARP */
- achan = chandial(addr, nil, nil, nil);
- /*
- * open ipv6 conversation
- *
- * the dial will fail if the type is already open on
- * this device.
- */
- snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]); /* ETIP6 */
- mchan6 = chandial(addr, nil, dir, &cchan6);
- /*
- * make it non-blocking
- */
- devtab[cchan6->type]->write(cchan6, nbmsg, strlen(nbmsg), 0);
- er = smalloc(sizeof(*er));
- er->mchan4 = mchan4;
- er->cchan4 = cchan4;
- er->achan = achan;
- er->mchan6 = mchan6;
- er->cchan6 = cchan6;
- er->f = ifc->conv->p->f;
- ifc->arg = er;
- free(buf);
- poperror();
- kproc("etherread4", etherread4, ifc);
- kproc("recvarpproc", recvarpproc, ifc);
- kproc("etherread6", etherread6, ifc);
- }
- /*
- * called with ifc wlock'd
- */
- static void
- etherunbind(Ipifc *ifc)
- {
- Etherrock *er = ifc->arg;
- if(er->read4p)
- postnote(er->read4p, 1, "unbind", 0);
- if(er->read6p)
- postnote(er->read6p, 1, "unbind", 0);
- if(er->arpp)
- postnote(er->arpp, 1, "unbind", 0);
- /* wait for readers to die */
- while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0)
- tsleep(&up->sleep, return0, 0, 300);
- if(er->mchan4 != nil)
- cclose(er->mchan4);
- if(er->achan != nil)
- cclose(er->achan);
- if(er->cchan4 != nil)
- cclose(er->cchan4);
- if(er->mchan6 != nil)
- cclose(er->mchan6);
- if(er->cchan6 != nil)
- cclose(er->cchan6);
- free(er);
- }
- /*
- * called by ipoput with a single block to write with ifc rlock'd
- */
- static void
- etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
- {
- Etherhdr *eh;
- Arpent *a;
- uchar mac[6];
- Etherrock *er = ifc->arg;
- /* get mac address of destination */
- a = arpget(er->f->arp, bp, version, ifc, ip, mac);
- if(a){
- /* check for broadcast or multicast */
- bp = multicastarp(er->f, a, ifc->m, mac);
- if(bp==nil){
- switch(version){
- case V4:
- sendarp(ifc, a);
- break;
- case V6:
- resolveaddr6(ifc, a);
- break;
- default:
- panic("etherbwrite: version %d", version);
- }
- return;
- }
- }
- /* make it a single block with space for the ether header */
- bp = padblock(bp, ifc->m->hsize);
- if(bp->next)
- bp = concatblock(bp);
- if(BLEN(bp) < ifc->mintu)
- bp = adjustblock(bp, ifc->mintu);
- eh = (Etherhdr*)bp->rp;
- /* copy in mac addresses and ether type */
- memmove(eh->s, ifc->mac, sizeof(eh->s));
- memmove(eh->d, mac, sizeof(eh->d));
- switch(version){
- case V4:
- eh->t[0] = 0x08;
- eh->t[1] = 0x00;
- devtab[er->mchan4->type]->bwrite(er->mchan4, bp, 0);
- break;
- case V6:
- eh->t[0] = 0x86;
- eh->t[1] = 0xDD;
- devtab[er->mchan6->type]->bwrite(er->mchan6, bp, 0);
- break;
- default:
- panic("etherbwrite2: version %d", version);
- }
- ifc->out++;
- }
- /*
- * process to read from the ethernet
- */
- static void
- etherread4(void *a)
- {
- Ipifc *ifc;
- Block *bp;
- Etherrock *er;
- ifc = a;
- er = ifc->arg;
- er->read4p = up; /* hide identity under a rock for unbind */
- if(waserror()){
- er->read4p = 0;
- pexit("hangup", 1);
- }
- for(;;){
- bp = devtab[er->mchan4->type]->bread(er->mchan4, ifc->maxtu, 0);
- if(!canrlock(ifc)){
- freeb(bp);
- continue;
- }
- if(waserror()){
- runlock(ifc);
- nexterror();
- }
- ifc->in++;
- bp->rp += ifc->m->hsize;
- if(ifc->lifc == nil)
- freeb(bp);
- else
- ipiput4(er->f, ifc, bp);
- runlock(ifc);
- poperror();
- }
- }
- /*
- * process to read from the ethernet, IPv6
- */
- static void
- etherread6(void *a)
- {
- Ipifc *ifc;
- Block *bp;
- Etherrock *er;
- ifc = a;
- er = ifc->arg;
- er->read6p = up; /* hide identity under a rock for unbind */
- if(waserror()){
- er->read6p = 0;
- pexit("hangup", 1);
- }
- for(;;){
- bp = devtab[er->mchan6->type]->bread(er->mchan6, ifc->maxtu, 0);
- if(!canrlock(ifc)){
- freeb(bp);
- continue;
- }
- if(waserror()){
- runlock(ifc);
- nexterror();
- }
- ifc->in++;
- bp->rp += ifc->m->hsize;
- if(ifc->lifc == nil)
- freeb(bp);
- else
- ipiput6(er->f, ifc, bp);
- runlock(ifc);
- poperror();
- }
- }
- static void
- etheraddmulti(Ipifc *ifc, uchar *a, uchar *)
- {
- uchar mac[6];
- char buf[64];
- Etherrock *er = ifc->arg;
- int version;
- version = multicastea(mac, a);
- snprint(buf, sizeof buf, "addmulti %E", mac);
- switch(version){
- case V4:
- devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
- break;
- case V6:
- devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
- break;
- default:
- panic("etheraddmulti: version %d", version);
- }
- }
- static void
- etherremmulti(Ipifc *ifc, uchar *a, uchar *)
- {
- uchar mac[6];
- char buf[64];
- Etherrock *er = ifc->arg;
- int version;
- version = multicastea(mac, a);
- snprint(buf, sizeof buf, "remmulti %E", mac);
- switch(version){
- case V4:
- devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
- break;
- case V6:
- devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
- break;
- default:
- panic("etherremmulti: version %d", version);
- }
- }
- /*
- * send an ethernet arp
- * (only v4, v6 uses the neighbor discovery, rfc1970)
- */
- static void
- sendarp(Ipifc *ifc, Arpent *a)
- {
- int n;
- Block *bp;
- Etherarp *e;
- Etherrock *er = ifc->arg;
- /* don't do anything if it's been less than a second since the last */
- if(NOW - a->ctime < 1000){
- arprelease(er->f->arp, a);
- return;
- }
- /* remove all but the last message */
- while((bp = a->hold) != nil){
- if(bp == a->last)
- break;
- a->hold = bp->list;
- freeblist(bp);
- }
- /* try to keep it around for a second more */
- a->ctime = NOW;
- arprelease(er->f->arp, a);
- n = sizeof(Etherarp);
- if(n < a->type->mintu)
- n = a->type->mintu;
- bp = allocb(n);
- memset(bp->rp, 0, n);
- e = (Etherarp*)bp->rp;
- memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
- ipv4local(ifc, e->spa);
- memmove(e->sha, ifc->mac, sizeof(e->sha));
- memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */
- memmove(e->s, ifc->mac, sizeof(e->s));
- hnputs(e->type, ETARP);
- hnputs(e->hrd, 1);
- hnputs(e->pro, ETIP4);
- e->hln = sizeof(e->sha);
- e->pln = sizeof(e->spa);
- hnputs(e->op, ARPREQUEST);
- bp->wp += n;
- devtab[er->achan->type]->bwrite(er->achan, bp, 0);
- }
- static void
- resolveaddr6(Ipifc *ifc, Arpent *a)
- {
- int sflag;
- Block *bp;
- Etherrock *er = ifc->arg;
- uchar ipsrc[IPaddrlen];
- /* don't do anything if it's been less than a second since the last */
- if(NOW - a->ctime < ReTransTimer){
- arprelease(er->f->arp, a);
- return;
- }
- /* remove all but the last message */
- while((bp = a->hold) != nil){
- if(bp == a->last)
- break;
- a->hold = bp->list;
- freeblist(bp);
- }
- /* try to keep it around for a second more */
- a->ctime = NOW;
- a->rtime = NOW + ReTransTimer;
- if(a->rxtsrem <= 0) {
- arprelease(er->f->arp, a);
- return;
- }
- a->rxtsrem--;
- arprelease(er->f->arp, a);
- if(sflag = ipv6anylocal(ifc, ipsrc))
- icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
- }
- /*
- * send a gratuitous arp to refresh arp caches
- */
- static void
- sendgarp(Ipifc *ifc, uchar *ip)
- {
- int n;
- Block *bp;
- Etherarp *e;
- Etherrock *er = ifc->arg;
- /* don't arp for our initial non address */
- if(ipcmp(ip, IPnoaddr) == 0)
- return;
- n = sizeof(Etherarp);
- if(n < ifc->m->mintu)
- n = ifc->m->mintu;
- bp = allocb(n);
- memset(bp->rp, 0, n);
- e = (Etherarp*)bp->rp;
- memmove(e->tpa, ip+IPv4off, sizeof(e->tpa));
- memmove(e->spa, ip+IPv4off, sizeof(e->spa));
- memmove(e->sha, ifc->mac, sizeof(e->sha));
- memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */
- memmove(e->s, ifc->mac, sizeof(e->s));
- hnputs(e->type, ETARP);
- hnputs(e->hrd, 1);
- hnputs(e->pro, ETIP4);
- e->hln = sizeof(e->sha);
- e->pln = sizeof(e->spa);
- hnputs(e->op, ARPREQUEST);
- bp->wp += n;
- devtab[er->achan->type]->bwrite(er->achan, bp, 0);
- }
- static void
- recvarp(Ipifc *ifc)
- {
- int n;
- Block *ebp, *rbp;
- Etherarp *e, *r;
- uchar ip[IPaddrlen];
- static uchar eprinted[4];
- Etherrock *er = ifc->arg;
- ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxtu, 0);
- if(ebp == nil)
- return;
- e = (Etherarp*)ebp->rp;
- switch(nhgets(e->op)) {
- default:
- break;
- case ARPREPLY:
- /* check for machine using my ip address */
- v4tov6(ip, e->spa);
- if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
- if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
- print("arprep: 0x%E/0x%E also has ip addr %V\n",
- e->s, e->sha, e->spa);
- break;
- }
- }
- /* make sure we're not entering broadcast addresses */
- if(ipcmp(ip, ipbroadcast) == 0 ||
- !memcmp(e->sha, etherbroadcast, sizeof(e->sha))){
- print("arprep: 0x%E/0x%E cannot register broadcast address %I\n",
- e->s, e->sha, e->spa);
- break;
- }
- arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
- break;
- case ARPREQUEST:
- /* don't answer arps till we know who we are */
- if(ifc->lifc == 0)
- break;
- /* check for machine using my ip or ether address */
- v4tov6(ip, e->spa);
- if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
- if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
- if (memcmp(eprinted, e->spa, sizeof(e->spa))){
- /* print only once */
- print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
- memmove(eprinted, e->spa, sizeof(e->spa));
- }
- }
- } else {
- if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
- print("arpreq: %V also has ether addr %E\n", e->spa, e->sha);
- break;
- }
- }
- /* refresh what we know about sender */
- arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1);
- /* answer only requests for our address or systems we're proxying for */
- v4tov6(ip, e->tpa);
- if(!iplocalonifc(ifc, ip))
- if(!ipproxyifc(er->f, ifc, ip))
- break;
- n = sizeof(Etherarp);
- if(n < ifc->mintu)
- n = ifc->mintu;
- rbp = allocb(n);
- r = (Etherarp*)rbp->rp;
- memset(r, 0, sizeof(Etherarp));
- hnputs(r->type, ETARP);
- hnputs(r->hrd, 1);
- hnputs(r->pro, ETIP4);
- r->hln = sizeof(r->sha);
- r->pln = sizeof(r->spa);
- hnputs(r->op, ARPREPLY);
- memmove(r->tha, e->sha, sizeof(r->tha));
- memmove(r->tpa, e->spa, sizeof(r->tpa));
- memmove(r->sha, ifc->mac, sizeof(r->sha));
- memmove(r->spa, e->tpa, sizeof(r->spa));
- memmove(r->d, e->sha, sizeof(r->d));
- memmove(r->s, ifc->mac, sizeof(r->s));
- rbp->wp += n;
- devtab[er->achan->type]->bwrite(er->achan, rbp, 0);
- }
- freeb(ebp);
- }
- static void
- recvarpproc(void *v)
- {
- Ipifc *ifc = v;
- Etherrock *er = ifc->arg;
- er->arpp = up;
- if(waserror()){
- er->arpp = 0;
- pexit("hangup", 1);
- }
- for(;;)
- recvarp(ifc);
- }
- static int
- multicastea(uchar *ea, uchar *ip)
- {
- int x;
- switch(x = ipismulticast(ip)){
- case V4:
- ea[0] = 0x01;
- ea[1] = 0x00;
- ea[2] = 0x5e;
- ea[3] = ip[13] & 0x7f;
- ea[4] = ip[14];
- ea[5] = ip[15];
- break;
- case V6:
- ea[0] = 0x33;
- ea[1] = 0x33;
- ea[2] = ip[12];
- ea[3] = ip[13];
- ea[4] = ip[14];
- ea[5] = ip[15];
- break;
- }
- return x;
- }
- /*
- * fill in an arp entry for broadcast or multicast
- * addresses. Return the first queued packet for the
- * IP address.
- */
- static Block*
- multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac)
- {
- /* is it broadcast? */
- switch(ipforme(f, a->ip)){
- case Runi:
- return nil;
- case Rbcast:
- memset(mac, 0xff, 6);
- return arpresolve(f->arp, a, medium, mac);
- default:
- break;
- }
- /* if multicast, fill in mac */
- switch(multicastea(mac, a->ip)){
- case V4:
- case V6:
- return arpresolve(f->arp, a, medium, mac);
- }
- /* let arp take care of it */
- return nil;
- }
- void
- ethermediumlink(void)
- {
- addipmedium(ðermedium);
- addipmedium(&gbemedium);
- }
- static void
- etherpref2addr(uchar *pref, uchar *ea)
- {
- pref[8] = ea[0] | 0x2;
- pref[9] = ea[1];
- pref[10] = ea[2];
- pref[11] = 0xFF;
- pref[12] = 0xFE;
- pref[13] = ea[3];
- pref[14] = ea[4];
- pref[15] = ea[5];
- }
|