static long ipwrite(Chan *ch, void *a, long n, vlong off) { Conv *c; Proto *x; char *p; Cmdbuf *cb; Fs *f; f = ipfs[ch->dev]; switch(TYPE(ch->qid)) { default: error(Eperm); case Qdata: x = f->p[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; if(c->sfd < 0) error(Ehungup); qlock(&c->wlock); if(waserror()){ qunlock(&c->wlock); nexterror(); } if(c->headers) { if(n < c->headers) error(Eshort); p = a; n = so_send(c->sfd, p + c->headers, n - c->headers, p, c->headers); if(n >= 0) n += c->headers; } else n = so_send(c->sfd, a, n, nil, 0); poperror(); qunlock(&c->wlock); if(n < 0) oserror(); break; case Qarp: return arpwrite(a, n); case Qndb: if(off > strlen(f->ndb)) error(Eio); if(off+n >= sizeof(f->ndb)-1) error(Eio); memmove(f->ndb+off, a, n); f->ndb[off+n] = 0; f->ndbvers++; f->ndbmtime = seconds(); break; case Qctl: x = f->p[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; cb = parsecmd(a, n); qlock(&c->l); if(waserror()){ qunlock(&c->l); free(cb); nexterror(); } if(cb->nf < 1) error("short control request"); if(strcmp(cb->f[0], "connect") == 0) connectctlmsg(x, c, cb); else if(strcmp(cb->f[0], "announce") == 0) announcectlmsg(x, c, cb); else if(strcmp(cb->f[0], "bind") == 0) bindctlmsg(x, c, cb); else if(strcmp(cb->f[0], "ttl") == 0){ /* ignored */ } else if(strcmp(cb->f[0], "tos") == 0){ /* ignored */ } else if(strcmp(cb->f[0], "ignoreadvice") == 0){ /* ignored */ } else if(strcmp(cb->f[0], "headers4") == 0){ if(c->p->stype != S_UDP) error(Enoctl); c->headers = OUdphdrlenv4; } else if(strcmp(cb->f[0], "oldheaders") == 0){ if(c->p->stype != S_UDP) error(Enoctl); c->headers = OUdphdrlen; } else if(strcmp(cb->f[0], "headers") == 0){ if(c->p->stype != S_UDP) error(Enoctl); c->headers = Udphdrlen; } else if(strcmp(cb->f[0], "hangup") == 0){ if(c->p->stype != S_TCP) error(Enoctl); qunlock(&c->l); if(waserror()){ qlock(&c->l); nexterror(); } /* TO DO: check fd status if socket close/hangup interrupted */ if(c->sfd >= 0 && so_hangup(c->sfd, 1) < 0) oserror(); qlock(&c->l); poperror(); c->sfd = -1; c->state = Hungup; } else if(strcmp(cb->f[0], "keepalive") == 0){ if(c->p->stype != S_TCP) error(Enoctl); if(c->sfd < 0) error("not connected"); so_keepalive(c->sfd, cb->nf>1? atoi(cb->f[1]): 0); } else error(Enoctl); poperror(); qunlock(&c->l); free(cb); break; } return n; }
static long ipwrite(Chan* ch, void *v, long n, vlong off) { Conv *c; Proto *x; char *p; Cmdbuf *cb; uchar ia[IPaddrlen], ma[IPaddrlen]; Fs *f; char *a; ulong offset = off; a = v; f = ipfs[ch->dev]; switch(TYPE(ch->qid)){ default: error(Eperm); case Qdata: x = f->p[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; if(c->wq == nil) error(Eperm); qwrite(c->wq, a, n); break; case Qarp: return arpwrite(f, a, n); case Qiproute: return routewrite(f, ch, a, n); case Qlog: netlogctl(f, a, n); return n; case Qndb: return ndbwrite(f, a, offset, n); break; case Qctl: x = f->p[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; cb = parsecmd(a, n); qlock(c); if(waserror()) { qunlock(c); free(cb); nexterror(); } if(cb->nf < 1) error("short control request"); if(strcmp(cb->f[0], "connect") == 0) connectctlmsg(x, c, cb); else if(strcmp(cb->f[0], "announce") == 0) announcectlmsg(x, c, cb); else if(strcmp(cb->f[0], "bind") == 0) bindctlmsg(x, c, cb); else if(strcmp(cb->f[0], "ttl") == 0) ttlctlmsg(c, cb); else if(strcmp(cb->f[0], "tos") == 0) tosctlmsg(c, cb); else if(strcmp(cb->f[0], "ignoreadvice") == 0) c->ignoreadvice = 1; else if(strcmp(cb->f[0], "addmulti") == 0){ if(cb->nf < 2) error("addmulti needs interface address"); if(cb->nf == 2){ if(!ipismulticast(c->raddr)) error("addmulti for a non multicast address"); if (parseip(ia, cb->f[1]) == -1) error(Ebadip); ipifcaddmulti(c, c->raddr, ia); } else { if (parseip(ia, cb->f[1]) == -1 || parseip(ma, cb->f[2]) == -1) error(Ebadip); if(!ipismulticast(ma)) error("addmulti for a non multicast address"); ipifcaddmulti(c, ma, ia); } } else if(strcmp(cb->f[0], "remmulti") == 0){ if(cb->nf < 2) error("remmulti needs interface address"); if(!ipismulticast(c->raddr)) error("remmulti for a non multicast address"); if (parseip(ia, cb->f[1]) == -1) error(Ebadip); ipifcremmulti(c, c->raddr, ia); } else if(strcmp(cb->f[0], "maxfragsize") == 0){ if(cb->nf < 2) error("maxfragsize needs size"); c->maxfragsize = (int)strtol(cb->f[1], nil, 0); } else if(x->ctl != nil) { p = x->ctl(c, cb->f, cb->nf); if(p != nil) error(p); } else error("unknown control request"); qunlock(c); free(cb); poperror(); } return n; }