## diffname ip/ipifc.c 1998/0306 ## diff -e /dev/null /n/emeliedump/1998/0306/sys/src/brazil/ip/ipifc.c 0a #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "ip.h" #define DPRINT if(0)print enum { Maxmedia = 16, Nself = Maxmedia*5, NHASH = (1<<6), NCACHE = 256, QMAX = 64*1024-1, }; Proto ipifc; extern Fs fs; Medium *media[] = { ðermedium, &nullmedium, 0 }; /* * cache of local addresses (addresses we answer to) */ typedef struct Ipself Ipself; struct Ipself { uchar a[IPaddrlen]; Ipself *hnext; /* next address in the hash table */ Iplink *link; /* binding twixt Ipself and Ipifc */ ulong expire; uchar type; /* type of address */ int ref; Ipself *next; /* free list */ }; typedef struct Ipselftab Ipselftab; struct Ipselftab { QLock; int inited; int acceptall; /* true if an interface has the null address */ Ipself *hash[NHASH]; /* hash chains */ }; Ipselftab selftab; /* * Multicast addresses are chained onto a Chan so that * we can remove them when the Chan is closed. */ typedef struct Ipmcast Ipmcast; struct Ipmcast { Ipmcast *next; uchar ma[IPaddrlen]; /* multicast address */ uchar ia[IPaddrlen]; /* interface address */ }; /* quick hash for ip addresses */ #define hashipa(a) ( ( ((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1] )%NHASH ) static char tifc[] = "ifc "; static void addselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a, int type); static void remselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a); static char* ipifcjoinmulti(Ipifc *ifc, char **argv, int argc); static char* ipifcleavemulti(Ipifc *ifc, char **argv, int argc); /* * find the medium with this name */ Medium* ipfindmedium(char *name) { Medium **mp; for(mp = media; *mp != nil; mp++) if(strcmp((*mp)->name, name) == 0) break; return *mp; } /* * attach a device (or pkt driver) to the interface. * called with c->car locked */ static char* ipifcbind(Conv *c, char **argv, int argc) { Ipifc *ifc; Medium *m; if(argc < 2) return Ebadarg; ifc = (Ipifc*)c->ptcl; /* bind the device to the interface */ m = ipfindmedium(argv[1]); if(m == nil) return "unknown interface type"; wlock(ifc); if(ifc->m != nil){ wunlock(ifc); return "interface already bound"; } if(waserror()){ wunlock(ifc); nexterror(); } (*m->bind)(ifc, argc, argv); if(argc > 2) strncpy(ifc->dev, argv[2], sizeof(ifc->dev)); else sprint(ifc->dev, "%s%d", m->name, c->x); ifc->dev[sizeof(ifc->dev)-1] = 0; ifc->m = m; ifc->minmtu = ifc->m->minmtu; ifc->maxmtu = ifc->m->maxmtu; ifc->ifcid++; wunlock(ifc); poperror(); return nil; } /* * detach a device from an interface, close the interface */ static char* ipifcunbind(Ipifc *ifc) { char *av[4]; char ip[32]; char mask[32]; if(waserror()){ wunlock(ifc); nexterror(); } wlock(ifc); if(ipifcgrab(ifc) == 0); goto out; /* hangup queues to stop queuing of packets */ qhangup(ifc->conv->rq, "unbind"); qhangup(ifc->conv->wq, "unbind"); /* dissociate routes */ ifc->ifcid++; /* disassociate logical interfaces */ av[0] = "remove"; av[1] = ip; av[2] = mask; av[3] = 0; while(ifc->lifc){ sprint(ip, "%I", ifc->lifc->local); sprint(mask, "%M", ifc->lifc->mask); ipifcrem(ifc, av, 3, 0); } /* disassociate device */ (*ifc->m->unbind)(ifc); memset(ifc->dev, 0, sizeof(ifc->dev)); ifc->arg = nil; ifc->m = &nullmedium; ifc->unbinding = 0; out: wunlock(ifc); poperror(); return nil; } static int ipifcstate(Conv *c, char *state, int n) { Ipifc *ifc; Iplifc *lifc; int m; ifc = (Ipifc*)c->ptcl; m = snprint(state, n, "%-12.12s %-5d", ifc->dev, ifc->maxmtu); rlock(ifc); for(lifc = ifc->lifc; lifc; lifc = lifc->next) m += snprint(state+m, n - m, " %-20.20I %-20.20M %-20.20I %-7d %-7d %-7d %-7d", lifc->local, lifc->mask, lifc->remote, ifc->in, ifc->out, ifc->inerr, ifc->outerr); m += snprint(state+m, n - m, "\n"); runlock(ifc); return m; } static int ipifclocal(Conv *c, char *state, int n) { Ipifc *ifc; Iplifc *lifc; Iplink *link; int m; ifc = (Ipifc*)c->ptcl; m = 0; rlock(ifc); for(lifc = ifc->lifc; lifc; lifc = lifc->next){ m += snprint(state+m, n - m, "%-20.20I ->", lifc->local); for(link = lifc->link; link; link = link->lifclink) m += snprint(state+m, n - m, " %-20.20I", link->local->a); m += snprint(state+m, n - m, "\n"); } runlock(ifc); return m; } static int ipifcinuse(Conv *c) { Ipifc *ifc; ifc = (Ipifc*)c->ptcl; return ifc->m != nil; } /* * called when a process writes to an interface's 'data' */ static void ipifckick(Conv *c, int) { Block *bp; Ipifc *ifc; bp = qget(c->wq); if(bp == nil) return; ifc = (Ipifc*)c->ptcl; if(ifc->m == nil || ifc->m->pktin == nil) freeb(bp); else (*ifc->m->pktin)(ifc, bp); } /* * we'll have to have a kick routine at * some point to deal with these */ static void ipifccreate(Conv *c) { Ipifc *ifc; c->rq = qopen(QMAX, 0, 0, 0); c->wq = qopen(QMAX, 0, 0, 0); ifc = (Ipifc*)c->ptcl; ifc->conv = c; } /* * called after last close of ipifc data or ctl * called with c locked, we must unlock */ static void ipifcclose(Conv *c) { /* * nothing to do since conversation stays open * till the device is unbound. */ unlock(c); } /* * add an address to an interface. */ char* ipifcadd(Ipifc *ifc, char **argv, int argc) { uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen]; uchar bcast[IPaddrlen], net[IPaddrlen]; Iplifc *lifc, **l; int i, type, mtu; memset(ip, 0, IPaddrlen); memset(mask, 0, IPaddrlen); memset(rem, 0, IPaddrlen); switch(argc){ case 5: mtu = strtoul(argv[4], 0, 0); if(mtu >= ifc->m->minmtu && mtu <= ifc->m->maxmtu) ifc->maxmtu = mtu; /* fall through */ case 4: parseip(ip, argv[1]); parseipmask(mask, argv[2]); parseip(rem, argv[3]); maskip(rem, mask, net); break; case 3: parseip(ip, argv[1]); parseipmask(mask, argv[2]); maskip(ip, mask, rem); maskip(rem, mask, net); break; case 2: parseip(ip, argv[1]); memmove(mask, defmask(ip), IPaddrlen); maskip(ip, mask, rem); maskip(rem, mask, net); break; default: return Ebadarg; break; } if(waserror()){ wunlock(ifc); panic("ipifcadd"); } 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) 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->next = nil; for(l = &ifc->lifc; *l; l = &(*l)->next) ; *l = lifc; /* add a route for the local network */ type = Rifc; if(ipcmp(mask, IPallbits) == 0) type |= Rptpt; if(isv4(ip)) v4addroute(tifc, rem+IPv4off, mask+IPv4off, ip+IPv4off, type); else v6addroute(tifc, ip, mask, rem, type); addselfcache(ifc, lifc, ip, Runi); /* add subnet directed broadcast addresses to the self cache */ for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) | ~mask[i]; addselfcache(ifc, lifc, bcast, Rbcast); /* add network directed broadcast addresses to the self cache */ memmove(mask, defmask(ip), IPaddrlen); for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) | ~mask[i]; addselfcache(ifc, lifc, bcast, Rbcast); addselfcache(ifc, lifc, IPv4bcast, Rbcast); out: wunlock(ifc); poperror(); return nil; } /* * remove an address from an interface. * called with c->car locked */ char* ipifcrem(Ipifc *ifc, char **argv, int argc, int dolock) { uchar ip[IPaddrlen]; uchar mask[IPaddrlen]; Iplifc *lifc, **l; if(argc < 3) return Ebadarg; parseip(ip, argv[1]); parseipmask(mask, argv[2]); if(dolock){ if(waserror()){ wunlock(ifc); nexterror(); } wlock(ifc); } /* find address on this interface and remove from chain */ lifc = nil; for(l = &ifc->lifc; *l; l = &(*l)->next) if(memcmp(ip, (*l)->local, IPaddrlen) == 0) if(memcmp(mask, (*l)->mask, IPaddrlen) == 0){ lifc = *l; *l = lifc->next; break; } if(lifc == nil) return "address not on this interface"; /* disassociate any addresses */ while(lifc->link) remselfcache(ifc, lifc, lifc->link->local->a); /* remove the route for this logical interface */ if(isv4(ip)) v4delroute(lifc->remote+IPv4off, lifc->mask+IPv4off); else v6delroute(lifc->remote, lifc->mask); free(lifc); out: if(dolock){ wunlock(ifc); poperror(); } return nil; } /* * distrbute routes to active interfaces like the * TRIP linecards */ void ipifcaddroute(int vers, uchar *addr, uchar *mask, uchar *gate, int type) { Medium *m; Conv **cp; Ipifc *ifc; for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){ if(*cp != nil) { ifc = (Ipifc*)(*cp)->ptcl; m = ifc->m; if(m->addroute != nil) m->addroute(ifc, vers, addr, mask, gate, type); } } } void ipifcremroute(int vers, uchar *addr, uchar *mask) { Medium *m; Conv **cp; Ipifc *ifc; for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){ if(*cp != nil) { ifc = (Ipifc*)(*cp)->ptcl; m = ifc->m; if(m->remroute != nil) m->remroute(ifc, vers, addr, mask); } } } /* * associate an address with the interface. This wipes out any previous * addresses. This is a macro that means, remove all the old interfaces * and add a new one. */ static char* ipifcconnect(Conv* c, char **argv, int argc) { char *err; Ipifc *ifc; char *av[4]; char ip[80], mask[80]; ifc = (Ipifc*)c->ptcl; if(ifc->m == nil) return "ipifc not yet bound to device"; av[0] = "remove"; av[1] = ip; av[2] = mask; av[3] = 0; if(waserror()){ wunlock(ifc); nexterror(); } wlock(ifc); while(ifc->lifc){ sprint(ip, "%I", ifc->lifc->local); sprint(mask, "%I", ifc->lifc->mask); ipifcrem(ifc, av, 3, 0); } wunlock(ifc); poperror(); err = ipifcadd(ifc, argv, argc); if(err) return err; Fsconnected(&fs, c, nil); return nil; } /* * non-standard control messages. * called with c->car locked. */ static char* ipifcctl(Conv* c, char**argv, int argc) { Ipifc *ifc; ifc = (Ipifc*)c->ptcl; if(strcmp(argv[0], "add") == 0) return ipifcadd(ifc, argv, argc); else if(strcmp(argv[0], "remove") == 0) return ipifcrem(ifc, argv, argc, 1); else if(strcmp(argv[0], "unbind") == 0) return ipifcunbind(ifc); else if(strcmp(argv[0], "joinmulti") == 0) return ipifcjoinmulti(ifc, argv, argc); else if(strcmp(argv[0], "leavemulti") == 0) return ipifcleavemulti(ifc, argv, argc); return "unsupported ctl"; } void ipifcinit(Fs *fs) { ipifc.name = "ipifc"; ipifc.kick = ipifckick; ipifc.connect = ipifcconnect; ipifc.announce = nil; ipifc.bind = ipifcbind; ipifc.state = ipifcstate; ipifc.create = ipifccreate; ipifc.close = ipifcclose; ipifc.rcv = nil; ipifc.ctl = ipifcctl; ipifc.advise = nil; ipifc.stats = ipstats; ipifc.inuse = ipifcinuse; ipifc.local = ipifclocal; ipifc.ipproto = -1; ipifc.nc = Maxmedia; ipifc.ptclsize = sizeof(Ipifc); Fsproto(fs, &ipifc); } /* * add to self routing cache * called with c->car locked */ static void addselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a, int type) { Ipself *p; Iplink *lp; int h; qlock(&selftab); /* see if the address already exists */ h = hashipa(a); for(p = selftab.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 = selftab.hash[h]; selftab.hash[h] = p; /* if the null address, accept all packets */ if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0) selftab.acceptall = 1; } /* look for a link for this lifc */ for(lp = p->link; lp; lp = lp->locallink) 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->local = p; lp->locallink = p->link; p->link = lp; lp->lifclink = lifc->link; lifc->link = lp; /* add to routing table */ if(isv4(a)) v4addroute(tifc, a+IPv4off, IPallbits+IPv4off, a+IPv4off, type); else v6addroute(tifc, a, IPallbits, a, type); if((type & Rmulti) && ifc->m->addmulti != nil) (*ifc->m->addmulti)(ifc, a, lifc->local); } else { lp->ref++; } qunlock(&selftab); } /* * These structures are unlinked from their chains while * other threads may be using them. To avoid excessive locking, * just put them aside for a while before freeing them. * called with &selftab locked */ static Iplink *freeiplink; static Ipself *freeipself; static void iplinkfree(Iplink *p) { Iplink **l, *np; ulong now = msec; l = &freeiplink; for(np = *l; np; np = *l){ if(np->expire > now){ *l = np->next; free(np); continue; } l = &np->next; } p->expire = now + 5000; /* give other threads 5 secs to get out */ p->next = nil; *l = p; } static void ipselffree(Ipself *p) { Ipself **l, *np; ulong now = msec; l = &freeipself; for(np = *l; np; np = *l){ if(np->expire > now){ *l = np->next; free(np); continue; } l = &np->next; } p->expire = now + 5000; /* give other threads 5 secs to get out */ p->next = nil; *l = p; } /* * Decrement reference for this address on this link. * Unlink from selftab if this is the last ref. * called with c->car locked */ static void remselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a) { Ipself *p, **l; Iplink *lp, *llp, **ill, **lll; qlock(&selftab); /* find the unique selftab entry */ l = &selftab.hash[hashipa(a)]; for(p = *l; p; p = *l){ if(ipcmp(p->a, a) == 0) break; l = &p->next; } if(p == nil) goto out; /* * walk down links from an ifc looking for one * that matches the selftab entry */ ill = &lifc->link; for(lp = *ill; lp; lp = *ill){ if(lp->local == p) break; ill = &lp->lifclink; } if(lp == nil) goto out; /* * walk down the links from the selftab looking for * the one we just found */ lll = &p->link; for(llp = *lll; llp; llp = *lll){ if(llp == lp) break; lll = &lp->locallink; } if(llp == nil) panic("remselfcache"); if(--(llp->ref) != 0) goto out; if((p->type & Rmulti) && ifc->m->remmulti != nil) (*ifc->m->remmulti)(ifc, a, lifc->local); /* ref == 0, remove from both chains and free the link */ *ill = lp->lifclink; *lll = llp->locallink; iplinkfree(lp); /* remove from routing table */ if(isv4(a)) v4delroute(a+IPv4off, IPallbits+IPv4off); else v6delroute(a, IPallbits); if(p->link != nil) goto out; /* no more links, remove from hash and free */ *l = p->next; ipselffree(p); /* if IPnoaddr, forget */ if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0) selftab.acceptall = 0; out: qunlock(&selftab); } static void dumpselftab(void) { int i, count; Ipself *p; qlock(&selftab); for(i = 0; i < NHASH; i++){ p = selftab.hash[i]; if(p == nil) continue; count = 0; for(; p != nil && count++ < 6; p = p->next) print("(%i %d %lux)", p->a, p->type, p); print("\n"); } qunlock(&selftab); } /* * returns * 0 - no match * Runi * Rbcast * Rmcast */ int ipforme(uchar *addr) { Ipself *p; int count; p = selftab.hash[hashipa(addr)]; count = 0; for(; p; p = p->next){ if(count++ > 1000){ /* check for loops */ dumpselftab(); break; } if(ipcmp(addr, p->a) == 0) return p->type; } /* hack to say accept anything */ if(selftab.acceptall) return Runi; return 0; } /* * find the ifc on same net as the remote system. If none, * return nil. */ Ipifc* findipifc(uchar *remote, int type) { Ipifc *ifc; Iplifc *lifc; Conv **cp; uchar gnet[IPaddrlen]; for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){ if(*cp == 0) continue; ifc = (Ipifc*)(*cp)->ptcl; for(lifc = ifc->lifc; lifc; lifc = lifc->next){ maskip(remote, lifc->mask, gnet); if(ipcmp(gnet, lifc->net) == 0){ qunlock(&ipifc); return ifc; } } } /* for now for broadcast and mutlicast, just use first interface */ if(type & (Rbcast|Rmulti)){ for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){ if(*cp == 0) continue; ifc = (Ipifc*)(*cp)->ptcl; if(ifc->lifc != nil) return ifc; } } return nil; } /* * find the local address 'closest' to the remote system, copy it to * local and return the ifc for that address */ void findlocalip(uchar *local, uchar *remote) { Ipifc *ifc; Iplifc *lifc; Conv **cp; Route *r; uchar gate[IPaddrlen]; uchar gnet[IPaddrlen]; qlock(&ipifc); r = v6lookup(remote); if(r != nil){ ifc = r->ifc; if(r->type & Rv4) v4tov6(gate, r->v4.gate); else ipmove(gate, r->v6.gate); if(r->type & Rifc){ ipmove(local, gate); goto out; } /* 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; } } } /* no match, choose first ifc local address */ for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){ if(*cp == 0) continue; ifc = (Ipifc*)(*cp)->ptcl; for(lifc = ifc->lifc; lifc; lifc = lifc->next){ ipmove(local, lifc->local); goto out; } } out: qunlock(&ipifc); } /* * return first v4 address associated with an interface */ int ipv4local(Ipifc *ifc, uchar *addr) { Iplifc *lifc; for(lifc = ifc->lifc; lifc; lifc = lifc->next){ if(isv4(lifc->local)){ memmove(addr, lifc->local+IPv4off, IPv4addrlen); return 1; } } return 0; } /* * return first v6 address associated with an interface */ int ipv6local(Ipifc *ifc, uchar *addr) { Iplifc *lifc; for(lifc = ifc->lifc; lifc; lifc = lifc->next){ if(!isv4(lifc->local)){ ipmove(addr, lifc->local); return 1; } } return 0; } /* * see if this address is bound to the interface */ Iplifc* iplocalonifc(Ipifc *ifc, uchar *ip) { Iplifc *lifc; for(lifc = ifc->lifc; lifc; lifc = lifc->next) if(ipcmp(ip, lifc->local) == 0) return lifc; return nil; } /* * See if we're proxying for this address on this interface */ int ipproxyifc(Ipifc *ifc, uchar *ip) { Route *r; uchar net[IPaddrlen]; Iplifc *lifc; /* see if this is a direct connected pt to pt address */ r = v6lookup(ip); if(r == nil) return 0; if((r->type & Rifc) == 0) return 0; if((r->type & Rptpt) == 0) 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; } /* * return multicast version if any */ int ipismulticast(uchar *ip) { if(isv4(ip)){ if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0) return V4; } else { if(ip[0] == 0xff) return V6; } return 0; } /* * used to allow on the fly unbinds, return -1 if interface unusable */ int ipifccheckin(Ipifc *ifc, Medium *med) { int rv; lock(&ifc->idlock); if(ifc->unbinding || ifc->m != med) rv = -1; else rv = ++(ifc->ref); if(ifc->ref < 0) panic("ipifccheckin"); unlock(&ifc->idlock); return rv; } void ipifccheckout(Ipifc *ifc) { lock(&ifc->idlock); if(--(ifc->ref) == 0) if(ifc->unbinding) wakeup(&ifc->wait); if(ifc->ref < 0) panic("ipifccheckin"); unlock(&ifc->idlock); } static int allout(void *x) { Ipifc *ifc = x; return ifc->ref == 0; } int ipifcgrab(Ipifc *ifc) { lock(&ifc->idlock); if(ifc->unbinding){ unlock(&ifc->idlock); return 0; } ifc->unbinding = 1; /* after this ref can only go down */ unlock(&ifc->idlock); sleep(&ifc->wait, allout, ifc); return 1; } /* * add a multicast address to an interface, called with c->car locked */ void ipifcaddmulti(Conv *c, uchar *ma, uchar *ia) { Ipifc *ifc; Iplifc *lifc; Conv **p; Ipmulti *multi, **l; for(l = &c->multi; *l; l = &(*l)->next) if(ipcmp(ma, (*l)->ma) == 0) if(ipcmp(ia, (*l)->ia) == 0) return; /* it's already there */ multi = *l = smalloc(sizeof(*multi)); ipmove(multi->ma, ma); ipmove(multi->ia, ia); multi->next = nil; for(p = 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) addselfcache(ifc, lifc, ma, Rmulti); wunlock(ifc); poperror(); } } /* * remove a multicast address from an interface, called with c->car locked */ void ipifcremmulti(Conv *c, uchar *ma, uchar *ia) { Ipmulti *multi, **l; Iplifc *lifc; Conv **p; Ipifc *ifc; 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 == nil) return; /* we don't have it open */ *l = multi->next; for(p = 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(ifc, lifc, ma); wunlock(ifc); poperror(); } free(multi); } /* * make lifc's join and leave multicast groups */ static char* ipifcjoinmulti(Ipifc *ifc, char **argv, int argc) { USED(ifc, argv, argc); return nil; } static char* ipifcleavemulti(Ipifc *ifc, char **argv, int argc) { USED(ifc, argv, argc); return nil; } . ## diffname ip/ipifc.c 1998/0307 ## diff -e /n/emeliedump/1998/0306/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0307/sys/src/brazil/ip/ipifc.c 1004,1056d 743,745c *l_lifc = link->lifclink; *l_self = link->selflink; iplinkfree(link); . 736c if(--(link->ref) != 0) . 733c if(link == nil) . 730c l_self = &link->selflink; . 726,728c l_self = &p->link; for(link = *l_self; link; link = *l_self){ if(link == *(l_lifc)) . 719c if(link == nil) . 716c l_lifc = &link->lifclink; . 712,714c l_lifc = &lifc->link; for(link = *l_lifc; link; link = *l_lifc){ if(link->self == p) . 693c Iplink *link, **l_self, **l_lifc; . 615,616c lp->self = p; lp->selflink = p->link; . 606c for(lp = p->link; lp; lp = lp->selflink) . 475a if(m == nil) continue; . 458a if(m == nil) continue; . 426c remselfcache(ifc, lifc, lifc->link->self->a); . 284,287c Ipifc *ifc; Medium *m; ifc = (Ipifc*)c->ptcl; m = ifc->m; if(m != nil && m->unbindonclose) ipifcunbind(ifc); . 274a ifc->unbinding = 0; ifc->m = nil; . 226c m += snprint(state+m, n - m, " %-20.20I", link->self->a); . 175,182c ifc->m = nil; . 161,163d 156a /* disassociate device */ (*ifc->m->unbind)(ifc); memset(ifc->dev, 0, sizeof(ifc->dev)); ifc->arg = nil; . 154,155c /* dissociate routes */ ifc->ifcid++; . 25a &pktmedium, . ## diffname ip/ipifc.c 1998/0310 ## diff -e /n/emeliedump/1998/0307/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0310/sys/src/brazil/ip/ipifc.c 789a } static char *stformat = "%-32.32I %2.2d %4.4s\n"; enum { Nstformat= 41, }; long ipselftabread(char *cp, ulong offset, int n) { int i, m, nifc; Ipself *p; Iplink *link; char state[8]; m = 0; qlock(&selftab); for(i = 0; i < NHASH && m < n; i++){ for(p = selftab.hash[i]; p != nil && m < n; p = p->next){ if(offset == 0){ nifc = 0; for(link = p->link; link; link = link->selflink) nifc++; routetype(p->type, state); m += snprint(cp + m, n - m, stformat, p->a, nifc, state); } offset -= Nstformat; } } qunlock(&selftab); return m; . 786c print("(%I %d %lux)", p->a, p->type, p); . 758,760d 751a if(p->link != nil) goto out; . ## diffname ip/ipifc.c 1998/0313 ## diff -e /n/emeliedump/1998/0310/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0313/sys/src/brazil/ip/ipifc.c 1116c remselfcache(f, ifc, lifc, ma); . 1104c for(p = f->ipifc->conv; *p; p++){ . 1091a Fs *f; f = c->p->f; . 1075c addselfcache(f, ifc, lifc, ma, Rmulti); . 1064c for(p = f->ipifc->conv; *p; p++){ . 1052a Fs *f; f = c->p->f; . 1009c r = v6lookup(f, ip); . 1002c ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip) . 946c qunlock(f->ipifc); . 935c e = &f->ipifc->conv[f->ipifc->nc]; for(cp = f->ipifc->conv; cp < e; cp++){ . 909,910c qlock(f->ipifc); r = v6lookup(f, remote); . 904c Conv **cp, **e; . 900c findlocalip(Fs *f, uchar *local, uchar *remote) . 883c for(cp = f->ipifc->conv; cp < e; cp++){ . 877d 874,875c if(ipcmp(gnet, lifc->net) == 0) . 868c e = &f->ipifc->conv[f->ipifc->nc]; for(cp = f->ipifc->conv; cp < e; cp++){ . 865c Conv **cp, **e; . 861c findipifc(Fs *f, uchar *remote, int type) . 850c if(f->self->acceptall) . 841,844d 838,839c p = f->self->hash[hashipa(addr)]; . 836d 833c ipforme(Fs *f, uchar *addr) . 820c qunlock(f->self); . 809c for(p = f->self->hash[i]; p != nil && m < n; p = p->next){ . 807c qlock(f->self); . 799c ipselftabread(Fs *f, char *cp, ulong offset, int n) . 773,791d 770c qunlock(f->self); . 767c f->self->acceptall = 0; . 759c v6delroute(f, a, IPallbits); . 757c v4delroute(f, a+IPv4off, IPallbits+IPv4off); . 703c l = &f->self->hash[hashipa(a)]; . 700c qlock(f->self); . 695c remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a) . 645c * called with f->self locked . 638c qunlock(f->self); . 630c v6addroute(f, tifc, a, IPallbits, a, type); . 628c v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off, a+IPv4off, type); . 607c f->self->acceptall = 1; . 602,603c p->next = f->self->hash[h]; f->self->hash[h] = p; . 593c for(p = f->self->hash[h]; p; p = p->next) . 589c qlock(f->self); . 583c addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type) . 575c ipifc = smalloc(sizeof(Ipifc)); ipifc->name = "ipifc"; ipifc->kick = ipifckick; ipifc->connect = ipifcconnect; ipifc->announce = nil; ipifc->bind = ipifcbind; ipifc->state = ipifcstate; ipifc->create = ipifccreate; ipifc->close = ipifcclose; ipifc->rcv = nil; ipifc->ctl = ipifcctl; ipifc->advise = nil; ipifc->stats = ipifcstats; ipifc->inuse = ipifcinuse; ipifc->local = ipifclocal; ipifc->ipproto = -1; ipifc->nc = Maxmedia; ipifc->ptclsize = sizeof(Ipifc); f->ipifc = ipifc; /* hack for ipifcremroute, findipifc, ... */ f->self = smalloc(sizeof(Ipselftab)); /* hack for ipforme */ Fsproto(f, ipifc); . 557,573c Proto *ipifc; . 555c ipifcinit(Fs *f) . 553a ipifcstats(Proto *ipifc, char *buf, int len) { return ipstats(ipifc->f, buf, len); } . 542a else if(strcmp(argv[0], "bootp") == 0) return bootp(ifc); . 526c Fsconnected(c, nil); . 475c e = &f->ipifc->conv[f->ipifc->nc]; for(cp = f->ipifc->conv; cp < e; cp++){ . 472c Conv **cp, **e; . 469c ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask) . 456c e = &f->ipifc->conv[f->ipifc->nc]; for(cp = f->ipifc->conv; cp < e; cp++){ . 453c Conv **cp, **e; . 450c ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type) . 433c v6delroute(f, lifc->remote, lifc->mask); . 431c v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off); . 427c remselfcache(f, ifc, lifc, lifc->link->self->a); . 400a f = ifc->conv->p->f; . 396a Fs *f; . 379c addselfcache(f, ifc, lifc, IPv4bcast, Rbcast); . 377c addselfcache(f, ifc, lifc, bcast, Rbcast); . 371c addselfcache(f, ifc, lifc, bcast, Rbcast); . 366c addselfcache(f, ifc, lifc, ip, Runi); . 364c v6addroute(f, tifc, ip, mask, rem, type); . 362c v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, ip+IPv4off, type); . 302a f = ifc->conv->p->f; . 301a Fs *f; . 255c (*ifc->m->pktin)(c->p->f, ifc, bp); . 73,74c static void addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type); static void remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a); . 54d 46d 27a &tripmedium, . 20,22d ## diffname ip/ipifc.c 1998/0314 ## diff -e /n/emeliedump/1998/0313/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0314/sys/src/brazil/ip/ipifc.c 556a else if(strcmp(argv[0], "iprouting") == 0){ i = 1; if(argc > 1) i = atoi(argv[1]); iprouting(c->p->f, i); return nil; } . 542a int i; . ## diffname ip/ipifc.c 1998/0316 ## diff -e /n/emeliedump/1998/0314/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0316/sys/src/brazil/ip/ipifc.c 880c /* for now for broadcast and multicast, just use first interface */ . 878a if(x != nil) return x; . 875,876c if(ipcmp(gnet, lifc->net) == 0){ if(x == nil || ipcmp(lifc->mask, xmask) > 0){ x = ifc; ipmove(xmask, lifc->mask); } } . 867a x = nil; /* find most specific match */ . 866a uchar xmask[IPaddrlen]; . 863c Ipifc *ifc, *x; . 363c v6addroute(f, tifc, rem, mask, ip, type); . ## diffname ip/ipifc.c 1998/0318 ## diff -e /n/emeliedump/1998/0316/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0318/sys/src/brazil/ip/ipifc.c 375a addselfcache(f, ifc, lifc, bcast, Rbcast); /* add old network directed broadcast addresses to the self cache */ memmove(mask, defmask(ip), IPaddrlen); for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) & mask[i]; . 371a /* add old subnet directed broadcast addresses to the self cache */ for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) & mask[i]; addselfcache(f, ifc, lifc, bcast, Rbcast); . ## diffname ip/ipifc.c 1998/0330 ## diff -e /n/emeliedump/1998/0318/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0330/sys/src/brazil/ip/ipifc.c 568a else if(strcmp(argv[0], "mtu") == 0) return ipifcsetmtu(ifc, argv, argc); . 288a * change an interface's mtu */ char* ipifcsetmtu(Ipifc *ifc, char **argv, int argc) { int mtu; if(argc < 2) return Ebadarg; if(ifc->m == nil) return Ebadarg; mtu = strtoul(argv[1], 0, 0); if(mtu < ifc->m->minmtu || mtu > ifc->m->maxmtu) return Ebadarg; ifc->maxmtu = mtu; return nil; } /* . ## diffname ip/ipifc.c 1998/0423 ## diff -e /n/emeliedump/1998/0330/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0423/sys/src/brazil/ip/ipifc.c 72a /* * link in a new medium */ void addipmedium(Medium *med) { int i; for(i = 0; i < nelem(media)-1; i++) if(media[i] == nil){ media[i] = med; break; } } . 22,25d 20c Medium *media[32] = . ## diffname ip/ipifc.c 1998/0507 ## diff -e /n/emeliedump/1998/0423/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0507/sys/src/brazil/ip/ipifc.c 162a ifc->conv->inuse--; . 137a ifc->conv->inuse++; . ## diffname ip/ipifc.c 1998/0515 ## diff -e /n/emeliedump/1998/0507/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0515/sys/src/brazil/ip/ipifc.c 296c if(m == nil || m->unbindonclose) . 168c if(ifc->m) (*ifc->m->unbind)(ifc); . ## diffname ip/ipifc.c 1998/0516 ## diff -e /n/emeliedump/1998/0515/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0516/sys/src/brazil/ip/ipifc.c 297c if(m != nil && m->unbindonclose) . 190a . 168c if(ifc->m != nil && ifc->m->unbind) . 164c if(ifc->m != nil && ifc->m->unbindonclose == 0){ lock(ifc->conv); ifc->conv->inuse--; unlock(ifc->conv); } . 138c if(ifc->m->unbindonclose == 0){ lock(ifc->conv); ifc->conv->inuse++; unlock(ifc->conv); } . ## diffname ip/ipifc.c 1998/0630 ## diff -e /n/emeliedump/1998/0516/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0630/sys/src/brazil/ip/ipifc.c 839c v6delroute(f, a, IPallbits, 1); . 837c v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1); . 488c v6delroute(f, lifc->remote, lifc->mask, 1); . 486c v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1); . 220c } . 217c " %-20.20I %-20.20M %-20.20I %-7d %-7d %-7d %-7d\n", . 215c m = 0; for(lifc = ifc->lifc; lifc; lifc = lifc->next) { m += snprint(state, n, "%-12.12s %-5d", ifc->dev, ifc->maxmtu); . 212,213d 199d 176,177c (*ifc->m->unbind)(ifc); . 168,172c ifc->conv->inuse--; . 138,142c ifc->conv->inuse++; . ## diffname ip/ipifc.c 1998/0702 ## diff -e /n/emeliedump/1998/0630/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0702/sys/src/brazil/ip/ipifc.c 331a if(ifc->m == nil) return "ipifc not yet bound to device"; . ## diffname ip/ipifc.c 1998/0709 ## diff -e /n/emeliedump/1998/0702/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0709/sys/src/brazil/ip/ipifc.c 210d 203,205c for(lifc = ifc->lifc; lifc; lifc = lifc->next) . 201a m = snprint(state, n, "%-12.12s %-5d", ifc->dev, ifc->maxmtu); . 168c if(ifc->m != nil && ifc->m->unbind) (*ifc->m->unbind)(ifc); . 164c if(ifc->m != nil && ifc->m->unbindonclose == 0){ lock(ifc->conv); ifc->conv->inuse--; unlock(ifc->conv); } . 138c if(ifc->m->unbindonclose == 0){ lock(ifc->conv); ifc->conv->inuse++; unlock(ifc->conv); } . ## diffname ip/ipifc.c 1998/0717 ## diff -e /n/emeliedump/1998/0709/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0717/sys/src/brazil/ip/ipifc.c 496,497d 494c if(dolock) . 479a } . 478c if(lifc == nil){ if(dolock) wunlock(ifc); . 466d 460,464c if(dolock) . 436d 377,380d 214c for(lifc = ifc->lifc; lifc && n > m; lifc = lifc->next) . ## diffname ip/ipifc.c 1998/0728 ## diff -e /n/emeliedump/1998/0717/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0728/sys/src/brazil/ip/ipifc.c 1098a int ipisbm(uchar *ip) { if(isv4(ip)){ if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0) return V4; if(ipcmp(ip, IPv4bcast) == 0) return V4; } else { if(ip[0] == 0xff) return V6; } return 0; } . ## diffname ip/ipifc.c 1998/0825 ## diff -e /n/emeliedump/1998/0728/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0825/sys/src/brazil/ip/ipifc.c 216c " %-20.20I %-20.20M %-20.20I %-7lud %-7lud %-7lud %-7lud\n", . ## diffname ip/ipifc.c 1998/0930 ## diff -e /n/emeliedump/1998/0825/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0930/sys/src/brazil/ip/ipifc.c 486d ## diffname ip/ipifc.c 1998/1005 ## diff -e /n/emeliedump/1998/0930/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/1005/sys/src/brazil/ip/ipifc.c 988,999c findprimaryip(f, local); . 974,978d 959d 950a * returns first ip address configured */ void findprimaryip(Fs *f, uchar *local) { Conv **cp, **e; Ipifc *ifc; Iplifc *lifc; /* find first ifc local address */ 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){ ipmove(local, lifc->local); return; } } } /* . 405a if(type & Rptpt) goto out; . 398a } . 397c if(ipcmp(mask, IPallbits) == 0){ /* point to point networks are a hack */ if(ipcmp(ip, rem) == 0) findprimaryip(f, lifc->local); . 218a if(ifc->lifc == nil) m += snprint(state+m, n - m, "\n"); . ## diffname ip/ipifc.c 1999/0223 ## diff -e /n/emeliedump/1998/1005/sys/src/brazil/ip/ipifc.c /n/emeliedump/1999/0223/sys/src/brazil/ip/ipifc.c 211c m = snprint(state, n, "%-12s %-5d", ifc->dev, ifc->maxmtu); . ## diffname ip/ipifc.c 1999/0302 ## diff -e /n/emeliedump/1999/0223/sys/src/brazil/ip/ipifc.c /n/emeliedump/1999/0302/sys/src/brazil/ip/ipifc.c 308c qunlock(c); . 171c qunlock(ifc->conv); . 169c qlock(ifc->conv); . 141c qunlock(ifc->conv); . 139c qlock(ifc->conv); . ## diffname ip/ipifc.c 1999/0731 ## diff -e /n/emeliedump/1999/0302/sys/src/brazil/ip/ipifc.c /n/emeliedump/1999/0731/sys/src/brazil/ip/ipifc.c 1233a static void ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip) { Conv **cp, **e; Ipifc *nifc; Iplifc *lifc; uchar net[IPaddrlen]; /* register the address on any network that will proxy for us */ e = &f->ipifc->conv[f->ipifc->nc]; for(cp = f->ipifc->conv; cp < e; cp++){ if(*cp == nil) continue; nifc = (Ipifc*)(*cp)->ptcl; if(nifc->m->areg == nil) continue; if(nifc == ifc) continue; for(lifc = nifc->lifc; lifc; lifc = lifc->next){ maskip(ip, lifc->mask, net); if(ipcmp(net, lifc->remote) == 0){ (*nifc->m->areg)(nifc, ip); break; } } } } . 438a /* register the address on this network for address resolution */ if(ifc->m->areg != nil) (*ifc->m->areg)(ifc, ip); . 413a } . 412c if(type & Rptpt){ ipifcregisterproxy(f, ifc, rem); . 68a static void ipifcregisterproxy(Fs*, Ipifc*, uchar*); . ## diffname ip/ipifc.c 1999/0803 ## diff -e /n/emeliedump/1999/0731/sys/src/brazil/ip/ipifc.c /n/emeliedump/1999/0803/sys/src/brazil/ip/ipifc.c 1265a runlock(nifc); . 1262c (*m->areg)(nifc, ip); . 1258a rlock(nifc); m = nifc->m; if(m == nil || m->areg == nil){ runlock(nifc); continue; } . 1255,1256d 1246a Medium *m; . ## diffname ip/ipifc.c 1999/0909 ## diff -e /n/emeliedump/1999/0803/sys/src/brazil/ip/ipifc.c /n/emeliedump/1999/0909/sys/src/brazil/ip/ipifc.c 1091,1093c if((r->type & (Rifc|Rptpt|Rproxy)) != (Rifc|Rptpt|Rproxy)) . 413c if((type & (Rptpt|Rproxy)) == (Rptpt|Rproxy)){ . 399d 351a case 6: if(strcmp(argv[5], "proxy") == 0) type |= Rproxy; /* fall through */ . 347a type = Rifc; . ## diffname ip/ipifc.c 1999/1029 ## diff -e /n/emeliedump/1999/0909/sys/src/brazil/ip/ipifc.c /n/emeliedump/1999/1029/sys/src/brazil/ip/ipifc.c 486a l = &lifc->next; } . 478,483c /* Are we point to point */ type = 0; if(ipcmp(mask, IPallbits) == 0) type = Rptpt; /* * find address on this interface and remove from chain. * for pt to pt we actually specify the remote address at the * addresss to remove. */ l = &ifc->lifc; for(lifc = *l; lifc != nil; lifc = lifc->next) { addr = lifc->local; if(type == Rptpt) addr = lifc->remote; if(memcmp(ip, addr, IPaddrlen) == 0 && memcmp(mask, lifc->mask, IPaddrlen) == 0) { . ## diffname ip/ipifc.c 1999/1031 ## diff -e /n/emeliedump/1999/1029/sys/src/brazil/ip/ipifc.c /n/emeliedump/1999/1031/sys/src/9/ip/ipifc.c 493c if(memcmp(ip, addr, IPaddrlen) == 0) if(memcmp(mask, lifc->mask, IPaddrlen) == 0) { . 465a uchar *addr; int type; . ## diffname ip/ipifc.c 2000/0107 ## diff -e /n/emeliedump/1999/1031/sys/src/9/ip/ipifc.c /n/emeliedump/2000/0107/sys/src/9/ip/ipifc.c 598,599c if(ipcmp(ifc->lifc->mask, IPallbits) == 0) sprint(ip, "%I", ifc->lifc->remote); else sprint(ip, "%I", ifc->lifc->local); sprint(mask, "%M", ifc->lifc->mask); . 192c if(ipcmp(ifc->lifc->mask, IPallbits) == 0) sprint(ip, "%I", ifc->lifc->remote); else sprint(ip, "%I", ifc->lifc->local); . ## diffname ip/ipifc.c 2000/0126 ## diff -e /n/emeliedump/2000/0107/sys/src/9/ip/ipifc.c /n/emeliedump/2000/0126/sys/src/9/ip/ipifc.c 20c Medium *media[Maxmedia] = . 13c Maxmedia = 32, . ## diffname ip/ipifc.c 2000/0913 ## diff -e /n/emeliedump/2000/0126/sys/src/9/ip/ipifc.c /n/emeliedump/2000/0913/sys/src/9/ip/ipifc.c 665c ipifc = smalloc(sizeof(Proto)); . ## diffname ip/ipifc.c 2000/1111 ## diff -e /n/emeliedump/2000/0913/sys/src/9/ip/ipifc.c /n/emeliedump/2000/1111/sys/src/9/ip/ipifc.c 633,634d ## diffname ip/ipifc.c 2000/1220 ## diff -e /n/emeliedump/2000/1111/sys/src/9/ip/ipifc.c /n/emeliedump/2000/1220/sys/src/9/ip/ipifc.c 312d 172,173d 169,170c if(ifc->m != nil && ifc->m->unbindonclose == 0) . 153a * called with ifc->conv closed . 142,143d 139,140c if(ifc->m->unbindonclose == 0) . 102c * called with c locked . ## diffname ip/ipifc.c 2001/0306 ## diff -e /n/emeliedump/2000/1220/sys/src/9/ip/ipifc.c /n/emeliedump/2001/0306/sys/src/9/ip/ipifc.c 260c ipifckick(Conv *c) . ## diffname ip/ipifc.c 2001/0710 ## diff -e /n/emeliedump/2001/0306/sys/src/9/ip/ipifc.c /n/emeliedump/2001/0710/sys/src/9/ip/ipifc.c 504a ifc->ifcid++; . 410c v6addroute(f, tifc, rem, mask, rem, type); . 408c v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type); . ## diffname ip/ipifc.c 2001/1117 ## diff -e /n/emeliedump/2001/0710/sys/src/9/ip/ipifc.c /n/emeliedump/2001/1117/sys/src/9/ip/ipifc.c 639c else if(strcmp(argv[0], "reassemble") == 0){ ifc->reassemble = 1; return nil; } else if(strcmp(argv[0], "iprouting") == 0){ . 290a ifc->reassemble = 0; . 175a ifc->reassemble = 0; . ## diffname ip/ipifc.c 2002/0221 ## diff -e /n/emeliedump/2001/1117/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0221/sys/src/9/ip/ipifc.c 909d 902,907c nifc = 0; for(link = p->link; link; link = link->selflink) nifc++; routetype(p->type, state); m += snprint(cp + m, n - m, stformat, p->a, nifc, state); if(off > 0){ off -= m; m = 0; . 898a off = offset; . 893c int i, m, nifc, off; . 885,888d ## diffname ip/ipifc.c 2002/0507 ## diff -e /n/emeliedump/2002/0221/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0507/sys/src/9/ip/ipifc.c 1293a if(found==0) { if(routerlt <= 0) return nil; else if((force) && (j<0)) { j = f->v6p->cdrouter; f->v6p->cdrouter = -1; } } // assert((found && (j>=0))||(!found && routerlt>0)); if(routerlt > 0) { memset(&r[j], 0, sizeof(v6router)); r[j].inuse = 1; r[j].ifc = ifc; r[j].ifcid = ifc->ifcid; ipmove(r[j].routeraddr, routeraddr); r[j].ltorigin = msec / 10^3; r[j].rp.mflag = (mflag!=0); r[j].rp.oflag = (oflag!=0); r[j].rp.rxmitra = rxmitra; r[j].rp.reachtime = reachtime; r[j].rp.routerlt = routerlt; r[j].rp.ttl = ttl; if((f->v6p->cdrouter < 0) || (force==1)) { f->v6p->cdrouter = j; adddefroute6(f, routeraddr, force); } } else if(j >= 0) { // remove router r[j].inuse = 0; if(f->v6p->cdrouter==j) { f->v6p->cdrouter = -1; v6delroute(f, v6Unspecified, v6Unspecified, 1); for(i=0; iv6p->cdrouter = i; adddefroute6(f, r[i].routeraddr, 1); break; } } } } return nil; } char* ipifcaddpref6(Ipifc *ifc, char**argv, int argc) { uchar onlink = 1; uchar autoflag = 1; long validlt = 0xffffffff; long preflt = 0xffffffff; long origint = msec / 10^3; uchar prefix[IPaddrlen]; int plen = 64; Iplifc *lifc; char addr[40]; char *params[3]; switch(argc) { case 7: preflt = atoi(argv[6]); /* fall through */ case 6: validlt = atoi(argv[5]); /* fall through */ case 5: autoflag = atoi(argv[4]); /* fall through */ case 4: onlink = atoi(argv[3]); /* fall through */ case 3: plen = atoi(argv[2]); case 2: break; default: return Ebadarg; } if((parseip(prefix, argv[1])!=6) || (validlt < preflt) || (plen > 64) || (islinklocal(prefix)) ) return Ebadarg; lifc = smalloc(sizeof(Iplifc)); lifc->onlink = (onlink!=0); lifc->autoflag = (autoflag!=0); lifc->validlt = validlt; lifc->preflt = preflt; lifc->origint = origint; if(ifc->m->pref2addr!=nil) ifc->m->pref2addr(prefix, ifc->mac); else return Ebadarg; sprint(addr, "%I", prefix); params[0] = "add"; params[1] = addr; params[2] = "/64"; return ipifcadd(ifc, params, 3, 0, lifc); } static char *gateformat = "%-1.1s %-40.40I %20ld %10d %-40.40s\n"; enum { Ngateformat= 116, }; static char *rtrstat[] = { [0] "*", [1] "-", }; /* line corresponding to current default router, if in f->v6p->v6rlist, starts with a "*", others with a "-". */ long ipgateread6(Fs *f, char *cp, ulong offset, int n) { v6router *r = f->v6p->v6rlist; int i, j, k, l; long m; if(offset % Ngateformat) return 0; offset = offset/Ngateformat; n = n/Ngateformat; i = f->v6p->cdrouter; k = i; if((i<0)||(i>2)) i = 0; m = 0; for(j = 0; (n > 0) && (j < Ngates) ; j++){ if(offset > 0){ offset--; i = (i+1) % Ngates; continue; } n--; if(r[i].inuse) { l = (i==k) ? 0 : 1; m += sprint(cp + m, gateformat, rtrstat[l], r[i].routeraddr, r[i].ltorigin, r[i].rp.routerlt, r[i].ifc->dev); } i = (i+1) % Ngates; } return m; . 1292c else { j = i; } . 1285,1288c return; } else { // V4 for(cp = f->ipifc->conv; cp < e; cp++){ if(*cp == nil) continue; nifc = (Ipifc*)(*cp)->ptcl; if(nifc == ifc) continue; rlock(nifc); m = nifc->m; 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); } } } // added for new v6 mesg types static void adddefroute6(Fs *f, uchar *gate, int force) { Route *r; r = v6lookup(f, v6Unspecified); if(r!=nil) if(!(force) && (strcmp(r->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); } enum { Ngates = 3, }; char* ipifcaddgate6(Fs *f, Ipifc *ifc, char**argv, int argc) { v6router *r = f->v6p->v6rlist; uchar routeraddr[IPaddrlen]; int mflag = f->v6p->rp.mflag; int oflag = f->v6p->rp.oflag; int reachtime = f->v6p->rp.reachtime; int rxmitra = f->v6p->rp.rxmitra; int ttl = MAXTTL; int routerlt = f->v6p->rp.routerlt; int force; // force == 1 forces argv[1] to // be the default router. int i, j; int found = 0; if((argc<3)||(argc>9)) return Ebadarg; if( (parseip(routeraddr, argv[1])!=6) || !(islinklocal(routeraddr)) ) return Ebadarg; force = (atoi(argv[2])!=0); switch(argc){ case 9: rxmitra = atoi(argv[8]); /* fall through */ case 8: reachtime = atoi(argv[7]); /* fall through */ case 7: routerlt = atoi(argv[6]); /* fall through */ case 6: oflag = atoi(argv[5]); /* fall through */ case 5: mflag = atoi(argv[4]); /* fall through */ case 4: ttl = atoi(argv[3]); /* fall through */ } if((force) && (routerlt < 0)) return Ebadarg; if((ttl < 0) || (255 < ttl)) return Ebadarg; j = -1; for(i=0; iipifc->conv; cp < e; cp++){ if(*cp == nil) continue; nifc = (Ipifc*)(*cp)->ptcl; if(nifc == ifc) continue; rlock(nifc); m = nifc->m; 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 address */ ipv62smcast(net, ip); addselfcache(f, nifc, lifc, net, Rmulti); arpenter(f, V6, ip, nifc->mac, 6, 0); //(*m->addmulti)(nifc, net, ip); break; } } . 1272,1277d 1075a if(!isv4(lifc->local) && !(lifc->tentative)){ ipmove(addr, lifc->local); return 1; } } return 0; } int ipv6anylocal(Ipifc *ifc, uchar *addr) { Iplifc *lifc; for(lifc = ifc->lifc; lifc; lifc = lifc->next){ . 1045a . 1044c if(version == 4) findprimaryip(f, local); else findprimaryip6(f, local); . 1041a else { 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; } . 1035,1039c if(version == 4) { 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; } . 1032a ipmove(local, v6Unspecified); } . 1031c else { . 1025a version = (memcmp(remote, v4prefix, IPv4off) == 0) ? 4 : 6; . 1023a USED(atype); USED(atypel); . 1022a int version; int atype = unspecifiedv6, atypel = unknownv6; . 989c * returns first ip address configured . 987a enum { unknownv6, multicastv6, unspecifiedv6, linklocalv6, sitelocalv6, globalv6, }; int v6addrtype(uchar *addr) { if(isv6global(addr)) return globalv6; if(islinklocal(addr)) return linklocalv6; if(isv6mcast(addr)) return multicastv6; if(issitelocal(addr)) return sitelocalv6; return unknownv6; } #define v6addrcurr(lifc) (( (lifc)->origint + (lifc)->preflt >= (msec/10^3) ) || ( (lifc)->preflt == 0xffffffff )) void findprimaryip6(Fs *f, uchar *local) { Conv **cp, **e; Ipifc *ifc; Iplifc *lifc; int atype, atypel; ipmove(local, v6Unspecified); atype = unspecifiedv6; /* find "best" (global > sitelocal > 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) if(v6addrcurr(lifc)) { ipmove(local, lifc->local); atype = atypel; if(atype == globalv6) return; } } } } . 960a . 959a . 953c x = nil; memset(xmask, 0, IPaddrlen); . 914a p = f->self->hash[hashipa(addr)]; for(; p; p = p->next){ if(ipcmp(addr, p->a) == 0) { return p->link->lifc->tentative; } } return 0; } . 913a int iptentative(Fs *f, uchar *addr) { Ipself *p; . 884a enum { Nstformat= 41, }; . 650a else if(strcmp(argv[0], "gate6") == 0) return ipifcaddgate6(c->p->f, ifc, argv, argc); else if(strcmp(argv[0], "addpref6") == 0) return ipifcaddpref6(ifc, argv, argc); else if(strcmp(argv[0], "setpar6") == 0) return ipifcsetpar6(ifc, argv, argc); else if(strcmp(argv[0], "sendra6") == 0) return ipifcsendra6(ifc, argv, argc); else if(strcmp(argv[0], "recvra6") == 0) return ipifcrecvra6(ifc, argv, argc); . 644c } else if(strcmp(argv[0], "iprouting") == 0){ . 630c return ipifcadd(ifc, argv, argc, 0, nil); else if(strcmp(argv[0], "try") == 0) return ipifcadd(ifc, argv, argc, 1, nil); . 617a char* ipifcsetpar6(Ipifc *ifc, char **argv, int argc) { int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint; argsleft = argc - 1; i = 1; if(argsleft % 2 != 0) return Ebadarg; while (argsleft > 1) { if(strcmp(argv[i],"recvra")==0) ifc->recvra6 = (atoi(argv[i+1]) != 0); else if(strcmp(argv[i],"sendra")==0) ifc->sendra6 = (atoi(argv[i+1]) != 0); else if(strcmp(argv[i],"mflag")==0) ifc->rp.mflag = (atoi(argv[i+1]) != 0); else if(strcmp(argv[i],"oflag")==0) ifc->rp.oflag = (atoi(argv[i+1]) != 0); else if(strcmp(argv[i],"maxraint")==0) ifc->rp.maxraint = atoi(argv[i+1]); else if(strcmp(argv[i],"minraint")==0) ifc->rp.minraint = atoi(argv[i+1]); else if(strcmp(argv[i],"linkmtu")==0) ifc->rp.linkmtu = atoi(argv[i+1]); else if(strcmp(argv[i],"reachtime")==0) ifc->rp.reachtime = atoi(argv[i+1]); else if(strcmp(argv[i],"rxmitra")==0) ifc->rp.rxmitra = atoi(argv[i+1]); else if(strcmp(argv[i],"ttl")==0) ifc->rp.ttl = atoi(argv[i+1]); else if(strcmp(argv[i],"routerlt")==0) ifc->rp.routerlt = atoi(argv[i+1]); else return Ebadarg; argsleft -= 2; i += 2; } // consistency check if(ifc->rp.maxraint < ifc->rp.minraint) { ifc->rp.maxraint = vmax; ifc->rp.minraint = vmin; return Ebadarg; } return nil; } char* ipifcsendra6(Ipifc *ifc, char **argv, int argc) { int i; i = 0; if(argc > 1) i = atoi(argv[1]); ifc->sendra6 = (i!=0); return nil; } char* ipifcrecvra6(Ipifc *ifc, char **argv, int argc) { int i; i = 0; if(argc > 1) i = atoi(argv[1]); ifc->recvra6 = (i!=0); return nil; } . 609c err = ipifcadd(ifc, argv, argc, 0, nil); . 528c * distribute routes to active interfaces like the . 518a if(ipcmp(ip, v6loopback) == 0) /* remove route for all node multicast */ v6delroute(f, v6allnodesN, v6allnodesNmask, 1); else if(memcmp(ip, v6linklocal, v6linklocalprefix) == 0) /* remove route for all link multicast */ v6delroute(f, v6allnodesL, v6allnodesLmask, 1); } . 517c else { . 508,509d 450a if(tentative && sendnbrdisc) icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac); . 446c if(isv4(ip) && ifc->m->areg != nil) . 444a else if(memcmp(ip, v6linklocal, v6linklocalprefix) == 0) { /* add link-local mcast address */ addselfcache(f, ifc, lifc, v6allnodesL, Rmulti); /* add route for all link multicast */ v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL, Rmulti); /* add solicited-node multicast address */ ipv62smcast(bcast, ip); addselfcache(f, ifc, lifc, bcast, Rmulti); } sendnbrdisc = 1; } . 443c /* add route for all node multicast */ v6addroute(f, tifc, v6allnodesN, v6allnodesNmask, v6allnodesN, Rmulti); } . 437,441c /* 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); . 431,435c /* 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); . 426,429c /* 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); . 421,424c 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); . 408a /* add local routes */ . 402c /* check for point-to-point interface */ if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */ . 397a . 396a lifc->tentative = tentative; if(lifcp != nil) { 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 = 1; lifc->autoflag = 1; lifc->validlt = 0xffffffff; lifc->preflt = 0xffffffff; lifc->origint = msec / 10^3; } . 389a } } . 387,388c for(lifc = ifc->lifc; lifc; lifc = lifc->next) { if(ipcmp(lifc->local, ip) == 0) { if(lifc->tentative != tentative) lifc->tentative = tentative; if(lifcp != nil) { lifc->onlink = lifcp->onlink; lifc->autoflag = lifcp->autoflag; lifc->validlt = lifcp->validlt; lifc->preflt = lifcp->preflt; lifc->origint = lifcp->origint; } . 383c if(isv4(ip)) tentative = 0; . 340a int sendnbrdisc = 0; . 334c ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) . 241c m += snprint(state+m, n - m, " %-40.40I", link->self->a); . 239c m += snprint(state+m, n - m, "%-40.40I ->", lifc->local); . 215,218c m += snprint(state+m, n - m, slineformat, lifc->local, lifc->mask, lifc->remote, lifc->validlt, lifc->preflt); . 211c m = snprint(state, n, sfixedformat, ifc->dev, ifc->maxmtu, ifc->sendra6, ifc->recvra6, ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint, ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime, ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt, ifc->in, ifc->out, ifc->inerr, ifc->outerr); . 201a char *sfixedformat = "device %-12s maxmtu %-5d sendra %-1d recvra %-1d mflag %-1d oflag %-1d maxraint %-10d minraint %-10d linkmtu %-10d reachtime %-10d rxmitra %-10d ttl %-10d routerlt %-10d pktin %-7lud pktout %-7lud errin %-7lud errout %-7lud\n"; char *slineformat = " %-40.40I %-10.10M %-40.40I %-12lud %-12lud\n"; . 140a ifc->rp.mflag = 0; // default not managed ifc->rp.oflag = 0; ifc->rp.maxraint = 600000; // millisecs ifc->rp.minraint = 200000; ifc->rp.linkmtu = 0; // no mtu sent ifc->rp.reachtime = 0; ifc->rp.rxmitra = 0; ifc->rp.ttl = MAXTTL; ifc->rp.routerlt = 3*(ifc->rp.maxraint); . 8a #include "ipv6.h" . ## diffname ip/ipifc.c 2002/0517 ## diff -e /n/emeliedump/2002/0507/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0517/sys/src/9/ip/ipifc.c 218c char slineformat[] = " %-40.40I %-10.10M %-40.40I %-12lud %-12lud\n"; . 216c char sfixedformat[] = "device %s maxmtu %d sendra %d recvra %d mflag %d oflag %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt %d pktin %lud pktout %lud errin %lud errout %lud\n"; . ## diffname ip/ipifc.c 2002/0601 ## diff -e /n/emeliedump/2002/0517/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0601/sys/src/9/ip/ipifc.c 1324c break; default: panic("findlocalip2: version %d", version); } . 1322c break; case V6: . 1320c switch(version){ case V4: . 1316a break; default: panic("findlocalip: version %d", version); . 1301,1302c break; case V6: . 1293c switch(version) { case V4: . 1281c version = (memcmp(remote, v4prefix, IPv4off) == 0) ? V4 : V6; . ## diffname ip/ipifc.c 2002/0615 ## diff -e /n/emeliedump/2002/0601/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0615/sys/src/9/ip/ipifc.c 586a print("ipifcrem: wrong address\n"); . 576,577c if (memcmp(ip, addr, IPaddrlen) == 0 && memcmp(mask, lifc->mask, IPaddrlen) == 0) { . 205c if (err = ipifcrem(ifc, av, 3, 0)) print("ipifcunbind, addr %s, mask %s: %s\n", ip, mask, err); . 170a char *err; . ## diffname ip/ipifc.c 2002/0710 ## diff -e /n/emeliedump/2002/0615/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0710/sys/src/9/ip/ipifc.c 1772c long origint = NOW / 10^3; . 1735c r[j].ltorigin = NOW / 10^3; . 1208c #define v6addrcurr(lifc) (( (lifc)->origint + (lifc)->preflt >= (NOW/10^3) ) || ( (lifc)->preflt == 0xffffffff )) . 962c ulong now = NOW; . 943c ulong now = NOW; . 448c lifc->origint = NOW / 10^3; . ## diffname ip/ipifc.c 2002/0712 ## diff -e /n/emeliedump/2002/0710/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0712/sys/src/9/ip/ipifc.c 844d 287a Conv *c = x; . 286c ipifckick(void *x) . ## diffname ip/ipifc.c 2002/0717 ## diff -e /n/emeliedump/2002/0712/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0717/sys/src/9/ip/ipifc.c 313c c->wq = qopen(QMAX, Qkick, ipifckick, c); . ## diffname ip/ipifc.c 2002/1110 ## diff -e /n/emeliedump/2002/0717/sys/src/9/ip/ipifc.c /n/emeliedump/2002/1110/sys/src/9/ip/ipifc.c 312a c->sq = qopen(2*QMAX, 0, 0, 0); . 304,305c * called when a new ipifc structure is created . 191,193c /* close queues to stop queuing of packets */ qclose(ifc->conv->rq); qclose(ifc->conv->wq); qclose(ifc->conv->sq); . 154a /* reopen all the queues closed by a previous unbind */ qreopen(c->rq); qreopen(c->eq); qreopen(c->sq); . 152a /* any ancillary structures (like routes) no longer pertain */ . 151c ifc->rp.routerlt = 3*(ifc->rp.maxraint); . 142d 136a /* set up parameters */ . 131a /* set the bound device name */ . 130a /* do medium specific binding */ . ## diffname ip/ipifc.c 2002/1112 ## diff -e /n/emeliedump/2002/1110/sys/src/9/ip/ipifc.c /n/emeliedump/2002/1112/sys/src/9/ip/ipifc.c 582c * for pt to pt we actually specify the remote address as the . ## diffname ip/ipifc.c 2003/0209 ## diff -e /n/emeliedump/2002/1112/sys/src/9/ip/ipifc.c /n/emeliedump/2003/0209/sys/src/9/ip/ipifc.c 396,397c if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu) ifc->maxtu = mtu; . 363c ifc->maxtu = mtu; . 361c if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu) . 244c ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6, . 229c char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt %d pktin %lud pktout %lud errin %lud errout %lud\n"; . 143,144c ifc->mintu = ifc->m->mintu; ifc->maxtu = ifc->m->maxtu; . ## diffname ip/ipifc.c 2003/0308 ## diff -e /n/emeliedump/2003/0209/sys/src/9/ip/ipifc.c /n/emeliedump/2003/0308/sys/src/9/ip/ipifc.c 1651c r = v6lookup(f, v6Unspecified, nil); . 1427c r = v6lookup(f, ip, nil); . 1294c r = v6lookup(f, remote, nil); . ## diffname ip/ipifc.c 2003/0318 ## diff -e /n/emeliedump/2003/0308/sys/src/9/ip/ipifc.c /n/emeliedump/2003/0318/sys/src/9/ip/ipifc.c 311a runlock(ifc); . 307a if(!canrlock(ifc)){ freeb(bp); return; } if(waserror()){ runlock(ifc); nexterror(); } . ## diffname ip/ipifc.c 2003/0322 ## diff -e /n/emeliedump/2003/0318/sys/src/9/ip/ipifc.c /n/emeliedump/2003/0322/sys/src/9/ip/ipifc.c 320a poperror(); .