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 /* dissociate routes */
184 if(ifc->m != nil && ifc->m->unbindonclose == 0)
188 /* disassociate logical interfaces (before zeroing ifc->arg) */
190 err = ipifcremlifc(ifc, ifc->lifc);
192 * note: err non-zero means lifc not found,
193 * which can't happen in this case.
199 /* disassociate device */
200 if(ifc->m && ifc->m->unbind)
201 (*ifc->m->unbind)(ifc);
202 memset(ifc->dev, 0, sizeof(ifc->dev));
206 /* close queues to stop queuing of packets */
207 qclose(ifc->conv->rq);
208 qclose(ifc->conv->wq);
209 qclose(ifc->conv->sq);
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 == nil || ifc->m->pktin == nil)
305 (*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);
421 /* ignore if this is already a local address for this ifc */
422 for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
423 if(ipcmp(lifc->local, ip) == 0) {
424 if(lifc->tentative != tentative)
425 lifc->tentative = tentative;
427 lifc->onlink = lifcp->onlink;
428 lifc->autoflag = lifcp->autoflag;
429 lifc->validlt = lifcp->validlt;
430 lifc->preflt = lifcp->preflt;
431 lifc->origint = lifcp->origint;
437 /* add the address to the list of logical ifc's for this ifc */
438 lifc = smalloc(sizeof(Iplifc));
439 ipmove(lifc->local, ip);
440 ipmove(lifc->mask, mask);
441 ipmove(lifc->remote, rem);
442 ipmove(lifc->net, net);
443 lifc->tentative = tentative;
445 lifc->onlink = lifcp->onlink;
446 lifc->autoflag = lifcp->autoflag;
447 lifc->validlt = lifcp->validlt;
448 lifc->preflt = lifcp->preflt;
449 lifc->origint = lifcp->origint;
450 } else { /* default values */
451 lifc->onlink = lifc->autoflag = 1;
452 lifc->validlt = lifc->preflt = ~0L;
453 lifc->origint = NOW / 1000;
457 for(l = &ifc->lifc; *l; l = &(*l)->next)
461 /* check for point-to-point interface */
462 if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */
463 if(ipcmp(mask, IPallbits) == 0)
466 /* add local routes */
468 v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
470 v6addroute(f, tifc, rem, mask, rem, type);
472 addselfcache(f, ifc, lifc, ip, Runi);
474 if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){
475 ipifcregisterproxy(f, ifc, rem);
479 if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
480 /* add subnet directed broadcast address to the self cache */
481 for(i = 0; i < IPaddrlen; i++)
482 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
483 addselfcache(f, ifc, lifc, bcast, Rbcast);
485 /* add subnet directed network 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 network directed broadcast address to the self cache */
491 memmove(mask, defmask(ip), IPaddrlen);
492 for(i = 0; i < IPaddrlen; i++)
493 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
494 addselfcache(f, ifc, lifc, bcast, Rbcast);
496 /* add network directed network address to the self cache */
497 memmove(mask, defmask(ip), IPaddrlen);
498 for(i = 0; i < IPaddrlen; i++)
499 bcast[i] = (ip[i] & mask[i]) & mask[i];
500 addselfcache(f, ifc, lifc, bcast, Rbcast);
502 addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
505 if(ipcmp(ip, v6loopback) == 0) {
506 /* add node-local mcast address */
507 addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
509 /* add route for all node multicast */
510 v6addroute(f, tifc, v6allnodesN, v6allnodesNmask,
511 v6allnodesN, Rmulti);
514 /* add all nodes multicast address */
515 addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
517 /* add route for all nodes multicast */
518 v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL,
521 /* add solicited-node multicast address */
522 ipv62smcast(bcast, ip);
523 addselfcache(f, ifc, lifc, bcast, Rmulti);
528 /* register the address on this network for address resolution */
529 if(isv4(ip) && ifc->m->areg != nil)
530 (*ifc->m->areg)(ifc, ip);
534 if(tentative && sendnbrdisc)
535 icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
540 * remove a logical interface from an ifc
541 * always called with ifc wlock'd
544 ipifcremlifc(Ipifc *ifc, Iplifc *lifc)
552 * find address on this interface and remove from chain.
553 * for pt to pt we actually specify the remote address as the
554 * addresss to remove.
556 for(l = &ifc->lifc; *l != nil && *l != lifc; l = &(*l)->next)
559 return "address not on this interface";
562 /* disassociate any addresses */
564 remselfcache(f, ifc, lifc, lifc->link->self->a);
566 /* remove the route for this logical interface */
567 if(isv4(lifc->local))
568 v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);
570 v6delroute(f, lifc->remote, lifc->mask, 1);
571 if(ipcmp(lifc->local, v6loopback) == 0)
572 /* remove route for all node multicast */
573 v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
574 else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0)
575 /* remove route for all link multicast */
576 v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
584 * remove an address from an interface.
585 * called with c->car locked
588 ipifcrem(Ipifc *ifc, char **argv, int argc)
591 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
597 if (parseip(ip, argv[1]) == -1)
599 parseipmask(mask, argv[2]);
601 maskip(ip, mask, rem);
603 if (parseip(rem, argv[3]) == -1)
609 * find address on this interface and remove from chain.
610 * for pt to pt we actually specify the remote address as the
611 * addresss to remove.
613 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
614 if (memcmp(ip, lifc->local, IPaddrlen) == 0
615 && memcmp(mask, lifc->mask, IPaddrlen) == 0
616 && memcmp(rem, lifc->remote, IPaddrlen) == 0)
620 rv = ipifcremlifc(ifc, lifc);
626 * distribute routes to active interfaces like the
630 ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type)
636 e = &f->ipifc->conv[f->ipifc->nc];
637 for(cp = f->ipifc->conv; cp < e; cp++){
639 ifc = (Ipifc*)(*cp)->ptcl;
642 m->addroute(ifc, vers, addr, mask, gate, type);
648 ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask)
654 e = &f->ipifc->conv[f->ipifc->nc];
655 for(cp = f->ipifc->conv; cp < e; cp++){
657 ifc = (Ipifc*)(*cp)->ptcl;
660 m->remroute(ifc, vers, addr, mask);
666 * associate an address with the interface. This wipes out any previous
667 * addresses. This is a macro that means, remove all the old interfaces
671 ipifcconnect(Conv* c, char **argv, int argc)
676 ifc = (Ipifc*)c->ptcl;
679 return "ipifc not yet bound to device";
687 err = ipifcremlifc(ifc, ifc->lifc);
694 err = ipifcadd(ifc, argv, argc, 0, nil);
703 ipifcra6(Ipifc *ifc, char **argv, int argc)
705 int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
710 if(argsleft % 2 != 0)
713 while (argsleft > 1) {
714 if(strcmp(argv[i], "recvra") == 0)
715 ifc->recvra6 = (atoi(argv[i+1]) != 0);
716 else if(strcmp(argv[i], "sendra") == 0)
717 ifc->sendra6 = (atoi(argv[i+1]) != 0);
718 else if(strcmp(argv[i], "mflag") == 0)
719 ifc->rp.mflag = (atoi(argv[i+1]) != 0);
720 else if(strcmp(argv[i], "oflag") == 0)
721 ifc->rp.oflag = (atoi(argv[i+1]) != 0);
722 else if(strcmp(argv[i], "maxraint") == 0)
723 ifc->rp.maxraint = atoi(argv[i+1]);
724 else if(strcmp(argv[i], "minraint") == 0)
725 ifc->rp.minraint = atoi(argv[i+1]);
726 else if(strcmp(argv[i], "linkmtu") == 0)
727 ifc->rp.linkmtu = atoi(argv[i+1]);
728 else if(strcmp(argv[i], "reachtime") == 0)
729 ifc->rp.reachtime = atoi(argv[i+1]);
730 else if(strcmp(argv[i], "rxmitra") == 0)
731 ifc->rp.rxmitra = atoi(argv[i+1]);
732 else if(strcmp(argv[i], "ttl") == 0)
733 ifc->rp.ttl = atoi(argv[i+1]);
734 else if(strcmp(argv[i], "routerlt") == 0)
735 ifc->rp.routerlt = atoi(argv[i+1]);
743 /* consistency check */
744 if(ifc->rp.maxraint < ifc->rp.minraint) {
745 ifc->rp.maxraint = vmax;
746 ifc->rp.minraint = vmin;
753 * non-standard control messages.
754 * called with c->car locked.
757 ipifcctl(Conv* c, char**argv, int argc)
762 ifc = (Ipifc*)c->ptcl;
763 if(strcmp(argv[0], "add") == 0)
764 return ipifcadd(ifc, argv, argc, 0, nil);
765 else if(strcmp(argv[0], "try") == 0)
766 return ipifcadd(ifc, argv, argc, 1, nil);
767 else if(strcmp(argv[0], "remove") == 0)
768 return ipifcrem(ifc, argv, argc);
769 else if(strcmp(argv[0], "unbind") == 0)
770 return ipifcunbind(ifc);
771 else if(strcmp(argv[0], "joinmulti") == 0)
772 return ipifcjoinmulti(ifc, argv, argc);
773 else if(strcmp(argv[0], "leavemulti") == 0)
774 return ipifcleavemulti(ifc, argv, argc);
775 else if(strcmp(argv[0], "mtu") == 0)
776 return ipifcsetmtu(ifc, argv, argc);
777 else if(strcmp(argv[0], "reassemble") == 0){
781 else if(strcmp(argv[0], "iprouting") == 0){
785 iprouting(c->p->f, i);
788 else if(strcmp(argv[0], "add6") == 0)
789 return ipifcadd6(ifc, argv, argc);
790 else if(strcmp(argv[0], "ra6") == 0)
791 return ipifcra6(ifc, argv, argc);
792 return "unsupported ctl";
796 ipifcstats(Proto *ipifc, char *buf, int len)
798 return ipstats(ipifc->f, buf, len);
806 ipifc = smalloc(sizeof(Proto));
807 ipifc->name = "ipifc";
808 ipifc->connect = ipifcconnect;
809 ipifc->announce = nil;
810 ipifc->bind = ipifcbind;
811 ipifc->state = ipifcstate;
812 ipifc->create = ipifccreate;
813 ipifc->close = ipifcclose;
815 ipifc->ctl = ipifcctl;
817 ipifc->stats = ipifcstats;
818 ipifc->inuse = ipifcinuse;
819 ipifc->local = ipifclocal;
821 ipifc->nc = Maxmedia;
822 ipifc->ptclsize = sizeof(Ipifc);
824 f->ipifc = ipifc; /* hack for ipifcremroute, findipifc, ... */
825 f->self = smalloc(sizeof(Ipselftab)); /* hack for ipforme */
831 * add to self routing cache
832 * called with c->car locked
835 addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
843 /* see if the address already exists */
845 for(p = f->self->hash[h]; p; p = p->next)
846 if(memcmp(a, p->a, IPaddrlen) == 0)
849 /* allocate a local address and add to hash chain */
851 p = smalloc(sizeof(*p));
854 p->next = f->self->hash[h];
855 f->self->hash[h] = p;
857 /* if the null address, accept all packets */
858 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
859 f->self->acceptall = 1;
862 /* look for a link for this lifc */
863 for(lp = p->link; lp; lp = lp->selflink)
867 /* allocate a lifc-to-local link and link to both */
869 lp = smalloc(sizeof(*lp));
873 lp->selflink = p->link;
875 lp->lifclink = lifc->link;
878 /* add to routing table */
880 v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off,
883 v6addroute(f, tifc, a, IPallbits, a, type);
885 if((type & Rmulti) && ifc->m->addmulti != nil)
886 (*ifc->m->addmulti)(ifc, a, lifc->local);
894 * These structures are unlinked from their chains while
895 * other threads may be using them. To avoid excessive locking,
896 * just put them aside for a while before freeing them.
897 * called with f->self locked
899 static Iplink *freeiplink;
900 static Ipself *freeipself;
903 iplinkfree(Iplink *p)
909 for(np = *l; np; np = *l){
910 if(np->expire > now){
917 p->expire = now + 5000; /* give other threads 5 secs to get out */
923 ipselffree(Ipself *p)
929 for(np = *l; np; np = *l){
930 if(np->expire > now){
937 p->expire = now + 5000; /* give other threads 5 secs to get out */
943 * Decrement reference for this address on this link.
944 * Unlink from selftab if this is the last ref.
945 * called with c->car locked
948 remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
951 Iplink *link, **l_self, **l_lifc;
955 /* find the unique selftab entry */
956 l = &f->self->hash[hashipa(a)];
957 for(p = *l; p; p = *l){
958 if(ipcmp(p->a, a) == 0)
967 * walk down links from an ifc looking for one
968 * that matches the selftab entry
970 l_lifc = &lifc->link;
971 for(link = *l_lifc; link; link = *l_lifc){
974 l_lifc = &link->lifclink;
981 * walk down the links from the selftab looking for
982 * the one we just found
985 for(link = *l_self; link; link = *l_self){
988 l_self = &link->selflink;
992 panic("remselfcache");
994 if(--(link->ref) != 0)
997 if((p->type & Rmulti) && ifc->m->remmulti != nil)
998 (*ifc->m->remmulti)(ifc, a, lifc->local);
1000 /* ref == 0, remove from both chains and free the link */
1001 *l_lifc = link->lifclink;
1002 *l_self = link->selflink;
1008 /* remove from routing table */
1010 v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
1012 v6delroute(f, a, IPallbits, 1);
1014 /* no more links, remove from hash and free */
1018 /* if IPnoaddr, forget */
1019 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1020 f->self->acceptall = 0;
1026 static char *stformat = "%-44.44I %2.2d %4.4s\n";
1033 ipselftabread(Fs *f, char *cp, ulong offset, int n)
1035 int i, m, nifc, off;
1043 for(i = 0; i < NHASH && m < n; i++){
1044 for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
1046 for(link = p->link; link; link = link->selflink)
1048 routetype(p->type, state);
1049 m += snprint(cp + m, n - m, stformat, p->a, nifc, state);
1061 iptentative(Fs *f, uchar *addr)
1065 p = f->self->hash[hashipa(addr)];
1066 for(; p; p = p->next){
1067 if(ipcmp(addr, p->a) == 0)
1068 return p->link->lifc->tentative;
1081 ipforme(Fs *f, uchar *addr)
1085 p = f->self->hash[hashipa(addr)];
1086 for(; p; p = p->next){
1087 if(ipcmp(addr, p->a) == 0)
1091 /* hack to say accept anything */
1092 if(f->self->acceptall)
1098 * find the ifc on same net as the remote system. If none,
1102 findipifc(Fs *f, uchar *remote, int type)
1107 uchar gnet[IPaddrlen], xmask[IPaddrlen];
1110 memset(xmask, 0, IPaddrlen);
1112 /* find most specific match */
1113 e = &f->ipifc->conv[f->ipifc->nc];
1114 for(cp = f->ipifc->conv; cp < e; cp++){
1117 ifc = (Ipifc*)(*cp)->ptcl;
1118 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1119 maskip(remote, lifc->mask, gnet);
1120 if(ipcmp(gnet, lifc->net) == 0){
1121 if(x == nil || ipcmp(lifc->mask, xmask) > 0){
1123 ipmove(xmask, lifc->mask);
1131 /* for now for broadcast and multicast, just use first interface */
1132 if(type & (Rbcast|Rmulti)){
1133 for(cp = f->ipifc->conv; cp < e; cp++){
1136 ifc = (Ipifc*)(*cp)->ptcl;
1137 if(ifc->lifc != nil)
1145 unknownv6, /* UGH */
1153 v6addrtype(uchar *addr)
1155 if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
1157 else if(islinklocal(addr) ||
1158 isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
1164 #define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
1165 (lifc)->origint + (lifc)->preflt >= NOW/1000)
1168 findprimaryipv6(Fs *f, uchar *local)
1175 ipmove(local, v6Unspecified);
1176 atype = unspecifiedv6;
1179 * find "best" (global > link local > unspecified)
1180 * local address; address must be current.
1182 e = &f->ipifc->conv[f->ipifc->nc];
1183 for(cp = f->ipifc->conv; cp < e; cp++){
1186 ifc = (Ipifc*)(*cp)->ptcl;
1187 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1188 atypel = v6addrtype(lifc->local);
1189 if(atypel > atype && v6addrcurr(lifc)) {
1190 ipmove(local, lifc->local);
1192 if(atype == globalv6)
1200 * returns first ip address configured
1203 findprimaryipv4(Fs *f, uchar *local)
1209 /* find first ifc local address */
1210 e = &f->ipifc->conv[f->ipifc->nc];
1211 for(cp = f->ipifc->conv; cp < e; cp++){
1214 ifc = (Ipifc*)(*cp)->ptcl;
1215 if((lifc = ifc->lifc) != nil){
1216 ipmove(local, lifc->local);
1223 * find the local address 'closest' to the remote system, copy it to
1224 * local and return the ifc for that address
1227 findlocalip(Fs *f, uchar *local, uchar *remote)
1229 int version, atype = unspecifiedv6, atypel = unknownv6;
1230 int atyper, deprecated;
1231 uchar gate[IPaddrlen], gnet[IPaddrlen];
1239 r = v6lookup(f, remote, nil);
1240 version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6;
1245 v4tov6(gate, r->v4.gate);
1247 ipmove(gate, r->v6.gate);
1248 ipmove(local, v6Unspecified);
1253 /* find ifc address closest to the gateway to use */
1254 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1255 maskip(gate, lifc->mask, gnet);
1256 if(ipcmp(gnet, lifc->net) == 0){
1257 ipmove(local, lifc->local);
1263 /* find ifc address with scope matching the destination */
1264 atyper = v6addrtype(remote);
1266 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1267 atypel = v6addrtype(lifc->local);
1268 /* prefer appropriate scope */
1269 if(atypel > atype && atype < atyper ||
1270 atypel < atype && atype > atyper){
1271 ipmove(local, lifc->local);
1272 deprecated = !v6addrcurr(lifc);
1274 } else if(atypel == atype){
1275 /* avoid deprecated addresses */
1276 if(deprecated && v6addrcurr(lifc)){
1277 ipmove(local, lifc->local);
1282 if(atype == atyper && !deprecated)
1289 panic("findlocalip: version %d", version);
1295 findprimaryipv4(f, local);
1298 findprimaryipv6(f, local);
1301 panic("findlocalip2: version %d", version);
1309 * return first v4 address associated with an interface
1312 ipv4local(Ipifc *ifc, uchar *addr)
1316 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1317 if(isv4(lifc->local)){
1318 memmove(addr, lifc->local+IPv4off, IPv4addrlen);
1326 * return first v6 address associated with an interface
1329 ipv6local(Ipifc *ifc, uchar *addr)
1333 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1334 if(!isv4(lifc->local) && !(lifc->tentative)){
1335 ipmove(addr, lifc->local);
1343 ipv6anylocal(Ipifc *ifc, uchar *addr)
1347 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1348 if(!isv4(lifc->local)){
1349 ipmove(addr, lifc->local);
1357 * see if this address is bound to the interface
1360 iplocalonifc(Ipifc *ifc, uchar *ip)
1364 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1365 if(ipcmp(ip, lifc->local) == 0)
1372 * See if we're proxying for this address on this interface
1375 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
1378 uchar net[IPaddrlen];
1381 /* see if this is a direct connected pt to pt address */
1382 r = v6lookup(f, ip, nil);
1383 if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
1386 /* see if this is on the right interface */
1387 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1388 maskip(ip, lifc->mask, net);
1389 if(ipcmp(net, lifc->remote) == 0)
1396 * return multicast version if any
1399 ipismulticast(uchar *ip)
1402 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1405 else if(ip[0] == 0xff)
1413 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1415 else if(ipcmp(ip, IPv4bcast) == 0)
1418 else if(ip[0] == 0xff)
1425 * add a multicast address to an interface, called with c->car locked
1428 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
1433 Ipmulti *multi, **l;
1438 for(l = &c->multi; *l; l = &(*l)->next)
1439 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1440 return; /* it's already there */
1442 multi = *l = smalloc(sizeof(*multi));
1443 ipmove(multi->ma, ma);
1444 ipmove(multi->ia, ia);
1447 for(p = f->ipifc->conv; *p; p++){
1448 if((*p)->inuse == 0)
1450 ifc = (Ipifc*)(*p)->ptcl;
1456 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1457 if(ipcmp(ia, lifc->local) == 0)
1458 addselfcache(f, ifc, lifc, ma, Rmulti);
1466 * remove a multicast address from an interface, called with c->car locked
1469 ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
1471 Ipmulti *multi, **l;
1479 for(l = &c->multi; *l; l = &(*l)->next)
1480 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1485 return; /* we don't have it open */
1489 for(p = f->ipifc->conv; *p; p++){
1490 if((*p)->inuse == 0)
1493 ifc = (Ipifc*)(*p)->ptcl;
1499 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1500 if(ipcmp(ia, lifc->local) == 0)
1501 remselfcache(f, ifc, lifc, ma);
1510 * make lifc's join and leave multicast groups
1513 ipifcjoinmulti(Ipifc *ifc, char **argv, int argc)
1515 USED(ifc, argv, argc);
1520 ipifcleavemulti(Ipifc *ifc, char **argv, int argc)
1522 USED(ifc, argv, argc);
1527 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
1533 uchar net[IPaddrlen];
1535 /* register the address on any network that will proxy for us */
1536 e = &f->ipifc->conv[f->ipifc->nc];
1538 if(!isv4(ip)) { /* V6 */
1539 for(cp = f->ipifc->conv; cp < e; cp++){
1540 if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
1544 if(m == nil || m->addmulti == nil) {
1548 for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1549 maskip(ip, lifc->mask, net);
1550 if(ipcmp(net, lifc->remote) == 0) {
1551 /* add solicited-node multicast addr */
1552 ipv62smcast(net, ip);
1553 addselfcache(f, nifc, lifc, net, Rmulti);
1554 arpenter(f, V6, ip, nifc->mac, 6, 0);
1555 // (*m->addmulti)(nifc, net, ip);
1563 for(cp = f->ipifc->conv; cp < e; cp++){
1564 if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
1568 if(m == nil || m->areg == nil){
1572 for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1573 maskip(ip, lifc->mask, net);
1574 if(ipcmp(net, lifc->remote) == 0){
1575 (*m->areg)(nifc, ip);
1585 /* added for new v6 mesg types */
1587 adddefroute6(Fs *f, uchar *gate, int force)
1591 r = v6lookup(f, v6Unspecified, nil);
1593 * route entries generated by all other means take precedence
1594 * over router announcements.
1596 if (r && !force && strcmp(r->tag, "ra") != 0)
1599 v6delroute(f, v6Unspecified, v6Unspecified, 1);
1600 v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
1608 ipifcadd6(Ipifc *ifc, char**argv, int argc)
1611 long origint = NOW / 1000, preflt = ~0L, validlt = ~0L;
1612 char addr[40], preflen[6];
1614 uchar autoflag = 1, onlink = 1;
1615 uchar prefix[IPaddrlen];
1620 preflt = atoi(argv[6]);
1623 validlt = atoi(argv[5]);
1626 autoflag = atoi(argv[4]);
1629 onlink = atoi(argv[3]);
1632 plen = atoi(argv[2]);
1640 if (parseip(prefix, argv[1]) != 6 || validlt < preflt || plen < 0 ||
1641 plen > 64 || islinklocal(prefix))
1644 lifc = smalloc(sizeof(Iplifc));
1645 lifc->onlink = (onlink != 0);
1646 lifc->autoflag = (autoflag != 0);
1647 lifc->validlt = validlt;
1648 lifc->preflt = preflt;
1649 lifc->origint = origint;
1651 /* issue "add" ctl msg for v6 link-local addr and prefix len */
1652 if(!ifc->m->pref2addr)
1654 ifc->m->pref2addr(prefix, ifc->mac); /* mac → v6 link-local addr */
1655 sprint(addr, "%I", prefix);
1656 sprint(preflen, "/%d", plen);
1659 params[2] = preflen;
1661 return ipifcadd(ifc, params, 3, 0, lifc);