/* * create a new arp entry for an ip address. */ static struct arpent *newarp6(struct arp *arp, uint8_t *ip, struct Ipifc *ifc, int addrxt) { unsigned int t; struct block *next, *xp; struct arpent *a, *e, *f, **l; struct medium *m = ifc->m; int empty; /* find oldest entry */ e = &arp->cache[NCACHE]; a = arp->cache; t = a->utime; for (f = a; f < e; f++) { if (f->utime < t) { t = f->utime; a = f; } } /* dump waiting packets */ xp = a->hold; a->hold = NULL; if (isv4(a->ip)) { while (xp) { next = xp->list; freeblist(xp); xp = next; } } else { /* queue icmp unreachable for rxmitproc later, w/o arp lock */ if (xp) { if (arp->dropl == NULL) arp->dropf = xp; else arp->dropl->list = xp; for (next = xp->list; next; next = next->list) xp = next; arp->dropl = xp; rendez_wakeup(&arp->rxmtq); } } /* take out of current chain */ l = &arp->hash[haship(a->ip)]; for (f = *l; f; f = f->hash) { if (f == a) { *l = a->hash; break; } l = &f->hash; } /* insert into new chain */ l = &arp->hash[haship(ip)]; a->hash = *l; *l = a; memmove(a->ip, ip, sizeof(a->ip)); a->utime = NOW; a->ctime = 0; /* somewhat of a "last sent time". 0, to trigger a send. */ a->type = m; a->rtime = NOW + ReTransTimer; a->rxtsrem = MAX_MULTICAST_SOLICIT; a->ifc = ifc; a->ifcid = ifc->ifcid; /* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */ if (!ipismulticast(a->ip) && addrxt) { l = &arp->rxmt; empty = (*l == NULL); for (f = *l; f; f = f->nextrxt) { if (f == a) { *l = a->nextrxt; break; } l = &f->nextrxt; } for (f = *l; f; f = f->nextrxt) { l = &f->nextrxt; } *l = a; if (empty) rendez_wakeup(&arp->rxmtq); } a->nextrxt = NULL; return a; }
static long ipwrite(Chan* ch, void *v, long n, vlong off) { Conv *c; Proto *x; char *p; Cmdbuf *cb; uchar ia[IPaddrlen], ma[IPaddrlen]; Fs *f; char *a; ulong offset = off; a = v; f = ipfs[ch->dev]; switch(TYPE(ch->qid)){ default: error(Eperm); case Qdata: x = f->p[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; if(c->wq == nil) error(Eperm); qwrite(c->wq, a, n); break; case Qarp: return arpwrite(f, a, n); case Qiproute: return routewrite(f, ch, a, n); case Qlog: netlogctl(f, a, n); return n; case Qndb: return ndbwrite(f, a, offset, n); break; case Qctl: x = f->p[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; cb = parsecmd(a, n); qlock(c); if(waserror()) { qunlock(c); free(cb); nexterror(); } if(cb->nf < 1) error("short control request"); if(strcmp(cb->f[0], "connect") == 0) connectctlmsg(x, c, cb); else if(strcmp(cb->f[0], "announce") == 0) announcectlmsg(x, c, cb); else if(strcmp(cb->f[0], "bind") == 0) bindctlmsg(x, c, cb); else if(strcmp(cb->f[0], "ttl") == 0) ttlctlmsg(c, cb); else if(strcmp(cb->f[0], "tos") == 0) tosctlmsg(c, cb); else if(strcmp(cb->f[0], "ignoreadvice") == 0) c->ignoreadvice = 1; else if(strcmp(cb->f[0], "addmulti") == 0){ if(cb->nf < 2) error("addmulti needs interface address"); if(cb->nf == 2){ if(!ipismulticast(c->raddr)) error("addmulti for a non multicast address"); if (parseip(ia, cb->f[1]) == -1) error(Ebadip); ipifcaddmulti(c, c->raddr, ia); } else { if (parseip(ia, cb->f[1]) == -1 || parseip(ma, cb->f[2]) == -1) error(Ebadip); if(!ipismulticast(ma)) error("addmulti for a non multicast address"); ipifcaddmulti(c, ma, ia); } } else if(strcmp(cb->f[0], "remmulti") == 0){ if(cb->nf < 2) error("remmulti needs interface address"); if(!ipismulticast(c->raddr)) error("remmulti for a non multicast address"); if (parseip(ia, cb->f[1]) == -1) error(Ebadip); ipifcremmulti(c, c->raddr, ia); } else if(strcmp(cb->f[0], "maxfragsize") == 0){ if(cb->nf < 2) error("maxfragsize needs size"); c->maxfragsize = (int)strtol(cb->f[1], nil, 0); } else if(x->ctl != nil) { p = x->ctl(c, cb->f, cb->nf); if(p != nil) error(p); } else error("unknown control request"); qunlock(c); free(cb); poperror(); } return n; }