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 *next; /* next address in the hash table */
30 Iplink *link; /* binding twixt Ipself and Ipifc */
32 uchar type; /* type of address */
39 int acceptall; /* true if an interface has the null address */
40 Ipself *hash[NHASH]; /* hash chains */
44 * Multicast addresses are chained onto a Chan so that
45 * we can remove them when the Chan is closed.
47 typedef struct Ipmcast Ipmcast;
51 uchar ma[IPaddrlen]; /* multicast address */
52 uchar ia[IPaddrlen]; /* interface address */
55 /* quick hash for ip addresses */
56 #define hashipa(a) ( ( ((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1] )%NHASH )
58 static char tifc[] = "ifc ";
60 static void addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
61 static void remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
62 static void ipifcregisteraddr(Fs*, Ipifc*, Iplifc*, uchar*);
63 static void ipifcregisterproxy(Fs*, Ipifc*, uchar*, int);
64 static char* ipifcremlifc(Ipifc*, Iplifc**);
66 static char Ebound[] = "interface already bound";
67 static char Eunbound[] = "interface not bound";
77 v6addrtype(uchar *addr)
79 if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
81 else if(islinklocal(addr) || ipcmp(addr, v6loopback) == 0 ||
82 isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
89 comprefixlen(uchar *a, uchar *b, int n)
93 for(i = 0; i < n; i++){
94 if((c = a[i] ^ b[i]) == 0)
96 for(i <<= 3; (c & 0x80) == 0; i++)
104 * link in a new medium
107 addipmedium(Medium *med)
111 for(i = 0; i < nelem(media)-1; i++)
119 * find the medium with this name
122 ipfindmedium(char *name)
126 for(mp = media; *mp != nil; mp++)
127 if(strcmp((*mp)->name, name) == 0)
133 * attach a device (or pkt driver) to the interface.
134 * called with c locked
137 ipifcbind(Conv *c, char **argv, int argc)
145 ifc = (Ipifc*)c->ptcl;
147 /* bind the device to the interface */
148 m = ipfindmedium(argv[1]);
150 return "unknown interface type";
162 /* do medium specific binding */
163 (*m->bind)(ifc, argc, argv);
165 /* set the bound device name */
167 strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
169 snprint(ifc->dev, sizeof ifc->dev, "%s%d", m->name, c->x);
170 ifc->dev[sizeof(ifc->dev)-1] = 0;
172 /* set up parameters */
174 ifc->mintu = ifc->m->mintu;
175 ifc->maxtu = ifc->m->maxtu;
178 if(ifc->m->unbindonclose == 0)
181 /* default router paramters */
182 ifc->rp = c->p->f->v6p->rp;
184 /* any ancillary structures (like routes) no longer pertain */
187 /* reopen all the queues closed by a previous unbind */
199 * detach a device from an interface, close the interface
202 ipifcunbind(Ipifc *ifc)
213 /* disassociate logical interfaces (before zeroing ifc->arg) */
214 while(ifc->lifc != nil)
215 ipifcremlifc(ifc, &ifc->lifc);
217 /* disassociate device */
218 if(m->unbind != nil){
219 extern Medium nullmedium;
222 * unbind() might unlock the ifc, so change the medium
223 * to the nullmedium to prevent packets from getting
224 * sent while the medium is shutting down.
226 ifc->m = &nullmedium;
234 memset(ifc->dev, 0, sizeof(ifc->dev));
240 /* close queues to stop queuing of packets */
241 qclose(ifc->conv->rq);
242 qclose(ifc->conv->wq);
243 qclose(ifc->conv->sq);
245 /* dissociate routes */
247 if(m->unbindonclose == 0)
255 char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag %d"
256 " maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt %d"
257 " pktin %lud pktout %lud errin %lud errout %lud speed %d delay %d\n";
259 char slineformat[] = " %-40I %-10M %-40I %-12lud %-12lud\n";
262 ipifcstate(Conv *c, char *state, int n)
268 ifc = (Ipifc*)c->ptcl;
269 m = snprint(state, n, sfixedformat,
270 ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
271 ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
272 ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
273 ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
274 ifc->in, ifc->out, ifc->inerr, ifc->outerr,
275 ifc->speed, ifc->delay);
278 for(lifc = ifc->lifc; lifc != nil && n > m; lifc = lifc->next)
279 m += snprint(state+m, n - m, slineformat, lifc->local,
280 lifc->mask, lifc->remote, lifc->validlt, lifc->preflt);
282 m += snprint(state+m, n - m, "\n");
288 ipifclocal(Conv *c, char *state, int n)
295 ifc = (Ipifc*)c->ptcl;
298 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
299 m += snprint(state+m, n - m, "%-40.40I ->", lifc->local);
300 for(link = lifc->link; link != nil; link = link->lifclink)
301 m += snprint(state+m, n - m, " %-40.40I", link->self->a);
302 m += snprint(state+m, n - m, "\n");
313 ifc = (Ipifc*)c->ptcl;
314 return ifc->m != nil;
318 ipifcadjustburst(Ipifc *ifc)
322 burst = ((vlong)ifc->delay * ifc->speed) / 8000;
323 if(burst < ifc->maxtu)
329 ipifcsetdelay(Ipifc *ifc, int delay)
333 else if(delay > 1000)
336 ipifcadjustburst(ifc);
340 ipifcsetspeed(Ipifc *ifc, int speed)
346 ipifcadjustburst(ifc);
350 ipifcoput(Ipifc *ifc, Block *bp, int version, uchar *ip)
353 ulong now = MACHP(0)->ticks;
354 int dt = TK2MS(now - ifc->ticks);
356 ifc->load -= ((vlong)dt * ifc->speed) / 8000;
357 if(ifc->load < 0 || dt < 0 || dt > 1000)
359 else if(ifc->load > ifc->burst){
364 bp = concatblock(bp);
365 ifc->load += BLEN(bp);
366 ifc->m->bwrite(ifc, bp, version, ip);
371 * called when a process writes to an interface's 'data'
384 ifc = (Ipifc*)c->ptcl;
390 if(ifc->m != nil && ifc->m->pktin != nil)
391 (*ifc->m->pktin)(c->p->f, ifc, bp);
399 * called when a new ipifc structure is created
406 c->rq = qopen(QMAX, 0, 0, 0);
407 c->wq = qopen(QMAX, Qkick, ipifckick, c);
408 c->sq = qopen(QMAX, 0, 0, 0);
409 if(c->rq == nil || c->wq == nil || c->sq == nil)
411 ifc = (Ipifc*)c->ptcl;
419 * called after last close of ipifc data or ctl
424 Ipifc *ifc = (Ipifc*)c->ptcl;
427 if(m != nil && m->unbindonclose)
432 * change an interface's mtu
435 ipifcsetmtu(Ipifc *ifc, int mtu)
441 if(mtu < m->mintu || mtu > m->maxtu)
444 ipifcadjustburst(ifc);
449 * add an address to an interface.
452 ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
454 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
455 uchar bcast[IPaddrlen], net[IPaddrlen];
462 memset(ip, 0, IPaddrlen);
463 memset(mask, 0, IPaddrlen);
464 memset(rem, 0, IPaddrlen);
467 if(strcmp(argv[5], "proxy") == 0)
471 mtu = strtoul(argv[4], 0, 0);
474 if (parseipandmask(ip, mask, argv[1], argv[2]) == -1 || parseip(rem, argv[3]) == -1)
476 maskip(rem, mask, net);
479 if (parseipandmask(ip, mask, argv[1], argv[2]) == -1)
481 maskip(ip, mask, rem);
482 maskip(rem, mask, net);
485 if (parseip(ip, argv[1]) == -1)
487 memmove(mask, defmask(ip), IPaddrlen);
488 maskip(ip, mask, rem);
489 maskip(rem, mask, net);
495 /* check for point-to-point interface */
496 if(ipcmp(ip, v6loopback) != 0) /* skip v6 loopback, it's a special address */
497 if(ipcmp(mask, IPallbits) == 0)
500 if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0){
517 ipifcsetmtu(ifc, mtu);
519 /* ignore if this is already a local address for this ifc */
520 if((lifc = iplocalonifc(ifc, ip)) != nil){
522 if(!lifc->onlink && lifcp->onlink){
524 addroute(f, lifc->remote, lifc->mask, ip, IPallbits,
525 lifc->remote, lifc->type, ifc, tifc);
526 if(v6addrtype(ip) != linklocalv6)
527 addroute(f, lifc->remote, lifc->mask, ip, IPnoaddr,
528 lifc->remote, lifc->type, ifc, tifc);
530 lifc->autoflag = lifcp->autoflag;
531 lifc->validlt = lifcp->validlt;
532 lifc->preflt = lifcp->preflt;
533 lifc->origint = lifcp->origint;
535 if(lifc->tentative != tentative){
536 lifc->tentative = tentative;
544 /* add the address to the list of logical ifc's for this ifc */
545 lifc = smalloc(sizeof(Iplifc));
546 ipmove(lifc->local, ip);
547 ipmove(lifc->mask, mask);
548 ipmove(lifc->remote, rem);
549 ipmove(lifc->net, net);
551 lifc->tentative = tentative;
553 lifc->onlink = lifcp->onlink;
554 lifc->autoflag = lifcp->autoflag;
555 lifc->validlt = lifcp->validlt;
556 lifc->preflt = lifcp->preflt;
557 lifc->origint = lifcp->origint;
558 } else { /* default values */
559 lifc->onlink = lifc->autoflag = 1;
560 lifc->validlt = lifc->preflt = ~0UL;
561 lifc->origint = NOW / 1000;
565 for(l = &ifc->lifc; *l != nil; l = &(*l)->next)
569 /* add route for this logical interface */
571 addroute(f, rem, mask, ip, IPallbits, rem, type, ifc, tifc);
572 if(v6addrtype(ip) != linklocalv6)
573 addroute(f, rem, mask, ip, IPnoaddr, rem, type, ifc, tifc);
576 addselfcache(f, ifc, lifc, ip, Runi);
581 ipifcregisterproxy(f, ifc, rem, 1);
586 /* add subnet directed broadcast address to the self cache */
587 for(i = 0; i < IPaddrlen; i++)
588 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
589 addselfcache(f, ifc, lifc, bcast, Rbcast);
591 /* add subnet directed network address to the self cache */
592 for(i = 0; i < IPaddrlen; i++)
593 bcast[i] = (ip[i] & mask[i]) & mask[i];
594 addselfcache(f, ifc, lifc, bcast, Rbcast);
596 /* add network directed broadcast address to the self cache */
597 memmove(mask, defmask(ip), IPaddrlen);
598 for(i = 0; i < IPaddrlen; i++)
599 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
600 addselfcache(f, ifc, lifc, bcast, Rbcast);
602 /* add network directed network address to the self cache */
603 memmove(mask, defmask(ip), IPaddrlen);
604 for(i = 0; i < IPaddrlen; i++)
605 bcast[i] = (ip[i] & mask[i]) & mask[i];
606 addselfcache(f, ifc, lifc, bcast, Rbcast);
608 addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
610 if(ipcmp(ip, v6loopback) == 0) {
611 /* add node-local mcast address */
612 addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
614 /* add route for all node multicast */
615 addroute(f, v6allnodesN, v6allnodesNmask,
617 v6allnodesN, Rmulti, ifc, tifc);
620 /* add all nodes multicast address */
621 addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
623 /* add route for all nodes multicast */
624 addroute(f, v6allnodesL, v6allnodesLmask,
626 v6allnodesL, Rmulti, ifc, tifc);
628 /* add solicited-node multicast address */
629 ipv62smcast(bcast, ip);
630 addselfcache(f, ifc, lifc, bcast, Rmulti);
638 ipifcregisteraddr(f, ifc, lifc, ip);
645 * remove a logical interface from an ifc
646 * called with ifc wlock'd
649 ipifcremlifc(Ipifc *ifc, Iplifc **l)
652 Fs *f = ifc->conv->p->f;
655 return "address not on this interface";
658 /* disassociate any addresses */
659 while(lifc->link != nil)
660 remselfcache(f, ifc, lifc, lifc->link->self->a);
662 /* remove the route for this logical interface */
664 remroute(f, lifc->remote, lifc->mask,
665 lifc->local, IPallbits,
666 lifc->remote, lifc->type, ifc, tifc);
667 if(v6addrtype(lifc->local) != linklocalv6)
668 remroute(f, lifc->remote, lifc->mask,
669 lifc->local, IPnoaddr,
670 lifc->remote, lifc->type, ifc, tifc);
673 /* unregister proxy */
674 if(lifc->type & Rptpt){
675 if(lifc->type & Rproxy)
676 ipifcregisterproxy(f, ifc, lifc->remote, 0);
680 /* remove route for all nodes multicast */
681 if((lifc->type & Rv4) == 0){
682 if(ipcmp(lifc->local, v6loopback) == 0)
683 remroute(f, v6allnodesN, v6allnodesNmask,
684 lifc->local, IPallbits,
685 v6allnodesN, Rmulti, ifc, tifc);
687 remroute(f, v6allnodesL, v6allnodesLmask,
688 lifc->local, IPallbits,
689 v6allnodesL, Rmulti, ifc, tifc);
698 * remove an address from an interface.
701 ipifcrem(Ipifc *ifc, char **argv, int argc)
703 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
709 if(parseipandmask(ip, mask, argv[1], argv[2]) == -1)
712 maskip(ip, mask, rem);
713 else if(parseip(rem, argv[3]) == -1)
717 * find address on this interface and remove from chain.
718 * for pt to pt we actually specify the remote address as the
719 * addresss to remove.
723 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
724 if(ipcmp(ip, lifc->local) == 0
725 && ipcmp(mask, lifc->mask) == 0
726 && ipcmp(rem, lifc->remote) == 0)
730 err = ipifcremlifc(ifc, l);
736 * associate an address with the interface. This wipes out any previous
737 * addresses. This is a macro that means, remove all the old interfaces
741 ipifcconnect(Conv* c, char **argv, int argc)
743 Ipifc *ifc = (Ipifc*)c->ptcl;
747 while(ifc->lifc != nil)
748 ipifcremlifc(ifc, &ifc->lifc);
751 err = ipifcadd(ifc, argv, argc, 0, nil);
760 ipifcra6(Ipifc *ifc, char **argv, int argc)
763 uchar sendra, recvra;
768 if((argsleft % 2) != 0)
771 sendra = ifc->sendra6;
772 recvra = ifc->recvra6;
775 while (argsleft > 1) {
776 if(strcmp(argv[i], "recvra") == 0)
777 recvra = atoi(argv[i+1]) != 0;
778 else if(strcmp(argv[i], "sendra") == 0)
779 sendra = atoi(argv[i+1]) != 0;
780 else if(strcmp(argv[i], "mflag") == 0)
781 rp.mflag = atoi(argv[i+1]) != 0;
782 else if(strcmp(argv[i], "oflag") == 0)
783 rp.oflag = atoi(argv[i+1]) != 0;
784 else if(strcmp(argv[i], "maxraint") == 0)
785 rp.maxraint = atoi(argv[i+1]);
786 else if(strcmp(argv[i], "minraint") == 0)
787 rp.minraint = atoi(argv[i+1]);
788 else if(strcmp(argv[i], "linkmtu") == 0)
789 rp.linkmtu = atoi(argv[i+1]);
790 else if(strcmp(argv[i], "reachtime") == 0)
791 rp.reachtime = atoi(argv[i+1]);
792 else if(strcmp(argv[i], "rxmitra") == 0)
793 rp.rxmitra = atoi(argv[i+1]);
794 else if(strcmp(argv[i], "ttl") == 0)
795 rp.ttl = atoi(argv[i+1]);
796 else if(strcmp(argv[i], "routerlt") == 0)
797 rp.routerlt = atoi(argv[i+1]);
805 /* consistency check */
806 if(rp.maxraint < rp.minraint)
810 ifc->sendra6 = sendra;
811 ifc->recvra6 = recvra;
817 * non-standard control messages.
820 ipifcctl(Conv* c, char **argv, int argc)
822 Ipifc *ifc = (Ipifc*)c->ptcl;
824 if(strcmp(argv[0], "add") == 0)
825 return ipifcadd(ifc, argv, argc, 0, nil);
826 else if(strcmp(argv[0], "try") == 0)
827 return ipifcadd(ifc, argv, argc, 1, nil);
828 else if(strcmp(argv[0], "remove") == 0)
829 return ipifcrem(ifc, argv, argc);
830 else if(strcmp(argv[0], "unbind") == 0)
831 return ipifcunbind(ifc);
832 else if(strcmp(argv[0], "mtu") == 0)
833 return ipifcsetmtu(ifc, argc>1? strtoul(argv[1], 0, 0): 0);
834 else if(strcmp(argv[0], "speed") == 0){
835 ipifcsetspeed(ifc, argc>1? atoi(argv[1]): 0);
838 else if(strcmp(argv[0], "delay") == 0){
839 ipifcsetdelay(ifc, argc>1? atoi(argv[1]): 0);
842 else if(strcmp(argv[0], "iprouting") == 0){
843 iprouting(c->p->f, argc>1? atoi(argv[1]): 1);
846 else if(strcmp(argv[0], "reflect") == 0){
847 ifc->reflect = argc>1? atoi(argv[1]): 1;
850 else if(strcmp(argv[0], "reassemble") == 0){
851 ifc->reassemble = argc>1? atoi(argv[1]): 1;
854 else if(strcmp(argv[0], "add6") == 0)
855 return ipifcadd6(ifc, argv, argc);
856 else if(strcmp(argv[0], "remove6") == 0)
857 return ipifcremove6(ifc, argv, argc);
858 else if(strcmp(argv[0], "ra6") == 0)
859 return ipifcra6(ifc, argv, argc);
860 return "unsupported ctl";
864 ipifcstats(Proto *ipifc, char *buf, int len)
866 return ipstats(ipifc->f, buf, len);
874 ipifc = smalloc(sizeof(Proto));
875 ipifc->name = "ipifc";
876 ipifc->connect = ipifcconnect;
877 ipifc->announce = nil;
878 ipifc->bind = ipifcbind;
879 ipifc->state = ipifcstate;
880 ipifc->create = ipifccreate;
881 ipifc->close = ipifcclose;
883 ipifc->ctl = ipifcctl;
885 ipifc->stats = ipifcstats;
886 ipifc->inuse = ipifcinuse;
887 ipifc->local = ipifclocal;
889 ipifc->nc = Maxmedia;
890 ipifc->ptclsize = sizeof(Ipifc);
892 f->ipifc = ipifc; /* hack for ipifcremroute, findipifc, ... */
893 f->self = smalloc(sizeof(Ipselftab)); /* hack for ipforme */
899 * add to self routing cache
902 addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
908 type |= (lifc->type & Rv4);
915 /* see if the address already exists */
917 for(p = f->self->hash[h]; p != nil; p = p->next)
918 if(ipcmp(a, p->a) == 0)
921 /* allocate a local address and add to hash chain */
923 p = smalloc(sizeof(*p));
926 p->next = f->self->hash[h];
927 f->self->hash[h] = p;
929 /* if the null address, accept all packets */
930 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
931 f->self->acceptall = 1;
934 /* look for a link for this lifc */
935 for(lp = p->link; lp != nil; lp = lp->selflink)
939 /* allocate a lifc-to-local link and link to both */
941 lp = smalloc(sizeof(*lp));
945 lp->selflink = p->link;
947 lp->lifclink = lifc->link;
950 /* add to routing table */
951 addroute(f, a, IPallbits,
953 ((type & (Rbcast|Rmulti)) != 0 || v6addrtype(a) == linklocalv6) ?
954 IPallbits : IPnoaddr,
957 if((type & Rmulti) && ifc->m->addmulti != nil)
958 (*ifc->m->addmulti)(ifc, a, lifc->local);
967 * These structures are unlinked from their chains while
968 * other threads may be using them. To avoid excessive locking,
969 * just put them aside for a while before freeing them.
970 * called with f->self locked
972 static Iplink *freeiplink;
973 static Ipself *freeipself;
976 iplinkfree(Iplink *p)
982 for(np = *l; np != nil; np = *l){
983 if((long)(now - np->expire) >= 0){
990 p->expire = now + 5000; /* give other threads 5 secs to get out */
996 ipselffree(Ipself *p)
1002 for(np = *l; np != nil; np = *l){
1003 if((long)(now - np->expire) >= 0){
1010 p->expire = now + 5000; /* give other threads 5 secs to get out */
1016 * Decrement reference for this address on this link.
1017 * Unlink from selftab if this is the last ref.
1020 remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
1023 Iplink *link, **l_self, **l_lifc;
1027 /* find the unique selftab entry */
1028 l = &f->self->hash[hashipa(a)];
1029 for(p = *l; p != nil; p = *l){
1030 if(ipcmp(p->a, a) == 0)
1039 * walk down links from an ifc looking for one
1040 * that matches the selftab entry
1042 l_lifc = &lifc->link;
1043 for(link = *l_lifc; link != nil; link = *l_lifc){
1046 l_lifc = &link->lifclink;
1053 * walk down the links from the selftab looking for
1054 * the one we just found
1057 for(link = *l_self; link != nil; link = *l_self){
1060 l_self = &link->selflink;
1064 panic("remselfcache");
1066 if(--(link->ref) != 0)
1069 /* remove from routing table */
1070 remroute(f, a, IPallbits,
1072 ((p->type & (Rbcast|Rmulti)) != 0 || v6addrtype(a) == linklocalv6) ?
1073 IPallbits : IPnoaddr,
1074 a, p->type, ifc, tifc);
1076 if((p->type & Rmulti) && ifc->m->remmulti != nil){
1078 (*ifc->m->remmulti)(ifc, a, lifc->local);
1083 /* ref == 0, remove from both chains and free the link */
1084 *l_lifc = link->lifclink;
1085 *l_self = link->selflink;
1091 /* if null address, forget */
1092 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1093 f->self->acceptall = 0;
1095 /* no more links, remove from hash and free */
1104 ipselftabread(Fs *f, char *cp, ulong offset, int n)
1106 int i, m, nifc, off;
1113 for(i = 0; i < NHASH && m < n; i++){
1114 for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
1116 for(link = p->link; link != nil; link = link->selflink)
1118 routetype(p->type, state);
1119 m += snprint(cp + m, n - m, "%-44.44I %2.2d %4.4s\n",
1138 ipforme(Fs *f, uchar *addr)
1142 for(p = f->self->hash[hashipa(addr)]; p != nil; p = p->next)
1143 if(ipcmp(addr, p->a) == 0)
1144 return p->type & (Runi|Rbcast|Rmulti);
1146 /* hack to say accept anything */
1147 if(f->self->acceptall)
1154 * find the ifc on same net as the remote system. If none,
1158 findipifc(Fs *f, uchar *local, uchar *remote, int type)
1160 uchar gnet[IPaddrlen];
1168 for(cp = f->ipifc->conv; *cp != nil; cp++){
1169 ifc = (Ipifc*)(*cp)->ptcl;
1172 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1174 if(ipcmp(remote, lifc->local) == 0){
1179 } else if(type & (Rbcast|Rmulti)) {
1180 if(ipcmp(local, lifc->local) == 0)
1183 maskip(remote, lifc->mask, gnet);
1184 if(ipcmp(gnet, lifc->net) == 0){
1185 spec = comprefixlen(remote, lifc->local, IPaddrlen);
1198 findipifcstr(Fs *f, char *s)
1200 uchar ip[IPaddrlen];
1205 x = strtol(s, &p, 10);
1206 if(p > s && *p == '\0'){
1209 if(x < f->ipifc->nc && (c = f->ipifc->conv[x]) != nil && ipifcinuse(c))
1210 return (Ipifc*)c->ptcl;
1212 if(parseip(ip, s) != -1)
1213 return findipifc(f, ip, ip, Runi);
1218 * find "best" (global > link local > unspecified)
1219 * local address; address must be current.
1222 findprimaryipv6(Fs *f, uchar *local)
1224 ulong now = NOW/1000;
1230 ipmove(local, v6Unspecified);
1231 atype = unspecifiedv6;
1233 for(cp = f->ipifc->conv; *cp != nil; cp++){
1234 ifc = (Ipifc*)(*cp)->ptcl;
1236 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1237 atypel = v6addrtype(lifc->local);
1239 if(lifc->preflt == ~0UL || lifc->preflt >= now-lifc->origint) {
1240 ipmove(local, lifc->local);
1242 if(atype == globalv6){
1253 * returns first v4 address configured
1256 findprimaryipv4(Fs *f, uchar *local)
1262 /* find first ifc local address */
1263 for(cp = f->ipifc->conv; *cp != nil; cp++){
1264 ifc = (Ipifc*)(*cp)->ptcl;
1266 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1267 if((lifc->type & Rv4) != 0){
1268 ipmove(local, lifc->local);
1275 ipmove(local, IPnoaddr);
1279 * ipv4local, ipv6local:
1280 * return a local address associated with an interface close to remote.
1281 * prefixlen is the number of leading bits in the local address that
1282 * have to match an interface address to be considered. this is used
1283 * by source specific routes to filter on the source address.
1284 * return non-zero on success or zero when no address was found.
1286 * for ipv4local, all addresses are 4 byte format.
1289 ipv4local(Ipifc *ifc, uchar *local, int prefixlen, uchar *remote)
1295 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1296 if((lifc->type & Rv4) == 0 || ipcmp(lifc->local, IPnoaddr) == 0)
1299 if(prefixlen && comprefixlen(lifc->local+IPv4off, local, IPv4addrlen) < prefixlen)
1302 a = comprefixlen(lifc->local+IPv4off, remote, IPv4addrlen);
1305 memmove(local, lifc->local+IPv4off, IPv4addrlen);
1312 ipv6local(Ipifc *ifc, uchar *local, int prefixlen, uchar *remote)
1324 memmove(local, v4prefix, IPv4off);
1325 if((prefixlen -= IPv4off*8) < 0)
1327 return ipv4local(ifc, local+IPv4off, prefixlen, remote+IPv4off);
1330 atype = v6addrtype(remote);
1331 b.atype = unknownv6;
1336 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1340 if(prefixlen && comprefixlen(lifc->local, local, IPaddrlen) < prefixlen)
1343 a.atype = v6addrtype(lifc->local);
1344 a.deprecated = lifc->preflt != ~0UL && lifc->preflt < now-lifc->origint;
1345 a.comprefixlen = comprefixlen(lifc->local, remote, IPaddrlen);
1347 /* prefer appropriate scope */
1348 if(a.atype != b.atype){
1349 if(a.atype > b.atype && b.atype < atype ||
1350 a.atype < b.atype && b.atype > atype)
1354 /* prefer non-deprecated addresses */
1355 if(a.deprecated != b.deprecated){
1360 /* prefer longer common prefix */
1361 if(a.comprefixlen != b.comprefixlen){
1362 if(a.comprefixlen > b.comprefixlen)
1369 ipmove(local, lifc->local);
1372 return b.atype >= atype;
1376 * find the local address for a remote destination
1379 findlocalip(Fs *f, uchar *local, uchar *remote)
1382 memmove(local, v4prefix, IPv4off);
1383 if(v4source(f, remote+IPv4off, local+IPv4off) == nil)
1384 findprimaryipv4(f, local);
1386 if(v6source(f, remote, local) == nil)
1387 findprimaryipv6(f, local);
1392 * see if this address is bound to the interface
1395 iplocalonifc(Ipifc *ifc, uchar *ip)
1399 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
1400 if(ipcmp(ip, lifc->local) == 0)
1407 ipremoteonifc(Ipifc *ifc, uchar *ip)
1409 uchar net[IPaddrlen];
1412 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1413 maskip(ip, lifc->mask, net);
1414 if(ipcmp(net, lifc->remote) == 0)
1422 * See if we're proxying for this address on this interface
1425 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
1429 /* see if this is a direct connected pt to pt address */
1430 r = v6lookup(f, ip, ip, nil);
1431 if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
1434 return ipremoteonifc(ifc, ip) != nil;
1438 * return multicast version if any
1441 ipismulticast(uchar *ip)
1444 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1447 else if(ip[0] == 0xff)
1453 * add a multicast address to an interface.
1456 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
1458 Ipmulti *multi, **l;
1463 if(isv4(ma) != isv4(ia))
1464 error("incompatible multicast/interface ip address");
1466 for(l = &c->multi; *l != nil; l = &(*l)->next)
1467 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1468 return; /* it's already there */
1471 if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
1477 if((lifc = iplocalonifc(ifc, ia)) != nil)
1478 addselfcache(f, ifc, lifc, ma, Rmulti);
1483 multi = smalloc(sizeof(*multi));
1484 ipmove(multi->ma, ma);
1485 ipmove(multi->ia, ia);
1492 * remove a multicast address from an interface.
1495 ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
1497 Ipmulti *multi, **l;
1502 for(l = &c->multi; *l != nil; l = &(*l)->next)
1503 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1508 return; /* we don't have it open */
1514 if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
1517 if((lifc = iplocalonifc(ifc, ia)) != nil)
1518 remselfcache(f, ifc, lifc, ma);
1526 /* register the address on this network for address resolution */
1528 ipifcregisteraddr(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *ip)
1531 print("ipifcregisteraddr %s %I %I: %s\n", ifc->dev, lifc->local, ip, up->errstr);
1534 if(ifc->m != nil && ifc->m->areg != nil)
1535 (*ifc->m->areg)(f, ifc, lifc, ip);
1540 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip, int add)
1547 /* register the address on any interface that will proxy for the ip */
1548 for(cp = f->ipifc->conv; *cp != nil; cp++){
1549 nifc = (Ipifc*)(*cp)->ptcl;
1550 if(nifc == ifc || !canrlock(nifc))
1554 || (lifc = ipremoteonifc(nifc, ip)) == nil
1555 || (lifc->type & Rptpt) != 0
1560 if((lifc->type & Rv4) == 0){
1561 /* add solicited-node multicast addr */
1564 addselfcache(f, nifc, lifc, a, Rmulti);
1566 remselfcache(f, nifc, lifc, a);
1569 ipifcregisteraddr(f, nifc, lifc, ip);
1576 ipifcadd6(Ipifc *ifc, char **argv, int argc)
1579 char addr[40], preflen[6];
1581 uchar prefix[IPaddrlen];
1587 lifc.validlt = lifc.preflt = ~0UL;
1588 lifc.origint = NOW / 1000;
1592 lifc.preflt = strtoul(argv[6], 0, 10);
1595 lifc.validlt = strtoul(argv[5], 0, 10);
1598 lifc.autoflag = atoi(argv[4]) != 0;
1601 lifc.onlink = atoi(argv[3]) != 0;
1604 plen = atoi(argv[2]);
1612 if (parseip(prefix, argv[1]) != 6 || lifc.validlt < lifc.preflt || plen < 0 ||
1613 plen > 64 || islinklocal(prefix))
1616 /* issue "add" ctl msg for v6 link-local addr and prefix len */
1618 if(m == nil || m->pref2addr == nil)
1620 (*m->pref2addr)(prefix, ifc->mac); /* mac → v6 link-local addr */
1622 sprint(addr, "%I", prefix);
1623 sprint(preflen, "/%d", plen);
1626 params[2] = preflen;
1628 return ipifcadd(ifc, params, 3, 0, &lifc);
1632 ipifcremove6(Ipifc *ifc, char**, int argc)
1642 for(l = &ifc->lifc; (lifc = *l) != nil;) {
1643 if((lifc->type & Rv4) == 0)
1644 if(lifc->validlt != ~0UL && lifc->validlt < now-lifc->origint)
1645 if(ipifcremlifc(ifc, l) == nil)