/* * add to self routing cache * called with c locked */ static void addselfcache(struct Fs *f, struct Ipifc *ifc, struct Iplifc *lifc, uint8_t * a, int type) { struct Ipself *p; struct Iplink *lp; int h; qlock(&f->self->qlock); /* see if the address already exists */ h = hashipa(a); for (p = f->self->hash[h]; p; p = p->next) if (memcmp(a, p->a, IPaddrlen) == 0) break; /* allocate a local address and add to hash chain */ if (p == NULL) { p = kzmalloc(sizeof(*p), 0); ipmove(p->a, a); p->type = type; p->next = f->self->hash[h]; f->self->hash[h] = p; /* if the null address, accept all packets */ if (ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0) f->self->acceptall = 1; } /* look for a link for this lifc */ for (lp = p->link; lp; lp = lp->selflink) if (lp->lifc == lifc) break; /* allocate a lifc-to-local link and link to both */ if (lp == NULL) { lp = kzmalloc(sizeof(*lp), 0); kref_init(&lp->ref, fake_release, 1); lp->lifc = lifc; lp->self = p; lp->selflink = p->link; p->link = lp; lp->lifclink = lifc->link; lifc->link = lp; /* add to routing table */ if (isv4(a)) v4addroute(f, tifc, a + IPv4off, IPallbits + IPv4off, a + IPv4off, type); else v6addroute(f, tifc, a, IPallbits, a, type); if ((type & Rmulti) && ifc->m->addmulti != NULL) (*ifc->m->addmulti) (ifc, a, lifc->local); } else { kref_get(&lp->ref, 1); } qunlock(&f->self->qlock); }
/* * add to self routing cache * called with c->car locked */ static void addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type) { Ipself *p; Iplink *lp; int h; qlock(f->self); /* see if the address already exists */ h = hashipa(a); for(p = f->self->hash[h]; p; p = p->next) if(memcmp(a, p->a, IPaddrlen) == 0) break; /* allocate a local address and add to hash chain */ if(p == nil){ p = smalloc(sizeof(*p)); ipmove(p->a, a); p->type = type; p->next = f->self->hash[h]; f->self->hash[h] = p; /* if the null address, accept all packets */ if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0) f->self->acceptall = 1; } /* look for a link for this lifc */ for(lp = p->link; lp; lp = lp->selflink) if(lp->lifc == lifc) break; /* allocate a lifc-to-local link and link to both */ if(lp == nil){ lp = smalloc(sizeof(*lp)); lp->ref = 1; lp->lifc = lifc; lp->self = p; lp->selflink = p->link; p->link = lp; lp->lifclink = lifc->link; lifc->link = lp; /* add to routing table */ if(isv4(a)) v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off, a+IPv4off, type); else v6addroute(f, tifc, a, IPallbits, a, type); if((type & Rmulti) && ifc->m->addmulti != nil) (*ifc->m->addmulti)(ifc, a, lifc->local); } else lp->ref++; qunlock(f->self); }
// added for new v6 mesg types static void adddefroute6(struct Fs *f, uint8_t * gate, int force) { struct route *r; r = v6lookup(f, v6Unspecified, NULL); if (r != NULL) if (!(force) && (strcmp(r->rt.tag, "ra") != 0)) // route entries generated return; // by all other means take // precedence over router annc v6delroute(f, v6Unspecified, v6Unspecified, 1); v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0); }
/* added for new v6 mesg types */ static void adddefroute6(Fs *f, uint8_t *gate, int force) { Route *r; r = v6lookup(f, v6Unspecified, nil); /* * route entries generated by all other means take precedence * over router announcements. */ if (r && !force && strcmp(r->tag, "ra") != 0) return; v6delroute(f, v6Unspecified, v6Unspecified, 1); v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0); }
/* * add an address to an interface. */ char* ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) { int i, type, mtu, sendnbrdisc = 0; uint8_t ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen]; uint8_t bcast[IPaddrlen], net[IPaddrlen]; Iplifc *lifc, **l; Fs *f; if(ifc->medium == nil) return "ipifc not yet bound to device"; f = ifc->conv->p->f; type = Rifc; memset(ip, 0, IPaddrlen); memset(mask, 0, IPaddrlen); memset(rem, 0, IPaddrlen); switch(argc){ case 6: if(strcmp(argv[5], "proxy") == 0) type |= Rproxy; /* fall through */ case 5: mtu = strtoul(argv[4], 0, 0); if(mtu >= ifc->medium->mintu && mtu <= ifc->medium->maxtu) ifc->maxtu = mtu; /* fall through */ case 4: if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1) return Ebadip; parseipmask(mask, argv[2]); maskip(rem, mask, net); break; case 3: if (parseip(ip, argv[1]) == -1) return Ebadip; parseipmask(mask, argv[2]); maskip(ip, mask, rem); maskip(rem, mask, net); break; case 2: if (parseip(ip, argv[1]) == -1) return Ebadip; memmove(mask, defmask(ip), IPaddrlen); maskip(ip, mask, rem); maskip(rem, mask, net); break; default: return Ebadarg; } if(isv4(ip)) tentative = 0; wlock(ifc); /* ignore if this is already a local address for this ifc */ for(lifc = ifc->lifc; lifc; lifc = lifc->next) { if(ipcmp(lifc->local, ip) == 0) { if(lifc->tentative != tentative) lifc->tentative = tentative; if(lifcp) { lifc->onlink = lifcp->onlink; lifc->autoflag = lifcp->autoflag; lifc->validlt = lifcp->validlt; lifc->preflt = lifcp->preflt; lifc->origint = lifcp->origint; } goto out; } } /* add the address to the list of logical ifc's for this ifc */ lifc = smalloc(sizeof(Iplifc)); ipmove(lifc->local, ip); ipmove(lifc->mask, mask); ipmove(lifc->remote, rem); ipmove(lifc->net, net); lifc->tentative = tentative; if(lifcp) { lifc->onlink = lifcp->onlink; lifc->autoflag = lifcp->autoflag; lifc->validlt = lifcp->validlt; lifc->preflt = lifcp->preflt; lifc->origint = lifcp->origint; } else { /* default values */ lifc->onlink = lifc->autoflag = 1; lifc->validlt = lifc->preflt = ~0L; lifc->origint = NOW / 1000; } lifc->next = nil; for(l = &ifc->lifc; *l; l = &(*l)->next) ; *l = lifc; /* check for point-to-point interface */ if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */ if(ipcmp(mask, IPallbits) == 0) type |= Rptpt; /* add local routes */ if(isv4(ip)) v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type); else v6addroute(f, tifc, rem, mask, rem, type); addselfcache(f, ifc, lifc, ip, Runi); if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){ ipifcregisterproxy(f, ifc, rem); goto out; } if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) { /* add subnet directed broadcast address to the self cache */ for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) | ~mask[i]; addselfcache(f, ifc, lifc, bcast, Rbcast); /* add subnet directed network address to the self cache */ for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) & mask[i]; addselfcache(f, ifc, lifc, bcast, Rbcast); /* add network directed broadcast address to the self cache */ memmove(mask, defmask(ip), IPaddrlen); for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) | ~mask[i]; addselfcache(f, ifc, lifc, bcast, Rbcast); /* add network directed network address to the self cache */ memmove(mask, defmask(ip), IPaddrlen); for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) & mask[i]; addselfcache(f, ifc, lifc, bcast, Rbcast); addselfcache(f, ifc, lifc, IPv4bcast, Rbcast); } else { if(ipcmp(ip, v6loopback) == 0) { /* add node-local mcast address */ addselfcache(f, ifc, lifc, v6allnodesN, Rmulti); /* add route for all node multicast */ v6addroute(f, tifc, v6allnodesN, v6allnodesNmask, v6allnodesN, Rmulti); } /* add all nodes multicast address */ addselfcache(f, ifc, lifc, v6allnodesL, Rmulti); /* add route for all nodes multicast */ v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL, Rmulti); /* add solicited-node multicast address */ ipv62smcast(bcast, ip); addselfcache(f, ifc, lifc, bcast, Rmulti); sendnbrdisc = 1; } /* register the address on this network for address resolution */ if(isv4(ip) && ifc->medium->areg != nil) (*ifc->medium->areg)(ifc, ip); out: wunlock(ifc); if(tentative && sendnbrdisc) icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac); return nil; }