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 ipifcregisterproxy(Fs*, Ipifc*, uchar*, int);
65 static char* ipifcremlifc(Ipifc*, Iplifc**);
75 v6addrtype(uchar *addr)
77 if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
79 else if(islinklocal(addr) ||
80 isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
86 #define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
87 (lifc)->origint + (lifc)->preflt >= NOW/1000)
92 if(v6addrtype(a) == linklocalv6)
98 comprefixlen(uchar *a, uchar *b, int n)
102 for(i = 0; i < n; i++){
103 if((c = a[i] ^ b[i]) == 0)
105 for(i <<= 3; (c & 0x80) == 0; i++)
113 * link in a new medium
116 addipmedium(Medium *med)
120 for(i = 0; i < nelem(media)-1; i++)
128 * find the medium with this name
131 ipfindmedium(char *name)
135 for(mp = media; *mp != nil; mp++)
136 if(strcmp((*mp)->name, name) == 0)
142 * attach a device (or pkt driver) to the interface.
143 * called with c locked
146 ipifcbind(Conv *c, char **argv, int argc)
154 ifc = (Ipifc*)c->ptcl;
156 /* bind the device to the interface */
157 m = ipfindmedium(argv[1]);
159 return "unknown interface type";
164 return "interface already bound";
171 /* do medium specific binding */
172 (*m->bind)(ifc, argc, argv);
174 /* set the bound device name */
176 strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
178 snprint(ifc->dev, sizeof ifc->dev, "%s%d", m->name, c->x);
179 ifc->dev[sizeof(ifc->dev)-1] = 0;
181 /* set up parameters */
183 ifc->mintu = ifc->m->mintu;
184 ifc->maxtu = ifc->m->maxtu;
185 if(ifc->m->unbindonclose == 0)
187 ifc->rp.mflag = 0; /* default not managed */
189 ifc->rp.maxraint = 600000; /* millisecs */
190 ifc->rp.minraint = 200000;
191 ifc->rp.linkmtu = 0; /* no mtu sent */
192 ifc->rp.reachtime = 0;
194 ifc->rp.ttl = MAXTTL;
195 ifc->rp.routerlt = 3 * ifc->rp.maxraint;
197 /* any ancillary structures (like routes) no longer pertain */
200 /* reopen all the queues closed by a previous unbind */
212 * detach a device from an interface, close the interface
213 * called with ifc->conv closed
216 ipifcunbind(Ipifc *ifc)
226 /* disassociate logical interfaces (before zeroing ifc->arg) */
227 while(ifc->lifc != nil){
228 err = ipifcremlifc(ifc, &ifc->lifc);
230 * note: err non-zero means lifc not found,
231 * which can't happen in this case.
237 /* disassociate device */
238 if(ifc->m != nil && ifc->m->unbind != nil)
239 (*ifc->m->unbind)(ifc);
240 memset(ifc->dev, 0, sizeof(ifc->dev));
244 /* close queues to stop queuing of packets */
245 qclose(ifc->conv->rq);
246 qclose(ifc->conv->wq);
247 qclose(ifc->conv->sq);
249 /* dissociate routes */
251 if(ifc->m != nil && ifc->m->unbindonclose == 0)
260 char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag"
261 " %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt"
262 " %d pktin %lud pktout %lud errin %lud errout %lud\n";
264 char slineformat[] = " %-40I %-10M %-40I %-12lud %-12lud\n";
267 ipifcstate(Conv *c, char *state, int n)
273 ifc = (Ipifc*)c->ptcl;
274 m = snprint(state, n, sfixedformat,
275 ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
276 ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
277 ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
278 ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
279 ifc->in, ifc->out, ifc->inerr, ifc->outerr);
282 for(lifc = ifc->lifc; lifc && n > m; lifc = lifc->next)
283 m += snprint(state+m, n - m, slineformat, lifc->local,
284 lifc->mask, lifc->remote, lifc->validlt, lifc->preflt);
286 m += snprint(state+m, n - m, "\n");
292 ipifclocal(Conv *c, char *state, int n)
299 ifc = (Ipifc*)c->ptcl;
303 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
304 m += snprint(state+m, n - m, "%-40.40I ->", lifc->local);
305 for(link = lifc->link; link != nil; link = link->lifclink)
306 m += snprint(state+m, n - m, " %-40.40I", link->self->a);
307 m += snprint(state+m, n - m, "\n");
318 ifc = (Ipifc*)c->ptcl;
319 return ifc->m != nil;
323 * called when a process writes to an interface's 'data'
336 ifc = (Ipifc*)c->ptcl;
345 if(ifc->m != nil && ifc->m->pktin != nil)
346 (*ifc->m->pktin)(c->p->f, ifc, bp);
354 * called when a new ipifc structure is created
361 c->rq = qopen(QMAX, 0, 0, 0);
362 c->wq = qopen(QMAX, Qkick, ipifckick, c);
363 c->sq = qopen(QMAX, 0, 0, 0);
364 if(c->rq == nil || c->wq == nil || c->sq == nil)
366 ifc = (Ipifc*)c->ptcl;
374 * called after last close of ipifc data or ctl
375 * called with c locked, we must unlock
382 ifc = (Ipifc*)c->ptcl;
383 if(ifc->m != nil && ifc->m->unbindonclose)
388 * change an interface's mtu
391 ipifcsetmtu(Ipifc *ifc, char **argv, int argc)
395 if(argc < 2 || ifc->m == nil)
397 mtu = strtoul(argv[1], 0, 0);
398 if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu)
405 * add an address to an interface.
408 ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
410 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
411 uchar bcast[IPaddrlen], net[IPaddrlen];
417 if((m = ifc->m) == nil)
418 return "ipifc not yet bound to device";
423 memset(ip, 0, IPaddrlen);
424 memset(mask, 0, IPaddrlen);
425 memset(rem, 0, IPaddrlen);
428 if(strcmp(argv[5], "proxy") == 0)
432 mtu = strtoul(argv[4], 0, 0);
433 if(mtu >= m->mintu && mtu <= m->maxtu)
437 if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1)
439 parseipmask(mask, argv[2]);
440 maskip(rem, mask, net);
443 if (parseip(ip, argv[1]) == -1)
445 parseipmask(mask, argv[2]);
446 maskip(ip, mask, rem);
447 maskip(rem, mask, net);
450 if (parseip(ip, argv[1]) == -1)
452 memmove(mask, defmask(ip), IPaddrlen);
453 maskip(ip, mask, rem);
454 maskip(rem, mask, net);
460 /* check for point-to-point interface */
461 if(ipcmp(ip, v6loopback) != 0) /* skip v6 loopback, it's a special address */
462 if(ipcmp(mask, IPallbits) == 0)
465 if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0){
476 /* ignore if this is already a local address for this ifc */
477 if((lifc = iplocalonifc(ifc, ip)) != nil){
479 lifc->onlink = lifcp->onlink;
480 lifc->autoflag = lifcp->autoflag;
481 lifc->validlt = lifcp->validlt;
482 lifc->preflt = lifcp->preflt;
483 lifc->origint = lifcp->origint;
485 if(lifc->tentative != tentative){
486 lifc->tentative = tentative;
494 /* add the address to the list of logical ifc's for this ifc */
495 lifc = smalloc(sizeof(Iplifc));
496 ipmove(lifc->local, ip);
497 ipmove(lifc->mask, mask);
498 ipmove(lifc->remote, rem);
499 ipmove(lifc->net, net);
501 lifc->tentative = tentative;
503 lifc->onlink = lifcp->onlink;
504 lifc->autoflag = lifcp->autoflag;
505 lifc->validlt = lifcp->validlt;
506 lifc->preflt = lifcp->preflt;
507 lifc->origint = lifcp->origint;
508 } else { /* default values */
509 lifc->onlink = lifc->autoflag = 1;
510 lifc->validlt = lifc->preflt = ~0L;
511 lifc->origint = NOW / 1000;
515 for(l = &ifc->lifc; *l != nil; l = &(*l)->next)
519 addroute(f, rem, mask, ip, defsmask(ip), rem, type, ifc, tifc);
521 addselfcache(f, ifc, lifc, ip, Runi);
526 ipifcregisterproxy(f, ifc, rem, 1);
531 /* add subnet directed broadcast address to the self cache */
532 for(i = 0; i < IPaddrlen; i++)
533 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
534 addselfcache(f, ifc, lifc, bcast, Rbcast);
536 /* add subnet directed network address to the self cache */
537 for(i = 0; i < IPaddrlen; i++)
538 bcast[i] = (ip[i] & mask[i]) & mask[i];
539 addselfcache(f, ifc, lifc, bcast, Rbcast);
541 /* add network directed broadcast address to the self cache */
542 memmove(mask, defmask(ip), IPaddrlen);
543 for(i = 0; i < IPaddrlen; i++)
544 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
545 addselfcache(f, ifc, lifc, bcast, Rbcast);
547 /* add network directed network address to the self cache */
548 memmove(mask, defmask(ip), IPaddrlen);
549 for(i = 0; i < IPaddrlen; i++)
550 bcast[i] = (ip[i] & mask[i]) & mask[i];
551 addselfcache(f, ifc, lifc, bcast, Rbcast);
553 addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
555 if(ipcmp(ip, v6loopback) == 0) {
556 /* add node-local mcast address */
557 addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
559 /* add route for all node multicast */
560 addroute(f, v6allnodesN, v6allnodesNmask,
562 v6allnodesN, Rmulti, ifc, tifc);
565 /* add all nodes multicast address */
566 addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
568 /* add route for all nodes multicast */
569 addroute(f, v6allnodesL, v6allnodesLmask,
571 v6allnodesL, Rmulti, ifc, tifc);
573 /* add solicited-node multicast address */
574 ipv62smcast(bcast, ip);
575 addselfcache(f, ifc, lifc, bcast, Rmulti);
582 /* register the address on this network for address resolution */
584 (*m->areg)(f, ifc, ip, ip);
590 * remove a logical interface from an ifc
591 * always called with ifc wlock'd
594 ipifcremlifc(Ipifc *ifc, Iplifc **l)
597 Fs *f = ifc->conv->p->f;
600 return "address not on this interface";
603 /* disassociate any addresses */
604 while(lifc->link != nil)
605 remselfcache(f, ifc, lifc, lifc->link->self->a);
607 /* remove the route for this logical interface */
608 remroute(f, lifc->remote, lifc->mask,
609 lifc->local, defsmask(lifc->local),
610 lifc->remote, lifc->type, ifc, tifc);
612 /* unregister proxy */
613 if(lifc->type & Rptpt){
614 if(lifc->type & Rproxy)
615 ipifcregisterproxy(f, ifc, lifc->remote, 0);
619 /* remove route for all nodes multicast */
620 if((lifc->type & Rv4) == 0){
621 if(ipcmp(lifc->local, v6loopback) == 0)
622 remroute(f, v6allnodesN, v6allnodesNmask,
623 lifc->local, IPallbits,
624 v6allnodesN, Rmulti, ifc, tifc);
626 remroute(f, v6allnodesL, v6allnodesLmask,
627 lifc->local, IPallbits,
628 v6allnodesL, Rmulti, ifc, tifc);
637 * remove an address from an interface.
638 * called with c->car locked
641 ipifcrem(Ipifc *ifc, char **argv, int argc)
644 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
649 if(parseip(ip, argv[1]) == -1)
651 parseipmask(mask, argv[2]);
653 maskip(ip, mask, rem);
654 else if(parseip(rem, argv[3]) == -1)
658 * find address on this interface and remove from chain.
659 * for pt to pt we actually specify the remote address as the
660 * addresss to remove.
664 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
665 if(ipcmp(ip, lifc->local) == 0
666 && ipcmp(mask, lifc->mask) == 0
667 && ipcmp(rem, lifc->remote) == 0)
671 rv = ipifcremlifc(ifc, l);
677 * associate an address with the interface. This wipes out any previous
678 * addresses. This is a macro that means, remove all the old interfaces
682 ipifcconnect(Conv* c, char **argv, int argc)
687 ifc = (Ipifc*)c->ptcl;
690 return "ipifc not yet bound to device";
693 while(ifc->lifc != nil){
694 err = ipifcremlifc(ifc, &ifc->lifc);
702 err = ipifcadd(ifc, argv, argc, 0, nil);
711 ipifcra6(Ipifc *ifc, char **argv, int argc)
713 int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
718 if(argsleft % 2 != 0)
721 while (argsleft > 1) {
722 if(strcmp(argv[i], "recvra") == 0)
723 ifc->recvra6 = (atoi(argv[i+1]) != 0);
724 else if(strcmp(argv[i], "sendra") == 0)
725 ifc->sendra6 = (atoi(argv[i+1]) != 0);
726 else if(strcmp(argv[i], "mflag") == 0)
727 ifc->rp.mflag = (atoi(argv[i+1]) != 0);
728 else if(strcmp(argv[i], "oflag") == 0)
729 ifc->rp.oflag = (atoi(argv[i+1]) != 0);
730 else if(strcmp(argv[i], "maxraint") == 0)
731 ifc->rp.maxraint = atoi(argv[i+1]);
732 else if(strcmp(argv[i], "minraint") == 0)
733 ifc->rp.minraint = atoi(argv[i+1]);
734 else if(strcmp(argv[i], "linkmtu") == 0)
735 ifc->rp.linkmtu = atoi(argv[i+1]);
736 else if(strcmp(argv[i], "reachtime") == 0)
737 ifc->rp.reachtime = atoi(argv[i+1]);
738 else if(strcmp(argv[i], "rxmitra") == 0)
739 ifc->rp.rxmitra = atoi(argv[i+1]);
740 else if(strcmp(argv[i], "ttl") == 0)
741 ifc->rp.ttl = atoi(argv[i+1]);
742 else if(strcmp(argv[i], "routerlt") == 0)
743 ifc->rp.routerlt = atoi(argv[i+1]);
751 /* consistency check */
752 if(ifc->rp.maxraint < ifc->rp.minraint) {
753 ifc->rp.maxraint = vmax;
754 ifc->rp.minraint = vmin;
761 * non-standard control messages.
762 * called with c->car locked.
765 ipifcctl(Conv* c, char **argv, int argc)
770 ifc = (Ipifc*)c->ptcl;
771 if(strcmp(argv[0], "add") == 0)
772 return ipifcadd(ifc, argv, argc, 0, nil);
773 else if(strcmp(argv[0], "try") == 0)
774 return ipifcadd(ifc, argv, argc, 1, nil);
775 else if(strcmp(argv[0], "remove") == 0)
776 return ipifcrem(ifc, argv, argc);
777 else if(strcmp(argv[0], "unbind") == 0)
778 return ipifcunbind(ifc);
779 else if(strcmp(argv[0], "mtu") == 0)
780 return ipifcsetmtu(ifc, argv, argc);
781 else if(strcmp(argv[0], "reassemble") == 0){
785 else if(strcmp(argv[0], "iprouting") == 0){
789 iprouting(c->p->f, i);
792 else if(strcmp(argv[0], "add6") == 0)
793 return ipifcadd6(ifc, argv, argc);
794 else if(strcmp(argv[0], "ra6") == 0)
795 return ipifcra6(ifc, argv, argc);
796 return "unsupported ctl";
800 ipifcstats(Proto *ipifc, char *buf, int len)
802 return ipstats(ipifc->f, buf, len);
810 ipifc = smalloc(sizeof(Proto));
811 ipifc->name = "ipifc";
812 ipifc->connect = ipifcconnect;
813 ipifc->announce = nil;
814 ipifc->bind = ipifcbind;
815 ipifc->state = ipifcstate;
816 ipifc->create = ipifccreate;
817 ipifc->close = ipifcclose;
819 ipifc->ctl = ipifcctl;
821 ipifc->stats = ipifcstats;
822 ipifc->inuse = ipifcinuse;
823 ipifc->local = ipifclocal;
825 ipifc->nc = Maxmedia;
826 ipifc->ptclsize = sizeof(Ipifc);
828 f->ipifc = ipifc; /* hack for ipifcremroute, findipifc, ... */
829 f->self = smalloc(sizeof(Ipselftab)); /* hack for ipforme */
835 * add to self routing cache
836 * called with c->car locked
839 addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
845 type |= (lifc->type & Rv4);
853 /* see if the address already exists */
855 for(p = f->self->hash[h]; p != nil; p = p->next)
856 if(ipcmp(a, p->a) == 0)
859 /* allocate a local address and add to hash chain */
861 p = smalloc(sizeof(*p));
864 p->next = f->self->hash[h];
865 f->self->hash[h] = p;
867 /* if the null address, accept all packets */
868 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
869 f->self->acceptall = 1;
872 /* look for a link for this lifc */
873 for(lp = p->link; lp != nil; lp = lp->selflink)
877 /* allocate a lifc-to-local link and link to both */
879 lp = smalloc(sizeof(*lp));
883 lp->selflink = p->link;
885 lp->lifclink = lifc->link;
888 /* add to routing table */
889 addroute(f, a, IPallbits,
890 lifc->local, defsmask(a),
893 if((type & Rmulti) && ifc->m->addmulti != nil)
894 (*ifc->m->addmulti)(ifc, a, lifc->local);
903 * These structures are unlinked from their chains while
904 * other threads may be using them. To avoid excessive locking,
905 * just put them aside for a while before freeing them.
906 * called with f->self locked
908 static Iplink *freeiplink;
909 static Ipself *freeipself;
912 iplinkfree(Iplink *p)
918 for(np = *l; np != nil; np = *l){
919 if((long)(now - np->expire) >= 0){
926 p->expire = now + 5000; /* give other threads 5 secs to get out */
932 ipselffree(Ipself *p)
938 for(np = *l; np != nil; np = *l){
939 if((long)(now - np->expire) >= 0){
946 p->expire = now + 5000; /* give other threads 5 secs to get out */
952 * Decrement reference for this address on this link.
953 * Unlink from selftab if this is the last ref.
954 * called with c->car locked
957 remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
960 Iplink *link, **l_self, **l_lifc;
964 /* find the unique selftab entry */
965 l = &f->self->hash[hashipa(a)];
966 for(p = *l; p != nil; p = *l){
967 if(ipcmp(p->a, a) == 0)
976 * walk down links from an ifc looking for one
977 * that matches the selftab entry
979 l_lifc = &lifc->link;
980 for(link = *l_lifc; link != nil; link = *l_lifc){
983 l_lifc = &link->lifclink;
990 * walk down the links from the selftab looking for
991 * the one we just found
994 for(link = *l_self; link != nil; link = *l_self){
997 l_self = &link->selflink;
1001 panic("remselfcache");
1003 if(--(link->ref) != 0)
1006 /* remove from routing table */
1007 remroute(f, a, IPallbits,
1008 lifc->local, defsmask(a),
1009 a, p->type, ifc, tifc);
1011 if((p->type & Rmulti) && ifc->m->remmulti != nil){
1013 (*ifc->m->remmulti)(ifc, a, lifc->local);
1018 /* ref == 0, remove from both chains and free the link */
1019 *l_lifc = link->lifclink;
1020 *l_self = link->selflink;
1026 /* if null address, forget */
1027 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1028 f->self->acceptall = 0;
1030 /* no more links, remove from hash and free */
1039 ipselftabread(Fs *f, char *cp, ulong offset, int n)
1041 int i, m, nifc, off;
1049 for(i = 0; i < NHASH && m < n; i++){
1050 for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
1052 for(link = p->link; link != nil; link = link->selflink)
1054 routetype(p->type, state);
1055 m += snprint(cp + m, n - m, "%-44.44I %2.2d %4.4s\n",
1068 iptentative(Fs *f, uchar *addr)
1072 for(p = f->self->hash[hashipa(addr)]; p != nil; p = p->next)
1073 if(ipcmp(addr, p->a) == 0)
1074 return p->link->lifc->tentative;
1087 ipforme(Fs *f, uchar *addr)
1091 for(p = f->self->hash[hashipa(addr)]; p != nil; p = p->next)
1092 if(ipcmp(addr, p->a) == 0)
1093 return p->type & (Runi|Rbcast|Rmulti);
1095 /* hack to say accept anything */
1096 if(f->self->acceptall)
1103 * find the ifc on same net as the remote system. If none,
1107 findipifc(Fs *f, uchar *local, uchar *remote, int type)
1109 uchar gnet[IPaddrlen];
1118 /* find most specific match */
1119 e = &f->ipifc->conv[f->ipifc->nc];
1120 for(cp = f->ipifc->conv; cp < e; cp++){
1123 ifc = (Ipifc*)(*cp)->ptcl;
1124 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1126 if(ipcmp(remote, lifc->local) == 0)
1128 } else if(type & (Rbcast|Rmulti)) {
1129 if(ipcmp(local, lifc->local) == 0)
1132 maskip(remote, lifc->mask, gnet);
1133 if(ipcmp(gnet, lifc->net) == 0){
1134 spec = comprefixlen(remote, lifc->local, IPaddrlen);
1146 findipifcstr(Fs *f, char *s)
1148 uchar ip[IPaddrlen];
1153 x = strtol(s, &p, 10);
1154 if(p > s && *p == '\0'){
1157 if(x < f->ipifc->nc && (c = f->ipifc->conv[x]) != nil)
1158 return (Ipifc*)c->ptcl;
1160 if(parseip(ip, s) != -1)
1161 return findipifc(f, IPnoaddr, ip, Runi);
1166 findprimaryipv6(Fs *f, uchar *local)
1173 ipmove(local, v6Unspecified);
1174 atype = unspecifiedv6;
1177 * find "best" (global > link local > unspecified)
1178 * local address; address must be current.
1180 e = &f->ipifc->conv[f->ipifc->nc];
1181 for(cp = f->ipifc->conv; cp < e; cp++){
1184 ifc = (Ipifc*)(*cp)->ptcl;
1185 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1186 atypel = v6addrtype(lifc->local);
1187 if(atypel > atype && v6addrcurr(lifc)) {
1188 ipmove(local, lifc->local);
1190 if(atype == globalv6)
1198 * returns first v4 address configured
1201 findprimaryipv4(Fs *f, uchar *local)
1207 /* find first ifc local address */
1208 e = &f->ipifc->conv[f->ipifc->nc];
1209 for(cp = f->ipifc->conv; cp < e; cp++){
1212 ifc = (Ipifc*)(*cp)->ptcl;
1213 if((lifc = ifc->lifc) != nil && (lifc->type & Rv4) != 0){
1214 ipmove(local, lifc->local);
1218 ipmove(local, IPnoaddr);
1222 * return v4 address associated with an interface close to remote
1225 ipv4local(Ipifc *ifc, uchar *local, uchar *remote)
1231 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1232 if((lifc->type & Rv4) == 0)
1234 a = comprefixlen(lifc->local+IPv4off, remote, IPv4addrlen);
1237 memmove(local, lifc->local+IPv4off, IPv4addrlen);
1244 * return v6 address associated with an interface close to remote
1247 ipv6local(Ipifc *ifc, uchar *local, uchar *remote)
1258 ipmove(local, v4prefix);
1259 return ipv4local(ifc, local+IPv4off, remote+IPv4off);
1262 atype = v6addrtype(remote);
1263 ipmove(local, v6Unspecified);
1264 b.atype = unknownv6;
1268 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1272 a.atype = v6addrtype(lifc->local);
1273 a.deprecated = !v6addrcurr(lifc);
1274 a.comprefixlen = comprefixlen(lifc->local, remote, IPaddrlen);
1276 /* prefer appropriate scope */
1277 if(a.atype != b.atype){
1278 if(a.atype > b.atype && b.atype < atype ||
1279 a.atype < b.atype && b.atype > atype)
1283 /* prefer non-deprecated addresses */
1284 if(a.deprecated != b.deprecated){
1289 /* prefer longer common prefix */
1290 if(a.comprefixlen != b.comprefixlen){
1291 if(a.comprefixlen > b.comprefixlen)
1298 ipmove(local, lifc->local);
1301 return b.atype >= atype;
1305 findlocalip(Fs *f, uchar *local, uchar *remote)
1313 e = &f->ipifc->conv[f->ipifc->nc];
1314 for(cp = f->ipifc->conv; cp < e; cp++){
1317 ifc = (Ipifc*)(*cp)->ptcl;
1318 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1321 r = v6lookup(f, remote, lifc->local, nil);
1322 if(r == nil || (ifc = r->ifc) == nil)
1325 ipmove(local, remote);
1328 if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){
1329 ipmove(local, v4prefix);
1330 if(ipv4local(ifc, local+IPv4off, r->v4.gate))
1333 if(ipv6local(ifc, local, remote))
1338 findprimaryipv4(f, local);
1340 findprimaryipv6(f, local);
1347 * see if this address is bound to the interface
1350 iplocalonifc(Ipifc *ifc, uchar *ip)
1354 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
1355 if(ipcmp(ip, lifc->local) == 0)
1362 ipremoteonifc(Ipifc *ifc, uchar *ip)
1364 uchar net[IPaddrlen];
1367 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1368 maskip(ip, lifc->mask, net);
1369 if(ipcmp(net, lifc->remote) == 0)
1377 * See if we're proxying for this address on this interface
1380 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
1384 /* see if this is a direct connected pt to pt address */
1385 r = v6lookup(f, ip, ip, nil);
1386 if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
1389 return ipremoteonifc(ifc, ip) != nil;
1393 * return multicast version if any
1396 ipismulticast(uchar *ip)
1399 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1402 else if(ip[0] == 0xff)
1410 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1412 else if(ipcmp(ip, IPv4bcast) == 0)
1415 else if(ip[0] == 0xff)
1422 * add a multicast address to an interface, called with c->car locked
1425 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
1427 Ipmulti *multi, **l;
1435 for(l = &c->multi; *l != nil; l = &(*l)->next)
1436 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1437 return; /* it's already there */
1439 multi = *l = smalloc(sizeof(*multi));
1440 ipmove(multi->ma, ma);
1441 ipmove(multi->ia, ia);
1444 e = &f->ipifc->conv[f->ipifc->nc];
1445 for(cp = f->ipifc->conv; cp < e; cp++){
1446 if((*cp) == nil || (*cp)->inuse == 0)
1448 ifc = (Ipifc*)(*cp)->ptcl;
1454 if((lifc = iplocalonifc(ifc, ia)) != nil)
1455 addselfcache(f, ifc, lifc, ma, Rmulti);
1463 * remove a multicast address from an interface, called with c->car locked
1466 ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
1468 Ipmulti *multi, **l;
1476 for(l = &c->multi; *l != nil; l = &(*l)->next)
1477 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1482 return; /* we don't have it open */
1486 e = &f->ipifc->conv[f->ipifc->nc];
1487 for(cp = f->ipifc->conv; cp < e; cp++){
1488 if((*cp) == nil || (*cp)->inuse == 0)
1490 ifc = (Ipifc*)(*cp)->ptcl;
1496 if((lifc = iplocalonifc(ifc, ia)) != nil)
1497 remselfcache(f, ifc, lifc, ma);
1506 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip, int add)
1508 uchar proxy[IPaddrlen];
1514 /* register the address on any interface that will proxy for the ip */
1515 e = &f->ipifc->conv[f->ipifc->nc];
1516 for(cp = f->ipifc->conv; cp < e; cp++){
1517 if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
1522 if(m == nil || m->areg == nil || waserror()){
1526 if((lifc = ipremoteonifc(nifc, ip)) != nil){
1527 if((lifc->type & Rv4) == 0){
1528 /* add solicited-node multicast addr */
1529 ipv62smcast(proxy, ip);
1531 addselfcache(f, nifc, lifc, proxy, Rmulti);
1533 remselfcache(f, nifc, lifc, proxy);
1535 ipmove(proxy, lifc->local);
1540 if(add && lifc != nil)
1541 (*m->areg)(f, nifc, ip, proxy);
1546 ipifcadd6(Ipifc *ifc, char**argv, int argc)
1549 char addr[40], preflen[6];
1551 uchar prefix[IPaddrlen];
1558 lifc.origint = NOW / 1000;
1562 lifc.preflt = atoi(argv[6]);
1565 lifc.validlt = atoi(argv[5]);
1568 lifc.autoflag = atoi(argv[4]) != 0;
1571 lifc.onlink = atoi(argv[3]) != 0;
1574 plen = atoi(argv[2]);
1582 if (parseip(prefix, argv[1]) != 6 || lifc.validlt < lifc.preflt || plen < 0 ||
1583 plen > 64 || islinklocal(prefix))
1586 /* issue "add" ctl msg for v6 link-local addr and prefix len */
1587 if(ifc->m->pref2addr == nil)
1589 (*ifc->m->pref2addr)(prefix, ifc->mac); /* mac → v6 link-local addr */
1591 sprint(addr, "%I", prefix);
1592 sprint(preflen, "/%d", plen);
1595 params[2] = preflen;
1597 return ipifcadd(ifc, params, 3, 0, &lifc);