2 #include "../port/lib.h"
6 #include "../port/error.h"
11 #define DPRINT if(0)print
21 Medium *media[Maxmedia] = { 0 };
24 * cache of local addresses (addresses we answer to)
29 Ipself *hnext; /* next address in the hash table */
30 Iplink *link; /* binding twixt Ipself and Ipifc */
32 uchar type; /* type of address */
34 Ipself *next; /* free list */
41 int acceptall; /* true if an interface has the null address */
42 Ipself *hash[NHASH]; /* hash chains */
46 * Multicast addresses are chained onto a Chan so that
47 * we can remove them when the Chan is closed.
49 typedef struct Ipmcast Ipmcast;
53 uchar ma[IPaddrlen]; /* multicast address */
54 uchar ia[IPaddrlen]; /* interface address */
57 /* quick hash for ip addresses */
58 #define hashipa(a) ( ( ((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1] )%NHASH )
60 static char tifc[] = "ifc ";
62 static void addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
63 static void remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
64 static void ipifcregisteraddr(Fs*, Ipifc*, uchar *, uchar *);
65 static void ipifcregisterproxy(Fs*, Ipifc*, uchar*, int);
66 static char* ipifcremlifc(Ipifc*, Iplifc**);
76 v6addrtype(uchar *addr)
78 if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
80 else if(islinklocal(addr) ||
81 isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
87 #define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
88 (lifc)->origint + (lifc)->preflt >= NOW/1000)
91 comprefixlen(uchar *a, uchar *b, int n)
95 for(i = 0; i < n; i++){
96 if((c = a[i] ^ b[i]) == 0)
98 for(i <<= 3; (c & 0x80) == 0; i++)
106 * link in a new medium
109 addipmedium(Medium *med)
113 for(i = 0; i < nelem(media)-1; i++)
121 * find the medium with this name
124 ipfindmedium(char *name)
128 for(mp = media; *mp != nil; mp++)
129 if(strcmp((*mp)->name, name) == 0)
135 * attach a device (or pkt driver) to the interface.
136 * called with c locked
139 ipifcbind(Conv *c, char **argv, int argc)
147 ifc = (Ipifc*)c->ptcl;
149 /* bind the device to the interface */
150 m = ipfindmedium(argv[1]);
152 return "unknown interface type";
157 return "interface already bound";
164 /* do medium specific binding */
165 (*m->bind)(ifc, argc, argv);
167 /* set the bound device name */
169 strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
171 snprint(ifc->dev, sizeof ifc->dev, "%s%d", m->name, c->x);
172 ifc->dev[sizeof(ifc->dev)-1] = 0;
174 /* set up parameters */
176 ifc->mintu = ifc->m->mintu;
177 ifc->maxtu = ifc->m->maxtu;
178 if(ifc->m->unbindonclose == 0)
180 ifc->rp.mflag = 0; /* default not managed */
182 ifc->rp.maxraint = 600000; /* millisecs */
183 ifc->rp.minraint = 200000;
184 ifc->rp.linkmtu = 0; /* no mtu sent */
185 ifc->rp.reachtime = 0;
187 ifc->rp.ttl = MAXTTL;
188 ifc->rp.routerlt = 3 * ifc->rp.maxraint;
190 /* any ancillary structures (like routes) no longer pertain */
193 /* reopen all the queues closed by a previous unbind */
205 * detach a device from an interface, close the interface
206 * called with ifc->conv closed
209 ipifcunbind(Ipifc *ifc)
219 /* disassociate logical interfaces (before zeroing ifc->arg) */
220 while(ifc->lifc != nil){
221 err = ipifcremlifc(ifc, &ifc->lifc);
226 /* disassociate device */
227 if(ifc->m != nil && ifc->m->unbind != nil)
228 (*ifc->m->unbind)(ifc);
229 memset(ifc->dev, 0, sizeof(ifc->dev));
235 /* close queues to stop queuing of packets */
236 qclose(ifc->conv->rq);
237 qclose(ifc->conv->wq);
238 qclose(ifc->conv->sq);
240 /* dissociate routes */
242 if(ifc->m != nil && ifc->m->unbindonclose == 0)
251 char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag"
252 " %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt"
253 " %d pktin %lud pktout %lud errin %lud errout %lud speed %d delay %d\n";
255 char slineformat[] = " %-40I %-10M %-40I %-12lud %-12lud\n";
258 ipifcstate(Conv *c, char *state, int n)
264 ifc = (Ipifc*)c->ptcl;
265 m = snprint(state, n, sfixedformat,
266 ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
267 ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
268 ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
269 ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
270 ifc->in, ifc->out, ifc->inerr, ifc->outerr,
271 ifc->speed, ifc->delay);
274 for(lifc = ifc->lifc; lifc != nil && n > m; lifc = lifc->next)
275 m += snprint(state+m, n - m, slineformat, lifc->local,
276 lifc->mask, lifc->remote, lifc->validlt, lifc->preflt);
278 m += snprint(state+m, n - m, "\n");
284 ipifclocal(Conv *c, char *state, int n)
291 ifc = (Ipifc*)c->ptcl;
294 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
295 m += snprint(state+m, n - m, "%-40.40I ->", lifc->local);
296 for(link = lifc->link; link != nil; link = link->lifclink)
297 m += snprint(state+m, n - m, " %-40.40I", link->self->a);
298 m += snprint(state+m, n - m, "\n");
309 ifc = (Ipifc*)c->ptcl;
310 return ifc->m != nil;
314 ipifcsetdelay(Ipifc *ifc, int delay)
318 else if(delay > 1000)
321 ifc->burst = ((vlong)delay * ifc->speed) / 8000;
322 if(ifc->burst < ifc->maxtu)
323 ifc->burst = ifc->maxtu;
327 ipifcsetspeed(Ipifc *ifc, int speed)
333 ipifcsetdelay(ifc, ifc->delay);
337 ipifcoput(Ipifc *ifc, Block *bp, int version, uchar *ip)
340 ulong now = MACHP(0)->ticks;
341 int dt = TK2MS(now - ifc->ticks);
343 ifc->load -= ((vlong)dt * ifc->speed) / 8000;
344 if(ifc->load < 0 || dt < 0 || dt > 1000)
346 else if(ifc->load > ifc->burst){
351 bp = concatblock(bp);
352 ifc->load += BLEN(bp);
353 ifc->m->bwrite(ifc, bp, version, ip);
358 * called when a process writes to an interface's 'data'
371 ifc = (Ipifc*)c->ptcl;
380 if(ifc->m != nil && ifc->m->pktin != nil)
381 (*ifc->m->pktin)(c->p->f, ifc, bp);
389 * called when a new ipifc structure is created
396 c->rq = qopen(QMAX, 0, 0, 0);
397 c->wq = qopen(QMAX, Qkick, ipifckick, c);
398 c->sq = qopen(QMAX, 0, 0, 0);
399 if(c->rq == nil || c->wq == nil || c->sq == nil)
401 ifc = (Ipifc*)c->ptcl;
406 ipifcsetspeed(ifc, 0);
407 ipifcsetdelay(ifc, 40);
411 * called after last close of ipifc data or ctl
412 * called with c locked, we must unlock
419 ifc = (Ipifc*)c->ptcl;
420 if(ifc->m != nil && ifc->m->unbindonclose)
425 * change an interface's mtu
428 ipifcsetmtu(Ipifc *ifc, char **argv, int argc)
432 if(argc < 2 || ifc->m == nil)
434 mtu = strtoul(argv[1], 0, 0);
435 if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu)
442 * add an address to an interface.
445 ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
447 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
448 uchar bcast[IPaddrlen], net[IPaddrlen];
455 memset(ip, 0, IPaddrlen);
456 memset(mask, 0, IPaddrlen);
457 memset(rem, 0, IPaddrlen);
460 if(strcmp(argv[5], "proxy") == 0)
464 mtu = strtoul(argv[4], 0, 0);
467 if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1)
469 parseipmask(mask, argv[2]);
470 maskip(rem, mask, net);
473 if (parseip(ip, argv[1]) == -1)
475 parseipmask(mask, argv[2]);
476 maskip(ip, mask, rem);
477 maskip(rem, mask, net);
480 if (parseip(ip, argv[1]) == -1)
482 memmove(mask, defmask(ip), IPaddrlen);
483 maskip(ip, mask, rem);
484 maskip(rem, mask, net);
490 /* check for point-to-point interface */
491 if(ipcmp(ip, v6loopback) != 0) /* skip v6 loopback, it's a special address */
492 if(ipcmp(mask, IPallbits) == 0)
495 if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0){
502 return "ipifc not yet bound to device";
510 if(mtu > 0 && mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
513 /* ignore if this is already a local address for this ifc */
514 if((lifc = iplocalonifc(ifc, ip)) != nil){
516 lifc->onlink = lifcp->onlink;
517 lifc->autoflag = lifcp->autoflag;
518 lifc->validlt = lifcp->validlt;
519 lifc->preflt = lifcp->preflt;
520 lifc->origint = lifcp->origint;
522 if(lifc->tentative != tentative){
523 lifc->tentative = tentative;
531 /* add the address to the list of logical ifc's for this ifc */
532 lifc = smalloc(sizeof(Iplifc));
533 ipmove(lifc->local, ip);
534 ipmove(lifc->mask, mask);
535 ipmove(lifc->remote, rem);
536 ipmove(lifc->net, net);
538 lifc->tentative = tentative;
540 lifc->onlink = lifcp->onlink;
541 lifc->autoflag = lifcp->autoflag;
542 lifc->validlt = lifcp->validlt;
543 lifc->preflt = lifcp->preflt;
544 lifc->origint = lifcp->origint;
545 } else { /* default values */
546 lifc->onlink = lifc->autoflag = 1;
547 lifc->validlt = lifc->preflt = ~0L;
548 lifc->origint = NOW / 1000;
552 for(l = &ifc->lifc; *l != nil; l = &(*l)->next)
556 /* add route for this logical interface */
557 addroute(f, rem, mask, ip, IPallbits, rem, type, ifc, tifc);
558 if(v6addrtype(ip) != linklocalv6)
559 addroute(f, rem, mask, ip, IPnoaddr, rem, type, ifc, tifc);
561 addselfcache(f, ifc, lifc, ip, Runi);
566 ipifcregisterproxy(f, ifc, rem, 1);
571 /* add subnet directed broadcast address to the self cache */
572 for(i = 0; i < IPaddrlen; i++)
573 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
574 addselfcache(f, ifc, lifc, bcast, Rbcast);
576 /* add subnet directed network address to the self cache */
577 for(i = 0; i < IPaddrlen; i++)
578 bcast[i] = (ip[i] & mask[i]) & mask[i];
579 addselfcache(f, ifc, lifc, bcast, Rbcast);
581 /* add network directed broadcast address to the self cache */
582 memmove(mask, defmask(ip), IPaddrlen);
583 for(i = 0; i < IPaddrlen; i++)
584 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
585 addselfcache(f, ifc, lifc, bcast, Rbcast);
587 /* add network directed network address to the self cache */
588 memmove(mask, defmask(ip), IPaddrlen);
589 for(i = 0; i < IPaddrlen; i++)
590 bcast[i] = (ip[i] & mask[i]) & mask[i];
591 addselfcache(f, ifc, lifc, bcast, Rbcast);
593 addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
595 if(ipcmp(ip, v6loopback) == 0) {
596 /* add node-local mcast address */
597 addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
599 /* add route for all node multicast */
600 addroute(f, v6allnodesN, v6allnodesNmask,
602 v6allnodesN, Rmulti, ifc, tifc);
605 /* add all nodes multicast address */
606 addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
608 /* add route for all nodes multicast */
609 addroute(f, v6allnodesL, v6allnodesLmask,
611 v6allnodesL, Rmulti, ifc, tifc);
613 /* add solicited-node multicast address */
614 ipv62smcast(bcast, ip);
615 addselfcache(f, ifc, lifc, bcast, Rmulti);
622 ipifcregisteraddr(f, ifc, ip, ip);
628 * remove a logical interface from an ifc
629 * always called with ifc wlock'd
632 ipifcremlifc(Ipifc *ifc, Iplifc **l)
635 Fs *f = ifc->conv->p->f;
638 return "address not on this interface";
641 /* disassociate any addresses */
642 while(lifc->link != nil)
643 remselfcache(f, ifc, lifc, lifc->link->self->a);
645 /* remove the route for this logical interface */
646 remroute(f, lifc->remote, lifc->mask,
647 lifc->local, IPallbits,
648 lifc->remote, lifc->type, ifc, tifc);
649 if(v6addrtype(lifc->local) != linklocalv6)
650 remroute(f, lifc->remote, lifc->mask,
651 lifc->local, IPnoaddr,
652 lifc->remote, lifc->type, ifc, tifc);
654 /* unregister proxy */
655 if(lifc->type & Rptpt){
656 if(lifc->type & Rproxy)
657 ipifcregisterproxy(f, ifc, lifc->remote, 0);
661 /* remove route for all nodes multicast */
662 if((lifc->type & Rv4) == 0){
663 if(ipcmp(lifc->local, v6loopback) == 0)
664 remroute(f, v6allnodesN, v6allnodesNmask,
665 lifc->local, IPallbits,
666 v6allnodesN, Rmulti, ifc, tifc);
668 remroute(f, v6allnodesL, v6allnodesLmask,
669 lifc->local, IPallbits,
670 v6allnodesL, Rmulti, ifc, tifc);
679 * remove an address from an interface.
680 * called with c->car locked
683 ipifcrem(Ipifc *ifc, char **argv, int argc)
686 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
691 if(parseip(ip, argv[1]) == -1)
693 parseipmask(mask, argv[2]);
695 maskip(ip, mask, rem);
696 else if(parseip(rem, argv[3]) == -1)
700 * find address on this interface and remove from chain.
701 * for pt to pt we actually specify the remote address as the
702 * addresss to remove.
706 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
707 if(ipcmp(ip, lifc->local) == 0
708 && ipcmp(mask, lifc->mask) == 0
709 && ipcmp(rem, lifc->remote) == 0)
713 rv = ipifcremlifc(ifc, l);
719 * associate an address with the interface. This wipes out any previous
720 * addresses. This is a macro that means, remove all the old interfaces
724 ipifcconnect(Conv* c, char **argv, int argc)
729 ifc = (Ipifc*)c->ptcl;
732 return "ipifc not yet bound to device";
735 while(ifc->lifc != nil){
736 err = ipifcremlifc(ifc, &ifc->lifc);
744 err = ipifcadd(ifc, argv, argc, 0, nil);
753 ipifcra6(Ipifc *ifc, char **argv, int argc)
755 int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
760 if(argsleft % 2 != 0)
763 while (argsleft > 1) {
764 if(strcmp(argv[i], "recvra") == 0)
765 ifc->recvra6 = (atoi(argv[i+1]) != 0);
766 else if(strcmp(argv[i], "sendra") == 0)
767 ifc->sendra6 = (atoi(argv[i+1]) != 0);
768 else if(strcmp(argv[i], "mflag") == 0)
769 ifc->rp.mflag = (atoi(argv[i+1]) != 0);
770 else if(strcmp(argv[i], "oflag") == 0)
771 ifc->rp.oflag = (atoi(argv[i+1]) != 0);
772 else if(strcmp(argv[i], "maxraint") == 0)
773 ifc->rp.maxraint = atoi(argv[i+1]);
774 else if(strcmp(argv[i], "minraint") == 0)
775 ifc->rp.minraint = atoi(argv[i+1]);
776 else if(strcmp(argv[i], "linkmtu") == 0)
777 ifc->rp.linkmtu = atoi(argv[i+1]);
778 else if(strcmp(argv[i], "reachtime") == 0)
779 ifc->rp.reachtime = atoi(argv[i+1]);
780 else if(strcmp(argv[i], "rxmitra") == 0)
781 ifc->rp.rxmitra = atoi(argv[i+1]);
782 else if(strcmp(argv[i], "ttl") == 0)
783 ifc->rp.ttl = atoi(argv[i+1]);
784 else if(strcmp(argv[i], "routerlt") == 0)
785 ifc->rp.routerlt = atoi(argv[i+1]);
793 /* consistency check */
794 if(ifc->rp.maxraint < ifc->rp.minraint) {
795 ifc->rp.maxraint = vmax;
796 ifc->rp.minraint = vmin;
803 * non-standard control messages.
804 * called with c->car locked.
807 ipifcctl(Conv* c, char **argv, int argc)
811 ifc = (Ipifc*)c->ptcl;
812 if(strcmp(argv[0], "add") == 0)
813 return ipifcadd(ifc, argv, argc, 0, nil);
814 else if(strcmp(argv[0], "try") == 0)
815 return ipifcadd(ifc, argv, argc, 1, nil);
816 else if(strcmp(argv[0], "remove") == 0)
817 return ipifcrem(ifc, argv, argc);
818 else if(strcmp(argv[0], "unbind") == 0)
819 return ipifcunbind(ifc);
820 else if(strcmp(argv[0], "mtu") == 0)
821 return ipifcsetmtu(ifc, argv, argc);
822 else if(strcmp(argv[0], "speed") == 0){
823 ipifcsetspeed(ifc, argc>1? atoi(argv[1]): 0);
826 else if(strcmp(argv[0], "delay") == 0){
827 ipifcsetdelay(ifc, argc>1? atoi(argv[1]): 0);
830 else if(strcmp(argv[0], "iprouting") == 0){
831 iprouting(c->p->f, argc>1? atoi(argv[1]): 1);
834 else if(strcmp(argv[0], "reflect") == 0){
835 ifc->reflect = argc>1? atoi(argv[1]): 1;
838 else if(strcmp(argv[0], "reassemble") == 0){
839 ifc->reassemble = argc>1? atoi(argv[1]): 1;
842 else if(strcmp(argv[0], "add6") == 0)
843 return ipifcadd6(ifc, argv, argc);
844 else if(strcmp(argv[0], "ra6") == 0)
845 return ipifcra6(ifc, argv, argc);
846 return "unsupported ctl";
850 ipifcstats(Proto *ipifc, char *buf, int len)
852 return ipstats(ipifc->f, buf, len);
860 ipifc = smalloc(sizeof(Proto));
861 ipifc->name = "ipifc";
862 ipifc->connect = ipifcconnect;
863 ipifc->announce = nil;
864 ipifc->bind = ipifcbind;
865 ipifc->state = ipifcstate;
866 ipifc->create = ipifccreate;
867 ipifc->close = ipifcclose;
869 ipifc->ctl = ipifcctl;
871 ipifc->stats = ipifcstats;
872 ipifc->inuse = ipifcinuse;
873 ipifc->local = ipifclocal;
875 ipifc->nc = Maxmedia;
876 ipifc->ptclsize = sizeof(Ipifc);
878 f->ipifc = ipifc; /* hack for ipifcremroute, findipifc, ... */
879 f->self = smalloc(sizeof(Ipselftab)); /* hack for ipforme */
885 * add to self routing cache
886 * called with c->car locked
889 addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
895 type |= (lifc->type & Rv4);
903 /* see if the address already exists */
905 for(p = f->self->hash[h]; p != nil; p = p->next)
906 if(ipcmp(a, p->a) == 0)
909 /* allocate a local address and add to hash chain */
911 p = smalloc(sizeof(*p));
914 p->next = f->self->hash[h];
915 f->self->hash[h] = p;
917 /* if the null address, accept all packets */
918 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
919 f->self->acceptall = 1;
922 /* look for a link for this lifc */
923 for(lp = p->link; lp != nil; lp = lp->selflink)
927 /* allocate a lifc-to-local link and link to both */
929 lp = smalloc(sizeof(*lp));
933 lp->selflink = p->link;
935 lp->lifclink = lifc->link;
938 /* add to routing table */
939 addroute(f, a, IPallbits,
941 ((type & (Rbcast|Rmulti)) != 0 || v6addrtype(a) == linklocalv6) ?
942 IPallbits : IPnoaddr,
945 if((type & Rmulti) && ifc->m->addmulti != nil)
946 (*ifc->m->addmulti)(ifc, a, lifc->local);
955 * These structures are unlinked from their chains while
956 * other threads may be using them. To avoid excessive locking,
957 * just put them aside for a while before freeing them.
958 * called with f->self locked
960 static Iplink *freeiplink;
961 static Ipself *freeipself;
964 iplinkfree(Iplink *p)
970 for(np = *l; np != nil; np = *l){
971 if((long)(now - np->expire) >= 0){
978 p->expire = now + 5000; /* give other threads 5 secs to get out */
984 ipselffree(Ipself *p)
990 for(np = *l; np != nil; np = *l){
991 if((long)(now - np->expire) >= 0){
998 p->expire = now + 5000; /* give other threads 5 secs to get out */
1004 * Decrement reference for this address on this link.
1005 * Unlink from selftab if this is the last ref.
1006 * called with c->car locked
1009 remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
1012 Iplink *link, **l_self, **l_lifc;
1016 /* find the unique selftab entry */
1017 l = &f->self->hash[hashipa(a)];
1018 for(p = *l; p != nil; p = *l){
1019 if(ipcmp(p->a, a) == 0)
1028 * walk down links from an ifc looking for one
1029 * that matches the selftab entry
1031 l_lifc = &lifc->link;
1032 for(link = *l_lifc; link != nil; link = *l_lifc){
1035 l_lifc = &link->lifclink;
1042 * walk down the links from the selftab looking for
1043 * the one we just found
1046 for(link = *l_self; link != nil; link = *l_self){
1049 l_self = &link->selflink;
1053 panic("remselfcache");
1055 if(--(link->ref) != 0)
1058 /* remove from routing table */
1059 remroute(f, a, IPallbits,
1061 ((p->type & (Rbcast|Rmulti)) != 0 || v6addrtype(a) == linklocalv6) ?
1062 IPallbits : IPnoaddr,
1063 a, p->type, ifc, tifc);
1065 if((p->type & Rmulti) && ifc->m->remmulti != nil){
1067 (*ifc->m->remmulti)(ifc, a, lifc->local);
1072 /* ref == 0, remove from both chains and free the link */
1073 *l_lifc = link->lifclink;
1074 *l_self = link->selflink;
1080 /* if null address, forget */
1081 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1082 f->self->acceptall = 0;
1084 /* no more links, remove from hash and free */
1093 ipselftabread(Fs *f, char *cp, ulong offset, int n)
1095 int i, m, nifc, off;
1103 for(i = 0; i < NHASH && m < n; i++){
1104 for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
1106 for(link = p->link; link != nil; link = link->selflink)
1108 routetype(p->type, state);
1109 m += snprint(cp + m, n - m, "%-44.44I %2.2d %4.4s\n",
1129 ipforme(Fs *f, uchar *addr)
1133 for(p = f->self->hash[hashipa(addr)]; p != nil; p = p->next)
1134 if(ipcmp(addr, p->a) == 0)
1135 return p->type & (Runi|Rbcast|Rmulti);
1137 /* hack to say accept anything */
1138 if(f->self->acceptall)
1145 * find the ifc on same net as the remote system. If none,
1149 findipifc(Fs *f, uchar *local, uchar *remote, int type)
1151 uchar gnet[IPaddrlen];
1159 for(cp = f->ipifc->conv; *cp != nil; cp++){
1160 ifc = (Ipifc*)(*cp)->ptcl;
1162 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1164 if(ipcmp(remote, lifc->local) == 0){
1169 } else if(type & (Rbcast|Rmulti)) {
1170 if(ipcmp(local, lifc->local) == 0)
1173 maskip(remote, lifc->mask, gnet);
1174 if(ipcmp(gnet, lifc->net) == 0){
1175 spec = comprefixlen(remote, lifc->local, IPaddrlen);
1188 findipifcstr(Fs *f, char *s)
1190 uchar ip[IPaddrlen];
1195 x = strtol(s, &p, 10);
1196 if(p > s && *p == '\0'){
1199 if(x < f->ipifc->nc && (c = f->ipifc->conv[x]) != nil && ipifcinuse(c))
1200 return (Ipifc*)c->ptcl;
1202 if(parseip(ip, s) != -1)
1203 return findipifc(f, ip, ip, Runi);
1208 * find "best" (global > link local > unspecified)
1209 * local address; address must be current.
1212 findprimaryipv6(Fs *f, uchar *local)
1219 ipmove(local, v6Unspecified);
1220 atype = unspecifiedv6;
1222 for(cp = f->ipifc->conv; *cp != nil; cp++){
1223 ifc = (Ipifc*)(*cp)->ptcl;
1225 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1226 atypel = v6addrtype(lifc->local);
1227 if(atypel > atype && v6addrcurr(lifc)) {
1228 ipmove(local, lifc->local);
1230 if(atype == globalv6){
1241 * returns first v4 address configured
1244 findprimaryipv4(Fs *f, uchar *local)
1250 /* find first ifc local address */
1251 for(cp = f->ipifc->conv; *cp != nil; cp++){
1252 ifc = (Ipifc*)(*cp)->ptcl;
1254 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1255 if((lifc->type & Rv4) != 0){
1256 ipmove(local, lifc->local);
1263 ipmove(local, IPnoaddr);
1267 * return v4 address associated with an interface close to remote
1270 ipv4local(Ipifc *ifc, uchar *local, uchar *remote)
1276 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1277 if((lifc->type & Rv4) == 0)
1279 a = comprefixlen(lifc->local+IPv4off, remote, IPv4addrlen);
1282 memmove(local, lifc->local+IPv4off, IPv4addrlen);
1289 * return v6 address associated with an interface close to remote
1292 ipv6local(Ipifc *ifc, uchar *local, uchar *remote)
1303 ipmove(local, v4prefix);
1304 return ipv4local(ifc, local+IPv4off, remote+IPv4off);
1307 atype = v6addrtype(remote);
1308 ipmove(local, v6Unspecified);
1309 b.atype = unknownv6;
1313 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1317 a.atype = v6addrtype(lifc->local);
1318 a.deprecated = !v6addrcurr(lifc);
1319 a.comprefixlen = comprefixlen(lifc->local, remote, IPaddrlen);
1321 /* prefer appropriate scope */
1322 if(a.atype != b.atype){
1323 if(a.atype > b.atype && b.atype < atype ||
1324 a.atype < b.atype && b.atype > atype)
1328 /* prefer non-deprecated addresses */
1329 if(a.deprecated != b.deprecated){
1334 /* prefer longer common prefix */
1335 if(a.comprefixlen != b.comprefixlen){
1336 if(a.comprefixlen > b.comprefixlen)
1343 ipmove(local, lifc->local);
1346 return b.atype >= atype;
1350 findlocalip(Fs *f, uchar *local, uchar *remote)
1357 for(cp = f->ipifc->conv; *cp != nil; cp++){
1358 ifc = (Ipifc*)(*cp)->ptcl;
1360 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1364 r = v6lookup(f, remote, lifc->local, nil);
1365 if(r == nil || (nifc = r->ifc) == nil)
1368 ipmove(local, remote);
1372 if(nifc != ifc) rlock(nifc);
1373 if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){
1374 ipmove(local, v4prefix);
1375 if(ipv4local(nifc, local+IPv4off, r->v4.gate)){
1376 if(nifc != ifc) runlock(nifc);
1381 if(ipv6local(nifc, local, remote)){
1382 if(nifc != ifc) runlock(nifc);
1386 if(nifc != ifc) runlock(nifc);
1391 findprimaryipv4(f, local);
1393 findprimaryipv6(f, local);
1398 * see if this address is bound to the interface
1401 iplocalonifc(Ipifc *ifc, uchar *ip)
1405 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
1406 if(ipcmp(ip, lifc->local) == 0)
1413 ipremoteonifc(Ipifc *ifc, uchar *ip)
1415 uchar net[IPaddrlen];
1418 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1419 maskip(ip, lifc->mask, net);
1420 if(ipcmp(net, lifc->remote) == 0)
1428 * See if we're proxying for this address on this interface
1431 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
1435 /* see if this is a direct connected pt to pt address */
1436 r = v6lookup(f, ip, ip, nil);
1437 if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
1440 return ipremoteonifc(ifc, ip) != nil;
1444 * return multicast version if any
1447 ipismulticast(uchar *ip)
1450 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1453 else if(ip[0] == 0xff)
1459 * add a multicast address to an interface, called with c->car locked
1462 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
1464 Ipmulti *multi, **l;
1469 for(l = &c->multi; *l != nil; l = &(*l)->next)
1470 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1471 return; /* it's already there */
1473 multi = *l = smalloc(sizeof(*multi));
1474 ipmove(multi->ma, ma);
1475 ipmove(multi->ia, ia);
1479 if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
1485 if((lifc = iplocalonifc(ifc, ia)) != nil)
1486 addselfcache(f, ifc, lifc, ma, Rmulti);
1494 * remove a multicast address from an interface, called with c->car locked
1497 ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
1499 Ipmulti *multi, **l;
1504 for(l = &c->multi; *l != nil; l = &(*l)->next)
1505 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1510 return; /* we don't have it open */
1516 if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
1519 if((lifc = iplocalonifc(ifc, ia)) != nil)
1520 remselfcache(f, ifc, lifc, ma);
1528 /* register the address on this network for address resolution */
1530 ipifcregisteraddr(Fs *f, Ipifc *ifc, uchar *ia, uchar *ip)
1537 print("ipifcregisteraddr %s %I %I: %s\n", ifc->dev, ia, ip, up->errstr);
1540 lifc = iplocalonifc(ifc, ia);
1541 if(lifc != nil && ifc->m != nil && ifc->m->areg != nil)
1542 (*ifc->m->areg)(f, ifc, lifc, ip);
1548 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip, int add)
1555 /* register the address on any interface that will proxy for the ip */
1556 for(cp = f->ipifc->conv; *cp != nil; cp++){
1557 nifc = (Ipifc*)(*cp)->ptcl;
1563 || (lifc = ipremoteonifc(nifc, ip)) == nil
1564 || (lifc->type & Rptpt) != 0
1569 if((lifc->type & Rv4) == 0){
1570 /* add solicited-node multicast addr */
1573 addselfcache(f, nifc, lifc, a, Rmulti);
1575 remselfcache(f, nifc, lifc, a);
1577 ipmove(a, lifc->local);
1582 ipifcregisteraddr(f, nifc, a, ip);
1587 ipifcadd6(Ipifc *ifc, char**argv, int argc)
1590 char addr[40], preflen[6];
1592 uchar prefix[IPaddrlen];
1599 lifc.origint = NOW / 1000;
1603 lifc.preflt = atoi(argv[6]);
1606 lifc.validlt = atoi(argv[5]);
1609 lifc.autoflag = atoi(argv[4]) != 0;
1612 lifc.onlink = atoi(argv[3]) != 0;
1615 plen = atoi(argv[2]);
1623 if (parseip(prefix, argv[1]) != 6 || lifc.validlt < lifc.preflt || plen < 0 ||
1624 plen > 64 || islinklocal(prefix))
1627 /* issue "add" ctl msg for v6 link-local addr and prefix len */
1628 if(ifc->m->pref2addr == nil)
1630 (*ifc->m->pref2addr)(prefix, ifc->mac); /* mac → v6 link-local addr */
1632 sprint(addr, "%I", prefix);
1633 sprint(preflen, "/%d", plen);
1636 params[2] = preflen;
1638 return ipifcadd(ifc, params, 3, 0, &lifc);