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 /* disassociate logical interfaces (before zeroing ifc->arg) */
185 err = ipifcremlifc(ifc, ifc->lifc);
187 * note: err non-zero means lifc not found,
188 * which can't happen in this case.
194 /* disassociate device */
195 if(ifc->m && ifc->m->unbind)
196 (*ifc->m->unbind)(ifc);
197 memset(ifc->dev, 0, sizeof(ifc->dev));
201 /* close queues to stop queuing of packets */
202 qclose(ifc->conv->rq);
203 qclose(ifc->conv->wq);
204 qclose(ifc->conv->sq);
206 /* dissociate routes */
208 if(ifc->m != nil && ifc->m->unbindonclose == 0)
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 && ifc->m->pktin)
303 (*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);
426 /* ignore if this is already a local address for this ifc */
427 for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
428 if(ipcmp(lifc->local, ip) == 0) {
429 if(lifc->tentative != tentative)
430 lifc->tentative = tentative;
432 lifc->onlink = lifcp->onlink;
433 lifc->autoflag = lifcp->autoflag;
434 lifc->validlt = lifcp->validlt;
435 lifc->preflt = lifcp->preflt;
436 lifc->origint = lifcp->origint;
442 /* add the address to the list of logical ifc's for this ifc */
443 lifc = smalloc(sizeof(Iplifc));
444 ipmove(lifc->local, ip);
445 ipmove(lifc->mask, mask);
446 ipmove(lifc->remote, rem);
447 ipmove(lifc->net, net);
448 lifc->tentative = tentative;
450 lifc->onlink = lifcp->onlink;
451 lifc->autoflag = lifcp->autoflag;
452 lifc->validlt = lifcp->validlt;
453 lifc->preflt = lifcp->preflt;
454 lifc->origint = lifcp->origint;
455 } else { /* default values */
456 lifc->onlink = lifc->autoflag = 1;
457 lifc->validlt = lifc->preflt = ~0L;
458 lifc->origint = NOW / 1000;
462 for(l = &ifc->lifc; *l; l = &(*l)->next)
466 /* check for point-to-point interface */
467 if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */
468 if(ipcmp(mask, IPallbits) == 0)
471 /* add local routes */
473 v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
475 v6addroute(f, tifc, rem, mask, rem, type);
477 addselfcache(f, ifc, lifc, ip, Runi);
479 if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){
480 ipifcregisterproxy(f, ifc, rem);
484 if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
485 /* add subnet directed broadcast 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 subnet directed network address to the self cache */
491 for(i = 0; i < IPaddrlen; i++)
492 bcast[i] = (ip[i] & mask[i]) & mask[i];
493 addselfcache(f, ifc, lifc, bcast, Rbcast);
495 /* add network directed broadcast address to the self cache */
496 memmove(mask, defmask(ip), IPaddrlen);
497 for(i = 0; i < IPaddrlen; i++)
498 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
499 addselfcache(f, ifc, lifc, bcast, Rbcast);
501 /* add network directed network address to the self cache */
502 memmove(mask, defmask(ip), IPaddrlen);
503 for(i = 0; i < IPaddrlen; i++)
504 bcast[i] = (ip[i] & mask[i]) & mask[i];
505 addselfcache(f, ifc, lifc, bcast, Rbcast);
507 addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
510 if(ipcmp(ip, v6loopback) == 0) {
511 /* add node-local mcast address */
512 addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
514 /* add route for all node multicast */
515 v6addroute(f, tifc, v6allnodesN, v6allnodesNmask,
516 v6allnodesN, Rmulti);
519 /* add all nodes multicast address */
520 addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
522 /* add route for all nodes multicast */
523 v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL,
526 /* add solicited-node multicast address */
527 ipv62smcast(bcast, ip);
528 addselfcache(f, ifc, lifc, bcast, Rmulti);
533 /* register the address on this network for address resolution */
534 if(isv4(ip) && ifc->m->areg)
535 (*ifc->m->areg)(ifc, ip);
541 if(!isv4(ip) && ipcmp(ip, IPnoaddr) != 0){
543 arpenter(f, V6, ip, ifc->mac, 6, 0);
545 icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
552 * remove a logical interface from an ifc
553 * always called with ifc wlock'd
556 ipifcremlifc(Ipifc *ifc, Iplifc *lifc)
564 * find address on this interface and remove from chain.
565 * for pt to pt we actually specify the remote address as the
566 * addresss to remove.
568 for(l = &ifc->lifc; *l != nil && *l != lifc; l = &(*l)->next)
571 return "address not on this interface";
574 /* disassociate any addresses */
576 remselfcache(f, ifc, lifc, lifc->link->self->a);
578 /* remove the route for this logical interface */
579 if(isv4(lifc->local))
580 v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);
582 v6delroute(f, lifc->remote, lifc->mask, 1);
583 if(ipcmp(lifc->local, v6loopback) == 0)
584 /* remove route for all node multicast */
585 v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
586 else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0)
587 /* remove route for all link multicast */
588 v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
596 * remove an address from an interface.
597 * called with c->car locked
600 ipifcrem(Ipifc *ifc, char **argv, int argc)
603 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
609 if (parseip(ip, argv[1]) == -1)
611 parseipmask(mask, argv[2]);
613 maskip(ip, mask, rem);
615 if (parseip(rem, argv[3]) == -1)
619 * find address on this interface and remove from chain.
620 * for pt to pt we actually specify the remote address as the
621 * addresss to remove.
624 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
625 if (memcmp(ip, lifc->local, IPaddrlen) == 0
626 && memcmp(mask, lifc->mask, IPaddrlen) == 0
627 && memcmp(rem, lifc->remote, IPaddrlen) == 0)
630 rv = ipifcremlifc(ifc, lifc);
636 * distribute routes to active interfaces like the
640 ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type)
646 e = &f->ipifc->conv[f->ipifc->nc];
647 for(cp = f->ipifc->conv; cp < e; cp++){
649 ifc = (Ipifc*)(*cp)->ptcl;
652 (*m->addroute)(ifc, vers, addr, mask, gate, type);
658 ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask)
664 e = &f->ipifc->conv[f->ipifc->nc];
665 for(cp = f->ipifc->conv; cp < e; cp++){
667 ifc = (Ipifc*)(*cp)->ptcl;
669 if(m && m->remroute){
671 (*m->remroute)(ifc, vers, addr, mask);
680 * associate an address with the interface. This wipes out any previous
681 * addresses. This is a macro that means, remove all the old interfaces
685 ipifcconnect(Conv* c, char **argv, int argc)
690 ifc = (Ipifc*)c->ptcl;
693 return "ipifc not yet bound to device";
697 err = ipifcremlifc(ifc, ifc->lifc);
705 err = ipifcadd(ifc, argv, argc, 0, nil);
714 ipifcra6(Ipifc *ifc, char **argv, int argc)
716 int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
721 if(argsleft % 2 != 0)
724 while (argsleft > 1) {
725 if(strcmp(argv[i], "recvra") == 0)
726 ifc->recvra6 = (atoi(argv[i+1]) != 0);
727 else if(strcmp(argv[i], "sendra") == 0)
728 ifc->sendra6 = (atoi(argv[i+1]) != 0);
729 else if(strcmp(argv[i], "mflag") == 0)
730 ifc->rp.mflag = (atoi(argv[i+1]) != 0);
731 else if(strcmp(argv[i], "oflag") == 0)
732 ifc->rp.oflag = (atoi(argv[i+1]) != 0);
733 else if(strcmp(argv[i], "maxraint") == 0)
734 ifc->rp.maxraint = atoi(argv[i+1]);
735 else if(strcmp(argv[i], "minraint") == 0)
736 ifc->rp.minraint = atoi(argv[i+1]);
737 else if(strcmp(argv[i], "linkmtu") == 0)
738 ifc->rp.linkmtu = atoi(argv[i+1]);
739 else if(strcmp(argv[i], "reachtime") == 0)
740 ifc->rp.reachtime = atoi(argv[i+1]);
741 else if(strcmp(argv[i], "rxmitra") == 0)
742 ifc->rp.rxmitra = atoi(argv[i+1]);
743 else if(strcmp(argv[i], "ttl") == 0)
744 ifc->rp.ttl = atoi(argv[i+1]);
745 else if(strcmp(argv[i], "routerlt") == 0)
746 ifc->rp.routerlt = atoi(argv[i+1]);
754 /* consistency check */
755 if(ifc->rp.maxraint < ifc->rp.minraint) {
756 ifc->rp.maxraint = vmax;
757 ifc->rp.minraint = vmin;
764 * non-standard control messages.
765 * called with c->car locked.
768 ipifcctl(Conv* c, char**argv, int argc)
773 ifc = (Ipifc*)c->ptcl;
774 if(strcmp(argv[0], "add") == 0)
775 return ipifcadd(ifc, argv, argc, 0, nil);
776 else if(strcmp(argv[0], "try") == 0)
777 return ipifcadd(ifc, argv, argc, 1, nil);
778 else if(strcmp(argv[0], "remove") == 0)
779 return ipifcrem(ifc, argv, argc);
780 else if(strcmp(argv[0], "unbind") == 0)
781 return ipifcunbind(ifc);
782 else if(strcmp(argv[0], "joinmulti") == 0)
783 return ipifcjoinmulti(ifc, argv, argc);
784 else if(strcmp(argv[0], "leavemulti") == 0)
785 return ipifcleavemulti(ifc, argv, argc);
786 else if(strcmp(argv[0], "mtu") == 0)
787 return ipifcsetmtu(ifc, argv, argc);
788 else if(strcmp(argv[0], "reassemble") == 0){
792 else if(strcmp(argv[0], "iprouting") == 0){
796 iprouting(c->p->f, i);
799 else if(strcmp(argv[0], "add6") == 0)
800 return ipifcadd6(ifc, argv, argc);
801 else if(strcmp(argv[0], "ra6") == 0)
802 return ipifcra6(ifc, argv, argc);
803 return "unsupported ctl";
807 ipifcstats(Proto *ipifc, char *buf, int len)
809 return ipstats(ipifc->f, buf, len);
817 ipifc = smalloc(sizeof(Proto));
818 ipifc->name = "ipifc";
819 ipifc->connect = ipifcconnect;
820 ipifc->announce = nil;
821 ipifc->bind = ipifcbind;
822 ipifc->state = ipifcstate;
823 ipifc->create = ipifccreate;
824 ipifc->close = ipifcclose;
826 ipifc->ctl = ipifcctl;
828 ipifc->stats = ipifcstats;
829 ipifc->inuse = ipifcinuse;
830 ipifc->local = ipifclocal;
832 ipifc->nc = Maxmedia;
833 ipifc->ptclsize = sizeof(Ipifc);
835 f->ipifc = ipifc; /* hack for ipifcremroute, findipifc, ... */
836 f->self = smalloc(sizeof(Ipselftab)); /* hack for ipforme */
842 * add to self routing cache
843 * called with c->car locked
846 addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
858 /* see if the address already exists */
860 for(p = f->self->hash[h]; p; p = p->next)
861 if(memcmp(a, p->a, IPaddrlen) == 0)
864 /* allocate a local address and add to hash chain */
866 p = smalloc(sizeof(*p));
869 p->next = f->self->hash[h];
870 f->self->hash[h] = p;
872 /* if the null address, accept all packets */
873 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
874 f->self->acceptall = 1;
877 /* look for a link for this lifc */
878 for(lp = p->link; lp; lp = lp->selflink)
882 /* allocate a lifc-to-local link and link to both */
884 lp = smalloc(sizeof(*lp));
888 lp->selflink = p->link;
890 lp->lifclink = lifc->link;
893 /* add to routing table */
895 v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off,
898 v6addroute(f, tifc, a, IPallbits, a, type);
900 if((type & Rmulti) && ifc->m->addmulti)
901 (*ifc->m->addmulti)(ifc, a, lifc->local);
910 * These structures are unlinked from their chains while
911 * other threads may be using them. To avoid excessive locking,
912 * just put them aside for a while before freeing them.
913 * called with f->self locked
915 static Iplink *freeiplink;
916 static Ipself *freeipself;
919 iplinkfree(Iplink *p)
925 for(np = *l; np; np = *l){
926 if(np->expire > now){
933 p->expire = now + 5000; /* give other threads 5 secs to get out */
939 ipselffree(Ipself *p)
945 for(np = *l; np; np = *l){
946 if(np->expire > now){
953 p->expire = now + 5000; /* give other threads 5 secs to get out */
959 * Decrement reference for this address on this link.
960 * Unlink from selftab if this is the last ref.
961 * called with c->car locked
964 remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
967 Iplink *link, **l_self, **l_lifc;
971 /* find the unique selftab entry */
972 l = &f->self->hash[hashipa(a)];
973 for(p = *l; p; p = *l){
974 if(ipcmp(p->a, a) == 0)
983 * walk down links from an ifc looking for one
984 * that matches the selftab entry
986 l_lifc = &lifc->link;
987 for(link = *l_lifc; link; link = *l_lifc){
990 l_lifc = &link->lifclink;
997 * walk down the links from the selftab looking for
998 * the one we just found
1001 for(link = *l_self; link; link = *l_self){
1004 l_self = &link->selflink;
1008 panic("remselfcache");
1010 if(--(link->ref) != 0)
1013 if((p->type & Rmulti) && ifc->m->remmulti){
1015 (*ifc->m->remmulti)(ifc, a, lifc->local);
1020 /* ref == 0, remove from both chains and free the link */
1021 *l_lifc = link->lifclink;
1022 *l_self = link->selflink;
1028 /* remove from routing table */
1030 v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
1032 v6delroute(f, a, IPallbits, 1);
1034 /* no more links, remove from hash and free */
1038 /* if IPnoaddr, forget */
1039 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1040 f->self->acceptall = 0;
1046 static char *stformat = "%-44.44I %2.2d %4.4s\n";
1053 ipselftabread(Fs *f, char *cp, ulong offset, int n)
1055 int i, m, nifc, off;
1063 for(i = 0; i < NHASH && m < n; i++){
1064 for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
1066 for(link = p->link; link; link = link->selflink)
1068 routetype(p->type, state);
1069 m += snprint(cp + m, n - m, stformat, p->a, nifc, state);
1081 iptentative(Fs *f, uchar *addr)
1085 p = f->self->hash[hashipa(addr)];
1086 for(; p; p = p->next){
1087 if(ipcmp(addr, p->a) == 0)
1088 return p->link->lifc->tentative;
1101 ipforme(Fs *f, uchar *addr)
1105 p = f->self->hash[hashipa(addr)];
1106 for(; p; p = p->next){
1107 if(ipcmp(addr, p->a) == 0)
1111 /* hack to say accept anything */
1112 if(f->self->acceptall)
1118 * find the ifc on same net as the remote system. If none,
1122 findipifc(Fs *f, uchar *remote, int type)
1127 uchar gnet[IPaddrlen], xmask[IPaddrlen];
1130 memset(xmask, 0, IPaddrlen);
1132 /* find most specific match */
1133 e = &f->ipifc->conv[f->ipifc->nc];
1134 for(cp = f->ipifc->conv; cp < e; cp++){
1137 ifc = (Ipifc*)(*cp)->ptcl;
1138 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1139 maskip(remote, lifc->mask, gnet);
1140 if(ipcmp(gnet, lifc->net) == 0){
1141 if(x == nil || ipcmp(lifc->mask, xmask) > 0){
1143 ipmove(xmask, lifc->mask);
1151 /* for now for broadcast and multicast, just use first interface */
1152 if(type & (Rbcast|Rmulti)){
1153 for(cp = f->ipifc->conv; cp < e; cp++){
1156 ifc = (Ipifc*)(*cp)->ptcl;
1157 if(ifc->lifc != nil)
1165 unknownv6, /* UGH */
1173 v6addrtype(uchar *addr)
1175 if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
1177 else if(islinklocal(addr) ||
1178 isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
1184 #define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
1185 (lifc)->origint + (lifc)->preflt >= NOW/1000)
1188 findprimaryipv6(Fs *f, uchar *local)
1195 ipmove(local, v6Unspecified);
1196 atype = unspecifiedv6;
1199 * find "best" (global > link local > unspecified)
1200 * local address; address must be current.
1202 e = &f->ipifc->conv[f->ipifc->nc];
1203 for(cp = f->ipifc->conv; cp < e; cp++){
1206 ifc = (Ipifc*)(*cp)->ptcl;
1207 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1208 atypel = v6addrtype(lifc->local);
1209 if(atypel > atype && v6addrcurr(lifc)) {
1210 ipmove(local, lifc->local);
1212 if(atype == globalv6)
1220 * returns first ip address configured
1223 findprimaryipv4(Fs *f, uchar *local)
1229 /* find first ifc local address */
1230 e = &f->ipifc->conv[f->ipifc->nc];
1231 for(cp = f->ipifc->conv; cp < e; cp++){
1234 ifc = (Ipifc*)(*cp)->ptcl;
1235 if((lifc = ifc->lifc) != nil){
1236 ipmove(local, lifc->local);
1243 * find the local address 'closest' to the remote system, copy it to
1244 * local and return the ifc for that address
1247 findlocalip(Fs *f, uchar *local, uchar *remote)
1249 int version, atype = unspecifiedv6, atypel = unknownv6;
1250 int atyper, deprecated;
1251 uchar gate[IPaddrlen], gnet[IPaddrlen];
1259 r = v6lookup(f, remote, nil);
1260 version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6;
1265 v4tov6(gate, r->v4.gate);
1267 ipmove(gate, r->v6.gate);
1268 ipmove(local, v6Unspecified);
1273 /* find ifc address closest to the gateway to use */
1274 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1275 maskip(gate, lifc->mask, gnet);
1276 if(ipcmp(gnet, lifc->net) == 0){
1277 ipmove(local, lifc->local);
1283 /* find ifc address with scope matching the destination */
1284 atyper = v6addrtype(remote);
1286 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1287 atypel = v6addrtype(lifc->local);
1288 /* prefer appropriate scope */
1289 if(atypel > atype && atype < atyper ||
1290 atypel < atype && atype > atyper){
1291 ipmove(local, lifc->local);
1292 deprecated = !v6addrcurr(lifc);
1294 } else if(atypel == atype){
1295 /* avoid deprecated addresses */
1296 if(deprecated && v6addrcurr(lifc)){
1297 ipmove(local, lifc->local);
1302 if(atype == atyper && !deprecated)
1309 panic("findlocalip: version %d", version);
1315 findprimaryipv4(f, local);
1318 findprimaryipv6(f, local);
1321 panic("findlocalip2: version %d", version);
1329 * return first v4 address associated with an interface
1332 ipv4local(Ipifc *ifc, uchar *addr)
1336 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1337 if(isv4(lifc->local)){
1338 memmove(addr, lifc->local+IPv4off, IPv4addrlen);
1346 * return first v6 address associated with an interface
1349 ipv6local(Ipifc *ifc, uchar *addr)
1353 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1354 if(!isv4(lifc->local) && !(lifc->tentative)){
1355 ipmove(addr, lifc->local);
1363 ipv6anylocal(Ipifc *ifc, uchar *addr)
1367 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1368 if(!isv4(lifc->local)){
1369 ipmove(addr, lifc->local);
1377 * see if this address is bound to the interface
1380 iplocalonifc(Ipifc *ifc, uchar *ip)
1384 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1385 if(ipcmp(ip, lifc->local) == 0)
1392 * See if we're proxying for this address on this interface
1395 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
1398 uchar net[IPaddrlen];
1401 /* see if this is a direct connected pt to pt address */
1402 r = v6lookup(f, ip, nil);
1403 if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
1406 /* see if this is on the right interface */
1407 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1408 maskip(ip, lifc->mask, net);
1409 if(ipcmp(net, lifc->remote) == 0)
1416 * return multicast version if any
1419 ipismulticast(uchar *ip)
1422 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1425 else if(ip[0] == 0xff)
1433 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1435 else if(ipcmp(ip, IPv4bcast) == 0)
1438 else if(ip[0] == 0xff)
1445 * add a multicast address to an interface, called with c->car locked
1448 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
1453 Ipmulti *multi, **l;
1458 for(l = &c->multi; *l; l = &(*l)->next)
1459 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1460 return; /* it's already there */
1462 multi = *l = smalloc(sizeof(*multi));
1463 ipmove(multi->ma, ma);
1464 ipmove(multi->ia, ia);
1467 for(p = f->ipifc->conv; *p; p++){
1468 if((*p)->inuse == 0)
1470 ifc = (Ipifc*)(*p)->ptcl;
1476 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1477 if(ipcmp(ia, lifc->local) == 0)
1478 addselfcache(f, ifc, lifc, ma, Rmulti);
1486 * remove a multicast address from an interface, called with c->car locked
1489 ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
1491 Ipmulti *multi, **l;
1499 for(l = &c->multi; *l; l = &(*l)->next)
1500 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1505 return; /* we don't have it open */
1509 for(p = f->ipifc->conv; *p; p++){
1510 if((*p)->inuse == 0)
1513 ifc = (Ipifc*)(*p)->ptcl;
1515 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1516 if(ipcmp(ia, lifc->local) == 0)
1517 remselfcache(f, ifc, lifc, ma);
1525 * make lifc's join and leave multicast groups
1528 ipifcjoinmulti(Ipifc *ifc, char **argv, int argc)
1530 USED(ifc, argv, argc);
1535 ipifcleavemulti(Ipifc *ifc, char **argv, int argc)
1537 USED(ifc, argv, argc);
1542 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
1548 uchar net[IPaddrlen];
1550 /* register the address on any network that will proxy for us */
1551 e = &f->ipifc->conv[f->ipifc->nc];
1553 if(!isv4(ip)) { /* V6 */
1554 for(cp = f->ipifc->conv; cp < e; cp++){
1555 if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
1559 if(m == nil || m->addmulti == nil) {
1567 for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1568 maskip(ip, lifc->mask, net);
1569 if(ipcmp(net, lifc->remote) == 0) {
1570 /* add solicited-node multicast addr */
1571 ipv62smcast(net, ip);
1572 addselfcache(f, nifc, lifc, net, Rmulti);
1573 arpenter(f, V6, ip, nifc->mac, 6, 0);
1582 for(cp = f->ipifc->conv; cp < e; cp++){
1583 if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
1587 if(m == nil || m->areg == nil){
1595 for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1596 maskip(ip, lifc->mask, net);
1597 if(ipcmp(net, lifc->remote) == 0){
1598 (*m->areg)(nifc, ip);
1609 /* added for new v6 mesg types */
1611 adddefroute6(Fs *f, uchar *gate, int force)
1615 r = v6lookup(f, v6Unspecified, nil);
1617 * route entries generated by all other means take precedence
1618 * over router announcements.
1620 if (r && !force && strcmp(r->tag, "ra") != 0)
1623 v6delroute(f, v6Unspecified, v6Unspecified, 1);
1624 v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
1632 ipifcadd6(Ipifc *ifc, char**argv, int argc)
1635 char addr[40], preflen[6];
1637 uchar prefix[IPaddrlen];
1644 lifc.origint = NOW / 1000;
1648 lifc.preflt = atoi(argv[6]);
1651 lifc.validlt = atoi(argv[5]);
1654 lifc.autoflag = atoi(argv[4]) != 0;
1657 lifc.onlink = atoi(argv[3]) != 0;
1660 plen = atoi(argv[2]);
1668 if (parseip(prefix, argv[1]) != 6 || lifc.validlt < lifc.preflt || plen < 0 ||
1669 plen > 64 || islinklocal(prefix))
1672 /* issue "add" ctl msg for v6 link-local addr and prefix len */
1673 if(ifc->m->pref2addr == nil)
1675 (*ifc->m->pref2addr)(prefix, ifc->mac); /* mac → v6 link-local addr */
1677 sprint(addr, "%I", prefix);
1678 sprint(preflen, "/%d", plen);
1681 params[2] = preflen;
1683 return ipifcadd(ifc, params, 3, 0, &lifc);