📄 ipifc.c
字号:
v6delroute(f, v6allnodesN, v6allnodesNmask, 1); else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0) /* remove route for all link multicast */ v6delroute(f, v6allnodesL, v6allnodesLmask, 1); } free(lifc); return nil;}/* * remove an address from an interface. * called with c->car locked */char*ipifcrem(Ipifc *ifc, char **argv, int argc){ uchar ip[IPaddrlen]; uchar mask[IPaddrlen]; uchar rem[IPaddrlen]; Iplifc *lifc; char *rv; if(argc < 3) return Ebadarg; parseip(ip, argv[1]); parseipmask(mask, argv[2]); if(argc < 4) maskip(ip, mask, rem); else parseip(rem, argv[3]); wlock(ifc); /* * find address on this interface and remove from chain. * for pt to pt we actually specify the remote address as the * addresss to remove. */ for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) { if (memcmp(ip, lifc->local, IPaddrlen) == 0 && memcmp(mask, lifc->mask, IPaddrlen) == 0 && memcmp(rem, lifc->remote, IPaddrlen) == 0) break; } rv = ipifcremlifc(ifc, lifc); wunlock(ifc); return rv;}/* * distribute routes to active interfaces like the * TRIP linecards */voidipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type){ Medium *m; Conv **cp, **e; Ipifc *ifc; e = &f->ipifc->conv[f->ipifc->nc]; for(cp = f->ipifc->conv; cp < e; cp++){ if(*cp != nil) { ifc = (Ipifc*)(*cp)->ptcl; m = ifc->m; if(m == nil) continue; if(m->addroute != nil) m->addroute(ifc, vers, addr, mask, gate, type); } }}voidipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask){ Medium *m; Conv **cp, **e; Ipifc *ifc; e = &f->ipifc->conv[f->ipifc->nc]; for(cp = f->ipifc->conv; cp < e; cp++){ if(*cp != nil) { ifc = (Ipifc*)(*cp)->ptcl; m = ifc->m; if(m == nil) continue; 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; ifc = (Ipifc*)c->ptcl; if(ifc->m == nil) return "ipifc not yet bound to device"; if(waserror()){ wunlock(ifc); nexterror(); } wlock(ifc); while(ifc->lifc){ err = ipifcremlifc(ifc, ifc->lifc); if(err) error(err); } wunlock(ifc); poperror(); err = ipifcadd(ifc, argv, argc, 0, nil); if(err) return err; Fsconnected(c, nil); return nil;}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;}/* * non-standard control messages. * called with c->car locked. */static char*ipifcctl(Conv* c, char**argv, int argc){ Ipifc *ifc; int i; ifc = (Ipifc*)c->ptcl; if(strcmp(argv[0], "add") == 0) return ipifcadd(ifc, argv, argc, 0, nil); else if(strcmp(argv[0], "try") == 0) return ipifcadd(ifc, argv, argc, 1, nil); else if(strcmp(argv[0], "remove") == 0) return ipifcrem(ifc, argv, argc); 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); else if(strcmp(argv[0], "mtu") == 0) return ipifcsetmtu(ifc, argv, argc); else if(strcmp(argv[0], "reassemble") == 0){ ifc->reassemble = 1; return nil; } else if(strcmp(argv[0], "iprouting") == 0){ i = 1; if(argc > 1) i = atoi(argv[1]); iprouting(c->p->f, i); return nil; } 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); return "unsupported ctl";}intipifcstats(Proto *ipifc, char *buf, int len){ return ipstats(ipifc->f, buf, len);}voidipifcinit(Fs *f){ Proto *ipifc; ipifc = smalloc(sizeof(Proto)); ipifc->name = "ipifc"; 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);}/* * add to self routing cache * called with c->car locked */static voidaddselfcache(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);}/* * 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 f->self locked */static Iplink *freeiplink;static Ipself *freeipself;static voidiplinkfree(Iplink *p){ Iplink **l, *np; ulong now = NOW; 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 voidipselffree(Ipself *p){ Ipself **l, *np; ulong now = NOW; 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 voidremselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a){ Ipself *p, **l; Iplink *link, **l_self, **l_lifc; qlock(f->self); /* find the unique selftab entry */ l = &f->self->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 */ l_lifc = &lifc->link; for(link = *l_lifc; link; link = *l_lifc){ if(link->self == p) break; l_lifc = &link->lifclink; } if(link == nil) goto out; /* * walk down the links from the selftab looking for * the one we just found */ l_self = &p->link; for(link = *l_self; link; link = *l_self){ if(link == *(l_lifc)) break; l_self = &link->selflink; } if(link == nil) panic("remselfcache"); if(--(link->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 */ *l_lifc = link->lifclink; *l_self = link->selflink; iplinkfree(link); if(p->link != nil) goto out; /* remove from routing table */ if(isv4(a)) v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1); else v6delroute(f, a, IPallbits, 1); /* 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) f->self->acceptall = 0;out: qunlock(f->self);}static char *stformat = "%-44.44I %2.2d %4.4s\n";enum{ Nstformat= 41,};longipselftabread(Fs *f, char *cp, ulong offset, int n){ int i, m, nifc, off; Ipself *p; Iplink *link; char state[8]; m = 0; off = offset; qlock(f->self); for(i = 0; i < NHASH && m < n; i++){ for(p = f->self->hash[i]; p != nil && m < n; p = p->next){ 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; } } } qunlock(f->self); return m;}intiptentative(Fs *f, uchar *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;}/* * returns * 0 - no match * Runi * Rbcast * Rmcast */intipforme(Fs *f, uchar *addr){ Ipself *p; p = f->self->hash[hashipa(addr)]; for(; p; p = p->next){ if(ipcmp(addr, p->a) == 0) return p->type; } /* hack to say accept anything */ if(f->self->acceptall) return Runi; return 0;}/* * find the ifc on same net as the remote system. If none, * return nil. */Ipifc*findipifc(Fs *f, uchar *remote, int type){ Ipifc *ifc, *x; Iplifc *lifc; Conv **cp, **e; uchar gnet[IPaddrlen]; uchar xmask[IPaddrlen];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -