// 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); }
/* * See if we're proxying for this address on this interface */ int ipproxyifc(Fs *f, Ipifc *ifc, uint8_t *ip) { Route *r; uint8_t net[IPaddrlen]; Iplifc *lifc; /* see if this is a direct connected pt to pt address */ r = v6lookup(f, ip, nil); if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy)) return 0; /* see if this is on the right interface */ for(lifc = ifc->lifc; lifc; lifc = lifc->next){ maskip(ip, lifc->mask, net); if(ipcmp(net, lifc->remote) == 0) return 1; } return 0; }
int arpwrite(struct Fs *fs, char *s, long len) { int n; struct route *r; struct arp *arp; struct block *bp; struct arpent *a, *fl, **l; struct medium *m; char *f[4], buf[256]; uint8_t ip[IPaddrlen], mac[MAClen]; arp = fs->arp; if (len <= 0) error(EINVAL, ERROR_FIXME); if (len > sizeof(buf)) len = sizeof(buf); strlcpy(buf, s, sizeof(buf)); if (len > 0 && buf[len - 2] == '\n') buf[len - 2] = 0; n = getfields(buf, f, 4, 1, " "); if (strcmp(f[0], "flush") == 0) { qlock(&arp->qlock); for (a = arp->cache; a < &arp->cache[NCACHE]; a++) { memset(a->ip, 0, sizeof(a->ip)); memset(a->mac, 0, sizeof(a->mac)); a->hash = NULL; a->state = 0; a->utime = 0; while (a->hold != NULL) { bp = a->hold->list; freeblist(a->hold); a->hold = bp; } } memset(arp->hash, 0, sizeof(arp->hash)); /* clear all pkts on these lists (rxmt, dropf/l) */ arp->rxmt = NULL; arp->dropf = NULL; arp->dropl = NULL; qunlock(&arp->qlock); } else if (strcmp(f[0], "add") == 0) { switch (n) { default: error(EINVAL, ERROR_FIXME); case 3: parseip(ip, f[1]); if (isv4(ip)) r = v4lookup(fs, ip + IPv4off, NULL); else r = v6lookup(fs, ip, NULL); if (r == NULL) error(EHOSTUNREACH, "Destination unreachable"); m = r->rt.ifc->m; n = parsemac(mac, f[2], m->maclen); break; case 4: m = ipfindmedium(f[1]); if (m == NULL) error(EINVAL, ERROR_FIXME); parseip(ip, f[2]); n = parsemac(mac, f[3], m->maclen); break; } if (m->ares == NULL) error(EINVAL, ERROR_FIXME); m->ares(fs, V6, ip, mac, n, 0); } else if (strcmp(f[0], "del") == 0) { if (n != 2) error(EINVAL, ERROR_FIXME); parseip(ip, f[1]); qlock(&arp->qlock); l = &arp->hash[haship(ip)]; for (a = *l; a; a = a->hash) { if (memcmp(ip, a->ip, sizeof(a->ip)) == 0) { *l = a->hash; break; } l = &a->hash; } if (a) { /* take out of re-transmit chain */ l = &arp->rxmt; for (fl = *l; fl; fl = fl->nextrxt) { if (fl == a) { *l = a->nextrxt; break; } l = &fl->nextrxt; } a->nextrxt = NULL; a->hash = NULL; a->hold = NULL; a->last = NULL; a->ifc = NULL; memset(a->ip, 0, sizeof(a->ip)); memset(a->mac, 0, sizeof(a->mac)); } qunlock(&arp->qlock); } else error(EINVAL, ERROR_FIXME); return len; }
void arpenter(struct Fs *fs, int version, uint8_t *ip, uint8_t *mac, int n, int refresh) { ERRSTACK(1); struct arp *arp; struct route *r; struct arpent *a, *f, **l; struct Ipifc *ifc; struct medium *type; struct block *bp, *next; uint8_t v6ip[IPaddrlen]; arp = fs->arp; if (n != 6) { return; } switch (version) { case V4: r = v4lookup(fs, ip, NULL); v4tov6(v6ip, ip); ip = v6ip; break; case V6: r = v6lookup(fs, ip, NULL); break; default: panic("arpenter: version %d", version); return; /* to supress warnings */ } if (r == NULL) { return; } ifc = r->rt.ifc; type = ifc->m; qlock(&arp->qlock); for (a = arp->hash[haship(ip)]; a; a = a->hash) { if (a->type != type || (a->state != AWAIT && a->state != AOK)) continue; if (ipcmp(a->ip, ip) == 0) { a->state = AOK; memmove(a->mac, mac, type->maclen); if (version == V6) { /* take out of re-transmit chain */ l = &arp->rxmt; for (f = *l; f; f = f->nextrxt) { if (f == a) { *l = a->nextrxt; break; } l = &f->nextrxt; } } a->ifc = ifc; a->ifcid = ifc->ifcid; bp = a->hold; a->hold = NULL; if (version == V4) ip += IPv4off; a->utime = NOW; a->ctime = a->utime; qunlock(&arp->qlock); while (bp) { next = bp->list; if (ifc != NULL) { rlock(&ifc->rwlock); if (waserror()) { runlock(&ifc->rwlock); nexterror(); } if (ifc->m != NULL) ifc->m->bwrite(ifc, bp, version, ip); else freeb(bp); runlock(&ifc->rwlock); poperror(); } else freeb(bp); bp = next; } return; } } if (refresh == 0) { a = newarp6(arp, ip, ifc, 0); a->state = AOK; a->type = type; a->ctime = NOW; memmove(a->mac, mac, type->maclen); } qunlock(&arp->qlock); }
/* * 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); }
int ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c) { Proc *up = externup(); int medialen, len, chunk, uflen, flen, seglen, lid, offset, fragoff; int morefrags, blklen, rv = 0, tentative; uint8_t *gate, nexthdr; Block *xp, *nb; Fraghdr6 fraghdr; IP *ip; Ip6hdr *eh; Ipifc *ifc; Route *r, *sr; ip = f->ip; /* Fill out the ip header */ eh = (Ip6hdr*)(bp->rp); ip->stats[OutRequests]++; /* Number of uint8_ts in data and ip header to write */ len = blocklen(bp); tentative = iptentative(f, eh->src); if(tentative){ netlog(f, Logip, "reject tx of packet with tentative src address %I\n", eh->src); goto free; } if(gating){ chunk = nhgets(eh->ploadlen); if(chunk > len){ ip->stats[OutDiscards]++; netlog(f, Logip, "short gated packet\n"); goto free; } if(chunk + IP6HDR < len) len = chunk + IP6HDR; } if(len >= IP_MAX){ ip->stats[OutDiscards]++; netlog(f, Logip, "exceeded ip max size %I\n", eh->dst); goto free; } r = v6lookup(f, eh->dst, c); if(r == nil){ // print("no route for %I, src %I free\n", eh->dst, eh->src); ip->stats[OutNoRoutes]++; netlog(f, Logip, "no interface %I\n", eh->dst); rv = -1; goto free; } ifc = r->RouteTree.ifc; if(r->RouteTree.type & (Rifc|Runi)) gate = eh->dst; else if(r->RouteTree.type & (Rbcast|Rmulti)) { gate = eh->dst; sr = v6lookup(f, eh->src, nil); if(sr && (sr->RouteTree.type & Runi)) ifc = sr->RouteTree.ifc; } else gate = r->v6.gate; if(!gating) eh->vcf[0] = IP_VER6; eh->ttl = ttl; if(!gating) { eh->vcf[0] |= tos >> 4; eh->vcf[1] = tos << 4; }