ref: e825af37ac4e6fd8fe73d8df6048b7ee304805ea
parent: fe00d007d93413d37e138202ace03eb6a2b59748
author: halfwit <michaelmisch1985@gmail.com>
date: Sat Mar 2 02:39:38 PST 2024
ip gives us access to dial and friends
--- a/Makefile
+++ b/Makefile
@@ -12,6 +12,7 @@
LIBS1=\
kern/libkern.a\
rc/librc.a\
+ libip/libip.a\
libmemdraw/libmemdraw.a\
libmemlayer/libmemlayer.a\
libdraw/libdraw.a\
@@ -34,7 +35,9 @@
kern/libkern.a:
(cd kern; $(MAKE))
-
+libip/libip.a:
+ (cd libip; $(MAKE))
+
libmemdraw/libmemdraw.a:
(cd libmemdraw; $(MAKE))
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
DESCRIPTION
-----------
-This is a fork of Russ Cox's drawterm and plan9front's drawterm that listens for incoming rcpu requests, instead of making one itself
+This is a fork of Russ Cox's drawterm and plan9front's drawterm that listens for incoming rcpu requests, instead of making one itself. It has rc with enough builtins that run inside the kernel for a typical session
INSTALLATION
--- a/TODO
+++ b/TODO
@@ -2,15 +2,20 @@
- [x]' read'
- [ ] 'write' ?
- [x] 'ls'
- - [x] 'mount'
+ - [x] 'cat'
+ - [ ] 'srv' ?
+ - [~] 'mount' - DEBUG: spin up an exportfs on 9, dial() in our mount call to it to use as our fd to get output
- [x] 'bind'
- [ ] 'mkdir'
- - [ ] 'rm'
+ - [x] 'rm'
- [ ] 'unmount'
- [ ] 'ns'
+ - [~] 'test' - only -d and maybe -f for now
+ - [x] 'echo'
+ - [ ] 'cp'
TODO:
- - [ ] Install rcmain properly on system, refer to it as needed
+ - [x] Install rcmain properly on system, refer to it as needed
- [ ] have it export a var service=unix
- [ ] Some people probably want aan?
- [x] Move rc code to use our libc.h, u.h everywhere so our defs of open + such are correct
@@ -37,6 +42,7 @@
- devcons - #c: needed, /dev/cons
- devenv - #e: needed, /dev/env
- devfs - #U: needed, local files
+ - devlfd - #L: needed, /fd
- devip - #I: !needed, networking
- devlfd - #L: !needed
- devmnt - #M: needed, client shares
@@ -44,4 +50,5 @@
- devroot - #/: needed, base of stack
- devssl - #D: !needed, ssl
- devtls - #a: !needed, tls
+ - devproc - #p: needed, /dev/proc, overlay any existing
- devtab - meta, needed - add/remove any devices that we add/remove, from here as well
--- /dev/null
+++ b/include/ip.h
@@ -1,0 +1,38 @@
+enum
+{
+ IPaddrlen= 16,
+ IPv4addrlen= 4,
+ IPv4off= 12,
+};
+
+uchar* defmask(uchar*);
+void maskip(uchar*, uchar*, uchar*);
+int eipfmt(Fmt*);
+int isv4(uchar*);
+vlong parseip(uchar*, char*);
+vlong parseipmask(uchar*, char*, int);
+vlong parseipandmask(uchar*, uchar*, char*, char*);
+char* v4parseip(uchar*, char*);
+
+void hnputv(void*, uvlong);
+void hnputl(void*, uint);
+void hnputs(void*, ushort);
+uvlong nhgetv(void*);
+uint nhgetl(void*);
+ushort nhgets(void*);
+
+int v6tov4(uchar*, uchar*);
+void v4tov6(uchar*, uchar*);
+
+#define ipcmp(x, y) memcmp(x, y, IPaddrlen)
+#define ipmove(x, y) memmove(x, y, IPaddrlen)
+
+extern uchar IPv4bcast[IPaddrlen];
+extern uchar IPv4bcastobs[IPaddrlen];
+extern uchar IPv4allsys[IPaddrlen];
+extern uchar IPv4allrouter[IPaddrlen];
+extern uchar IPnoaddr[IPaddrlen];
+extern uchar v4prefix[IPaddrlen];
+extern uchar IPallbits[IPaddrlen];
+
+#define CLASS(p) ((*(uchar*)(p))>>6)
--- a/kern/Makefile
+++ b/kern/Makefile
@@ -14,6 +14,8 @@
devenv.$O\
devfs-$(OS).$O\
devlfd-$(OS).$O\
+ devip-$(OS).$O\
+ devip.$O\
devmnt.$O\
devpipe.$O\
devroot.$O\
--- /dev/null
+++ b/kern/devip-posix.c
@@ -1,0 +1,259 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include "u.h"
+#include "lib.h"
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+#include "ip.h"
+
+#include "devip.h"
+
+#undef listen
+#undef accept
+#undef bind
+
+static int
+family(unsigned char *addr)
+{
+ if(isv4(addr))
+ return AF_INET;
+ return AF_INET6;
+}
+
+static int
+addrlen(struct sockaddr_storage *ss)
+{
+ switch(ss->ss_family){
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+ }
+ return 0;
+}
+
+void
+osipinit(void)
+{
+ char buf[1024];
+ gethostname(buf, sizeof(buf));
+ kstrdup(&sysname, buf);
+
+}
+
+int
+so_socket(int type, unsigned char *addr)
+{
+ int fd, one;
+
+ switch(type) {
+ default:
+ error("bad protocol type");
+ case S_TCP:
+ type = SOCK_STREAM;
+ break;
+ case S_UDP:
+ type = SOCK_DGRAM;
+ break;
+ }
+
+ fd = socket(family(addr), type, 0);
+ if(fd < 0)
+ oserror();
+
+ one = 1;
+ if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) > 0){
+ oserrstr();
+ print("setsockopt: %r");
+ }
+
+ return fd;
+}
+
+void
+so_connect(int fd, unsigned char *raddr, unsigned short rport)
+{
+ struct sockaddr_storage ss;
+
+ memset(&ss, 0, sizeof(ss));
+
+ ss.ss_family = family(raddr);
+
+ switch(ss.ss_family){
+ case AF_INET:
+ hnputs(&((struct sockaddr_in*)&ss)->sin_port, rport);
+ v6tov4((unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr, raddr);
+ break;
+ case AF_INET6:
+ hnputs(&((struct sockaddr_in6*)&ss)->sin6_port, rport);
+ memcpy(&((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, raddr, sizeof(struct in6_addr));
+ break;
+ }
+
+ if(connect(fd, (struct sockaddr*)&ss, addrlen(&ss)) < 0)
+ oserror();
+}
+
+void
+so_getsockname(int fd, unsigned char *laddr, unsigned short *lport)
+{
+ socklen_t len;
+ struct sockaddr_storage ss;
+
+ len = sizeof(ss);
+ if(getsockname(fd, (struct sockaddr*)&ss, &len) < 0)
+ oserror();
+
+ switch(ss.ss_family){
+ case AF_INET:
+ v4tov6(laddr, (unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr);
+ *lport = nhgets(&((struct sockaddr_in*)&ss)->sin_port);
+ break;
+ case AF_INET6:
+ memcpy(laddr, &((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, sizeof(struct in6_addr));
+ *lport = nhgets(&((struct sockaddr_in6*)&ss)->sin6_port);
+ break;
+ default:
+ error("not AF_INET or AF_INET6");
+ }
+}
+
+void
+so_listen(int fd)
+{
+ if(listen(fd, 5) < 0)
+ oserror();
+}
+
+int
+so_accept(int fd, unsigned char *raddr, unsigned short *rport)
+{
+ int nfd;
+ socklen_t len;
+ struct sockaddr_storage ss;
+
+ len = sizeof(ss);
+ nfd = accept(fd, (struct sockaddr*)&ss, &len);
+ if(nfd < 0)
+ oserror();
+
+ switch(ss.ss_family){
+ case AF_INET:
+ v4tov6(raddr, (unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr);
+ *rport = nhgets(&((struct sockaddr_in*)&ss)->sin_port);
+ break;
+ case AF_INET6:
+ memcpy(raddr, &((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, sizeof(struct in6_addr));
+ *rport = nhgets(&((struct sockaddr_in6*)&ss)->sin6_port);
+ break;
+ default:
+ error("not AF_INET or AF_INET6");
+ }
+ return nfd;
+}
+
+void
+so_bind(int fd, int su, unsigned short port, unsigned char *addr)
+{
+ int i, one;
+ struct sockaddr_storage ss;
+
+ one = 1;
+ if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0){
+ oserrstr();
+ print("setsockopt: %r");
+ }
+
+ if(su) {
+ for(i = 600; i < 1024; i++) {
+ memset(&ss, 0, sizeof(ss));
+ ss.ss_family = family(addr);
+
+ switch(ss.ss_family){
+ case AF_INET:
+ ((struct sockaddr_in*)&ss)->sin_port = i;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6*)&ss)->sin6_port = i;
+ break;
+ }
+
+ if(bind(fd, (struct sockaddr*)&ss, addrlen(&ss)) >= 0)
+ return;
+ }
+ oserror();
+ }
+
+ memset(&ss, 0, sizeof(ss));
+ ss.ss_family = family(addr);
+
+ switch(ss.ss_family){
+ case AF_INET:
+ hnputs(&((struct sockaddr_in*)&ss)->sin_port, port);
+ break;
+ case AF_INET6:
+ hnputs(&((struct sockaddr_in6*)&ss)->sin6_port, port);
+ break;
+ }
+
+ if(bind(fd, (struct sockaddr*)&ss, addrlen(&ss)) < 0)
+ oserror();
+}
+
+int
+so_gethostbyname(char *host, char **hostv, int n)
+{
+ char buf[INET6_ADDRSTRLEN];
+ struct addrinfo *r, *p;
+ int i;
+
+ r = NULL;
+ if(getaddrinfo(host, NULL, NULL, &r))
+ return 0;
+ for(i = 0, p = r; i < n && p != NULL; p = p->ai_next){
+ switch (p->ai_family) {
+ default:
+ continue;
+ case AF_INET:
+ inet_ntop(AF_INET, &((struct sockaddr_in*)p->ai_addr)->sin_addr, buf, sizeof(buf));
+ break;
+ case AF_INET6:
+ inet_ntop(AF_INET6, &((struct sockaddr_in6*)p->ai_addr)->sin6_addr, buf, sizeof(buf));
+ break;
+ }
+ hostv[i++] = strdup(buf);
+ }
+ freeaddrinfo(r);
+ return i;
+}
+
+int
+so_getservbyname(char *service, char *net, char *port)
+{
+ struct servent *s;
+
+ s = getservbyname(service, net);
+ if(s == 0)
+ return -1;
+
+ sprint(port, "%d", nhgets(&s->s_port));
+ return 0;
+}
+
+int
+so_send(int fd, void *d, int n, int f)
+{
+ return send(fd, d, n, f);
+}
+
+int
+so_recv(int fd, void *d, int n, int f)
+{
+ return recv(fd, d, n, f);
+}
--- /dev/null
+++ b/kern/devip-win32.c
@@ -1,0 +1,265 @@
+#define _WIN32_WINNT 0x0501
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+#include "u.h"
+#include "lib.h"
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+#include "ip.h"
+
+#include "devip.h"
+
+#ifdef MSVC
+#pragma comment(lib, "wsock32.lib")
+#endif
+
+#undef listen
+#undef accept
+#undef bind
+
+static int
+family(unsigned char *addr)
+{
+ if(isv4(addr))
+ return AF_INET;
+ return AF_INET6;
+}
+
+static int
+addrlen(struct sockaddr_storage *ss)
+{
+ switch(ss->ss_family){
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+ }
+ return 0;
+}
+
+void
+osipinit(void)
+{
+ WSADATA wasdat;
+ char buf[1024];
+
+ if(WSAStartup(MAKEWORD(1, 1), &wasdat) != 0)
+ panic("no winsock.dll");
+
+ gethostname(buf, sizeof(buf));
+ kstrdup(&sysname, buf);
+}
+
+int
+so_socket(int type, unsigned char *addr)
+{
+ int fd, one;
+
+ switch(type) {
+ default:
+ error("bad protocol type");
+ case S_TCP:
+ type = SOCK_STREAM;
+ break;
+ case S_UDP:
+ type = SOCK_DGRAM;
+ break;
+ }
+
+ fd = socket(family(addr), type, 0);
+ if(fd < 0)
+ oserror();
+
+ one = 1;
+ if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) > 0){
+ oserrstr();
+ print("setsockopt: %s\n", up->errstr);
+ }
+
+ return fd;
+}
+
+
+void
+so_connect(int fd, unsigned char *raddr, unsigned short rport)
+{
+ struct sockaddr_storage ss;
+
+ memset(&ss, 0, sizeof(ss));
+
+ ss.ss_family = family(raddr);
+
+ switch(ss.ss_family){
+ case AF_INET:
+ hnputs(&((struct sockaddr_in*)&ss)->sin_port, rport);
+ v6tov4((unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr, raddr);
+ break;
+ case AF_INET6:
+ hnputs(&((struct sockaddr_in6*)&ss)->sin6_port, rport);
+ memcpy(&((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, raddr, sizeof(struct in6_addr));
+ break;
+ }
+
+ if(connect(fd, (struct sockaddr*)&ss, addrlen(&ss)) < 0)
+ oserror();
+}
+
+void
+so_getsockname(int fd, unsigned char *laddr, unsigned short *lport)
+{
+ int len;
+ struct sockaddr_storage ss;
+
+ len = sizeof(ss);
+ if(getsockname(fd, (struct sockaddr*)&ss, &len) < 0)
+ oserror();
+
+ switch(ss.ss_family){
+ case AF_INET:
+ v4tov6(laddr, (unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr);
+ *lport = nhgets(&((struct sockaddr_in*)&ss)->sin_port);
+ break;
+ case AF_INET6:
+ memcpy(laddr, &((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, sizeof(struct in6_addr));
+ *lport = nhgets(&((struct sockaddr_in6*)&ss)->sin6_port);
+ break;
+ default:
+ error("not AF_INET or AF_INET6");
+ }
+}
+
+void
+so_listen(int fd)
+{
+ if(listen(fd, 5) < 0)
+ oserror();
+}
+
+int
+so_accept(int fd, unsigned char *raddr, unsigned short *rport)
+{
+ int nfd;
+ int len;
+ struct sockaddr_storage ss;
+
+ len = sizeof(ss);
+ nfd = accept(fd, (struct sockaddr*)&ss, &len);
+ if(nfd < 0)
+ oserror();
+
+ switch(ss.ss_family){
+ case AF_INET:
+ v4tov6(raddr, (unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr);
+ *rport = nhgets(&((struct sockaddr_in*)&ss)->sin_port);
+ break;
+ case AF_INET6:
+ memcpy(raddr, &((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, sizeof(struct in6_addr));
+ *rport = nhgets(&((struct sockaddr_in6*)&ss)->sin6_port);
+ break;
+ default:
+ error("not AF_INET or AF_INET6");
+ }
+ return nfd;
+}
+
+void
+so_bind(int fd, int su, unsigned short port, unsigned char *addr)
+{
+ int i, one;
+ struct sockaddr_storage ss;
+
+ one = 1;
+ if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0){
+ oserrstr();
+ print("setsockopt: %r");
+ }
+
+ if(su) {
+ for(i = 600; i < 1024; i++) {
+ memset(&ss, 0, sizeof(ss));
+ ss.ss_family = family(addr);
+
+ switch(ss.ss_family){
+ case AF_INET:
+ ((struct sockaddr_in*)&ss)->sin_port = i;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6*)&ss)->sin6_port = i;
+ break;
+ }
+
+ if(bind(fd, (struct sockaddr*)&ss, addrlen(&ss)) >= 0)
+ return;
+ }
+ oserror();
+ }
+
+ memset(&ss, 0, sizeof(ss));
+ ss.ss_family = family(addr);
+
+ switch(ss.ss_family){
+ case AF_INET:
+ hnputs(&((struct sockaddr_in*)&ss)->sin_port, port);
+ break;
+ case AF_INET6:
+ hnputs(&((struct sockaddr_in6*)&ss)->sin6_port, port);
+ break;
+ }
+
+ if(bind(fd, (struct sockaddr*)&ss, addrlen(&ss)) < 0)
+ oserror();
+}
+
+int
+so_gethostbyname(char *host, char **hostv, int n)
+{
+ char buf[INET6_ADDRSTRLEN];
+ struct addrinfo *r, *p;
+ DWORD l;
+ int i;
+
+ r = NULL;
+ if(getaddrinfo(host, NULL, NULL, &r))
+ return 0;
+ for(i = 0, p = r; i < n && p != NULL; p = p->ai_next){
+ switch (p->ai_family) {
+ default:
+ continue;
+ case AF_INET:
+ case AF_INET6:
+ l = sizeof(buf);
+ WSAAddressToStringA(p->ai_addr, p->ai_addrlen, NULL, buf, &l);
+ break;
+ }
+ hostv[i++] = strdup(buf);
+ }
+ freeaddrinfo(r);
+ return i;
+}
+
+int
+so_getservbyname(char *service, char *net, char *port)
+{
+ struct servent *s;
+
+ s = getservbyname(service, net);
+ if(s == 0)
+ return -1;
+
+ sprint(port, "%d", nhgets(&s->s_port));
+ return 0;
+}
+
+int
+so_send(int fd, void *d, int n, int f)
+{
+ return send(fd, d, n, f);
+}
+
+int
+so_recv(int fd, void *d, int n, int f)
+{
+ return recv(fd, d, n, f);
+}
--- /dev/null
+++ b/kern/devip.c
@@ -1,0 +1,870 @@
+#include "u.h"
+#include "lib.h"
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+#include "ip.h"
+
+#include "devip.h"
+
+void csclose(Chan*);
+long csread(Chan*, void*, long, vlong);
+long cswrite(Chan*, void*, long, vlong);
+
+void osipinit(void);
+
+enum
+{
+ Qtopdir = 1, /* top level directory */
+ Qtopbase,
+ Qcs = Qtopbase,
+
+ Qprotodir, /* directory for a protocol */
+ Qprotobase,
+ Qclone = Qprotobase,
+
+ Qconvdir, /* directory for a conversation */
+ Qconvbase,
+ Qctl = Qconvbase,
+ Qdata,
+ 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))
+#define ipzero(x) memset(x, 0, IPaddrlen)
+
+typedef struct Proto Proto;
+typedef struct Conv Conv;
+struct Conv
+{
+ int x;
+ Ref r;
+ int sfd;
+ int perm;
+ char owner[KNAMELEN];
+ char* state;
+ uchar laddr[IPaddrlen];
+ ushort lport;
+ uchar raddr[IPaddrlen];
+ 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];
+
+static Conv* protoclone(Proto*, char*, int);
+static void setladdr(Conv*);
+
+static char network[] = "network";
+
+static int
+ip3gen(Chan *c, int i, Dir *dp)
+{
+ Qid q;
+ Conv *cv;
+ char *p;
+
+ cv = proto[PROTO(c->qid)].conv[CONV(c->qid)];
+ mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE);
+
+ switch(i) {
+ default:
+ return -1;
+ case Qctl:
+ devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
+ return 1;
+ case Qdata:
+ devdir(c, q, "data", 0, cv->owner, cv->perm, dp);
+ return 1;
+ case Qlisten:
+ devdir(c, q, "listen", 0, cv->owner, cv->perm, dp);
+ return 1;
+ case Qlocal:
+ p = "local";
+ break;
+ case Qremote:
+ p = "remote";
+ break;
+ case Qstatus:
+ p = "status";
+ break;
+ }
+ devdir(c, q, p, 0, cv->owner, 0444, dp);
+ return 1;
+}
+
+static int
+ip2gen(Chan *c, int i, Dir *dp)
+{
+ Qid q;
+
+ switch(i) {
+ case Qclone:
+ mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE);
+ devdir(c, q, "clone", 0, network, 0666, dp);
+ return 1;
+ }
+ return -1;
+}
+
+static int
+ip1gen(Chan *c, int i, Dir *dp)
+{
+ Qid q;
+ char *p;
+ int prot;
+ int len = 0;
+
+ prot = 0666;
+ mkqid(&q, QID(0, 0, i), 0, QTFILE);
+ switch(i) {
+ default:
+ return -1;
+ case Qcs:
+ p = "cs";
+ prot = 0664;
+ break;
+ }
+ devdir(c, q, p, len, network, prot, dp);
+ return 1;
+}
+
+static int
+ipgen(Chan *c, char *nname, Dirtab *d, int nd, int s, Dir *dp)
+{
+ Qid q;
+ Conv *cv;
+
+ switch(TYPE(c->qid)) {
+ case Qtopdir:
+ if(s == DEVDOTDOT){
+ mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
+ snprint(up->genbuf, sizeof up->genbuf, "#I%lud", c->dev);
+ devdir(c, q, up->genbuf, 0, network, 0555, dp);
+ return 1;
+ }
+ if(s < np) {
+ mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
+ devdir(c, q, proto[s].name, 0, network, 0555, dp);
+ return 1;
+ }
+ s -= np;
+ return ip1gen(c, s+Qtopbase, dp);
+ case Qcs:
+ return ip1gen(c, TYPE(c->qid), dp);
+ case Qprotodir:
+ if(s == DEVDOTDOT){
+ mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
+ snprint(up->genbuf, sizeof up->genbuf, "#I%lud", c->dev);
+ devdir(c, q, up->genbuf, 0, network, 0555, dp);
+ return 1;
+ }
+ if(s < proto[PROTO(c->qid)].nc) {
+ cv = proto[PROTO(c->qid)].conv[s];
+ snprint(up->genbuf, sizeof up->genbuf, "%d", s);
+ mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR);
+ devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp);
+ return 1;
+ }
+ s -= proto[PROTO(c->qid)].nc;
+ return ip2gen(c, s+Qprotobase, dp);
+ case Qclone:
+ return ip2gen(c, TYPE(c->qid), dp);
+ case Qconvdir:
+ if(s == DEVDOTDOT){
+ s = PROTO(c->qid);
+ mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
+ devdir(c, q, proto[s].name, 0, network, 0555, dp);
+ return 1;
+ }
+ return ip3gen(c, s+Qconvbase, dp);
+ case Qctl:
+ case Qdata:
+ case Qlisten:
+ case Qlocal:
+ case Qremote:
+ case Qstatus:
+ return ip3gen(c, TYPE(c->qid), dp);
+ }
+ 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;
+ uchar raddr[IPaddrlen];
+ 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 Qclone:
+ 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);
+ }
+ ipmove(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";
+ ipzero(cc->laddr);
+ ipzero(cc->raddr);
+ 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[IPaddrlen];
+ char buf[128], *p;
+
+/*print("ipread %s %lux\n", chanpath(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)];
+ ipmove(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)];
+ ipmove(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;
+
+ if(c->sfd == -1)
+ c->sfd = so_socket(c->p->stype, c->laddr);
+
+ so_bind(c->sfd, c->restricted, c->lport, c->laddr);
+}
+
+static void
+setladdrport(Conv *c, char *str)
+{
+ char *p;
+ uchar addr[IPaddrlen];
+
+ p = strchr(str, '!');
+ if(p == 0) {
+ p = str;
+ ipzero(c->laddr);
+ }
+ else {
+ *p++ = 0;
+ parseip(addr, str);
+ ipmove(c->laddr, addr);
+ }
+ if(*p == '*')
+ c->lport = 0;
+ else
+ c->lport = atoi(p);
+
+ setlport(c);
+}
+
+static char*
+setraddrport(Conv *c, char *str)
+{
+ char *p;
+ uchar addr[IPaddrlen];
+
+ p = strchr(str, '!');
+ if(p == 0)
+ return "malformed address";
+ *p++ = 0;
+ parseip(addr, str);
+ ipmove(c->raddr, 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;
+ }
+ if(c->sfd == -1)
+ c->sfd = so_socket(c->p->stype, c->raddr);
+ 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;
+ ipzero(c->laddr);
+ ipzero(c->raddr);
+ c->lport = 0;
+ c->rport = 0;
+ c->sfd = nfd;
+
+ unlock(&c->r.lk);
+ unlock(&p->l);
+ poperror();
+ return c;
+}
+
+void
+csclose(Chan *c)
+{
+ free(c->aux);
+ c->aux = nil;
+}
+
+long
+csread(Chan *c, void *a, long n, vlong offset)
+{
+ char *s, *e, *p;
+
+ s = c->aux;
+ if(s == nil)
+ return 0;
+ e = strchr(s, 0);
+ s += offset;
+ if(s >= e)
+ return 0;
+ p = strchr(s, '\n');
+ if(p != nil)
+ p++;
+ else
+ p = e;
+ if(p - s < n)
+ n = p - s;
+ memmove(a, s, n);
+ return n;
+}
+
+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,
+ "rcpu", 17019,
+ "t9fs", 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;
+}
+
+long
+cswrite(Chan *c, void *a, long n, vlong offset)
+{
+ char *f[4], *ips[8];
+ char *s, *ns;
+ uchar ip[IPaddrlen];
+ int i, nf, port, nips;
+
+ 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");
+ if(strcmp(f[0], "net") == 0)
+ f[0] = "tcp";
+ if(strcmp(f[1], "*") == 0){
+ ns = smprint("/net/%s/clone %d", f[0], port);
+ } else {
+ if(parseip(ip, f[1]) != -1){
+ ips[0] = smprint("%I", ip);
+ nips = 1;
+ } else {
+ nips = so_gethostbyname(f[1], ips, nelem(ips));
+ if(nips <= 0)
+ error("no translation for host found");
+ }
+ ns = smprint("/net/%s/clone %s!%d", f[0], ips[0], port);
+ free(ips[0]);
+ for(i=1; i<nips; i++){
+ ips[0] = smprint("%s\n/net/%s/clone %s!%d", ns, f[0], ips[i], port);
+ free(ips[i]);
+ free(ns);
+ ns = ips[0];
+ }
+ }
+ 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,
+};
+
--- a/kern/devtab.c
+++ b/kern/devtab.c
@@ -8,6 +8,8 @@
extern Dev rootdevtab;
extern Dev pipedevtab;
extern Dev fsdevtab;
+extern Dev lfddevtab;
+extern Dev ipdevtab;
extern Dev mntdevtab;
extern Dev lfddevtab;
extern Dev cmddevtab;
@@ -18,6 +20,8 @@
&consdevtab,
&pipedevtab,
&fsdevtab,
+ &lfddevtab,
+ &ipdevtab,
&mntdevtab,
&lfddevtab,
&cmddevtab,
--- /dev/null
+++ b/libip/Makefile
@@ -1,0 +1,19 @@
+ROOT=..
+include ../Make.config
+LIB=libip.a
+
+OFILES=\
+ eipfmt.$O\
+ parseip.$O\
+ classmask.$O\
+ bo.$O\
+ ipaux.$O\
+
+default: $(LIB)
+$(LIB): $(OFILES)
+ $(AR) r $(LIB) $(OFILES)
+ $(RANLIB) $(LIB)
+
+%.$O: %.c
+ $(CC) $(CFLAGS) $*.c
+
--- /dev/null
+++ b/libip/bo.c
@@ -1,0 +1,77 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+
+void
+hnputv(void *p, uvlong v)
+{
+ uchar *a;
+
+ a = p;
+ a[0] = v>>56;
+ a[1] = v>>48;
+ a[2] = v>>40;
+ a[3] = v>>32;
+ a[4] = v>>24;
+ a[5] = v>>16;
+ a[6] = v>>8;
+ a[7] = v;
+}
+
+void
+hnputl(void *p, uint v)
+{
+ uchar *a;
+
+ a = p;
+ a[0] = v>>24;
+ a[1] = v>>16;
+ a[2] = v>>8;
+ a[3] = v;
+}
+
+void
+hnputs(void *p, ushort v)
+{
+ uchar *a;
+
+ a = p;
+ a[0] = v>>8;
+ a[1] = v;
+}
+
+uvlong
+nhgetv(void *p)
+{
+ uchar *a;
+ uvlong v;
+
+ a = p;
+ v = (uvlong)a[0]<<56;
+ v |= (uvlong)a[1]<<48;
+ v |= (uvlong)a[2]<<40;
+ v |= (uvlong)a[3]<<32;
+ v |= a[4]<<24;
+ v |= a[5]<<16;
+ v |= a[6]<<8;
+ v |= a[7]<<0;
+ return v;
+}
+
+uint
+nhgetl(void *p)
+{
+ uchar *a;
+
+ a = p;
+ return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
+}
+
+ushort
+nhgets(void *p)
+{
+ uchar *a;
+
+ a = p;
+ return (a[0]<<8)|(a[1]<<0);
+}
--- /dev/null
+++ b/libip/classmask.c
@@ -1,0 +1,86 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+
+static uchar classmask[4][16] = {
+ 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,
+ 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,
+};
+
+static uchar v6loopback[IPaddrlen] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0x01
+};
+
+static uchar v6linklocal[IPaddrlen] = {
+ 0xfe, 0x80, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+static uchar v6linklocalmask[IPaddrlen] = {
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+static int v6llpreflen = 8; /* link-local prefix length in bytes */
+
+static uchar v6multicast[IPaddrlen] = {
+ 0xff, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+static uchar v6multicastmask[IPaddrlen] = {
+ 0xff, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+static int v6mcpreflen = 1; /* multicast prefix length */
+
+static uchar v6solicitednode[IPaddrlen] = {
+ 0xff, 0x02, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0x01,
+ 0xff, 0, 0, 0
+};
+static uchar v6solicitednodemask[IPaddrlen] = {
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x0, 0x0, 0x0
+};
+static int v6snpreflen = 13;
+
+uchar*
+defmask(uchar *ip)
+{
+ if(isv4(ip))
+ return classmask[ip[IPv4off]>>6];
+ else {
+ if(ipcmp(ip, v6loopback) == 0)
+ return IPallbits;
+ else if(memcmp(ip, v6linklocal, v6llpreflen) == 0)
+ return v6linklocalmask;
+ else if(memcmp(ip, v6solicitednode, v6snpreflen) == 0)
+ return v6solicitednodemask;
+ else if(memcmp(ip, v6multicast, v6mcpreflen) == 0)
+ return v6multicastmask;
+ return IPallbits;
+ }
+}
+
+void
+maskip(uchar *from, uchar *mask, uchar *to)
+{
+ int i;
+
+ for(i = 0; i < IPaddrlen; i++)
+ to[i] = from[i] & mask[i];
+}
--- /dev/null
+++ b/libip/eipfmt.c
@@ -1,0 +1,109 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+
+enum
+{
+ Isprefix= 16,
+};
+
+uchar prefixvals[256] =
+{
+[0x00] 0 | Isprefix,
+[0x80] 1 | Isprefix,
+[0xC0] 2 | Isprefix,
+[0xE0] 3 | Isprefix,
+[0xF0] 4 | Isprefix,
+[0xF8] 5 | Isprefix,
+[0xFC] 6 | Isprefix,
+[0xFE] 7 | Isprefix,
+[0xFF] 8 | Isprefix,
+};
+
+int
+eipfmt(Fmt *f)
+{
+ char buf[5*8];
+ static char *efmt = "%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux";
+ static char *ifmt = "%d.%d.%d.%d";
+ uchar *p, ip[16];
+ ulong *lp;
+ ushort s;
+ int i, j, n, eln, eli;
+
+ 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': /* Ip address */
+ p = va_arg(f->args, uchar*);
+common:
+ if(memcmp(p, v4prefix, 12) == 0){
+ snprint(buf, sizeof buf, ifmt, p[12], p[13], p[14], p[15]);
+ return fmtstrcpy(f, buf);
+ }
+
+ /* find longest elision */
+ eln = eli = -1;
+ for(i = 0; i < 16; i += 2){
+ for(j = i; j < 16; j += 2)
+ if(p[j] != 0 || p[j+1] != 0)
+ break;
+ if(j > i && j - i > eln){
+ eli = i;
+ eln = j - i;
+ }
+ }
+
+ /* print with possible elision */
+ n = 0;
+ for(i = 0; i < 16; i += 2){
+ if(i == eli){
+ n += sprint(buf+n, "::");
+ i += eln;
+ if(i >= 16)
+ break;
+ } else if(i != 0)
+ n += sprint(buf+n, ":");
+ s = (p[i]<<8) + p[i+1];
+ n += sprint(buf+n, "%ux", s);
+ }
+ return fmtstrcpy(f, buf);
+
+ case 'i': /* v6 address as 4 longs */
+ lp = va_arg(f->args, ulong*);
+ for(i = 0; i < 4; i++)
+ hnputl(ip+4*i, *lp++);
+ p = ip;
+ goto common;
+
+ case 'V': /* v4 ip address */
+ p = va_arg(f->args, uchar*);
+ snprint(buf, sizeof buf, ifmt, p[0], p[1], p[2], p[3]);
+ return fmtstrcpy(f, buf);
+
+ case 'M': /* ip mask */
+ p = va_arg(f->args, uchar*);
+
+ /* look for a prefix mask */
+ for(i = 0; i < 16; i++)
+ if(p[i] != 0xff)
+ break;
+ if(i < 16){
+ if((prefixvals[p[i]] & Isprefix) == 0)
+ goto common;
+ for(j = i+1; j < 16; j++)
+ if(p[j] != 0)
+ goto common;
+ n = 8*i + (prefixvals[p[i]] & ~Isprefix);
+ } else
+ n = 8*16;
+
+ /* got one, use /xx format */
+ snprint(buf, sizeof buf, "/%d", n);
+ return fmtstrcpy(f, buf);
+ }
+ return fmtstrcpy(f, "(eipfmt)");
+}
--- /dev/null
+++ b/libip/ipaux.c
@@ -1,0 +1,102 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+
+/*
+ * well known IP addresses
+ */
+uchar IPv4bcast[IPaddrlen] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff
+};
+uchar IPv4allsys[IPaddrlen] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0xff, 0xff,
+ 0xe0, 0, 0, 0x01
+};
+uchar IPv4allrouter[IPaddrlen] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0xff, 0xff,
+ 0xe0, 0, 0, 0x02
+};
+uchar IPallbits[IPaddrlen] = {
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff
+};
+uchar IPnoaddr[IPaddrlen];
+
+/*
+ * prefix of all v4 addresses
+ */
+uchar v4prefix[IPaddrlen] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0xff, 0xff,
+ 0, 0, 0, 0
+};
+
+int
+isv4(uchar *ip)
+{
+ return memcmp(ip, v4prefix, IPv4off) == 0;
+}
+
+/*
+ * the following routines are unrolled with no memset's to speed
+ * up the usual case
+ */
+void
+v4tov6(uchar *v6, uchar *v4)
+{
+ v6[0] = 0;
+ v6[1] = 0;
+ v6[2] = 0;
+ v6[3] = 0;
+ v6[4] = 0;
+ v6[5] = 0;
+ v6[6] = 0;
+ v6[7] = 0;
+ v6[8] = 0;
+ v6[9] = 0;
+ v6[10] = 0xff;
+ v6[11] = 0xff;
+ v6[12] = v4[0];
+ v6[13] = v4[1];
+ v6[14] = v4[2];
+ v6[15] = v4[3];
+}
+
+int
+v6tov4(uchar *v4, uchar *v6)
+{
+ if(v6[0] == 0
+ && v6[1] == 0
+ && v6[2] == 0
+ && v6[3] == 0
+ && v6[4] == 0
+ && v6[5] == 0
+ && v6[6] == 0
+ && v6[7] == 0
+ && v6[8] == 0
+ && v6[9] == 0
+ && v6[10] == 0xff
+ && v6[11] == 0xff)
+ {
+ v4[0] = v6[12];
+ v4[1] = v6[13];
+ v4[2] = v6[14];
+ v4[3] = v6[15];
+ return 0;
+ } else {
+ memset(v4, 0, 4);
+ if(memcmp(v6, IPnoaddr, IPaddrlen) == 0)
+ return 0;
+ return -1;
+ }
+}
--- /dev/null
+++ b/libip/parseip.c
@@ -1,0 +1,176 @@
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include <ip.h>
+
+char*
+v4parseip(uchar *to, char *from)
+{
+ int i;
+ char *p;
+
+ p = from;
+ for(i = 0; i < 4 && *p; i++){
+ to[i] = strtoul(p, &p, 0);
+ if(*p == '.')
+ p++;
+ }
+ switch(CLASS(to)){
+ case 0: /* class A - 1 uchar 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 uchar net */
+ if(i == 3){
+ to[3] = to[2];
+ to[2] = 0;
+ }
+ break;
+ }
+ return p;
+}
+
+static int
+ipcharok(int c)
+{
+ return c == '.' || c == ':' || (isascii(c) && isxdigit(c));
+}
+
+static int
+delimchar(int c)
+{
+ if(c == '\0')
+ return 1;
+ if(c == '.' || c == ':' || (isascii(c) && isalnum(c)))
+ return 0;
+ return 1;
+}
+
+/*
+ * `from' may contain an address followed by other characters,
+ * at least in /boot, so we permit whitespace (and more) after the address.
+ * we do ensure that "delete" cannot be parsed as "de::".
+ *
+ * some callers don't check the return value for errors, so
+ * set `to' to something distinctive in the case of a parse error.
+ */
+vlong
+parseip(uchar *to, char *from)
+{
+ int i, elipsis = 0, v4 = 1;
+ ulong x;
+ char *p, *op;
+
+ memset(to, 0, IPaddrlen);
+ p = from;
+ for(i = 0; i < IPaddrlen && ipcharok(*p); i+=2){
+ op = p;
+ x = strtoul(p, &p, 16);
+ if(*p == '.' || (*p == 0 && i == 0)){ /* ends with v4? */
+ if(i > IPaddrlen-4){
+ memset(to, 0, IPaddrlen);
+ return -1; /* parse error */
+ }
+ p = v4parseip(to+i, op);
+ i += 4;
+ break;
+ }
+ /* v6: at most 4 hex digits, followed by colon or delim */
+ if(x != (ushort)x || (*p != ':' && !delimchar(*p))) {
+ memset(to, 0, IPaddrlen);
+ return -1; /* parse error */
+ }
+ to[i] = x>>8;
+ to[i+1] = x;
+ if(*p == ':'){
+ v4 = 0;
+ if(*++p == ':'){ /* :: is elided zero short(s) */
+ if (elipsis) {
+ memset(to, 0, IPaddrlen);
+ return -1; /* second :: */
+ }
+ elipsis = i+2;
+ p++;
+ }
+ } else if (p == op) /* strtoul made no progress? */
+ break;
+ }
+ if (p == from || !delimchar(*p)) {
+ memset(to, 0, IPaddrlen);
+ return -1; /* parse error */
+ }
+ if(i < IPaddrlen){
+ memmove(&to[elipsis+IPaddrlen-i], &to[elipsis], i-elipsis);
+ memset(&to[elipsis], 0, IPaddrlen-i);
+ }
+ if(v4){
+ to[10] = to[11] = 0xff;
+ return (ulong)nhgetl(to + IPv4off);
+ } else
+ return 6;
+}
+
+/*
+ * hack to allow ip v4 masks to be entered in the old
+ * style
+ */
+vlong
+parseipmask(uchar *to, char *from, int v4)
+{
+ vlong x;
+ int i, w;
+ uchar *p;
+
+ if(*from == '/'){
+ /* as a number of prefix bits */
+ i = atoi(from+1);
+ if(i < 0)
+ i = 0;
+ if(i <= 32 && v4)
+ i += 96;
+ if(i > 128)
+ i = 128;
+ w = i;
+ memset(to, 0, IPaddrlen);
+ for(p = to; i >= 8; i -= 8)
+ *p++ = 0xff;
+ if(i > 0)
+ *p = ~((1<<(8-i))-1);
+ /*
+ * identify as ipv6 if the mask is inexpressible as a v4 mask
+ * (because it has too few mask bits). Arguably, we could
+ * always return 6 here.
+ */
+ if (w < 96)
+ return v4 ? -1 : 6;
+ x = (ulong)nhgetl(to+IPv4off);
+ } else {
+ /* as a straight v4 bit mask */
+ x = parseip(to, from);
+ if(memcmp(to, v4prefix, IPv4off) == 0)
+ memset(to, 0xff, IPv4off);
+ else if(v4 && memcmp(to, IPallbits, IPv4off) != 0)
+ x = -1;
+ }
+ return x;
+}
+
+vlong
+parseipandmask(uchar *ip, uchar *mask, char *ipstr, char *maskstr)
+{
+ vlong x;
+
+ x = parseip(ip, ipstr);
+ if(maskstr == nil)
+ memset(mask, 0xff, IPaddrlen);
+ else if(parseipmask(mask, maskstr, memcmp(ip, v4prefix, IPv4off) == 0) == -1)
+ x = -1;
+ return x;
+}
--- a/main.c
+++ b/main.c
@@ -60,10 +60,13 @@
panic("bind #c: %r");
if(bind("#e", "/env", MREPL|MCREATE) < 0)
panic("bind #e: %r");
+ if(bind("#I", "/net", MBEFORE) < 0)
+ panic("bind #I: %r");
if(bind("#U", "/root", MREPL) < 0)
panic("bind #U: %r");
if(bind("/root", "/", MAFTER) < 0)
panic("bind /root: %r");
+
char *cmd[] = {
"drawcpu",
"-c"
--- a/rc/drawcpu.c
+++ b/rc/drawcpu.c
@@ -30,6 +30,11 @@
"mount", execmount,
"unmount", execunmount,
"ls", execls,
+ "cat", execcat,
+ "rm", execrm,
+ "mkdir", execmkdir,
+ "test", exectest,
+ "echo", exececho,
0
};
@@ -412,8 +417,14 @@
int
Open(char *file, int mode)
{
+ int fd;
static int tab[] = {OREAD,OWRITE,ORDWR,OREAD|ORCLOSE};
- return open(file, tab[mode&3]);
+ fd = open(file, tab[mode&3]);
+ if(fd < 0 && strcmp(file, "/fd/0") == 0)
+ fd = lfdfd(0);
+ if(fd < 0 && strcmp(file, "/fd/1") == 0)
+ fd = lfdfd(1);
+ return fd;
}
void
@@ -457,12 +468,6 @@
Isatty(int fd)
{
return isatty(fd);
- /*
- char buf[64];
- if(fd2path(fd, buf, sizeof buf) != 0)
- return 0;
- return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;
- */
}
void
--- a/rc/exec.h
+++ b/rc/exec.h
@@ -74,7 +74,8 @@
};
extern void (*builtinfunc(char *name))(void);
-void execread(void), execns(void), execls(void);
+void execread(void), execns(void), execls(void), execcat(void);
+void execrm(void), execmkdir(void), exectest(void), exececho(void);
void execbind(void), execmount(void), execunmount(void);
void execcd(void), execwhatis(void), execeval(void), execexec(void);
int execforkexec(void);
--- a/rc/simple.c
+++ b/rc/simple.c
@@ -302,6 +302,59 @@
}
void
+execrm(void)
+{
+ int i, recurse, force;
+ char *fd;
+ Dir *db;
+ word *a;
+
+ force = recurse = 0;
+ popword(); /* rm */
+ while(runq->argv->words && runq->argv->words->word[0]=='-'){
+ char *f = runq->argv->words->word+1;
+ if(*f == '-'){
+ popword();
+ break;
+ }
+ for(; *f; f++){
+ switch(*f){
+ case 'r':
+ recurse = 1;
+ break;
+ case 'f':
+ force = 1;
+ break;
+ default:
+ goto Usage;
+ }
+ popword();
+ }
+ }
+ a = runq->argv->words;
+ for(;a;a = a->next){
+ if(remove(a->word) != -1)
+ continue;
+ db = nil;
+ if(recurse && (db=dirstat(a->word))!=nil && (db->qid.type&QTDIR))
+ rmdir(a->word);
+ else
+ goto Error;
+ free(db);
+ }
+ return;
+Error:
+ pfmt(err, "rm: %r\n", strerror(errno));
+ poplist();
+ return;
+Usage:
+ pfmt(err, "usage: rm [-fr] file ...\n");
+ setstatus("rm usage");
+ poplist();
+ return;
+}
+
+void
execns(void)
{
//print("Execns\n");
@@ -346,7 +399,6 @@
goto Error;
return;
Error:
- setstatus("bind error");
poplist();
if(qflag)
return;
@@ -412,6 +464,7 @@
goto Error;
if(sysmount(fd, -1, runq->argv->words->next->word, flag, spec) < 0)
goto Error;
+ poplist();
return;
Error:
setstatus("mount error");
@@ -432,7 +485,106 @@
//unmount
}
+int
+cat(int f, char *s)
+{
+ char buf[IOUNIT];
+ long n;
+ while((n=Read(f, buf, sizeof buf))>0)
+ if(Write(1, buf, n)!=n)
+ pfmt(err, "write error copying %s: %s", s, strerror(errno));
+ if(n < 0)
+ pfmt(err, "error reading %s: %s", s, strerror(errno));
+}
+
void
+execcat(void)
+{
+ int f;
+ popword(); /* cat */
+ word *a;
+
+ a = runq->argv->words;
+ if(count(a) == 0){
+ cat(f, "<stdin>");
+ close(f);
+ } else for(;a;a = a->next){
+ f = Open(a->word, OREAD);
+ if(f < 0){
+ pfmt(err, "can't open %s: %s", a->word, strerror(errno));
+ break;
+ }
+ cat(f, a->word);
+ close(f);
+ write(1, "\n", 1);
+ }
+ poplist();
+}
+
+int
+hasmode(char *f, ulong m)
+{
+ int r;
+ Dir *dir;
+ dir = dirstat(f);
+ if (dir == nil)
+ return 0;
+ r = (dir->mode & m) != 0;
+ free(dir);
+ return r;
+}
+
+void
+exectest(void)
+{
+ /* TODO(halfwit): Only care about -d for my needs, but test has a ton of things */
+ setstatus("no such file");
+ if(strcmp(runq->argv->words->next->word, "-d")==0)
+ if(hasmode(runq->argv->words->next->next->word, DMDIR))
+ setstatus("");
+ poplist();
+}
+
+void
+execmkdir(void)
+{
+
+}
+
+void
+exececho(void)
+{
+ int nflag;
+ int i, len;
+ char *buf, *p;
+ word *a, *c;
+
+ nflag = 0;
+ popword(); /* echo */
+ a = runq->argv->words;
+ if(count(a) > 0 && strcmp(a->word, "-n") == 0){
+ a = a->next; // move up our counter as well
+ nflag = 1;
+ }
+ len = 1;
+ for(c = a; c; c = c->next)
+ len += strlen(c->word)+1;
+ buf = malloc(len);
+ if(buf == 0)
+ panic("no memory");
+ p = buf;
+ for(c = a; c; c = c->next){
+ strcpy(p, c->word);
+ p += strlen(p);
+ if(c->next)
+ *p++ = ' ';
+ }
+ if(!nflag)
+ *p++ = '\n';
+ write(1, buf, p-buf);
+}
+
+void
execls(void)
{
Dir *db;
@@ -714,9 +866,6 @@
fd = Open(file, 0);
if(fd >= 0)
break;
- if(strcmp(file, "/fd/0")==0){
- fd = open("/dev/cons", OREAD);
- }
free(file);
}
if(fd<0){