static void findprimaryipv6(Fs *f, uint8_t *local) { int atype, atypel; Conv **cp, **e; Ipifc *ifc; Iplifc *lifc; ipmove(local, v6Unspecified); atype = unspecifiedv6; /* * find "best" (global > link local > unspecified) * local address; address must be current. */ e = &f->ipifc->conv[f->ipifc->nc]; for(cp = f->ipifc->conv; cp < e; cp++){ if(*cp == 0) continue; ifc = (Ipifc*)(*cp)->ptcl; for(lifc = ifc->lifc; lifc; lifc = lifc->next){ atypel = v6addrtype(lifc->local); if(atypel > atype && v6addrcurr(lifc)) { ipmove(local, lifc->local); atype = atypel; if(atype == globalv6) return; } } } }
/* * find the local address 'closest' to the remote system, copy it to * local and return the ifc for that address */ void findlocalip(Fs *f, uint8_t *local, uint8_t *remote) { int version, atype = unspecifiedv6, atypel = unknownv6; int atyper, deprecated; uint8_t gate[IPaddrlen], gnet[IPaddrlen]; Ipifc *ifc; Iplifc *lifc; Route *r; USED(atype); USED(atypel); qlock(f->ipifc); r = v6lookup(f, remote, nil); version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6; if(r != nil){ ifc = r->ifc; if(r->type & Rv4) v4tov6(gate, r->v4.gate); else { ipmove(gate, r->v6.gate); ipmove(local, v6Unspecified); } switch(version) { case V4: /* find ifc address closest to the gateway to use */ for(lifc = ifc->lifc; lifc; lifc = lifc->next){ maskip(gate, lifc->mask, gnet); if(ipcmp(gnet, lifc->net) == 0){ ipmove(local, lifc->local); goto out; } } break; case V6: /* find ifc address with scope matching the destination */ atyper = v6addrtype(remote); deprecated = 0; for(lifc = ifc->lifc; lifc; lifc = lifc->next){ atypel = v6addrtype(lifc->local); /* prefer appropriate scope */ if(atypel > atype && atype < atyper || atypel < atype && atype > atyper){ ipmove(local, lifc->local); deprecated = !v6addrcurr(lifc); atype = atypel; } else if(atypel == atype){ /* avoid deprecated addresses */ if(deprecated && v6addrcurr(lifc)){ ipmove(local, lifc->local); atype = atypel; deprecated = 0; } } if(atype == atyper && !deprecated) goto out; } if(atype >= atyper) goto out; break; default: panic("findlocalip: version %d", version); } } switch(version){ case V4: findprimaryipv4(f, local); break; case V6: findprimaryipv6(f, local); break; default: panic("findlocalip2: version %d", version); } out: qunlock(f->ipifc); }
/* * find the local address 'closest' to the remote system, copy it to * local and return the ifc for that address */ void findlocalip(struct Fs *f, uint8_t * local, uint8_t * remote) { struct Ipifc *ifc; struct Iplifc *lifc; struct route *r; uint8_t gate[IPaddrlen]; uint8_t gnet[IPaddrlen]; int version; int atype = unspecifiedv6, atypel = unknownv6; qlock(&f->ipifc->qlock); r = v6lookup(f, remote, NULL); version = isv4(remote) ? V4 : V6; if (r != NULL) { ifc = r->rt.ifc; if (r->rt.type & Rv4) v4tov6(gate, r->v4.gate); else { ipmove(gate, r->v6.gate); ipmove(local, v6Unspecified); } /* find ifc address closest to the gateway to use */ switch (version) { case V4: for (lifc = ifc->lifc; lifc; lifc = lifc->next) { maskip(gate, lifc->mask, gnet); if (ipcmp(gnet, lifc->net) == 0) { ipmove(local, lifc->local); goto out; } } break; case V6: for (lifc = ifc->lifc; lifc; lifc = lifc->next) { atypel = v6addrtype(lifc->local); maskip(gate, lifc->mask, gnet); if (ipcmp(gnet, lifc->net) == 0) if (atypel > atype) if (v6addrcurr(lifc)) { ipmove(local, lifc->local); atype = atypel; if (atype == globalv6) break; } } if (atype > unspecifiedv6) goto out; break; default: panic("findlocalip: version %d", version); } } switch (version) { case V4: findprimaryipv4(f, local); break; case V6: findprimaryipv6(f, local); break; default: panic("findlocalip2: version %d", version); } out: qunlock(&f->ipifc->qlock); }