17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "../port/error.h"
77dd7cddfSDavid du Colombier
8ac020a8fSDavid du Colombier #include "../port/netif.h"
97dd7cddfSDavid du Colombier #include "ip.h"
103ff48bf5SDavid du Colombier #include "ipv6.h"
117dd7cddfSDavid du Colombier
127dd7cddfSDavid du Colombier typedef struct Etherhdr Etherhdr;
137dd7cddfSDavid du Colombier struct Etherhdr
147dd7cddfSDavid du Colombier {
157dd7cddfSDavid du Colombier uchar d[6];
167dd7cddfSDavid du Colombier uchar s[6];
177dd7cddfSDavid du Colombier uchar t[2];
187dd7cddfSDavid du Colombier };
197dd7cddfSDavid du Colombier
205d82c6aeSDavid du Colombier static uchar ipbroadcast[IPaddrlen] = {
215d82c6aeSDavid du Colombier 0xff,0xff,0xff,0xff,
225d82c6aeSDavid du Colombier 0xff,0xff,0xff,0xff,
235d82c6aeSDavid du Colombier 0xff,0xff,0xff,0xff,
245d82c6aeSDavid du Colombier 0xff,0xff,0xff,0xff,
255d82c6aeSDavid du Colombier };
265d82c6aeSDavid du Colombier
275d82c6aeSDavid du Colombier static uchar etherbroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
285d82c6aeSDavid du Colombier
293ff48bf5SDavid du Colombier static void etherread4(void *a);
303ff48bf5SDavid du Colombier static void etherread6(void *a);
317dd7cddfSDavid du Colombier static void etherbind(Ipifc *ifc, int argc, char **argv);
327dd7cddfSDavid du Colombier static void etherunbind(Ipifc *ifc);
337dd7cddfSDavid du Colombier static void etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
347dd7cddfSDavid du Colombier static void etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia);
357dd7cddfSDavid du Colombier static void etherremmulti(Ipifc *ifc, uchar *a, uchar *ia);
3659cc4ca5SDavid du Colombier static Block* multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac);
377dd7cddfSDavid du Colombier static void sendarp(Ipifc *ifc, Arpent *a);
387dd7cddfSDavid du Colombier static void sendgarp(Ipifc *ifc, uchar*);
397dd7cddfSDavid du Colombier static int multicastea(uchar *ea, uchar *ip);
407dd7cddfSDavid du Colombier static void recvarpproc(void*);
413ff48bf5SDavid du Colombier static void resolveaddr6(Ipifc *ifc, Arpent *a);
423ff48bf5SDavid du Colombier static void etherpref2addr(uchar *pref, uchar *ea);
437dd7cddfSDavid du Colombier
447dd7cddfSDavid du Colombier Medium ethermedium =
457dd7cddfSDavid du Colombier {
467dd7cddfSDavid du Colombier .name= "ether",
477dd7cddfSDavid du Colombier .hsize= 14,
483f695129SDavid du Colombier .mintu= 60,
493f695129SDavid du Colombier .maxtu= 1514,
507dd7cddfSDavid du Colombier .maclen= 6,
517dd7cddfSDavid du Colombier .bind= etherbind,
527dd7cddfSDavid du Colombier .unbind= etherunbind,
537dd7cddfSDavid du Colombier .bwrite= etherbwrite,
547dd7cddfSDavid du Colombier .addmulti= etheraddmulti,
557dd7cddfSDavid du Colombier .remmulti= etherremmulti,
567dd7cddfSDavid du Colombier .ares= arpenter,
577dd7cddfSDavid du Colombier .areg= sendgarp,
583ff48bf5SDavid du Colombier .pref2addr= etherpref2addr,
597dd7cddfSDavid du Colombier };
607dd7cddfSDavid du Colombier
6159cc4ca5SDavid du Colombier Medium gbemedium =
6259cc4ca5SDavid du Colombier {
6359cc4ca5SDavid du Colombier .name= "gbe",
6459cc4ca5SDavid du Colombier .hsize= 14,
653f695129SDavid du Colombier .mintu= 60,
663f695129SDavid du Colombier .maxtu= 9014,
6759cc4ca5SDavid du Colombier .maclen= 6,
6859cc4ca5SDavid du Colombier .bind= etherbind,
6959cc4ca5SDavid du Colombier .unbind= etherunbind,
7059cc4ca5SDavid du Colombier .bwrite= etherbwrite,
7159cc4ca5SDavid du Colombier .addmulti= etheraddmulti,
7259cc4ca5SDavid du Colombier .remmulti= etherremmulti,
7359cc4ca5SDavid du Colombier .ares= arpenter,
7459cc4ca5SDavid du Colombier .areg= sendgarp,
753ff48bf5SDavid du Colombier .pref2addr= etherpref2addr,
7659cc4ca5SDavid du Colombier };
7759cc4ca5SDavid du Colombier
787dd7cddfSDavid du Colombier typedef struct Etherrock Etherrock;
797dd7cddfSDavid du Colombier struct Etherrock
807dd7cddfSDavid du Colombier {
817dd7cddfSDavid du Colombier Fs *f; /* file system we belong to */
827dd7cddfSDavid du Colombier Proc *arpp; /* arp process */
833ff48bf5SDavid du Colombier Proc *read4p; /* reading process (v4)*/
843ff48bf5SDavid du Colombier Proc *read6p; /* reading process (v6)*/
853ff48bf5SDavid du Colombier Chan *mchan4; /* Data channel for v4 */
867dd7cddfSDavid du Colombier Chan *achan; /* Arp channel */
873ff48bf5SDavid du Colombier Chan *cchan4; /* Control channel for v4 */
883ff48bf5SDavid du Colombier Chan *mchan6; /* Data channel for v6 */
893ff48bf5SDavid du Colombier Chan *cchan6; /* Control channel for v6 */
907dd7cddfSDavid du Colombier };
917dd7cddfSDavid du Colombier
927dd7cddfSDavid du Colombier /*
937dd7cddfSDavid du Colombier * ethernet arp request
947dd7cddfSDavid du Colombier */
957dd7cddfSDavid du Colombier enum
967dd7cddfSDavid du Colombier {
977dd7cddfSDavid du Colombier ARPREQUEST = 1,
987dd7cddfSDavid du Colombier ARPREPLY = 2,
997dd7cddfSDavid du Colombier };
1003ff48bf5SDavid du Colombier
1017dd7cddfSDavid du Colombier typedef struct Etherarp Etherarp;
1027dd7cddfSDavid du Colombier struct Etherarp
1037dd7cddfSDavid du Colombier {
1047dd7cddfSDavid du Colombier uchar d[6];
1057dd7cddfSDavid du Colombier uchar s[6];
1067dd7cddfSDavid du Colombier uchar type[2];
1077dd7cddfSDavid du Colombier uchar hrd[2];
1087dd7cddfSDavid du Colombier uchar pro[2];
1097dd7cddfSDavid du Colombier uchar hln;
1107dd7cddfSDavid du Colombier uchar pln;
1117dd7cddfSDavid du Colombier uchar op[2];
1127dd7cddfSDavid du Colombier uchar sha[6];
1137dd7cddfSDavid du Colombier uchar spa[4];
1147dd7cddfSDavid du Colombier uchar tha[6];
1157dd7cddfSDavid du Colombier uchar tpa[4];
1167dd7cddfSDavid du Colombier };
1177dd7cddfSDavid du Colombier
1183ff48bf5SDavid du Colombier static char *nbmsg = "nonblocking";
1197dd7cddfSDavid du Colombier
1207dd7cddfSDavid du Colombier /*
1217dd7cddfSDavid du Colombier * called to bind an IP ifc to an ethernet device
1227dd7cddfSDavid du Colombier * called with ifc wlock'd
1237dd7cddfSDavid du Colombier */
1247dd7cddfSDavid du Colombier static void
etherbind(Ipifc * ifc,int argc,char ** argv)1257dd7cddfSDavid du Colombier etherbind(Ipifc *ifc, int argc, char **argv)
1267dd7cddfSDavid du Colombier {
1273ff48bf5SDavid du Colombier Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6, *schan;
1283ff48bf5SDavid du Colombier char addr[Maxpath]; //char addr[2*KNAMELEN];
1293ff48bf5SDavid du Colombier char dir[Maxpath]; //char dir[2*KNAMELEN];
1307dd7cddfSDavid du Colombier char *buf;
13180ee5cbfSDavid du Colombier int n;
1327dd7cddfSDavid du Colombier char *ptr;
1337dd7cddfSDavid du Colombier Etherrock *er;
1347dd7cddfSDavid du Colombier
1357dd7cddfSDavid du Colombier if(argc < 2)
1367dd7cddfSDavid du Colombier error(Ebadarg);
1377dd7cddfSDavid du Colombier
1383ff48bf5SDavid du Colombier mchan4 = cchan4 = achan = mchan6 = cchan6 = nil;
1397dd7cddfSDavid du Colombier buf = nil;
1407dd7cddfSDavid du Colombier if(waserror()){
1413ff48bf5SDavid du Colombier if(mchan4 != nil)
1423ff48bf5SDavid du Colombier cclose(mchan4);
1433ff48bf5SDavid du Colombier if(cchan4 != nil)
1443ff48bf5SDavid du Colombier cclose(cchan4);
1457dd7cddfSDavid du Colombier if(achan != nil)
1467dd7cddfSDavid du Colombier cclose(achan);
1473ff48bf5SDavid du Colombier if(mchan6 != nil)
1483ff48bf5SDavid du Colombier cclose(mchan6);
1493ff48bf5SDavid du Colombier if(cchan6 != nil)
1503ff48bf5SDavid du Colombier cclose(cchan6);
1517dd7cddfSDavid du Colombier if(buf != nil)
1527dd7cddfSDavid du Colombier free(buf);
1537dd7cddfSDavid du Colombier nexterror();
1547dd7cddfSDavid du Colombier }
1557dd7cddfSDavid du Colombier
1567dd7cddfSDavid du Colombier /*
157ac020a8fSDavid du Colombier * open ipv4 conversation
1587dd7cddfSDavid du Colombier *
1597dd7cddfSDavid du Colombier * the dial will fail if the type is already open on
1607dd7cddfSDavid du Colombier * this device.
1617dd7cddfSDavid du Colombier */
162ac020a8fSDavid du Colombier snprint(addr, sizeof(addr), "%s!0x800", argv[2]); /* ETIP4 */
1633ff48bf5SDavid du Colombier mchan4 = chandial(addr, nil, dir, &cchan4);
1643ff48bf5SDavid du Colombier
1653ff48bf5SDavid du Colombier /*
1663ff48bf5SDavid du Colombier * make it non-blocking
1673ff48bf5SDavid du Colombier */
1683ff48bf5SDavid du Colombier devtab[cchan4->type]->write(cchan4, nbmsg, strlen(nbmsg), 0);
1697dd7cddfSDavid du Colombier
1707dd7cddfSDavid du Colombier /*
1713f695129SDavid du Colombier * get mac address and speed
1727dd7cddfSDavid du Colombier */
1733432ceaeSDavid du Colombier snprint(addr, sizeof(addr), "%s/stats", argv[2]);
1747dd7cddfSDavid du Colombier buf = smalloc(512);
1753ff48bf5SDavid du Colombier schan = namec(addr, Aopen, OREAD, 0);
1763ff48bf5SDavid du Colombier if(waserror()){
1773ff48bf5SDavid du Colombier cclose(schan);
1783ff48bf5SDavid du Colombier nexterror();
1793ff48bf5SDavid du Colombier }
1803ff48bf5SDavid du Colombier n = devtab[schan->type]->read(schan, buf, 511, 0);
1813ff48bf5SDavid du Colombier cclose(schan);
1823ff48bf5SDavid du Colombier poperror();
1837dd7cddfSDavid du Colombier buf[n] = 0;
1847dd7cddfSDavid du Colombier
1857dd7cddfSDavid du Colombier ptr = strstr(buf, "addr: ");
1867dd7cddfSDavid du Colombier if(!ptr)
1877dd7cddfSDavid du Colombier error(Eio);
1887dd7cddfSDavid du Colombier ptr += 6;
1897dd7cddfSDavid du Colombier parsemac(ifc->mac, ptr, 6);
1907dd7cddfSDavid du Colombier
1913f695129SDavid du Colombier ptr = strstr(buf, "mbps: ");
1923f695129SDavid du Colombier if(ptr){
1933f695129SDavid du Colombier ptr += 6;
1943f695129SDavid du Colombier ifc->mbps = atoi(ptr);
1953f695129SDavid du Colombier } else
1963f695129SDavid du Colombier ifc->mbps = 100;
1973f695129SDavid du Colombier
1987dd7cddfSDavid du Colombier /*
1997dd7cddfSDavid du Colombier * open arp conversation
2007dd7cddfSDavid du Colombier */
201ac020a8fSDavid du Colombier snprint(addr, sizeof(addr), "%s!0x806", argv[2]); /* ETARP */
20280ee5cbfSDavid du Colombier achan = chandial(addr, nil, nil, nil);
2037dd7cddfSDavid du Colombier
2043ff48bf5SDavid du Colombier /*
2053e76a0ddSDavid du Colombier * open ipv6 conversation
2063ff48bf5SDavid du Colombier *
2073ff48bf5SDavid du Colombier * the dial will fail if the type is already open on
2083ff48bf5SDavid du Colombier * this device.
2093ff48bf5SDavid du Colombier */
210ac020a8fSDavid du Colombier snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]); /* ETIP6 */
2113ff48bf5SDavid du Colombier mchan6 = chandial(addr, nil, dir, &cchan6);
2123ff48bf5SDavid du Colombier
2133ff48bf5SDavid du Colombier /*
2143ff48bf5SDavid du Colombier * make it non-blocking
2153ff48bf5SDavid du Colombier */
2163ff48bf5SDavid du Colombier devtab[cchan6->type]->write(cchan6, nbmsg, strlen(nbmsg), 0);
2173ff48bf5SDavid du Colombier
2187dd7cddfSDavid du Colombier er = smalloc(sizeof(*er));
2193ff48bf5SDavid du Colombier er->mchan4 = mchan4;
2203ff48bf5SDavid du Colombier er->cchan4 = cchan4;
2217dd7cddfSDavid du Colombier er->achan = achan;
2223ff48bf5SDavid du Colombier er->mchan6 = mchan6;
2233ff48bf5SDavid du Colombier er->cchan6 = cchan6;
2247dd7cddfSDavid du Colombier er->f = ifc->conv->p->f;
2257dd7cddfSDavid du Colombier ifc->arg = er;
2267dd7cddfSDavid du Colombier
2277dd7cddfSDavid du Colombier free(buf);
2287dd7cddfSDavid du Colombier poperror();
2297dd7cddfSDavid du Colombier
2303ff48bf5SDavid du Colombier kproc("etherread4", etherread4, ifc);
2317dd7cddfSDavid du Colombier kproc("recvarpproc", recvarpproc, ifc);
2323ff48bf5SDavid du Colombier kproc("etherread6", etherread6, ifc);
2337dd7cddfSDavid du Colombier }
2347dd7cddfSDavid du Colombier
2357dd7cddfSDavid du Colombier /*
2367dd7cddfSDavid du Colombier * called with ifc wlock'd
2377dd7cddfSDavid du Colombier */
2387dd7cddfSDavid du Colombier static void
etherunbind(Ipifc * ifc)2397dd7cddfSDavid du Colombier etherunbind(Ipifc *ifc)
2407dd7cddfSDavid du Colombier {
2417dd7cddfSDavid du Colombier Etherrock *er = ifc->arg;
2427dd7cddfSDavid du Colombier
2433ff48bf5SDavid du Colombier if(er->read4p)
2443ff48bf5SDavid du Colombier postnote(er->read4p, 1, "unbind", 0);
2453ff48bf5SDavid du Colombier if(er->read6p)
2463ff48bf5SDavid du Colombier postnote(er->read6p, 1, "unbind", 0);
2477dd7cddfSDavid du Colombier if(er->arpp)
2487dd7cddfSDavid du Colombier postnote(er->arpp, 1, "unbind", 0);
2497dd7cddfSDavid du Colombier
2507dd7cddfSDavid du Colombier /* wait for readers to die */
2513ff48bf5SDavid du Colombier while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0)
2527dd7cddfSDavid du Colombier tsleep(&up->sleep, return0, 0, 300);
2537dd7cddfSDavid du Colombier
2543ff48bf5SDavid du Colombier if(er->mchan4 != nil)
2553ff48bf5SDavid du Colombier cclose(er->mchan4);
2567dd7cddfSDavid du Colombier if(er->achan != nil)
2577dd7cddfSDavid du Colombier cclose(er->achan);
2583ff48bf5SDavid du Colombier if(er->cchan4 != nil)
2593ff48bf5SDavid du Colombier cclose(er->cchan4);
2603ff48bf5SDavid du Colombier if(er->mchan6 != nil)
2613ff48bf5SDavid du Colombier cclose(er->mchan6);
2623ff48bf5SDavid du Colombier if(er->cchan6 != nil)
2633ff48bf5SDavid du Colombier cclose(er->cchan6);
2647dd7cddfSDavid du Colombier
2657dd7cddfSDavid du Colombier free(er);
2667dd7cddfSDavid du Colombier }
2677dd7cddfSDavid du Colombier
2687dd7cddfSDavid du Colombier /*
2697dd7cddfSDavid du Colombier * called by ipoput with a single block to write with ifc rlock'd
2707dd7cddfSDavid du Colombier */
2717dd7cddfSDavid du Colombier static void
etherbwrite(Ipifc * ifc,Block * bp,int version,uchar * ip)2727dd7cddfSDavid du Colombier etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
2737dd7cddfSDavid du Colombier {
2747dd7cddfSDavid du Colombier Etherhdr *eh;
2757dd7cddfSDavid du Colombier Arpent *a;
2767dd7cddfSDavid du Colombier uchar mac[6];
2777dd7cddfSDavid du Colombier Etherrock *er = ifc->arg;
2787dd7cddfSDavid du Colombier
2797dd7cddfSDavid du Colombier /* get mac address of destination */
2803ff48bf5SDavid du Colombier a = arpget(er->f->arp, bp, version, ifc, ip, mac);
2817dd7cddfSDavid du Colombier if(a){
2827dd7cddfSDavid du Colombier /* check for broadcast or multicast */
28359cc4ca5SDavid du Colombier bp = multicastarp(er->f, a, ifc->m, mac);
2847dd7cddfSDavid du Colombier if(bp==nil){
2853ff48bf5SDavid du Colombier switch(version){
2863ff48bf5SDavid du Colombier case V4:
2877dd7cddfSDavid du Colombier sendarp(ifc, a);
2883ff48bf5SDavid du Colombier break;
2893ff48bf5SDavid du Colombier case V6:
2903ff48bf5SDavid du Colombier resolveaddr6(ifc, a);
2913ff48bf5SDavid du Colombier break;
2923ff48bf5SDavid du Colombier default:
2933ff48bf5SDavid du Colombier panic("etherbwrite: version %d", version);
2943ff48bf5SDavid du Colombier }
2957dd7cddfSDavid du Colombier return;
2967dd7cddfSDavid du Colombier }
2977dd7cddfSDavid du Colombier }
2987dd7cddfSDavid du Colombier
2997dd7cddfSDavid du Colombier /* make it a single block with space for the ether header */
3007dd7cddfSDavid du Colombier bp = padblock(bp, ifc->m->hsize);
3017dd7cddfSDavid du Colombier if(bp->next)
3027dd7cddfSDavid du Colombier bp = concatblock(bp);
3033f695129SDavid du Colombier if(BLEN(bp) < ifc->mintu)
3043f695129SDavid du Colombier bp = adjustblock(bp, ifc->mintu);
3057dd7cddfSDavid du Colombier eh = (Etherhdr*)bp->rp;
3067dd7cddfSDavid du Colombier
3077dd7cddfSDavid du Colombier /* copy in mac addresses and ether type */
3087dd7cddfSDavid du Colombier memmove(eh->s, ifc->mac, sizeof(eh->s));
3097dd7cddfSDavid du Colombier memmove(eh->d, mac, sizeof(eh->d));
3103ff48bf5SDavid du Colombier
3117dd7cddfSDavid du Colombier switch(version){
3127dd7cddfSDavid du Colombier case V4:
3137dd7cddfSDavid du Colombier eh->t[0] = 0x08;
3147dd7cddfSDavid du Colombier eh->t[1] = 0x00;
3153ff48bf5SDavid du Colombier devtab[er->mchan4->type]->bwrite(er->mchan4, bp, 0);
3167dd7cddfSDavid du Colombier break;
3177dd7cddfSDavid du Colombier case V6:
3187dd7cddfSDavid du Colombier eh->t[0] = 0x86;
3197dd7cddfSDavid du Colombier eh->t[1] = 0xDD;
3203ff48bf5SDavid du Colombier devtab[er->mchan6->type]->bwrite(er->mchan6, bp, 0);
3217dd7cddfSDavid du Colombier break;
3223ff48bf5SDavid du Colombier default:
3233ff48bf5SDavid du Colombier panic("etherbwrite2: version %d", version);
3247dd7cddfSDavid du Colombier }
3257dd7cddfSDavid du Colombier ifc->out++;
3267dd7cddfSDavid du Colombier }
3277dd7cddfSDavid du Colombier
3283ff48bf5SDavid du Colombier
3297dd7cddfSDavid du Colombier /*
3307dd7cddfSDavid du Colombier * process to read from the ethernet
3317dd7cddfSDavid du Colombier */
3327dd7cddfSDavid du Colombier static void
etherread4(void * a)3333ff48bf5SDavid du Colombier etherread4(void *a)
3347dd7cddfSDavid du Colombier {
3357dd7cddfSDavid du Colombier Ipifc *ifc;
3367dd7cddfSDavid du Colombier Block *bp;
3377dd7cddfSDavid du Colombier Etherrock *er;
3387dd7cddfSDavid du Colombier
3397dd7cddfSDavid du Colombier ifc = a;
3407dd7cddfSDavid du Colombier er = ifc->arg;
3413ff48bf5SDavid du Colombier er->read4p = up; /* hide identity under a rock for unbind */
3427dd7cddfSDavid du Colombier if(waserror()){
3433ff48bf5SDavid du Colombier er->read4p = 0;
3447dd7cddfSDavid du Colombier pexit("hangup", 1);
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier for(;;){
3473f695129SDavid du Colombier bp = devtab[er->mchan4->type]->bread(er->mchan4, ifc->maxtu, 0);
3487dd7cddfSDavid du Colombier if(!canrlock(ifc)){
3497dd7cddfSDavid du Colombier freeb(bp);
3507dd7cddfSDavid du Colombier continue;
3517dd7cddfSDavid du Colombier }
3527dd7cddfSDavid du Colombier if(waserror()){
3537dd7cddfSDavid du Colombier runlock(ifc);
3547dd7cddfSDavid du Colombier nexterror();
3557dd7cddfSDavid du Colombier }
3567dd7cddfSDavid du Colombier ifc->in++;
3577dd7cddfSDavid du Colombier bp->rp += ifc->m->hsize;
3587dd7cddfSDavid du Colombier if(ifc->lifc == nil)
3597dd7cddfSDavid du Colombier freeb(bp);
3607dd7cddfSDavid du Colombier else
3613ff48bf5SDavid du Colombier ipiput4(er->f, ifc, bp);
3623ff48bf5SDavid du Colombier runlock(ifc);
3633ff48bf5SDavid du Colombier poperror();
3643ff48bf5SDavid du Colombier }
3653ff48bf5SDavid du Colombier }
3663ff48bf5SDavid du Colombier
3673ff48bf5SDavid du Colombier
3683ff48bf5SDavid du Colombier /*
3693ff48bf5SDavid du Colombier * process to read from the ethernet, IPv6
3703ff48bf5SDavid du Colombier */
3713ff48bf5SDavid du Colombier static void
etherread6(void * a)3723ff48bf5SDavid du Colombier etherread6(void *a)
3733ff48bf5SDavid du Colombier {
3743ff48bf5SDavid du Colombier Ipifc *ifc;
3753ff48bf5SDavid du Colombier Block *bp;
3763ff48bf5SDavid du Colombier Etherrock *er;
3773ff48bf5SDavid du Colombier
3783ff48bf5SDavid du Colombier ifc = a;
3793ff48bf5SDavid du Colombier er = ifc->arg;
3803ff48bf5SDavid du Colombier er->read6p = up; /* hide identity under a rock for unbind */
3813ff48bf5SDavid du Colombier if(waserror()){
3823ff48bf5SDavid du Colombier er->read6p = 0;
3833ff48bf5SDavid du Colombier pexit("hangup", 1);
3843ff48bf5SDavid du Colombier }
3853ff48bf5SDavid du Colombier for(;;){
3863f695129SDavid du Colombier bp = devtab[er->mchan6->type]->bread(er->mchan6, ifc->maxtu, 0);
3873ff48bf5SDavid du Colombier if(!canrlock(ifc)){
3883ff48bf5SDavid du Colombier freeb(bp);
3893ff48bf5SDavid du Colombier continue;
3903ff48bf5SDavid du Colombier }
3913ff48bf5SDavid du Colombier if(waserror()){
3923ff48bf5SDavid du Colombier runlock(ifc);
3933ff48bf5SDavid du Colombier nexterror();
3943ff48bf5SDavid du Colombier }
3953ff48bf5SDavid du Colombier ifc->in++;
3963ff48bf5SDavid du Colombier bp->rp += ifc->m->hsize;
3973ff48bf5SDavid du Colombier if(ifc->lifc == nil)
3983ff48bf5SDavid du Colombier freeb(bp);
3993ff48bf5SDavid du Colombier else
4003ff48bf5SDavid du Colombier ipiput6(er->f, ifc, bp);
4017dd7cddfSDavid du Colombier runlock(ifc);
4027dd7cddfSDavid du Colombier poperror();
4037dd7cddfSDavid du Colombier }
4047dd7cddfSDavid du Colombier }
4057dd7cddfSDavid du Colombier
4067dd7cddfSDavid du Colombier static void
etheraddmulti(Ipifc * ifc,uchar * a,uchar *)4077dd7cddfSDavid du Colombier etheraddmulti(Ipifc *ifc, uchar *a, uchar *)
4087dd7cddfSDavid du Colombier {
4097dd7cddfSDavid du Colombier uchar mac[6];
4107dd7cddfSDavid du Colombier char buf[64];
4117dd7cddfSDavid du Colombier Etherrock *er = ifc->arg;
4123ff48bf5SDavid du Colombier int version;
4137dd7cddfSDavid du Colombier
4143ff48bf5SDavid du Colombier version = multicastea(mac, a);
415*4e3613abSDavid du Colombier snprint(buf, sizeof buf, "addmulti %E", mac);
4163ff48bf5SDavid du Colombier switch(version){
4173ff48bf5SDavid du Colombier case V4:
4183ff48bf5SDavid du Colombier devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
4193ff48bf5SDavid du Colombier break;
4203ff48bf5SDavid du Colombier case V6:
4213ff48bf5SDavid du Colombier devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
4223ff48bf5SDavid du Colombier break;
4233ff48bf5SDavid du Colombier default:
4243ff48bf5SDavid du Colombier panic("etheraddmulti: version %d", version);
4253ff48bf5SDavid du Colombier }
4267dd7cddfSDavid du Colombier }
4277dd7cddfSDavid du Colombier
4287dd7cddfSDavid du Colombier static void
etherremmulti(Ipifc * ifc,uchar * a,uchar *)4297dd7cddfSDavid du Colombier etherremmulti(Ipifc *ifc, uchar *a, uchar *)
4307dd7cddfSDavid du Colombier {
4317dd7cddfSDavid du Colombier uchar mac[6];
4327dd7cddfSDavid du Colombier char buf[64];
4337dd7cddfSDavid du Colombier Etherrock *er = ifc->arg;
4343ff48bf5SDavid du Colombier int version;
4357dd7cddfSDavid du Colombier
4363ff48bf5SDavid du Colombier version = multicastea(mac, a);
437*4e3613abSDavid du Colombier snprint(buf, sizeof buf, "remmulti %E", mac);
4383ff48bf5SDavid du Colombier switch(version){
4393ff48bf5SDavid du Colombier case V4:
4403ff48bf5SDavid du Colombier devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
4413ff48bf5SDavid du Colombier break;
4423ff48bf5SDavid du Colombier case V6:
4433ff48bf5SDavid du Colombier devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
4443ff48bf5SDavid du Colombier break;
4453ff48bf5SDavid du Colombier default:
4463ff48bf5SDavid du Colombier panic("etherremmulti: version %d", version);
4473ff48bf5SDavid du Colombier }
4487dd7cddfSDavid du Colombier }
4497dd7cddfSDavid du Colombier
4507dd7cddfSDavid du Colombier /*
4517dd7cddfSDavid du Colombier * send an ethernet arp
4527dd7cddfSDavid du Colombier * (only v4, v6 uses the neighbor discovery, rfc1970)
4537dd7cddfSDavid du Colombier */
4547dd7cddfSDavid du Colombier static void
sendarp(Ipifc * ifc,Arpent * a)4557dd7cddfSDavid du Colombier sendarp(Ipifc *ifc, Arpent *a)
4567dd7cddfSDavid du Colombier {
4577dd7cddfSDavid du Colombier int n;
4587dd7cddfSDavid du Colombier Block *bp;
4597dd7cddfSDavid du Colombier Etherarp *e;
4607dd7cddfSDavid du Colombier Etherrock *er = ifc->arg;
4617dd7cddfSDavid du Colombier
4627dd7cddfSDavid du Colombier /* don't do anything if it's been less than a second since the last */
463a6a9e072SDavid du Colombier if(NOW - a->ctime < 1000){
4647dd7cddfSDavid du Colombier arprelease(er->f->arp, a);
4657dd7cddfSDavid du Colombier return;
4667dd7cddfSDavid du Colombier }
4677dd7cddfSDavid du Colombier
4687dd7cddfSDavid du Colombier /* remove all but the last message */
4697dd7cddfSDavid du Colombier while((bp = a->hold) != nil){
4707dd7cddfSDavid du Colombier if(bp == a->last)
4717dd7cddfSDavid du Colombier break;
4727dd7cddfSDavid du Colombier a->hold = bp->list;
4737dd7cddfSDavid du Colombier freeblist(bp);
4747dd7cddfSDavid du Colombier }
4757dd7cddfSDavid du Colombier
4767dd7cddfSDavid du Colombier /* try to keep it around for a second more */
477a6a9e072SDavid du Colombier a->ctime = NOW;
4787dd7cddfSDavid du Colombier arprelease(er->f->arp, a);
4797dd7cddfSDavid du Colombier
4807dd7cddfSDavid du Colombier n = sizeof(Etherarp);
4813f695129SDavid du Colombier if(n < a->type->mintu)
4823f695129SDavid du Colombier n = a->type->mintu;
4837dd7cddfSDavid du Colombier bp = allocb(n);
4847dd7cddfSDavid du Colombier memset(bp->rp, 0, n);
4857dd7cddfSDavid du Colombier e = (Etherarp*)bp->rp;
4867dd7cddfSDavid du Colombier memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
4877dd7cddfSDavid du Colombier ipv4local(ifc, e->spa);
4887dd7cddfSDavid du Colombier memmove(e->sha, ifc->mac, sizeof(e->sha));
4897dd7cddfSDavid du Colombier memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */
4907dd7cddfSDavid du Colombier memmove(e->s, ifc->mac, sizeof(e->s));
4917dd7cddfSDavid du Colombier
4927dd7cddfSDavid du Colombier hnputs(e->type, ETARP);
4937dd7cddfSDavid du Colombier hnputs(e->hrd, 1);
4943ff48bf5SDavid du Colombier hnputs(e->pro, ETIP4);
4957dd7cddfSDavid du Colombier e->hln = sizeof(e->sha);
4967dd7cddfSDavid du Colombier e->pln = sizeof(e->spa);
4977dd7cddfSDavid du Colombier hnputs(e->op, ARPREQUEST);
4987dd7cddfSDavid du Colombier bp->wp += n;
4997dd7cddfSDavid du Colombier
500db7ae703SDavid du Colombier devtab[er->achan->type]->bwrite(er->achan, bp, 0);
5017dd7cddfSDavid du Colombier }
5027dd7cddfSDavid du Colombier
5033ff48bf5SDavid du Colombier static void
resolveaddr6(Ipifc * ifc,Arpent * a)5043ff48bf5SDavid du Colombier resolveaddr6(Ipifc *ifc, Arpent *a)
5053ff48bf5SDavid du Colombier {
5063ff48bf5SDavid du Colombier int sflag;
5073ff48bf5SDavid du Colombier Block *bp;
5083ff48bf5SDavid du Colombier Etherrock *er = ifc->arg;
5093ff48bf5SDavid du Colombier uchar ipsrc[IPaddrlen];
5103ff48bf5SDavid du Colombier
5113ff48bf5SDavid du Colombier /* don't do anything if it's been less than a second since the last */
512a6a9e072SDavid du Colombier if(NOW - a->ctime < ReTransTimer){
5133ff48bf5SDavid du Colombier arprelease(er->f->arp, a);
5143ff48bf5SDavid du Colombier return;
5153ff48bf5SDavid du Colombier }
5163ff48bf5SDavid du Colombier
5173ff48bf5SDavid du Colombier /* remove all but the last message */
5183ff48bf5SDavid du Colombier while((bp = a->hold) != nil){
5193ff48bf5SDavid du Colombier if(bp == a->last)
5203ff48bf5SDavid du Colombier break;
5213ff48bf5SDavid du Colombier a->hold = bp->list;
5223ff48bf5SDavid du Colombier freeblist(bp);
5233ff48bf5SDavid du Colombier }
5243ff48bf5SDavid du Colombier
5253ff48bf5SDavid du Colombier /* try to keep it around for a second more */
526a6a9e072SDavid du Colombier a->ctime = NOW;
527a6a9e072SDavid du Colombier a->rtime = NOW + ReTransTimer;
5283ff48bf5SDavid du Colombier if(a->rxtsrem <= 0) {
5293ff48bf5SDavid du Colombier arprelease(er->f->arp, a);
5303ff48bf5SDavid du Colombier return;
5313ff48bf5SDavid du Colombier }
5323ff48bf5SDavid du Colombier
5333ff48bf5SDavid du Colombier a->rxtsrem--;
5343ff48bf5SDavid du Colombier arprelease(er->f->arp, a);
5353ff48bf5SDavid du Colombier
5363ff48bf5SDavid du Colombier if(sflag = ipv6anylocal(ifc, ipsrc))
5373ff48bf5SDavid du Colombier icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
5383ff48bf5SDavid du Colombier }
5393ff48bf5SDavid du Colombier
5407dd7cddfSDavid du Colombier /*
5417dd7cddfSDavid du Colombier * send a gratuitous arp to refresh arp caches
5427dd7cddfSDavid du Colombier */
5437dd7cddfSDavid du Colombier static void
sendgarp(Ipifc * ifc,uchar * ip)5447dd7cddfSDavid du Colombier sendgarp(Ipifc *ifc, uchar *ip)
5457dd7cddfSDavid du Colombier {
5467dd7cddfSDavid du Colombier int n;
5477dd7cddfSDavid du Colombier Block *bp;
5487dd7cddfSDavid du Colombier Etherarp *e;
5497dd7cddfSDavid du Colombier Etherrock *er = ifc->arg;
5507dd7cddfSDavid du Colombier
5517dd7cddfSDavid du Colombier /* don't arp for our initial non address */
5527dd7cddfSDavid du Colombier if(ipcmp(ip, IPnoaddr) == 0)
5537dd7cddfSDavid du Colombier return;
5547dd7cddfSDavid du Colombier
5557dd7cddfSDavid du Colombier n = sizeof(Etherarp);
5563f695129SDavid du Colombier if(n < ifc->m->mintu)
5573f695129SDavid du Colombier n = ifc->m->mintu;
5587dd7cddfSDavid du Colombier bp = allocb(n);
5597dd7cddfSDavid du Colombier memset(bp->rp, 0, n);
5607dd7cddfSDavid du Colombier e = (Etherarp*)bp->rp;
5617dd7cddfSDavid du Colombier memmove(e->tpa, ip+IPv4off, sizeof(e->tpa));
5627dd7cddfSDavid du Colombier memmove(e->spa, ip+IPv4off, sizeof(e->spa));
5637dd7cddfSDavid du Colombier memmove(e->sha, ifc->mac, sizeof(e->sha));
5647dd7cddfSDavid du Colombier memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */
5657dd7cddfSDavid du Colombier memmove(e->s, ifc->mac, sizeof(e->s));
5667dd7cddfSDavid du Colombier
5677dd7cddfSDavid du Colombier hnputs(e->type, ETARP);
5687dd7cddfSDavid du Colombier hnputs(e->hrd, 1);
5693ff48bf5SDavid du Colombier hnputs(e->pro, ETIP4);
5707dd7cddfSDavid du Colombier e->hln = sizeof(e->sha);
5717dd7cddfSDavid du Colombier e->pln = sizeof(e->spa);
5727dd7cddfSDavid du Colombier hnputs(e->op, ARPREQUEST);
5737dd7cddfSDavid du Colombier bp->wp += n;
5747dd7cddfSDavid du Colombier
575db7ae703SDavid du Colombier devtab[er->achan->type]->bwrite(er->achan, bp, 0);
5767dd7cddfSDavid du Colombier }
5777dd7cddfSDavid du Colombier
5787dd7cddfSDavid du Colombier static void
recvarp(Ipifc * ifc)5797dd7cddfSDavid du Colombier recvarp(Ipifc *ifc)
5807dd7cddfSDavid du Colombier {
5817dd7cddfSDavid du Colombier int n;
5827dd7cddfSDavid du Colombier Block *ebp, *rbp;
5837dd7cddfSDavid du Colombier Etherarp *e, *r;
5847dd7cddfSDavid du Colombier uchar ip[IPaddrlen];
585ef9eff0bSDavid du Colombier static uchar eprinted[4];
5867dd7cddfSDavid du Colombier Etherrock *er = ifc->arg;
5877dd7cddfSDavid du Colombier
5883f695129SDavid du Colombier ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxtu, 0);
589db7ae703SDavid du Colombier if(ebp == nil)
5907dd7cddfSDavid du Colombier return;
5917dd7cddfSDavid du Colombier
5927dd7cddfSDavid du Colombier e = (Etherarp*)ebp->rp;
5937dd7cddfSDavid du Colombier switch(nhgets(e->op)) {
5947dd7cddfSDavid du Colombier default:
5957dd7cddfSDavid du Colombier break;
5967dd7cddfSDavid du Colombier
5977dd7cddfSDavid du Colombier case ARPREPLY:
5983ff48bf5SDavid du Colombier /* check for machine using my ip address */
5993ff48bf5SDavid du Colombier v4tov6(ip, e->spa);
6009a747e4fSDavid du Colombier if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
6019a747e4fSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
6029a747e4fSDavid du Colombier print("arprep: 0x%E/0x%E also has ip addr %V\n",
6039a747e4fSDavid du Colombier e->s, e->sha, e->spa);
6049a747e4fSDavid du Colombier break;
6059a747e4fSDavid du Colombier }
6069a747e4fSDavid du Colombier }
6073ff48bf5SDavid du Colombier
6085d82c6aeSDavid du Colombier /* make sure we're not entering broadcast addresses */
6095d82c6aeSDavid du Colombier if(ipcmp(ip, ipbroadcast) == 0 ||
6105d82c6aeSDavid du Colombier !memcmp(e->sha, etherbroadcast, sizeof(e->sha))){
6115d82c6aeSDavid du Colombier print("arprep: 0x%E/0x%E cannot register broadcast address %I\n",
6125d82c6aeSDavid du Colombier e->s, e->sha, e->spa);
6135d82c6aeSDavid du Colombier break;
6145d82c6aeSDavid du Colombier }
6155d82c6aeSDavid du Colombier
6167dd7cddfSDavid du Colombier arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
6177dd7cddfSDavid du Colombier break;
6187dd7cddfSDavid du Colombier
6197dd7cddfSDavid du Colombier case ARPREQUEST:
6207dd7cddfSDavid du Colombier /* don't answer arps till we know who we are */
6217dd7cddfSDavid du Colombier if(ifc->lifc == 0)
6227dd7cddfSDavid du Colombier break;
6237dd7cddfSDavid du Colombier
6243ff48bf5SDavid du Colombier /* check for machine using my ip or ether address */
6257dd7cddfSDavid du Colombier v4tov6(ip, e->spa);
6267dd7cddfSDavid du Colombier if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
627ef9eff0bSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
628ef9eff0bSDavid du Colombier if (memcmp(eprinted, e->spa, sizeof(e->spa))){
629ef9eff0bSDavid du Colombier /* print only once */
6303ff48bf5SDavid du Colombier print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
631ef9eff0bSDavid du Colombier memmove(eprinted, e->spa, sizeof(e->spa));
632ef9eff0bSDavid du Colombier }
633ef9eff0bSDavid du Colombier }
6347dd7cddfSDavid du Colombier } else {
6357dd7cddfSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
6363ff48bf5SDavid du Colombier print("arpreq: %V also has ether addr %E\n", e->spa, e->sha);
6377dd7cddfSDavid du Colombier break;
6387dd7cddfSDavid du Colombier }
6397dd7cddfSDavid du Colombier }
6407dd7cddfSDavid du Colombier
6417dd7cddfSDavid du Colombier /* refresh what we know about sender */
6427dd7cddfSDavid du Colombier arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1);
6437dd7cddfSDavid du Colombier
6447dd7cddfSDavid du Colombier /* answer only requests for our address or systems we're proxying for */
6457dd7cddfSDavid du Colombier v4tov6(ip, e->tpa);
6467dd7cddfSDavid du Colombier if(!iplocalonifc(ifc, ip))
6477dd7cddfSDavid du Colombier if(!ipproxyifc(er->f, ifc, ip))
6487dd7cddfSDavid du Colombier break;
6497dd7cddfSDavid du Colombier
6507dd7cddfSDavid du Colombier n = sizeof(Etherarp);
6513f695129SDavid du Colombier if(n < ifc->mintu)
6523f695129SDavid du Colombier n = ifc->mintu;
6537dd7cddfSDavid du Colombier rbp = allocb(n);
6547dd7cddfSDavid du Colombier r = (Etherarp*)rbp->rp;
6557dd7cddfSDavid du Colombier memset(r, 0, sizeof(Etherarp));
6567dd7cddfSDavid du Colombier hnputs(r->type, ETARP);
6577dd7cddfSDavid du Colombier hnputs(r->hrd, 1);
6583ff48bf5SDavid du Colombier hnputs(r->pro, ETIP4);
6597dd7cddfSDavid du Colombier r->hln = sizeof(r->sha);
6607dd7cddfSDavid du Colombier r->pln = sizeof(r->spa);
6617dd7cddfSDavid du Colombier hnputs(r->op, ARPREPLY);
6627dd7cddfSDavid du Colombier memmove(r->tha, e->sha, sizeof(r->tha));
6637dd7cddfSDavid du Colombier memmove(r->tpa, e->spa, sizeof(r->tpa));
6647dd7cddfSDavid du Colombier memmove(r->sha, ifc->mac, sizeof(r->sha));
6657dd7cddfSDavid du Colombier memmove(r->spa, e->tpa, sizeof(r->spa));
6667dd7cddfSDavid du Colombier memmove(r->d, e->sha, sizeof(r->d));
6677dd7cddfSDavid du Colombier memmove(r->s, ifc->mac, sizeof(r->s));
6687dd7cddfSDavid du Colombier rbp->wp += n;
6697dd7cddfSDavid du Colombier
670db7ae703SDavid du Colombier devtab[er->achan->type]->bwrite(er->achan, rbp, 0);
6717dd7cddfSDavid du Colombier }
6727dd7cddfSDavid du Colombier freeb(ebp);
6737dd7cddfSDavid du Colombier }
6747dd7cddfSDavid du Colombier
6757dd7cddfSDavid du Colombier static void
recvarpproc(void * v)6767dd7cddfSDavid du Colombier recvarpproc(void *v)
6777dd7cddfSDavid du Colombier {
6787dd7cddfSDavid du Colombier Ipifc *ifc = v;
6797dd7cddfSDavid du Colombier Etherrock *er = ifc->arg;
6807dd7cddfSDavid du Colombier
6817dd7cddfSDavid du Colombier er->arpp = up;
6827dd7cddfSDavid du Colombier if(waserror()){
6837dd7cddfSDavid du Colombier er->arpp = 0;
6847dd7cddfSDavid du Colombier pexit("hangup", 1);
6857dd7cddfSDavid du Colombier }
6867dd7cddfSDavid du Colombier for(;;)
6877dd7cddfSDavid du Colombier recvarp(ifc);
6887dd7cddfSDavid du Colombier }
6897dd7cddfSDavid du Colombier
6907dd7cddfSDavid du Colombier static int
multicastea(uchar * ea,uchar * ip)6917dd7cddfSDavid du Colombier multicastea(uchar *ea, uchar *ip)
6927dd7cddfSDavid du Colombier {
6937dd7cddfSDavid du Colombier int x;
6947dd7cddfSDavid du Colombier
6957dd7cddfSDavid du Colombier switch(x = ipismulticast(ip)){
6967dd7cddfSDavid du Colombier case V4:
6977dd7cddfSDavid du Colombier ea[0] = 0x01;
6987dd7cddfSDavid du Colombier ea[1] = 0x00;
6997dd7cddfSDavid du Colombier ea[2] = 0x5e;
7007dd7cddfSDavid du Colombier ea[3] = ip[13] & 0x7f;
7017dd7cddfSDavid du Colombier ea[4] = ip[14];
7027dd7cddfSDavid du Colombier ea[5] = ip[15];
7037dd7cddfSDavid du Colombier break;
7047dd7cddfSDavid du Colombier case V6:
7057dd7cddfSDavid du Colombier ea[0] = 0x33;
7067dd7cddfSDavid du Colombier ea[1] = 0x33;
7077dd7cddfSDavid du Colombier ea[2] = ip[12];
7087dd7cddfSDavid du Colombier ea[3] = ip[13];
7097dd7cddfSDavid du Colombier ea[4] = ip[14];
7107dd7cddfSDavid du Colombier ea[5] = ip[15];
7117dd7cddfSDavid du Colombier break;
7127dd7cddfSDavid du Colombier }
7137dd7cddfSDavid du Colombier return x;
7147dd7cddfSDavid du Colombier }
7157dd7cddfSDavid du Colombier
7167dd7cddfSDavid du Colombier /*
7177dd7cddfSDavid du Colombier * fill in an arp entry for broadcast or multicast
7183ff48bf5SDavid du Colombier * addresses. Return the first queued packet for the
7193ff48bf5SDavid du Colombier * IP address.
7207dd7cddfSDavid du Colombier */
7217dd7cddfSDavid du Colombier static Block*
multicastarp(Fs * f,Arpent * a,Medium * medium,uchar * mac)72259cc4ca5SDavid du Colombier multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac)
7237dd7cddfSDavid du Colombier {
7247dd7cddfSDavid du Colombier /* is it broadcast? */
7257dd7cddfSDavid du Colombier switch(ipforme(f, a->ip)){
7267dd7cddfSDavid du Colombier case Runi:
7277dd7cddfSDavid du Colombier return nil;
7287dd7cddfSDavid du Colombier case Rbcast:
7297dd7cddfSDavid du Colombier memset(mac, 0xff, 6);
73059cc4ca5SDavid du Colombier return arpresolve(f->arp, a, medium, mac);
7317dd7cddfSDavid du Colombier default:
7327dd7cddfSDavid du Colombier break;
7337dd7cddfSDavid du Colombier }
7347dd7cddfSDavid du Colombier
7357dd7cddfSDavid du Colombier /* if multicast, fill in mac */
7367dd7cddfSDavid du Colombier switch(multicastea(mac, a->ip)){
7377dd7cddfSDavid du Colombier case V4:
7387dd7cddfSDavid du Colombier case V6:
73959cc4ca5SDavid du Colombier return arpresolve(f->arp, a, medium, mac);
7407dd7cddfSDavid du Colombier }
7417dd7cddfSDavid du Colombier
7427dd7cddfSDavid du Colombier /* let arp take care of it */
7437dd7cddfSDavid du Colombier return nil;
7447dd7cddfSDavid du Colombier }
7457dd7cddfSDavid du Colombier
7467dd7cddfSDavid du Colombier void
ethermediumlink(void)7477dd7cddfSDavid du Colombier ethermediumlink(void)
7487dd7cddfSDavid du Colombier {
7497dd7cddfSDavid du Colombier addipmedium(ðermedium);
75059cc4ca5SDavid du Colombier addipmedium(&gbemedium);
7517dd7cddfSDavid du Colombier }
7523ff48bf5SDavid du Colombier
7533ff48bf5SDavid du Colombier
7543ff48bf5SDavid du Colombier static void
etherpref2addr(uchar * pref,uchar * ea)7553ff48bf5SDavid du Colombier etherpref2addr(uchar *pref, uchar *ea)
7563ff48bf5SDavid du Colombier {
7573ff48bf5SDavid du Colombier pref[8] = ea[0] | 0x2;
7583ff48bf5SDavid du Colombier pref[9] = ea[1];
7593ff48bf5SDavid du Colombier pref[10] = ea[2];
7603ff48bf5SDavid du Colombier pref[11] = 0xFF;
7613ff48bf5SDavid du Colombier pref[12] = 0xFE;
7623ff48bf5SDavid du Colombier pref[13] = ea[3];
7633ff48bf5SDavid du Colombier pref[14] = ea[4];
7643ff48bf5SDavid du Colombier pref[15] = ea[5];
7653ff48bf5SDavid du Colombier }
766