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){
503 return "ipifc not yet bound to device";
511 if(mtu > 0 && mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
514 /* ignore if this is already a local address for this ifc */
515 if((lifc = iplocalonifc(ifc, ip)) != nil){
517 lifc->onlink = lifcp->onlink;
518 lifc->autoflag = lifcp->autoflag;
519 lifc->validlt = lifcp->validlt;
520 lifc->preflt = lifcp->preflt;
521 lifc->origint = lifcp->origint;
523 if(lifc->tentative != tentative){
524 lifc->tentative = tentative;
532 /* add the address to the list of logical ifc's for this ifc */
533 lifc = smalloc(sizeof(Iplifc));
534 ipmove(lifc->local, ip);
535 ipmove(lifc->mask, mask);
536 ipmove(lifc->remote, rem);
537 ipmove(lifc->net, net);
539 lifc->tentative = tentative;
541 lifc->onlink = lifcp->onlink;
542 lifc->autoflag = lifcp->autoflag;
543 lifc->validlt = lifcp->validlt;
544 lifc->preflt = lifcp->preflt;
545 lifc->origint = lifcp->origint;
546 } else { /* default values */
547 lifc->onlink = lifc->autoflag = 1;
548 lifc->validlt = lifc->preflt = ~0L;
549 lifc->origint = NOW / 1000;
553 for(l = &ifc->lifc; *l != nil; l = &(*l)->next)
557 /* add route for this logical interface */
558 addroute(f, rem, mask, ip, IPallbits, rem, type, ifc, tifc);
559 if(v6addrtype(ip) != linklocalv6)
560 addroute(f, rem, mask, ip, IPnoaddr, rem, type, ifc, tifc);
562 addselfcache(f, ifc, lifc, ip, Runi);
567 ipifcregisterproxy(f, ifc, rem, 1);
572 /* add subnet directed broadcast address to the self cache */
573 for(i = 0; i < IPaddrlen; i++)
574 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
575 addselfcache(f, ifc, lifc, bcast, Rbcast);
577 /* add subnet directed network address to the self cache */
578 for(i = 0; i < IPaddrlen; i++)
579 bcast[i] = (ip[i] & mask[i]) & mask[i];
580 addselfcache(f, ifc, lifc, bcast, Rbcast);
582 /* add network directed broadcast address to the self cache */
583 memmove(mask, defmask(ip), IPaddrlen);
584 for(i = 0; i < IPaddrlen; i++)
585 bcast[i] = (ip[i] & mask[i]) | ~mask[i];
586 addselfcache(f, ifc, lifc, bcast, Rbcast);
588 /* add network directed network address to the self cache */
589 memmove(mask, defmask(ip), IPaddrlen);
590 for(i = 0; i < IPaddrlen; i++)
591 bcast[i] = (ip[i] & mask[i]) & mask[i];
592 addselfcache(f, ifc, lifc, bcast, Rbcast);
594 addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
596 if(ipcmp(ip, v6loopback) == 0) {
597 /* add node-local mcast address */
598 addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
600 /* add route for all node multicast */
601 addroute(f, v6allnodesN, v6allnodesNmask,
603 v6allnodesN, Rmulti, ifc, tifc);
606 /* add all nodes multicast address */
607 addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
609 /* add route for all nodes multicast */
610 addroute(f, v6allnodesL, v6allnodesLmask,
612 v6allnodesL, Rmulti, ifc, tifc);
614 /* add solicited-node multicast address */
615 ipv62smcast(bcast, ip);
616 addselfcache(f, ifc, lifc, bcast, Rmulti);
623 ipifcregisteraddr(f, ifc, ip, ip);
629 * remove a logical interface from an ifc
630 * always called with ifc wlock'd
633 ipifcremlifc(Ipifc *ifc, Iplifc **l)
636 Fs *f = ifc->conv->p->f;
639 return "address not on this interface";
642 /* disassociate any addresses */
643 while(lifc->link != nil)
644 remselfcache(f, ifc, lifc, lifc->link->self->a);
646 /* remove the route for this logical interface */
647 remroute(f, lifc->remote, lifc->mask,
648 lifc->local, IPallbits,
649 lifc->remote, lifc->type, ifc, tifc);
650 if(v6addrtype(lifc->local) != linklocalv6)
651 remroute(f, lifc->remote, lifc->mask,
652 lifc->local, IPnoaddr,
653 lifc->remote, lifc->type, ifc, tifc);
655 /* unregister proxy */
656 if(lifc->type & Rptpt){
657 if(lifc->type & Rproxy)
658 ipifcregisterproxy(f, ifc, lifc->remote, 0);
662 /* remove route for all nodes multicast */
663 if((lifc->type & Rv4) == 0){
664 if(ipcmp(lifc->local, v6loopback) == 0)
665 remroute(f, v6allnodesN, v6allnodesNmask,
666 lifc->local, IPallbits,
667 v6allnodesN, Rmulti, ifc, tifc);
669 remroute(f, v6allnodesL, v6allnodesLmask,
670 lifc->local, IPallbits,
671 v6allnodesL, Rmulti, ifc, tifc);
680 * remove an address from an interface.
681 * called with c->car locked
684 ipifcrem(Ipifc *ifc, char **argv, int argc)
687 uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
692 if(parseip(ip, argv[1]) == -1)
694 parseipmask(mask, argv[2]);
696 maskip(ip, mask, rem);
697 else if(parseip(rem, argv[3]) == -1)
701 * find address on this interface and remove from chain.
702 * for pt to pt we actually specify the remote address as the
703 * addresss to remove.
707 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
708 if(ipcmp(ip, lifc->local) == 0
709 && ipcmp(mask, lifc->mask) == 0
710 && ipcmp(rem, lifc->remote) == 0)
714 rv = ipifcremlifc(ifc, l);
720 * associate an address with the interface. This wipes out any previous
721 * addresses. This is a macro that means, remove all the old interfaces
725 ipifcconnect(Conv* c, char **argv, int argc)
730 ifc = (Ipifc*)c->ptcl;
733 return "ipifc not yet bound to device";
736 while(ifc->lifc != nil){
737 err = ipifcremlifc(ifc, &ifc->lifc);
745 err = ipifcadd(ifc, argv, argc, 0, nil);
754 ipifcra6(Ipifc *ifc, char **argv, int argc)
757 uchar sendra, recvra;
762 if((argsleft % 2) != 0)
765 sendra = ifc->sendra6;
766 recvra = ifc->recvra6;
769 while (argsleft > 1) {
770 if(strcmp(argv[i], "recvra") == 0)
771 recvra = (atoi(argv[i+1]) != 0);
772 else if(strcmp(argv[i], "sendra") == 0)
773 sendra = (atoi(argv[i+1]) != 0);
774 else if(strcmp(argv[i], "mflag") == 0)
775 rp.mflag = (atoi(argv[i+1]) != 0);
776 else if(strcmp(argv[i], "oflag") == 0)
777 rp.oflag = (atoi(argv[i+1]) != 0);
778 else if(strcmp(argv[i], "maxraint") == 0)
779 rp.maxraint = atoi(argv[i+1]);
780 else if(strcmp(argv[i], "minraint") == 0)
781 rp.minraint = atoi(argv[i+1]);
782 else if(strcmp(argv[i], "linkmtu") == 0)
783 rp.linkmtu = atoi(argv[i+1]);
784 else if(strcmp(argv[i], "reachtime") == 0)
785 rp.reachtime = atoi(argv[i+1]);
786 else if(strcmp(argv[i], "rxmitra") == 0)
787 rp.rxmitra = atoi(argv[i+1]);
788 else if(strcmp(argv[i], "ttl") == 0)
789 rp.ttl = atoi(argv[i+1]);
790 else if(strcmp(argv[i], "routerlt") == 0)
791 rp.routerlt = atoi(argv[i+1]);
799 /* consistency check */
800 if(rp.maxraint < rp.minraint)
804 ifc->sendra6 = sendra;
805 ifc->recvra6 = recvra;
811 * non-standard control messages.
812 * called with c->car locked.
815 ipifcctl(Conv* c, char **argv, int argc)
819 ifc = (Ipifc*)c->ptcl;
820 if(strcmp(argv[0], "add") == 0)
821 return ipifcadd(ifc, argv, argc, 0, nil);
822 else if(strcmp(argv[0], "try") == 0)
823 return ipifcadd(ifc, argv, argc, 1, nil);
824 else if(strcmp(argv[0], "remove") == 0)
825 return ipifcrem(ifc, argv, argc);
826 else if(strcmp(argv[0], "unbind") == 0)
827 return ipifcunbind(ifc);
828 else if(strcmp(argv[0], "mtu") == 0)
829 return ipifcsetmtu(ifc, argv, argc);
830 else if(strcmp(argv[0], "speed") == 0){
831 ipifcsetspeed(ifc, argc>1? atoi(argv[1]): 0);
834 else if(strcmp(argv[0], "delay") == 0){
835 ipifcsetdelay(ifc, argc>1? atoi(argv[1]): 0);
838 else if(strcmp(argv[0], "iprouting") == 0){
839 iprouting(c->p->f, argc>1? atoi(argv[1]): 1);
842 else if(strcmp(argv[0], "reflect") == 0){
843 ifc->reflect = argc>1? atoi(argv[1]): 1;
846 else if(strcmp(argv[0], "reassemble") == 0){
847 ifc->reassemble = argc>1? atoi(argv[1]): 1;
850 else if(strcmp(argv[0], "add6") == 0)
851 return ipifcadd6(ifc, argv, argc);
852 else if(strcmp(argv[0], "ra6") == 0)
853 return ipifcra6(ifc, argv, argc);
854 return "unsupported ctl";
858 ipifcstats(Proto *ipifc, char *buf, int len)
860 return ipstats(ipifc->f, buf, len);
868 ipifc = smalloc(sizeof(Proto));
869 ipifc->name = "ipifc";
870 ipifc->connect = ipifcconnect;
871 ipifc->announce = nil;
872 ipifc->bind = ipifcbind;
873 ipifc->state = ipifcstate;
874 ipifc->create = ipifccreate;
875 ipifc->close = ipifcclose;
877 ipifc->ctl = ipifcctl;
879 ipifc->stats = ipifcstats;
880 ipifc->inuse = ipifcinuse;
881 ipifc->local = ipifclocal;
883 ipifc->nc = Maxmedia;
884 ipifc->ptclsize = sizeof(Ipifc);
886 f->ipifc = ipifc; /* hack for ipifcremroute, findipifc, ... */
887 f->self = smalloc(sizeof(Ipselftab)); /* hack for ipforme */
893 * add to self routing cache
894 * called with c->car locked
897 addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
903 type |= (lifc->type & Rv4);
910 /* see if the address already exists */
912 for(p = f->self->hash[h]; p != nil; p = p->next)
913 if(ipcmp(a, p->a) == 0)
916 /* allocate a local address and add to hash chain */
918 p = smalloc(sizeof(*p));
921 p->next = f->self->hash[h];
922 f->self->hash[h] = p;
924 /* if the null address, accept all packets */
925 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
926 f->self->acceptall = 1;
929 /* look for a link for this lifc */
930 for(lp = p->link; lp != nil; lp = lp->selflink)
934 /* allocate a lifc-to-local link and link to both */
936 lp = smalloc(sizeof(*lp));
940 lp->selflink = p->link;
942 lp->lifclink = lifc->link;
945 /* add to routing table */
946 addroute(f, a, IPallbits,
948 ((type & (Rbcast|Rmulti)) != 0 || v6addrtype(a) == linklocalv6) ?
949 IPallbits : IPnoaddr,
952 if((type & Rmulti) && ifc->m->addmulti != nil)
953 (*ifc->m->addmulti)(ifc, a, lifc->local);
962 * These structures are unlinked from their chains while
963 * other threads may be using them. To avoid excessive locking,
964 * just put them aside for a while before freeing them.
965 * called with f->self locked
967 static Iplink *freeiplink;
968 static Ipself *freeipself;
971 iplinkfree(Iplink *p)
977 for(np = *l; np != nil; np = *l){
978 if((long)(now - np->expire) >= 0){
985 p->expire = now + 5000; /* give other threads 5 secs to get out */
991 ipselffree(Ipself *p)
997 for(np = *l; np != nil; np = *l){
998 if((long)(now - np->expire) >= 0){
1005 p->expire = now + 5000; /* give other threads 5 secs to get out */
1011 * Decrement reference for this address on this link.
1012 * Unlink from selftab if this is the last ref.
1013 * called with c->car locked
1016 remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
1019 Iplink *link, **l_self, **l_lifc;
1023 /* find the unique selftab entry */
1024 l = &f->self->hash[hashipa(a)];
1025 for(p = *l; p != nil; p = *l){
1026 if(ipcmp(p->a, a) == 0)
1035 * walk down links from an ifc looking for one
1036 * that matches the selftab entry
1038 l_lifc = &lifc->link;
1039 for(link = *l_lifc; link != nil; link = *l_lifc){
1042 l_lifc = &link->lifclink;
1049 * walk down the links from the selftab looking for
1050 * the one we just found
1053 for(link = *l_self; link != nil; link = *l_self){
1056 l_self = &link->selflink;
1060 panic("remselfcache");
1062 if(--(link->ref) != 0)
1065 /* remove from routing table */
1066 remroute(f, a, IPallbits,
1068 ((p->type & (Rbcast|Rmulti)) != 0 || v6addrtype(a) == linklocalv6) ?
1069 IPallbits : IPnoaddr,
1070 a, p->type, ifc, tifc);
1072 if((p->type & Rmulti) && ifc->m->remmulti != nil){
1074 (*ifc->m->remmulti)(ifc, a, lifc->local);
1079 /* ref == 0, remove from both chains and free the link */
1080 *l_lifc = link->lifclink;
1081 *l_self = link->selflink;
1087 /* if null address, forget */
1088 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1089 f->self->acceptall = 0;
1091 /* no more links, remove from hash and free */
1100 ipselftabread(Fs *f, char *cp, ulong offset, int n)
1102 int i, m, nifc, off;
1110 for(i = 0; i < NHASH && m < n; i++){
1111 for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
1113 for(link = p->link; link != nil; link = link->selflink)
1115 routetype(p->type, state);
1116 m += snprint(cp + m, n - m, "%-44.44I %2.2d %4.4s\n",
1136 ipforme(Fs *f, uchar *addr)
1140 for(p = f->self->hash[hashipa(addr)]; p != nil; p = p->next)
1141 if(ipcmp(addr, p->a) == 0)
1142 return p->type & (Runi|Rbcast|Rmulti);
1144 /* hack to say accept anything */
1145 if(f->self->acceptall)
1152 * find the ifc on same net as the remote system. If none,
1156 findipifc(Fs *f, uchar *local, uchar *remote, int type)
1158 uchar gnet[IPaddrlen];
1166 for(cp = f->ipifc->conv; *cp != nil; cp++){
1167 ifc = (Ipifc*)(*cp)->ptcl;
1169 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1171 if(ipcmp(remote, lifc->local) == 0){
1176 } else if(type & (Rbcast|Rmulti)) {
1177 if(ipcmp(local, lifc->local) == 0)
1180 maskip(remote, lifc->mask, gnet);
1181 if(ipcmp(gnet, lifc->net) == 0){
1182 spec = comprefixlen(remote, lifc->local, IPaddrlen);
1195 findipifcstr(Fs *f, char *s)
1197 uchar ip[IPaddrlen];
1202 x = strtol(s, &p, 10);
1203 if(p > s && *p == '\0'){
1206 if(x < f->ipifc->nc && (c = f->ipifc->conv[x]) != nil && ipifcinuse(c))
1207 return (Ipifc*)c->ptcl;
1209 if(parseip(ip, s) != -1)
1210 return findipifc(f, ip, ip, Runi);
1215 * find "best" (global > link local > unspecified)
1216 * local address; address must be current.
1219 findprimaryipv6(Fs *f, uchar *local)
1226 ipmove(local, v6Unspecified);
1227 atype = unspecifiedv6;
1229 for(cp = f->ipifc->conv; *cp != nil; cp++){
1230 ifc = (Ipifc*)(*cp)->ptcl;
1232 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1233 atypel = v6addrtype(lifc->local);
1234 if(atypel > atype && v6addrcurr(lifc)) {
1235 ipmove(local, lifc->local);
1237 if(atype == globalv6){
1248 * returns first v4 address configured
1251 findprimaryipv4(Fs *f, uchar *local)
1257 /* find first ifc local address */
1258 for(cp = f->ipifc->conv; *cp != nil; cp++){
1259 ifc = (Ipifc*)(*cp)->ptcl;
1261 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1262 if((lifc->type & Rv4) != 0){
1263 ipmove(local, lifc->local);
1270 ipmove(local, IPnoaddr);
1274 * return v4 address associated with an interface close to remote
1277 ipv4local(Ipifc *ifc, uchar *local, uchar *remote)
1283 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1284 if((lifc->type & Rv4) == 0 || ipcmp(lifc->local, IPnoaddr) == 0)
1286 a = comprefixlen(lifc->local+IPv4off, remote, IPv4addrlen);
1289 memmove(local, lifc->local+IPv4off, IPv4addrlen);
1296 * return v6 address associated with an interface close to remote
1299 ipv6local(Ipifc *ifc, uchar *local, uchar *remote)
1310 ipmove(local, v4prefix);
1311 return ipv4local(ifc, local+IPv4off, remote+IPv4off);
1314 atype = v6addrtype(remote);
1315 ipmove(local, v6Unspecified);
1316 b.atype = unknownv6;
1320 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1324 a.atype = v6addrtype(lifc->local);
1325 a.deprecated = !v6addrcurr(lifc);
1326 a.comprefixlen = comprefixlen(lifc->local, remote, IPaddrlen);
1328 /* prefer appropriate scope */
1329 if(a.atype != b.atype){
1330 if(a.atype > b.atype && b.atype < atype ||
1331 a.atype < b.atype && b.atype > atype)
1335 /* prefer non-deprecated addresses */
1336 if(a.deprecated != b.deprecated){
1341 /* prefer longer common prefix */
1342 if(a.comprefixlen != b.comprefixlen){
1343 if(a.comprefixlen > b.comprefixlen)
1350 ipmove(local, lifc->local);
1353 return b.atype >= atype;
1357 findlocalip(Fs *f, uchar *local, uchar *remote)
1364 for(cp = f->ipifc->conv; *cp != nil; cp++){
1365 ifc = (Ipifc*)(*cp)->ptcl;
1367 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1371 r = v6lookup(f, remote, lifc->local, nil);
1372 if(r == nil || (nifc = r->ifc) == nil)
1375 ipmove(local, remote);
1379 if(nifc != ifc) rlock(nifc);
1380 if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){
1381 ipmove(local, v4prefix);
1382 if(ipv4local(nifc, local+IPv4off, r->v4.gate)){
1383 if(nifc != ifc) runlock(nifc);
1388 if(ipv6local(nifc, local, remote)){
1389 if(nifc != ifc) runlock(nifc);
1393 if(nifc != ifc) runlock(nifc);
1398 findprimaryipv4(f, local);
1400 findprimaryipv6(f, local);
1405 * see if this address is bound to the interface
1408 iplocalonifc(Ipifc *ifc, uchar *ip)
1412 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
1413 if(ipcmp(ip, lifc->local) == 0)
1420 ipremoteonifc(Ipifc *ifc, uchar *ip)
1422 uchar net[IPaddrlen];
1425 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1426 maskip(ip, lifc->mask, net);
1427 if(ipcmp(net, lifc->remote) == 0)
1435 * See if we're proxying for this address on this interface
1438 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
1442 /* see if this is a direct connected pt to pt address */
1443 r = v6lookup(f, ip, ip, nil);
1444 if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
1447 return ipremoteonifc(ifc, ip) != nil;
1451 * return multicast version if any
1454 ipismulticast(uchar *ip)
1457 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1460 else if(ip[0] == 0xff)
1466 * add a multicast address to an interface, called with c->car locked
1469 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
1471 Ipmulti *multi, **l;
1476 if(isv4(ma) != isv4(ia))
1477 error("incompatible multicast/interface ip address");
1479 for(l = &c->multi; *l != nil; l = &(*l)->next)
1480 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1481 return; /* it's already there */
1484 if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
1490 if((lifc = iplocalonifc(ifc, ia)) != nil)
1491 addselfcache(f, ifc, lifc, ma, Rmulti);
1496 multi = smalloc(sizeof(*multi));
1497 ipmove(multi->ma, ma);
1498 ipmove(multi->ia, ia);
1505 * remove a multicast address from an interface, called with c->car locked
1508 ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
1510 Ipmulti *multi, **l;
1515 for(l = &c->multi; *l != nil; l = &(*l)->next)
1516 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1521 return; /* we don't have it open */
1527 if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
1530 if((lifc = iplocalonifc(ifc, ia)) != nil)
1531 remselfcache(f, ifc, lifc, ma);
1539 /* register the address on this network for address resolution */
1541 ipifcregisteraddr(Fs *f, Ipifc *ifc, uchar *ia, uchar *ip)
1548 print("ipifcregisteraddr %s %I %I: %s\n", ifc->dev, ia, ip, up->errstr);
1551 lifc = iplocalonifc(ifc, ia);
1552 if(lifc != nil && ifc->m != nil && ifc->m->areg != nil)
1553 (*ifc->m->areg)(f, ifc, lifc, ip);
1559 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip, int add)
1566 /* register the address on any interface that will proxy for the ip */
1567 for(cp = f->ipifc->conv; *cp != nil; cp++){
1568 nifc = (Ipifc*)(*cp)->ptcl;
1574 || (lifc = ipremoteonifc(nifc, ip)) == nil
1575 || (lifc->type & Rptpt) != 0
1580 if((lifc->type & Rv4) == 0){
1581 /* add solicited-node multicast addr */
1584 addselfcache(f, nifc, lifc, a, Rmulti);
1586 remselfcache(f, nifc, lifc, a);
1588 ipmove(a, lifc->local);
1593 ipifcregisteraddr(f, nifc, a, ip);
1598 ipifcadd6(Ipifc *ifc, char**argv, int argc)
1601 char addr[40], preflen[6];
1603 uchar prefix[IPaddrlen];
1610 lifc.origint = NOW / 1000;
1614 lifc.preflt = atoi(argv[6]);
1617 lifc.validlt = atoi(argv[5]);
1620 lifc.autoflag = atoi(argv[4]) != 0;
1623 lifc.onlink = atoi(argv[3]) != 0;
1626 plen = atoi(argv[2]);
1634 if (parseip(prefix, argv[1]) != 6 || lifc.validlt < lifc.preflt || plen < 0 ||
1635 plen > 64 || islinklocal(prefix))
1638 /* issue "add" ctl msg for v6 link-local addr and prefix len */
1639 if(ifc->m->pref2addr == nil)
1641 (*ifc->m->pref2addr)(prefix, ifc->mac); /* mac → v6 link-local addr */
1643 sprint(addr, "%I", prefix);
1644 sprint(preflen, "/%d", plen);
1647 params[2] = preflen;
1649 return ipifcadd(ifc, params, 3, 0, &lifc);