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 "ip.h"
99ef1f84bSDavid du Colombier #include "ipv6.h"
109ef1f84bSDavid du Colombier
119ef1f84bSDavid du Colombier #define DPRINT if(0)print
129ef1f84bSDavid du Colombier
139ef1f84bSDavid du Colombier enum {
149ef1f84bSDavid du Colombier Maxmedia = 32,
159ef1f84bSDavid du Colombier Nself = Maxmedia*5,
169ef1f84bSDavid du Colombier NHASH = 1<<6,
179ef1f84bSDavid du Colombier NCACHE = 256,
189ef1f84bSDavid du Colombier QMAX = 192*1024-1,
19*a3323688SDavid du Colombier Maxv6repr = (128/(4*4))*(4+1), /* limit of xxxx:xxxx:⋯ notation */
209ef1f84bSDavid du Colombier };
219ef1f84bSDavid du Colombier
229ef1f84bSDavid du Colombier Medium *media[Maxmedia] = { 0 };
239ef1f84bSDavid du Colombier
249ef1f84bSDavid du Colombier /*
259ef1f84bSDavid du Colombier * cache of local addresses (addresses we answer to)
269ef1f84bSDavid du Colombier */
279ef1f84bSDavid du Colombier struct Ipself
289ef1f84bSDavid du Colombier {
299ef1f84bSDavid du Colombier uchar a[IPaddrlen];
309ef1f84bSDavid du Colombier Ipself *hnext; /* next address in the hash table */
319ef1f84bSDavid du Colombier Iplink *link; /* binding twixt Ipself and Ipifc */
329ef1f84bSDavid du Colombier ulong expire;
339ef1f84bSDavid du Colombier uchar type; /* type of address */
349ef1f84bSDavid du Colombier int ref;
359ef1f84bSDavid du Colombier Ipself *next; /* free list */
369ef1f84bSDavid du Colombier };
379ef1f84bSDavid du Colombier
389ef1f84bSDavid du Colombier struct Ipselftab
399ef1f84bSDavid du Colombier {
409ef1f84bSDavid du Colombier QLock;
419ef1f84bSDavid du Colombier int inited;
429ef1f84bSDavid du Colombier int acceptall; /* true if an interface has the null address */
439ef1f84bSDavid du Colombier Ipself *hash[NHASH]; /* hash chains */
449ef1f84bSDavid du Colombier };
459ef1f84bSDavid du Colombier
469ef1f84bSDavid du Colombier /*
479ef1f84bSDavid du Colombier * Multicast addresses are chained onto a Chan so that
489ef1f84bSDavid du Colombier * we can remove them when the Chan is closed.
499ef1f84bSDavid du Colombier */
509ef1f84bSDavid du Colombier typedef struct Ipmcast Ipmcast;
519ef1f84bSDavid du Colombier struct Ipmcast
529ef1f84bSDavid du Colombier {
539ef1f84bSDavid du Colombier Ipmcast *next;
549ef1f84bSDavid du Colombier uchar ma[IPaddrlen]; /* multicast address */
559ef1f84bSDavid du Colombier uchar ia[IPaddrlen]; /* interface address */
569ef1f84bSDavid du Colombier };
579ef1f84bSDavid du Colombier
589ef1f84bSDavid du Colombier /* quick hash for ip addresses */
599ef1f84bSDavid du Colombier #define hashipa(a) ( ( ((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1] )%NHASH )
609ef1f84bSDavid du Colombier
619ef1f84bSDavid du Colombier static char tifc[] = "ifc ";
629ef1f84bSDavid du Colombier
639ef1f84bSDavid du Colombier static void addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
649ef1f84bSDavid du Colombier static void remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
659ef1f84bSDavid du Colombier static char* ipifcjoinmulti(Ipifc *ifc, char **argv, int argc);
669ef1f84bSDavid du Colombier static char* ipifcleavemulti(Ipifc *ifc, char **argv, int argc);
679ef1f84bSDavid du Colombier static void ipifcregisterproxy(Fs*, Ipifc*, uchar*);
689ef1f84bSDavid du Colombier static char* ipifcremlifc(Ipifc*, Iplifc*);
699ef1f84bSDavid du Colombier
709ef1f84bSDavid du Colombier /*
719ef1f84bSDavid du Colombier * link in a new medium
729ef1f84bSDavid du Colombier */
739ef1f84bSDavid du Colombier void
addipmedium(Medium * med)749ef1f84bSDavid du Colombier addipmedium(Medium *med)
759ef1f84bSDavid du Colombier {
769ef1f84bSDavid du Colombier int i;
779ef1f84bSDavid du Colombier
789ef1f84bSDavid du Colombier for(i = 0; i < nelem(media)-1; i++)
799ef1f84bSDavid du Colombier if(media[i] == nil){
809ef1f84bSDavid du Colombier media[i] = med;
819ef1f84bSDavid du Colombier break;
829ef1f84bSDavid du Colombier }
839ef1f84bSDavid du Colombier }
849ef1f84bSDavid du Colombier
859ef1f84bSDavid du Colombier /*
869ef1f84bSDavid du Colombier * find the medium with this name
879ef1f84bSDavid du Colombier */
889ef1f84bSDavid du Colombier Medium*
ipfindmedium(char * name)899ef1f84bSDavid du Colombier ipfindmedium(char *name)
909ef1f84bSDavid du Colombier {
919ef1f84bSDavid du Colombier Medium **mp;
929ef1f84bSDavid du Colombier
939ef1f84bSDavid du Colombier for(mp = media; *mp != nil; mp++)
949ef1f84bSDavid du Colombier if(strcmp((*mp)->name, name) == 0)
959ef1f84bSDavid du Colombier break;
969ef1f84bSDavid du Colombier return *mp;
979ef1f84bSDavid du Colombier }
989ef1f84bSDavid du Colombier
999ef1f84bSDavid du Colombier /*
1009ef1f84bSDavid du Colombier * attach a device (or pkt driver) to the interface.
1019ef1f84bSDavid du Colombier * called with c locked
1029ef1f84bSDavid du Colombier */
1039ef1f84bSDavid du Colombier static char*
ipifcbind(Conv * c,char ** argv,int argc)1049ef1f84bSDavid du Colombier ipifcbind(Conv *c, char **argv, int argc)
1059ef1f84bSDavid du Colombier {
1069ef1f84bSDavid du Colombier Ipifc *ifc;
1079ef1f84bSDavid du Colombier Medium *medium;
1089ef1f84bSDavid du Colombier
1099ef1f84bSDavid du Colombier if(argc < 2)
1109ef1f84bSDavid du Colombier return Ebadarg;
1119ef1f84bSDavid du Colombier
1129ef1f84bSDavid du Colombier ifc = (Ipifc*)c->ptcl;
1139ef1f84bSDavid du Colombier
1149ef1f84bSDavid du Colombier /* bind the device to the interface */
1159ef1f84bSDavid du Colombier medium = ipfindmedium(argv[1]);
1169ef1f84bSDavid du Colombier if(medium == nil)
1179ef1f84bSDavid du Colombier return "unknown interface type";
1189ef1f84bSDavid du Colombier
1199ef1f84bSDavid du Colombier wlock(ifc);
1209ef1f84bSDavid du Colombier if(ifc->medium != nil){
1219ef1f84bSDavid du Colombier wunlock(ifc);
1229ef1f84bSDavid du Colombier return "interface already bound";
1239ef1f84bSDavid du Colombier }
1249ef1f84bSDavid du Colombier if(waserror()){
1259ef1f84bSDavid du Colombier wunlock(ifc);
1269ef1f84bSDavid du Colombier nexterror();
1279ef1f84bSDavid du Colombier }
1289ef1f84bSDavid du Colombier
1299ef1f84bSDavid du Colombier /* do medium specific binding */
1309ef1f84bSDavid du Colombier (*medium->bind)(ifc, argc, argv);
1319ef1f84bSDavid du Colombier
1329ef1f84bSDavid du Colombier /* set the bound device name */
1339ef1f84bSDavid du Colombier if(argc > 2)
1349ef1f84bSDavid du Colombier strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
1359ef1f84bSDavid du Colombier else
1369ef1f84bSDavid du Colombier snprint(ifc->dev, sizeof ifc->dev, "%s%d", medium->name, c->x);
1379ef1f84bSDavid du Colombier ifc->dev[sizeof(ifc->dev)-1] = 0;
1389ef1f84bSDavid du Colombier
1399ef1f84bSDavid du Colombier /* set up parameters */
1409ef1f84bSDavid du Colombier ifc->medium = medium;
1419ef1f84bSDavid du Colombier ifc->mintu = ifc->medium->mintu;
1429ef1f84bSDavid du Colombier ifc->maxtu = ifc->medium->maxtu;
1439ef1f84bSDavid du Colombier if(ifc->medium->unbindonclose == 0)
1449ef1f84bSDavid du Colombier ifc->conv->inuse++;
1459ef1f84bSDavid du Colombier ifc->rp.mflag = 0; /* default not managed */
1469ef1f84bSDavid du Colombier ifc->rp.oflag = 0;
1479ef1f84bSDavid du Colombier ifc->rp.maxraint = 600000; /* millisecs */
1489ef1f84bSDavid du Colombier ifc->rp.minraint = 200000;
1499ef1f84bSDavid du Colombier ifc->rp.linkmtu = 0; /* no mtu sent */
1509ef1f84bSDavid du Colombier ifc->rp.reachtime = 0;
1519ef1f84bSDavid du Colombier ifc->rp.rxmitra = 0;
1529ef1f84bSDavid du Colombier ifc->rp.ttl = MAXTTL;
1539ef1f84bSDavid du Colombier ifc->rp.routerlt = 3 * ifc->rp.maxraint;
1549ef1f84bSDavid du Colombier
1559ef1f84bSDavid du Colombier /* any ancillary structures (like routes) no longer pertain */
1569ef1f84bSDavid du Colombier ifc->ifcid++;
1579ef1f84bSDavid du Colombier
1589ef1f84bSDavid du Colombier /* reopen all the queues closed by a previous unbind */
1599ef1f84bSDavid du Colombier qreopen(c->rq);
1609ef1f84bSDavid du Colombier qreopen(c->eq);
1619ef1f84bSDavid du Colombier qreopen(c->sq);
1629ef1f84bSDavid du Colombier
1639ef1f84bSDavid du Colombier wunlock(ifc);
1649ef1f84bSDavid du Colombier poperror();
1659ef1f84bSDavid du Colombier
1669ef1f84bSDavid du Colombier return nil;
1679ef1f84bSDavid du Colombier }
1689ef1f84bSDavid du Colombier
1699ef1f84bSDavid du Colombier /*
1709ef1f84bSDavid du Colombier * detach a device from an interface, close the interface
1719ef1f84bSDavid du Colombier * called with ifc->conv closed
1729ef1f84bSDavid du Colombier */
1739ef1f84bSDavid du Colombier static char*
ipifcunbind(Ipifc * ifc)1749ef1f84bSDavid du Colombier ipifcunbind(Ipifc *ifc)
1759ef1f84bSDavid du Colombier {
1769ef1f84bSDavid du Colombier char *err;
1779ef1f84bSDavid du Colombier
1789ef1f84bSDavid du Colombier if(waserror()){
1799ef1f84bSDavid du Colombier wunlock(ifc);
1809ef1f84bSDavid du Colombier nexterror();
1819ef1f84bSDavid du Colombier }
1829ef1f84bSDavid du Colombier wlock(ifc);
1839ef1f84bSDavid du Colombier
1849ef1f84bSDavid du Colombier /* dissociate routes */
1859ef1f84bSDavid du Colombier if(ifc->medium != nil && ifc->medium->unbindonclose == 0)
1869ef1f84bSDavid du Colombier ifc->conv->inuse--;
1879ef1f84bSDavid du Colombier ifc->ifcid++;
1889ef1f84bSDavid du Colombier
1899ef1f84bSDavid du Colombier /* disassociate logical interfaces (before zeroing ifc->arg) */
1909ef1f84bSDavid du Colombier while(ifc->lifc){
1919ef1f84bSDavid du Colombier err = ipifcremlifc(ifc, ifc->lifc);
1929ef1f84bSDavid du Colombier /*
1939ef1f84bSDavid du Colombier * note: err non-zero means lifc not found,
1949ef1f84bSDavid du Colombier * which can't happen in this case.
1959ef1f84bSDavid du Colombier */
1969ef1f84bSDavid du Colombier if(err)
1979ef1f84bSDavid du Colombier error(err);
1989ef1f84bSDavid du Colombier }
1999ef1f84bSDavid du Colombier
2009ef1f84bSDavid du Colombier /* disassociate device */
2019ef1f84bSDavid du Colombier if(ifc->medium && ifc->medium->unbind)
2029ef1f84bSDavid du Colombier (*ifc->medium->unbind)(ifc);
2039ef1f84bSDavid du Colombier memset(ifc->dev, 0, sizeof(ifc->dev));
2049ef1f84bSDavid du Colombier ifc->arg = nil;
2059ef1f84bSDavid du Colombier ifc->reassemble = 0;
2069ef1f84bSDavid du Colombier
2079ef1f84bSDavid du Colombier /* close queues to stop queuing of packets */
2089ef1f84bSDavid du Colombier qclose(ifc->conv->rq);
2099ef1f84bSDavid du Colombier qclose(ifc->conv->wq);
2109ef1f84bSDavid du Colombier qclose(ifc->conv->sq);
2119ef1f84bSDavid du Colombier
2129ef1f84bSDavid du Colombier ifc->medium = nil;
2139ef1f84bSDavid du Colombier wunlock(ifc);
2149ef1f84bSDavid du Colombier poperror();
2159ef1f84bSDavid du Colombier return nil;
2169ef1f84bSDavid du Colombier }
2179ef1f84bSDavid du Colombier
2189ef1f84bSDavid du Colombier char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag"
2199ef1f84bSDavid du Colombier " %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt"
2209ef1f84bSDavid du Colombier " %d pktin %lud pktout %lud errin %lud errout %lud\n";
2219ef1f84bSDavid du Colombier
2229ef1f84bSDavid du Colombier char slineformat[] = " %-40I %-10M %-40I %-12lud %-12lud\n";
2239ef1f84bSDavid du Colombier
2249ef1f84bSDavid du Colombier static int
ipifcstate(Conv * c,char * state,int n)2259ef1f84bSDavid du Colombier ipifcstate(Conv *c, char *state, int n)
2269ef1f84bSDavid du Colombier {
2279ef1f84bSDavid du Colombier Ipifc *ifc;
2289ef1f84bSDavid du Colombier Iplifc *lifc;
2299ef1f84bSDavid du Colombier char *e, *s;
2309ef1f84bSDavid du Colombier
2319ef1f84bSDavid du Colombier ifc = (Ipifc*)c->ptcl;
2329ef1f84bSDavid du Colombier s = state;
2339ef1f84bSDavid du Colombier e = s+n;
2349ef1f84bSDavid du Colombier s = seprint(s, e, sfixedformat,
2359ef1f84bSDavid du Colombier ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
2369ef1f84bSDavid du Colombier ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
2379ef1f84bSDavid du Colombier ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
2389ef1f84bSDavid du Colombier ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
2399ef1f84bSDavid du Colombier ifc->in, ifc->out, ifc->inerr, ifc->outerr);
2409ef1f84bSDavid du Colombier
2419ef1f84bSDavid du Colombier rlock(ifc);
2429ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc && s < e; lifc = lifc->next)
2439ef1f84bSDavid du Colombier s = seprint(s, e, slineformat, lifc->local,
2449ef1f84bSDavid du Colombier lifc->mask, lifc->remote, lifc->validlt, lifc->preflt);
2459ef1f84bSDavid du Colombier if(ifc->lifc == nil)
2469ef1f84bSDavid du Colombier s = seprint(s, e, "\n");
2479ef1f84bSDavid du Colombier runlock(ifc);
2489ef1f84bSDavid du Colombier return s - state;
2499ef1f84bSDavid du Colombier }
2509ef1f84bSDavid du Colombier
2519ef1f84bSDavid du Colombier static int
ipifclocal(Conv * c,char * state,int n)2529ef1f84bSDavid du Colombier ipifclocal(Conv *c, char *state, int n)
2539ef1f84bSDavid du Colombier {
2549ef1f84bSDavid du Colombier Ipifc *ifc;
2559ef1f84bSDavid du Colombier Iplifc *lifc;
2569ef1f84bSDavid du Colombier Iplink *link;
2579ef1f84bSDavid du Colombier char *e, *s;
2589ef1f84bSDavid du Colombier
2599ef1f84bSDavid du Colombier ifc = (Ipifc*)c->ptcl;
2609ef1f84bSDavid du Colombier s = state;
2619ef1f84bSDavid du Colombier e = s+n;
2629ef1f84bSDavid du Colombier
2639ef1f84bSDavid du Colombier rlock(ifc);
2649ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc && s < e; lifc = lifc->next){
2659ef1f84bSDavid du Colombier s = seprint(s, e, "%-40.40I ->", lifc->local);
2669ef1f84bSDavid du Colombier for(link = lifc->link; link; link = link->lifclink)
2679ef1f84bSDavid du Colombier s = seprint(s, e, " %-40.40I", link->self->a);
2689ef1f84bSDavid du Colombier s = seprint(s, e, "\n");
2699ef1f84bSDavid du Colombier }
2709ef1f84bSDavid du Colombier runlock(ifc);
2719ef1f84bSDavid du Colombier return s - state;
2729ef1f84bSDavid du Colombier }
2739ef1f84bSDavid du Colombier
2749ef1f84bSDavid du Colombier static int
ipifcinuse(Conv * c)2759ef1f84bSDavid du Colombier ipifcinuse(Conv *c)
2769ef1f84bSDavid du Colombier {
2779ef1f84bSDavid du Colombier Ipifc *ifc;
2789ef1f84bSDavid du Colombier
2799ef1f84bSDavid du Colombier ifc = (Ipifc*)c->ptcl;
2809ef1f84bSDavid du Colombier return ifc->medium != nil;
2819ef1f84bSDavid du Colombier }
2829ef1f84bSDavid du Colombier
2839ef1f84bSDavid du Colombier /*
2849ef1f84bSDavid du Colombier * called when a process writes to an interface's 'data'
2859ef1f84bSDavid du Colombier */
2869ef1f84bSDavid du Colombier static void
ipifckick(void * x)2879ef1f84bSDavid du Colombier ipifckick(void *x)
2889ef1f84bSDavid du Colombier {
2899ef1f84bSDavid du Colombier Conv *c = x;
2909ef1f84bSDavid du Colombier Block *bp;
2919ef1f84bSDavid du Colombier Ipifc *ifc;
2929ef1f84bSDavid du Colombier
2939ef1f84bSDavid du Colombier bp = qget(c->wq);
2949ef1f84bSDavid du Colombier if(bp == nil)
2959ef1f84bSDavid du Colombier return;
2969ef1f84bSDavid du Colombier
2979ef1f84bSDavid du Colombier ifc = (Ipifc*)c->ptcl;
2989ef1f84bSDavid du Colombier if(!canrlock(ifc)){
2999ef1f84bSDavid du Colombier freeb(bp);
3009ef1f84bSDavid du Colombier return;
3019ef1f84bSDavid du Colombier }
3029ef1f84bSDavid du Colombier if(waserror()){
3039ef1f84bSDavid du Colombier runlock(ifc);
3049ef1f84bSDavid du Colombier nexterror();
3059ef1f84bSDavid du Colombier }
3069ef1f84bSDavid du Colombier if(ifc->medium == nil || ifc->medium->pktin == nil)
3079ef1f84bSDavid du Colombier freeb(bp);
3089ef1f84bSDavid du Colombier else
3099ef1f84bSDavid du Colombier (*ifc->medium->pktin)(c->p->f, ifc, bp);
3109ef1f84bSDavid du Colombier runlock(ifc);
3119ef1f84bSDavid du Colombier poperror();
3129ef1f84bSDavid du Colombier }
3139ef1f84bSDavid du Colombier
3149ef1f84bSDavid du Colombier /*
3159ef1f84bSDavid du Colombier * called when a new ipifc structure is created
3169ef1f84bSDavid du Colombier */
3179ef1f84bSDavid du Colombier static void
ipifccreate(Conv * c)3189ef1f84bSDavid du Colombier ipifccreate(Conv *c)
3199ef1f84bSDavid du Colombier {
3209ef1f84bSDavid du Colombier Ipifc *ifc;
3219ef1f84bSDavid du Colombier
3229ef1f84bSDavid du Colombier c->rq = qopen(QMAX, 0, 0, 0);
3239ef1f84bSDavid du Colombier c->sq = qopen(QMAX, 0, 0, 0);
3249ef1f84bSDavid du Colombier c->wq = qopen(QMAX, Qkick, ipifckick, c);
3259ef1f84bSDavid du Colombier ifc = (Ipifc*)c->ptcl;
3269ef1f84bSDavid du Colombier ifc->conv = c;
3279ef1f84bSDavid du Colombier ifc->unbinding = 0;
3289ef1f84bSDavid du Colombier ifc->medium = nil;
3299ef1f84bSDavid du Colombier ifc->reassemble = 0;
3309ef1f84bSDavid du Colombier }
3319ef1f84bSDavid du Colombier
3329ef1f84bSDavid du Colombier /*
3339ef1f84bSDavid du Colombier * called after last close of ipifc data or ctl
3349ef1f84bSDavid du Colombier * called with c locked, we must unlock
3359ef1f84bSDavid du Colombier */
3369ef1f84bSDavid du Colombier static void
ipifcclose(Conv * c)3379ef1f84bSDavid du Colombier ipifcclose(Conv *c)
3389ef1f84bSDavid du Colombier {
3399ef1f84bSDavid du Colombier Ipifc *ifc;
3409ef1f84bSDavid du Colombier Medium *medium;
3419ef1f84bSDavid du Colombier
3429ef1f84bSDavid du Colombier ifc = (Ipifc*)c->ptcl;
3439ef1f84bSDavid du Colombier medium = ifc->medium;
3449ef1f84bSDavid du Colombier if(medium != nil && medium->unbindonclose)
3459ef1f84bSDavid du Colombier ipifcunbind(ifc);
3469ef1f84bSDavid du Colombier }
3479ef1f84bSDavid du Colombier
3489ef1f84bSDavid du Colombier /*
3499ef1f84bSDavid du Colombier * change an interface's mtu
3509ef1f84bSDavid du Colombier */
3519ef1f84bSDavid du Colombier char*
ipifcsetmtu(Ipifc * ifc,char ** argv,int argc)3529ef1f84bSDavid du Colombier ipifcsetmtu(Ipifc *ifc, char **argv, int argc)
3539ef1f84bSDavid du Colombier {
3549ef1f84bSDavid du Colombier int mtu;
3559ef1f84bSDavid du Colombier
3569ef1f84bSDavid du Colombier if(argc < 2 || ifc->medium == nil)
3579ef1f84bSDavid du Colombier return Ebadarg;
3589ef1f84bSDavid du Colombier mtu = strtoul(argv[1], 0, 0);
3599ef1f84bSDavid du Colombier if(mtu < ifc->medium->mintu || mtu > ifc->medium->maxtu)
3609ef1f84bSDavid du Colombier return Ebadarg;
3619ef1f84bSDavid du Colombier ifc->maxtu = mtu;
3629ef1f84bSDavid du Colombier return nil;
3639ef1f84bSDavid du Colombier }
3649ef1f84bSDavid du Colombier
3659ef1f84bSDavid du Colombier /*
3669ef1f84bSDavid du Colombier * add an address to an interface.
3679ef1f84bSDavid du Colombier */
3689ef1f84bSDavid du Colombier char*
ipifcadd(Ipifc * ifc,char ** argv,int argc,int tentative,Iplifc * lifcp)3699ef1f84bSDavid du Colombier ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
3709ef1f84bSDavid du Colombier {
3719ef1f84bSDavid du Colombier int i, type, mtu, sendnbrdisc = 0;
3729ef1f84bSDavid du Colombier uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
3739ef1f84bSDavid du Colombier uchar bcast[IPaddrlen], net[IPaddrlen];
3749ef1f84bSDavid du Colombier Iplifc *lifc, **l;
3759ef1f84bSDavid du Colombier Fs *f;
3769ef1f84bSDavid du Colombier
3779ef1f84bSDavid du Colombier if(ifc->medium == nil)
3789ef1f84bSDavid du Colombier return "ipifc not yet bound to device";
3799ef1f84bSDavid du Colombier
3809ef1f84bSDavid du Colombier f = ifc->conv->p->f;
3819ef1f84bSDavid du Colombier
3829ef1f84bSDavid du Colombier type = Rifc;
3839ef1f84bSDavid du Colombier memset(ip, 0, IPaddrlen);
3849ef1f84bSDavid du Colombier memset(mask, 0, IPaddrlen);
3859ef1f84bSDavid du Colombier memset(rem, 0, IPaddrlen);
3869ef1f84bSDavid du Colombier switch(argc){
3879ef1f84bSDavid du Colombier case 6:
3889ef1f84bSDavid du Colombier if(strcmp(argv[5], "proxy") == 0)
3899ef1f84bSDavid du Colombier type |= Rproxy;
3909ef1f84bSDavid du Colombier /* fall through */
3919ef1f84bSDavid du Colombier case 5:
3929ef1f84bSDavid du Colombier mtu = strtoul(argv[4], 0, 0);
3939ef1f84bSDavid du Colombier if(mtu >= ifc->medium->mintu && mtu <= ifc->medium->maxtu)
3949ef1f84bSDavid du Colombier ifc->maxtu = mtu;
3959ef1f84bSDavid du Colombier /* fall through */
3969ef1f84bSDavid du Colombier case 4:
3979ef1f84bSDavid du Colombier if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1)
3989ef1f84bSDavid du Colombier return Ebadip;
3999ef1f84bSDavid du Colombier parseipmask(mask, argv[2]);
4009ef1f84bSDavid du Colombier maskip(rem, mask, net);
4019ef1f84bSDavid du Colombier break;
4029ef1f84bSDavid du Colombier case 3:
4039ef1f84bSDavid du Colombier if (parseip(ip, argv[1]) == -1)
4049ef1f84bSDavid du Colombier return Ebadip;
4059ef1f84bSDavid du Colombier parseipmask(mask, argv[2]);
4069ef1f84bSDavid du Colombier maskip(ip, mask, rem);
4079ef1f84bSDavid du Colombier maskip(rem, mask, net);
4089ef1f84bSDavid du Colombier break;
4099ef1f84bSDavid du Colombier case 2:
4109ef1f84bSDavid du Colombier if (parseip(ip, argv[1]) == -1)
4119ef1f84bSDavid du Colombier return Ebadip;
4129ef1f84bSDavid du Colombier memmove(mask, defmask(ip), IPaddrlen);
4139ef1f84bSDavid du Colombier maskip(ip, mask, rem);
4149ef1f84bSDavid du Colombier maskip(rem, mask, net);
4159ef1f84bSDavid du Colombier break;
4169ef1f84bSDavid du Colombier default:
4179ef1f84bSDavid du Colombier return Ebadarg;
4189ef1f84bSDavid du Colombier }
4199ef1f84bSDavid du Colombier if(isv4(ip))
4209ef1f84bSDavid du Colombier tentative = 0;
4219ef1f84bSDavid du Colombier wlock(ifc);
4229ef1f84bSDavid du Colombier
4239ef1f84bSDavid du Colombier /* ignore if this is already a local address for this ifc */
4249ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
4259ef1f84bSDavid du Colombier if(ipcmp(lifc->local, ip) == 0) {
4269ef1f84bSDavid du Colombier if(lifc->tentative != tentative)
4279ef1f84bSDavid du Colombier lifc->tentative = tentative;
4289ef1f84bSDavid du Colombier if(lifcp) {
4299ef1f84bSDavid du Colombier lifc->onlink = lifcp->onlink;
4309ef1f84bSDavid du Colombier lifc->autoflag = lifcp->autoflag;
4319ef1f84bSDavid du Colombier lifc->validlt = lifcp->validlt;
4329ef1f84bSDavid du Colombier lifc->preflt = lifcp->preflt;
4339ef1f84bSDavid du Colombier lifc->origint = lifcp->origint;
4349ef1f84bSDavid du Colombier }
4359ef1f84bSDavid du Colombier goto out;
4369ef1f84bSDavid du Colombier }
4379ef1f84bSDavid du Colombier }
4389ef1f84bSDavid du Colombier
4399ef1f84bSDavid du Colombier /* add the address to the list of logical ifc's for this ifc */
4409ef1f84bSDavid du Colombier lifc = smalloc(sizeof(Iplifc));
4419ef1f84bSDavid du Colombier ipmove(lifc->local, ip);
4429ef1f84bSDavid du Colombier ipmove(lifc->mask, mask);
4439ef1f84bSDavid du Colombier ipmove(lifc->remote, rem);
4449ef1f84bSDavid du Colombier ipmove(lifc->net, net);
4459ef1f84bSDavid du Colombier lifc->tentative = tentative;
4469ef1f84bSDavid du Colombier if(lifcp) {
4479ef1f84bSDavid du Colombier lifc->onlink = lifcp->onlink;
4489ef1f84bSDavid du Colombier lifc->autoflag = lifcp->autoflag;
4499ef1f84bSDavid du Colombier lifc->validlt = lifcp->validlt;
4509ef1f84bSDavid du Colombier lifc->preflt = lifcp->preflt;
4519ef1f84bSDavid du Colombier lifc->origint = lifcp->origint;
4529ef1f84bSDavid du Colombier } else { /* default values */
4539ef1f84bSDavid du Colombier lifc->onlink = lifc->autoflag = 1;
4549ef1f84bSDavid du Colombier lifc->validlt = lifc->preflt = ~0L;
4559ef1f84bSDavid du Colombier lifc->origint = NOW / 1000;
4569ef1f84bSDavid du Colombier }
4579ef1f84bSDavid du Colombier lifc->next = nil;
4589ef1f84bSDavid du Colombier
4599ef1f84bSDavid du Colombier for(l = &ifc->lifc; *l; l = &(*l)->next)
4609ef1f84bSDavid du Colombier ;
4619ef1f84bSDavid du Colombier *l = lifc;
4629ef1f84bSDavid du Colombier
4639ef1f84bSDavid du Colombier /* check for point-to-point interface */
4649ef1f84bSDavid du Colombier if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */
4659ef1f84bSDavid du Colombier if(ipcmp(mask, IPallbits) == 0)
4669ef1f84bSDavid du Colombier type |= Rptpt;
4679ef1f84bSDavid du Colombier
4689ef1f84bSDavid du Colombier /* add local routes */
4699ef1f84bSDavid du Colombier if(isv4(ip))
4709ef1f84bSDavid du Colombier v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
4719ef1f84bSDavid du Colombier else
4729ef1f84bSDavid du Colombier v6addroute(f, tifc, rem, mask, rem, type);
4739ef1f84bSDavid du Colombier
4749ef1f84bSDavid du Colombier addselfcache(f, ifc, lifc, ip, Runi);
4759ef1f84bSDavid du Colombier
4769ef1f84bSDavid du Colombier if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){
4779ef1f84bSDavid du Colombier ipifcregisterproxy(f, ifc, rem);
4789ef1f84bSDavid du Colombier goto out;
4799ef1f84bSDavid du Colombier }
4809ef1f84bSDavid du Colombier
4819ef1f84bSDavid du Colombier if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
4829ef1f84bSDavid du Colombier /* add subnet directed broadcast address to the self cache */
4839ef1f84bSDavid du Colombier for(i = 0; i < IPaddrlen; i++)
4849ef1f84bSDavid du Colombier bcast[i] = (ip[i] & mask[i]) | ~mask[i];
4859ef1f84bSDavid du Colombier addselfcache(f, ifc, lifc, bcast, Rbcast);
4869ef1f84bSDavid du Colombier
4879ef1f84bSDavid du Colombier /* add subnet directed network address to the self cache */
4889ef1f84bSDavid du Colombier for(i = 0; i < IPaddrlen; i++)
4899ef1f84bSDavid du Colombier bcast[i] = (ip[i] & mask[i]) & mask[i];
4909ef1f84bSDavid du Colombier addselfcache(f, ifc, lifc, bcast, Rbcast);
4919ef1f84bSDavid du Colombier
4929ef1f84bSDavid du Colombier /* add network directed broadcast address to the self cache */
4939ef1f84bSDavid du Colombier memmove(mask, defmask(ip), IPaddrlen);
4949ef1f84bSDavid du Colombier for(i = 0; i < IPaddrlen; i++)
4959ef1f84bSDavid du Colombier bcast[i] = (ip[i] & mask[i]) | ~mask[i];
4969ef1f84bSDavid du Colombier addselfcache(f, ifc, lifc, bcast, Rbcast);
4979ef1f84bSDavid du Colombier
4989ef1f84bSDavid du Colombier /* add network directed network address to the self cache */
4999ef1f84bSDavid du Colombier memmove(mask, defmask(ip), IPaddrlen);
5009ef1f84bSDavid du Colombier for(i = 0; i < IPaddrlen; i++)
5019ef1f84bSDavid du Colombier bcast[i] = (ip[i] & mask[i]) & mask[i];
5029ef1f84bSDavid du Colombier addselfcache(f, ifc, lifc, bcast, Rbcast);
5039ef1f84bSDavid du Colombier
5049ef1f84bSDavid du Colombier addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
5059ef1f84bSDavid du Colombier }
5069ef1f84bSDavid du Colombier else {
5079ef1f84bSDavid du Colombier if(ipcmp(ip, v6loopback) == 0) {
5089ef1f84bSDavid du Colombier /* add node-local mcast address */
5099ef1f84bSDavid du Colombier addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
5109ef1f84bSDavid du Colombier
5119ef1f84bSDavid du Colombier /* add route for all node multicast */
5129ef1f84bSDavid du Colombier v6addroute(f, tifc, v6allnodesN, v6allnodesNmask,
5139ef1f84bSDavid du Colombier v6allnodesN, Rmulti);
5149ef1f84bSDavid du Colombier }
5159ef1f84bSDavid du Colombier
5169ef1f84bSDavid du Colombier /* add all nodes multicast address */
5179ef1f84bSDavid du Colombier addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
5189ef1f84bSDavid du Colombier
5199ef1f84bSDavid du Colombier /* add route for all nodes multicast */
5209ef1f84bSDavid du Colombier v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL,
5219ef1f84bSDavid du Colombier Rmulti);
5229ef1f84bSDavid du Colombier
5239ef1f84bSDavid du Colombier /* add solicited-node multicast address */
5249ef1f84bSDavid du Colombier ipv62smcast(bcast, ip);
5259ef1f84bSDavid du Colombier addselfcache(f, ifc, lifc, bcast, Rmulti);
5269ef1f84bSDavid du Colombier
5279ef1f84bSDavid du Colombier sendnbrdisc = 1;
5289ef1f84bSDavid du Colombier }
5299ef1f84bSDavid du Colombier
5309ef1f84bSDavid du Colombier /* register the address on this network for address resolution */
5319ef1f84bSDavid du Colombier if(isv4(ip) && ifc->medium->areg != nil)
5329ef1f84bSDavid du Colombier (*ifc->medium->areg)(ifc, ip);
5339ef1f84bSDavid du Colombier
5349ef1f84bSDavid du Colombier out:
5359ef1f84bSDavid du Colombier wunlock(ifc);
5369ef1f84bSDavid du Colombier if(tentative && sendnbrdisc)
5379ef1f84bSDavid du Colombier icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
5389ef1f84bSDavid du Colombier return nil;
5399ef1f84bSDavid du Colombier }
5409ef1f84bSDavid du Colombier
5419ef1f84bSDavid du Colombier /*
5429ef1f84bSDavid du Colombier * remove a logical interface from an ifc
5439ef1f84bSDavid du Colombier * always called with ifc wlock'd
5449ef1f84bSDavid du Colombier */
5459ef1f84bSDavid du Colombier static char*
ipifcremlifc(Ipifc * ifc,Iplifc * lifc)5469ef1f84bSDavid du Colombier ipifcremlifc(Ipifc *ifc, Iplifc *lifc)
5479ef1f84bSDavid du Colombier {
5489ef1f84bSDavid du Colombier Iplifc **l;
5499ef1f84bSDavid du Colombier Fs *f;
5509ef1f84bSDavid du Colombier
5519ef1f84bSDavid du Colombier f = ifc->conv->p->f;
5529ef1f84bSDavid du Colombier
5539ef1f84bSDavid du Colombier /*
5549ef1f84bSDavid du Colombier * find address on this interface and remove from chain.
5559ef1f84bSDavid du Colombier * for pt to pt we actually specify the remote address as the
5569ef1f84bSDavid du Colombier * addresss to remove.
5579ef1f84bSDavid du Colombier */
5589ef1f84bSDavid du Colombier for(l = &ifc->lifc; *l != nil && *l != lifc; l = &(*l)->next)
5599ef1f84bSDavid du Colombier ;
5609ef1f84bSDavid du Colombier if(*l == nil)
5619ef1f84bSDavid du Colombier return "address not on this interface";
5629ef1f84bSDavid du Colombier *l = lifc->next;
5639ef1f84bSDavid du Colombier
5649ef1f84bSDavid du Colombier /* disassociate any addresses */
5659ef1f84bSDavid du Colombier while(lifc->link)
5669ef1f84bSDavid du Colombier remselfcache(f, ifc, lifc, lifc->link->self->a);
5679ef1f84bSDavid du Colombier
5689ef1f84bSDavid du Colombier /* remove the route for this logical interface */
5699ef1f84bSDavid du Colombier if(isv4(lifc->local))
5709ef1f84bSDavid du Colombier v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);
5719ef1f84bSDavid du Colombier else {
5729ef1f84bSDavid du Colombier v6delroute(f, lifc->remote, lifc->mask, 1);
5739ef1f84bSDavid du Colombier if(ipcmp(lifc->local, v6loopback) == 0)
5749ef1f84bSDavid du Colombier /* remove route for all node multicast */
5759ef1f84bSDavid du Colombier v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
5769ef1f84bSDavid du Colombier else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0)
5779ef1f84bSDavid du Colombier /* remove route for all link multicast */
5789ef1f84bSDavid du Colombier v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
5799ef1f84bSDavid du Colombier }
5809ef1f84bSDavid du Colombier
5819ef1f84bSDavid du Colombier free(lifc);
5829ef1f84bSDavid du Colombier return nil;
5839ef1f84bSDavid du Colombier }
5849ef1f84bSDavid du Colombier
5859ef1f84bSDavid du Colombier /*
5869ef1f84bSDavid du Colombier * remove an address from an interface.
5879ef1f84bSDavid du Colombier * called with c->car locked
5889ef1f84bSDavid du Colombier */
5899ef1f84bSDavid du Colombier char*
ipifcrem(Ipifc * ifc,char ** argv,int argc)5909ef1f84bSDavid du Colombier ipifcrem(Ipifc *ifc, char **argv, int argc)
5919ef1f84bSDavid du Colombier {
5929ef1f84bSDavid du Colombier char *rv;
5939ef1f84bSDavid du Colombier uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
5949ef1f84bSDavid du Colombier Iplifc *lifc;
5959ef1f84bSDavid du Colombier
5969ef1f84bSDavid du Colombier if(argc < 3)
5979ef1f84bSDavid du Colombier return Ebadarg;
5989ef1f84bSDavid du Colombier
5999ef1f84bSDavid du Colombier if (parseip(ip, argv[1]) == -1)
6009ef1f84bSDavid du Colombier return Ebadip;
6019ef1f84bSDavid du Colombier parseipmask(mask, argv[2]);
6029ef1f84bSDavid du Colombier if(argc < 4)
6039ef1f84bSDavid du Colombier maskip(ip, mask, rem);
6049ef1f84bSDavid du Colombier else
6059ef1f84bSDavid du Colombier if (parseip(rem, argv[3]) == -1)
6069ef1f84bSDavid du Colombier return Ebadip;
6079ef1f84bSDavid du Colombier
6089ef1f84bSDavid du Colombier wlock(ifc);
6099ef1f84bSDavid du Colombier
6109ef1f84bSDavid du Colombier /*
6119ef1f84bSDavid du Colombier * find address on this interface and remove from chain.
6129ef1f84bSDavid du Colombier * for pt to pt we actually specify the remote address as the
6139ef1f84bSDavid du Colombier * addresss to remove.
6149ef1f84bSDavid du Colombier */
6159ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
6169ef1f84bSDavid du Colombier if (memcmp(ip, lifc->local, IPaddrlen) == 0
6179ef1f84bSDavid du Colombier && memcmp(mask, lifc->mask, IPaddrlen) == 0
6189ef1f84bSDavid du Colombier && memcmp(rem, lifc->remote, IPaddrlen) == 0)
6199ef1f84bSDavid du Colombier break;
6209ef1f84bSDavid du Colombier }
6219ef1f84bSDavid du Colombier
6229ef1f84bSDavid du Colombier rv = ipifcremlifc(ifc, lifc);
6239ef1f84bSDavid du Colombier wunlock(ifc);
6249ef1f84bSDavid du Colombier return rv;
6259ef1f84bSDavid du Colombier }
6269ef1f84bSDavid du Colombier
6279ef1f84bSDavid du Colombier /*
6289ef1f84bSDavid du Colombier * distribute routes to active interfaces like the
6299ef1f84bSDavid du Colombier * TRIP linecards
6309ef1f84bSDavid du Colombier */
6319ef1f84bSDavid du Colombier void
ipifcaddroute(Fs * f,int vers,uchar * addr,uchar * mask,uchar * gate,int type)6329ef1f84bSDavid du Colombier ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type)
6339ef1f84bSDavid du Colombier {
6349ef1f84bSDavid du Colombier Medium *medium;
6359ef1f84bSDavid du Colombier Conv **cp, **e;
6369ef1f84bSDavid du Colombier Ipifc *ifc;
6379ef1f84bSDavid du Colombier
6389ef1f84bSDavid du Colombier e = &f->ipifc->conv[f->ipifc->nc];
6399ef1f84bSDavid du Colombier for(cp = f->ipifc->conv; cp < e; cp++){
6409ef1f84bSDavid du Colombier if(*cp != nil) {
6419ef1f84bSDavid du Colombier ifc = (Ipifc*)(*cp)->ptcl;
6429ef1f84bSDavid du Colombier medium = ifc->medium;
6439ef1f84bSDavid du Colombier if(medium != nil && medium->addroute != nil)
6449ef1f84bSDavid du Colombier medium->addroute(ifc, vers, addr, mask, gate, type);
6459ef1f84bSDavid du Colombier }
6469ef1f84bSDavid du Colombier }
6479ef1f84bSDavid du Colombier }
6489ef1f84bSDavid du Colombier
6499ef1f84bSDavid du Colombier void
ipifcremroute(Fs * f,int vers,uchar * addr,uchar * mask)6509ef1f84bSDavid du Colombier ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask)
6519ef1f84bSDavid du Colombier {
6529ef1f84bSDavid du Colombier Medium *medium;
6539ef1f84bSDavid du Colombier Conv **cp, **e;
6549ef1f84bSDavid du Colombier Ipifc *ifc;
6559ef1f84bSDavid du Colombier
6569ef1f84bSDavid du Colombier e = &f->ipifc->conv[f->ipifc->nc];
6579ef1f84bSDavid du Colombier for(cp = f->ipifc->conv; cp < e; cp++){
6589ef1f84bSDavid du Colombier if(*cp != nil) {
6599ef1f84bSDavid du Colombier ifc = (Ipifc*)(*cp)->ptcl;
6609ef1f84bSDavid du Colombier medium = ifc->medium;
6619ef1f84bSDavid du Colombier if(medium != nil && medium->remroute != nil)
6629ef1f84bSDavid du Colombier medium->remroute(ifc, vers, addr, mask);
6639ef1f84bSDavid du Colombier }
6649ef1f84bSDavid du Colombier }
6659ef1f84bSDavid du Colombier }
6669ef1f84bSDavid du Colombier
6679ef1f84bSDavid du Colombier /*
6689ef1f84bSDavid du Colombier * associate an address with the interface. This wipes out any previous
6699ef1f84bSDavid du Colombier * addresses. This is a macro that means, remove all the old interfaces
6709ef1f84bSDavid du Colombier * and add a new one.
6719ef1f84bSDavid du Colombier */
6729ef1f84bSDavid du Colombier static char*
ipifcconnect(Conv * c,char ** argv,int argc)6739ef1f84bSDavid du Colombier ipifcconnect(Conv* c, char **argv, int argc)
6749ef1f84bSDavid du Colombier {
6759ef1f84bSDavid du Colombier char *err;
6769ef1f84bSDavid du Colombier Ipifc *ifc;
6779ef1f84bSDavid du Colombier
6789ef1f84bSDavid du Colombier ifc = (Ipifc*)c->ptcl;
6799ef1f84bSDavid du Colombier
6809ef1f84bSDavid du Colombier if(ifc->medium == nil)
6819ef1f84bSDavid du Colombier return "ipifc not yet bound to device";
6829ef1f84bSDavid du Colombier
6839ef1f84bSDavid du Colombier if(waserror()){
6849ef1f84bSDavid du Colombier wunlock(ifc);
6859ef1f84bSDavid du Colombier nexterror();
6869ef1f84bSDavid du Colombier }
6879ef1f84bSDavid du Colombier wlock(ifc);
6889ef1f84bSDavid du Colombier while(ifc->lifc){
6899ef1f84bSDavid du Colombier err = ipifcremlifc(ifc, ifc->lifc);
6909ef1f84bSDavid du Colombier if(err)
6919ef1f84bSDavid du Colombier error(err);
6929ef1f84bSDavid du Colombier }
6939ef1f84bSDavid du Colombier wunlock(ifc);
6949ef1f84bSDavid du Colombier poperror();
6959ef1f84bSDavid du Colombier
6969ef1f84bSDavid du Colombier err = ipifcadd(ifc, argv, argc, 0, nil);
6979ef1f84bSDavid du Colombier if(err)
6989ef1f84bSDavid du Colombier return err;
6999ef1f84bSDavid du Colombier
7009ef1f84bSDavid du Colombier Fsconnected(c, nil);
7019ef1f84bSDavid du Colombier return nil;
7029ef1f84bSDavid du Colombier }
7039ef1f84bSDavid du Colombier
7049ef1f84bSDavid du Colombier char*
ipifcra6(Ipifc * ifc,char ** argv,int argc)7059ef1f84bSDavid du Colombier ipifcra6(Ipifc *ifc, char **argv, int argc)
7069ef1f84bSDavid du Colombier {
7079ef1f84bSDavid du Colombier int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
7089ef1f84bSDavid du Colombier
7099ef1f84bSDavid du Colombier argsleft = argc - 1;
7109ef1f84bSDavid du Colombier i = 1;
7119ef1f84bSDavid du Colombier
7129ef1f84bSDavid du Colombier if(argsleft % 2 != 0)
7139ef1f84bSDavid du Colombier return Ebadarg;
7149ef1f84bSDavid du Colombier
7159ef1f84bSDavid du Colombier while (argsleft > 1) {
7169ef1f84bSDavid du Colombier if(strcmp(argv[i], "recvra") == 0)
7179ef1f84bSDavid du Colombier ifc->recvra6 = (atoi(argv[i+1]) != 0);
7189ef1f84bSDavid du Colombier else if(strcmp(argv[i], "sendra") == 0)
7199ef1f84bSDavid du Colombier ifc->sendra6 = (atoi(argv[i+1]) != 0);
7209ef1f84bSDavid du Colombier else if(strcmp(argv[i], "mflag") == 0)
7219ef1f84bSDavid du Colombier ifc->rp.mflag = (atoi(argv[i+1]) != 0);
7229ef1f84bSDavid du Colombier else if(strcmp(argv[i], "oflag") == 0)
7239ef1f84bSDavid du Colombier ifc->rp.oflag = (atoi(argv[i+1]) != 0);
7249ef1f84bSDavid du Colombier else if(strcmp(argv[i], "maxraint") == 0)
7259ef1f84bSDavid du Colombier ifc->rp.maxraint = atoi(argv[i+1]);
7269ef1f84bSDavid du Colombier else if(strcmp(argv[i], "minraint") == 0)
7279ef1f84bSDavid du Colombier ifc->rp.minraint = atoi(argv[i+1]);
7289ef1f84bSDavid du Colombier else if(strcmp(argv[i], "linkmtu") == 0)
7299ef1f84bSDavid du Colombier ifc->rp.linkmtu = atoi(argv[i+1]);
7309ef1f84bSDavid du Colombier else if(strcmp(argv[i], "reachtime") == 0)
7319ef1f84bSDavid du Colombier ifc->rp.reachtime = atoi(argv[i+1]);
7329ef1f84bSDavid du Colombier else if(strcmp(argv[i], "rxmitra") == 0)
7339ef1f84bSDavid du Colombier ifc->rp.rxmitra = atoi(argv[i+1]);
7349ef1f84bSDavid du Colombier else if(strcmp(argv[i], "ttl") == 0)
7359ef1f84bSDavid du Colombier ifc->rp.ttl = atoi(argv[i+1]);
7369ef1f84bSDavid du Colombier else if(strcmp(argv[i], "routerlt") == 0)
7379ef1f84bSDavid du Colombier ifc->rp.routerlt = atoi(argv[i+1]);
7389ef1f84bSDavid du Colombier else
7399ef1f84bSDavid du Colombier return Ebadarg;
7409ef1f84bSDavid du Colombier
7419ef1f84bSDavid du Colombier argsleft -= 2;
7429ef1f84bSDavid du Colombier i += 2;
7439ef1f84bSDavid du Colombier }
7449ef1f84bSDavid du Colombier
7459ef1f84bSDavid du Colombier /* consistency check */
7469ef1f84bSDavid du Colombier if(ifc->rp.maxraint < ifc->rp.minraint) {
7479ef1f84bSDavid du Colombier ifc->rp.maxraint = vmax;
7489ef1f84bSDavid du Colombier ifc->rp.minraint = vmin;
7499ef1f84bSDavid du Colombier return Ebadarg;
7509ef1f84bSDavid du Colombier }
7519ef1f84bSDavid du Colombier return nil;
7529ef1f84bSDavid du Colombier }
7539ef1f84bSDavid du Colombier
7549ef1f84bSDavid du Colombier /*
7559ef1f84bSDavid du Colombier * non-standard control messages.
7569ef1f84bSDavid du Colombier * called with c->car locked.
7579ef1f84bSDavid du Colombier */
7589ef1f84bSDavid du Colombier static char*
ipifcctl(Conv * c,char ** argv,int argc)7599ef1f84bSDavid du Colombier ipifcctl(Conv* c, char**argv, int argc)
7609ef1f84bSDavid du Colombier {
7619ef1f84bSDavid du Colombier Ipifc *ifc;
7629ef1f84bSDavid du Colombier int i;
7639ef1f84bSDavid du Colombier
7649ef1f84bSDavid du Colombier ifc = (Ipifc*)c->ptcl;
7659ef1f84bSDavid du Colombier if(strcmp(argv[0], "add") == 0)
7669ef1f84bSDavid du Colombier return ipifcadd(ifc, argv, argc, 0, nil);
7679ef1f84bSDavid du Colombier else if(strcmp(argv[0], "try") == 0)
7689ef1f84bSDavid du Colombier return ipifcadd(ifc, argv, argc, 1, nil);
7699ef1f84bSDavid du Colombier else if(strcmp(argv[0], "remove") == 0)
7709ef1f84bSDavid du Colombier return ipifcrem(ifc, argv, argc);
7719ef1f84bSDavid du Colombier else if(strcmp(argv[0], "unbind") == 0)
7729ef1f84bSDavid du Colombier return ipifcunbind(ifc);
7739ef1f84bSDavid du Colombier else if(strcmp(argv[0], "joinmulti") == 0)
7749ef1f84bSDavid du Colombier return ipifcjoinmulti(ifc, argv, argc);
7759ef1f84bSDavid du Colombier else if(strcmp(argv[0], "leavemulti") == 0)
7769ef1f84bSDavid du Colombier return ipifcleavemulti(ifc, argv, argc);
7779ef1f84bSDavid du Colombier else if(strcmp(argv[0], "mtu") == 0)
7789ef1f84bSDavid du Colombier return ipifcsetmtu(ifc, argv, argc);
7799ef1f84bSDavid du Colombier else if(strcmp(argv[0], "reassemble") == 0){
7809ef1f84bSDavid du Colombier ifc->reassemble = 1;
7819ef1f84bSDavid du Colombier return nil;
7829ef1f84bSDavid du Colombier }
7839ef1f84bSDavid du Colombier else if(strcmp(argv[0], "iprouting") == 0){
7849ef1f84bSDavid du Colombier i = 1;
7859ef1f84bSDavid du Colombier if(argc > 1)
7869ef1f84bSDavid du Colombier i = atoi(argv[1]);
7879ef1f84bSDavid du Colombier iprouting(c->p->f, i);
7889ef1f84bSDavid du Colombier return nil;
7899ef1f84bSDavid du Colombier }
7909ef1f84bSDavid du Colombier else if(strcmp(argv[0], "add6") == 0)
7919ef1f84bSDavid du Colombier return ipifcadd6(ifc, argv, argc);
7929ef1f84bSDavid du Colombier else if(strcmp(argv[0], "ra6") == 0)
7939ef1f84bSDavid du Colombier return ipifcra6(ifc, argv, argc);
7949ef1f84bSDavid du Colombier return "unsupported ctl";
7959ef1f84bSDavid du Colombier }
7969ef1f84bSDavid du Colombier
7979ef1f84bSDavid du Colombier int
ipifcstats(Proto * ipifc,char * buf,int len)7989ef1f84bSDavid du Colombier ipifcstats(Proto *ipifc, char *buf, int len)
7999ef1f84bSDavid du Colombier {
8009ef1f84bSDavid du Colombier return ipstats(ipifc->f, buf, len);
8019ef1f84bSDavid du Colombier }
8029ef1f84bSDavid du Colombier
8039ef1f84bSDavid du Colombier void
ipifcinit(Fs * f)8049ef1f84bSDavid du Colombier ipifcinit(Fs *f)
8059ef1f84bSDavid du Colombier {
8069ef1f84bSDavid du Colombier Proto *ipifc;
8079ef1f84bSDavid du Colombier
8089ef1f84bSDavid du Colombier ipifc = smalloc(sizeof(Proto));
8099ef1f84bSDavid du Colombier ipifc->name = "ipifc";
8109ef1f84bSDavid du Colombier ipifc->connect = ipifcconnect;
8119ef1f84bSDavid du Colombier ipifc->announce = nil;
8129ef1f84bSDavid du Colombier ipifc->bind = ipifcbind;
8139ef1f84bSDavid du Colombier ipifc->state = ipifcstate;
8149ef1f84bSDavid du Colombier ipifc->create = ipifccreate;
8159ef1f84bSDavid du Colombier ipifc->close = ipifcclose;
8169ef1f84bSDavid du Colombier ipifc->rcv = nil;
8179ef1f84bSDavid du Colombier ipifc->ctl = ipifcctl;
8189ef1f84bSDavid du Colombier ipifc->advise = nil;
8199ef1f84bSDavid du Colombier ipifc->stats = ipifcstats;
8209ef1f84bSDavid du Colombier ipifc->inuse = ipifcinuse;
8219ef1f84bSDavid du Colombier ipifc->local = ipifclocal;
8229ef1f84bSDavid du Colombier ipifc->ipproto = -1;
8239ef1f84bSDavid du Colombier ipifc->nc = Maxmedia;
8249ef1f84bSDavid du Colombier ipifc->ptclsize = sizeof(Ipifc);
8259ef1f84bSDavid du Colombier
8269ef1f84bSDavid du Colombier f->ipifc = ipifc; /* hack for ipifcremroute, findipifc, ... */
8279ef1f84bSDavid du Colombier f->self = smalloc(sizeof(Ipselftab)); /* hack for ipforme */
8289ef1f84bSDavid du Colombier
8299ef1f84bSDavid du Colombier Fsproto(f, ipifc);
8309ef1f84bSDavid du Colombier }
8319ef1f84bSDavid du Colombier
8329ef1f84bSDavid du Colombier /*
8339ef1f84bSDavid du Colombier * add to self routing cache
8349ef1f84bSDavid du Colombier * called with c->car locked
8359ef1f84bSDavid du Colombier */
8369ef1f84bSDavid du Colombier static void
addselfcache(Fs * f,Ipifc * ifc,Iplifc * lifc,uchar * a,int type)8379ef1f84bSDavid du Colombier addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
8389ef1f84bSDavid du Colombier {
8399ef1f84bSDavid du Colombier Ipself *p;
8409ef1f84bSDavid du Colombier Iplink *lp;
8419ef1f84bSDavid du Colombier int h;
8429ef1f84bSDavid du Colombier
8439ef1f84bSDavid du Colombier qlock(f->self);
8449ef1f84bSDavid du Colombier
8459ef1f84bSDavid du Colombier /* see if the address already exists */
8469ef1f84bSDavid du Colombier h = hashipa(a);
8479ef1f84bSDavid du Colombier for(p = f->self->hash[h]; p; p = p->next)
8489ef1f84bSDavid du Colombier if(memcmp(a, p->a, IPaddrlen) == 0)
8499ef1f84bSDavid du Colombier break;
8509ef1f84bSDavid du Colombier
8519ef1f84bSDavid du Colombier /* allocate a local address and add to hash chain */
8529ef1f84bSDavid du Colombier if(p == nil){
8539ef1f84bSDavid du Colombier p = smalloc(sizeof(*p));
8549ef1f84bSDavid du Colombier ipmove(p->a, a);
8559ef1f84bSDavid du Colombier p->type = type;
8569ef1f84bSDavid du Colombier p->next = f->self->hash[h];
8579ef1f84bSDavid du Colombier f->self->hash[h] = p;
8589ef1f84bSDavid du Colombier
8599ef1f84bSDavid du Colombier /* if the null address, accept all packets */
8609ef1f84bSDavid du Colombier if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
8619ef1f84bSDavid du Colombier f->self->acceptall = 1;
8629ef1f84bSDavid du Colombier }
8639ef1f84bSDavid du Colombier
8649ef1f84bSDavid du Colombier /* look for a link for this lifc */
8659ef1f84bSDavid du Colombier for(lp = p->link; lp; lp = lp->selflink)
8669ef1f84bSDavid du Colombier if(lp->lifc == lifc)
8679ef1f84bSDavid du Colombier break;
8689ef1f84bSDavid du Colombier
8699ef1f84bSDavid du Colombier /* allocate a lifc-to-local link and link to both */
8709ef1f84bSDavid du Colombier if(lp == nil){
8719ef1f84bSDavid du Colombier lp = smalloc(sizeof(*lp));
8729ef1f84bSDavid du Colombier lp->ref = 1;
8739ef1f84bSDavid du Colombier lp->lifc = lifc;
8749ef1f84bSDavid du Colombier lp->self = p;
8759ef1f84bSDavid du Colombier lp->selflink = p->link;
8769ef1f84bSDavid du Colombier p->link = lp;
8779ef1f84bSDavid du Colombier lp->lifclink = lifc->link;
8789ef1f84bSDavid du Colombier lifc->link = lp;
8799ef1f84bSDavid du Colombier
8809ef1f84bSDavid du Colombier /* add to routing table */
8819ef1f84bSDavid du Colombier if(isv4(a))
8829ef1f84bSDavid du Colombier v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off,
8839ef1f84bSDavid du Colombier a+IPv4off, type);
8849ef1f84bSDavid du Colombier else
8859ef1f84bSDavid du Colombier v6addroute(f, tifc, a, IPallbits, a, type);
8869ef1f84bSDavid du Colombier
8879ef1f84bSDavid du Colombier if((type & Rmulti) && ifc->medium->addmulti != nil)
8889ef1f84bSDavid du Colombier (*ifc->medium->addmulti)(ifc, a, lifc->local);
8899ef1f84bSDavid du Colombier } else
8909ef1f84bSDavid du Colombier lp->ref++;
8919ef1f84bSDavid du Colombier
8929ef1f84bSDavid du Colombier qunlock(f->self);
8939ef1f84bSDavid du Colombier }
8949ef1f84bSDavid du Colombier
8959ef1f84bSDavid du Colombier /*
8969ef1f84bSDavid du Colombier * These structures are unlinked from their chains while
8979ef1f84bSDavid du Colombier * other threads may be using them. To avoid excessive locking,
8989ef1f84bSDavid du Colombier * just put them aside for a while before freeing them.
8999ef1f84bSDavid du Colombier * called with f->self locked
9009ef1f84bSDavid du Colombier */
9019ef1f84bSDavid du Colombier static Iplink *freeiplink;
9029ef1f84bSDavid du Colombier static Ipself *freeipself;
9039ef1f84bSDavid du Colombier
9049ef1f84bSDavid du Colombier static void
iplinkfree(Iplink * p)9059ef1f84bSDavid du Colombier iplinkfree(Iplink *p)
9069ef1f84bSDavid du Colombier {
9079ef1f84bSDavid du Colombier Iplink **l, *np;
9089ef1f84bSDavid du Colombier ulong now = NOW;
9099ef1f84bSDavid du Colombier
9109ef1f84bSDavid du Colombier l = &freeiplink;
9119ef1f84bSDavid du Colombier for(np = *l; np; np = *l){
9129ef1f84bSDavid du Colombier if(np->expire > now){
9139ef1f84bSDavid du Colombier *l = np->next;
9149ef1f84bSDavid du Colombier free(np);
9159ef1f84bSDavid du Colombier continue;
9169ef1f84bSDavid du Colombier }
9179ef1f84bSDavid du Colombier l = &np->next;
9189ef1f84bSDavid du Colombier }
9199ef1f84bSDavid du Colombier p->expire = now + 5000; /* give other threads 5 secs to get out */
9209ef1f84bSDavid du Colombier p->next = nil;
9219ef1f84bSDavid du Colombier *l = p;
9229ef1f84bSDavid du Colombier }
9239ef1f84bSDavid du Colombier
9249ef1f84bSDavid du Colombier static void
ipselffree(Ipself * p)9259ef1f84bSDavid du Colombier ipselffree(Ipself *p)
9269ef1f84bSDavid du Colombier {
9279ef1f84bSDavid du Colombier Ipself **l, *np;
9289ef1f84bSDavid du Colombier ulong now = NOW;
9299ef1f84bSDavid du Colombier
9309ef1f84bSDavid du Colombier l = &freeipself;
9319ef1f84bSDavid du Colombier for(np = *l; np; np = *l){
9329ef1f84bSDavid du Colombier if(np->expire > now){
9339ef1f84bSDavid du Colombier *l = np->next;
9349ef1f84bSDavid du Colombier free(np);
9359ef1f84bSDavid du Colombier continue;
9369ef1f84bSDavid du Colombier }
9379ef1f84bSDavid du Colombier l = &np->next;
9389ef1f84bSDavid du Colombier }
9399ef1f84bSDavid du Colombier p->expire = now + 5000; /* give other threads 5 secs to get out */
9409ef1f84bSDavid du Colombier p->next = nil;
9419ef1f84bSDavid du Colombier *l = p;
9429ef1f84bSDavid du Colombier }
9439ef1f84bSDavid du Colombier
9449ef1f84bSDavid du Colombier /*
9459ef1f84bSDavid du Colombier * Decrement reference for this address on this link.
9469ef1f84bSDavid du Colombier * Unlink from selftab if this is the last ref.
9479ef1f84bSDavid du Colombier * called with c->car locked
9489ef1f84bSDavid du Colombier */
9499ef1f84bSDavid du Colombier static void
remselfcache(Fs * f,Ipifc * ifc,Iplifc * lifc,uchar * a)9509ef1f84bSDavid du Colombier remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
9519ef1f84bSDavid du Colombier {
9529ef1f84bSDavid du Colombier Ipself *p, **l;
9539ef1f84bSDavid du Colombier Iplink *link, **l_self, **l_lifc;
9549ef1f84bSDavid du Colombier
9559ef1f84bSDavid du Colombier qlock(f->self);
9569ef1f84bSDavid du Colombier
9579ef1f84bSDavid du Colombier /* find the unique selftab entry */
9589ef1f84bSDavid du Colombier l = &f->self->hash[hashipa(a)];
9599ef1f84bSDavid du Colombier for(p = *l; p; p = *l){
9609ef1f84bSDavid du Colombier if(ipcmp(p->a, a) == 0)
9619ef1f84bSDavid du Colombier break;
9629ef1f84bSDavid du Colombier l = &p->next;
9639ef1f84bSDavid du Colombier }
9649ef1f84bSDavid du Colombier
9659ef1f84bSDavid du Colombier if(p == nil)
9669ef1f84bSDavid du Colombier goto out;
9679ef1f84bSDavid du Colombier
9689ef1f84bSDavid du Colombier /*
9699ef1f84bSDavid du Colombier * walk down links from an ifc looking for one
9709ef1f84bSDavid du Colombier * that matches the selftab entry
9719ef1f84bSDavid du Colombier */
9729ef1f84bSDavid du Colombier l_lifc = &lifc->link;
9739ef1f84bSDavid du Colombier for(link = *l_lifc; link; link = *l_lifc){
9749ef1f84bSDavid du Colombier if(link->self == p)
9759ef1f84bSDavid du Colombier break;
9769ef1f84bSDavid du Colombier l_lifc = &link->lifclink;
9779ef1f84bSDavid du Colombier }
9789ef1f84bSDavid du Colombier
9799ef1f84bSDavid du Colombier if(link == nil)
9809ef1f84bSDavid du Colombier goto out;
9819ef1f84bSDavid du Colombier
9829ef1f84bSDavid du Colombier /*
9839ef1f84bSDavid du Colombier * walk down the links from the selftab looking for
9849ef1f84bSDavid du Colombier * the one we just found
9859ef1f84bSDavid du Colombier */
9869ef1f84bSDavid du Colombier l_self = &p->link;
9879ef1f84bSDavid du Colombier for(link = *l_self; link; link = *l_self){
9889ef1f84bSDavid du Colombier if(link == *l_lifc)
9899ef1f84bSDavid du Colombier break;
9909ef1f84bSDavid du Colombier l_self = &link->selflink;
9919ef1f84bSDavid du Colombier }
9929ef1f84bSDavid du Colombier
9939ef1f84bSDavid du Colombier if(link == nil)
9949ef1f84bSDavid du Colombier panic("remselfcache");
9959ef1f84bSDavid du Colombier
9969ef1f84bSDavid du Colombier if(--(link->ref) != 0)
9979ef1f84bSDavid du Colombier goto out;
9989ef1f84bSDavid du Colombier
9999ef1f84bSDavid du Colombier if((p->type & Rmulti) && ifc->medium->remmulti != nil)
10009ef1f84bSDavid du Colombier (*ifc->medium->remmulti)(ifc, a, lifc->local);
10019ef1f84bSDavid du Colombier
10029ef1f84bSDavid du Colombier /* ref == 0, remove from both chains and free the link */
10039ef1f84bSDavid du Colombier *l_lifc = link->lifclink;
10049ef1f84bSDavid du Colombier *l_self = link->selflink;
10059ef1f84bSDavid du Colombier iplinkfree(link);
10069ef1f84bSDavid du Colombier
10079ef1f84bSDavid du Colombier if(p->link != nil)
10089ef1f84bSDavid du Colombier goto out;
10099ef1f84bSDavid du Colombier
10109ef1f84bSDavid du Colombier /* remove from routing table */
10119ef1f84bSDavid du Colombier if(isv4(a))
10129ef1f84bSDavid du Colombier v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
10139ef1f84bSDavid du Colombier else
10149ef1f84bSDavid du Colombier v6delroute(f, a, IPallbits, 1);
10159ef1f84bSDavid du Colombier
10169ef1f84bSDavid du Colombier /* no more links, remove from hash and free */
10179ef1f84bSDavid du Colombier *l = p->next;
10189ef1f84bSDavid du Colombier ipselffree(p);
10199ef1f84bSDavid du Colombier
10209ef1f84bSDavid du Colombier /* if IPnoaddr, forget */
10219ef1f84bSDavid du Colombier if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
10229ef1f84bSDavid du Colombier f->self->acceptall = 0;
10239ef1f84bSDavid du Colombier
10249ef1f84bSDavid du Colombier out:
10259ef1f84bSDavid du Colombier qunlock(f->self);
10269ef1f84bSDavid du Colombier }
10279ef1f84bSDavid du Colombier
10289ef1f84bSDavid du Colombier static char *stformat = "%-44.44I %2.2d %4.4s\n";
10299ef1f84bSDavid du Colombier enum
10309ef1f84bSDavid du Colombier {
10319ef1f84bSDavid du Colombier Nstformat= 41,
10329ef1f84bSDavid du Colombier };
10339ef1f84bSDavid du Colombier
10349ef1f84bSDavid du Colombier long
ipselftabread(Fs * f,char * cp,ulong offset,int n)10359ef1f84bSDavid du Colombier ipselftabread(Fs *f, char *cp, ulong offset, int n)
10369ef1f84bSDavid du Colombier {
10379ef1f84bSDavid du Colombier int i, nifc, off;
10389ef1f84bSDavid du Colombier Ipself *p;
10399ef1f84bSDavid du Colombier Iplink *link;
10409ef1f84bSDavid du Colombier char *e, *s, state[8];
10419ef1f84bSDavid du Colombier
10429ef1f84bSDavid du Colombier s = cp;
10439ef1f84bSDavid du Colombier e = s+n;
10449ef1f84bSDavid du Colombier off = offset;
10459ef1f84bSDavid du Colombier qlock(f->self);
10469ef1f84bSDavid du Colombier for(i = 0; i < NHASH && s < e; i++){
10479ef1f84bSDavid du Colombier for(p = f->self->hash[i]; p != nil && s < e; p = p->next){
10489ef1f84bSDavid du Colombier nifc = 0;
10499ef1f84bSDavid du Colombier for(link = p->link; link; link = link->selflink)
10509ef1f84bSDavid du Colombier nifc++;
10519ef1f84bSDavid du Colombier routetype(p->type, state);
10529ef1f84bSDavid du Colombier s = seprint(s, e, stformat, p->a, nifc, state);
10539ef1f84bSDavid du Colombier if(off > 0){
10549ef1f84bSDavid du Colombier off -= s - cp;
10559ef1f84bSDavid du Colombier s = cp;
10569ef1f84bSDavid du Colombier }
10579ef1f84bSDavid du Colombier }
10589ef1f84bSDavid du Colombier }
10599ef1f84bSDavid du Colombier qunlock(f->self);
10609ef1f84bSDavid du Colombier return s - cp;
10619ef1f84bSDavid du Colombier }
10629ef1f84bSDavid du Colombier
10639ef1f84bSDavid du Colombier int
iptentative(Fs * f,uchar * addr)10649ef1f84bSDavid du Colombier iptentative(Fs *f, uchar *addr)
10659ef1f84bSDavid du Colombier {
10669ef1f84bSDavid du Colombier Ipself *p;
10679ef1f84bSDavid du Colombier
10689ef1f84bSDavid du Colombier p = f->self->hash[hashipa(addr)];
10699ef1f84bSDavid du Colombier for(; p; p = p->next){
10709ef1f84bSDavid du Colombier if(ipcmp(addr, p->a) == 0)
10719ef1f84bSDavid du Colombier return p->link->lifc->tentative;
10729ef1f84bSDavid du Colombier }
10739ef1f84bSDavid du Colombier return 0;
10749ef1f84bSDavid du Colombier }
10759ef1f84bSDavid du Colombier
10769ef1f84bSDavid du Colombier /*
10779ef1f84bSDavid du Colombier * returns
10789ef1f84bSDavid du Colombier * 0 - no match
10799ef1f84bSDavid du Colombier * Runi
10809ef1f84bSDavid du Colombier * Rbcast
10819ef1f84bSDavid du Colombier * Rmcast
10829ef1f84bSDavid du Colombier */
10839ef1f84bSDavid du Colombier int
ipforme(Fs * f,uchar * addr)10849ef1f84bSDavid du Colombier ipforme(Fs *f, uchar *addr)
10859ef1f84bSDavid du Colombier {
10869ef1f84bSDavid du Colombier Ipself *p;
10879ef1f84bSDavid du Colombier
10889ef1f84bSDavid du Colombier p = f->self->hash[hashipa(addr)];
10899ef1f84bSDavid du Colombier for(; p; p = p->next){
10909ef1f84bSDavid du Colombier if(ipcmp(addr, p->a) == 0)
10919ef1f84bSDavid du Colombier return p->type;
10929ef1f84bSDavid du Colombier }
10939ef1f84bSDavid du Colombier
10949ef1f84bSDavid du Colombier /* hack to say accept anything */
10959ef1f84bSDavid du Colombier if(f->self->acceptall)
10969ef1f84bSDavid du Colombier return Runi;
10979ef1f84bSDavid du Colombier return 0;
10989ef1f84bSDavid du Colombier }
10999ef1f84bSDavid du Colombier
11009ef1f84bSDavid du Colombier /*
11019ef1f84bSDavid du Colombier * find the ifc on same net as the remote system. If none,
11029ef1f84bSDavid du Colombier * return nil.
11039ef1f84bSDavid du Colombier */
11049ef1f84bSDavid du Colombier Ipifc*
findipifc(Fs * f,uchar * remote,int type)11059ef1f84bSDavid du Colombier findipifc(Fs *f, uchar *remote, int type)
11069ef1f84bSDavid du Colombier {
11079ef1f84bSDavid du Colombier Ipifc *ifc, *x;
11089ef1f84bSDavid du Colombier Iplifc *lifc;
11099ef1f84bSDavid du Colombier Conv **cp, **e;
11109ef1f84bSDavid du Colombier uchar gnet[IPaddrlen], xmask[IPaddrlen];
11119ef1f84bSDavid du Colombier
11129ef1f84bSDavid du Colombier x = nil;
11139ef1f84bSDavid du Colombier memset(xmask, 0, IPaddrlen);
11149ef1f84bSDavid du Colombier
11159ef1f84bSDavid du Colombier /* find most specific match */
11169ef1f84bSDavid du Colombier e = &f->ipifc->conv[f->ipifc->nc];
11179ef1f84bSDavid du Colombier for(cp = f->ipifc->conv; cp < e; cp++){
11189ef1f84bSDavid du Colombier if(*cp == 0)
11199ef1f84bSDavid du Colombier continue;
11209ef1f84bSDavid du Colombier ifc = (Ipifc*)(*cp)->ptcl;
11219ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc; lifc = lifc->next){
11229ef1f84bSDavid du Colombier maskip(remote, lifc->mask, gnet);
11239ef1f84bSDavid du Colombier if(ipcmp(gnet, lifc->net) == 0){
11249ef1f84bSDavid du Colombier if(x == nil || ipcmp(lifc->mask, xmask) > 0){
11259ef1f84bSDavid du Colombier x = ifc;
11269ef1f84bSDavid du Colombier ipmove(xmask, lifc->mask);
11279ef1f84bSDavid du Colombier }
11289ef1f84bSDavid du Colombier }
11299ef1f84bSDavid du Colombier }
11309ef1f84bSDavid du Colombier }
11319ef1f84bSDavid du Colombier if(x != nil)
11329ef1f84bSDavid du Colombier return x;
11339ef1f84bSDavid du Colombier
11349ef1f84bSDavid du Colombier /* for now for broadcast and multicast, just use first interface */
11359ef1f84bSDavid du Colombier if(type & (Rbcast|Rmulti)){
11369ef1f84bSDavid du Colombier for(cp = f->ipifc->conv; cp < e; cp++){
11379ef1f84bSDavid du Colombier if(*cp == 0)
11389ef1f84bSDavid du Colombier continue;
11399ef1f84bSDavid du Colombier ifc = (Ipifc*)(*cp)->ptcl;
11409ef1f84bSDavid du Colombier if(ifc->lifc != nil)
11419ef1f84bSDavid du Colombier return ifc;
11429ef1f84bSDavid du Colombier }
11439ef1f84bSDavid du Colombier }
11449ef1f84bSDavid du Colombier return nil;
11459ef1f84bSDavid du Colombier }
11469ef1f84bSDavid du Colombier
11479ef1f84bSDavid du Colombier enum {
11489ef1f84bSDavid du Colombier unknownv6, /* UGH */
11499ef1f84bSDavid du Colombier // multicastv6,
11509ef1f84bSDavid du Colombier unspecifiedv6,
11519ef1f84bSDavid du Colombier linklocalv6,
11529ef1f84bSDavid du Colombier globalv6,
11539ef1f84bSDavid du Colombier };
11549ef1f84bSDavid du Colombier
11559ef1f84bSDavid du Colombier int
v6addrtype(uchar * addr)11569ef1f84bSDavid du Colombier v6addrtype(uchar *addr)
11579ef1f84bSDavid du Colombier {
11589ef1f84bSDavid du Colombier if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
11599ef1f84bSDavid du Colombier return unknownv6;
11609ef1f84bSDavid du Colombier else if(islinklocal(addr) ||
11619ef1f84bSDavid du Colombier isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
11629ef1f84bSDavid du Colombier return linklocalv6;
11639ef1f84bSDavid du Colombier else
11649ef1f84bSDavid du Colombier return globalv6;
11659ef1f84bSDavid du Colombier }
11669ef1f84bSDavid du Colombier
11679ef1f84bSDavid du Colombier #define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
11689ef1f84bSDavid du Colombier (lifc)->origint + (lifc)->preflt >= NOW/1000)
11699ef1f84bSDavid du Colombier
11709ef1f84bSDavid du Colombier static void
findprimaryipv6(Fs * f,uchar * local)11719ef1f84bSDavid du Colombier findprimaryipv6(Fs *f, uchar *local)
11729ef1f84bSDavid du Colombier {
11739ef1f84bSDavid du Colombier int atype, atypel;
11749ef1f84bSDavid du Colombier Conv **cp, **e;
11759ef1f84bSDavid du Colombier Ipifc *ifc;
11769ef1f84bSDavid du Colombier Iplifc *lifc;
11779ef1f84bSDavid du Colombier
11789ef1f84bSDavid du Colombier ipmove(local, v6Unspecified);
11799ef1f84bSDavid du Colombier atype = unspecifiedv6;
11809ef1f84bSDavid du Colombier
11819ef1f84bSDavid du Colombier /*
11829ef1f84bSDavid du Colombier * find "best" (global > link local > unspecified)
11839ef1f84bSDavid du Colombier * local address; address must be current.
11849ef1f84bSDavid du Colombier */
11859ef1f84bSDavid du Colombier e = &f->ipifc->conv[f->ipifc->nc];
11869ef1f84bSDavid du Colombier for(cp = f->ipifc->conv; cp < e; cp++){
11879ef1f84bSDavid du Colombier if(*cp == 0)
11889ef1f84bSDavid du Colombier continue;
11899ef1f84bSDavid du Colombier ifc = (Ipifc*)(*cp)->ptcl;
11909ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc; lifc = lifc->next){
11919ef1f84bSDavid du Colombier atypel = v6addrtype(lifc->local);
11929ef1f84bSDavid du Colombier if(atypel > atype && v6addrcurr(lifc)) {
11939ef1f84bSDavid du Colombier ipmove(local, lifc->local);
11949ef1f84bSDavid du Colombier atype = atypel;
11959ef1f84bSDavid du Colombier if(atype == globalv6)
11969ef1f84bSDavid du Colombier return;
11979ef1f84bSDavid du Colombier }
11989ef1f84bSDavid du Colombier }
11999ef1f84bSDavid du Colombier }
12009ef1f84bSDavid du Colombier }
12019ef1f84bSDavid du Colombier
12029ef1f84bSDavid du Colombier /*
12039ef1f84bSDavid du Colombier * returns first ip address configured
12049ef1f84bSDavid du Colombier */
12059ef1f84bSDavid du Colombier static void
findprimaryipv4(Fs * f,uchar * local)12069ef1f84bSDavid du Colombier findprimaryipv4(Fs *f, uchar *local)
12079ef1f84bSDavid du Colombier {
12089ef1f84bSDavid du Colombier Conv **cp, **e;
12099ef1f84bSDavid du Colombier Ipifc *ifc;
12109ef1f84bSDavid du Colombier Iplifc *lifc;
12119ef1f84bSDavid du Colombier
12129ef1f84bSDavid du Colombier /* find first ifc local address */
12139ef1f84bSDavid du Colombier e = &f->ipifc->conv[f->ipifc->nc];
12149ef1f84bSDavid du Colombier for(cp = f->ipifc->conv; cp < e; cp++){
12159ef1f84bSDavid du Colombier if(*cp == 0)
12169ef1f84bSDavid du Colombier continue;
12179ef1f84bSDavid du Colombier ifc = (Ipifc*)(*cp)->ptcl;
12189ef1f84bSDavid du Colombier if((lifc = ifc->lifc) != nil){
12199ef1f84bSDavid du Colombier ipmove(local, lifc->local);
12209ef1f84bSDavid du Colombier return;
12219ef1f84bSDavid du Colombier }
12229ef1f84bSDavid du Colombier }
12239ef1f84bSDavid du Colombier }
12249ef1f84bSDavid du Colombier
12259ef1f84bSDavid du Colombier /*
12269ef1f84bSDavid du Colombier * find the local address 'closest' to the remote system, copy it to
12279ef1f84bSDavid du Colombier * local and return the ifc for that address
12289ef1f84bSDavid du Colombier */
12299ef1f84bSDavid du Colombier void
findlocalip(Fs * f,uchar * local,uchar * remote)12309ef1f84bSDavid du Colombier findlocalip(Fs *f, uchar *local, uchar *remote)
12319ef1f84bSDavid du Colombier {
12329ef1f84bSDavid du Colombier int version, atype = unspecifiedv6, atypel = unknownv6;
12339ef1f84bSDavid du Colombier int atyper, deprecated;
12349ef1f84bSDavid du Colombier uchar gate[IPaddrlen], gnet[IPaddrlen];
12359ef1f84bSDavid du Colombier Ipifc *ifc;
12369ef1f84bSDavid du Colombier Iplifc *lifc;
12379ef1f84bSDavid du Colombier Route *r;
12389ef1f84bSDavid du Colombier
12399ef1f84bSDavid du Colombier USED(atype);
12409ef1f84bSDavid du Colombier USED(atypel);
12419ef1f84bSDavid du Colombier qlock(f->ipifc);
12429ef1f84bSDavid du Colombier r = v6lookup(f, remote, nil);
12439ef1f84bSDavid du Colombier version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6;
12449ef1f84bSDavid du Colombier
12459ef1f84bSDavid du Colombier if(r != nil){
12469ef1f84bSDavid du Colombier ifc = r->ifc;
12479ef1f84bSDavid du Colombier if(r->type & Rv4)
12489ef1f84bSDavid du Colombier v4tov6(gate, r->v4.gate);
12499ef1f84bSDavid du Colombier else {
12509ef1f84bSDavid du Colombier ipmove(gate, r->v6.gate);
12519ef1f84bSDavid du Colombier ipmove(local, v6Unspecified);
12529ef1f84bSDavid du Colombier }
12539ef1f84bSDavid du Colombier
12549ef1f84bSDavid du Colombier switch(version) {
12559ef1f84bSDavid du Colombier case V4:
12569ef1f84bSDavid du Colombier /* find ifc address closest to the gateway to use */
12579ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc; lifc = lifc->next){
12589ef1f84bSDavid du Colombier maskip(gate, lifc->mask, gnet);
12599ef1f84bSDavid du Colombier if(ipcmp(gnet, lifc->net) == 0){
12609ef1f84bSDavid du Colombier ipmove(local, lifc->local);
12619ef1f84bSDavid du Colombier goto out;
12629ef1f84bSDavid du Colombier }
12639ef1f84bSDavid du Colombier }
12649ef1f84bSDavid du Colombier break;
12659ef1f84bSDavid du Colombier case V6:
12669ef1f84bSDavid du Colombier /* find ifc address with scope matching the destination */
12679ef1f84bSDavid du Colombier atyper = v6addrtype(remote);
12689ef1f84bSDavid du Colombier deprecated = 0;
12699ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc; lifc = lifc->next){
12709ef1f84bSDavid du Colombier atypel = v6addrtype(lifc->local);
12719ef1f84bSDavid du Colombier /* prefer appropriate scope */
12729ef1f84bSDavid du Colombier if(atypel > atype && atype < atyper ||
12739ef1f84bSDavid du Colombier atypel < atype && atype > atyper){
12749ef1f84bSDavid du Colombier ipmove(local, lifc->local);
12759ef1f84bSDavid du Colombier deprecated = !v6addrcurr(lifc);
12769ef1f84bSDavid du Colombier atype = atypel;
12779ef1f84bSDavid du Colombier } else if(atypel == atype){
12789ef1f84bSDavid du Colombier /* avoid deprecated addresses */
12799ef1f84bSDavid du Colombier if(deprecated && v6addrcurr(lifc)){
12809ef1f84bSDavid du Colombier ipmove(local, lifc->local);
12819ef1f84bSDavid du Colombier atype = atypel;
12829ef1f84bSDavid du Colombier deprecated = 0;
12839ef1f84bSDavid du Colombier }
12849ef1f84bSDavid du Colombier }
12859ef1f84bSDavid du Colombier if(atype == atyper && !deprecated)
12869ef1f84bSDavid du Colombier goto out;
12879ef1f84bSDavid du Colombier }
12889ef1f84bSDavid du Colombier if(atype >= atyper)
12899ef1f84bSDavid du Colombier goto out;
12909ef1f84bSDavid du Colombier break;
12919ef1f84bSDavid du Colombier default:
12929ef1f84bSDavid du Colombier panic("findlocalip: version %d", version);
12939ef1f84bSDavid du Colombier }
12949ef1f84bSDavid du Colombier }
12959ef1f84bSDavid du Colombier
12969ef1f84bSDavid du Colombier switch(version){
12979ef1f84bSDavid du Colombier case V4:
12989ef1f84bSDavid du Colombier findprimaryipv4(f, local);
12999ef1f84bSDavid du Colombier break;
13009ef1f84bSDavid du Colombier case V6:
13019ef1f84bSDavid du Colombier findprimaryipv6(f, local);
13029ef1f84bSDavid du Colombier break;
13039ef1f84bSDavid du Colombier default:
13049ef1f84bSDavid du Colombier panic("findlocalip2: version %d", version);
13059ef1f84bSDavid du Colombier }
13069ef1f84bSDavid du Colombier
13079ef1f84bSDavid du Colombier out:
13089ef1f84bSDavid du Colombier qunlock(f->ipifc);
13099ef1f84bSDavid du Colombier }
13109ef1f84bSDavid du Colombier
13119ef1f84bSDavid du Colombier /*
13129ef1f84bSDavid du Colombier * return first v4 address associated with an interface
13139ef1f84bSDavid du Colombier */
13149ef1f84bSDavid du Colombier int
ipv4local(Ipifc * ifc,uchar * addr)13159ef1f84bSDavid du Colombier ipv4local(Ipifc *ifc, uchar *addr)
13169ef1f84bSDavid du Colombier {
13179ef1f84bSDavid du Colombier Iplifc *lifc;
13189ef1f84bSDavid du Colombier
13199ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc; lifc = lifc->next){
13209ef1f84bSDavid du Colombier if(isv4(lifc->local)){
13219ef1f84bSDavid du Colombier memmove(addr, lifc->local+IPv4off, IPv4addrlen);
13229ef1f84bSDavid du Colombier return 1;
13239ef1f84bSDavid du Colombier }
13249ef1f84bSDavid du Colombier }
13259ef1f84bSDavid du Colombier return 0;
13269ef1f84bSDavid du Colombier }
13279ef1f84bSDavid du Colombier
13289ef1f84bSDavid du Colombier /*
13299ef1f84bSDavid du Colombier * return first v6 address associated with an interface
13309ef1f84bSDavid du Colombier */
13319ef1f84bSDavid du Colombier int
ipv6local(Ipifc * ifc,uchar * addr)13329ef1f84bSDavid du Colombier ipv6local(Ipifc *ifc, uchar *addr)
13339ef1f84bSDavid du Colombier {
13349ef1f84bSDavid du Colombier Iplifc *lifc;
13359ef1f84bSDavid du Colombier
13369ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc; lifc = lifc->next){
13379ef1f84bSDavid du Colombier if(!isv4(lifc->local) && !(lifc->tentative)){
13389ef1f84bSDavid du Colombier ipmove(addr, lifc->local);
13399ef1f84bSDavid du Colombier return 1;
13409ef1f84bSDavid du Colombier }
13419ef1f84bSDavid du Colombier }
13429ef1f84bSDavid du Colombier return 0;
13439ef1f84bSDavid du Colombier }
13449ef1f84bSDavid du Colombier
13459ef1f84bSDavid du Colombier int
ipv6anylocal(Ipifc * ifc,uchar * addr)13469ef1f84bSDavid du Colombier ipv6anylocal(Ipifc *ifc, uchar *addr)
13479ef1f84bSDavid du Colombier {
13489ef1f84bSDavid du Colombier Iplifc *lifc;
13499ef1f84bSDavid du Colombier
13509ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc; lifc = lifc->next){
13519ef1f84bSDavid du Colombier if(!isv4(lifc->local)){
13529ef1f84bSDavid du Colombier ipmove(addr, lifc->local);
13539ef1f84bSDavid du Colombier return SRC_UNI;
13549ef1f84bSDavid du Colombier }
13559ef1f84bSDavid du Colombier }
13569ef1f84bSDavid du Colombier return SRC_UNSPEC;
13579ef1f84bSDavid du Colombier }
13589ef1f84bSDavid du Colombier
13599ef1f84bSDavid du Colombier /*
13609ef1f84bSDavid du Colombier * see if this address is bound to the interface
13619ef1f84bSDavid du Colombier */
13629ef1f84bSDavid du Colombier Iplifc*
iplocalonifc(Ipifc * ifc,uchar * ip)13639ef1f84bSDavid du Colombier iplocalonifc(Ipifc *ifc, uchar *ip)
13649ef1f84bSDavid du Colombier {
13659ef1f84bSDavid du Colombier Iplifc *lifc;
13669ef1f84bSDavid du Colombier
13679ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc; lifc = lifc->next)
13689ef1f84bSDavid du Colombier if(ipcmp(ip, lifc->local) == 0)
13699ef1f84bSDavid du Colombier return lifc;
13709ef1f84bSDavid du Colombier return nil;
13719ef1f84bSDavid du Colombier }
13729ef1f84bSDavid du Colombier
13739ef1f84bSDavid du Colombier
13749ef1f84bSDavid du Colombier /*
13759ef1f84bSDavid du Colombier * See if we're proxying for this address on this interface
13769ef1f84bSDavid du Colombier */
13779ef1f84bSDavid du Colombier int
ipproxyifc(Fs * f,Ipifc * ifc,uchar * ip)13789ef1f84bSDavid du Colombier ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
13799ef1f84bSDavid du Colombier {
13809ef1f84bSDavid du Colombier Route *r;
13819ef1f84bSDavid du Colombier uchar net[IPaddrlen];
13829ef1f84bSDavid du Colombier Iplifc *lifc;
13839ef1f84bSDavid du Colombier
13849ef1f84bSDavid du Colombier /* see if this is a direct connected pt to pt address */
13859ef1f84bSDavid du Colombier r = v6lookup(f, ip, nil);
13869ef1f84bSDavid du Colombier if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
13879ef1f84bSDavid du Colombier return 0;
13889ef1f84bSDavid du Colombier
13899ef1f84bSDavid du Colombier /* see if this is on the right interface */
13909ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc; lifc = lifc->next){
13919ef1f84bSDavid du Colombier maskip(ip, lifc->mask, net);
13929ef1f84bSDavid du Colombier if(ipcmp(net, lifc->remote) == 0)
13939ef1f84bSDavid du Colombier return 1;
13949ef1f84bSDavid du Colombier }
13959ef1f84bSDavid du Colombier return 0;
13969ef1f84bSDavid du Colombier }
13979ef1f84bSDavid du Colombier
13989ef1f84bSDavid du Colombier /*
13999ef1f84bSDavid du Colombier * return multicast version if any
14009ef1f84bSDavid du Colombier */
14019ef1f84bSDavid du Colombier int
ipismulticast(uchar * ip)14029ef1f84bSDavid du Colombier ipismulticast(uchar *ip)
14039ef1f84bSDavid du Colombier {
14049ef1f84bSDavid du Colombier if(isv4(ip)){
14059ef1f84bSDavid du Colombier if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
14069ef1f84bSDavid du Colombier return V4;
14079ef1f84bSDavid du Colombier }
14089ef1f84bSDavid du Colombier else if(ip[0] == 0xff)
14099ef1f84bSDavid du Colombier return V6;
14109ef1f84bSDavid du Colombier return 0;
14119ef1f84bSDavid du Colombier }
14129ef1f84bSDavid du Colombier int
ipisbm(uchar * ip)14139ef1f84bSDavid du Colombier ipisbm(uchar *ip)
14149ef1f84bSDavid du Colombier {
14159ef1f84bSDavid du Colombier if(isv4(ip)){
14169ef1f84bSDavid du Colombier if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
14179ef1f84bSDavid du Colombier return V4;
14189ef1f84bSDavid du Colombier else if(ipcmp(ip, IPv4bcast) == 0)
14199ef1f84bSDavid du Colombier return V4;
14209ef1f84bSDavid du Colombier }
14219ef1f84bSDavid du Colombier else if(ip[0] == 0xff)
14229ef1f84bSDavid du Colombier return V6;
14239ef1f84bSDavid du Colombier return 0;
14249ef1f84bSDavid du Colombier }
14259ef1f84bSDavid du Colombier
14269ef1f84bSDavid du Colombier
14279ef1f84bSDavid du Colombier /*
14289ef1f84bSDavid du Colombier * add a multicast address to an interface, called with c->car locked
14299ef1f84bSDavid du Colombier */
14309ef1f84bSDavid du Colombier void
ipifcaddmulti(Conv * c,uchar * ma,uchar * ia)14319ef1f84bSDavid du Colombier ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
14329ef1f84bSDavid du Colombier {
14339ef1f84bSDavid du Colombier Ipifc *ifc;
14349ef1f84bSDavid du Colombier Iplifc *lifc;
14359ef1f84bSDavid du Colombier Conv **p;
14369ef1f84bSDavid du Colombier Ipmulti *multi, **l;
14379ef1f84bSDavid du Colombier Fs *f;
14389ef1f84bSDavid du Colombier
14399ef1f84bSDavid du Colombier f = c->p->f;
14409ef1f84bSDavid du Colombier
14419ef1f84bSDavid du Colombier for(l = &c->multi; *l; l = &(*l)->next)
14429ef1f84bSDavid du Colombier if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
14439ef1f84bSDavid du Colombier return; /* it's already there */
14449ef1f84bSDavid du Colombier
14459ef1f84bSDavid du Colombier multi = *l = smalloc(sizeof(*multi));
14469ef1f84bSDavid du Colombier ipmove(multi->ma, ma);
14479ef1f84bSDavid du Colombier ipmove(multi->ia, ia);
14489ef1f84bSDavid du Colombier multi->next = nil;
14499ef1f84bSDavid du Colombier
14509ef1f84bSDavid du Colombier for(p = f->ipifc->conv; *p; p++){
14519ef1f84bSDavid du Colombier if((*p)->inuse == 0)
14529ef1f84bSDavid du Colombier continue;
14539ef1f84bSDavid du Colombier ifc = (Ipifc*)(*p)->ptcl;
14549ef1f84bSDavid du Colombier if(waserror()){
14559ef1f84bSDavid du Colombier wunlock(ifc);
14569ef1f84bSDavid du Colombier nexterror();
14579ef1f84bSDavid du Colombier }
14589ef1f84bSDavid du Colombier wlock(ifc);
14599ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc; lifc = lifc->next)
14609ef1f84bSDavid du Colombier if(ipcmp(ia, lifc->local) == 0)
14619ef1f84bSDavid du Colombier addselfcache(f, ifc, lifc, ma, Rmulti);
14629ef1f84bSDavid du Colombier wunlock(ifc);
14639ef1f84bSDavid du Colombier poperror();
14649ef1f84bSDavid du Colombier }
14659ef1f84bSDavid du Colombier }
14669ef1f84bSDavid du Colombier
14679ef1f84bSDavid du Colombier
14689ef1f84bSDavid du Colombier /*
14699ef1f84bSDavid du Colombier * remove a multicast address from an interface, called with c->car locked
14709ef1f84bSDavid du Colombier */
14719ef1f84bSDavid du Colombier void
ipifcremmulti(Conv * c,uchar * ma,uchar * ia)14729ef1f84bSDavid du Colombier ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
14739ef1f84bSDavid du Colombier {
14749ef1f84bSDavid du Colombier Ipmulti *multi, **l;
14759ef1f84bSDavid du Colombier Iplifc *lifc;
14769ef1f84bSDavid du Colombier Conv **p;
14779ef1f84bSDavid du Colombier Ipifc *ifc;
14789ef1f84bSDavid du Colombier Fs *f;
14799ef1f84bSDavid du Colombier
14809ef1f84bSDavid du Colombier f = c->p->f;
14819ef1f84bSDavid du Colombier
14829ef1f84bSDavid du Colombier for(l = &c->multi; *l; l = &(*l)->next)
14839ef1f84bSDavid du Colombier if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
14849ef1f84bSDavid du Colombier break;
14859ef1f84bSDavid du Colombier
14869ef1f84bSDavid du Colombier multi = *l;
14879ef1f84bSDavid du Colombier if(multi == nil)
14889ef1f84bSDavid du Colombier return; /* we don't have it open */
14899ef1f84bSDavid du Colombier
14909ef1f84bSDavid du Colombier *l = multi->next;
14919ef1f84bSDavid du Colombier
14929ef1f84bSDavid du Colombier for(p = f->ipifc->conv; *p; p++){
14939ef1f84bSDavid du Colombier if((*p)->inuse == 0)
14949ef1f84bSDavid du Colombier continue;
14959ef1f84bSDavid du Colombier
14969ef1f84bSDavid du Colombier ifc = (Ipifc*)(*p)->ptcl;
14979ef1f84bSDavid du Colombier if(waserror()){
14989ef1f84bSDavid du Colombier wunlock(ifc);
14999ef1f84bSDavid du Colombier nexterror();
15009ef1f84bSDavid du Colombier }
15019ef1f84bSDavid du Colombier wlock(ifc);
15029ef1f84bSDavid du Colombier for(lifc = ifc->lifc; lifc; lifc = lifc->next)
15039ef1f84bSDavid du Colombier if(ipcmp(ia, lifc->local) == 0)
15049ef1f84bSDavid du Colombier remselfcache(f, ifc, lifc, ma);
15059ef1f84bSDavid du Colombier wunlock(ifc);
15069ef1f84bSDavid du Colombier poperror();
15079ef1f84bSDavid du Colombier }
15089ef1f84bSDavid du Colombier
15099ef1f84bSDavid du Colombier free(multi);
15109ef1f84bSDavid du Colombier }
15119ef1f84bSDavid du Colombier
15129ef1f84bSDavid du Colombier /*
15139ef1f84bSDavid du Colombier * make lifc's join and leave multicast groups
15149ef1f84bSDavid du Colombier */
15159ef1f84bSDavid du Colombier static char*
ipifcjoinmulti(Ipifc * ifc,char ** argv,int argc)15169ef1f84bSDavid du Colombier ipifcjoinmulti(Ipifc *ifc, char **argv, int argc)
15179ef1f84bSDavid du Colombier {
15189ef1f84bSDavid du Colombier USED(ifc, argv, argc);
15199ef1f84bSDavid du Colombier return nil;
15209ef1f84bSDavid du Colombier }
15219ef1f84bSDavid du Colombier
15229ef1f84bSDavid du Colombier static char*
ipifcleavemulti(Ipifc * ifc,char ** argv,int argc)15239ef1f84bSDavid du Colombier ipifcleavemulti(Ipifc *ifc, char **argv, int argc)
15249ef1f84bSDavid du Colombier {
15259ef1f84bSDavid du Colombier USED(ifc, argv, argc);
15269ef1f84bSDavid du Colombier return nil;
15279ef1f84bSDavid du Colombier }
15289ef1f84bSDavid du Colombier
15299ef1f84bSDavid du Colombier static void
ipifcregisterproxy(Fs * f,Ipifc * ifc,uchar * ip)15309ef1f84bSDavid du Colombier ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
15319ef1f84bSDavid du Colombier {
15329ef1f84bSDavid du Colombier Conv **cp, **e;
15339ef1f84bSDavid du Colombier Ipifc *nifc;
15349ef1f84bSDavid du Colombier Iplifc *lifc;
15359ef1f84bSDavid du Colombier Medium *medium;
15369ef1f84bSDavid du Colombier uchar net[IPaddrlen];
15379ef1f84bSDavid du Colombier
15389ef1f84bSDavid du Colombier /* register the address on any network that will proxy for us */
15399ef1f84bSDavid du Colombier e = &f->ipifc->conv[f->ipifc->nc];
15409ef1f84bSDavid du Colombier
15419ef1f84bSDavid du Colombier if(!isv4(ip)) { /* V6 */
15429ef1f84bSDavid du Colombier for(cp = f->ipifc->conv; cp < e; cp++){
15439ef1f84bSDavid du Colombier if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
15449ef1f84bSDavid du Colombier continue;
15459ef1f84bSDavid du Colombier rlock(nifc);
15469ef1f84bSDavid du Colombier medium = nifc->medium;
15479ef1f84bSDavid du Colombier if(medium == nil || medium->addmulti == nil) {
15489ef1f84bSDavid du Colombier runlock(nifc);
15499ef1f84bSDavid du Colombier continue;
15509ef1f84bSDavid du Colombier }
15519ef1f84bSDavid du Colombier for(lifc = nifc->lifc; lifc; lifc = lifc->next){
15529ef1f84bSDavid du Colombier maskip(ip, lifc->mask, net);
15539ef1f84bSDavid du Colombier if(ipcmp(net, lifc->remote) == 0) {
15549ef1f84bSDavid du Colombier /* add solicited-node multicast addr */
15559ef1f84bSDavid du Colombier ipv62smcast(net, ip);
15569ef1f84bSDavid du Colombier addselfcache(f, nifc, lifc, net, Rmulti);
15579ef1f84bSDavid du Colombier arpenter(f, V6, ip, nifc->mac, 6, 0);
15589ef1f84bSDavid du Colombier // (*medium->addmulti)(nifc, net, ip);
15599ef1f84bSDavid du Colombier break;
15609ef1f84bSDavid du Colombier }
15619ef1f84bSDavid du Colombier }
15629ef1f84bSDavid du Colombier runlock(nifc);
15639ef1f84bSDavid du Colombier }
15649ef1f84bSDavid du Colombier }
15659ef1f84bSDavid du Colombier else { /* V4 */
15669ef1f84bSDavid du Colombier for(cp = f->ipifc->conv; cp < e; cp++){
15679ef1f84bSDavid du Colombier if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
15689ef1f84bSDavid du Colombier continue;
15699ef1f84bSDavid du Colombier rlock(nifc);
15709ef1f84bSDavid du Colombier medium = nifc->medium;
15719ef1f84bSDavid du Colombier if(medium == nil || medium->areg == nil){
15729ef1f84bSDavid du Colombier runlock(nifc);
15739ef1f84bSDavid du Colombier continue;
15749ef1f84bSDavid du Colombier }
15759ef1f84bSDavid du Colombier for(lifc = nifc->lifc; lifc; lifc = lifc->next){
15769ef1f84bSDavid du Colombier maskip(ip, lifc->mask, net);
15779ef1f84bSDavid du Colombier if(ipcmp(net, lifc->remote) == 0){
15789ef1f84bSDavid du Colombier (*medium->areg)(nifc, ip);
15799ef1f84bSDavid du Colombier break;
15809ef1f84bSDavid du Colombier }
15819ef1f84bSDavid du Colombier }
15829ef1f84bSDavid du Colombier runlock(nifc);
15839ef1f84bSDavid du Colombier }
15849ef1f84bSDavid du Colombier }
15859ef1f84bSDavid du Colombier }
15869ef1f84bSDavid du Colombier
15879ef1f84bSDavid du Colombier
15889ef1f84bSDavid du Colombier /* added for new v6 mesg types */
15899ef1f84bSDavid du Colombier static void
adddefroute6(Fs * f,uchar * gate,int force)15909ef1f84bSDavid du Colombier adddefroute6(Fs *f, uchar *gate, int force)
15919ef1f84bSDavid du Colombier {
15929ef1f84bSDavid du Colombier Route *r;
15939ef1f84bSDavid du Colombier
15949ef1f84bSDavid du Colombier r = v6lookup(f, v6Unspecified, nil);
15959ef1f84bSDavid du Colombier /*
15969ef1f84bSDavid du Colombier * route entries generated by all other means take precedence
15979ef1f84bSDavid du Colombier * over router announcements.
15989ef1f84bSDavid du Colombier */
15999ef1f84bSDavid du Colombier if (r && !force && strcmp(r->tag, "ra") != 0)
16009ef1f84bSDavid du Colombier return;
16019ef1f84bSDavid du Colombier
16029ef1f84bSDavid du Colombier v6delroute(f, v6Unspecified, v6Unspecified, 1);
16039ef1f84bSDavid du Colombier v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
16049ef1f84bSDavid du Colombier }
16059ef1f84bSDavid du Colombier
16069ef1f84bSDavid du Colombier enum {
16079ef1f84bSDavid du Colombier Ngates = 3,
16089ef1f84bSDavid du Colombier };
16099ef1f84bSDavid du Colombier
16109ef1f84bSDavid du Colombier char*
ipifcadd6(Ipifc * ifc,char ** argv,int argc)16119ef1f84bSDavid du Colombier ipifcadd6(Ipifc *ifc, char**argv, int argc)
16129ef1f84bSDavid du Colombier {
16139ef1f84bSDavid du Colombier int plen = 64;
16149ef1f84bSDavid du Colombier long origint = NOW / 1000, preflt = ~0L, validlt = ~0L;
1615*a3323688SDavid du Colombier char addr[Maxv6repr], preflen[6];
16169ef1f84bSDavid du Colombier char *params[3];
16179ef1f84bSDavid du Colombier uchar autoflag = 1, onlink = 1;
16189ef1f84bSDavid du Colombier uchar prefix[IPaddrlen];
16199ef1f84bSDavid du Colombier Iplifc *lifc;
16209ef1f84bSDavid du Colombier
16219ef1f84bSDavid du Colombier switch(argc) {
16229ef1f84bSDavid du Colombier case 7:
16239ef1f84bSDavid du Colombier preflt = atoi(argv[6]);
16249ef1f84bSDavid du Colombier /* fall through */
16259ef1f84bSDavid du Colombier case 6:
16269ef1f84bSDavid du Colombier validlt = atoi(argv[5]);
16279ef1f84bSDavid du Colombier /* fall through */
16289ef1f84bSDavid du Colombier case 5:
16299ef1f84bSDavid du Colombier autoflag = atoi(argv[4]);
16309ef1f84bSDavid du Colombier /* fall through */
16319ef1f84bSDavid du Colombier case 4:
16329ef1f84bSDavid du Colombier onlink = atoi(argv[3]);
16339ef1f84bSDavid du Colombier /* fall through */
16349ef1f84bSDavid du Colombier case 3:
16359ef1f84bSDavid du Colombier plen = atoi(argv[2]);
16369ef1f84bSDavid du Colombier /* fall through */
16379ef1f84bSDavid du Colombier case 2:
16389ef1f84bSDavid du Colombier break;
16399ef1f84bSDavid du Colombier default:
16409ef1f84bSDavid du Colombier return Ebadarg;
16419ef1f84bSDavid du Colombier }
16429ef1f84bSDavid du Colombier
1643*a3323688SDavid du Colombier if (parseip(prefix, argv[1]) != 6)
1644*a3323688SDavid du Colombier return "bad ipv6 address";
1645*a3323688SDavid du Colombier if (validlt < preflt)
1646*a3323688SDavid du Colombier return "valid ipv6 lifetime less than preferred lifetime";
1647*a3323688SDavid du Colombier if (plen < 0)
1648*a3323688SDavid du Colombier return "negative ipv6 prefix length";
1649*a3323688SDavid du Colombier /* i think that this length limit is bogus - geoff */
1650*a3323688SDavid du Colombier // if (plen > 64)
1651*a3323688SDavid du Colombier // return "ipv6 prefix length greater than 64;
1652*a3323688SDavid du Colombier if (islinklocal(prefix))
1653*a3323688SDavid du Colombier return "ipv6 prefix is link-local";
16549ef1f84bSDavid du Colombier
16559ef1f84bSDavid du Colombier lifc = smalloc(sizeof(Iplifc));
16569ef1f84bSDavid du Colombier lifc->onlink = (onlink != 0);
16579ef1f84bSDavid du Colombier lifc->autoflag = (autoflag != 0);
16589ef1f84bSDavid du Colombier lifc->validlt = validlt;
16599ef1f84bSDavid du Colombier lifc->preflt = preflt;
16609ef1f84bSDavid du Colombier lifc->origint = origint;
16619ef1f84bSDavid du Colombier
16629ef1f84bSDavid du Colombier /* issue "add" ctl msg for v6 link-local addr and prefix len */
16639ef1f84bSDavid du Colombier if(!ifc->medium->pref2addr)
1664*a3323688SDavid du Colombier return "no pref2addr on interface";
16659ef1f84bSDavid du Colombier ifc->medium->pref2addr(prefix, ifc->mac); /* mac → v6 link-local addr */
1666*a3323688SDavid du Colombier snprint(addr, sizeof addr, "%I", prefix);
1667*a3323688SDavid du Colombier snprint(preflen, sizeof preflen, "/%d", plen);
16689ef1f84bSDavid du Colombier params[0] = "add";
16699ef1f84bSDavid du Colombier params[1] = addr;
16709ef1f84bSDavid du Colombier params[2] = preflen;
16719ef1f84bSDavid du Colombier
16729ef1f84bSDavid du Colombier return ipifcadd(ifc, params, 3, 0, lifc);
16739ef1f84bSDavid du Colombier }
1674