19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier #include "../port/error.h"
79ef1f84bSDavid du Colombier
89ef1f84bSDavid du Colombier #include "../port/netif.h"
99ef1f84bSDavid du Colombier #include "ip.h"
109ef1f84bSDavid du Colombier #include "ipv6.h"
119ef1f84bSDavid du Colombier
12a3323688SDavid du Colombier #include "etherif.h"
13a3323688SDavid du Colombier
149ef1f84bSDavid du Colombier typedef struct Etherhdr Etherhdr;
159ef1f84bSDavid du Colombier struct Etherhdr
169ef1f84bSDavid du Colombier {
17*4f13628bSDavid du Colombier uchar d[Eaddrlen];
18*4f13628bSDavid du Colombier uchar s[Eaddrlen];
199ef1f84bSDavid du Colombier uchar t[2];
209ef1f84bSDavid du Colombier };
219ef1f84bSDavid du Colombier
229ef1f84bSDavid du Colombier static uchar ipbroadcast[IPaddrlen] = {
239ef1f84bSDavid du Colombier 0xff,0xff,0xff,0xff,
249ef1f84bSDavid du Colombier 0xff,0xff,0xff,0xff,
259ef1f84bSDavid du Colombier 0xff,0xff,0xff,0xff,
269ef1f84bSDavid du Colombier 0xff,0xff,0xff,0xff,
279ef1f84bSDavid du Colombier };
289ef1f84bSDavid du Colombier
299ef1f84bSDavid du Colombier static uchar etherbroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
309ef1f84bSDavid du Colombier
319ef1f84bSDavid du Colombier static void etherread4(void *a);
329ef1f84bSDavid du Colombier static void etherread6(void *a);
339ef1f84bSDavid du Colombier static void etherbind(Ipifc *ifc, int argc, char **argv);
349ef1f84bSDavid du Colombier static void etherunbind(Ipifc *ifc);
359ef1f84bSDavid du Colombier static void etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
369ef1f84bSDavid du Colombier static void etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia);
379ef1f84bSDavid du Colombier static void etherremmulti(Ipifc *ifc, uchar *a, uchar *ia);
389ef1f84bSDavid du Colombier static Block* multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac);
399ef1f84bSDavid du Colombier static void sendarp(Ipifc *ifc, Arpent *a);
409ef1f84bSDavid du Colombier static void sendgarp(Ipifc *ifc, uchar*);
419ef1f84bSDavid du Colombier static int multicastea(uchar *ea, uchar *ip);
429ef1f84bSDavid du Colombier static void recvarpproc(void*);
439ef1f84bSDavid du Colombier static void resolveaddr6(Ipifc *ifc, Arpent *a);
449ef1f84bSDavid du Colombier static void etherpref2addr(uchar *pref, uchar *ea);
459ef1f84bSDavid du Colombier
469ef1f84bSDavid du Colombier Medium ethermedium =
479ef1f84bSDavid du Colombier {
489ef1f84bSDavid du Colombier .name= "ether",
49*4f13628bSDavid du Colombier .hsize= ETHERHDRSIZE,
50*4f13628bSDavid du Colombier .mintu= ETHERMINTU,
51*4f13628bSDavid du Colombier .maxtu= ETHERMAXTU,
52*4f13628bSDavid du Colombier .maclen= Eaddrlen,
539ef1f84bSDavid du Colombier .bind= etherbind,
549ef1f84bSDavid du Colombier .unbind= etherunbind,
559ef1f84bSDavid du Colombier .bwrite= etherbwrite,
569ef1f84bSDavid du Colombier .addmulti= etheraddmulti,
579ef1f84bSDavid du Colombier .remmulti= etherremmulti,
589ef1f84bSDavid du Colombier .ares= arpenter,
599ef1f84bSDavid du Colombier .areg= sendgarp,
609ef1f84bSDavid du Colombier .pref2addr= etherpref2addr,
619ef1f84bSDavid du Colombier };
629ef1f84bSDavid du Colombier
639ef1f84bSDavid du Colombier Medium gbemedium =
649ef1f84bSDavid du Colombier {
659ef1f84bSDavid du Colombier .name= "gbe",
66*4f13628bSDavid du Colombier .hsize= ETHERHDRSIZE,
67*4f13628bSDavid du Colombier .mintu= ETHERMINTU,
689ef1f84bSDavid du Colombier .maxtu= 9014,
69*4f13628bSDavid du Colombier .maclen= Eaddrlen,
709ef1f84bSDavid du Colombier .bind= etherbind,
719ef1f84bSDavid du Colombier .unbind= etherunbind,
729ef1f84bSDavid du Colombier .bwrite= etherbwrite,
739ef1f84bSDavid du Colombier .addmulti= etheraddmulti,
749ef1f84bSDavid du Colombier .remmulti= etherremmulti,
759ef1f84bSDavid du Colombier .ares= arpenter,
769ef1f84bSDavid du Colombier .areg= sendgarp,
779ef1f84bSDavid du Colombier .pref2addr= etherpref2addr,
789ef1f84bSDavid du Colombier };
799ef1f84bSDavid du Colombier
809ef1f84bSDavid du Colombier typedef struct Etherrock Etherrock;
819ef1f84bSDavid du Colombier struct Etherrock
829ef1f84bSDavid du Colombier {
839ef1f84bSDavid du Colombier Fs *f; /* file system we belong to */
849ef1f84bSDavid du Colombier Proc *arpp; /* arp process */
859ef1f84bSDavid du Colombier Proc *read4p; /* reading process (v4)*/
869ef1f84bSDavid du Colombier Proc *read6p; /* reading process (v6)*/
879ef1f84bSDavid du Colombier Chan *mchan4; /* Data channel for v4 */
889ef1f84bSDavid du Colombier Chan *achan; /* Arp channel */
899ef1f84bSDavid du Colombier Chan *cchan4; /* Control channel for v4 */
909ef1f84bSDavid du Colombier Chan *mchan6; /* Data channel for v6 */
919ef1f84bSDavid du Colombier Chan *cchan6; /* Control channel for v6 */
929ef1f84bSDavid du Colombier };
939ef1f84bSDavid du Colombier
949ef1f84bSDavid du Colombier /*
959ef1f84bSDavid du Colombier * ethernet arp request
969ef1f84bSDavid du Colombier */
979ef1f84bSDavid du Colombier enum
989ef1f84bSDavid du Colombier {
999ef1f84bSDavid du Colombier ARPREQUEST = 1,
1009ef1f84bSDavid du Colombier ARPREPLY = 2,
1019ef1f84bSDavid du Colombier };
1029ef1f84bSDavid du Colombier
1039ef1f84bSDavid du Colombier typedef struct Etherarp Etherarp;
1049ef1f84bSDavid du Colombier struct Etherarp
1059ef1f84bSDavid du Colombier {
106*4f13628bSDavid du Colombier uchar d[Eaddrlen];
107*4f13628bSDavid du Colombier uchar s[Eaddrlen];
1089ef1f84bSDavid du Colombier uchar type[2];
1099ef1f84bSDavid du Colombier uchar hrd[2];
1109ef1f84bSDavid du Colombier uchar pro[2];
1119ef1f84bSDavid du Colombier uchar hln;
1129ef1f84bSDavid du Colombier uchar pln;
1139ef1f84bSDavid du Colombier uchar op[2];
114*4f13628bSDavid du Colombier uchar sha[Eaddrlen];
115*4f13628bSDavid du Colombier uchar spa[IPv4addrlen];
116*4f13628bSDavid du Colombier uchar tha[Eaddrlen];
117*4f13628bSDavid du Colombier uchar tpa[IPv4addrlen];
1189ef1f84bSDavid du Colombier };
1199ef1f84bSDavid du Colombier
1209ef1f84bSDavid du Colombier static char *nbmsg = "nonblocking";
1219ef1f84bSDavid du Colombier
1229ef1f84bSDavid du Colombier /*
1239ef1f84bSDavid du Colombier * called to bind an IP ifc to an ethernet device
1249ef1f84bSDavid du Colombier * called with ifc wlock'd
1259ef1f84bSDavid du Colombier */
1269ef1f84bSDavid du Colombier static void
etherbind(Ipifc * ifc,int argc,char ** argv)1279ef1f84bSDavid du Colombier etherbind(Ipifc *ifc, int argc, char **argv)
1289ef1f84bSDavid du Colombier {
1299ef1f84bSDavid du Colombier Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6, *schan;
1309ef1f84bSDavid du Colombier char addr[Maxpath]; //char addr[2*KNAMELEN];
1319ef1f84bSDavid du Colombier char dir[Maxpath]; //char dir[2*KNAMELEN];
1329ef1f84bSDavid du Colombier char *buf;
1339ef1f84bSDavid du Colombier int n;
1349ef1f84bSDavid du Colombier char *ptr;
1359ef1f84bSDavid du Colombier Etherrock *er;
1369ef1f84bSDavid du Colombier
1379ef1f84bSDavid du Colombier if(argc < 2)
1389ef1f84bSDavid du Colombier error(Ebadarg);
1399ef1f84bSDavid du Colombier
1409ef1f84bSDavid du Colombier mchan4 = cchan4 = achan = mchan6 = cchan6 = nil;
1419ef1f84bSDavid du Colombier buf = nil;
1429ef1f84bSDavid du Colombier if(waserror()){
1439ef1f84bSDavid du Colombier if(mchan4 != nil)
1449ef1f84bSDavid du Colombier cclose(mchan4);
1459ef1f84bSDavid du Colombier if(cchan4 != nil)
1469ef1f84bSDavid du Colombier cclose(cchan4);
1479ef1f84bSDavid du Colombier if(achan != nil)
1489ef1f84bSDavid du Colombier cclose(achan);
1499ef1f84bSDavid du Colombier if(mchan6 != nil)
1509ef1f84bSDavid du Colombier cclose(mchan6);
1519ef1f84bSDavid du Colombier if(cchan6 != nil)
1529ef1f84bSDavid du Colombier cclose(cchan6);
1539ef1f84bSDavid du Colombier if(buf != nil)
1549ef1f84bSDavid du Colombier free(buf);
1559ef1f84bSDavid du Colombier nexterror();
1569ef1f84bSDavid du Colombier }
1579ef1f84bSDavid du Colombier
1589ef1f84bSDavid du Colombier /*
1599ef1f84bSDavid du Colombier * open ipv4 conversation
1609ef1f84bSDavid du Colombier *
1619ef1f84bSDavid du Colombier * the dial will fail if the type is already open on
1629ef1f84bSDavid du Colombier * this device.
1639ef1f84bSDavid du Colombier */
1649ef1f84bSDavid du Colombier snprint(addr, sizeof(addr), "%s!0x800", argv[2]); /* ETIP4 */
1659ef1f84bSDavid du Colombier mchan4 = chandial(addr, nil, dir, &cchan4);
1669ef1f84bSDavid du Colombier
1679ef1f84bSDavid du Colombier /*
1689ef1f84bSDavid du Colombier * make it non-blocking
1699ef1f84bSDavid du Colombier */
1709ef1f84bSDavid du Colombier cchan4->dev->write(cchan4, nbmsg, strlen(nbmsg), 0);
1719ef1f84bSDavid du Colombier
1729ef1f84bSDavid du Colombier /*
1739ef1f84bSDavid du Colombier * get mac address and speed
1749ef1f84bSDavid du Colombier */
1759ef1f84bSDavid du Colombier snprint(addr, sizeof(addr), "%s/stats", argv[2]);
1769ef1f84bSDavid du Colombier buf = smalloc(512);
1779ef1f84bSDavid du Colombier schan = namec(addr, Aopen, OREAD, 0);
1789ef1f84bSDavid du Colombier if(waserror()){
1799ef1f84bSDavid du Colombier cclose(schan);
1809ef1f84bSDavid du Colombier nexterror();
1819ef1f84bSDavid du Colombier }
1829ef1f84bSDavid du Colombier n = schan->dev->read(schan, buf, 511, 0);
1839ef1f84bSDavid du Colombier cclose(schan);
1849ef1f84bSDavid du Colombier poperror();
1859ef1f84bSDavid du Colombier buf[n] = 0;
1869ef1f84bSDavid du Colombier
1879ef1f84bSDavid du Colombier ptr = strstr(buf, "addr: ");
1889ef1f84bSDavid du Colombier if(!ptr)
1899ef1f84bSDavid du Colombier error(Eio);
1909ef1f84bSDavid du Colombier ptr += 6;
1919ef1f84bSDavid du Colombier parsemac(ifc->mac, ptr, 6);
1929ef1f84bSDavid du Colombier
1939ef1f84bSDavid du Colombier ptr = strstr(buf, "mbps: ");
1949ef1f84bSDavid du Colombier if(ptr){
1959ef1f84bSDavid du Colombier ptr += 6;
1969ef1f84bSDavid du Colombier ifc->mbps = atoi(ptr);
1979ef1f84bSDavid du Colombier } else
1989ef1f84bSDavid du Colombier ifc->mbps = 100;
1999ef1f84bSDavid du Colombier
2009ef1f84bSDavid du Colombier /*
2019ef1f84bSDavid du Colombier * open arp conversation
2029ef1f84bSDavid du Colombier */
2039ef1f84bSDavid du Colombier snprint(addr, sizeof(addr), "%s!0x806", argv[2]); /* ETARP */
2049ef1f84bSDavid du Colombier achan = chandial(addr, nil, nil, nil);
2059ef1f84bSDavid du Colombier
2069ef1f84bSDavid du Colombier /*
2079ef1f84bSDavid du Colombier * open ipv6 conversation
2089ef1f84bSDavid du Colombier *
2099ef1f84bSDavid du Colombier * the dial will fail if the type is already open on
2109ef1f84bSDavid du Colombier * this device.
2119ef1f84bSDavid du Colombier */
2129ef1f84bSDavid du Colombier snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]); /* ETIP6 */
2139ef1f84bSDavid du Colombier mchan6 = chandial(addr, nil, dir, &cchan6);
2149ef1f84bSDavid du Colombier
2159ef1f84bSDavid du Colombier /*
2169ef1f84bSDavid du Colombier * make it non-blocking
2179ef1f84bSDavid du Colombier */
2189ef1f84bSDavid du Colombier cchan6->dev->write(cchan6, nbmsg, strlen(nbmsg), 0);
2199ef1f84bSDavid du Colombier
2209ef1f84bSDavid du Colombier er = smalloc(sizeof(*er));
2219ef1f84bSDavid du Colombier er->mchan4 = mchan4;
2229ef1f84bSDavid du Colombier er->cchan4 = cchan4;
2239ef1f84bSDavid du Colombier er->achan = achan;
2249ef1f84bSDavid du Colombier er->mchan6 = mchan6;
2259ef1f84bSDavid du Colombier er->cchan6 = cchan6;
2269ef1f84bSDavid du Colombier er->f = ifc->conv->p->f;
2279ef1f84bSDavid du Colombier ifc->arg = er;
2289ef1f84bSDavid du Colombier
2299ef1f84bSDavid du Colombier free(buf);
2309ef1f84bSDavid du Colombier poperror();
2319ef1f84bSDavid du Colombier
2329ef1f84bSDavid du Colombier kproc("etherread4", etherread4, ifc);
2339ef1f84bSDavid du Colombier kproc("recvarpproc", recvarpproc, ifc);
2349ef1f84bSDavid du Colombier kproc("etherread6", etherread6, ifc);
2359ef1f84bSDavid du Colombier }
2369ef1f84bSDavid du Colombier
2379ef1f84bSDavid du Colombier /*
2389ef1f84bSDavid du Colombier * called with ifc wlock'd
2399ef1f84bSDavid du Colombier */
2409ef1f84bSDavid du Colombier static void
etherunbind(Ipifc * ifc)2419ef1f84bSDavid du Colombier etherunbind(Ipifc *ifc)
2429ef1f84bSDavid du Colombier {
2439ef1f84bSDavid du Colombier Etherrock *er = ifc->arg;
2449ef1f84bSDavid du Colombier
2459ef1f84bSDavid du Colombier if(er->read4p)
2469ef1f84bSDavid du Colombier postnote(er->read4p, 1, "unbind", 0);
2479ef1f84bSDavid du Colombier if(er->read6p)
2489ef1f84bSDavid du Colombier postnote(er->read6p, 1, "unbind", 0);
2499ef1f84bSDavid du Colombier if(er->arpp)
2509ef1f84bSDavid du Colombier postnote(er->arpp, 1, "unbind", 0);
2519ef1f84bSDavid du Colombier
2529ef1f84bSDavid du Colombier /* wait for readers to die */
2539ef1f84bSDavid du Colombier while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0)
2549ef1f84bSDavid du Colombier tsleep(&up->sleep, return0, 0, 300);
2559ef1f84bSDavid du Colombier
2569ef1f84bSDavid du Colombier if(er->mchan4 != nil)
2579ef1f84bSDavid du Colombier cclose(er->mchan4);
2589ef1f84bSDavid du Colombier if(er->achan != nil)
2599ef1f84bSDavid du Colombier cclose(er->achan);
2609ef1f84bSDavid du Colombier if(er->cchan4 != nil)
2619ef1f84bSDavid du Colombier cclose(er->cchan4);
2629ef1f84bSDavid du Colombier if(er->mchan6 != nil)
2639ef1f84bSDavid du Colombier cclose(er->mchan6);
2649ef1f84bSDavid du Colombier if(er->cchan6 != nil)
2659ef1f84bSDavid du Colombier cclose(er->cchan6);
2669ef1f84bSDavid du Colombier
2679ef1f84bSDavid du Colombier free(er);
2689ef1f84bSDavid du Colombier }
2699ef1f84bSDavid du Colombier
2709ef1f84bSDavid du Colombier /*
2719ef1f84bSDavid du Colombier * called by ipoput with a single block to write with ifc rlock'd
2729ef1f84bSDavid du Colombier */
2739ef1f84bSDavid du Colombier static void
etherbwrite(Ipifc * ifc,Block * bp,int version,uchar * ip)2749ef1f84bSDavid du Colombier etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
2759ef1f84bSDavid du Colombier {
2769ef1f84bSDavid du Colombier Etherhdr *eh;
2779ef1f84bSDavid du Colombier Arpent *a;
278*4f13628bSDavid du Colombier uchar mac[Eaddrlen];
2799ef1f84bSDavid du Colombier Etherrock *er = ifc->arg;
2809ef1f84bSDavid du Colombier
2819ef1f84bSDavid du Colombier /* get mac address of destination */
2829ef1f84bSDavid du Colombier a = arpget(er->f->arp, bp, version, ifc, ip, mac);
2839ef1f84bSDavid du Colombier if(a){
2849ef1f84bSDavid du Colombier /* check for broadcast or multicast */
2859ef1f84bSDavid du Colombier bp = multicastarp(er->f, a, ifc->medium, mac);
2869ef1f84bSDavid du Colombier if(bp==nil){
2879ef1f84bSDavid du Colombier switch(version){
2889ef1f84bSDavid du Colombier case V4:
2899ef1f84bSDavid du Colombier sendarp(ifc, a);
2909ef1f84bSDavid du Colombier break;
2919ef1f84bSDavid du Colombier case V6:
2929ef1f84bSDavid du Colombier resolveaddr6(ifc, a);
2939ef1f84bSDavid du Colombier break;
2949ef1f84bSDavid du Colombier default:
2959ef1f84bSDavid du Colombier panic("etherbwrite: version %d", version);
2969ef1f84bSDavid du Colombier }
2979ef1f84bSDavid du Colombier return;
2989ef1f84bSDavid du Colombier }
2999ef1f84bSDavid du Colombier }
3009ef1f84bSDavid du Colombier
3019ef1f84bSDavid du Colombier /* make it a single block with space for the ether header */
3029ef1f84bSDavid du Colombier bp = padblock(bp, ifc->medium->hsize);
3039ef1f84bSDavid du Colombier if(bp->next)
3049ef1f84bSDavid du Colombier bp = concatblock(bp);
3059ef1f84bSDavid du Colombier if(BLEN(bp) < ifc->mintu)
3069ef1f84bSDavid du Colombier bp = adjustblock(bp, ifc->mintu);
3079ef1f84bSDavid du Colombier eh = (Etherhdr*)bp->rp;
3089ef1f84bSDavid du Colombier
3099ef1f84bSDavid du Colombier /* copy in mac addresses and ether type */
3109ef1f84bSDavid du Colombier memmove(eh->s, ifc->mac, sizeof(eh->s));
3119ef1f84bSDavid du Colombier memmove(eh->d, mac, sizeof(eh->d));
3129ef1f84bSDavid du Colombier
3139ef1f84bSDavid du Colombier switch(version){
3149ef1f84bSDavid du Colombier case V4:
315*4f13628bSDavid du Colombier eh->t[0] = ETIP4>>8;
316*4f13628bSDavid du Colombier eh->t[1] = ETIP4;
3179ef1f84bSDavid du Colombier er->mchan4->dev->bwrite(er->mchan4, bp, 0);
3189ef1f84bSDavid du Colombier break;
3199ef1f84bSDavid du Colombier case V6:
320*4f13628bSDavid du Colombier eh->t[0] = ETIP6>>8;
321*4f13628bSDavid du Colombier eh->t[1] = ETIP6;
3229ef1f84bSDavid du Colombier er->mchan6->dev->bwrite(er->mchan6, bp, 0);
3239ef1f84bSDavid du Colombier break;
3249ef1f84bSDavid du Colombier default:
3259ef1f84bSDavid du Colombier panic("etherbwrite2: version %d", version);
3269ef1f84bSDavid du Colombier }
3279ef1f84bSDavid du Colombier ifc->out++;
3289ef1f84bSDavid du Colombier }
3299ef1f84bSDavid du Colombier
3309ef1f84bSDavid du Colombier
3319ef1f84bSDavid du Colombier /*
3329ef1f84bSDavid du Colombier * process to read from the ethernet
3339ef1f84bSDavid du Colombier */
3349ef1f84bSDavid du Colombier static void
etherread4(void * a)3359ef1f84bSDavid du Colombier etherread4(void *a)
3369ef1f84bSDavid du Colombier {
3379ef1f84bSDavid du Colombier Ipifc *ifc;
3389ef1f84bSDavid du Colombier Block *bp;
3399ef1f84bSDavid du Colombier Etherrock *er;
3409ef1f84bSDavid du Colombier
3419ef1f84bSDavid du Colombier ifc = a;
3429ef1f84bSDavid du Colombier er = ifc->arg;
3439ef1f84bSDavid du Colombier er->read4p = up; /* hide identity under a rock for unbind */
3449ef1f84bSDavid du Colombier if(waserror()){
3459ef1f84bSDavid du Colombier er->read4p = 0;
3469ef1f84bSDavid du Colombier pexit("hangup", 1);
3479ef1f84bSDavid du Colombier }
3489ef1f84bSDavid du Colombier for(;;){
3499ef1f84bSDavid du Colombier bp = er->mchan4->dev->bread(er->mchan4, ifc->maxtu, 0);
3509ef1f84bSDavid du Colombier if(!canrlock(ifc)){
3519ef1f84bSDavid du Colombier freeb(bp);
3529ef1f84bSDavid du Colombier continue;
3539ef1f84bSDavid du Colombier }
3549ef1f84bSDavid du Colombier if(waserror()){
3559ef1f84bSDavid du Colombier runlock(ifc);
3569ef1f84bSDavid du Colombier nexterror();
3579ef1f84bSDavid du Colombier }
3589ef1f84bSDavid du Colombier ifc->in++;
3599ef1f84bSDavid du Colombier bp->rp += ifc->medium->hsize;
3609ef1f84bSDavid du Colombier if(ifc->lifc == nil)
3619ef1f84bSDavid du Colombier freeb(bp);
3629ef1f84bSDavid du Colombier else
3639ef1f84bSDavid du Colombier ipiput4(er->f, ifc, bp);
3649ef1f84bSDavid du Colombier runlock(ifc);
3659ef1f84bSDavid du Colombier poperror();
3669ef1f84bSDavid du Colombier }
3679ef1f84bSDavid du Colombier }
3689ef1f84bSDavid du Colombier
3699ef1f84bSDavid du Colombier
3709ef1f84bSDavid du Colombier /*
3719ef1f84bSDavid du Colombier * process to read from the ethernet, IPv6
3729ef1f84bSDavid du Colombier */
3739ef1f84bSDavid du Colombier static void
etherread6(void * a)3749ef1f84bSDavid du Colombier etherread6(void *a)
3759ef1f84bSDavid du Colombier {
3769ef1f84bSDavid du Colombier Ipifc *ifc;
3779ef1f84bSDavid du Colombier Block *bp;
3789ef1f84bSDavid du Colombier Etherrock *er;
3799ef1f84bSDavid du Colombier
3809ef1f84bSDavid du Colombier ifc = a;
3819ef1f84bSDavid du Colombier er = ifc->arg;
3829ef1f84bSDavid du Colombier er->read6p = up; /* hide identity under a rock for unbind */
3839ef1f84bSDavid du Colombier if(waserror()){
3849ef1f84bSDavid du Colombier er->read6p = 0;
3859ef1f84bSDavid du Colombier pexit("hangup", 1);
3869ef1f84bSDavid du Colombier }
3879ef1f84bSDavid du Colombier for(;;){
3889ef1f84bSDavid du Colombier bp = er->mchan6->dev->bread(er->mchan6, ifc->maxtu, 0);
3899ef1f84bSDavid du Colombier if(!canrlock(ifc)){
3909ef1f84bSDavid du Colombier freeb(bp);
3919ef1f84bSDavid du Colombier continue;
3929ef1f84bSDavid du Colombier }
3939ef1f84bSDavid du Colombier if(waserror()){
3949ef1f84bSDavid du Colombier runlock(ifc);
3959ef1f84bSDavid du Colombier nexterror();
3969ef1f84bSDavid du Colombier }
3979ef1f84bSDavid du Colombier ifc->in++;
3989ef1f84bSDavid du Colombier bp->rp += ifc->medium->hsize;
3999ef1f84bSDavid du Colombier if(ifc->lifc == nil)
4009ef1f84bSDavid du Colombier freeb(bp);
4019ef1f84bSDavid du Colombier else
4029ef1f84bSDavid du Colombier ipiput6(er->f, ifc, bp);
4039ef1f84bSDavid du Colombier runlock(ifc);
4049ef1f84bSDavid du Colombier poperror();
4059ef1f84bSDavid du Colombier }
4069ef1f84bSDavid du Colombier }
4079ef1f84bSDavid du Colombier
4089ef1f84bSDavid du Colombier static void
etheraddmulti(Ipifc * ifc,uchar * a,uchar *)4099ef1f84bSDavid du Colombier etheraddmulti(Ipifc *ifc, uchar *a, uchar *)
4109ef1f84bSDavid du Colombier {
411*4f13628bSDavid du Colombier uchar mac[Eaddrlen];
4129ef1f84bSDavid du Colombier char buf[64];
4139ef1f84bSDavid du Colombier Etherrock *er = ifc->arg;
4149ef1f84bSDavid du Colombier int version;
4159ef1f84bSDavid du Colombier
4169ef1f84bSDavid du Colombier version = multicastea(mac, a);
417a3323688SDavid du Colombier snprint(buf, sizeof buf, "addmulti %E", mac);
4189ef1f84bSDavid du Colombier switch(version){
4199ef1f84bSDavid du Colombier case V4:
4209ef1f84bSDavid du Colombier er->cchan4->dev->write(er->cchan4, buf, strlen(buf), 0);
4219ef1f84bSDavid du Colombier break;
4229ef1f84bSDavid du Colombier case V6:
4239ef1f84bSDavid du Colombier er->cchan6->dev->write(er->cchan6, buf, strlen(buf), 0);
4249ef1f84bSDavid du Colombier break;
4259ef1f84bSDavid du Colombier default:
4269ef1f84bSDavid du Colombier panic("etheraddmulti: version %d", version);
4279ef1f84bSDavid du Colombier }
4289ef1f84bSDavid du Colombier }
4299ef1f84bSDavid du Colombier
4309ef1f84bSDavid du Colombier static void
etherremmulti(Ipifc * ifc,uchar * a,uchar *)4319ef1f84bSDavid du Colombier etherremmulti(Ipifc *ifc, uchar *a, uchar *)
4329ef1f84bSDavid du Colombier {
433*4f13628bSDavid du Colombier uchar mac[Eaddrlen];
4349ef1f84bSDavid du Colombier char buf[64];
4359ef1f84bSDavid du Colombier Etherrock *er = ifc->arg;
4369ef1f84bSDavid du Colombier int version;
4379ef1f84bSDavid du Colombier
4389ef1f84bSDavid du Colombier version = multicastea(mac, a);
439a3323688SDavid du Colombier snprint(buf, sizeof buf, "remmulti %E", mac);
4409ef1f84bSDavid du Colombier switch(version){
4419ef1f84bSDavid du Colombier case V4:
4429ef1f84bSDavid du Colombier er->cchan4->dev->write(er->cchan4, buf, strlen(buf), 0);
4439ef1f84bSDavid du Colombier break;
4449ef1f84bSDavid du Colombier case V6:
4459ef1f84bSDavid du Colombier er->cchan6->dev->write(er->cchan6, buf, strlen(buf), 0);
4469ef1f84bSDavid du Colombier break;
4479ef1f84bSDavid du Colombier default:
4489ef1f84bSDavid du Colombier panic("etherremmulti: version %d", version);
4499ef1f84bSDavid du Colombier }
4509ef1f84bSDavid du Colombier }
4519ef1f84bSDavid du Colombier
4529ef1f84bSDavid du Colombier /*
4539ef1f84bSDavid du Colombier * send an ethernet arp
4549ef1f84bSDavid du Colombier * (only v4, v6 uses the neighbor discovery, rfc1970)
4559ef1f84bSDavid du Colombier */
4569ef1f84bSDavid du Colombier static void
sendarp(Ipifc * ifc,Arpent * a)4579ef1f84bSDavid du Colombier sendarp(Ipifc *ifc, Arpent *a)
4589ef1f84bSDavid du Colombier {
4599ef1f84bSDavid du Colombier int n;
4609ef1f84bSDavid du Colombier Block *bp;
4619ef1f84bSDavid du Colombier Etherarp *e;
4629ef1f84bSDavid du Colombier Etherrock *er = ifc->arg;
4639ef1f84bSDavid du Colombier
4649ef1f84bSDavid du Colombier /* don't do anything if it's been less than a second since the last */
4659ef1f84bSDavid du Colombier if(NOW - a->ctime < 1000){
4669ef1f84bSDavid du Colombier arprelease(er->f->arp, a);
4679ef1f84bSDavid du Colombier return;
4689ef1f84bSDavid du Colombier }
4699ef1f84bSDavid du Colombier
4709ef1f84bSDavid du Colombier /* remove all but the last message */
4719ef1f84bSDavid du Colombier while((bp = a->hold) != nil){
4729ef1f84bSDavid du Colombier if(bp == a->last)
4739ef1f84bSDavid du Colombier break;
4749ef1f84bSDavid du Colombier a->hold = bp->list;
4759ef1f84bSDavid du Colombier freeblist(bp);
4769ef1f84bSDavid du Colombier }
4779ef1f84bSDavid du Colombier
4789ef1f84bSDavid du Colombier /* try to keep it around for a second more */
4799ef1f84bSDavid du Colombier a->ctime = NOW;
4809ef1f84bSDavid du Colombier arprelease(er->f->arp, a);
4819ef1f84bSDavid du Colombier
4829ef1f84bSDavid du Colombier n = sizeof(Etherarp);
4839ef1f84bSDavid du Colombier if(n < a->type->mintu)
4849ef1f84bSDavid du Colombier n = a->type->mintu;
4859ef1f84bSDavid du Colombier bp = allocb(n);
4869ef1f84bSDavid du Colombier memset(bp->rp, 0, n);
4879ef1f84bSDavid du Colombier e = (Etherarp*)bp->rp;
4889ef1f84bSDavid du Colombier memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
4899ef1f84bSDavid du Colombier ipv4local(ifc, e->spa);
4909ef1f84bSDavid du Colombier memmove(e->sha, ifc->mac, sizeof(e->sha));
4919ef1f84bSDavid du Colombier memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */
4929ef1f84bSDavid du Colombier memmove(e->s, ifc->mac, sizeof(e->s));
4939ef1f84bSDavid du Colombier
4949ef1f84bSDavid du Colombier hnputs(e->type, ETARP);
4959ef1f84bSDavid du Colombier hnputs(e->hrd, 1);
4969ef1f84bSDavid du Colombier hnputs(e->pro, ETIP4);
4979ef1f84bSDavid du Colombier e->hln = sizeof(e->sha);
4989ef1f84bSDavid du Colombier e->pln = sizeof(e->spa);
4999ef1f84bSDavid du Colombier hnputs(e->op, ARPREQUEST);
5009ef1f84bSDavid du Colombier bp->wp += n;
5019ef1f84bSDavid du Colombier
5029ef1f84bSDavid du Colombier er->achan->dev->bwrite(er->achan, bp, 0);
5039ef1f84bSDavid du Colombier }
5049ef1f84bSDavid du Colombier
5059ef1f84bSDavid du Colombier static void
resolveaddr6(Ipifc * ifc,Arpent * a)5069ef1f84bSDavid du Colombier resolveaddr6(Ipifc *ifc, Arpent *a)
5079ef1f84bSDavid du Colombier {
5089ef1f84bSDavid du Colombier int sflag;
5099ef1f84bSDavid du Colombier Block *bp;
5109ef1f84bSDavid du Colombier Etherrock *er = ifc->arg;
5119ef1f84bSDavid du Colombier uchar ipsrc[IPaddrlen];
5129ef1f84bSDavid du Colombier
5139ef1f84bSDavid du Colombier /* don't do anything if it's been less than a second since the last */
5149ef1f84bSDavid du Colombier if(NOW - a->ctime < ReTransTimer){
5159ef1f84bSDavid du Colombier arprelease(er->f->arp, a);
5169ef1f84bSDavid du Colombier return;
5179ef1f84bSDavid du Colombier }
5189ef1f84bSDavid du Colombier
5199ef1f84bSDavid du Colombier /* remove all but the last message */
5209ef1f84bSDavid du Colombier while((bp = a->hold) != nil){
5219ef1f84bSDavid du Colombier if(bp == a->last)
5229ef1f84bSDavid du Colombier break;
5239ef1f84bSDavid du Colombier a->hold = bp->list;
5249ef1f84bSDavid du Colombier freeblist(bp);
5259ef1f84bSDavid du Colombier }
5269ef1f84bSDavid du Colombier
5279ef1f84bSDavid du Colombier /* try to keep it around for a second more */
5289ef1f84bSDavid du Colombier a->ctime = NOW;
5299ef1f84bSDavid du Colombier a->rtime = NOW + ReTransTimer;
5309ef1f84bSDavid du Colombier if(a->rxtsrem <= 0) {
5319ef1f84bSDavid du Colombier arprelease(er->f->arp, a);
5329ef1f84bSDavid du Colombier return;
5339ef1f84bSDavid du Colombier }
5349ef1f84bSDavid du Colombier
5359ef1f84bSDavid du Colombier a->rxtsrem--;
5369ef1f84bSDavid du Colombier arprelease(er->f->arp, a);
5379ef1f84bSDavid du Colombier
5389ef1f84bSDavid du Colombier if(sflag = ipv6anylocal(ifc, ipsrc))
5399ef1f84bSDavid du Colombier icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
5409ef1f84bSDavid du Colombier }
5419ef1f84bSDavid du Colombier
5429ef1f84bSDavid du Colombier /*
5439ef1f84bSDavid du Colombier * send a gratuitous arp to refresh arp caches
5449ef1f84bSDavid du Colombier */
5459ef1f84bSDavid du Colombier static void
sendgarp(Ipifc * ifc,uchar * ip)5469ef1f84bSDavid du Colombier sendgarp(Ipifc *ifc, uchar *ip)
5479ef1f84bSDavid du Colombier {
5489ef1f84bSDavid du Colombier int n;
5499ef1f84bSDavid du Colombier Block *bp;
5509ef1f84bSDavid du Colombier Etherarp *e;
5519ef1f84bSDavid du Colombier Etherrock *er = ifc->arg;
5529ef1f84bSDavid du Colombier
5539ef1f84bSDavid du Colombier /* don't arp for our initial non address */
5549ef1f84bSDavid du Colombier if(ipcmp(ip, IPnoaddr) == 0)
5559ef1f84bSDavid du Colombier return;
5569ef1f84bSDavid du Colombier
5579ef1f84bSDavid du Colombier n = sizeof(Etherarp);
5589ef1f84bSDavid du Colombier if(n < ifc->medium->mintu)
5599ef1f84bSDavid du Colombier n = ifc->medium->mintu;
5609ef1f84bSDavid du Colombier bp = allocb(n);
5619ef1f84bSDavid du Colombier memset(bp->rp, 0, n);
5629ef1f84bSDavid du Colombier e = (Etherarp*)bp->rp;
5639ef1f84bSDavid du Colombier memmove(e->tpa, ip+IPv4off, sizeof(e->tpa));
5649ef1f84bSDavid du Colombier memmove(e->spa, ip+IPv4off, sizeof(e->spa));
5659ef1f84bSDavid du Colombier memmove(e->sha, ifc->mac, sizeof(e->sha));
5669ef1f84bSDavid du Colombier memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */
5679ef1f84bSDavid du Colombier memmove(e->s, ifc->mac, sizeof(e->s));
5689ef1f84bSDavid du Colombier
5699ef1f84bSDavid du Colombier hnputs(e->type, ETARP);
5709ef1f84bSDavid du Colombier hnputs(e->hrd, 1);
5719ef1f84bSDavid du Colombier hnputs(e->pro, ETIP4);
5729ef1f84bSDavid du Colombier e->hln = sizeof(e->sha);
5739ef1f84bSDavid du Colombier e->pln = sizeof(e->spa);
5749ef1f84bSDavid du Colombier hnputs(e->op, ARPREQUEST);
5759ef1f84bSDavid du Colombier bp->wp += n;
5769ef1f84bSDavid du Colombier
5779ef1f84bSDavid du Colombier er->achan->dev->bwrite(er->achan, bp, 0);
5789ef1f84bSDavid du Colombier }
5799ef1f84bSDavid du Colombier
5809ef1f84bSDavid du Colombier static void
recvarp(Ipifc * ifc)5819ef1f84bSDavid du Colombier recvarp(Ipifc *ifc)
5829ef1f84bSDavid du Colombier {
5839ef1f84bSDavid du Colombier int n;
5849ef1f84bSDavid du Colombier Block *ebp, *rbp;
5859ef1f84bSDavid du Colombier Etherarp *e, *r;
5869ef1f84bSDavid du Colombier uchar ip[IPaddrlen];
5879ef1f84bSDavid du Colombier static uchar eprinted[4];
5889ef1f84bSDavid du Colombier Etherrock *er = ifc->arg;
5899ef1f84bSDavid du Colombier
5909ef1f84bSDavid du Colombier ebp = er->achan->dev->bread(er->achan, ifc->maxtu, 0);
5919ef1f84bSDavid du Colombier if(ebp == nil)
5929ef1f84bSDavid du Colombier return;
5939ef1f84bSDavid du Colombier
5949ef1f84bSDavid du Colombier e = (Etherarp*)ebp->rp;
5959ef1f84bSDavid du Colombier switch(nhgets(e->op)) {
5969ef1f84bSDavid du Colombier default:
5979ef1f84bSDavid du Colombier break;
5989ef1f84bSDavid du Colombier
5999ef1f84bSDavid du Colombier case ARPREPLY:
6009ef1f84bSDavid du Colombier /* check for machine using my ip address */
6019ef1f84bSDavid du Colombier v4tov6(ip, e->spa);
6029ef1f84bSDavid du Colombier if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
6039ef1f84bSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
6049ef1f84bSDavid du Colombier print("arprep: 0x%E/0x%E also has ip addr %V\n",
6059ef1f84bSDavid du Colombier e->s, e->sha, e->spa);
6069ef1f84bSDavid du Colombier break;
6079ef1f84bSDavid du Colombier }
6089ef1f84bSDavid du Colombier }
6099ef1f84bSDavid du Colombier
6109ef1f84bSDavid du Colombier /* make sure we're not entering broadcast addresses */
6119ef1f84bSDavid du Colombier if(ipcmp(ip, ipbroadcast) == 0 ||
6129ef1f84bSDavid du Colombier !memcmp(e->sha, etherbroadcast, sizeof(e->sha))){
6139ef1f84bSDavid du Colombier print("arprep: 0x%E/0x%E cannot register broadcast address %I\n",
6149ef1f84bSDavid du Colombier e->s, e->sha, e->spa);
6159ef1f84bSDavid du Colombier break;
6169ef1f84bSDavid du Colombier }
6179ef1f84bSDavid du Colombier
6189ef1f84bSDavid du Colombier arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
6199ef1f84bSDavid du Colombier break;
6209ef1f84bSDavid du Colombier
6219ef1f84bSDavid du Colombier case ARPREQUEST:
6229ef1f84bSDavid du Colombier /* don't answer arps till we know who we are */
6239ef1f84bSDavid du Colombier if(ifc->lifc == 0)
6249ef1f84bSDavid du Colombier break;
6259ef1f84bSDavid du Colombier
6269ef1f84bSDavid du Colombier /* check for machine using my ip or ether address */
6279ef1f84bSDavid du Colombier v4tov6(ip, e->spa);
6289ef1f84bSDavid du Colombier if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
6299ef1f84bSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
6309ef1f84bSDavid du Colombier if (memcmp(eprinted, e->spa, sizeof(e->spa))){
6319ef1f84bSDavid du Colombier /* print only once */
6329ef1f84bSDavid du Colombier print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
6339ef1f84bSDavid du Colombier memmove(eprinted, e->spa, sizeof(e->spa));
6349ef1f84bSDavid du Colombier }
6359ef1f84bSDavid du Colombier }
6369ef1f84bSDavid du Colombier } else {
6379ef1f84bSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
6389ef1f84bSDavid du Colombier print("arpreq: %V also has ether addr %E\n", e->spa, e->sha);
6399ef1f84bSDavid du Colombier break;
6409ef1f84bSDavid du Colombier }
6419ef1f84bSDavid du Colombier }
6429ef1f84bSDavid du Colombier
6439ef1f84bSDavid du Colombier /* refresh what we know about sender */
6449ef1f84bSDavid du Colombier arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1);
6459ef1f84bSDavid du Colombier
6469ef1f84bSDavid du Colombier /* answer only requests for our address or systems we're proxying for */
6479ef1f84bSDavid du Colombier v4tov6(ip, e->tpa);
6489ef1f84bSDavid du Colombier if(!iplocalonifc(ifc, ip))
6499ef1f84bSDavid du Colombier if(!ipproxyifc(er->f, ifc, ip))
6509ef1f84bSDavid du Colombier break;
6519ef1f84bSDavid du Colombier
6529ef1f84bSDavid du Colombier n = sizeof(Etherarp);
6539ef1f84bSDavid du Colombier if(n < ifc->mintu)
6549ef1f84bSDavid du Colombier n = ifc->mintu;
6559ef1f84bSDavid du Colombier rbp = allocb(n);
6569ef1f84bSDavid du Colombier r = (Etherarp*)rbp->rp;
6579ef1f84bSDavid du Colombier memset(r, 0, sizeof(Etherarp));
6589ef1f84bSDavid du Colombier hnputs(r->type, ETARP);
6599ef1f84bSDavid du Colombier hnputs(r->hrd, 1);
6609ef1f84bSDavid du Colombier hnputs(r->pro, ETIP4);
6619ef1f84bSDavid du Colombier r->hln = sizeof(r->sha);
6629ef1f84bSDavid du Colombier r->pln = sizeof(r->spa);
6639ef1f84bSDavid du Colombier hnputs(r->op, ARPREPLY);
6649ef1f84bSDavid du Colombier memmove(r->tha, e->sha, sizeof(r->tha));
6659ef1f84bSDavid du Colombier memmove(r->tpa, e->spa, sizeof(r->tpa));
6669ef1f84bSDavid du Colombier memmove(r->sha, ifc->mac, sizeof(r->sha));
6679ef1f84bSDavid du Colombier memmove(r->spa, e->tpa, sizeof(r->spa));
6689ef1f84bSDavid du Colombier memmove(r->d, e->sha, sizeof(r->d));
6699ef1f84bSDavid du Colombier memmove(r->s, ifc->mac, sizeof(r->s));
6709ef1f84bSDavid du Colombier rbp->wp += n;
6719ef1f84bSDavid du Colombier
6729ef1f84bSDavid du Colombier er->achan->dev->bwrite(er->achan, rbp, 0);
6739ef1f84bSDavid du Colombier }
6749ef1f84bSDavid du Colombier freeb(ebp);
6759ef1f84bSDavid du Colombier }
6769ef1f84bSDavid du Colombier
6779ef1f84bSDavid du Colombier static void
recvarpproc(void * v)6789ef1f84bSDavid du Colombier recvarpproc(void *v)
6799ef1f84bSDavid du Colombier {
6809ef1f84bSDavid du Colombier Ipifc *ifc = v;
6819ef1f84bSDavid du Colombier Etherrock *er = ifc->arg;
6829ef1f84bSDavid du Colombier
6839ef1f84bSDavid du Colombier er->arpp = up;
6849ef1f84bSDavid du Colombier if(waserror()){
6859ef1f84bSDavid du Colombier er->arpp = 0;
6869ef1f84bSDavid du Colombier pexit("hangup", 1);
6879ef1f84bSDavid du Colombier }
6889ef1f84bSDavid du Colombier for(;;)
6899ef1f84bSDavid du Colombier recvarp(ifc);
6909ef1f84bSDavid du Colombier }
6919ef1f84bSDavid du Colombier
6929ef1f84bSDavid du Colombier static int
multicastea(uchar * ea,uchar * ip)6939ef1f84bSDavid du Colombier multicastea(uchar *ea, uchar *ip)
6949ef1f84bSDavid du Colombier {
6959ef1f84bSDavid du Colombier int x;
6969ef1f84bSDavid du Colombier
6979ef1f84bSDavid du Colombier switch(x = ipismulticast(ip)){
6989ef1f84bSDavid du Colombier case V4:
6999ef1f84bSDavid du Colombier ea[0] = 0x01;
7009ef1f84bSDavid du Colombier ea[1] = 0x00;
7019ef1f84bSDavid du Colombier ea[2] = 0x5e;
7029ef1f84bSDavid du Colombier ea[3] = ip[13] & 0x7f;
7039ef1f84bSDavid du Colombier ea[4] = ip[14];
7049ef1f84bSDavid du Colombier ea[5] = ip[15];
7059ef1f84bSDavid du Colombier break;
7069ef1f84bSDavid du Colombier case V6:
7079ef1f84bSDavid du Colombier ea[0] = 0x33;
7089ef1f84bSDavid du Colombier ea[1] = 0x33;
7099ef1f84bSDavid du Colombier ea[2] = ip[12];
7109ef1f84bSDavid du Colombier ea[3] = ip[13];
7119ef1f84bSDavid du Colombier ea[4] = ip[14];
7129ef1f84bSDavid du Colombier ea[5] = ip[15];
7139ef1f84bSDavid du Colombier break;
7149ef1f84bSDavid du Colombier }
7159ef1f84bSDavid du Colombier return x;
7169ef1f84bSDavid du Colombier }
7179ef1f84bSDavid du Colombier
7189ef1f84bSDavid du Colombier /*
7199ef1f84bSDavid du Colombier * fill in an arp entry for broadcast or multicast
7209ef1f84bSDavid du Colombier * addresses. Return the first queued packet for the
7219ef1f84bSDavid du Colombier * IP address.
7229ef1f84bSDavid du Colombier */
7239ef1f84bSDavid du Colombier static Block*
multicastarp(Fs * f,Arpent * a,Medium * medium,uchar * mac)7249ef1f84bSDavid du Colombier multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac)
7259ef1f84bSDavid du Colombier {
7269ef1f84bSDavid du Colombier /* is it broadcast? */
7279ef1f84bSDavid du Colombier switch(ipforme(f, a->ip)){
7289ef1f84bSDavid du Colombier case Runi:
7299ef1f84bSDavid du Colombier return nil;
7309ef1f84bSDavid du Colombier case Rbcast:
7319ef1f84bSDavid du Colombier memset(mac, 0xff, 6);
7329ef1f84bSDavid du Colombier return arpresolve(f->arp, a, medium, mac);
7339ef1f84bSDavid du Colombier default:
7349ef1f84bSDavid du Colombier break;
7359ef1f84bSDavid du Colombier }
7369ef1f84bSDavid du Colombier
7379ef1f84bSDavid du Colombier /* if multicast, fill in mac */
7389ef1f84bSDavid du Colombier switch(multicastea(mac, a->ip)){
7399ef1f84bSDavid du Colombier case V4:
7409ef1f84bSDavid du Colombier case V6:
7419ef1f84bSDavid du Colombier return arpresolve(f->arp, a, medium, mac);
7429ef1f84bSDavid du Colombier }
7439ef1f84bSDavid du Colombier
7449ef1f84bSDavid du Colombier /* let arp take care of it */
7459ef1f84bSDavid du Colombier return nil;
7469ef1f84bSDavid du Colombier }
7479ef1f84bSDavid du Colombier
7489ef1f84bSDavid du Colombier void
ethermediumlink(void)7499ef1f84bSDavid du Colombier ethermediumlink(void)
7509ef1f84bSDavid du Colombier {
7519ef1f84bSDavid du Colombier addipmedium(ðermedium);
7529ef1f84bSDavid du Colombier addipmedium(&gbemedium);
7539ef1f84bSDavid du Colombier }
7549ef1f84bSDavid du Colombier
7559ef1f84bSDavid du Colombier
7569ef1f84bSDavid du Colombier static void
etherpref2addr(uchar * pref,uchar * ea)7579ef1f84bSDavid du Colombier etherpref2addr(uchar *pref, uchar *ea)
7589ef1f84bSDavid du Colombier {
7599ef1f84bSDavid du Colombier pref[8] = ea[0] | 0x2;
7609ef1f84bSDavid du Colombier pref[9] = ea[1];
7619ef1f84bSDavid du Colombier pref[10] = ea[2];
7629ef1f84bSDavid du Colombier pref[11] = 0xFF;
7639ef1f84bSDavid du Colombier pref[12] = 0xFE;
7649ef1f84bSDavid du Colombier pref[13] = ea[3];
7659ef1f84bSDavid du Colombier pref[14] = ea[4];
7669ef1f84bSDavid du Colombier pref[15] = ea[5];
7679ef1f84bSDavid du Colombier }
768