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 void ipifcregisteraddr(Fs*, Ipifc*, uchar *, uchar *);
65 static void ipifcregisterproxy(Fs*, Ipifc*, uchar*, int);
66 static char* ipifcremlifc(Ipifc*, Iplifc**);
76 v6addrtype(uchar *addr)
78 if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
80 else if(islinklocal(addr) ||
81 isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
87 #define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
88 (lifc)->origint + (lifc)->preflt >= NOW/1000)
91 comprefixlen(uchar *a, uchar *b, int n)
95 for(i = 0; i < n; i++){
96 if((c = a[i] ^ b[i]) == 0)
98 for(i <<= 3; (c & 0x80) == 0; i++)
106 * link in a new medium
109 addipmedium(Medium *med)
113 for(i = 0; i < nelem(media)-1; i++)
121 * find the medium with this name
124 ipfindmedium(char *name)
128 for(mp = media; *mp != nil; mp++)
129 if(strcmp((*mp)->name, name) == 0)
135 * attach a device (or pkt driver) to the interface.
136 * called with c locked
139 ipifcbind(Conv *c, char **argv, int argc)
147 ifc = (Ipifc*)c->ptcl;
149 /* bind the device to the interface */
150 m = ipfindmedium(argv[1]);
152 return "unknown interface type";
157 return "interface already bound";
164 /* do medium specific binding */
165 (*m->bind)(ifc, argc, argv);
167 /* set the bound device name */
169 strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
171 snprint(ifc->dev, sizeof ifc->dev, "%s%d", m->name, c->x);
172 ifc->dev[sizeof(ifc->dev)-1] = 0;
174 /* set up parameters */
176 ifc->mintu = ifc->m->mintu;
177 ifc->maxtu = ifc->m->maxtu;
178 if(ifc->m->unbindonclose == 0)
180 ifc->rp.mflag = 0; /* default not managed */
182 ifc->rp.maxraint = 600000; /* millisecs */
183 ifc->rp.minraint = 200000;
184 ifc->rp.linkmtu = 0; /* no mtu sent */
185 ifc->rp.reachtime = 0;
187 ifc->rp.ttl = MAXTTL;
188 ifc->rp.routerlt = 3 * ifc->rp.maxraint;
190 /* any ancillary structures (like routes) no longer pertain */
193 /* reopen all the queues closed by a previous unbind */
205 * detach a device from an interface, close the interface
206 * called with ifc->conv closed
209 ipifcunbind(Ipifc *ifc)
219 /* disassociate logical interfaces (before zeroing ifc->arg) */
220 while(ifc->lifc != nil){
221 err = ipifcremlifc(ifc, &ifc->lifc);
226 /* disassociate device */
227 if(ifc->m != nil && ifc->m->unbind != nil)
228 (*ifc->m->unbind)(ifc);
229 memset(ifc->dev, 0, sizeof(ifc->dev));
235 /* close queues to stop queuing of packets */
236 qclose(ifc->conv->rq);
237 qclose(ifc->conv->wq);
238 qclose(ifc->conv->sq);
240 /* dissociate routes */
242 if(ifc->m != nil && ifc->m->unbindonclose == 0)
251 char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag"
252 " %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt"
253 " %d pktin %lud pktout %lud errin %lud errout %lud\n";
255 char slineformat[] = " %-40I %-10M %-40I %-12lud %-12lud\n";
258 ipifcstate(Conv *c, char *state, int n)
264 ifc = (Ipifc*)c->ptcl;
265 m = snprint(state, n, sfixedformat,
266 ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
267 ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
268 ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
269 ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
270 ifc->in, ifc->out, ifc->inerr, ifc->outerr);
273 for(lifc = ifc->lifc; lifc != nil && n > m; lifc = lifc->next)
274 m += snprint(state+m, n - m, slineformat, lifc->local,
275 lifc->mask, lifc->remote, lifc->validlt, lifc->preflt);
277 m += snprint(state+m, n - m, "\n");
283 ipifclocal(Conv *c, char *state, int n)
290 ifc = (Ipifc*)c->ptcl;
293 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
294 m += snprint(state+m, n - m, "%-40.40I ->", lifc->local);
295 for(link = lifc->link; link != nil; link = link->lifclink)
296 m += snprint(state+m, n - m, " %-40.40I", link->self->a);
297 m += snprint(state+m, n - m, "\n");
308 ifc = (Ipifc*)c->ptcl;
309 return ifc->m != nil;
313 * called when a process writes to an interface's 'data'
326 ifc = (Ipifc*)c->ptcl;
335 if(ifc->m != nil && ifc->m->pktin != nil)
336 (*ifc->m->pktin)(c->p->f, ifc, bp);
344 * called when a new ipifc structure is created
351 c->rq = qopen(QMAX, 0, 0, 0);
352 c->wq = qopen(QMAX, Qkick, ipifckick, c);
353 c->sq = qopen(QMAX, 0, 0, 0);
354 if(c->rq == nil || c->wq == nil || c->sq == nil)
356 ifc = (Ipifc*)c->ptcl;
364 * called after last close of ipifc data or ctl
365 * called with c locked, we must unlock
372 ifc = (Ipifc*)c->ptcl;
373 if(ifc->m != nil && ifc->m->unbindonclose)
378 * change an interface's mtu
381 ipifcsetmtu(Ipifc *ifc, char **argv, int argc)
385 if(argc < 2 || ifc->m == nil)
387 mtu = strtoul(argv[1], 0, 0);
388 if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu)
395 * add an address to an interface.
398 ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
400 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
401 uchar bcast[IPaddrlen], net[IPaddrlen];
408 memset(ip, 0, IPaddrlen);
409 memset(mask, 0, IPaddrlen);
410 memset(rem, 0, IPaddrlen);
413 if(strcmp(argv[5], "proxy") == 0)
417 mtu = strtoul(argv[4], 0, 0);
420 if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1)
422 parseipmask(mask, argv[2]);
423 maskip(rem, mask, net);
426 if (parseip(ip, argv[1]) == -1)
428 parseipmask(mask, argv[2]);
429 maskip(ip, mask, rem);
430 maskip(rem, mask, net);
433 if (parseip(ip, argv[1]) == -1)
435 memmove(mask, defmask(ip), IPaddrlen);
436 maskip(ip, mask, rem);
437 maskip(rem, mask, net);
443 /* check for point-to-point interface */
444 if(ipcmp(ip, v6loopback) != 0) /* skip v6 loopback, it's a special address */
445 if(ipcmp(mask, IPallbits) == 0)
448 if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0){
455 return "ipifc not yet bound to device";
463 if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
466 /* ignore if this is already a local address for this ifc */
467 if((lifc = iplocalonifc(ifc, ip)) != nil){
469 lifc->onlink = lifcp->onlink;
470 lifc->autoflag = lifcp->autoflag;
471 lifc->validlt = lifcp->validlt;
472 lifc->preflt = lifcp->preflt;
473 lifc->origint = lifcp->origint;
475 if(lifc->tentative != tentative){
476 lifc->tentative = tentative;
484 /* add the address to the list of logical ifc's for this ifc */
485 lifc = smalloc(sizeof(Iplifc));
486 ipmove(lifc->local, ip);
487 ipmove(lifc->mask, mask);
488 ipmove(lifc->remote, rem);
489 ipmove(lifc->net, net);
491 lifc->tentative = tentative;
493 lifc->onlink = lifcp->onlink;
494 lifc->autoflag = lifcp->autoflag;
495 lifc->validlt = lifcp->validlt;
496 lifc->preflt = lifcp->preflt;
497 lifc->origint = lifcp->origint;
498 } else { /* default values */
499 lifc->onlink = lifc->autoflag = 1;
500 lifc->validlt = lifc->preflt = ~0L;
501 lifc->origint = NOW / 1000;
505 for(l = &ifc->lifc; *l != nil; l = &(*l)->next)
509 /* add route for this logical interface */
510 addroute(f, rem, mask, ip, IPallbits, rem, type, ifc, tifc);
511 if(v6addrtype(ip) != linklocalv6)
512 addroute(f, rem, mask, ip, IPnoaddr, rem, type, ifc, tifc);
514 addselfcache(f, ifc, lifc, ip, Runi);
519 ipifcregisterproxy(f, ifc, rem, 1);
524 /* add subnet directed broadcast address to the self cache */
525 for(i = 0; i < IPaddrlen; i++)
526 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
527 addselfcache(f, ifc, lifc, bcast, Rbcast);
529 /* add subnet directed network address to the self cache */
530 for(i = 0; i < IPaddrlen; i++)
531 bcast[i] = (ip[i] & mask[i]) & mask[i];
532 addselfcache(f, ifc, lifc, bcast, Rbcast);
534 /* add network directed broadcast address to the self cache */
535 memmove(mask, defmask(ip), IPaddrlen);
536 for(i = 0; i < IPaddrlen; i++)
537 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
538 addselfcache(f, ifc, lifc, bcast, Rbcast);
540 /* add network directed network address to the self cache */
541 memmove(mask, defmask(ip), IPaddrlen);
542 for(i = 0; i < IPaddrlen; i++)
543 bcast[i] = (ip[i] & mask[i]) & mask[i];
544 addselfcache(f, ifc, lifc, bcast, Rbcast);
546 addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
548 if(ipcmp(ip, v6loopback) == 0) {
549 /* add node-local mcast address */
550 addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
552 /* add route for all node multicast */
553 addroute(f, v6allnodesN, v6allnodesNmask,
555 v6allnodesN, Rmulti, ifc, tifc);
558 /* add all nodes multicast address */
559 addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
561 /* add route for all nodes multicast */
562 addroute(f, v6allnodesL, v6allnodesLmask,
564 v6allnodesL, Rmulti, ifc, tifc);
566 /* add solicited-node multicast address */
567 ipv62smcast(bcast, ip);
568 addselfcache(f, ifc, lifc, bcast, Rmulti);
575 ipifcregisteraddr(f, ifc, ip, ip);
581 * remove a logical interface from an ifc
582 * always called with ifc wlock'd
585 ipifcremlifc(Ipifc *ifc, Iplifc **l)
588 Fs *f = ifc->conv->p->f;
591 return "address not on this interface";
594 /* disassociate any addresses */
595 while(lifc->link != nil)
596 remselfcache(f, ifc, lifc, lifc->link->self->a);
598 /* remove the route for this logical interface */
599 remroute(f, lifc->remote, lifc->mask,
600 lifc->local, IPallbits,
601 lifc->remote, lifc->type, ifc, tifc);
602 if(v6addrtype(lifc->local) != linklocalv6)
603 remroute(f, lifc->remote, lifc->mask,
604 lifc->local, IPnoaddr,
605 lifc->remote, lifc->type, ifc, tifc);
607 /* unregister proxy */
608 if(lifc->type & Rptpt){
609 if(lifc->type & Rproxy)
610 ipifcregisterproxy(f, ifc, lifc->remote, 0);
614 /* remove route for all nodes multicast */
615 if((lifc->type & Rv4) == 0){
616 if(ipcmp(lifc->local, v6loopback) == 0)
617 remroute(f, v6allnodesN, v6allnodesNmask,
618 lifc->local, IPallbits,
619 v6allnodesN, Rmulti, ifc, tifc);
621 remroute(f, v6allnodesL, v6allnodesLmask,
622 lifc->local, IPallbits,
623 v6allnodesL, Rmulti, ifc, tifc);
632 * remove an address from an interface.
633 * called with c->car locked
636 ipifcrem(Ipifc *ifc, char **argv, int argc)
639 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
644 if(parseip(ip, argv[1]) == -1)
646 parseipmask(mask, argv[2]);
648 maskip(ip, mask, rem);
649 else if(parseip(rem, argv[3]) == -1)
653 * find address on this interface and remove from chain.
654 * for pt to pt we actually specify the remote address as the
655 * addresss to remove.
659 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
660 if(ipcmp(ip, lifc->local) == 0
661 && ipcmp(mask, lifc->mask) == 0
662 && ipcmp(rem, lifc->remote) == 0)
666 rv = ipifcremlifc(ifc, l);
672 * associate an address with the interface. This wipes out any previous
673 * addresses. This is a macro that means, remove all the old interfaces
677 ipifcconnect(Conv* c, char **argv, int argc)
682 ifc = (Ipifc*)c->ptcl;
685 return "ipifc not yet bound to device";
688 while(ifc->lifc != nil){
689 err = ipifcremlifc(ifc, &ifc->lifc);
697 err = ipifcadd(ifc, argv, argc, 0, nil);
706 ipifcra6(Ipifc *ifc, char **argv, int argc)
708 int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
713 if(argsleft % 2 != 0)
716 while (argsleft > 1) {
717 if(strcmp(argv[i], "recvra") == 0)
718 ifc->recvra6 = (atoi(argv[i+1]) != 0);
719 else if(strcmp(argv[i], "sendra") == 0)
720 ifc->sendra6 = (atoi(argv[i+1]) != 0);
721 else if(strcmp(argv[i], "mflag") == 0)
722 ifc->rp.mflag = (atoi(argv[i+1]) != 0);
723 else if(strcmp(argv[i], "oflag") == 0)
724 ifc->rp.oflag = (atoi(argv[i+1]) != 0);
725 else if(strcmp(argv[i], "maxraint") == 0)
726 ifc->rp.maxraint = atoi(argv[i+1]);
727 else if(strcmp(argv[i], "minraint") == 0)
728 ifc->rp.minraint = atoi(argv[i+1]);
729 else if(strcmp(argv[i], "linkmtu") == 0)
730 ifc->rp.linkmtu = atoi(argv[i+1]);
731 else if(strcmp(argv[i], "reachtime") == 0)
732 ifc->rp.reachtime = atoi(argv[i+1]);
733 else if(strcmp(argv[i], "rxmitra") == 0)
734 ifc->rp.rxmitra = atoi(argv[i+1]);
735 else if(strcmp(argv[i], "ttl") == 0)
736 ifc->rp.ttl = atoi(argv[i+1]);
737 else if(strcmp(argv[i], "routerlt") == 0)
738 ifc->rp.routerlt = atoi(argv[i+1]);
746 /* consistency check */
747 if(ifc->rp.maxraint < ifc->rp.minraint) {
748 ifc->rp.maxraint = vmax;
749 ifc->rp.minraint = vmin;
756 * non-standard control messages.
757 * called with c->car locked.
760 ipifcctl(Conv* c, char **argv, int argc)
764 ifc = (Ipifc*)c->ptcl;
765 if(strcmp(argv[0], "add") == 0)
766 return ipifcadd(ifc, argv, argc, 0, nil);
767 else if(strcmp(argv[0], "try") == 0)
768 return ipifcadd(ifc, argv, argc, 1, nil);
769 else if(strcmp(argv[0], "remove") == 0)
770 return ipifcrem(ifc, argv, argc);
771 else if(strcmp(argv[0], "unbind") == 0)
772 return ipifcunbind(ifc);
773 else if(strcmp(argv[0], "mtu") == 0)
774 return ipifcsetmtu(ifc, argv, argc);
775 else if(strcmp(argv[0], "iprouting") == 0){
776 iprouting(c->p->f, argc>1? atoi(argv[1]): 1);
779 else if(strcmp(argv[0], "reflect") == 0){
780 ifc->reflect = argc>1? atoi(argv[1]): 1;
783 else if(strcmp(argv[0], "reassemble") == 0){
784 ifc->reassemble = argc>1? atoi(argv[1]): 1;
787 else if(strcmp(argv[0], "add6") == 0)
788 return ipifcadd6(ifc, argv, argc);
789 else if(strcmp(argv[0], "ra6") == 0)
790 return ipifcra6(ifc, argv, argc);
791 return "unsupported ctl";
795 ipifcstats(Proto *ipifc, char *buf, int len)
797 return ipstats(ipifc->f, buf, len);
805 ipifc = smalloc(sizeof(Proto));
806 ipifc->name = "ipifc";
807 ipifc->connect = ipifcconnect;
808 ipifc->announce = nil;
809 ipifc->bind = ipifcbind;
810 ipifc->state = ipifcstate;
811 ipifc->create = ipifccreate;
812 ipifc->close = ipifcclose;
814 ipifc->ctl = ipifcctl;
816 ipifc->stats = ipifcstats;
817 ipifc->inuse = ipifcinuse;
818 ipifc->local = ipifclocal;
820 ipifc->nc = Maxmedia;
821 ipifc->ptclsize = sizeof(Ipifc);
823 f->ipifc = ipifc; /* hack for ipifcremroute, findipifc, ... */
824 f->self = smalloc(sizeof(Ipselftab)); /* hack for ipforme */
830 * add to self routing cache
831 * called with c->car locked
834 addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
840 type |= (lifc->type & Rv4);
848 /* see if the address already exists */
850 for(p = f->self->hash[h]; p != nil; p = p->next)
851 if(ipcmp(a, p->a) == 0)
854 /* allocate a local address and add to hash chain */
856 p = smalloc(sizeof(*p));
859 p->next = f->self->hash[h];
860 f->self->hash[h] = p;
862 /* if the null address, accept all packets */
863 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
864 f->self->acceptall = 1;
867 /* look for a link for this lifc */
868 for(lp = p->link; lp != nil; lp = lp->selflink)
872 /* allocate a lifc-to-local link and link to both */
874 lp = smalloc(sizeof(*lp));
878 lp->selflink = p->link;
880 lp->lifclink = lifc->link;
883 /* add to routing table */
884 addroute(f, a, IPallbits,
886 ((type & (Rbcast|Rmulti)) != 0 || v6addrtype(a) == linklocalv6) ?
887 IPallbits : IPnoaddr,
890 if((type & Rmulti) && ifc->m->addmulti != nil)
891 (*ifc->m->addmulti)(ifc, a, lifc->local);
900 * These structures are unlinked from their chains while
901 * other threads may be using them. To avoid excessive locking,
902 * just put them aside for a while before freeing them.
903 * called with f->self locked
905 static Iplink *freeiplink;
906 static Ipself *freeipself;
909 iplinkfree(Iplink *p)
915 for(np = *l; np != nil; np = *l){
916 if((long)(now - np->expire) >= 0){
923 p->expire = now + 5000; /* give other threads 5 secs to get out */
929 ipselffree(Ipself *p)
935 for(np = *l; np != nil; np = *l){
936 if((long)(now - np->expire) >= 0){
943 p->expire = now + 5000; /* give other threads 5 secs to get out */
949 * Decrement reference for this address on this link.
950 * Unlink from selftab if this is the last ref.
951 * called with c->car locked
954 remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
957 Iplink *link, **l_self, **l_lifc;
961 /* find the unique selftab entry */
962 l = &f->self->hash[hashipa(a)];
963 for(p = *l; p != nil; p = *l){
964 if(ipcmp(p->a, a) == 0)
973 * walk down links from an ifc looking for one
974 * that matches the selftab entry
976 l_lifc = &lifc->link;
977 for(link = *l_lifc; link != nil; link = *l_lifc){
980 l_lifc = &link->lifclink;
987 * walk down the links from the selftab looking for
988 * the one we just found
991 for(link = *l_self; link != nil; link = *l_self){
994 l_self = &link->selflink;
998 panic("remselfcache");
1000 if(--(link->ref) != 0)
1003 /* remove from routing table */
1004 remroute(f, a, IPallbits,
1006 ((p->type & (Rbcast|Rmulti)) != 0 || v6addrtype(a) == linklocalv6) ?
1007 IPallbits : IPnoaddr,
1008 a, p->type, ifc, tifc);
1010 if((p->type & Rmulti) && ifc->m->remmulti != nil){
1012 (*ifc->m->remmulti)(ifc, a, lifc->local);
1017 /* ref == 0, remove from both chains and free the link */
1018 *l_lifc = link->lifclink;
1019 *l_self = link->selflink;
1025 /* if null address, forget */
1026 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1027 f->self->acceptall = 0;
1029 /* no more links, remove from hash and free */
1038 ipselftabread(Fs *f, char *cp, ulong offset, int n)
1040 int i, m, nifc, off;
1048 for(i = 0; i < NHASH && m < n; i++){
1049 for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
1051 for(link = p->link; link != nil; link = link->selflink)
1053 routetype(p->type, state);
1054 m += snprint(cp + m, n - m, "%-44.44I %2.2d %4.4s\n",
1074 ipforme(Fs *f, uchar *addr)
1078 for(p = f->self->hash[hashipa(addr)]; p != nil; p = p->next)
1079 if(ipcmp(addr, p->a) == 0)
1080 return p->type & (Runi|Rbcast|Rmulti);
1082 /* hack to say accept anything */
1083 if(f->self->acceptall)
1090 * find the ifc on same net as the remote system. If none,
1094 findipifc(Fs *f, uchar *local, uchar *remote, int type)
1096 uchar gnet[IPaddrlen];
1104 for(cp = f->ipifc->conv; *cp != nil; cp++){
1105 ifc = (Ipifc*)(*cp)->ptcl;
1107 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1109 if(ipcmp(remote, lifc->local) == 0){
1114 } else if(type & (Rbcast|Rmulti)) {
1115 if(ipcmp(local, lifc->local) == 0)
1118 maskip(remote, lifc->mask, gnet);
1119 if(ipcmp(gnet, lifc->net) == 0){
1120 spec = comprefixlen(remote, lifc->local, IPaddrlen);
1133 findipifcstr(Fs *f, char *s)
1135 uchar ip[IPaddrlen];
1140 x = strtol(s, &p, 10);
1141 if(p > s && *p == '\0'){
1144 if(x < f->ipifc->nc && (c = f->ipifc->conv[x]) != nil && ipifcinuse(c))
1145 return (Ipifc*)c->ptcl;
1147 if(parseip(ip, s) != -1)
1148 return findipifc(f, ip, ip, Runi);
1153 * find "best" (global > link local > unspecified)
1154 * local address; address must be current.
1157 findprimaryipv6(Fs *f, uchar *local)
1164 ipmove(local, v6Unspecified);
1165 atype = unspecifiedv6;
1167 for(cp = f->ipifc->conv; *cp != nil; cp++){
1168 ifc = (Ipifc*)(*cp)->ptcl;
1170 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1171 atypel = v6addrtype(lifc->local);
1172 if(atypel > atype && v6addrcurr(lifc)) {
1173 ipmove(local, lifc->local);
1175 if(atype == globalv6){
1186 * returns first v4 address configured
1189 findprimaryipv4(Fs *f, uchar *local)
1195 /* find first ifc local address */
1196 for(cp = f->ipifc->conv; *cp != nil; cp++){
1197 ifc = (Ipifc*)(*cp)->ptcl;
1199 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1200 if((lifc->type & Rv4) != 0){
1201 ipmove(local, lifc->local);
1208 ipmove(local, IPnoaddr);
1212 * return v4 address associated with an interface close to remote
1215 ipv4local(Ipifc *ifc, uchar *local, uchar *remote)
1221 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1222 if((lifc->type & Rv4) == 0)
1224 a = comprefixlen(lifc->local+IPv4off, remote, IPv4addrlen);
1227 memmove(local, lifc->local+IPv4off, IPv4addrlen);
1234 * return v6 address associated with an interface close to remote
1237 ipv6local(Ipifc *ifc, uchar *local, uchar *remote)
1248 ipmove(local, v4prefix);
1249 return ipv4local(ifc, local+IPv4off, remote+IPv4off);
1252 atype = v6addrtype(remote);
1253 ipmove(local, v6Unspecified);
1254 b.atype = unknownv6;
1258 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1262 a.atype = v6addrtype(lifc->local);
1263 a.deprecated = !v6addrcurr(lifc);
1264 a.comprefixlen = comprefixlen(lifc->local, remote, IPaddrlen);
1266 /* prefer appropriate scope */
1267 if(a.atype != b.atype){
1268 if(a.atype > b.atype && b.atype < atype ||
1269 a.atype < b.atype && b.atype > atype)
1273 /* prefer non-deprecated addresses */
1274 if(a.deprecated != b.deprecated){
1279 /* prefer longer common prefix */
1280 if(a.comprefixlen != b.comprefixlen){
1281 if(a.comprefixlen > b.comprefixlen)
1288 ipmove(local, lifc->local);
1291 return b.atype >= atype;
1295 findlocalip(Fs *f, uchar *local, uchar *remote)
1302 for(cp = f->ipifc->conv; *cp != nil; cp++){
1303 ifc = (Ipifc*)(*cp)->ptcl;
1305 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1309 r = v6lookup(f, remote, lifc->local, nil);
1310 if(r == nil || (nifc = r->ifc) == nil)
1313 ipmove(local, remote);
1317 if(nifc != ifc) rlock(nifc);
1318 if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){
1319 ipmove(local, v4prefix);
1320 if(ipv4local(nifc, local+IPv4off, r->v4.gate)){
1321 if(nifc != ifc) runlock(nifc);
1326 if(ipv6local(nifc, local, remote)){
1327 if(nifc != ifc) runlock(nifc);
1331 if(nifc != ifc) runlock(nifc);
1336 findprimaryipv4(f, local);
1338 findprimaryipv6(f, local);
1343 * see if this address is bound to the interface
1346 iplocalonifc(Ipifc *ifc, uchar *ip)
1350 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
1351 if(ipcmp(ip, lifc->local) == 0)
1358 ipremoteonifc(Ipifc *ifc, uchar *ip)
1360 uchar net[IPaddrlen];
1363 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1364 maskip(ip, lifc->mask, net);
1365 if(ipcmp(net, lifc->remote) == 0)
1373 * See if we're proxying for this address on this interface
1376 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
1380 /* see if this is a direct connected pt to pt address */
1381 r = v6lookup(f, ip, ip, nil);
1382 if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
1385 return ipremoteonifc(ifc, ip) != nil;
1389 * return multicast version if any
1392 ipismulticast(uchar *ip)
1395 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1398 else if(ip[0] == 0xff)
1404 * add a multicast address to an interface, called with c->car locked
1407 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
1409 Ipmulti *multi, **l;
1414 for(l = &c->multi; *l != nil; l = &(*l)->next)
1415 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1416 return; /* it's already there */
1418 multi = *l = smalloc(sizeof(*multi));
1419 ipmove(multi->ma, ma);
1420 ipmove(multi->ia, ia);
1424 if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
1430 if((lifc = iplocalonifc(ifc, ia)) != nil)
1431 addselfcache(f, ifc, lifc, ma, Rmulti);
1439 * remove a multicast address from an interface, called with c->car locked
1442 ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
1444 Ipmulti *multi, **l;
1449 for(l = &c->multi; *l != nil; l = &(*l)->next)
1450 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1455 return; /* we don't have it open */
1461 if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
1467 if((lifc = iplocalonifc(ifc, ia)) != nil)
1468 remselfcache(f, ifc, lifc, ma);
1475 /* register the address on this network for address resolution */
1477 ipifcregisteraddr(Fs *f, Ipifc *ifc, uchar *ia, uchar *ip)
1484 print("ipifcregisteraddr %s %I %I: %s\n", ifc->dev, ia, ip, up->errstr);
1487 lifc = iplocalonifc(ifc, ia);
1488 if(lifc != nil && ifc->m != nil && ifc->m->areg != nil)
1489 (*ifc->m->areg)(f, ifc, lifc, ip);
1495 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip, int add)
1502 /* register the address on any interface that will proxy for the ip */
1503 for(cp = f->ipifc->conv; *cp != nil; cp++){
1504 nifc = (Ipifc*)(*cp)->ptcl;
1510 || (lifc = ipremoteonifc(nifc, ip)) == nil
1511 || (lifc->type & Rptpt) != 0
1516 if((lifc->type & Rv4) == 0){
1517 /* add solicited-node multicast addr */
1520 addselfcache(f, nifc, lifc, a, Rmulti);
1522 remselfcache(f, nifc, lifc, a);
1524 ipmove(a, lifc->local);
1529 ipifcregisteraddr(f, nifc, a, ip);
1534 ipifcadd6(Ipifc *ifc, char**argv, int argc)
1537 char addr[40], preflen[6];
1539 uchar prefix[IPaddrlen];
1546 lifc.origint = NOW / 1000;
1550 lifc.preflt = atoi(argv[6]);
1553 lifc.validlt = atoi(argv[5]);
1556 lifc.autoflag = atoi(argv[4]) != 0;
1559 lifc.onlink = atoi(argv[3]) != 0;
1562 plen = atoi(argv[2]);
1570 if (parseip(prefix, argv[1]) != 6 || lifc.validlt < lifc.preflt || plen < 0 ||
1571 plen > 64 || islinklocal(prefix))
1574 /* issue "add" ctl msg for v6 link-local addr and prefix len */
1575 if(ifc->m->pref2addr == nil)
1577 (*ifc->m->pref2addr)(prefix, ifc->mac); /* mac → v6 link-local addr */
1579 sprint(addr, "%I", prefix);
1580 sprint(preflen, "/%d", plen);
1583 params[2] = preflen;
1585 return ipifcadd(ifc, params, 3, 0, &lifc);