2 #include "../port/lib.h"
6 #include "../port/error.h"
11 #define DPRINT if(0)print
21 Medium *media[Maxmedia] = { 0 };
24 * cache of local addresses (addresses we answer to)
29 Ipself *hnext; /* next address in the hash table */
30 Iplink *link; /* binding twixt Ipself and Ipifc */
32 uchar type; /* type of address */
34 Ipself *next; /* free list */
41 int acceptall; /* true if an interface has the null address */
42 Ipself *hash[NHASH]; /* hash chains */
46 * Multicast addresses are chained onto a Chan so that
47 * we can remove them when the Chan is closed.
49 typedef struct Ipmcast Ipmcast;
53 uchar ma[IPaddrlen]; /* multicast address */
54 uchar ia[IPaddrlen]; /* interface address */
57 /* quick hash for ip addresses */
58 #define hashipa(a) ( ( ((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1] )%NHASH )
60 static char tifc[] = "ifc ";
62 static void addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
63 static void remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
64 static char* ipifcjoinmulti(Ipifc *ifc, char **argv, int argc);
65 static char* ipifcleavemulti(Ipifc *ifc, char **argv, int argc);
66 static void ipifcregisterproxy(Fs*, Ipifc*, uchar*);
67 static char* ipifcremlifc(Ipifc*, Iplifc*);
70 * link in a new medium
73 addipmedium(Medium *med)
77 for(i = 0; i < nelem(media)-1; i++)
85 * find the medium with this name
88 ipfindmedium(char *name)
92 for(mp = media; *mp != nil; mp++)
93 if(strcmp((*mp)->name, name) == 0)
99 * attach a device (or pkt driver) to the interface.
100 * called with c locked
103 ipifcbind(Conv *c, char **argv, int argc)
111 ifc = (Ipifc*)c->ptcl;
113 /* bind the device to the interface */
114 m = ipfindmedium(argv[1]);
116 return "unknown interface type";
121 return "interface already bound";
128 /* do medium specific binding */
129 (*m->bind)(ifc, argc, argv);
131 /* set the bound device name */
133 strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
135 snprint(ifc->dev, sizeof ifc->dev, "%s%d", m->name, c->x);
136 ifc->dev[sizeof(ifc->dev)-1] = 0;
138 /* set up parameters */
140 ifc->mintu = ifc->m->mintu;
141 ifc->maxtu = ifc->m->maxtu;
142 if(ifc->m->unbindonclose == 0)
144 ifc->rp.mflag = 0; /* default not managed */
146 ifc->rp.maxraint = 600000; /* millisecs */
147 ifc->rp.minraint = 200000;
148 ifc->rp.linkmtu = 0; /* no mtu sent */
149 ifc->rp.reachtime = 0;
151 ifc->rp.ttl = MAXTTL;
152 ifc->rp.routerlt = 3 * ifc->rp.maxraint;
154 /* any ancillary structures (like routes) no longer pertain */
157 /* reopen all the queues closed by a previous unbind */
169 * detach a device from an interface, close the interface
170 * called with ifc->conv closed
173 ipifcunbind(Ipifc *ifc)
183 /* disassociate logical interfaces (before zeroing ifc->arg) */
185 err = ipifcremlifc(ifc, ifc->lifc);
187 * note: err non-zero means lifc not found,
188 * which can't happen in this case.
194 /* disassociate device */
195 if(ifc->m && ifc->m->unbind)
196 (*ifc->m->unbind)(ifc);
197 memset(ifc->dev, 0, sizeof(ifc->dev));
201 /* close queues to stop queuing of packets */
202 qclose(ifc->conv->rq);
203 qclose(ifc->conv->wq);
204 qclose(ifc->conv->sq);
206 /* dissociate routes */
208 if(ifc->m != nil && ifc->m->unbindonclose == 0)
217 char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag"
218 " %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt"
219 " %d pktin %lud pktout %lud errin %lud errout %lud\n";
221 char slineformat[] = " %-40I %-10M %-40I %-12lud %-12lud\n";
224 ipifcstate(Conv *c, char *state, int n)
230 ifc = (Ipifc*)c->ptcl;
231 m = snprint(state, n, sfixedformat,
232 ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
233 ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
234 ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
235 ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
236 ifc->in, ifc->out, ifc->inerr, ifc->outerr);
239 for(lifc = ifc->lifc; lifc && n > m; lifc = lifc->next)
240 m += snprint(state+m, n - m, slineformat, lifc->local,
241 lifc->mask, lifc->remote, lifc->validlt, lifc->preflt);
243 m += snprint(state+m, n - m, "\n");
249 ipifclocal(Conv *c, char *state, int n)
256 ifc = (Ipifc*)c->ptcl;
260 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
261 m += snprint(state+m, n - m, "%-40.40I ->", lifc->local);
262 for(link = lifc->link; link; link = link->lifclink)
263 m += snprint(state+m, n - m, " %-40.40I", link->self->a);
264 m += snprint(state+m, n - m, "\n");
275 ifc = (Ipifc*)c->ptcl;
276 return ifc->m != nil;
280 * called when a process writes to an interface's 'data'
293 ifc = (Ipifc*)c->ptcl;
302 if(ifc->m && ifc->m->pktin)
303 (*ifc->m->pktin)(c->p->f, ifc, bp);
311 * called when a new ipifc structure is created
318 c->rq = qopen(QMAX, 0, 0, 0);
319 c->wq = qopen(QMAX, Qkick, ipifckick, c);
320 c->sq = qopen(QMAX, 0, 0, 0);
321 if(c->rq == nil || c->wq == nil || c->sq == nil)
323 ifc = (Ipifc*)c->ptcl;
331 * called after last close of ipifc data or ctl
332 * called with c locked, we must unlock
340 ifc = (Ipifc*)c->ptcl;
342 if(m && m->unbindonclose)
347 * change an interface's mtu
350 ipifcsetmtu(Ipifc *ifc, char **argv, int argc)
354 if(argc < 2 || ifc->m == nil)
356 mtu = strtoul(argv[1], 0, 0);
357 if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu)
364 * add an address to an interface.
367 ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
369 int i, type, mtu, sendnbrdisc = 0;
370 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
371 uchar bcast[IPaddrlen], net[IPaddrlen];
376 return "ipifc not yet bound to device";
381 memset(ip, 0, IPaddrlen);
382 memset(mask, 0, IPaddrlen);
383 memset(rem, 0, IPaddrlen);
386 if(strcmp(argv[5], "proxy") == 0)
390 mtu = strtoul(argv[4], 0, 0);
391 if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
395 if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1)
397 parseipmask(mask, argv[2]);
398 maskip(rem, mask, net);
401 if (parseip(ip, argv[1]) == -1)
403 parseipmask(mask, argv[2]);
404 maskip(ip, mask, rem);
405 maskip(rem, mask, net);
408 if (parseip(ip, argv[1]) == -1)
410 memmove(mask, defmask(ip), IPaddrlen);
411 maskip(ip, mask, rem);
412 maskip(rem, mask, net);
426 /* ignore if this is already a local address for this ifc */
427 for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
428 if(ipcmp(lifc->local, ip) == 0) {
429 if(lifc->tentative != tentative)
430 lifc->tentative = tentative;
432 lifc->onlink = lifcp->onlink;
433 lifc->autoflag = lifcp->autoflag;
434 lifc->validlt = lifcp->validlt;
435 lifc->preflt = lifcp->preflt;
436 lifc->origint = lifcp->origint;
442 /* add the address to the list of logical ifc's for this ifc */
443 lifc = smalloc(sizeof(Iplifc));
444 ipmove(lifc->local, ip);
445 ipmove(lifc->mask, mask);
446 ipmove(lifc->remote, rem);
447 ipmove(lifc->net, net);
448 lifc->tentative = tentative;
450 lifc->onlink = lifcp->onlink;
451 lifc->autoflag = lifcp->autoflag;
452 lifc->validlt = lifcp->validlt;
453 lifc->preflt = lifcp->preflt;
454 lifc->origint = lifcp->origint;
455 } else { /* default values */
456 lifc->onlink = lifc->autoflag = 1;
457 lifc->validlt = lifc->preflt = ~0L;
458 lifc->origint = NOW / 1000;
462 for(l = &ifc->lifc; *l; l = &(*l)->next)
466 /* check for point-to-point interface */
467 if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */
468 if(ipcmp(mask, IPallbits) == 0)
471 /* add local routes */
473 v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
475 v6addroute(f, tifc, rem, mask, rem, type);
477 addselfcache(f, ifc, lifc, ip, Runi);
479 if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){
480 ipifcregisterproxy(f, ifc, rem);
484 if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
485 /* add subnet directed broadcast address to the self cache */
486 for(i = 0; i < IPaddrlen; i++)
487 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
488 addselfcache(f, ifc, lifc, bcast, Rbcast);
490 /* add subnet directed network address to the self cache */
491 for(i = 0; i < IPaddrlen; i++)
492 bcast[i] = (ip[i] & mask[i]) & mask[i];
493 addselfcache(f, ifc, lifc, bcast, Rbcast);
495 /* add network directed broadcast address to the self cache */
496 memmove(mask, defmask(ip), IPaddrlen);
497 for(i = 0; i < IPaddrlen; i++)
498 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
499 addselfcache(f, ifc, lifc, bcast, Rbcast);
501 /* add network directed network address to the self cache */
502 memmove(mask, defmask(ip), IPaddrlen);
503 for(i = 0; i < IPaddrlen; i++)
504 bcast[i] = (ip[i] & mask[i]) & mask[i];
505 addselfcache(f, ifc, lifc, bcast, Rbcast);
507 addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
510 if(ipcmp(ip, v6loopback) == 0) {
511 /* add node-local mcast address */
512 addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
514 /* add route for all node multicast */
515 v6addroute(f, tifc, v6allnodesN, v6allnodesNmask,
516 v6allnodesN, Rmulti);
519 /* add all nodes multicast address */
520 addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
522 /* add route for all nodes multicast */
523 v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL,
526 /* add solicited-node multicast address */
527 ipv62smcast(bcast, ip);
528 addselfcache(f, ifc, lifc, bcast, Rmulti);
533 /* register the address on this network for address resolution */
534 if(isv4(ip) && ifc->m->areg)
535 (*ifc->m->areg)(ifc, ip);
541 if(!isv4(ip) && ipcmp(ip, IPnoaddr) != 0){
543 arpenter(f, V6, ip, ifc->mac, 6, 0);
545 icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
552 * remove a logical interface from an ifc
553 * always called with ifc wlock'd
556 ipifcremlifc(Ipifc *ifc, Iplifc *lifc)
564 * find address on this interface and remove from chain.
565 * for pt to pt we actually specify the remote address as the
566 * addresss to remove.
568 for(l = &ifc->lifc; *l != nil && *l != lifc; l = &(*l)->next)
571 return "address not on this interface";
574 /* disassociate any addresses */
576 remselfcache(f, ifc, lifc, lifc->link->self->a);
578 /* remove the route for this logical interface */
579 if(isv4(lifc->local))
580 v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);
582 v6delroute(f, lifc->remote, lifc->mask, 1);
583 if(ipcmp(lifc->local, v6loopback) == 0)
584 /* remove route for all node multicast */
585 v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
586 else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0)
587 /* remove route for all link multicast */
588 v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
596 * remove an address from an interface.
597 * called with c->car locked
600 ipifcrem(Ipifc *ifc, char **argv, int argc)
603 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
609 if (parseip(ip, argv[1]) == -1)
611 parseipmask(mask, argv[2]);
613 maskip(ip, mask, rem);
615 if (parseip(rem, argv[3]) == -1)
619 * find address on this interface and remove from chain.
620 * for pt to pt we actually specify the remote address as the
621 * addresss to remove.
624 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
625 if (memcmp(ip, lifc->local, IPaddrlen) == 0
626 && memcmp(mask, lifc->mask, IPaddrlen) == 0
627 && memcmp(rem, lifc->remote, IPaddrlen) == 0)
630 rv = ipifcremlifc(ifc, lifc);
636 * distribute routes to active interfaces like the
640 ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type)
646 e = &f->ipifc->conv[f->ipifc->nc];
647 for(cp = f->ipifc->conv; cp < e; cp++){
649 ifc = (Ipifc*)(*cp)->ptcl;
652 (*m->addroute)(ifc, vers, addr, mask, gate, type);
658 ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask)
664 e = &f->ipifc->conv[f->ipifc->nc];
665 for(cp = f->ipifc->conv; cp < e; cp++){
667 ifc = (Ipifc*)(*cp)->ptcl;
669 if(m && m->remroute){
671 (*m->remroute)(ifc, vers, addr, mask);
680 * associate an address with the interface. This wipes out any previous
681 * addresses. This is a macro that means, remove all the old interfaces
685 ipifcconnect(Conv* c, char **argv, int argc)
690 ifc = (Ipifc*)c->ptcl;
693 return "ipifc not yet bound to device";
697 err = ipifcremlifc(ifc, ifc->lifc);
705 err = ipifcadd(ifc, argv, argc, 0, nil);
714 ipifcra6(Ipifc *ifc, char **argv, int argc)
716 int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
721 if(argsleft % 2 != 0)
724 while (argsleft > 1) {
725 if(strcmp(argv[i], "recvra") == 0)
726 ifc->recvra6 = (atoi(argv[i+1]) != 0);
727 else if(strcmp(argv[i], "sendra") == 0)
728 ifc->sendra6 = (atoi(argv[i+1]) != 0);
729 else if(strcmp(argv[i], "mflag") == 0)
730 ifc->rp.mflag = (atoi(argv[i+1]) != 0);
731 else if(strcmp(argv[i], "oflag") == 0)
732 ifc->rp.oflag = (atoi(argv[i+1]) != 0);
733 else if(strcmp(argv[i], "maxraint") == 0)
734 ifc->rp.maxraint = atoi(argv[i+1]);
735 else if(strcmp(argv[i], "minraint") == 0)
736 ifc->rp.minraint = atoi(argv[i+1]);
737 else if(strcmp(argv[i], "linkmtu") == 0)
738 ifc->rp.linkmtu = atoi(argv[i+1]);
739 else if(strcmp(argv[i], "reachtime") == 0)
740 ifc->rp.reachtime = atoi(argv[i+1]);
741 else if(strcmp(argv[i], "rxmitra") == 0)
742 ifc->rp.rxmitra = atoi(argv[i+1]);
743 else if(strcmp(argv[i], "ttl") == 0)
744 ifc->rp.ttl = atoi(argv[i+1]);
745 else if(strcmp(argv[i], "routerlt") == 0)
746 ifc->rp.routerlt = atoi(argv[i+1]);
754 /* consistency check */
755 if(ifc->rp.maxraint < ifc->rp.minraint) {
756 ifc->rp.maxraint = vmax;
757 ifc->rp.minraint = vmin;
764 * non-standard control messages.
765 * called with c->car locked.
768 ipifcctl(Conv* c, char**argv, int argc)
773 ifc = (Ipifc*)c->ptcl;
774 if(strcmp(argv[0], "add") == 0)
775 return ipifcadd(ifc, argv, argc, 0, nil);
776 else if(strcmp(argv[0], "try") == 0)
777 return ipifcadd(ifc, argv, argc, 1, nil);
778 else if(strcmp(argv[0], "remove") == 0)
779 return ipifcrem(ifc, argv, argc);
780 else if(strcmp(argv[0], "unbind") == 0)
781 return ipifcunbind(ifc);
782 else if(strcmp(argv[0], "joinmulti") == 0)
783 return ipifcjoinmulti(ifc, argv, argc);
784 else if(strcmp(argv[0], "leavemulti") == 0)
785 return ipifcleavemulti(ifc, argv, argc);
786 else if(strcmp(argv[0], "mtu") == 0)
787 return ipifcsetmtu(ifc, argv, argc);
788 else if(strcmp(argv[0], "reassemble") == 0){
792 else if(strcmp(argv[0], "iprouting") == 0){
796 iprouting(c->p->f, i);
799 else if(strcmp(argv[0], "add6") == 0)
800 return ipifcadd6(ifc, argv, argc);
801 else if(strcmp(argv[0], "ra6") == 0)
802 return ipifcra6(ifc, argv, argc);
803 return "unsupported ctl";
807 ipifcstats(Proto *ipifc, char *buf, int len)
809 return ipstats(ipifc->f, buf, len);
817 ipifc = smalloc(sizeof(Proto));
818 ipifc->name = "ipifc";
819 ipifc->connect = ipifcconnect;
820 ipifc->announce = nil;
821 ipifc->bind = ipifcbind;
822 ipifc->state = ipifcstate;
823 ipifc->create = ipifccreate;
824 ipifc->close = ipifcclose;
826 ipifc->ctl = ipifcctl;
828 ipifc->stats = ipifcstats;
829 ipifc->inuse = ipifcinuse;
830 ipifc->local = ipifclocal;
832 ipifc->nc = Maxmedia;
833 ipifc->ptclsize = sizeof(Ipifc);
835 f->ipifc = ipifc; /* hack for ipifcremroute, findipifc, ... */
836 f->self = smalloc(sizeof(Ipselftab)); /* hack for ipforme */
842 * add to self routing cache
843 * called with c->car locked
846 addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
858 /* see if the address already exists */
860 for(p = f->self->hash[h]; p; p = p->next)
861 if(memcmp(a, p->a, IPaddrlen) == 0)
864 /* allocate a local address and add to hash chain */
866 p = smalloc(sizeof(*p));
869 p->next = f->self->hash[h];
870 f->self->hash[h] = p;
872 /* if the null address, accept all packets */
873 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
874 f->self->acceptall = 1;
877 /* look for a link for this lifc */
878 for(lp = p->link; lp; lp = lp->selflink)
882 /* allocate a lifc-to-local link and link to both */
884 lp = smalloc(sizeof(*lp));
888 lp->selflink = p->link;
890 lp->lifclink = lifc->link;
893 /* add to routing table */
895 v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off,
898 v6addroute(f, tifc, a, IPallbits, a, type);
900 if((type & Rmulti) && ifc->m->addmulti)
901 (*ifc->m->addmulti)(ifc, a, lifc->local);
910 * These structures are unlinked from their chains while
911 * other threads may be using them. To avoid excessive locking,
912 * just put them aside for a while before freeing them.
913 * called with f->self locked
915 static Iplink *freeiplink;
916 static Ipself *freeipself;
919 iplinkfree(Iplink *p)
925 for(np = *l; np; np = *l){
926 if(np->expire > now){
933 p->expire = now + 5000; /* give other threads 5 secs to get out */
939 ipselffree(Ipself *p)
945 for(np = *l; np; np = *l){
946 if(np->expire > now){
953 p->expire = now + 5000; /* give other threads 5 secs to get out */
959 * Decrement reference for this address on this link.
960 * Unlink from selftab if this is the last ref.
961 * called with c->car locked
964 remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
967 Iplink *link, **l_self, **l_lifc;
971 /* find the unique selftab entry */
972 l = &f->self->hash[hashipa(a)];
973 for(p = *l; p; p = *l){
974 if(ipcmp(p->a, a) == 0)
983 * walk down links from an ifc looking for one
984 * that matches the selftab entry
986 l_lifc = &lifc->link;
987 for(link = *l_lifc; link; link = *l_lifc){
990 l_lifc = &link->lifclink;
997 * walk down the links from the selftab looking for
998 * the one we just found
1001 for(link = *l_self; link; link = *l_self){
1004 l_self = &link->selflink;
1008 panic("remselfcache");
1010 if(--(link->ref) != 0)
1013 if((p->type & Rmulti) && ifc->m->remmulti){
1015 (*ifc->m->remmulti)(ifc, a, lifc->local);
1020 /* ref == 0, remove from both chains and free the link */
1021 *l_lifc = link->lifclink;
1022 *l_self = link->selflink;
1028 /* remove from routing table */
1030 v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
1032 v6delroute(f, a, IPallbits, 1);
1034 /* no more links, remove from hash and free */
1038 /* if IPnoaddr, forget */
1039 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1040 f->self->acceptall = 0;
1046 static char *stformat = "%-44.44I %2.2d %4.4s\n";
1053 ipselftabread(Fs *f, char *cp, ulong offset, int n)
1055 int i, m, nifc, off;
1063 for(i = 0; i < NHASH && m < n; i++){
1064 for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
1066 for(link = p->link; link; link = link->selflink)
1068 routetype(p->type, state);
1069 m += snprint(cp + m, n - m, stformat, p->a, nifc, state);
1081 iptentative(Fs *f, uchar *addr)
1085 p = f->self->hash[hashipa(addr)];
1086 for(; p; p = p->next){
1087 if(ipcmp(addr, p->a) == 0)
1088 return p->link->lifc->tentative;
1101 ipforme(Fs *f, uchar *addr)
1105 p = f->self->hash[hashipa(addr)];
1106 for(; p; p = p->next){
1107 if(ipcmp(addr, p->a) == 0)
1111 /* hack to say accept anything */
1112 if(f->self->acceptall)
1118 * find the ifc on same net as the remote system. If none,
1122 findipifc(Fs *f, uchar *remote, int type)
1127 uchar gnet[IPaddrlen], xmask[IPaddrlen];
1130 memset(xmask, 0, IPaddrlen);
1132 /* find most specific match */
1133 e = &f->ipifc->conv[f->ipifc->nc];
1134 for(cp = f->ipifc->conv; cp < e; cp++){
1137 ifc = (Ipifc*)(*cp)->ptcl;
1138 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1139 maskip(remote, lifc->mask, gnet);
1140 if(ipcmp(gnet, lifc->net) == 0){
1141 if(x == nil || ipcmp(lifc->mask, xmask) > 0){
1143 ipmove(xmask, lifc->mask);
1151 /* for now for broadcast and multicast, just use first interface */
1152 if(type & (Rbcast|Rmulti)){
1153 for(cp = f->ipifc->conv; cp < e; cp++){
1156 ifc = (Ipifc*)(*cp)->ptcl;
1157 if(ifc->lifc != nil)
1165 unknownv6, /* UGH */
1172 v6addrtype(uchar *addr)
1174 if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
1176 else if(islinklocal(addr) ||
1177 isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
1183 #define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
1184 (lifc)->origint + (lifc)->preflt >= NOW/1000)
1187 findprimaryipv6(Fs *f, uchar *local)
1194 ipmove(local, v6Unspecified);
1195 atype = unspecifiedv6;
1198 * find "best" (global > link local > unspecified)
1199 * local address; address must be current.
1201 e = &f->ipifc->conv[f->ipifc->nc];
1202 for(cp = f->ipifc->conv; cp < e; cp++){
1205 ifc = (Ipifc*)(*cp)->ptcl;
1206 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1207 atypel = v6addrtype(lifc->local);
1208 if(atypel > atype && v6addrcurr(lifc)) {
1209 ipmove(local, lifc->local);
1211 if(atype == globalv6)
1219 * returns first ip address configured
1222 findprimaryipv4(Fs *f, uchar *local)
1228 /* find first ifc local address */
1229 e = &f->ipifc->conv[f->ipifc->nc];
1230 for(cp = f->ipifc->conv; cp < e; cp++){
1233 ifc = (Ipifc*)(*cp)->ptcl;
1234 if((lifc = ifc->lifc) != nil){
1235 ipmove(local, lifc->local);
1239 ipmove(local, IPnoaddr);
1243 comprefixlen(uchar *a, uchar *b, int n)
1247 for(i = 0; i < n; i++){
1248 if((c = a[i] ^ b[i]) == 0)
1250 for(i <<= 3; (c & 0x80) == 0; i++)
1258 * return v4 address associated with an interface close to remote
1261 ipv4local(Ipifc *ifc, uchar *local, uchar *remote)
1267 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1268 if(!isv4(lifc->local))
1270 a = comprefixlen(lifc->local+IPv4off, remote, IPv4addrlen);
1273 memmove(local, lifc->local+IPv4off, IPv4addrlen);
1280 * return v6 address associated with an interface close to remote
1283 ipv6local(Ipifc *ifc, uchar *local, uchar *remote)
1294 ipmove(local, v4prefix);
1295 return ipv4local(ifc, local+IPv4off, remote+IPv4off);
1298 atype = v6addrtype(remote);
1299 ipmove(local, v6Unspecified);
1300 b.atype = unknownv6;
1304 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1308 a.atype = v6addrtype(lifc->local);
1309 a.deprecated = !v6addrcurr(lifc);
1310 a.comprefixlen = comprefixlen(lifc->local, remote, IPaddrlen);
1312 /* prefer appropriate scope */
1313 if(a.atype != b.atype){
1314 if(a.atype > b.atype && b.atype < atype ||
1315 a.atype < b.atype && b.atype > atype)
1319 /* prefer non-deprecated addresses */
1320 if(a.deprecated != b.deprecated){
1325 /* prefer longer common prefix */
1326 if(a.comprefixlen != b.comprefixlen){
1327 if(a.comprefixlen > b.comprefixlen)
1334 ipmove(local, lifc->local);
1337 return b.atype >= atype;
1341 * find the local address 'closest' to the remote system, copy it to local
1344 findlocalip(Fs *f, uchar *local, uchar *remote)
1349 if((r = v6lookup(f, remote, nil)) != nil){
1351 ipmove(local, remote);
1354 if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){
1355 ipmove(local, v4prefix);
1356 if(ipv4local(r->ifc, local+IPv4off, r->v4.gate))
1359 if(ipv6local(r->ifc, local, remote))
1363 findprimaryipv4(f, local);
1365 findprimaryipv6(f, local);
1371 * see if this address is bound to the interface
1374 iplocalonifc(Ipifc *ifc, uchar *ip)
1378 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1379 if(ipcmp(ip, lifc->local) == 0)
1386 * See if we're proxying for this address on this interface
1389 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
1392 uchar net[IPaddrlen];
1395 /* see if this is a direct connected pt to pt address */
1396 r = v6lookup(f, ip, nil);
1397 if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
1400 /* see if this is on the right interface */
1401 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1402 maskip(ip, lifc->mask, net);
1403 if(ipcmp(net, lifc->remote) == 0)
1410 * return multicast version if any
1413 ipismulticast(uchar *ip)
1416 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1419 else if(ip[0] == 0xff)
1427 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1429 else if(ipcmp(ip, IPv4bcast) == 0)
1432 else if(ip[0] == 0xff)
1439 * add a multicast address to an interface, called with c->car locked
1442 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
1447 Ipmulti *multi, **l;
1452 for(l = &c->multi; *l; l = &(*l)->next)
1453 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1454 return; /* it's already there */
1456 multi = *l = smalloc(sizeof(*multi));
1457 ipmove(multi->ma, ma);
1458 ipmove(multi->ia, ia);
1461 for(p = f->ipifc->conv; *p; p++){
1462 if((*p)->inuse == 0)
1464 ifc = (Ipifc*)(*p)->ptcl;
1470 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1471 if(ipcmp(ia, lifc->local) == 0)
1472 addselfcache(f, ifc, lifc, ma, Rmulti);
1480 * remove a multicast address from an interface, called with c->car locked
1483 ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
1485 Ipmulti *multi, **l;
1493 for(l = &c->multi; *l; l = &(*l)->next)
1494 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1499 return; /* we don't have it open */
1503 for(p = f->ipifc->conv; *p; p++){
1504 if((*p)->inuse == 0)
1507 ifc = (Ipifc*)(*p)->ptcl;
1509 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1510 if(ipcmp(ia, lifc->local) == 0)
1511 remselfcache(f, ifc, lifc, ma);
1519 * make lifc's join and leave multicast groups
1522 ipifcjoinmulti(Ipifc *ifc, char **argv, int argc)
1524 USED(ifc, argv, argc);
1529 ipifcleavemulti(Ipifc *ifc, char **argv, int argc)
1531 USED(ifc, argv, argc);
1536 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
1542 uchar net[IPaddrlen];
1544 /* register the address on any network that will proxy for us */
1545 e = &f->ipifc->conv[f->ipifc->nc];
1547 if(!isv4(ip)) { /* V6 */
1548 for(cp = f->ipifc->conv; cp < e; cp++){
1549 if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
1553 if(m == nil || m->addmulti == nil) {
1561 for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1562 maskip(ip, lifc->mask, net);
1563 if(ipcmp(net, lifc->remote) == 0) {
1564 /* add solicited-node multicast addr */
1565 ipv62smcast(net, ip);
1566 addselfcache(f, nifc, lifc, net, Rmulti);
1567 arpenter(f, V6, ip, nifc->mac, 6, 0);
1576 for(cp = f->ipifc->conv; cp < e; cp++){
1577 if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
1581 if(m == nil || m->areg == nil){
1589 for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1590 maskip(ip, lifc->mask, net);
1591 if(ipcmp(net, lifc->remote) == 0){
1592 (*m->areg)(nifc, ip);
1603 ipifcadd6(Ipifc *ifc, char**argv, int argc)
1606 char addr[40], preflen[6];
1608 uchar prefix[IPaddrlen];
1615 lifc.origint = NOW / 1000;
1619 lifc.preflt = atoi(argv[6]);
1622 lifc.validlt = atoi(argv[5]);
1625 lifc.autoflag = atoi(argv[4]) != 0;
1628 lifc.onlink = atoi(argv[3]) != 0;
1631 plen = atoi(argv[2]);
1639 if (parseip(prefix, argv[1]) != 6 || lifc.validlt < lifc.preflt || plen < 0 ||
1640 plen > 64 || islinklocal(prefix))
1643 /* issue "add" ctl msg for v6 link-local addr and prefix len */
1644 if(ifc->m->pref2addr == nil)
1646 (*ifc->m->pref2addr)(prefix, ifc->mac); /* mac → v6 link-local addr */
1648 sprint(addr, "%I", prefix);
1649 sprint(preflen, "/%d", plen);
1652 params[2] = preflen;
1654 return ipifcadd(ifc, params, 3, 0, &lifc);