diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/unix/drawterm/kern/devip.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/unix/drawterm/kern/devip.c')
-rwxr-xr-x | sys/src/cmd/unix/drawterm/kern/devip.c | 938 |
1 files changed, 938 insertions, 0 deletions
diff --git a/sys/src/cmd/unix/drawterm/kern/devip.c b/sys/src/cmd/unix/drawterm/kern/devip.c new file mode 100755 index 000000000..f192aebcb --- /dev/null +++ b/sys/src/cmd/unix/drawterm/kern/devip.c @@ -0,0 +1,938 @@ +#include "u.h" +#include "lib.h" +#include "dat.h" +#include "fns.h" +#include "error.h" + +#include "devip.h" + +void hnputl(void *p, unsigned long v); +void hnputs(void *p, unsigned short v); +unsigned long nhgetl(void *p); +unsigned short nhgets(void *p); +unsigned long parseip(char *to, char *from); +void csclose(Chan*); +long csread(Chan*, void*, long, vlong); +long cswrite(Chan*, void*, long, vlong); + +void osipinit(void); + +enum +{ + Qtopdir = 1, /* top level directory */ + Qcs, + Qprotodir, /* directory for a protocol */ + Qclonus, + Qconvdir, /* directory for a conversation */ + Qdata, + Qctl, + Qstatus, + Qremote, + Qlocal, + Qlisten, + + MAXPROTO = 4 +}; +#define TYPE(x) ((int)((x).path & 0xf)) +#define CONV(x) ((int)(((x).path >> 4)&0xfff)) +#define PROTO(x) ((int)(((x).path >> 16)&0xff)) +#define QID(p, c, y) (((p)<<16) | ((c)<<4) | (y)) + +typedef struct Proto Proto; +typedef struct Conv Conv; +struct Conv +{ + int x; + Ref r; + int sfd; + int perm; + char owner[KNAMELEN]; + char* state; + ulong laddr; + ushort lport; + ulong raddr; + ushort rport; + int restricted; + char cerr[KNAMELEN]; + Proto* p; +}; + +struct Proto +{ + Lock l; + int x; + int stype; + char name[KNAMELEN]; + int nc; + int maxconv; + Conv** conv; + Qid qid; +}; + +static int np; +static Proto proto[MAXPROTO]; +int eipfmt(Fmt*); + +static Conv* protoclone(Proto*, char*, int); +static void setladdr(Conv*); + +int +ipgen(Chan *c, char *nname, Dirtab *d, int nd, int s, Dir *dp) +{ + Qid q; + Conv *cv; + char *p; + + USED(nname); + q.vers = 0; + q.type = 0; + switch(TYPE(c->qid)) { + case Qtopdir: + if(s >= 1+np) + return -1; + + if(s == 0){ + q.path = QID(s, 0, Qcs); + devdir(c, q, "cs", 0, "network", 0666, dp); + }else{ + s--; + q.path = QID(s, 0, Qprotodir); + q.type = QTDIR; + devdir(c, q, proto[s].name, 0, "network", DMDIR|0555, dp); + } + return 1; + case Qprotodir: + if(s < proto[PROTO(c->qid)].nc) { + cv = proto[PROTO(c->qid)].conv[s]; + sprint(up->genbuf, "%d", s); + q.path = QID(PROTO(c->qid), s, Qconvdir); + q.type = QTDIR; + devdir(c, q, up->genbuf, 0, cv->owner, DMDIR|0555, dp); + return 1; + } + s -= proto[PROTO(c->qid)].nc; + switch(s) { + default: + return -1; + case 0: + p = "clone"; + q.path = QID(PROTO(c->qid), 0, Qclonus); + break; + } + devdir(c, q, p, 0, "network", 0555, dp); + return 1; + case Qconvdir: + cv = proto[PROTO(c->qid)].conv[CONV(c->qid)]; + switch(s) { + default: + return -1; + case 0: + q.path = QID(PROTO(c->qid), CONV(c->qid), Qdata); + devdir(c, q, "data", 0, cv->owner, cv->perm, dp); + return 1; + case 1: + q.path = QID(PROTO(c->qid), CONV(c->qid), Qctl); + devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp); + return 1; + case 2: + p = "status"; + q.path = QID(PROTO(c->qid), CONV(c->qid), Qstatus); + break; + case 3: + p = "remote"; + q.path = QID(PROTO(c->qid), CONV(c->qid), Qremote); + break; + case 4: + p = "local"; + q.path = QID(PROTO(c->qid), CONV(c->qid), Qlocal); + break; + case 5: + p = "listen"; + q.path = QID(PROTO(c->qid), CONV(c->qid), Qlisten); + break; + } + devdir(c, q, p, 0, cv->owner, 0444, dp); + return 1; + } + return -1; +} + +static void +newproto(char *name, int type, int maxconv) +{ + int l; + Proto *p; + + if(np >= MAXPROTO) { + print("no %s: increase MAXPROTO", name); + return; + } + + p = &proto[np]; + strcpy(p->name, name); + p->stype = type; + p->qid.path = QID(np, 0, Qprotodir); + p->qid.type = QTDIR; + p->x = np++; + p->maxconv = maxconv; + l = sizeof(Conv*)*(p->maxconv+1); + p->conv = mallocz(l, 1); + if(p->conv == 0) + panic("no memory"); +} + +void +ipinit(void) +{ + osipinit(); + + newproto("udp", S_UDP, 10); + newproto("tcp", S_TCP, 30); + + fmtinstall('I', eipfmt); + fmtinstall('E', eipfmt); + +} + +Chan * +ipattach(char *spec) +{ + Chan *c; + + c = devattach('I', spec); + c->qid.path = QID(0, 0, Qtopdir); + c->qid.type = QTDIR; + c->qid.vers = 0; + return c; +} + +static Walkqid* +ipwalk(Chan *c, Chan *nc, char **name, int nname) +{ + return devwalk(c, nc, name, nname, 0, 0, ipgen); +} + +int +ipstat(Chan *c, uchar *dp, int n) +{ + return devstat(c, dp, n, 0, 0, ipgen); +} + +Chan * +ipopen(Chan *c, int omode) +{ + Proto *p; + ulong raddr; + ushort rport; + int perm, sfd; + Conv *cv, *lcv; + + omode &= 3; + perm = 0; + switch(omode) { + case OREAD: + perm = 4; + break; + case OWRITE: + perm = 2; + break; + case ORDWR: + perm = 6; + break; + } + + switch(TYPE(c->qid)) { + default: + break; + case Qtopdir: + case Qprotodir: + case Qconvdir: + case Qstatus: + case Qremote: + case Qlocal: + if(omode != OREAD) + error(Eperm); + break; + case Qclonus: + p = &proto[PROTO(c->qid)]; + cv = protoclone(p, up->user, -1); + if(cv == 0) + error(Enodev); + c->qid.path = QID(p->x, cv->x, Qctl); + c->qid.vers = 0; + break; + case Qdata: + case Qctl: + p = &proto[PROTO(c->qid)]; + lock(&p->l); + cv = p->conv[CONV(c->qid)]; + lock(&cv->r.lk); + if((perm & (cv->perm>>6)) != perm) { + if(strcmp(up->user, cv->owner) != 0 || + (perm & cv->perm) != perm) { + unlock(&cv->r.lk); + unlock(&p->l); + error(Eperm); + } + } + cv->r.ref++; + if(cv->r.ref == 1) { + memmove(cv->owner, up->user, KNAMELEN); + cv->perm = 0660; + } + unlock(&cv->r.lk); + unlock(&p->l); + break; + case Qlisten: + p = &proto[PROTO(c->qid)]; + lcv = p->conv[CONV(c->qid)]; + sfd = so_accept(lcv->sfd, &raddr, &rport); + cv = protoclone(p, up->user, sfd); + if(cv == 0) { + close(sfd); + error(Enodev); + } + cv->raddr = raddr; + cv->rport = rport; + setladdr(cv); + cv->state = "Established"; + c->qid.path = QID(p->x, cv->x, Qctl); + break; + } + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +ipclose(Chan *c) +{ + Conv *cc; + + switch(TYPE(c->qid)) { + case Qcs: + csclose(c); + break; + case Qdata: + case Qctl: + if((c->flag & COPEN) == 0) + break; + cc = proto[PROTO(c->qid)].conv[CONV(c->qid)]; + if(decref(&cc->r) != 0) + break; + strcpy(cc->owner, "network"); + cc->perm = 0666; + cc->state = "Closed"; + cc->laddr = 0; + cc->raddr = 0; + cc->lport = 0; + cc->rport = 0; + close(cc->sfd); + break; + } +} + +long +ipread(Chan *ch, void *a, long n, vlong offset) +{ + int r; + Conv *c; + Proto *x; + uchar ip[4]; + char buf[128], *p; + +/*print("ipread %s %lux\n", c2name(ch), (long)ch->qid.path);*/ + p = a; + switch(TYPE(ch->qid)) { + default: + error(Eperm); + case Qcs: + return csread(ch, a, n, offset); + case Qprotodir: + case Qtopdir: + case Qconvdir: + return devdirread(ch, a, n, 0, 0, ipgen); + case Qctl: + sprint(buf, "%d", CONV(ch->qid)); + return readstr(offset, p, n, buf); + case Qremote: + c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; + hnputl(ip, c->raddr); + sprint(buf, "%I!%d\n", ip, c->rport); + return readstr(offset, p, n, buf); + case Qlocal: + c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; + hnputl(ip, c->laddr); + sprint(buf, "%I!%d\n", ip, c->lport); + return readstr(offset, p, n, buf); + case Qstatus: + x = &proto[PROTO(ch->qid)]; + c = x->conv[CONV(ch->qid)]; + sprint(buf, "%s/%d %d %s \n", + c->p->name, c->x, c->r.ref, c->state); + return readstr(offset, p, n, buf); + case Qdata: + c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; + r = so_recv(c->sfd, a, n, 0); + if(r < 0){ + oserrstr(); + nexterror(); + } + return r; + } +} + +static void +setladdr(Conv *c) +{ + so_getsockname(c->sfd, &c->laddr, &c->lport); +} + +static void +setlport(Conv *c) +{ + if(c->restricted == 0 && c->lport == 0) + return; + + so_bind(c->sfd, c->restricted, c->lport); +} + +static void +setladdrport(Conv *c, char *str) +{ + char *p, addr[4]; + + p = strchr(str, '!'); + if(p == 0) { + p = str; + c->laddr = 0; + } + else { + *p++ = 0; + parseip(addr, str); + c->laddr = nhgetl((uchar*)addr); + } + if(*p == '*') + c->lport = 0; + else + c->lport = atoi(p); + + setlport(c); +} + +static char* +setraddrport(Conv *c, char *str) +{ + char *p, addr[4]; + + p = strchr(str, '!'); + if(p == 0) + return "malformed address"; + *p++ = 0; + parseip(addr, str); + c->raddr = nhgetl((uchar*)addr); + c->rport = atoi(p); + p = strchr(p, '!'); + if(p) { + if(strcmp(p, "!r") == 0) + c->restricted = 1; + } + return 0; +} + +long +ipwrite(Chan *ch, void *a, long n, vlong offset) +{ + Conv *c; + Proto *x; + int r, nf; + char *p, *fields[3], buf[128]; + + switch(TYPE(ch->qid)) { + default: + error(Eperm); + case Qcs: + return cswrite(ch, a, n, offset); + case Qctl: + x = &proto[PROTO(ch->qid)]; + c = x->conv[CONV(ch->qid)]; + if(n > sizeof(buf)-1) + n = sizeof(buf)-1; + memmove(buf, a, n); + buf[n] = '\0'; + + nf = tokenize(buf, fields, 3); + if(strcmp(fields[0], "connect") == 0){ + switch(nf) { + default: + error("bad args to connect"); + case 2: + p = setraddrport(c, fields[1]); + if(p != 0) + error(p); + break; + case 3: + p = setraddrport(c, fields[1]); + if(p != 0) + error(p); + c->lport = atoi(fields[2]); + setlport(c); + break; + } + so_connect(c->sfd, c->raddr, c->rport); + setladdr(c); + c->state = "Established"; + return n; + } + if(strcmp(fields[0], "announce") == 0) { + switch(nf){ + default: + error("bad args to announce"); + case 2: + setladdrport(c, fields[1]); + break; + } + so_listen(c->sfd); + c->state = "Announced"; + return n; + } + if(strcmp(fields[0], "bind") == 0){ + switch(nf){ + default: + error("bad args to bind"); + case 2: + c->lport = atoi(fields[1]); + break; + } + setlport(c); + return n; + } + error("bad control message"); + case Qdata: + x = &proto[PROTO(ch->qid)]; + c = x->conv[CONV(ch->qid)]; + r = so_send(c->sfd, a, n, 0); + if(r < 0){ + oserrstr(); + nexterror(); + } + return r; + } + return n; +} + +static Conv* +protoclone(Proto *p, char *user, int nfd) +{ + Conv *c, **pp, **ep; + + c = 0; + lock(&p->l); + if(waserror()) { + unlock(&p->l); + nexterror(); + } + ep = &p->conv[p->maxconv]; + for(pp = p->conv; pp < ep; pp++) { + c = *pp; + if(c == 0) { + c = mallocz(sizeof(Conv), 1); + if(c == 0) + error(Enomem); + lock(&c->r.lk); + c->r.ref = 1; + c->p = p; + c->x = pp - p->conv; + p->nc++; + *pp = c; + break; + } + lock(&c->r.lk); + if(c->r.ref == 0) { + c->r.ref++; + break; + } + unlock(&c->r.lk); + } + if(pp >= ep) { + unlock(&p->l); + poperror(); + return 0; + } + + strcpy(c->owner, user); + c->perm = 0660; + c->state = "Closed"; + c->restricted = 0; + c->laddr = 0; + c->raddr = 0; + c->lport = 0; + c->rport = 0; + c->sfd = nfd; + if(nfd == -1) + c->sfd = so_socket(p->stype); + + unlock(&c->r.lk); + unlock(&p->l); + poperror(); + return c; +} + +enum +{ + Isprefix= 16, +}; + +uchar prefixvals[256] = +{ +/*0x00*/ 0 | Isprefix, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0x30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0x40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0x50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0x60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0x70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0x80*/ 1 | Isprefix, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0x90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0xA0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0xB0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0xC0*/ 2 | Isprefix, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0xD0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0xE0*/ 3 | Isprefix, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0xF0*/ 4 | Isprefix, + 0, 0, 0, 0, 0, 0, 0, +/*0xF8*/ 5 | Isprefix, + 0, 0, 0, +/*0xFC*/ 6 | Isprefix, + 0, +/*0xFE*/ 7 | Isprefix, +/*0xFF*/ 8 | Isprefix, +}; + +int +eipfmt(Fmt *f) +{ + char buf[5*8]; + static char *efmt = "%.2lux%.2lux%.2lux%.2lux%.2lux%.2lux"; + static char *ifmt = "%d.%d.%d.%d"; + uchar *p, ip[16]; + ulong ul; + + switch(f->r) { + case 'E': /* Ethernet address */ + p = va_arg(f->args, uchar*); + snprint(buf, sizeof buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]); + return fmtstrcpy(f, buf); + + case 'I': + ul = va_arg(f->args, ulong); + hnputl(ip, ul); + snprint(buf, sizeof buf, ifmt, ip[0], ip[1], ip[2], ip[3]); + return fmtstrcpy(f, buf); + } + return fmtstrcpy(f, "(eipfmt)"); +} + +void +hnputl(void *p, unsigned long v) +{ + unsigned char *a; + + a = p; + a[0] = v>>24; + a[1] = v>>16; + a[2] = v>>8; + a[3] = v; +} + +void +hnputs(void *p, unsigned short v) +{ + unsigned char *a; + + a = p; + a[0] = v>>8; + a[1] = v; +} + +unsigned long +nhgetl(void *p) +{ + unsigned char *a; + a = p; + return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0); +} + +unsigned short +nhgets(void *p) +{ + unsigned char *a; + a = p; + return (a[0]<<8)|(a[1]<<0); +} + +#define CLASS(p) ((*(unsigned char*)(p))>>6) + +unsigned long +parseip(char *to, char *from) +{ + int i; + char *p; + + p = from; + memset(to, 0, 4); + for(i = 0; i < 4 && *p; i++){ + to[i] = strtoul(p, &p, 10); + if(*p != '.' && *p != 0){ + memset(to, 0, 4); + return 0; + } + if(*p == '.') + p++; + } + switch(CLASS(to)){ + case 0: /* class A - 1 byte net */ + case 1: + if(i == 3){ + to[3] = to[2]; + to[2] = to[1]; + to[1] = 0; + } else if (i == 2){ + to[3] = to[1]; + to[1] = 0; + } + break; + case 2: /* class B - 2 byte net */ + if(i == 3){ + to[3] = to[2]; + to[2] = 0; + } + break; + } + return nhgetl(to); +} + +void +csclose(Chan *c) +{ + free(c->aux); +} + +long +csread(Chan *c, void *a, long n, vlong offset) +{ + if(c->aux == nil) + return 0; + return readstr(offset, a, n, c->aux); +} + +static struct +{ + char *name; + uint num; +} tab[] = { + "cs", 1, + "echo", 7, + "discard", 9, + "systat", 11, + "daytime", 13, + "netstat", 15, + "chargen", 19, + "ftp-data", 20, + "ftp", 21, + "ssh", 22, + "telnet", 23, + "smtp", 25, + "time", 37, + "whois", 43, + "dns", 53, + "domain", 53, + "uucp", 64, + "gopher", 70, + "rje", 77, + "finger", 79, + "http", 80, + "link", 87, + "supdup", 95, + "hostnames", 101, + "iso-tsap", 102, + "x400", 103, + "x400-snd", 104, + "csnet-ns", 105, + "pop-2", 109, + "pop3", 110, + "portmap", 111, + "uucp-path", 117, + "nntp", 119, + "netbios", 139, + "imap4", 143, + "NeWS", 144, + "print-srv", 170, + "z39.50", 210, + "fsb", 400, + "sysmon", 401, + "proxy", 402, + "proxyd", 404, + "https", 443, + "cifs", 445, + "ssmtp", 465, + "rexec", 512, + "login", 513, + "shell", 514, + "printer", 515, + "courier", 530, + "cscan", 531, + "uucp", 540, + "snntp", 563, + "9fs", 564, + "whoami", 565, + "guard", 566, + "ticket", 567, + "dlsftp", 666, + "fmclient", 729, + "imaps", 993, + "pop3s", 995, + "ingreslock", 1524, + "pptp", 1723, + "nfs", 2049, + "webster", 2627, + "weather", 3000, + "secstore", 5356, + "Xdisplay", 6000, + "styx", 6666, + "mpeg", 6667, + "rstyx", 6668, + "infdb", 6669, + "infsigner", 6671, + "infcsigner", 6672, + "inflogin", 6673, + "bandt", 7330, + "face", 32000, + "dhashgate", 11978, + "exportfs", 17007, + "rexexec", 17009, + "ncpu", 17010, + "cpu", 17013, + "glenglenda1", 17020, + "glenglenda2", 17021, + "glenglenda3", 17022, + "glenglenda4", 17023, + "glenglenda5", 17024, + "glenglenda6", 17025, + "glenglenda7", 17026, + "glenglenda8", 17027, + "glenglenda9", 17028, + "glenglenda10", 17029, + "flyboy", 17032, + "dlsftp", 17033, + "venti", 17034, + "wiki", 17035, + "vica", 17036, + 0 +}; + +static int +lookupport(char *s) +{ + int i; + char buf[10], *p; + + i = strtol(s, &p, 0); + if(*s && *p == 0) + return i; + + i = so_getservbyname(s, "tcp", buf); + if(i != -1) + return atoi(buf); + for(i=0; tab[i].name; i++) + if(strcmp(s, tab[i].name) == 0) + return tab[i].num; + return 0; +} + +static ulong +lookuphost(char *s) +{ + char to[4]; + ulong ip; + + memset(to, 0, sizeof to); + parseip(to, s); + ip = nhgetl(to); + if(ip != 0) + return ip; + if((s = hostlookup(s)) == nil) + return 0; + parseip(to, s); + ip = nhgetl(to); + free(s); + return ip; +} + +long +cswrite(Chan *c, void *a, long n, vlong offset) +{ + char *f[4]; + char *s, *ns; + ulong ip; + int nf, port; + + s = malloc(n+1); + if(s == nil) + error(Enomem); + if(waserror()){ + free(s); + nexterror(); + } + memmove(s, a, n); + s[n] = 0; + nf = getfields(s, f, nelem(f), 0, "!"); + if(nf != 3) + error("can't translate"); + + port = lookupport(f[2]); + if(port <= 0) + error("no translation for port found"); + + ip = lookuphost(f[1]); + if(ip == 0) + error("no translation for host found"); + + ns = smprint("/net/%s/clone %I!%d", f[0], ip, port); + if(ns == nil) + error(Enomem); + free(c->aux); + c->aux = ns; + poperror(); + free(s); + return n; +} + +Dev ipdevtab = +{ + 'I', + "ip", + + devreset, + ipinit, + devshutdown, + ipattach, + ipwalk, + ipstat, + ipopen, + devcreate, + ipclose, + ipread, + devbread, + ipwrite, + devbwrite, + devremove, + devwstat, +}; + |