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->sq = qopen(QMAX, 0, 0, 0);
320 c->wq = qopen(QMAX, Qkick, ipifckick, c);
321 ifc = (Ipifc*)c->ptcl;
329 * called after last close of ipifc data or ctl
330 * called with c locked, we must unlock
338 ifc = (Ipifc*)c->ptcl;
340 if(m && m->unbindonclose)
345 * change an interface's mtu
348 ipifcsetmtu(Ipifc *ifc, char **argv, int argc)
352 if(argc < 2 || ifc->m == nil)
354 mtu = strtoul(argv[1], 0, 0);
355 if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu)
362 * add an address to an interface.
365 ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
367 int i, type, mtu, sendnbrdisc = 0;
368 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
369 uchar bcast[IPaddrlen], net[IPaddrlen];
374 return "ipifc not yet bound to device";
379 memset(ip, 0, IPaddrlen);
380 memset(mask, 0, IPaddrlen);
381 memset(rem, 0, IPaddrlen);
384 if(strcmp(argv[5], "proxy") == 0)
388 mtu = strtoul(argv[4], 0, 0);
389 if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
393 if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1)
395 parseipmask(mask, argv[2]);
396 maskip(rem, mask, net);
399 if (parseip(ip, argv[1]) == -1)
401 parseipmask(mask, argv[2]);
402 maskip(ip, mask, rem);
403 maskip(rem, mask, net);
406 if (parseip(ip, argv[1]) == -1)
408 memmove(mask, defmask(ip), IPaddrlen);
409 maskip(ip, mask, rem);
410 maskip(rem, mask, net);
419 /* ignore if this is already a local address for this ifc */
420 for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
421 if(ipcmp(lifc->local, ip) == 0) {
422 if(lifc->tentative != tentative)
423 lifc->tentative = tentative;
425 lifc->onlink = lifcp->onlink;
426 lifc->autoflag = lifcp->autoflag;
427 lifc->validlt = lifcp->validlt;
428 lifc->preflt = lifcp->preflt;
429 lifc->origint = lifcp->origint;
435 /* add the address to the list of logical ifc's for this ifc */
436 lifc = smalloc(sizeof(Iplifc));
437 ipmove(lifc->local, ip);
438 ipmove(lifc->mask, mask);
439 ipmove(lifc->remote, rem);
440 ipmove(lifc->net, net);
441 lifc->tentative = tentative;
443 lifc->onlink = lifcp->onlink;
444 lifc->autoflag = lifcp->autoflag;
445 lifc->validlt = lifcp->validlt;
446 lifc->preflt = lifcp->preflt;
447 lifc->origint = lifcp->origint;
448 } else { /* default values */
449 lifc->onlink = lifc->autoflag = 1;
450 lifc->validlt = lifc->preflt = ~0L;
451 lifc->origint = NOW / 1000;
455 for(l = &ifc->lifc; *l; l = &(*l)->next)
459 /* check for point-to-point interface */
460 if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */
461 if(ipcmp(mask, IPallbits) == 0)
464 /* add local routes */
466 v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
468 v6addroute(f, tifc, rem, mask, rem, type);
470 addselfcache(f, ifc, lifc, ip, Runi);
472 if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){
473 ipifcregisterproxy(f, ifc, rem);
477 if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
478 /* add subnet directed broadcast address to the self cache */
479 for(i = 0; i < IPaddrlen; i++)
480 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
481 addselfcache(f, ifc, lifc, bcast, Rbcast);
483 /* add subnet directed network address to the self cache */
484 for(i = 0; i < IPaddrlen; i++)
485 bcast[i] = (ip[i] & mask[i]) & mask[i];
486 addselfcache(f, ifc, lifc, bcast, Rbcast);
488 /* add network directed broadcast address to the self cache */
489 memmove(mask, defmask(ip), IPaddrlen);
490 for(i = 0; i < IPaddrlen; i++)
491 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
492 addselfcache(f, ifc, lifc, bcast, Rbcast);
494 /* add network directed network address to the self cache */
495 memmove(mask, defmask(ip), IPaddrlen);
496 for(i = 0; i < IPaddrlen; i++)
497 bcast[i] = (ip[i] & mask[i]) & mask[i];
498 addselfcache(f, ifc, lifc, bcast, Rbcast);
500 addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
503 if(ipcmp(ip, v6loopback) == 0) {
504 /* add node-local mcast address */
505 addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
507 /* add route for all node multicast */
508 v6addroute(f, tifc, v6allnodesN, v6allnodesNmask,
509 v6allnodesN, Rmulti);
512 /* add all nodes multicast address */
513 addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
515 /* add route for all nodes multicast */
516 v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL,
519 /* add solicited-node multicast address */
520 ipv62smcast(bcast, ip);
521 addselfcache(f, ifc, lifc, bcast, Rmulti);
526 /* register the address on this network for address resolution */
527 if(isv4(ip) && ifc->m->areg != nil)
528 (*ifc->m->areg)(ifc, ip);
532 if(tentative && sendnbrdisc)
533 icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
538 * remove a logical interface from an ifc
539 * always called with ifc wlock'd
542 ipifcremlifc(Ipifc *ifc, Iplifc *lifc)
550 * find address on this interface and remove from chain.
551 * for pt to pt we actually specify the remote address as the
552 * addresss to remove.
554 for(l = &ifc->lifc; *l != nil && *l != lifc; l = &(*l)->next)
557 return "address not on this interface";
560 /* disassociate any addresses */
562 remselfcache(f, ifc, lifc, lifc->link->self->a);
564 /* remove the route for this logical interface */
565 if(isv4(lifc->local))
566 v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);
568 v6delroute(f, lifc->remote, lifc->mask, 1);
569 if(ipcmp(lifc->local, v6loopback) == 0)
570 /* remove route for all node multicast */
571 v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
572 else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0)
573 /* remove route for all link multicast */
574 v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
582 * remove an address from an interface.
583 * called with c->car locked
586 ipifcrem(Ipifc *ifc, char **argv, int argc)
589 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
595 if (parseip(ip, argv[1]) == -1)
597 parseipmask(mask, argv[2]);
599 maskip(ip, mask, rem);
601 if (parseip(rem, argv[3]) == -1)
607 * find address on this interface and remove from chain.
608 * for pt to pt we actually specify the remote address as the
609 * addresss to remove.
611 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
612 if (memcmp(ip, lifc->local, IPaddrlen) == 0
613 && memcmp(mask, lifc->mask, IPaddrlen) == 0
614 && memcmp(rem, lifc->remote, IPaddrlen) == 0)
618 rv = ipifcremlifc(ifc, lifc);
624 * distribute routes to active interfaces like the
628 ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type)
634 e = &f->ipifc->conv[f->ipifc->nc];
635 for(cp = f->ipifc->conv; cp < e; cp++){
637 ifc = (Ipifc*)(*cp)->ptcl;
640 m->addroute(ifc, vers, addr, mask, gate, type);
646 ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask)
652 e = &f->ipifc->conv[f->ipifc->nc];
653 for(cp = f->ipifc->conv; cp < e; cp++){
655 ifc = (Ipifc*)(*cp)->ptcl;
658 m->remroute(ifc, vers, addr, mask);
664 * associate an address with the interface. This wipes out any previous
665 * addresses. This is a macro that means, remove all the old interfaces
669 ipifcconnect(Conv* c, char **argv, int argc)
674 ifc = (Ipifc*)c->ptcl;
677 return "ipifc not yet bound to device";
685 err = ipifcremlifc(ifc, ifc->lifc);
692 err = ipifcadd(ifc, argv, argc, 0, nil);
701 ipifcra6(Ipifc *ifc, char **argv, int argc)
703 int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
708 if(argsleft % 2 != 0)
711 while (argsleft > 1) {
712 if(strcmp(argv[i], "recvra") == 0)
713 ifc->recvra6 = (atoi(argv[i+1]) != 0);
714 else if(strcmp(argv[i], "sendra") == 0)
715 ifc->sendra6 = (atoi(argv[i+1]) != 0);
716 else if(strcmp(argv[i], "mflag") == 0)
717 ifc->rp.mflag = (atoi(argv[i+1]) != 0);
718 else if(strcmp(argv[i], "oflag") == 0)
719 ifc->rp.oflag = (atoi(argv[i+1]) != 0);
720 else if(strcmp(argv[i], "maxraint") == 0)
721 ifc->rp.maxraint = atoi(argv[i+1]);
722 else if(strcmp(argv[i], "minraint") == 0)
723 ifc->rp.minraint = atoi(argv[i+1]);
724 else if(strcmp(argv[i], "linkmtu") == 0)
725 ifc->rp.linkmtu = atoi(argv[i+1]);
726 else if(strcmp(argv[i], "reachtime") == 0)
727 ifc->rp.reachtime = atoi(argv[i+1]);
728 else if(strcmp(argv[i], "rxmitra") == 0)
729 ifc->rp.rxmitra = atoi(argv[i+1]);
730 else if(strcmp(argv[i], "ttl") == 0)
731 ifc->rp.ttl = atoi(argv[i+1]);
732 else if(strcmp(argv[i], "routerlt") == 0)
733 ifc->rp.routerlt = atoi(argv[i+1]);
741 /* consistency check */
742 if(ifc->rp.maxraint < ifc->rp.minraint) {
743 ifc->rp.maxraint = vmax;
744 ifc->rp.minraint = vmin;
751 * non-standard control messages.
752 * called with c->car locked.
755 ipifcctl(Conv* c, char**argv, int argc)
760 ifc = (Ipifc*)c->ptcl;
761 if(strcmp(argv[0], "add") == 0)
762 return ipifcadd(ifc, argv, argc, 0, nil);
763 else if(strcmp(argv[0], "try") == 0)
764 return ipifcadd(ifc, argv, argc, 1, nil);
765 else if(strcmp(argv[0], "remove") == 0)
766 return ipifcrem(ifc, argv, argc);
767 else if(strcmp(argv[0], "unbind") == 0)
768 return ipifcunbind(ifc);
769 else if(strcmp(argv[0], "joinmulti") == 0)
770 return ipifcjoinmulti(ifc, argv, argc);
771 else if(strcmp(argv[0], "leavemulti") == 0)
772 return ipifcleavemulti(ifc, argv, argc);
773 else if(strcmp(argv[0], "mtu") == 0)
774 return ipifcsetmtu(ifc, argv, argc);
775 else if(strcmp(argv[0], "reassemble") == 0){
779 else if(strcmp(argv[0], "iprouting") == 0){
783 iprouting(c->p->f, i);
786 else if(strcmp(argv[0], "add6") == 0)
787 return ipifcadd6(ifc, argv, argc);
788 else if(strcmp(argv[0], "ra6") == 0)
789 return ipifcra6(ifc, argv, argc);
790 return "unsupported ctl";
794 ipifcstats(Proto *ipifc, char *buf, int len)
796 return ipstats(ipifc->f, buf, len);
804 ipifc = smalloc(sizeof(Proto));
805 ipifc->name = "ipifc";
806 ipifc->connect = ipifcconnect;
807 ipifc->announce = nil;
808 ipifc->bind = ipifcbind;
809 ipifc->state = ipifcstate;
810 ipifc->create = ipifccreate;
811 ipifc->close = ipifcclose;
813 ipifc->ctl = ipifcctl;
815 ipifc->stats = ipifcstats;
816 ipifc->inuse = ipifcinuse;
817 ipifc->local = ipifclocal;
819 ipifc->nc = Maxmedia;
820 ipifc->ptclsize = sizeof(Ipifc);
822 f->ipifc = ipifc; /* hack for ipifcremroute, findipifc, ... */
823 f->self = smalloc(sizeof(Ipselftab)); /* hack for ipforme */
829 * add to self routing cache
830 * called with c->car locked
833 addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
841 /* see if the address already exists */
843 for(p = f->self->hash[h]; p; p = p->next)
844 if(memcmp(a, p->a, IPaddrlen) == 0)
847 /* allocate a local address and add to hash chain */
849 p = smalloc(sizeof(*p));
852 p->next = f->self->hash[h];
853 f->self->hash[h] = p;
855 /* if the null address, accept all packets */
856 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
857 f->self->acceptall = 1;
860 /* look for a link for this lifc */
861 for(lp = p->link; lp; lp = lp->selflink)
865 /* allocate a lifc-to-local link and link to both */
867 lp = smalloc(sizeof(*lp));
871 lp->selflink = p->link;
873 lp->lifclink = lifc->link;
876 /* add to routing table */
878 v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off,
881 v6addroute(f, tifc, a, IPallbits, a, type);
883 if((type & Rmulti) && ifc->m->addmulti != nil)
884 (*ifc->m->addmulti)(ifc, a, lifc->local);
892 * These structures are unlinked from their chains while
893 * other threads may be using them. To avoid excessive locking,
894 * just put them aside for a while before freeing them.
895 * called with f->self locked
897 static Iplink *freeiplink;
898 static Ipself *freeipself;
901 iplinkfree(Iplink *p)
907 for(np = *l; np; np = *l){
908 if(np->expire > now){
915 p->expire = now + 5000; /* give other threads 5 secs to get out */
921 ipselffree(Ipself *p)
927 for(np = *l; np; np = *l){
928 if(np->expire > now){
935 p->expire = now + 5000; /* give other threads 5 secs to get out */
941 * Decrement reference for this address on this link.
942 * Unlink from selftab if this is the last ref.
943 * called with c->car locked
946 remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
949 Iplink *link, **l_self, **l_lifc;
953 /* find the unique selftab entry */
954 l = &f->self->hash[hashipa(a)];
955 for(p = *l; p; p = *l){
956 if(ipcmp(p->a, a) == 0)
965 * walk down links from an ifc looking for one
966 * that matches the selftab entry
968 l_lifc = &lifc->link;
969 for(link = *l_lifc; link; link = *l_lifc){
972 l_lifc = &link->lifclink;
979 * walk down the links from the selftab looking for
980 * the one we just found
983 for(link = *l_self; link; link = *l_self){
986 l_self = &link->selflink;
990 panic("remselfcache");
992 if(--(link->ref) != 0)
995 if((p->type & Rmulti) && ifc->m->remmulti != nil)
996 (*ifc->m->remmulti)(ifc, a, lifc->local);
998 /* ref == 0, remove from both chains and free the link */
999 *l_lifc = link->lifclink;
1000 *l_self = link->selflink;
1006 /* remove from routing table */
1008 v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
1010 v6delroute(f, a, IPallbits, 1);
1012 /* no more links, remove from hash and free */
1016 /* if IPnoaddr, forget */
1017 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1018 f->self->acceptall = 0;
1024 static char *stformat = "%-44.44I %2.2d %4.4s\n";
1031 ipselftabread(Fs *f, char *cp, ulong offset, int n)
1033 int i, m, nifc, off;
1041 for(i = 0; i < NHASH && m < n; i++){
1042 for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
1044 for(link = p->link; link; link = link->selflink)
1046 routetype(p->type, state);
1047 m += snprint(cp + m, n - m, stformat, p->a, nifc, state);
1059 iptentative(Fs *f, uchar *addr)
1063 p = f->self->hash[hashipa(addr)];
1064 for(; p; p = p->next){
1065 if(ipcmp(addr, p->a) == 0)
1066 return p->link->lifc->tentative;
1079 ipforme(Fs *f, uchar *addr)
1083 p = f->self->hash[hashipa(addr)];
1084 for(; p; p = p->next){
1085 if(ipcmp(addr, p->a) == 0)
1089 /* hack to say accept anything */
1090 if(f->self->acceptall)
1096 * find the ifc on same net as the remote system. If none,
1100 findipifc(Fs *f, uchar *remote, int type)
1105 uchar gnet[IPaddrlen], xmask[IPaddrlen];
1108 memset(xmask, 0, IPaddrlen);
1110 /* find most specific match */
1111 e = &f->ipifc->conv[f->ipifc->nc];
1112 for(cp = f->ipifc->conv; cp < e; cp++){
1115 ifc = (Ipifc*)(*cp)->ptcl;
1116 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1117 maskip(remote, lifc->mask, gnet);
1118 if(ipcmp(gnet, lifc->net) == 0){
1119 if(x == nil || ipcmp(lifc->mask, xmask) > 0){
1121 ipmove(xmask, lifc->mask);
1129 /* for now for broadcast and multicast, just use first interface */
1130 if(type & (Rbcast|Rmulti)){
1131 for(cp = f->ipifc->conv; cp < e; cp++){
1134 ifc = (Ipifc*)(*cp)->ptcl;
1135 if(ifc->lifc != nil)
1143 unknownv6, /* UGH */
1151 v6addrtype(uchar *addr)
1153 if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
1155 else if(islinklocal(addr) ||
1156 isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
1162 #define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
1163 (lifc)->origint + (lifc)->preflt >= NOW/1000)
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; 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 ip 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){
1214 ipmove(local, lifc->local);
1221 * find the local address 'closest' to the remote system, copy it to
1222 * local and return the ifc for that address
1225 findlocalip(Fs *f, uchar *local, uchar *remote)
1227 int version, atype = unspecifiedv6, atypel = unknownv6;
1228 int atyper, deprecated;
1229 uchar gate[IPaddrlen], gnet[IPaddrlen];
1237 r = v6lookup(f, remote, nil);
1238 version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6;
1243 v4tov6(gate, r->v4.gate);
1245 ipmove(gate, r->v6.gate);
1246 ipmove(local, v6Unspecified);
1251 /* find ifc address closest to the gateway to use */
1252 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1253 maskip(gate, lifc->mask, gnet);
1254 if(ipcmp(gnet, lifc->net) == 0){
1255 ipmove(local, lifc->local);
1261 /* find ifc address with scope matching the destination */
1262 atyper = v6addrtype(remote);
1264 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1265 atypel = v6addrtype(lifc->local);
1266 /* prefer appropriate scope */
1267 if(atypel > atype && atype < atyper ||
1268 atypel < atype && atype > atyper){
1269 ipmove(local, lifc->local);
1270 deprecated = !v6addrcurr(lifc);
1272 } else if(atypel == atype){
1273 /* avoid deprecated addresses */
1274 if(deprecated && v6addrcurr(lifc)){
1275 ipmove(local, lifc->local);
1280 if(atype == atyper && !deprecated)
1287 panic("findlocalip: version %d", version);
1293 findprimaryipv4(f, local);
1296 findprimaryipv6(f, local);
1299 panic("findlocalip2: version %d", version);
1307 * return first v4 address associated with an interface
1310 ipv4local(Ipifc *ifc, uchar *addr)
1314 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1315 if(isv4(lifc->local)){
1316 memmove(addr, lifc->local+IPv4off, IPv4addrlen);
1324 * return first v6 address associated with an interface
1327 ipv6local(Ipifc *ifc, uchar *addr)
1331 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1332 if(!isv4(lifc->local) && !(lifc->tentative)){
1333 ipmove(addr, lifc->local);
1341 ipv6anylocal(Ipifc *ifc, uchar *addr)
1345 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1346 if(!isv4(lifc->local)){
1347 ipmove(addr, lifc->local);
1355 * see if this address is bound to the interface
1358 iplocalonifc(Ipifc *ifc, uchar *ip)
1362 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1363 if(ipcmp(ip, lifc->local) == 0)
1370 * See if we're proxying for this address on this interface
1373 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
1376 uchar net[IPaddrlen];
1379 /* see if this is a direct connected pt to pt address */
1380 r = v6lookup(f, ip, nil);
1381 if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
1384 /* see if this is on the right interface */
1385 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1386 maskip(ip, lifc->mask, net);
1387 if(ipcmp(net, lifc->remote) == 0)
1394 * return multicast version if any
1397 ipismulticast(uchar *ip)
1400 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1403 else if(ip[0] == 0xff)
1411 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1413 else if(ipcmp(ip, IPv4bcast) == 0)
1416 else if(ip[0] == 0xff)
1423 * add a multicast address to an interface, called with c->car locked
1426 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
1431 Ipmulti *multi, **l;
1436 for(l = &c->multi; *l; l = &(*l)->next)
1437 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1438 return; /* it's already there */
1440 multi = *l = smalloc(sizeof(*multi));
1441 ipmove(multi->ma, ma);
1442 ipmove(multi->ia, ia);
1445 for(p = f->ipifc->conv; *p; p++){
1446 if((*p)->inuse == 0)
1448 ifc = (Ipifc*)(*p)->ptcl;
1454 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1455 if(ipcmp(ia, lifc->local) == 0)
1456 addselfcache(f, ifc, lifc, ma, Rmulti);
1464 * remove a multicast address from an interface, called with c->car locked
1467 ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
1469 Ipmulti *multi, **l;
1477 for(l = &c->multi; *l; l = &(*l)->next)
1478 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1483 return; /* we don't have it open */
1487 for(p = f->ipifc->conv; *p; p++){
1488 if((*p)->inuse == 0)
1491 ifc = (Ipifc*)(*p)->ptcl;
1497 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1498 if(ipcmp(ia, lifc->local) == 0)
1499 remselfcache(f, ifc, lifc, ma);
1508 * make lifc's join and leave multicast groups
1511 ipifcjoinmulti(Ipifc *ifc, char **argv, int argc)
1513 USED(ifc, argv, argc);
1518 ipifcleavemulti(Ipifc *ifc, char **argv, int argc)
1520 USED(ifc, argv, argc);
1525 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
1531 uchar net[IPaddrlen];
1533 /* register the address on any network that will proxy for us */
1534 e = &f->ipifc->conv[f->ipifc->nc];
1536 if(!isv4(ip)) { /* V6 */
1537 for(cp = f->ipifc->conv; cp < e; cp++){
1538 if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
1542 if(m == nil || m->addmulti == nil) {
1546 for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1547 maskip(ip, lifc->mask, net);
1548 if(ipcmp(net, lifc->remote) == 0) {
1549 /* add solicited-node multicast addr */
1550 ipv62smcast(net, ip);
1551 addselfcache(f, nifc, lifc, net, Rmulti);
1552 arpenter(f, V6, ip, nifc->mac, 6, 0);
1553 // (*m->addmulti)(nifc, net, ip);
1561 for(cp = f->ipifc->conv; cp < e; cp++){
1562 if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
1566 if(m == nil || m->areg == nil){
1570 for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1571 maskip(ip, lifc->mask, net);
1572 if(ipcmp(net, lifc->remote) == 0){
1573 (*m->areg)(nifc, ip);
1583 /* added for new v6 mesg types */
1585 adddefroute6(Fs *f, uchar *gate, int force)
1589 r = v6lookup(f, v6Unspecified, nil);
1591 * route entries generated by all other means take precedence
1592 * over router announcements.
1594 if (r && !force && strcmp(r->tag, "ra") != 0)
1597 v6delroute(f, v6Unspecified, v6Unspecified, 1);
1598 v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
1606 ipifcadd6(Ipifc *ifc, char**argv, int argc)
1609 long origint = NOW / 1000, preflt = ~0L, validlt = ~0L;
1610 char addr[40], preflen[6];
1612 uchar autoflag = 1, onlink = 1;
1613 uchar prefix[IPaddrlen];
1618 preflt = atoi(argv[6]);
1621 validlt = atoi(argv[5]);
1624 autoflag = atoi(argv[4]);
1627 onlink = atoi(argv[3]);
1630 plen = atoi(argv[2]);
1638 if (parseip(prefix, argv[1]) != 6 || validlt < preflt || plen < 0 ||
1639 plen > 64 || islinklocal(prefix))
1642 lifc = smalloc(sizeof(Iplifc));
1643 lifc->onlink = (onlink != 0);
1644 lifc->autoflag = (autoflag != 0);
1645 lifc->validlt = validlt;
1646 lifc->preflt = preflt;
1647 lifc->origint = origint;
1649 /* issue "add" ctl msg for v6 link-local addr and prefix len */
1650 if(!ifc->m->pref2addr)
1652 ifc->m->pref2addr(prefix, ifc->mac); /* mac → v6 link-local addr */
1653 sprint(addr, "%I", prefix);
1654 sprint(preflen, "/%d", plen);
1657 params[2] = preflen;
1659 return ipifcadd(ifc, params, 3, 0, lifc);