/* * 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); }
long sysrfork(ulong *arg) { Proc *p; int n, i; Fgrp *ofg; Pgrp *opg; Rgrp *org; Egrp *oeg; ulong pid, flag; Mach *wm; flag = arg[0]; /* Check flags before we commit */ if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG)) error(Ebadarg); if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG)) error(Ebadarg); if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG)) error(Ebadarg); if((flag&RFPROC) == 0) { if(flag & (RFMEM|RFNOWAIT)) error(Ebadarg); if(flag & (RFFDG|RFCFDG)) { ofg = up->fgrp; if(flag & RFFDG) up->fgrp = dupfgrp(ofg); else up->fgrp = dupfgrp(nil); closefgrp(ofg); } if(flag & (RFNAMEG|RFCNAMEG)) { opg = up->pgrp; up->pgrp = newpgrp(); if(flag & RFNAMEG) pgrpcpy(up->pgrp, opg); /* inherit noattach */ up->pgrp->noattach = opg->noattach; closepgrp(opg); } if(flag & RFNOMNT) up->pgrp->noattach = 1; if(flag & RFREND) { org = up->rgrp; up->rgrp = newrgrp(); closergrp(org); } if(flag & (RFENVG|RFCENVG)) { oeg = up->egrp; up->egrp = smalloc(sizeof(Egrp)); up->egrp->ref = 1; if(flag & RFENVG) envcpy(up->egrp, oeg); closeegrp(oeg); } if(flag & RFNOTEG) up->noteid = incref(¬eidalloc); return 0; } p = newproc(); p->fpsave = up->fpsave; p->scallnr = up->scallnr; p->s = up->s; p->nerrlab = 0; p->slash = up->slash; p->dot = up->dot; incref(p->dot); memmove(p->note, up->note, sizeof(p->note)); p->privatemem = up->privatemem; p->noswap = up->noswap; p->nnote = up->nnote; p->notified = 0; p->lastnote = up->lastnote; p->notify = up->notify; p->ureg = up->ureg; p->dbgreg = 0; /* Make a new set of memory segments */ n = flag & RFMEM; qlock(&p->seglock); if(waserror()){ qunlock(&p->seglock); nexterror(); } for(i = 0; i < NSEG; i++) if(up->seg[i]) p->seg[i] = dupseg(up->seg, i, n); qunlock(&p->seglock); poperror(); /* File descriptors */ if(flag & (RFFDG|RFCFDG)) { if(flag & RFFDG) p->fgrp = dupfgrp(up->fgrp); else p->fgrp = dupfgrp(nil); } else { p->fgrp = up->fgrp; incref(p->fgrp); } /* Process groups */ if(flag & (RFNAMEG|RFCNAMEG)) { p->pgrp = newpgrp(); if(flag & RFNAMEG) pgrpcpy(p->pgrp, up->pgrp); /* inherit noattach */ p->pgrp->noattach = up->pgrp->noattach; } else { p->pgrp = up->pgrp; incref(p->pgrp); } if(flag & RFNOMNT) up->pgrp->noattach = 1; if(flag & RFREND) p->rgrp = newrgrp(); else { incref(up->rgrp); p->rgrp = up->rgrp; } /* Environment group */ if(flag & (RFENVG|RFCENVG)) { p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; if(flag & RFENVG) envcpy(p->egrp, up->egrp); } else { p->egrp = up->egrp; incref(p->egrp); } p->hang = up->hang; p->procmode = up->procmode; /* Craft a return frame which will cause the child to pop out of * the scheduler in user mode with the return register zero */ forkchild(p, up->dbgreg); p->parent = up; p->parentpid = up->pid; if(flag&RFNOWAIT) p->parentpid = 0; else { lock(&up->exl); up->nchild++; unlock(&up->exl); } if((flag&RFNOTEG) == 0) p->noteid = up->noteid; /* don't penalize the child, it hasn't done FP in a note handler. */ p->fpstate = up->fpstate & ~FPillegal; pid = p->pid; memset(p->time, 0, sizeof(p->time)); p->time[TReal] = MACHP(0)->ticks; kstrdup(&p->text, up->text); kstrdup(&p->user, up->user); /* * since the bss/data segments are now shareable, * any mmu info about this process is now stale * (i.e. has bad properties) and has to be discarded. */ flushmmu(); p->basepri = up->basepri; p->priority = up->basepri; p->fixedpri = up->fixedpri; p->mp = up->mp; wm = up->wired; if(wm) procwired(p, wm->machno); ready(p); sched(); return pid; }
Packet* _vtrpc(VtConn *z, Packet *p, VtFcall *tx) { int i; uchar tag, buf[2], *top; Rwait *r, *rr; if(z == nil){ werrstr("not connected"); packetfree(p); return nil; } /* must malloc because stack could be private */ r = vtmallocz(sizeof(Rwait)); qlock(&z->lk); r->r.l = &z->lk; tag = gettag(z, r); if(tx){ /* vtfcallrpc can't print packet because it doesn't have tag */ tx->tag = tag; if(chattyventi) fprint(2, "%s -> %F\n", argv0, tx); } /* slam tag into packet */ top = packetpeek(p, buf, 0, 2); if(top == nil){ packetfree(p); return nil; } if(top == buf){ werrstr("first two bytes must be in same packet fragment"); packetfree(p); vtfree(r); return nil; } top[1] = tag; qunlock(&z->lk); if(vtsend(z, p) < 0){ vtfree(r); return nil; } qlock(&z->lk); /* wait for the muxer to give us our packet */ r->sleeping = 1; z->nsleep++; while(z->muxer && !r->done) rsleep(&r->r); z->nsleep--; r->sleeping = 0; /* if not done, there's no muxer: start muxing */ if(!r->done){ if(z->muxer) abort(); z->muxer = 1; while(!r->done){ qunlock(&z->lk); if((p = vtrecv(z)) == nil){ werrstr("unexpected eof on venti connection"); z->muxer = 0; vtfree(r); return nil; } qlock(&z->lk); muxrpc(z, p); } z->muxer = 0; /* if there is anyone else sleeping, wake first unfinished to mux */ if(z->nsleep) for(i=0; i<256; i++){ rr = z->wait[i]; if(rr && rr->sleeping && !rr->done){ rwakeup(&rr->r); break; } } } p = r->p; puttag(z, r, tag); vtfree(r); qunlock(&z->lk); return p; }
static Xfid* fsysread(Xfid *x, Fid *f) { Fcall t; uchar *b; int i, id, n, o, e, j, k, *ids, nids; Dirtab *d, dt; Column *c; uint clock, len; char buf[16]; if(f->qid.type & QTDIR){ if(FILE(f->qid) == Qacme){ /* empty dir */ t.data = nil; t.count = 0; respond(x, &t, nil); return x; } o = x->offset; e = x->offset+x->count; clock = getclock(); b = emalloc(messagesize); id = WIN(f->qid); n = 0; if(id > 0) d = dirtabw; else d = dirtab; d++; /* first entry is '.' */ for(i=0; d->name!=nil && i<e; i+=len){ len = dostat(WIN(x->f->qid), d, b+n, x->count-n, clock); if(len <= BIT16SZ) break; if(i >= o) n += len; d++; } if(id == 0){ qlock(&row); nids = 0; ids = nil; for(j=0; j<row.ncol; j++){ c = row.col[j]; for(k=0; k<c->nw; k++){ ids = erealloc(ids, (nids+1)*sizeof(int)); ids[nids++] = c->w[k]->id; } } qunlock(&row); qsort(ids, nids, sizeof ids[0], idcmp); j = 0; dt.name = buf; for(; j<nids && i<e; i+=len){ k = ids[j]; sprint(dt.name, "%d", k); dt.qid = QID(k, Qdir); dt.type = QTDIR; dt.perm = DMDIR|0700; len = dostat(k, &dt, b+n, x->count-n, clock); if(len == 0) break; if(i >= o) n += len; j++; } free(ids); } t.data = (char*)b; t.count = n; respond(x, &t, nil); free(b); return x; } sendp(x->c, xfidread); return nil; }
long consread(Chan *c, void *va, long count, vlong offset) { int i, n, ch, eol; Pointer m; char *p, buf[64]; if(c->qid.type & QTDIR) return devdirread(c, va, count, contab, nelem(contab), devgen); switch((ulong)c->qid.path) { default: error(Egreg); case Qsysctl: return readstr(offset, va, count, VERSION); case Qsysname: if(ossysname == nil) return 0; return readstr(offset, va, count, ossysname); case Qrandom: return randomread(va, count); case Qnotquiterandom: pseudoRandomBytes(va, count); return count; case Qpin: p = "pin set"; if(up->env->pgrp->pin == Nopin) p = "no pin"; return readstr(offset, va, count, p); case Qhostowner: return readstr(offset, va, count, eve); case Qhoststdin: return read(0, va, count); /* should be pread */ case Quser: return readstr(offset, va, count, up->env->user); case Qjit: snprint(buf, sizeof(buf), "%d", cflag); return readstr(offset, va, count, buf); case Qtime: snprint(buf, sizeof(buf), "%.lld", timeoffset + osusectime()); return readstr(offset, va, count, buf); case Qdrivers: p = malloc(READSTR); if(p == nil) error(Enomem); n = 0; for(i = 0; devtab[i] != nil; i++) n += snprint(p+n, READSTR-n, "#%C %s\n", devtab[i]->dc, devtab[i]->name); n = readstr(offset, va, count, p); free(p); return n; case Qmemory: return poolread(va, count, offset); case Qnull: return 0; case Qmsec: return readnum(offset, va, count, osmillisec(), NUMSIZE); case Qcons: qlock(&kbd.q); if(waserror()){ qunlock(&kbd.q); nexterror(); } if(dflag) error(Enonexist); while(!qcanread(lineq)) { qread(kbdq, &kbd.line[kbd.x], 1); ch = kbd.line[kbd.x]; if(kbd.raw){ qiwrite(lineq, &kbd.line[kbd.x], 1); continue; } eol = 0; switch(ch) { case '\b': if(kbd.x) kbd.x--; break; case 0x15: kbd.x = 0; break; case '\n': case 0x04: eol = 1; default: kbd.line[kbd.x++] = ch; break; } if(kbd.x == sizeof(kbd.line) || eol){ if(ch == 0x04) kbd.x--; qwrite(lineq, kbd.line, kbd.x); kbd.x = 0; } } n = qread(lineq, va, count); qunlock(&kbd.q); poperror(); return n; case Qscancode: if(offset == 0) return readstr(0, va, count, gkscanid); else return qread(gkscanq, va, count); case Qkeyboard: return qread(gkbdq, va, count); case Qpointer: m = mouseconsume(); n = sprint(buf, "m%11d %11d %11d %11lud ", m.x, m.y, m.b, m.msec); if (count < n) n = count; memmove(va, buf, n); return n; case Qkprint: rlock(&kprintq.l); if(waserror()){ runlock(&kprintq.l); nexterror(); } n = qread(kprintq.q, va, count); poperror(); runlock(&kprintq.l); return n; case Qsnarf: if(offset == 0) { free(c->aux); c->aux = clipread(); } if(c->aux == nil) return 0; return readstr(offset, va, count, c->aux); } }
static void tcpreader(void *a) { Session *s = a; uchar *buf; int buflen = 0x1ffff + 4; buf = nbemalloc(buflen); for (;;) { int n; uchar flags; ushort length; n = readn(s->fd, buf, 4); if (n != 4) { die: free(buf); if (s->state == Connected) (*s->write)(s, nil, -1); deletesession(s); return; } flags = buf[1]; length = nhgets(buf + 2) | ((flags & 1) << 16); n = readn(s->fd, buf + 4, length); if (n != length) goto die; if (flags & 0xfe) { print("nbss: invalid flags field 0x%.2ux\n", flags); goto die; } switch (buf[0]) { case 0: /* session message */ if (s->state != Connected && s->state != Dead) { print("nbss: unexpected session message\n"); goto die; } if (s->state == Connected) { if ((*s->write)(s, buf + 4, length) != 0) { s->state = Dead; goto die; } } break; case 0x81: /* session request */ { uchar *p, *ep; Listen *l; int k; int called_found; uchar error_code; if (s->state == Connected) { print("nbss: unexpected session request\n"); goto die; } p = buf + 4; ep = p + length; k = nbnamedecode(p, p, ep, s->to); if (k == 0) { print("nbss: malformed called name in session request\n"); goto die; } p += k; k = nbnamedecode(p, p, ep, s->from); if (k == 0) { print("nbss: malformed calling name in session request\n"); goto die; } /* p += k; if (p != ep) { print("nbss: extra data at end of session request\n"); goto die; } */ called_found = 0; //print("nbss: called %B calling %B\n", s->to, s->from); qlock(&listens); for (l = listens.head; l; l = l->next) if (nbnameequal(l->to, s->to)) { called_found = 1; if (nbnameequal(l->from, s->from)) break; } if (l == nil) { qunlock(&listens); error_code = called_found ? 0x81 : 0x80; replydie: buf[0] = 0x83; buf[1] = 0; hnputs(buf + 2, 1); buf[4] = error_code; write(s->fd, buf, 5); goto die; } if (!(*l->accept)(l->magic, s, &s->write)) { qunlock(&listens); error_code = 0x83; goto replydie; } buf[0] = 0x82; buf[1] = 0; hnputs(buf + 2, 0); if (write(s->fd, buf, 4) != 4) { qunlock(&listens); goto die; } s->state = Connected; qunlock(&listens); break; } case 0x85: /* keep awake */ break; default: print("nbss: opcode 0x%.2ux unexpected\n", buf[0]); goto die; } } }
void waitthread(void *v) { Waitmsg *w; Command *c, *lc; uint pid; int found, ncmd; Rune *cmd; char *err; Text *t; Pid *pids, *p, *lastp; enum { WErr, WKill, WWait, WCmd, NWALT }; Alt alts[NWALT+1]; USED(v); threadsetname("waitthread"); pids = nil; alts[WErr].c = cerr; alts[WErr].v = &err; alts[WErr].op = CHANRCV; alts[WKill].c = ckill; alts[WKill].v = &cmd; alts[WKill].op = CHANRCV; alts[WWait].c = cwait; alts[WWait].v = &w; alts[WWait].op = CHANRCV; alts[WCmd].c = ccommand; alts[WCmd].v = &c; alts[WCmd].op = CHANRCV; alts[NWALT].op = CHANEND; command = nil; for(;;) { switch(alt(alts)) { case WErr: qlock(&row.lk); warning(nil, "%s", err); free(err); flushimage(display, 1); qunlock(&row.lk); break; case WKill: found = FALSE; ncmd = runestrlen(cmd); for(c=command; c; c=c->next) { /* -1 for blank */ if(runeeq(c->name, c->nname-1, cmd, ncmd) == TRUE) { if(postnote(PNGROUP, c->pid, "kill") < 0) warning(nil, "kill %S: %r\n", cmd); found = TRUE; } } if(!found) warning(nil, "Kill: no process %S\n", cmd); free(cmd); break; case WWait: pid = w->pid; lc = nil; for(c=command; c; c=c->next) { if(c->pid == pid) { if(lc) lc->next = c->next; else command = c->next; break; } lc = c; } qlock(&row.lk); t = &row.tag; textcommit(t, TRUE); if(c == nil) { /* helper processes use this exit status */ if(strncmp(w->msg, "libthread", 9) != 0) { p = emalloc(sizeof(Pid)); p->pid = pid; strncpy(p->msg, w->msg, sizeof(p->msg)); p->next = pids; pids = p; } } else { if(search(t, c->name, c->nname)) { textdelete(t, t->q0, t->q1, TRUE); textsetselect(t, 0, 0); } if(w->msg[0]) warning(c->md, "%.*S: exit %s\n", c->nname-1, c->name, w->msg); flushimage(display, 1); } qunlock(&row.lk); free(w); Freecmd: if(c) { if(c->iseditcmd) sendul(cedit, 0); free(c->text); free(c->name); fsysdelid(c->md); free(c); } break; case WCmd: /* has this command already exited? */ lastp = nil; for(p=pids; p!=nil; p=p->next) { if(p->pid == c->pid) { if(p->msg[0]) warning(c->md, "%s\n", p->msg); if(lastp == nil) pids = p->next; else lastp->next = p->next; free(p); goto Freecmd; } lastp = p; } c->next = command; command = c; qlock(&row.lk); t = &row.tag; textcommit(t, TRUE); textinsert(t, 0, c->name, c->nname, TRUE); textsetselect(t, 0, 0); flushimage(display, 1); qunlock(&row.lk); break; } } }
static int xgraph(HConnect *c) { char *name; Hio *hout; Memimage *m; int dotext; Graph g; Arg arg; char *graph, *a; name = hargstr(c, "arg", ""); if((arg.index = findname(name)) == -1 && strcmp(name, "*") != 0){ werrstr("unknown name %s", name); goto error; } a = hargstr(c, "arg2", ""); if(a[0] && (arg.index2 = findname(a)) == -1){ werrstr("unknown name %s", a); goto error; } g.arg = &arg; g.t0 = hargint(c, "t0", -120); g.t1 = hargint(c, "t1", 0); g.min = hargint(c, "min", -1); g.max = hargint(c, "max", -1); g.wid = hargint(c, "wid", -1); g.ht = hargint(c, "ht", -1); dotext = hargstr(c, "text", "")[0] != 0; g.fill = hargint(c, "fill", -1); graph = hargstr(c, "graph", "raw"); if(strcmp(graph, "raw") == 0) g.fn = rawgraph; else if(strcmp(graph, "diskbw") == 0) g.fn = diskgraph; else if(strcmp(graph, "iobw") == 0) g.fn = iograph; else if(strcmp(graph, "netbw") == 0) g.fn = netgraph; else if(strcmp(graph, "diff") == 0) g.fn = diffgraph; else if(strcmp(graph, "pct") == 0) g.fn = pctgraph; else if(strcmp(graph, "pctdiff") == 0) g.fn = pctdiffgraph; else if(strcmp(graph, "divdiff") == 0) g.fn = divdiffgraph; else{ werrstr("unknown graph %s", graph); goto error; } if(dotext){ hsettype(c, "text/plain"); dotextbin(&c->hout, &g); hflush(&c->hout); return 0; } m = statgraph(&g); if(m == nil) goto error; if(hsettype(c, "image/png") < 0) return -1; hout = &c->hout; writepng(hout, m); qlock(&memdrawlock); freememimage(m); qunlock(&memdrawlock); hflush(hout); return 0; error: return herror(c); }
static int chanio(Ep *ep, Hostchan *hc, int dir, int pid, void *a, int len) { Ctlr *ctlr; int nleft, n, nt, i, maxpkt, npkt; uint hcdma, hctsiz; ctlr = ep->hp->aux; maxpkt = ep->maxpkt; npkt = HOWMANY(len, ep->maxpkt); if(npkt == 0) npkt = 1; hc->hcchar = (hc->hcchar & ~Epdir) | dir; if(dir == Epin) n = ROUND(len, ep->maxpkt); else n = len; hc->hctsiz = n | npkt<<OPktcnt | pid; hc->hcdma = dmaaddr(a); nleft = len; logstart(ep); for(;;){ hcdma = hc->hcdma; hctsiz = hc->hctsiz; hc->hctsiz = hctsiz & ~Dopng; if(hc->hcchar&Chen){ dprint("ep%d.%d before chanio hcchar=%8.8ux\n", ep->dev->nb, ep->nb, hc->hcchar); hc->hcchar |= Chen | Chdis; while(hc->hcchar&Chen) ; hc->hcint = Chhltd; } if((i = hc->hcint) != 0){ dprint("ep%d.%d before chanio hcint=%8.8ux\n", ep->dev->nb, ep->nb, i); hc->hcint = i; } if(hc->hcsplt & Spltena){ qlock(&ctlr->split); sofwait(ctlr, hc - ctlr->regs->hchan); if((dwc.regs->hfnum & 1) == 0) hc->hcchar &= ~Oddfrm; else hc->hcchar |= Oddfrm; } hc->hcchar = (hc->hcchar &~ Chdis) | Chen; clog(ep, hc); if(ep->ttype == Tbulk && dir == Epin) i = chanwait(ep, ctlr, hc, /* Ack| */ Chhltd); else if(ep->ttype == Tintr && (hc->hcsplt & Spltena)) i = chanwait(ep, ctlr, hc, Chhltd); else i = chanwait(ep, ctlr, hc, Chhltd|Nak); clog(ep, hc); hc->hcint = i; if(hc->hcsplt & Spltena){ hc->hcsplt &= ~Compsplt; qunlock(&ctlr->split); } if((i & Xfercomp) == 0 && i != (Chhltd|Ack) && i != Chhltd){ if(i & Stall) error(Estalled); if(i & (Nyet|Frmovrun)) continue; if(i & Nak){ if(ep->ttype == Tintr) tsleep(&up->sleep, return0, 0, ep->pollival); else tsleep(&up->sleep, return0, 0, 1); continue; } logdump(ep); print("usbotg: ep%d.%d error intr %8.8ux\n", ep->dev->nb, ep->nb, i); if(i & ~(Chhltd|Ack)) error(Eio); if(hc->hcdma != hcdma) print("usbotg: weird hcdma %x->%x intr %x->%x\n", hcdma, hc->hcdma, i, hc->hcint); } n = hc->hcdma - hcdma; if(n == 0){ if((hc->hctsiz & Pktcnt) != (hctsiz & Pktcnt)) break; else continue; } if(dir == Epin && ep->ttype == Tbulk && n == nleft){ nt = (hctsiz & Xfersize) - (hc->hctsiz & Xfersize); if(nt != n){ if(n == ROUND(nt, 4)) n = nt; else print("usbotg: intr %8.8ux " "dma %8.8ux-%8.8ux " "hctsiz %8.8ux-%8.ux\n", i, hcdma, hc->hcdma, hctsiz, hc->hctsiz); } } if(n > nleft){ if(n != ROUND(nleft, 4)) dprint("too much: wanted %d got %d\n", len, len - nleft + n); n = nleft; } nleft -= n; if(nleft == 0 || (n % maxpkt) != 0) break; if((i & Xfercomp) && ep->ttype != Tctl) break; if(dir == Epout) dprint("too little: nleft %d hcdma %x->%x hctsiz %x->%x intr %x\n", nleft, hcdma, hc->hcdma, hctsiz, hc->hctsiz, i); } logdump(ep); return len - nleft; }
static int sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp) { Qid q; uvlong l; int i, r; SDpart *pp; SDunit *unit; SDev *sdev; switch(TYPE(c->qid)){ case Qtopdir: if(s == DEVDOTDOT){ mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR); snprint(up->genbuf, sizeof up->genbuf, "#%C", sddevtab.dc); devdir(c, q, up->genbuf, 0, eve, 0555, dp); return 1; } if(s+Qtopbase < Qunitdir) return sd1gen(c, s+Qtopbase, dp); s -= (Qunitdir-Qtopbase); qlock(&devslock); for(i=0; i<nelem(devs); i++){ if(devs[i]){ if(s < devs[i]->nunit) break; s -= devs[i]->nunit; } } if(i == nelem(devs)){ /* Run off the end of the list */ qunlock(&devslock); return -1; } if((sdev = devs[i]) == nil){ qunlock(&devslock); return 0; } incref(&sdev->r); qunlock(&devslock); if((unit = sdev->unit[s]) == nil) if((unit = sdgetunit(sdev, s)) == nil){ decref(&sdev->r); return 0; } mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR); if(emptystr(unit->user)) kstrdup(&unit->user, eve); devdir(c, q, unit->name, 0, unit->user, unit->perm, dp); decref(&sdev->r); return 1; case Qunitdir: if(s == DEVDOTDOT){ mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR); snprint(up->genbuf, sizeof up->genbuf, "#%C", sddevtab.dc); devdir(c, q, up->genbuf, 0, eve, 0555, dp); return 1; } if((sdev = sdgetdev(DEV(c->qid))) == nil){ devdir(c, c->qid, "unavailable", 0, eve, 0, dp); return 1; } unit = sdev->unit[UNIT(c->qid)]; qlock(&unit->ctl); /* * Check for media change. * If one has already been detected, sectors will be zero. * If there is one waiting to be detected, online * will return > 1. * Online is a bit of a large hammer but does the job. */ if(unit->sectors == 0 || (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1)) sdinitpart(unit); i = s+Qunitbase; if(i < Qpart){ r = sd2gen(c, i, dp); qunlock(&unit->ctl); decref(&sdev->r); return r; } i -= Qpart; if(unit->part == nil || i >= unit->npart){ qunlock(&unit->ctl); decref(&sdev->r); break; } pp = &unit->part[i]; if(!pp->valid){ qunlock(&unit->ctl); decref(&sdev->r); return 0; } l = (pp->end - pp->start) * unit->secsize; mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart), unit->vers+pp->vers, QTFILE); if(emptystr(pp->user)) kstrdup(&pp->user, eve); devdir(c, q, pp->name, l, pp->user, pp->perm, dp); qunlock(&unit->ctl); decref(&sdev->r); return 1; case Qraw: case Qctl: case Qpart: if((sdev = sdgetdev(DEV(c->qid))) == nil){ devdir(c, q, "unavailable", 0, eve, 0, dp); return 1; } unit = sdev->unit[UNIT(c->qid)]; qlock(&unit->ctl); r = sd2gen(c, TYPE(c->qid), dp); qunlock(&unit->ctl); decref(&sdev->r); return r; case Qtopctl: return sd1gen(c, TYPE(c->qid), dp); default: break; } return -1; }
static long sdbio(Chan* c, int write, char* a, long len, uvlong off) { int nchange; long l; uchar *b; SDpart *pp; SDunit *unit; SDev *sdev; ulong max, nb, offset; uvlong bno; sdev = sdgetdev(DEV(c->qid)); if(sdev == nil){ decref(&sdev->r); error(Enonexist); } unit = sdev->unit[UNIT(c->qid)]; if(unit == nil) error(Enonexist); nchange = 0; qlock(&unit->ctl); while(waserror()){ /* notification of media change; go around again */ if(strcmp(up->env->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){ sdinitpart(unit); continue; } /* other errors; give up */ qunlock(&unit->ctl); decref(&sdev->r); nexterror(); } pp = &unit->part[PART(c->qid)]; if(unit->vers+pp->vers != c->qid.vers) error(Echange); /* * Check the request is within bounds. * Removeable drives are locked throughout the I/O * in case the media changes unexpectedly. * Non-removeable drives are not locked during the I/O * to allow the hardware to optimise if it can; this is * a little fast and loose. * It's assumed that non-removeable media parameters * (sectors, secsize) can't change once the drive has * been brought online. */ bno = (off/unit->secsize) + pp->start; nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno; max = SDmaxio/unit->secsize; if(nb > max) nb = max; if(bno+nb > pp->end) nb = pp->end - bno; if(bno >= pp->end || nb == 0){ if(write) error(Eio); qunlock(&unit->ctl); decref(&sdev->r); poperror(); return 0; } if(!(unit->inquiry[1] & SDinq1removable)){ qunlock(&unit->ctl); poperror(); } b = sdmalloc(nb*unit->secsize); if(b == nil) error(Enomem); if(waserror()){ sdfree(b); if(!(unit->inquiry[1] & SDinq1removable)) decref(&sdev->r); /* gadverdamme! */ nexterror(); } offset = off%unit->secsize; if(offset+len > nb*unit->secsize) len = nb*unit->secsize - offset; if(write){ if(offset || (len%unit->secsize)){ l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno); if(l < 0) error(Eio); if(l < (nb*unit->secsize)){ nb = l/unit->secsize; l = nb*unit->secsize - offset; if(len > l) len = l; } } memmove(b+offset, a, len); l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno); if(l < 0) error(Eio); if(l < offset) len = 0; else if(len > l - offset) len = l - offset; } else{ l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno); if(l < 0) error(Eio); if(l < offset) len = 0; else if(len > l - offset) len = l - offset; memmove(a, b+offset, len); } sdfree(b); poperror(); if(unit->inquiry[1] & SDinq1removable){ qunlock(&unit->ctl); poperror(); } decref(&sdev->r); return len; }
static long sdwrite(Chan* c, void* a, long n, vlong off) { char *f0; int i; uvlong end, start; Cmdbuf *cb; SDifc *ifc; SDreq *req; SDunit *unit; SDev *sdev; switch(TYPE(c->qid)){ default: error(Eperm); case Qtopctl: cb = parsecmd(a, n); if(waserror()){ free(cb); nexterror(); } if(cb->nf == 0) error("empty control message"); f0 = cb->f[0]; cb->f++; cb->nf--; if(strcmp(f0, "config") == 0){ /* wormhole into ugly legacy interface */ legacytopctl(cb); poperror(); free(cb); break; } /* * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb), * where sdifc[i]->name=="ata" and cb contains the args. */ ifc = nil; sdev = nil; for(i=0; sdifc[i]; i++){ if(strcmp(sdifc[i]->name, f0) == 0){ ifc = sdifc[i]; sdev = nil; goto subtopctl; } } /* * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb), * where sdifc[i] and sdev match controller letter "1", * and cb contains the args. */ if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){ if((sdev = sdgetdev(f0[2])) != nil){ ifc = sdev->ifc; goto subtopctl; } } error("unknown interface"); subtopctl: if(waserror()){ if(sdev) decref(&sdev->r); nexterror(); } if(ifc->wtopctl) ifc->wtopctl(sdev, cb); else error(Ebadctl); poperror(); poperror(); if (sdev) decref(&sdev->r); free(cb); break; case Qctl: cb = parsecmd(a, n); sdev = sdgetdev(DEV(c->qid)); if(sdev == nil) error(Enonexist); unit = sdev->unit[UNIT(c->qid)]; qlock(&unit->ctl); if(waserror()){ qunlock(&unit->ctl); decref(&sdev->r); free(cb); nexterror(); } if(unit->vers != c->qid.vers) error(Echange); if(cb->nf < 1) error(Ebadctl); if(strcmp(cb->f[0], "part") == 0){ if(cb->nf != 4) error(Ebadctl); if(unit->sectors == 0 && !sdinitpart(unit)) error(Eio); start = strtoull(cb->f[2], 0, 0); end = strtoull(cb->f[3], 0, 0); sdaddpart(unit, cb->f[1], start, end); } else if(strcmp(cb->f[0], "delpart") == 0){ if(cb->nf != 2 || unit->part == nil) error(Ebadctl); sddelpart(unit, cb->f[1]); } else if(unit->dev->ifc->wctl) unit->dev->ifc->wctl(unit, cb); else error(Ebadctl); qunlock(&unit->ctl); decref(&sdev->r); poperror(); free(cb); break; case Qraw: sdev = sdgetdev(DEV(c->qid)); if(sdev == nil) error(Enonexist); unit = sdev->unit[UNIT(c->qid)]; qlock(&unit->raw); if(waserror()){ qunlock(&unit->raw); decref(&sdev->r); nexterror(); } switch(unit->state){ case Rawcmd: if(n < 6 || n > sizeof(req->cmd)) error(Ebadarg); if((req = malloc(sizeof(SDreq))) == nil) error(Enomem); req->unit = unit; memmove(req->cmd, a, n); req->clen = n; req->flags = SDnosense; req->status = ~0; unit->req = req; unit->state = Rawdata; break; case Rawstatus: unit->state = Rawcmd; free(unit->req); unit->req = nil; error(Ebadusefd); case Rawdata: unit->state = Rawstatus; unit->req->write = 1; n = sdrio(unit->req, a, n); } qunlock(&unit->raw); decref(&sdev->r); poperror(); break; case Qpart: return sdbio(c, 1, a, n, off); } return n; }
static long sdread(Chan *c, void *a, long n, vlong off) { char *p, *e, *buf; SDpart *pp; SDunit *unit; SDev *sdev; ulong offset; int i, l, m, status; offset = off; switch(TYPE(c->qid)){ default: error(Eperm); case Qtopctl: m = 64*1024; /* room for register dumps */ p = buf = malloc(m); if(p == nil) error(Enomem); e = p + m; qlock(&devslock); for(i = 0; i < nelem(devs); i++){ sdev = devs[i]; if(sdev && sdev->ifc->rtopctl) p = sdev->ifc->rtopctl(sdev, p, e); } qunlock(&devslock); n = readstr(off, a, n, buf); free(buf); return n; case Qtopdir: case Qunitdir: return devdirread(c, a, n, 0, 0, sdgen); case Qctl: sdev = sdgetdev(DEV(c->qid)); if(sdev == nil) error(Enonexist); unit = sdev->unit[UNIT(c->qid)]; m = 16*1024; /* room for register dumps */ p = malloc(m); if(p == nil) error(Enomem); l = snprint(p, m, "inquiry %.48s\n", (char*)unit->inquiry+8); qlock(&unit->ctl); /* * If there's a device specific routine it must * provide all information pertaining to night geometry * and the garscadden trains. */ if(unit->dev->ifc->rctl) l += unit->dev->ifc->rctl(unit, p+l, m-l); if(unit->sectors == 0) sdinitpart(unit); if(unit->sectors){ if(unit->dev->ifc->rctl == nil) l += snprint(p+l, m-l, "geometry %llud %lud\n", unit->sectors, unit->secsize); pp = unit->part; for(i = 0; i < unit->npart; i++){ if(pp->valid) l += snprint(p+l, m-l, "part %s %llud %llud\n", pp->name, pp->start, pp->end); pp++; } } qunlock(&unit->ctl); decref(&sdev->r); l = readstr(offset, a, n, p); free(p); return l; case Qraw: sdev = sdgetdev(DEV(c->qid)); if(sdev == nil) error(Enonexist); unit = sdev->unit[UNIT(c->qid)]; qlock(&unit->raw); if(waserror()){ qunlock(&unit->raw); decref(&sdev->r); nexterror(); } if(unit->state == Rawdata){ unit->state = Rawstatus; i = sdrio(unit->req, a, n); } else if(unit->state == Rawstatus){ status = unit->req->status; unit->state = Rawcmd; free(unit->req); unit->req = nil; i = readnum(0, a, n, status, NUMSIZE); } else i = 0; qunlock(&unit->raw); decref(&sdev->r); poperror(); return i; case Qpart: return sdbio(c, 0, a, n, off); } }
/* * 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(Fs *f, Ipifc *ifc, Iplifc *lifc, uint8_t *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->medium->remmulti != nil) (*ifc->medium->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); }
void cwrite(Chan* c, uchar *buf, int len, vlong off) { int o, eo; Mntcache *m; ulong eblock, ee; Extent *p, *f, *e, *tail; ulong offset; if(off > maxcache || len == 0) return; m = c->mcp; if(m == 0) return; qlock(m); if(cdev(m, c) == 0) { qunlock(m); c->mcp = 0; return; } offset = off; m->qid.vers++; c->qid.vers++; p = 0; for(f = m->list; f; f = f->next) { if(f->start >= offset) break; p = f; } if(p != 0) { ee = p->start+p->len; eo = offset - p->start; /* pack in predecessor if there is space */ if(offset <= ee && eo < BY2PG) { o = len; if(o > BY2PG - eo) o = BY2PG - eo; if(cpgmove(p, buf, eo, o)) { if(eo+o > p->len) p->len = eo+o; buf += o; len -= o; offset += o; } } } /* free the overlap -- it's a rare case */ eblock = offset+len; while(f && f->start < eblock) { e = f->next; extentfree(f); f = e; } /* link the block (if any) into the middle */ e = cchain(buf, offset, len, &tail); if(e != 0) { tail->next = f; f = e; } if(p == 0) m->list = f; else p->next = f; qunlock(m); }
void respond(Req *r, char *error) { int i, m, n; char errbuf[ERRMAX]; Srv *srv; srv = r->srv; assert(srv != nil); assert(r->responded == 0); r->error = error; switch(r->ifcall.type){ default: assert(0); /* * Flush is special. If the handler says so, we return * without further processing. Respond will be called * again once it is safe. */ case Tflush: if(rflush(r, error)<0) return; break; case Tversion: rversion(r, error); break; case Tauth: rauth(r, error); break; case Tattach: rattach(r, error); break; case Twalk: rwalk(r, error); break; case Topen: ropen(r, error); break; case Tcreate: rcreate(r, error); break; case Tread: rread(r, error); break; case Twrite: rwrite(r, error); break; case Tclunk: rclunk(r, error); break; case Tremove: rremove(r, error, errbuf); break; case Tstat: rstat(r, error); break; case Twstat: rwstat(r, error); break; } r->ofcall.tag = r->ifcall.tag; r->ofcall.type = r->ifcall.type+1; if(r->error) setfcallerror(&r->ofcall, r->error); if(chatty9p) fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall); qlock(&srv->wlock); n = convS2M(&r->ofcall, srv->wbuf, srv->msize); if(n <= 0){ fprint(2, "n = %d %F\n", n, &r->ofcall); abort(); } assert(n > 2); if(r->pool) /* not a fake */ closereq(removereq(r->pool, r->ifcall.tag)); m = write(srv->outfd, srv->wbuf, n); if(m != n) sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd); qunlock(&srv->wlock); qlock(&r->lk); /* no one will add flushes now */ r->responded = 1; qunlock(&r->lk); for(i=0; i<r->nflush; i++) respond(r->flush[i], nil); free(r->flush); r->flush = nil; r->nflush = 0; if(r->pool) closereq(r); else free(r); }
NbSession * nbssconnect(NbName to, NbName from) { Session *s; uchar ipaddr[IPaddrlen]; char dialaddress[100]; char dir[NETPATHLEN]; uchar msg[576]; int fd; long o; uchar flags; long length; if (!nbnameresolve(to, ipaddr)) return nil; fmtinstall('I', eipfmt); snprint(dialaddress, sizeof(dialaddress), "tcp!%I!netbios", ipaddr); fd = dial(dialaddress, nil, dir, nil); if (fd < 0) return nil; msg[0] = 0x81; msg[1] = 0; o = 4; o += nbnameencode(msg + o, msg + sizeof(msg) - o, to); o += nbnameencode(msg + o, msg + sizeof(msg) - o, from); hnputs(msg + 2, o - 4); if (write(fd, msg, o) != o) { close(fd); return nil; } if (readn(fd, msg, 4) != 4) { close(fd); return nil; } flags = msg[1]; length = nhgets(msg + 2) | ((flags & 1) << 16); switch (msg[0]) { default: close(fd); werrstr("unexpected session message code 0x%.2ux", msg[0]); return nil; case 0x82: if (length != 0) { close(fd); werrstr("length not 0 in positive session response"); return nil; } break; case 0x83: if (length != 1) { close(fd); werrstr("length not 1 in negative session response"); return nil; } if (readn(fd, msg + 4, 1) != 1) { close(fd); return nil; } close(fd); werrstr("negative session response 0x%.2ux", msg[4]); return nil; } s = nbemalloc(sizeof(Session)); s->fd = fd; s->state = Connected; qlock(&sessions); s->next = sessions.head; sessions.head = s; qunlock(&sessions); return s; }
static void connproc(void *v) { VtSconn *sc; VtConn *c; Packet *p; VtReq *r; int fd; static int first=1; if(first && chattyventi){ first=0; fmtinstall('F', vtfcallfmt); } r = nil; sc = v; sc->c = nil; if(0) fprint(2, "new call %s on %d\n", sc->dir, sc->ctl); fd = accept(sc->ctl, sc->dir); close(sc->ctl); if(fd < 0){ fprint(2, "accept %s: %r\n", sc->dir); goto out; } c = vtconn(fd, fd); sc->c = c; if(vtversion(c) < 0){ fprint(2, "vtversion %s: %r\n", sc->dir); goto out; } if(vtsrvhello(c) < 0){ fprint(2, "vtsrvhello %s: %r\n", sc->dir); goto out; } if(0) fprint(2, "new proc %s\n", sc->dir); proccreate(vtsendproc, c, STACK); qlock(&c->lk); while(!c->writeq) rsleep(&c->rpcfork); qunlock(&c->lk); while((p = vtrecv(c)) != nil){ r = vtmallocz(sizeof(VtReq)); if(vtfcallunpack(&r->tx, p) < 0){ vtlog(VtServerLog, "<font size=-1>%T %s:</font> recv bad packet %p: %r<br>\n", c->addr, p); fprint(2, "bad packet on %s: %r\n", sc->dir); packetfree(p); continue; } vtlog(VtServerLog, "<font size=-1>%T %s:</font> recv packet %p (%F)<br>\n", c->addr, p, &r->tx); if(chattyventi) fprint(2, "%s <- %F\n", argv0, &r->tx); packetfree(p); if(r->tx.msgtype == VtTgoodbye) break; r->rx.tag = r->tx.tag; r->sc = sc; scincref(sc); if(_vtqsend(sc->srv->q, r) < 0){ scdecref(sc); fprint(2, "hungup queue\n"); break; } r = nil; } if(0) fprint(2, "eof on %s\n", sc->dir); out: if(r){ vtfcallclear(&r->tx); vtfree(r); } if(0) fprint(2, "freed %s\n", sc->dir); scdecref(sc); return; }
void mousethread(void *v) { Text *t, *argt; int but; uint q0, q1; Window *w; Plumbmsg *pm; Mouse m; char *act; enum { MResize, MMouse, MPlumb, MWarnings, NMALT }; static Alt alts[NMALT+1]; USED(v); threadsetname("mousethread"); alts[MResize].c = mousectl->resizec; alts[MResize].v = nil; alts[MResize].op = CHANRCV; alts[MMouse].c = mousectl->c; alts[MMouse].v = &mousectl->m; alts[MMouse].op = CHANRCV; alts[MPlumb].c = cplumb; alts[MPlumb].v = ± alts[MPlumb].op = CHANRCV; alts[MWarnings].c = cwarn; alts[MWarnings].v = nil; alts[MWarnings].op = CHANRCV; if(cplumb == nil) alts[MPlumb].op = CHANNOP; alts[NMALT].op = CHANEND; for(;;) { qlock(&row.lk); flushwarnings(); qunlock(&row.lk); flushimage(display, 1); switch(alt(alts)) { case MResize: if(getwindow(display, Refnone) < 0) error("attach to window"); draw(screen, screen->r, display->white, nil, ZP); iconinit(); scrlresize(); rowresize(&row, screen->clipr); break; case MPlumb: if(strcmp(pm->type, "text") == 0) { act = plumblookup(pm->attr, "action"); if(act==nil || strcmp(act, "showfile")==0) plumblook(pm); else if(strcmp(act, "showdata")==0) plumbshow(pm); } plumbfree(pm); break; case MWarnings: break; case MMouse: /* * Make a copy so decisions are consistent; mousectl changes * underfoot. Can't just receive into m because this introduces * another race; see /sys/src/libdraw/mouse.c. */ m = mousectl->m; qlock(&row.lk); t = rowwhich(&row, m.xy); if(t!=mousetext && mousetext!=nil && mousetext->w!=nil) { winlock(mousetext->w, 'M'); mousetext->eq0 = ~0; wincommit(mousetext->w, mousetext); winunlock(mousetext->w); } mousetext = t; if(t == nil) goto Continue; w = t->w; if(t==nil || m.buttons==0) goto Continue; but = 0; if(m.buttons == 1) but = 1; else if(m.buttons == 2) but = 2; else if(m.buttons == 4) but = 3; barttext = t; if(t->what==Body && ptinrect(m.xy, t->scrollr)) { if(but) { if(swapscrollbuttons) { if(but == 1) but = 3; else if(but == 3) but = 1; } winlock(w, 'M'); t->eq0 = ~0; textscroll(t, but); winunlock(w); } goto Continue; } /* scroll buttons, wheels, etc. */ if(w != nil && (m.buttons & (8|16))) { if(m.buttons & 8) but = Kscrolloneup; else but = Kscrollonedown; winlock(w, 'M'); t->eq0 = ~0; texttype(t, but); winunlock(w); goto Continue; } if(ptinrect(m.xy, t->scrollr)) { if(but) { if(t->what == Columntag) rowdragcol(&row, t->col, but); else if(t->what == Tag) { coldragwin(t->col, t->w, but); if(t->w) barttext = &t->w->body; } if(t->col) activecol = t->col; } goto Continue; } if(m.buttons) { if(w) winlock(w, 'M'); t->eq0 = ~0; if(w) wincommit(w, t); else textcommit(t, TRUE); if(m.buttons & 1) { textselect(t); if(w) winsettag(w); argtext = t; seltext = t; if(t->col) activecol = t->col; /* button 1 only */ if(t->w!=nil && t==&t->w->body) activewin = t->w; } else if(m.buttons & 2) { if(textselect2(t, &q0, &q1, &argt)) execute(t, q0, q1, FALSE, argt); } else if(m.buttons & 4) { if(textselect3(t, &q0, &q1)) look3(t, q0, q1, FALSE); } if(w) winunlock(w); goto Continue; } Continue: qunlock(&row.lk); break; } } }
void threadmain(int argc, char *argv[]) { int i; char *file; Arena *arena; u64int offset, aoffset; Part *part; uchar buf[8192]; ArenaHead head; ZClump zerocl; ventifmtinstall(); qlock(&godot); aoffset = 0; ARGBEGIN{ case 'f': fast = 1; ventidoublechecksha1 = 0; break; case 'h': host = EARGF(usage()); break; case 'o': haveaoffset = 1; aoffset = strtoull(EARGF(usage()), 0, 0); break; case 'M': maxwrites = atoi(EARGF(usage())); break; case 'v': verbose = 1; break; default: usage(); break; }ARGEND offset = ~(u64int)0; switch(argc) { default: usage(); case 2: offset = strtoull(argv[1], 0, 0); /* fall through */ case 1: file = argv[0]; } fmtinstall('V', vtscorefmt); statsinit(); part = initpart(file, OREAD); if(part == nil) sysfatal("can't open file %s: %r", file); if(readpart(part, aoffset, buf, sizeof buf) < 0) sysfatal("can't read file %s: %r", file); if(unpackarenahead(&head, buf) < 0) sysfatal("corrupted arena header: %r"); if(aoffset+head.size > part->size) sysfatal("arena is truncated: want %llud bytes have %llud", head.size, part->size); partblocksize(part, head.blocksize); initdcache(8 * MaxDiskBlock); arena = initarena(part, aoffset, head.size, head.blocksize); if(arena == nil) sysfatal("initarena: %r"); z = nil; if(host==nil || strcmp(host, "/dev/null") != 0){ z = vtdial(host); if(z == nil) sysfatal("could not connect to server: %r"); if(vtconnect(z) < 0) sysfatal("vtconnect: %r"); } c = chancreate(sizeof(ZClump), 0); for(i=0; i<12; i++) vtproc(vtsendthread, nil); rdarena(arena, offset); if(vtsync(z) < 0) sysfatal("executing sync: %r"); memset(&zerocl, 0, sizeof zerocl); for(i=0; i<12; i++) send(c, &zerocl); if(z){ vthangup(z); } threadexitsall(0); }
static Xfid* fsyswalk(Xfid *x, Fid *f) { Fcall t; int c, i, j, id; Qid q; uchar type; ulong path; Fid *nf; Dirtab *d, *dir; Window *w; char *err; nf = nil; w = nil; if(f->open) return respond(x, &t, "walk of open file"); if(x->fid != x->newfid){ nf = newfid(x->newfid); if(nf->busy) return respond(x, &t, "newfid already in use"); nf->busy = TRUE; nf->open = FALSE; nf->mntdir = f->mntdir; if(f->mntdir) f->mntdir->ref++; nf->dir = f->dir; nf->qid = f->qid; nf->w = f->w; nf->nrpart = 0; /* not open, so must be zero */ if(nf->w) incref(nf->w); f = nf; /* walk f */ } t.nwqid = 0; err = nil; dir = nil; id = WIN(f->qid); q = f->qid; if(x->nwname > 0){ for(i=0; i<x->nwname; i++){ if((q.type & QTDIR) == 0){ err = Enotdir; break; } if(strcmp(x->wname[i], "..") == 0){ type = QTDIR; path = Qdir; id = 0; if(w){ winclose(w); w = nil; } Accept: if(i == MAXWELEM){ err = "name too long"; break; } q.type = type; q.vers = 0; q.path = QID(id, path); t.wqid[t.nwqid++] = q; continue; } /* is it a numeric name? */ for(j=0; (c=x->wname[i][j]); j++) if(c<'0' || '9'<c) goto Regular; /* yes: it's a directory */ if(w) /* name has form 27/23; get out before losing w */ break; id = atoi(x->wname[i]); qlock(&row); w = lookid(id, FALSE); if(w == nil){ qunlock(&row); break; } incref(w); /* we'll drop reference at end if there's an error */ path = Qdir; type = QTDIR; qunlock(&row); dir = dirtabw; goto Accept; Regular: // if(FILE(f->qid) == Qacme) /* empty directory */ // break; if(strcmp(x->wname[i], "new") == 0){ if(w) error("w set in walk to new"); sendp(cnewwindow, nil); /* signal newwindowthread */ w = recvp(cnewwindow); /* receive new window */ incref(w); type = QTDIR; path = QID(w->id, Qdir); id = w->id; dir = dirtabw; goto Accept; } if(id == 0) d = dirtab; else d = dirtabw; d++; /* skip '.' */ for(; d->name; d++) if(strcmp(x->wname[i], d->name) == 0){ path = d->qid; type = d->type; dir = d; goto Accept; } break; /* file not found */ } if(i==0 && err == nil) err = Eexist; } if(err!=nil || t.nwqid<x->nwname){ if(nf){ nf->busy = FALSE; fsysdelid(nf->mntdir); } }else if(t.nwqid == x->nwname){ if(w){ f->w = w; w = nil; /* don't drop the reference */ } if(dir) f->dir = dir; f->qid = q; } if(w != nil) winclose(w); return respond(x, &t, err); }
/* * read a queue. if no data is queued, post a struct block * and wait on its Rendez. */ long qread(struct queue *q, void *vp, int len) { ERRSTACK(1); struct block *b, *first, **l; int m, n; qlock(&q->rlock); if (waserror()) { qunlock(&q->rlock); nexterror(); } spin_lock_irqsave(&q->lock); again: if (!qwait(q)) { /* queue closed */ spin_unlock_irqsave(&q->lock); qunlock(&q->rlock); poperror(); return 0; } /* if we get here, there's at least one block in the queue */ // TODO: Consider removing the Qcoalesce flag and force a coalescing // strategy by default. if (q->state & Qcoalesce) { /* when coalescing, 0 length blocks just go away */ b = q->bfirst; if (BLEN(b) <= 0) { freeb(qremove(q)); goto again; } /* grab the first block plus as many * following blocks as will completely * fit in the read. */ n = 0; l = &first; m = BLEN(b); for (;;) { *l = qremove(q); l = &b->next; n += m; b = q->bfirst; if (b == NULL) break; m = BLEN(b); if (n + m > len) break; } } else { first = qremove(q); n = BLEN(first); } /* copy to user space outside of the ilock */ spin_unlock_irqsave(&q->lock); b = bl2mem(vp, first, len); spin_lock_irqsave(&q->lock); /* take care of any left over partial block */ if (b != NULL) { n -= BLEN(b); if (q->state & Qmsg) freeb(b); else qputback(q, b); } /* restart producer */ qwakeup_iunlock(q); poperror(); qunlock(&q->rlock); return n; }
void respond(Req *r, char *error) { int i, m, n; char errbuf[ERRMAX]; Srv *srv; srv = r->srv; assert(srv != nil); if(r->responded){ assert(r->pool); goto free; } assert(r->responded == 0); r->error = error; switch(r->ifcall.type){ default: assert(0); /* * Flush is special. If the handler says so, we return * without further processing. Respond will be called * again once it is safe. */ case Tflush: if(rflush(r, error)<0) return; break; case Tversion: rversion(r, error); break; case Tauth: rauth(r, error); break; case Tattach: rattach(r, error); break; case Twalk: rwalk(r, error); break; case Topen: ropen(r, error); break; case Tcreate: rcreate(r, error); break; case Tread: rread(r, error); break; case Twrite: rwrite(r, error); break; case Tclunk: rclunk(r, error); break; case Tremove: rremove(r, error, errbuf); break; case Tstat: rstat(r, error); break; case Twstat: rwstat(r, error); break; } r->ofcall.tag = r->ifcall.tag; r->ofcall.type = r->ifcall.type+1; if(r->error) setfcallerror(&r->ofcall, r->error); if(srv->fake) return; if(chatty9p) fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall); qlock(&srv->wlock); n = convS2M(&r->ofcall, srv->wbuf, srv->msize); if(n <= 0){ fprint(2, "n = %d %F\n", n, &r->ofcall); abort(); } assert(n > 2); /* * There is a race here - we must remove the entry before * the write, so that if the client is very fast and reuses the * tag, the read loop won't think it is still in use. * * By removing the entry before the write, we open up a * race with incoming Tflush messages. Specifically, an * incoming Tflush might not see r even though it has not * yet been responded to. It would then send an Rflush * immediately, potentially before we do the write. This can't * happen because we already old srv->wlock, so nothing * is going out on the wire before this write. */ if(r->pool) /* not a fake */ closereq(removereq(r->pool, r->ifcall.tag)); qlock(&r->lk); r->responded = 1; if(r->pool) if(r->ref.ref == 1+r->nflush) if(r->fid){ /* * There are no references other than in our r->flush array, * so no one else should be accessing r concurrently. * Close the fid now, before responding to the message. * * If the client is behaving (there are no outstanding T-messages * that reference r->fid) and the message is a Tclunk or Tremove, * then this closefid will call destroyfid. * * This means destroyfid can't piddle around * indefinitely (we're holding srv->wlock!), but it provides * for tighter semantics as to when destroyfid is called. * * LANL has observed cases where waiting until after the write * can delay a closefid on a Twrite for many 9P transactions, * so that a handful of transactions can happen including a Tclunk * and a Topen, and the original fid will still not be destroyed. */ closefid(r->fid); r->fid = nil; } qunlock(&r->lk); m = write(srv->outfd, srv->wbuf, n); if(m != n) sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd); qunlock(&srv->wlock); free: qlock(&r->lk); /* no one will add flushes now */ for(i=0; i<r->nflush; i++){ r->flush[i]->oldreq = nil; /* so it doesn't try to lock us! */ respond(r->flush[i], nil); } free(r->flush); r->nflush = 0; r->flush = nil; qunlock(&r->lk); if(r->pool) closereq(r); else free(r); }
/* * add a block to a queue obeying flow control */ long qbwrite(struct queue *q, struct block *b) { ERRSTACK(1); int n, dowakeup; volatile bool should_free_b = TRUE; n = BLEN(b); if (q->bypass) { (*q->bypass) (q->arg, b); return n; } dowakeup = 0; qlock(&q->wlock); if (waserror()) { if (b != NULL && should_free_b) freeb(b); qunlock(&q->wlock); nexterror(); } spin_lock_irqsave(&q->lock); /* give up if the queue is closed */ if (q->state & Qclosed) { spin_unlock_irqsave(&q->lock); error(EFAIL, q->err); } /* if nonblocking, don't queue over the limit */ if (q->len >= q->limit) { /* drop overflow takes priority over regular non-blocking */ if (q->state & Qdropoverflow) { spin_unlock_irqsave(&q->lock); freeb(b); dropcnt += n; qunlock(&q->wlock); poperror(); return n; } if (q->state & Qnonblock) { spin_unlock_irqsave(&q->lock); freeb(b); error(EAGAIN, "queue full"); } } /* queue the block */ should_free_b = FALSE; if (q->bfirst) q->blast->next = b; else q->bfirst = b; q->blast = b; b->next = 0; q->len += BALLOC(b); q->dlen += n; QDEBUG checkb(b, "qbwrite"); b = NULL; /* make sure other end gets awakened */ if (q->state & Qstarve) { q->state &= ~Qstarve; dowakeup = 1; } spin_unlock_irqsave(&q->lock); /* get output going again */ if (q->kick && (dowakeup || (q->state & Qkick))) q->kick(q->arg); /* wakeup anyone consuming at the other end */ if (dowakeup) { rendez_wakeup(&q->rr); qwake_cb(q, FDTAP_FILT_READABLE); } /* * flow control, wait for queue to get below the limit * before allowing the process to continue and queue * more. We do this here so that postnote can only * interrupt us after the data has been queued. This * means that things like 9p flushes and ssl messages * will not be disrupted by software interrupts. * * Note - this is moderately dangerous since a process * that keeps getting interrupted and rewriting will * queue infinite crud. */ for (;;) { if ((q->state & (Qdropoverflow | Qnonblock)) || qnotfull(q)) break; spin_lock_irqsave(&q->lock); q->state |= Qflow; spin_unlock_irqsave(&q->lock); rendez_sleep(&q->wr, qnotfull, q); } qunlock(&q->wlock); poperror(); return n; }
long sysexec(ulong *arg) { Segment *s, *ts; ulong t, d, b; int i; Chan *tc; char **argv, **argp; char *a, *charp, *args, *file, *file0; char *progarg[sizeof(Exec)/2+1], *elem, progelem[64]; ulong ssize, spage, nargs, nbytes, n, bssend; int indir; Exec exec; char line[sizeof(Exec)]; Fgrp *f; Image *img; ulong magic, text, entry, data, bss; Tos *tos; indir = 0; elem = nil; validaddr(arg[0], 1, 0); file0 = validnamedup((char*)arg[0], 1); if(waserror()){ free(file0); free(elem); nexterror(); } file = file0; for(;;){ tc = namec(file, Aopen, OEXEC, 0); if(waserror()){ cclose(tc); nexterror(); } if(!indir) kstrdup(&elem, up->genbuf); n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0); if(n < 2) error(Ebadexec); magic = l2be(exec.magic); text = l2be(exec.text); entry = l2be(exec.entry); if(n==sizeof(Exec) && (magic == AOUT_MAGIC)){ if(text >= USTKTOP-UTZERO || entry < UTZERO+sizeof(Exec) || entry >= UTZERO+sizeof(Exec)+text) error(Ebadexec); break; /* for binary */ } /* * Process #! /bin/sh args ... */ memmove(line, &exec, sizeof(Exec)); if(indir || line[0]!='#' || line[1]!='!') error(Ebadexec); n = shargs(line, n, progarg); if(n == 0) error(Ebadexec); indir = 1; /* * First arg becomes complete file name */ progarg[n++] = file; progarg[n] = 0; validaddr(arg[1], BY2WD, 1); arg[1] += BY2WD; file = progarg[0]; if(strlen(elem) >= sizeof progelem) error(Ebadexec); strcpy(progelem, elem); progarg[0] = progelem; poperror(); cclose(tc); } data = l2be(exec.data); bss = l2be(exec.bss); t = (UTZERO+sizeof(Exec)+text+(BY2PG-1)) & ~(BY2PG-1); d = (t + data + (BY2PG-1)) & ~(BY2PG-1); bssend = t + data + bss; b = (bssend + (BY2PG-1)) & ~(BY2PG-1); if(t >= KZERO || d >= KZERO || b >= KZERO) error(Ebadexec); /* * Args: pass 1: count */ nbytes = sizeof(Tos); /* hole for profiling clock at top of stack (and more) */ nargs = 0; if(indir){ argp = progarg; while(*argp){ a = *argp++; nbytes += strlen(a) + 1; nargs++; } } evenaddr(arg[1]); argp = (char**)arg[1]; validaddr((ulong)argp, BY2WD, 0); while(*argp){ a = *argp++; if(((ulong)argp&(BY2PG-1)) < BY2WD) validaddr((ulong)argp, BY2WD, 0); validaddr((ulong)a, 1, 0); nbytes += ((char*)vmemchr(a, 0, 0x7FFFFFFF) - a) + 1; nargs++; } ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1)); /* * 8-byte align SP for those (e.g. sparc) that need it. * execregs() will subtract another 4 bytes for argc. */ if((ssize+4) & 7) ssize += 4; spage = (ssize+(BY2PG-1)) >> PGSHIFT; /* * Build the stack segment, putting it in kernel virtual for the moment */ if(spage > TSTKSIZ) error(Enovmem); qlock(&up->seglock); if(waserror()){ qunlock(&up->seglock); nexterror(); } up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG); /* * Args: pass 2: assemble; the pages will be faulted in */ tos = (Tos*)(TSTKTOP - sizeof(Tos)); tos->cyclefreq = m->cyclefreq; cycles((uvlong*)&tos->pcycles); tos->pcycles = -tos->pcycles; tos->kcycles = tos->pcycles; tos->clock = 0; argv = (char**)(TSTKTOP - ssize); charp = (char*)(TSTKTOP - nbytes); args = charp; if(indir) argp = progarg; else argp = (char**)arg[1]; for(i=0; i<nargs; i++){ if(indir && *argp==0) { indir = 0; argp = (char**)arg[1]; } *argv++ = charp + (USTKTOP-TSTKTOP); n = strlen(*argp) + 1; memmove(charp, *argp++, n); charp += n; } free(file0); free(up->text); up->text = elem; elem = nil; /* so waserror() won't free elem */ USED(elem); /* copy args; easiest from new process's stack */ n = charp - args; if(n > 128) /* don't waste too much space on huge arg lists */ n = 128; a = up->args; up->args = nil; free(a); up->args = smalloc(n); memmove(up->args, args, n); if(n>0 && up->args[n-1]!='\0'){ /* make sure last arg is NUL-terminated */ /* put NUL at UTF-8 character boundary */ for(i=n-1; i>0; --i) if(fullrune(up->args+i, n-i)) break; up->args[i] = 0; n = i+1; } up->nargs = n; /* * Committed. * Free old memory. * Special segments are maintained across exec */ for(i = SSEG; i <= BSEG; i++) { putseg(up->seg[i]); /* prevent a second free if we have an error */ up->seg[i] = 0; } for(i = BSEG+1; i < NSEG; i++) { s = up->seg[i]; if(s != 0 && (s->type&SG_CEXEC)) { putseg(s); up->seg[i] = 0; } } /* * Close on exec */ f = up->fgrp; for(i=0; i<=f->maxfd; i++) fdclose(i, CCEXEC); /* Text. Shared. Attaches to cache image if possible */ /* attachimage returns a locked cache image */ img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT); ts = img->s; up->seg[TSEG] = ts; ts->flushme = 1; ts->fstart = 0; ts->flen = sizeof(Exec)+text; unlock(img); /* Data. Shared. */ s = newseg(SG_DATA, t, (d-t)>>PGSHIFT); up->seg[DSEG] = s; /* Attached by hand */ incref(img); s->image = img; s->fstart = ts->fstart+ts->flen; s->flen = data; /* BSS. Zero fill on demand */ up->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT); /* * Move the stack */ s = up->seg[ESEG]; up->seg[ESEG] = 0; up->seg[SSEG] = s; qunlock(&up->seglock); poperror(); /* seglock */ poperror(); /* elem */ s->base = USTKTOP-USTKSIZE; s->top = USTKTOP; relocateseg(s, USTKTOP-TSTKTOP); /* * '/' processes are higher priority (hack to make /ip more responsive). */ if(devtab[tc->type]->dc == L'/') up->basepri = PriRoot; up->priority = up->basepri; poperror(); cclose(tc); /* * At this point, the mmu contains info about the old address * space and needs to be flushed */ flushmmu(); qlock(&up->debug); up->nnote = 0; up->notify = 0; up->notified = 0; up->privatemem = 0; procsetup(up); qunlock(&up->debug); if(up->hang) up->procctl = Proc_stopme; return execregs(entry, ssize, nargs); }
int cread(Chan *c, uchar *buf, int len, vlong off) { KMap *k; Page *p; Mntcache *m; Extent *e, **t; int o, l, total; ulong offset; if(off+len > maxcache) return 0; m = c->mcp; if(m == 0) return 0; qlock(m); if(cdev(m, c) == 0) { qunlock(m); c->mcp = 0; return 0; } offset = off; t = &m->list; for(e = *t; e; e = e->next) { if(offset >= e->start && offset < e->start+e->len) break; t = &e->next; } if(e == 0) { qunlock(m); return 0; } total = 0; while(len) { p = cpage(e); if(p == 0) { *t = e->next; extentfree(e); qunlock(m); return total; } o = offset - e->start; l = len; if(l > e->len-o) l = e->len-o; k = kmap(p); if(waserror()) { kunmap(k); putpage(p); qunlock(m); nexterror(); } memmove(buf, (uchar*)VA(k) + o, l); poperror(); kunmap(k); putpage(p); buf += l; len -= l; offset += l; total += l; t = &e->next; e = e->next; if(e == 0 || e->start != offset) break; } qunlock(m); return total; }
void mousethread(void *) { Plumbmsg *pm; Mouse m; Text *t; int but; enum { MResize, MMouse, MPlumb, MRefresh, NMALT }; static Alt alts[NMALT+1]; threadsetname("mousethread"); alts[MResize].c = mousectl->resizec; alts[MResize].v = nil; alts[MResize].op = CHANRCV; alts[MMouse].c = mousectl->c; alts[MMouse].v = &mousectl->Mouse; alts[MMouse].op = CHANRCV; alts[MPlumb].c = cplumb; alts[MPlumb].v = ± alts[MPlumb].op = CHANRCV; alts[MRefresh].c = crefresh; alts[MRefresh].v = nil; alts[MRefresh].op = CHANRCV; if(cplumb == nil) alts[MPlumb].op = CHANNOP; alts[NMALT].op = CHANEND; for(;;){ qlock(&row); flushrefresh(); qunlock(&row); flushimage(display, 1); switch(alt(alts)){ case MResize: if(getwindow(display, Refnone) < 0) error("resized"); scrlresize(); tmpresize(); rowresize(&row, screen->clipr); break; case MPlumb: plumblook(pm); plumbfree(pm); break; case MRefresh: break; case MMouse: m = mousectl->Mouse; if(m.buttons == 0) continue; qlock(&row); but = 0; if(m.buttons == 1) but = 1; else if(m.buttons == 2) but = 2; else if(m.buttons == 4) but = 3; if(m.buttons & (8|16)){ if(m.buttons & 8) but = Kscrolloneup; else but = Kscrollonedown; rowwhich(&row, m.xy, but, TRUE); }else if(but){ t = rowwhich(&row, m.xy, but, FALSE); if(t) textmouse(t, m.xy, but); } qunlock(&row); break; } } }
void cupdate(Chan *c, uchar *buf, int len, vlong off) { Mntcache *m; Extent *tail; Extent *e, *f, *p; int o, ee, eblock; ulong offset; if(off > maxcache || len == 0) return; m = c->mcp; if(m == 0) return; qlock(m); if(cdev(m, c) == 0) { qunlock(m); c->mcp = 0; return; } /* * Find the insertion point */ offset = off; p = 0; for(f = m->list; f; f = f->next) { if(f->start > offset) break; p = f; } /* trim if there is a successor */ eblock = offset+len; if(f != 0 && eblock > f->start) { len -= (eblock - f->start); if(len <= 0) { qunlock(m); return; } } if(p == 0) { /* at the head */ e = cchain(buf, offset, len, &tail); if(e != 0) { m->list = e; tail->next = f; } qunlock(m); return; } /* trim to the predecessor */ ee = p->start+p->len; if(offset < ee) { o = ee - offset; len -= o; if(len <= 0) { qunlock(m); return; } buf += o; offset += o; } /* try and pack data into the predecessor */ if(offset == ee && p->len < BY2PG) { o = len; if(o > BY2PG - p->len) o = BY2PG - p->len; if(cpgmove(p, buf, p->len, o)) { p->len += o; buf += o; len -= o; offset += o; if(len <= 0) { if(f && p->start + p->len > f->start) print("CACHE: p->start=%uld p->len=%d f->start=%uld\n", p->start, p->len, f->start); qunlock(m); return; } } } e = cchain(buf, offset, len, &tail); if(e != 0) { p->next = e; tail->next = f; } qunlock(m); }
/* * Call user, if necessary, with note. * Pass user the Ureg struct and the note on his stack. */ int notify(Ureg* ureg) { int l; Note *n; u32int s; uintptr sp; NFrame *nf; if(up->procctl) procctl(up); if(up->nnote == 0) return 0; fpunotify(ureg); s = spllo(); qlock(&up->debug); up->notepending = 0; n = &up->note[0]; if(strncmp(n->msg, "sys:", 4) == 0){ l = strlen(n->msg); if(l > ERRMAX-23) /* " pc=0x0123456789abcdef\0" */ l = ERRMAX-23; snprint(n->msg + l, sizeof n->msg - l, " pc=%#lux", ureg->pc); } if(n->flag != NUser && (up->notified || up->notify == 0)){ if(n->flag == NDebug) pprint("suicide: %s\n", n->msg); qunlock(&up->debug); pexit(n->msg, n->flag != NDebug); } if(up->notified){ qunlock(&up->debug); splhi(); return 0; } if(up->notify == nil){ qunlock(&up->debug); pexit(n->msg, n->flag != NDebug); } if(!okaddr(PTR2UINT(up->notify), 1, 0)){ pprint("suicide: notify function address %#p\n", up->notify); qunlock(&up->debug); pexit("Suicide", 0); } sp = ureg->sp - sizeof(NFrame); if(!okaddr(sp, sizeof(NFrame), 1)){ qunlock(&up->debug); pprint("suicide: notify stack address %#p\n", sp); pexit("Suicide", 0); } nf = UINT2PTR(sp); memmove(&nf->ureg, ureg, sizeof(Ureg)); nf->old = up->ureg; up->ureg = nf; memmove(nf->msg, up->note[0].msg, ERRMAX); nf->arg1 = nf->msg; nf->arg0 = &nf->ureg; nf->ip = 0; ureg->sp = sp; ureg->pc = PTR2UINT(up->notify); up->notified = 1; up->nnote--; memmove(&up->lastnote, &up->note[0], sizeof(Note)); memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); qunlock(&up->debug); splx(s); return 1; }
/* * decapsulate IP packet from IP/ESP packet in bp and * pass the result up the spi's Conv's read queue. */ void espiput(Proto *esp, Ipifc*, Block *bp) { int payload, nexthdr; uchar *auth, *espspi; Conv *c; Espcb *ecb; Esptail *et; Fs *f; Userhdr *uh; Versdep vers; f = esp->f; getverslens(pktipvers(f, &bp), &vers); bp = pullupblock(bp, vers.hdrlen + Esptaillen); if(bp == nil) { netlog(f, Logesp, "esp: short packet\n"); return; } getpktspiaddrs(bp->rp, &vers); qlock(esp); /* Look for a conversation structure for this port */ c = convlookup(esp, vers.spi); if(c == nil) { qunlock(esp); netlog(f, Logesp, "esp: no conv %I -> %I!%lud\n", vers.raddr, vers.laddr, vers.spi); icmpnoconv(f, bp); freeblist(bp); return; } qlock(c); qunlock(esp); ecb = c->ptcl; /* too hard to do decryption/authentication on block lists */ if(bp->next) bp = concatblock(bp); if(BLEN(bp) < vers.hdrlen + ecb->espivlen + Esptaillen + ecb->ahlen) { qunlock(c); netlog(f, Logesp, "esp: short block %I -> %I!%lud\n", vers.raddr, vers.laddr, vers.spi); freeb(bp); return; } auth = bp->wp - ecb->ahlen; espspi = vers.version == V4? ((Esp4hdr*)bp->rp)->espspi: ((Esp6hdr*)bp->rp)->espspi; /* compute secure hash and authenticate */ if(!ecb->auth(ecb, espspi, auth - espspi, auth)) { qunlock(c); print("esp: bad auth %I -> %I!%ld\n", vers.raddr, vers.laddr, vers.spi); netlog(f, Logesp, "esp: bad auth %I -> %I!%lud\n", vers.raddr, vers.laddr, vers.spi); freeb(bp); return; } payload = BLEN(bp) - vers.hdrlen - ecb->ahlen; if(payload <= 0 || payload % 4 != 0 || payload % ecb->espblklen != 0) { qunlock(c); netlog(f, Logesp, "esp: bad length %I -> %I!%lud payload=%d BLEN=%lud\n", vers.raddr, vers.laddr, vers.spi, payload, BLEN(bp)); freeb(bp); return; } /* decrypt payload */ if(!ecb->cipher(ecb, bp->rp + vers.hdrlen, payload)) { qunlock(c); print("esp: cipher failed %I -> %I!%ld: %s\n", vers.raddr, vers.laddr, vers.spi, up->errstr); netlog(f, Logesp, "esp: cipher failed %I -> %I!%lud: %s\n", vers.raddr, vers.laddr, vers.spi, up->errstr); freeb(bp); return; } payload -= Esptaillen; et = (Esptail*)(bp->rp + vers.hdrlen + payload); payload -= et->pad + ecb->espivlen; nexthdr = et->nexthdr; if(payload <= 0) { qunlock(c); netlog(f, Logesp, "esp: short packet after decrypt %I -> %I!%lud\n", vers.raddr, vers.laddr, vers.spi); freeb(bp); return; } /* trim packet */ bp->rp += vers.hdrlen + ecb->espivlen; /* toss original IP & ESP hdrs */ bp->wp = bp->rp + payload; if(ecb->header) { /* assume Userhdrlen < Esp4hdrlen < Esp6hdrlen */ bp->rp -= Userhdrlen; uh = (Userhdr*)bp->rp; memset(uh, 0, Userhdrlen); uh->nexthdr = nexthdr; } /* ingress filtering here? */ if(qfull(c->rq)){ netlog(f, Logesp, "esp: qfull %I -> %I.%uld\n", vers.raddr, vers.laddr, vers.spi); freeblist(bp); }else { // print("esp: pass up: %uld\n", BLEN(bp)); qpass(c->rq, bp); /* pass packet up the read queue */ } qunlock(c); }