/* * 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); }
/* * find first ip addr suitable for proto and * that isn't the friggin loopback address. * deprecate link-local and multicast addresses. */ static int myipvnaddr(uint8_t *ip, struct proto *proto, char *net) { int ipisv4, wantv4; struct ipifc *nifc; struct iplifc *lifc; uint8_t mynet[IPaddrlen], linklocal[IPaddrlen]; static struct ipifc *ifc; ipmove(linklocal, IPnoaddr); wantv4 = proto->version == 4; ifc = readipifc(net, ifc, -1); for(nifc = ifc; nifc; nifc = nifc->next) for(lifc = nifc->lifc; lifc; lifc = lifc->next){ maskip(lifc->ip, loopbackmask, mynet); if(ipcmp(mynet, loopbacknet) == 0) continue; if(ISIPV6MCAST(lifc->ip) || ISIPV6LINKLOCAL(lifc->ip)) { ipmove(linklocal, lifc->ip); continue; } ipisv4 = isv4(lifc->ip) != 0; if(ipcmp(lifc->ip, IPnoaddr) != 0 && wantv4 == ipisv4){ ipmove(ip, lifc->ip); return 0; } } /* no global unicast addrs found, fall back to link-local, if any */ ipmove(ip, linklocal); return ipcmp(ip, IPnoaddr) == 0? -1: 0; }
/* * set a local port making sure the quad of raddr,rport,laddr,lport is unique */ char* setluniqueport(Conv* c, int lport) { Proto *p; Conv *xp; int x; p = c->p; qlock(p); for(x = 0; x < p->nc; x++){ xp = p->conv[x]; if(xp == nil) break; if(xp == c) continue; if((xp->state == Connected || xp->state == Announced) && xp->lport == lport && xp->rport == c->rport && ipcmp(xp->raddr, c->raddr) == 0 && ipcmp(xp->laddr, c->laddr) == 0){ qunlock(p); return "address in use"; } } c->lport = lport; qunlock(p); return nil; }
void rudpadvise(Proto *rudp, Block *bp, char *msg) { Udphdr *h; uint8_t source[IPaddrlen], dest[IPaddrlen]; uint16_t psource, pdest; Conv *s, **p; h = (Udphdr*)(bp->rp); v4tov6(dest, h->udpdst); v4tov6(source, h->udpsrc); psource = nhgets(h->udpsport); pdest = nhgets(h->udpdport); /* Look for a connection */ for(p = rudp->conv; *p; p++) { s = *p; if(s->rport == pdest) if(s->lport == psource) if(ipcmp(s->raddr, dest) == 0) if(ipcmp(s->laddr, source) == 0){ qhangup(s->rq, msg); qhangup(s->wq, msg); break; } } freeblist(bp); }
// find first ip addr that isn't the friggin loopback address // unless there are no others int myipaddr(uchar *ip, char *net) { Ipifc *nifc; Iplifc *lifc; static Ipifc *ifc; uchar mynet[IPaddrlen]; ifc = readipifc(net, ifc, -1); for(nifc = ifc; nifc; nifc = nifc->next) for(lifc = nifc->lifc; lifc; lifc = lifc->next){ /* unspecified */ if(ipcmp(lifc->ip, IPnoaddr) == 0) continue; /* ipv6 loopback */ if(ipcmp(lifc->ip, loopback6) == 0) continue; /* ipv4 loopback */ maskip(lifc->ip, loopbackmask, mynet); if(ipcmp(mynet, loopbacknet) == 0) continue; ipmove(ip, lifc->ip); return 0; } ipmove(ip, IPnoaddr); return -1; }
/* * 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); }
static void ipifcregisterproxy(Fs *f, Ipifc *ifc, uint8_t *ip) { Conv **cp, **e; Ipifc *nifc; Iplifc *lifc; Medium *m; uint8_t net[IPaddrlen]; /* register the address on any network that will proxy for us */ e = &f->ipifc->conv[f->ipifc->nc]; if(!isv4(ip)) { /* V6 */ for(cp = f->ipifc->conv; cp < e; cp++){ if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc) continue; rlock(nifc); m = nifc->medium; if(m == nil || m->addmulti == nil) { runlock(nifc); continue; } for(lifc = nifc->lifc; lifc; lifc = lifc->next){ maskip(ip, lifc->mask, net); if(ipcmp(net, lifc->remote) == 0) { /* add solicited-node multicast addr */ ipv62smcast(net, ip); addselfcache(f, nifc, lifc, net, Rmulti); arpenter(f, V6, ip, nifc->mac, 6, 0); // (*m->addmulti)(nifc, net, ip); break; } } runlock(nifc); } } else { /* V4 */ for(cp = f->ipifc->conv; cp < e; cp++){ if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc) continue; rlock(nifc); m = nifc->medium; if(m == nil || m->areg == nil){ runlock(nifc); continue; } for(lifc = nifc->lifc; lifc; lifc = lifc->next){ maskip(ip, lifc->mask, net); if(ipcmp(net, lifc->remote) == 0){ (*m->areg)(nifc, ip); break; } } runlock(nifc); } } }
static int isvalidip(uchar *ip) { if(ipcmp(ip, IPnoaddr) == 0) return 0; if(ipcmp(ip, v4prefix) == 0) return 0; return 1; }
void udpadvise(Proto *udp, Block *bp, char *msg) { Udp4hdr *h4; Udp6hdr *h6; uchar source[IPaddrlen], dest[IPaddrlen]; ushort psource, pdest; Conv *s, **p; int version; h4 = (Udp4hdr*)(bp->rp); version = ((h4->vihl&0xF0)==IP_VER6) ? 6 : 4; switch(version) { case V4: v4tov6(dest, h4->udpdst); v4tov6(source, h4->udpsrc); psource = nhgets(h4->udpsport); pdest = nhgets(h4->udpdport); break; case V6: h6 = (Udp6hdr*)(bp->rp); ipmove(dest, h6->udpdst); ipmove(source, h6->udpsrc); psource = nhgets(h6->udpsport); pdest = nhgets(h6->udpdport); break; default: panic("udpadvise: version %d", version); return; /* to avoid a warning */ } /* Look for a connection */ qlock(udp); for(p = udp->conv; *p; p++) { s = *p; if(s->rport == pdest) if(s->lport == psource) if(ipcmp(s->raddr, dest) == 0) if(ipcmp(s->laddr, source) == 0){ if(s->ignoreadvice) break; qlock(s); qunlock(udp); qhangup(s->rq, msg); qhangup(s->wq, msg); qunlock(s); freeblist(bp); return; } } qunlock(udp); freeblist(bp); }
static uchar* getipv4addr(void) { Ipifc *nifc; Iplifc *lifc; static Ipifc *ifc; ifc = readipifc("/net", ifc, -1); for(nifc = ifc; nifc; nifc = nifc->next) for(lifc = nifc->lifc; lifc; lifc = lifc->next) if(ipcmp(lifc->ip, IPnoaddr) != 0 && ipcmp(lifc->ip, v4prefix) != 0) return lifc->ip; return nil; }
/* subnetcmp compares the two ip_subnet values a and b. * It returns -1, 0, or +1 if a is, respectively, * less than, equal to, or greater than b. */ static int subnetcmp(const ip_subnet *a, const ip_subnet *b) { ip_address neta, maska, netb, maskb; int r; networkof(a, &neta); maskof(a, &maska); networkof(b, &netb); maskof(b, &maskb); r = ipcmp(&neta, &netb); if (r == 0) r = ipcmp(&maska, &maskb); return r; }
/* * pick a local port and set it */ static void setlport(Conv *c) { uchar laddr[IPaddrlen]; ushort p; so_bind(c->sfd, c->restricted, c->laddr, c->lport); if(c->lport == 0 || ipcmp(c->laddr, IPnoaddr) == 0){ so_getsockname(c->sfd, laddr, &p); if(c->lport == 0) c->lport = p; if(ipcmp(c->laddr, IPnoaddr) == 0) memmove(c->laddr, laddr, sizeof laddr); } }
/* * called by protocol connect routine to set addresses */ char* Fsstdconnect(Conv *c, char *argv[], int argc) { char *p; switch(argc) { default: return "bad args to connect"; case 2: p = setraddrport(c, argv[1]); if(p != nil) return p; setladdr(c); p = setlport(c); if (p != nil) return p; break; case 3: p = setraddrport(c, argv[1]); if(p != nil) return p; p = setladdrport(c, argv[2], 0); if(p != nil) return p; } if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 && memcmp(c->laddr, v4prefix, IPv4off) == 0) || ipcmp(c->raddr, IPnoaddr) == 0) c->ipversion = V4; else c->ipversion = V6; return nil; }
static int rbootpread(char *bp, ulong offset, int len) { int n, i; char *buf; uchar a[4]; if(debug) print("dhcp: bootpread() \n"); buf = smalloc(READSTR); if(waserror()){ free(buf); nexterror(); } hnputl(a, fsip); n = snprint(buf, READSTR, "fsip %15V\n", a); hnputl(a, auip); n += snprint(buf + n, READSTR-n, "auip %15V\n", a); hnputl(a, gwip); n += snprint(buf + n, READSTR-n, "gwip %15V\n", a); hnputl(a, ipmask); n += snprint(buf + n, READSTR-n, "ipmask %15V\n", a); hnputl(a, ipaddr); n += snprint(buf + n, READSTR-n, "ipaddr %15V\n", a); n += snprint(buf+n, READSTR-n, "expired %lud\n", iplease); n += snprint(buf + n, READSTR-n, "dns"); if(dns2ip){ hnputl(a, dns2ip); n+=snprint(buf + n, READSTR-n, " %15V", a); } if(dns1ip){ hnputl(a, dns1ip); n += snprint(buf + n, READSTR-n, " %15V", a); } for(i=0; i<2; i++) if(ipcmp(pppdns[i], IPnoaddr) != 0 && ipcmp(pppdns[i], v4prefix) != 0) n += snprint(buf + n, READSTR-n, " %15I", pppdns[i]); snprint(buf + n, READSTR-n, "\n"); len = readstr(offset, bp, len, buf); poperror(); free(buf); return len; }
void netlogctl(Fs *f, char* s, int n) { int i, set; Netlogflag *fp; Cmdbuf *cb; Cmdtab *ct; cb = parsecmd(s, n); if(waserror()){ free(cb); nexterror(); } if(cb->nf < 2) error(Ebadnetctl); ct = lookupcmd(cb, routecmd, nelem(routecmd)); SET(set); switch(ct->index){ case CMset: set = 1; break; case CMclear: set = 0; break; case CMonly: parseip(f->alog->iponly, cb->f[1]); if(ipcmp(f->alog->iponly, IPnoaddr) == 0) f->alog->iponlyset = 0; else f->alog->iponlyset = 1; free(cb); poperror(); return; default: cmderror(cb, "unknown netlog control message"); } for(i = 1; i < cb->nf; i++){ for(fp = flags; fp->name; fp++) if(strcmp(fp->name, cb->f[i]) == 0) break; if(fp->name == nil) continue; if(set) f->alog->logmask |= fp->mask; else f->alog->logmask &= ~fp->mask; } free(cb); poperror(); }
/* * find the ifc on same net as the remote system. If none, * return NULL. */ struct Ipifc *findipifc(struct Fs *f, uint8_t * remote, int type) { struct Ipifc *ifc, *x; struct Iplifc *lifc; struct conv **cp, **e; uint8_t gnet[IPaddrlen]; uint8_t xmask[IPaddrlen]; x = NULL; memset(xmask, 0, IPaddrlen); /* find most specific match */ e = &f->ipifc->conv[f->ipifc->nc]; for (cp = f->ipifc->conv; cp < e; cp++) { if (*cp == 0) continue; ifc = (struct Ipifc *)(*cp)->ptcl; for (lifc = ifc->lifc; lifc; lifc = lifc->next) { maskip(remote, lifc->mask, gnet); if (ipcmp(gnet, lifc->net) == 0) { if (x == NULL || ipcmp(lifc->mask, xmask) > 0) { x = ifc; ipmove(xmask, lifc->mask); } } } } if (x != NULL) return x; /* for now for broadcast and multicast, just use first interface */ if (type & (Rbcast | Rmulti)) { for (cp = f->ipifc->conv; cp < e; cp++) { if (*cp == 0) continue; ifc = (struct Ipifc *)(*cp)->ptcl; if (ifc->lifc != NULL) return ifc; } } return NULL; }
/* * see if this address is bound to the interface */ struct Iplifc *iplocalonifc(struct Ipifc *ifc, uint8_t * ip) { struct Iplifc *lifc; for (lifc = ifc->lifc; lifc; lifc = lifc->next) if (ipcmp(ip, lifc->local) == 0) return lifc; return NULL; }
void netlogctl(struct Fs *f, char *s, int n) { ERRSTACK(1); int i, set = 0; Netlogflag *fp; struct cmdbuf *cb; struct cmdtab *ct; cb = parsecmd(s, n); if (waserror()) { kfree(cb); nexterror(); } if (cb->nf < 2) error(EINVAL, ERROR_FIXME); ct = lookupcmd(cb, routecmd, ARRAY_SIZE(routecmd)); switch (ct->index) { case CMset: set = 1; break; case CMclear: set = 0; break; case CMonly: parseip(f->alog->iponly, cb->f[1]); if (ipcmp(f->alog->iponly, IPnoaddr) == 0) f->alog->iponlyset = 0; else f->alog->iponlyset = 1; kfree(cb); poperror(); return; default: cmderror(cb, "unknown ip control message"); } for (i = 1; i < cb->nf; i++) { for (fp = flags; fp->name; fp++) if (strcmp(fp->name, cb->f[i]) == 0) break; if (fp->name == NULL) continue; if (set) f->alog->logmask |= fp->mask; else f->alog->logmask &= ~fp->mask; } kfree(cb); poperror(); }
static int convipvers(Conv *c) { if((memcmp(c->raddr, v4prefix, IPv4off) == 0 && memcmp(c->laddr, v4prefix, IPv4off) == 0) || ipcmp(c->raddr, IPnoaddr) == 0) return V4; else return V6; }
/* * see if this address is bound to the interface */ Iplifc* iplocalonifc(Ipifc *ifc, uint8_t *ip) { Iplifc *lifc; for(lifc = ifc->lifc; lifc; lifc = lifc->next) if(ipcmp(ip, lifc->local) == 0) return lifc; return nil; }
static void grekick(void *x, Block *bp) { Conv *c = x; GREhdr *ghp; uchar laddr[IPaddrlen], raddr[IPaddrlen]; if(bp == nil) return; /* Make space to fit ip header (gre header already there) */ bp = padblock(bp, GRE_IPONLY); if(bp == nil) return; /* make sure the message has a GRE header */ bp = pullupblock(bp, GRE_IPONLY+GRE_IPPLUSGRE); if(bp == nil) return; ghp = (GREhdr *)(bp->rp); ghp->vihl = IP_VER4; if(!((GREpriv*)c->p->priv)->raw){ v4tov6(raddr, ghp->dst); if(ipcmp(raddr, v4prefix) == 0) memmove(ghp->dst, c->raddr + IPv4off, IPv4addrlen); v4tov6(laddr, ghp->src); if(ipcmp(laddr, v4prefix) == 0){ if(ipcmp(c->laddr, IPnoaddr) == 0) findlocalip(c->p->f, c->laddr, raddr); /* pick interface closest to dest */ memmove(ghp->src, c->laddr + IPv4off, IPv4addrlen); } hnputs(ghp->eproto, c->rport); } ghp->proto = IP_GREPROTO; ghp->frag[0] = 0; ghp->frag[1] = 0; ipoput4(c->p->f, bp, 0, c->ttl, c->tos, nil); }
/* * fill in the media address if we have it. Otherwise return an * arpent that represents the state of the address resolution FSM * for ip. Add the packet to be sent onto the list of packets * waiting for ip->mac to be resolved. */ struct arpent *arpget(struct arp *arp, struct block *bp, int version, struct Ipifc *ifc, uint8_t *ip, uint8_t *mac) { int hash, len; struct arpent *a; struct medium *type = ifc->m; uint8_t v6ip[IPaddrlen]; uint16_t *s, *d; if (version == V4) { v4tov6(v6ip, ip); ip = v6ip; } qlock(&arp->qlock); hash = haship(ip); for (a = arp->hash[hash]; a; a = a->hash) { if (ipcmp(ip, a->ip) == 0) if (type == a->type) break; } if (a == NULL) { a = newarp6(arp, ip, ifc, (version != V4)); a->state = AWAIT; } a->utime = NOW; if (a->state == AWAIT) { if (bp != NULL) { if (a->hold) a->last->list = bp; else a->hold = bp; a->last = bp; bp->list = NULL; } return a; /* return with arp qlocked */ } s = (uint16_t *)a->mac; d = (uint16_t *)mac; len = a->type->maclen / 2; while (len) { *d++ = *s++; len--; } /* remove old entries */ if (NOW - a->ctime > 15 * 60 * 1000) cleanarpent(arp, a); qunlock(&arp->qlock); return NULL; }
int v6addrtype(uint8_t *addr) { if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0) return unknownv6; else if(islinklocal(addr) || isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop) return linklocalv6; else return globalv6; }
static void sunudpread(void *v) { int n, paraport, port; uchar *buf; Arg arg = *(Arg*)v; SunMsgUdp *msg; SunSrv *srv; Udphdr udp; uchar localip[IPaddrlen]; sendp(arg.csync, 0); srv = arg.srv; paraport = -1; /* 127.1 */ memmove(localip, v4prefix, IPaddrlen); localip[12] = 127; localip[15] = 1; buf = emalloc(UdpMaxRead); while((n = udpread(arg.fd, &udp, buf, UdpMaxRead)) > 0){ if(arg.srv->chatty) fprint(2, "udpread got %d (%d) from %I\n", n, Udphdrsize, udp.raddr); msg = emalloc(sizeof(SunMsgUdp)); msg->udp = udp; msg->msg.data = emalloc(n); msg->msg.count = n; memmove(msg->msg.data, buf, n); msg->msg.creply = arg.creply; msg->msg.srv = arg.srv; if(arg.srv->chatty) fprint(2, "message %p count %d\n", msg, msg->msg.count); if((srv->localonly || srv->localparanoia) && ipcmp(udp.raddr, localip) != 0){ fprint(2, "dropping message from %I: not local\n", udp.raddr); sunmsgreplyerror(&msg->msg, SunAuthTooWeak); continue; } if(srv->localparanoia){ port = nhgets(udp.rport); if(paraport == -1){ fprint(2, "paranoid mode: only %I/%d allowed\n", localip, port); paraport = port; }else if(paraport != port){ fprint(2, "dropping message from %I: not port %d\n", udp.raddr, port); sunmsgreplyerror(&msg->msg, SunAuthTooWeak); continue; } } if(srv->ipokay && !srv->ipokay(udp.raddr, nhgets(udp.rport))) msg->msg.rpc.status = SunProgUnavail; sendp(arg.srv->crequest, msg); } }
/* * remove a multicast address from an interface, called with c locked */ void ipifcremmulti(struct conv *c, uint8_t * ma, uint8_t * ia) { ERRSTACK(1); struct Ipmulti *multi, **l; struct Iplifc *lifc; struct conv **p; struct Ipifc *ifc; struct Fs *f; f = c->p->f; for (l = &c->multi; *l; l = &(*l)->next) if (ipcmp(ma, (*l)->ma) == 0) if (ipcmp(ia, (*l)->ia) == 0) break; multi = *l; if (multi == NULL) return; /* we don't have it open */ *l = multi->next; for (p = f->ipifc->conv; *p; p++) { if ((*p)->inuse == 0) continue; ifc = (struct Ipifc *)(*p)->ptcl; if (waserror()) { wunlock(&ifc->rwlock); nexterror(); } wlock(&ifc->rwlock); for (lifc = ifc->lifc; lifc; lifc = lifc->next) if (ipcmp(ia, lifc->local) == 0) remselfcache(f, ifc, lifc, ma); wunlock(&ifc->rwlock); poperror(); } kfree(multi); }
/* * remove a multicast address from an interface, called with c->car locked */ void ipifcremmulti(Conv *c, uint8_t *ma, uint8_t *ia) { Proc *up = externup(); Ipmulti *multi, **l; Iplifc *lifc; Conv **p; Ipifc *ifc; Fs *f; f = c->p->f; for(l = &c->multi; *l; l = &(*l)->next) if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0) break; multi = *l; if(multi == nil) return; /* we don't have it open */ *l = multi->next; for(p = f->ipifc->conv; *p; p++){ if((*p)->inuse == 0) continue; ifc = (Ipifc*)(*p)->ptcl; if(waserror()){ wunlock(ifc); nexterror(); } wlock(ifc); for(lifc = ifc->lifc; lifc; lifc = lifc->next) if(ipcmp(ia, lifc->local) == 0) remselfcache(f, ifc, lifc, ma); wunlock(ifc); poperror(); } free(multi); }
static void hostdel_v6(struct in6_addr *ip) { for (struct hostcache *ptr = hostcache_list; ptr; ptr = ptr->next) { if (!ipcmp(&(ptr->ipnum_v6), ip)) { if (ptr->next) { ptr->next->prev = ptr->prev; } *ptr->prev = ptr->next; free(ptr); return; } } }
int iptentative(Fs *f, uint8_t *addr) { Ipself *p; p = f->self->hash[hashipa(addr)]; for(; p; p = p->next){ if(ipcmp(addr, p->a) == 0) return p->link->lifc->tentative; } return 0; }
int ipisbm(uint8_t *ip) { if(isv4(ip)){ if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0) return V4; else if(ipcmp(ip, IPv4bcast) == 0) return V4; } else if(ip[0] == 0xff) return V6; return 0; }
void relsendack(Conv *c, Reliable *r, int hangup) { Udphdr *uh; Block *bp; Rudphdr *rh; int ptcllen; Fs *f; bp = allocb(UDP_IPHDR + UDP_RHDRSIZE); if(bp == nil) return; bp->wp += UDP_IPHDR + UDP_RHDRSIZE; f = c->p->f; uh = (Udphdr *)(bp->rp); uh->vihl = IP_VER4; rh = (Rudphdr*)uh; ptcllen = (UDP_RHDRSIZE-UDP_PHDRSIZE); uh->Unused = 0; uh->udpproto = IP_UDPPROTO; uh->frag[0] = 0; uh->frag[1] = 0; hnputs(uh->udpplen, ptcllen); v6tov4(uh->udpdst, r->addr); hnputs(uh->udpdport, r->port); hnputs(uh->udpsport, c->lport); if(ipcmp(c->laddr, IPnoaddr) == 0) findlocalip(f, c->laddr, c->raddr); v6tov4(uh->udpsrc, c->laddr); hnputs(uh->udplen, ptcllen); if(hangup) hnputl(rh->relsgen, Hangupgen); else hnputl(rh->relsgen, r->sndgen); hnputl(rh->relseq, 0); hnputl(rh->relagen, r->rcvgen); hnputl(rh->relack, r->rcvseq); if(r->acksent < r->rcvseq) r->acksent = r->rcvseq; uh->udpcksum[0] = 0; uh->udpcksum[1] = 0; hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, UDP_RHDRSIZE)); DPRINT("sendack: %lud/%lud, %lud/%lud\n", 0L, r->sndgen, r->rcvseq, r->rcvgen); doipoput(c, f, bp, 0, c->ttl, c->tos); }