summaryrefslogtreecommitdiff
path: root/emu
diff options
context:
space:
mode:
Diffstat (limited to 'emu')
-rw-r--r--emu/DragonFly/emu2
-rw-r--r--emu/DragonFly/emu-g2
-rw-r--r--emu/FreeBSD/emu2
-rw-r--r--emu/Linux/emu-g2
-rw-r--r--emu/Linux/emu-wrt2
-rw-r--r--emu/MacOSX/emu2
-rw-r--r--emu/MacOSX/emu-g2
-rw-r--r--emu/NetBSD/emu2
-rw-r--r--emu/Nt/ipif.c2
-rw-r--r--emu/Nt/ipif6.c413
-rw-r--r--emu/OpenBSD/emu2
-rw-r--r--emu/Unixware/emu2
-rw-r--r--emu/port/devip.c45
-rw-r--r--emu/port/ip.h13
-rw-r--r--emu/port/ipif-posix.c46
-rw-r--r--emu/port/ipif6-posix.c415
16 files changed, 885 insertions, 69 deletions
diff --git a/emu/DragonFly/emu b/emu/DragonFly/emu
index e4fbc42a..55705a2b 100644
--- a/emu/DragonFly/emu
+++ b/emu/DragonFly/emu
@@ -18,7 +18,7 @@ dev
pointer
snarf
- ip ipif ipaux
+ ip ipif-posix ipaux
eia
audio audio
mem
diff --git a/emu/DragonFly/emu-g b/emu/DragonFly/emu-g
index 0667fd62..a5a74e5f 100644
--- a/emu/DragonFly/emu-g
+++ b/emu/DragonFly/emu-g
@@ -13,7 +13,7 @@ dev
cmd cmd
indir
- ip ipif ipaux
+ ip ipif-posix ipaux
eia
mem
diff --git a/emu/FreeBSD/emu b/emu/FreeBSD/emu
index e4fbc42a..55705a2b 100644
--- a/emu/FreeBSD/emu
+++ b/emu/FreeBSD/emu
@@ -18,7 +18,7 @@ dev
pointer
snarf
- ip ipif ipaux
+ ip ipif-posix ipaux
eia
audio audio
mem
diff --git a/emu/Linux/emu-g b/emu/Linux/emu-g
index 3d45c288..8df0b4c5 100644
--- a/emu/Linux/emu-g
+++ b/emu/Linux/emu-g
@@ -16,7 +16,7 @@ dev
cmd cmd
indir
- ip ipif-posix ipaux
+ ip ipif6-posix ipaux
eia
# audio audio
mem
diff --git a/emu/Linux/emu-wrt b/emu/Linux/emu-wrt
index 4f7f6fc6..0eac3aff 100644
--- a/emu/Linux/emu-wrt
+++ b/emu/Linux/emu-wrt
@@ -18,7 +18,7 @@ dev
# pointer
# snarf
- ip ipif-posix ipaux
+ ip ipif6-posix ipaux
# eia
# audio audio
mem
diff --git a/emu/MacOSX/emu b/emu/MacOSX/emu
index a1a9666f..eaefdbda 100644
--- a/emu/MacOSX/emu
+++ b/emu/MacOSX/emu
@@ -18,7 +18,7 @@ dev
pointer
snarf
- ip ipif ipaux
+ ip ipif-posix ipaux
eia
# audio audio
mem
diff --git a/emu/MacOSX/emu-g b/emu/MacOSX/emu-g
index d196f5ce..8ba4ba4f 100644
--- a/emu/MacOSX/emu-g
+++ b/emu/MacOSX/emu-g
@@ -14,7 +14,7 @@ dev
cmd cmd
indir
- ip ipif ipaux
+ ip ipif-posix ipaux
eia
# audio audio
mem
diff --git a/emu/NetBSD/emu b/emu/NetBSD/emu
index e4fbc42a..55705a2b 100644
--- a/emu/NetBSD/emu
+++ b/emu/NetBSD/emu
@@ -18,7 +18,7 @@ dev
pointer
snarf
- ip ipif ipaux
+ ip ipif-posix ipaux
eia
audio audio
mem
diff --git a/emu/Nt/ipif.c b/emu/Nt/ipif.c
index 327d5471..d690e48a 100644
--- a/emu/Nt/ipif.c
+++ b/emu/Nt/ipif.c
@@ -184,7 +184,7 @@ so_connect(int fd, unsigned long raddr, unsigned short rport)
sin = (struct sockaddr_in*)&sa;
sin->sin_family = AF_INET;
hnputs(&sin->sin_port, rport);
- hnputl(&sin->sin_addr.s_addr, raddr);
+ memmove(&sin->sin_addr.s_addr, raddr+IPv4off, IPv4addrlen);
osenter();
r = connect(fd, &sa, sizeof(sa));
diff --git a/emu/Nt/ipif6.c b/emu/Nt/ipif6.c
new file mode 100644
index 00000000..a8fc8538
--- /dev/null
+++ b/emu/Nt/ipif6.c
@@ -0,0 +1,413 @@
+#define Unknown win_Unknown
+
+/* vista (0x0600) was the first to support IPPROTO_IPV6 */
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0600
+
+#include <winsock2.h>
+#include <ws2def.h>
+#include <ws2tcpip.h>
+#include <wspiapi.h>
+#undef Unknown
+
+#include "dat.h"
+#include "fns.h"
+#include "ip.h"
+#include "error.h"
+
+extern int SOCK_SELECT;
+
+int
+so_socket(int type)
+{
+ int fd, one;
+ int v6only;
+
+ switch(type) {
+ default:
+ error("bad protocol type");
+ case S_TCP:
+ type = SOCK_STREAM;
+ break;
+ case S_UDP:
+ type = SOCK_DGRAM;
+ break;
+ }
+
+ fd = socket(AF_INET6, type, 0);
+ if(fd < 0)
+ oserror();
+
+ /* OpenBSD has v6only fixed to 1, so the following will fail */
+ v6only = 0;
+ if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&v6only, sizeof v6only) < 0)
+ oserror();
+
+ if(type == SOCK_DGRAM){
+ one = 1;
+ setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&one, sizeof(one));
+ }else{
+ one = 1;
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one));
+ }
+ return fd;
+}
+
+int
+so_send(int sock, void *va, int len, void *hdr, int hdrlen)
+{
+ int r;
+ struct sockaddr_storage sa;
+ struct sockaddr_in6 *sin6;
+ char *h = hdr;
+
+ osenter();
+ if(hdr == 0)
+ r = send(sock, va, len, 0);
+ else {
+ memset(&sa, 0, sizeof(sa));
+ sin6 = (struct sockaddr_in6*)&sa;
+ sin6->sin6_family = AF_INET6;
+ switch(hdrlen){
+ case OUdphdrlenv4:
+ v4tov6((uchar*)&sin6->sin6_addr, h);
+ memmove(&sin6->sin6_port, h+8, 2);
+ break;
+ case OUdphdrlen:
+ memmove((uchar*)&sin6->sin6_addr, h, IPaddrlen);
+ memmove(&sin6->sin6_port, h+2*IPaddrlen, 2); /* rport */
+ break;
+ default:
+ memmove((uchar*)&sin6->sin6_addr, h, IPaddrlen);
+ memmove(&sin6->sin6_port, h+3*IPaddrlen, 2);
+ break;
+ }
+ r = sendto(sock, va, len, 0, (struct sockaddr*)sin6, sizeof(*sin6));
+ }
+ osleave();
+ return r;
+}
+
+static int
+doselect(int sock)
+{
+ fd_set waitr;
+ struct timeval seltime;
+
+ up->syscall = SOCK_SELECT;
+ FD_ZERO(&waitr);
+ FD_SET(sock, &waitr);
+ for(;;){
+ int nfds;
+ fd_set in, exc;
+
+ in = waitr;
+ exc = waitr;
+ seltime.tv_sec = 1;
+ seltime.tv_usec = 0L;
+ nfds = select(sizeof(fd_set)*8, &in, (fd_set*)0, &exc, &seltime);
+ if(up->intwait) {
+ up->intwait = 0;
+ return -1;
+ }
+ if(nfds < 0) {
+ print("select error\n");
+ return 0;
+ }
+ if(FD_ISSET(sock, &in) || FD_ISSET(sock, &exc)){
+ return 0;
+ }
+ }
+}
+
+int
+so_recv(int sock, void *va, int len, void *hdr, int hdrlen)
+{
+ int r, l;
+ struct sockaddr_storage sa;
+ struct sockaddr_in6 *sin6;
+ char h[Udphdrlen];
+
+ osenter();
+ if(doselect(sock) < 0) {
+ osleave();
+ return -1;
+ }
+ if(hdr == 0)
+ r = recv(sock, va, len, 0);
+ else {
+ sin6 = (struct sockaddr_in6*)&sa;
+ l = sizeof(sa);
+ r = recvfrom(sock, va, len, 0, (struct sockaddr*)&sa, &l);
+ if(r >= 0) {
+ memset(h, 0, sizeof h);
+ switch(hdrlen){
+ case OUdphdrlenv4:
+ if(v6tov4(h, (uchar*)&sin6->sin6_addr) < 0) {
+ osleave();
+ error("OUdphdrlenv4 with IPv6 address");
+ }
+ memmove(h+2*IPv4addrlen, &sin6->sin6_port, 2);
+ break;
+ case OUdphdrlen:
+ memmove(h, (uchar*)&sin6->sin6_addr, IPaddrlen);
+ memmove(h+2*IPaddrlen, &sin6->sin6_port, 2);
+ break;
+ default:
+ memmove(h, (uchar*)&sin6->sin6_addr, IPaddrlen);
+ memmove(h+3*IPaddrlen, &sin6->sin6_port, 2);
+ break;
+ }
+
+ /* alas there's no way to get the local addr/port correctly. Pretend. */
+ memset(&sa, 0, sizeof sa);
+ l = sizeof(sa);
+ getsockname(sock, (struct sockaddr*)&sa, &l);
+ switch(hdrlen){
+ case OUdphdrlenv4:
+ /*
+ * we get v6Unspecified/noaddr if local address cannot be determined.
+ * that's reasonable for ipv4 too.
+ */
+ if(ipcmp(v6Unspecified, (uchar*)&sin6->sin6_addr) != 0
+ && v6tov4(h+IPv4addrlen, (uchar*)&sin6->sin6_addr) < 0) {
+ osleave();
+ error("OUdphdrlenv4 with IPv6 address");
+ }
+ memmove(h+2*IPv4addrlen+2, &sin6->sin6_port, 2);
+ break;
+ case OUdphdrlen:
+ memmove(h+IPaddrlen, (uchar*)&sin6->sin6_addr, IPaddrlen);
+ memmove(h+2*IPaddrlen+2, &sin6->sin6_port, 2);
+ break;
+ default:
+ memmove(h+IPaddrlen, (uchar*)&sin6->sin6_addr, IPaddrlen);
+ memmove(h+2*IPaddrlen, (uchar*)&sin6->sin6_addr, IPaddrlen); /* ifcaddr */
+ memmove(h+3*IPaddrlen+2, &sin6->sin6_port, 2);
+ break;
+ }
+ memmove(hdr, h, hdrlen);
+ }
+ }
+ osleave();
+ return r;
+}
+
+void
+so_close(int sock)
+{
+ closesocket(sock);
+}
+
+void
+so_connect(int fd, unsigned char *raddr, unsigned short rport)
+{
+ int r;
+ struct sockaddr_storage sa;
+ struct sockaddr_in6 *sin6;
+
+ memset(&sa, 0, sizeof(sa));
+ sin6 = (struct sockaddr_in6*)&sa;
+ sin6->sin6_family = AF_INET6;
+ hnputs(&sin6->sin6_port, rport);
+ memmove((uchar*)&sin6->sin6_addr, raddr, IPaddrlen);
+
+ osenter();
+ r = connect(fd, (struct sockaddr*)sin6, sizeof(*sin6));
+ osleave();
+ if(r < 0)
+ oserror();
+}
+
+void
+so_getsockname(int fd, unsigned char *laddr, unsigned short *lport)
+{
+ int len;
+ struct sockaddr_storage sa;
+ struct sockaddr_in6 *sin6;
+
+ len = sizeof(*sin6);
+ if(getsockname(fd, (struct sockaddr*)&sa, &len) < 0)
+ oserror();
+
+ sin6 = (struct sockaddr_in6*)&sa;
+ if(sin6->sin6_family != AF_INET6 || len != sizeof(*sin6))
+ error("not AF_INET6");
+
+ memmove(laddr, &sin6->sin6_addr, IPaddrlen);
+ *lport = nhgets(&sin6->sin6_port);
+}
+
+void
+so_listen(int fd)
+{
+ int r;
+
+ osenter();
+ r = listen(fd, 256);
+ osleave();
+ if(r < 0)
+ oserror();
+}
+
+int
+so_accept(int fd, unsigned char *raddr, unsigned short *rport)
+{
+ int nfd, len;
+ struct sockaddr_storage sa;
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6*)&sa;
+
+ len = sizeof(*sin6);
+ osenter();
+ if(doselect(fd) < 0) {
+ osleave();
+ return -1;
+ }
+ nfd = accept(fd, (struct sockaddr*)&sa, &len);
+ osleave();
+ if(nfd < 0)
+ oserror();
+
+ if(sin6->sin6_family != AF_INET6 || len != sizeof(*sin6))
+ error("not AF_INET6");
+
+ memmove(raddr, &sin6->sin6_addr, IPaddrlen);
+ *rport = nhgets(&sin6->sin6_port);
+ return nfd;
+}
+
+void
+so_bind(int fd, int su, unsigned char *addr, unsigned short port)
+{
+ int i, one;
+ struct sockaddr_storage sa;
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6*)&sa;
+
+ one = 1;
+ if(0 && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0) {
+ oserrstr(up->genbuf, sizeof(up->genbuf));
+ print("setsockopt: %s", up->genbuf);
+ }
+
+ if(su) {
+ for(i = 600; i < 1024; i++) {
+ memset(&sa, 0, sizeof(sa));
+ sin6->sin6_family = AF_INET6;
+ memmove(&sin6->sin6_addr, addr, IPaddrlen);
+ hnputs(&sin6->sin6_port, i);
+
+ if(bind(fd, (struct sockaddr*)sin6, sizeof(*sin6)) >= 0)
+ return;
+ }
+ oserror();
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ sin6->sin6_family = AF_INET6;
+ memmove(&sin6->sin6_addr, addr, IPaddrlen);
+ hnputs(&sin6->sin6_port, port);
+
+ if(bind(fd, (struct sockaddr*)sin6, sizeof(*sin6)) < 0)
+ oserror();
+}
+
+static int
+resolve(char *name, char **hostv, int n, int isnumeric)
+{
+ int i;
+ struct addrinfo *res0, *r;
+ char buf[5*8];
+ uchar addr[IPaddrlen];
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = isnumeric ? AI_NUMERICHOST : 0;
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ if(getaddrinfo(name, nil, &hints, &res0) < 0)
+ return 0;
+ i = 0;
+ for(r = res0; r != nil && i < n; r = r->ai_next) {
+ if(r->ai_family == AF_INET)
+ v4tov6(addr, (uchar*)&((struct sockaddr_in*)r->ai_addr)->sin_addr);
+ else if(r->ai_family == AF_INET6)
+ memmove(addr, &((struct sockaddr_in6*)r->ai_addr)->sin6_addr, IPaddrlen);
+ else
+ continue;
+
+ snprint(buf, sizeof buf, "%I", addr);
+ hostv[i++] = strdup(buf);
+ }
+
+ freeaddrinfo(res0);
+ return i;
+}
+
+int
+so_gethostbyname(char *host, char **hostv, int n)
+{
+ return resolve(host, hostv, n, 0);
+}
+
+int
+so_gethostbyaddr(char *addr, char **hostv, int n)
+{
+ return resolve(addr, hostv, n, 1);
+}
+
+int
+so_getservbyname(char *service, char *net, char *port)
+{
+ ushort p;
+ struct servent *s;
+
+ s = getservbyname(service, net);
+ if(s == 0)
+ return -1;
+ p = s->s_port;
+ sprint(port, "%d", nhgets(&p));
+ return 0;
+}
+
+int
+so_hangup(int fd, int nolinger)
+{
+ int r;
+ static struct linger l = {1, 0};
+
+ osenter();
+ if(nolinger)
+ setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&l, sizeof(l));
+ r = closesocket(fd);
+ osleave();
+ return r;
+}
+
+void
+arpadd(char *ipaddr, char *eaddr, int n)
+{
+ error("arp not implemented");
+}
+
+int
+so_mustbind(int restricted, int port)
+{
+ USED(restricted);
+ USED(port);
+ /* Windows requires bound sockets, even on port 0 */
+ return 1;
+}
+
+void
+so_keepalive(int fd, int ms)
+{
+ int on;
+
+ USED(ms);
+ on = 1;
+ setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&on, sizeof(on));
+}
diff --git a/emu/OpenBSD/emu b/emu/OpenBSD/emu
index 4d9a7d0b..511c38ec 100644
--- a/emu/OpenBSD/emu
+++ b/emu/OpenBSD/emu
@@ -18,7 +18,7 @@ dev
pointer
snarf
- ip ipif ipaux
+ ip ipif-posix ipaux
eia
audio audio
mem
diff --git a/emu/Unixware/emu b/emu/Unixware/emu
index 92fc91bd..898ff599 100644
--- a/emu/Unixware/emu
+++ b/emu/Unixware/emu
@@ -18,7 +18,7 @@ dev
pointer
snarf
- ip ipif ipaux
+ ip ipif-posix ipaux
eia
# audio audio
mem
diff --git a/emu/port/devip.c b/emu/port/devip.c
index e70d7dc3..85088018 100644
--- a/emu/port/devip.c
+++ b/emu/port/devip.c
@@ -138,8 +138,6 @@ static char* ipstates[] = {
static Conv* protoclone(Proto*, char*, int);
static Conv* newconv(Proto*, Conv **);
static void setladdr(Conv*);
-static ulong ip6w(uchar*);
-static void ipw6(uchar*, ulong);
static int
ip3gen(Chan *c, int i, Dir *dp)
@@ -384,7 +382,7 @@ ipopen(Chan *c, int omode)
{
Conv *cv, *nc;
Proto *p;
- ulong raddr;
+ uchar raddr[IPaddrlen];
ushort rport;
int perm, sfd;
Fs *f;
@@ -469,14 +467,14 @@ ipopen(Chan *c, int omode)
nexterror();
}
- sfd = so_accept(cv->sfd, &raddr, &rport);
+ sfd = so_accept(cv->sfd, raddr, &rport);
nc = protoclone(p, up->env->user, sfd);
if(nc == 0) {
so_close(sfd);
error(Enodev);
}
- ipw6(nc->raddr, raddr);
+ memmove(nc->raddr, raddr, IPaddrlen);
nc->rport = rport;
setladdr(nc);
nc->state = Connected;
@@ -612,11 +610,8 @@ ipread(Chan *ch, void *a, long n, vlong off)
static void
setladdr(Conv *c)
{
- ulong laddr;
-
/* TO DO: this can't be right for hosts with several addresses before connect/accept */
- so_getsockname(c->sfd, &laddr, &c->lport);
- ipw6(c->laddr, laddr);
+ so_getsockname(c->sfd, c->laddr, &c->lport);
}
/*
@@ -625,16 +620,16 @@ setladdr(Conv *c)
static void
setlport(Conv *c)
{
- ulong laddr;
+ uchar laddr[IPaddrlen];
ushort p;
- so_bind(c->sfd, c->restricted, ip6w(c->laddr), c->lport);
- if(c->lport == 0 || ipcmp(c->laddr, IPnoaddr) == 0){
- so_getsockname(c->sfd, &laddr, &p);
+ so_bind(c->sfd, c->restricted, c->laddr, c->lport);
+ if(c->lport == 0 || ipcmp(c->laddr, IPnoaddr) == 0){
+ so_getsockname(c->sfd, laddr, &p);
if(c->lport == 0)
c->lport = p;
if(ipcmp(c->laddr, IPnoaddr) == 0)
- ipw6(c->laddr, laddr);
+ memmove(c->laddr, laddr, sizeof laddr);
}
}
@@ -755,7 +750,7 @@ connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
nexterror();
}
/* p = x->connect(c, cb->f, cb->nf); */
- so_connect(c->sfd, ip6w(c->raddr), c->rport);
+ so_connect(c->sfd, c->raddr, c->rport);
qlock(&c->l);
poperror();
setladdr(c);
@@ -1121,23 +1116,3 @@ Fsbuiltinproto(Fs* f, uchar proto)
{
return f->t2p[proto] != nil;
}
-
-/*
- * temporarily convert ipv6 addresses to ipv4 as ulong for
- * ipif.c interface
- */
-static ulong
-ip6w(uchar *a)
-{
- uchar v4[IPv4addrlen];
-
- v6tov4(v4, a);
- return (((((v4[0]<<8)|v4[1])<<8)|v4[2])<<8)|v4[3];
-}
-
-static void
-ipw6(uchar *a, ulong w)
-{
- memmove(a, v4prefix, IPv4off);
- hnputl(a+IPv4off, w);
-}
diff --git a/emu/port/ip.h b/emu/port/ip.h
index 1462b755..d6f67bab 100644
--- a/emu/port/ip.h
+++ b/emu/port/ip.h
@@ -16,11 +16,11 @@ typedef struct Proto Proto;
typedef struct Conv Conv;
extern int so_socket(int type);
-extern void so_connect(int, unsigned long, unsigned short);
-extern void so_getsockname(int, unsigned long*, unsigned short*);
-extern void so_bind(int, int, unsigned long, unsigned short);
+extern void so_connect(int, uchar*, ushort);
+extern void so_getsockname(int, uchar*, ushort*);
+extern void so_bind(int, int, uchar*, ushort);
extern void so_listen(int);
-extern int so_accept(int, unsigned long*, unsigned short*);
+extern int so_accept(int, uchar*, ushort*);
extern int so_getservbyname(char*, char*, char*);
extern int so_gethostbyname(char*, char**, int);
extern int so_gethostbyaddr(char*, char**, int);
@@ -34,9 +34,9 @@ extern void so_keepalive(int, int);
extern void hnputl(void *p, unsigned long v);
-extern void hnputs(void *p, unsigned short v);
+extern void hnputs(void *p, ushort v);
extern unsigned long nhgetl(void *p);
-extern unsigned short nhgets(void *p);
+extern ushort nhgets(void *p);
extern unsigned long parseip(uchar *to, char *from);
extern int parsemac(uchar *to, char *from, int len);
extern char* v4parseip(uchar*, char*);
@@ -57,6 +57,7 @@ extern uchar IPv4allrouter[IPaddrlen];
extern uchar IPnoaddr[IPaddrlen];
extern uchar v4prefix[IPaddrlen];
extern uchar IPallbits[IPaddrlen];
+extern uchar v6Unspecified[IPaddrlen];
extern void arpadd(char*, char*, int);
extern int arpwrite(char*, int);
diff --git a/emu/port/ipif-posix.c b/emu/port/ipif-posix.c
index 77b5f85d..23e4bf95 100644
--- a/emu/port/ipif-posix.c
+++ b/emu/port/ipif-posix.c
@@ -10,6 +10,7 @@
#include <net/if_arp.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
+#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#undef ulong
@@ -21,6 +22,15 @@
#include "ip.h"
#include "error.h"
+char Enotv4[] = "address not IPv4";
+
+static void
+ipw6(uchar *a, ulong w)
+{
+ memmove(a, v4prefix, IPv4off);
+ memmove(a+IPv4off, &w, IPv4addrlen);
+}
+
int
so_socket(int type)
{
@@ -42,10 +52,10 @@ so_socket(int type)
oserror();
if(type == SOCK_DGRAM){
one = 1;
- setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&one, sizeof (one));
+ setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&one, sizeof(one));
}else{
one = 1;
- setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one));
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one));
}
return fd;
}
@@ -58,7 +68,6 @@ so_send(int sock, void *va, int len, void *hdr, int hdrlen)
struct sockaddr_in *sin;
char *h = hdr;
-
osenter();
if(hdr == 0)
r = write(sock, va, len);
@@ -94,7 +103,6 @@ so_recv(int sock, void *va, int len, void *hdr, int hdrlen)
struct sockaddr_in *sin;
char h[Udphdrlen];
-
osenter();
if(hdr == 0)
r = read(sock, va, len);
@@ -106,7 +114,7 @@ so_recv(int sock, void *va, int len, void *hdr, int hdrlen)
memset(h, 0, sizeof(h));
switch(hdrlen){
case OUdphdrlenv4:
- memmove(h, &sin->sin_addr, 4);
+ memmove(h, &sin->sin_addr, IPv4addrlen);
memmove(h+2*IPv4addrlen, &sin->sin_port, 2);
break;
case OUdphdrlen:
@@ -120,6 +128,7 @@ so_recv(int sock, void *va, int len, void *hdr, int hdrlen)
}
/* alas there's no way to get the local addr/port correctly. Pretend. */
+ memset(&sa, 0, sizeof(sa));
getsockname(sock, &sa, &l);
switch(hdrlen){
case OUdphdrlenv4:
@@ -150,17 +159,20 @@ so_close(int sock)
}
void
-so_connect(int fd, unsigned long raddr, unsigned short rport)
+so_connect(int fd, uchar *raddr, ushort rport)
{
int r;
struct sockaddr sa;
struct sockaddr_in *sin;
+ if(!isv4(raddr))
+ error(Enotv4);
+
memset(&sa, 0, sizeof(sa));
sin = (struct sockaddr_in*)&sa;
sin->sin_family = AF_INET;
hnputs(&sin->sin_port, rport);
- hnputl(&sin->sin_addr.s_addr, raddr);
+ memmove(&sin->sin_addr.s_addr, raddr+IPv4off, IPv4addrlen);
osenter();
r = connect(fd, &sa, sizeof(sa));
@@ -170,7 +182,7 @@ so_connect(int fd, unsigned long raddr, unsigned short rport)
}
void
-so_getsockname(int fd, unsigned long *laddr, unsigned short *lport)
+so_getsockname(int fd, uchar *laddr, ushort *lport)
{
int len;
struct sockaddr sa;
@@ -182,9 +194,9 @@ so_getsockname(int fd, unsigned long *laddr, unsigned short *lport)
sin = (struct sockaddr_in*)&sa;
if(sin->sin_family != AF_INET || len != sizeof(*sin))
- error("not AF_INET");
+ error(Enotv4);
- *laddr = nhgetl(&sin->sin_addr.s_addr);
+ ipw6(laddr, sin->sin_addr.s_addr);
*lport = nhgets(&sin->sin_port);
}
@@ -201,7 +213,7 @@ so_listen(int fd)
}
int
-so_accept(int fd, unsigned long *raddr, unsigned short *rport)
+so_accept(int fd, uchar *raddr, ushort *rport)
{
int nfd, len;
struct sockaddr sa;
@@ -217,15 +229,15 @@ so_accept(int fd, unsigned long *raddr, unsigned short *rport)
oserror();
if(sin->sin_family != AF_INET || len != sizeof(*sin))
- error("not AF_INET");
+ error(Enotv4);
- *raddr = nhgetl(&sin->sin_addr.s_addr);
+ ipw6(raddr, sin->sin_addr.s_addr);
*rport = nhgets(&sin->sin_port);
return nfd;
}
void
-so_bind(int fd, int su, unsigned long addr, unsigned short port)
+so_bind(int fd, int su, uchar *addr, ushort port)
{
int i, one;
struct sockaddr sa;
@@ -243,7 +255,7 @@ so_bind(int fd, int su, unsigned long addr, unsigned short port)
for(i = 600; i < 1024; i++) {
memset(&sa, 0, sizeof(sa));
sin->sin_family = AF_INET;
- hnputl(&sin->sin_addr.s_addr, addr);
+ memmove(&sin->sin_addr.s_addr, addr+IPv4off, IPv4addrlen);
hnputs(&sin->sin_port, i);
if(bind(fd, &sa, sizeof(sa)) >= 0)
@@ -254,7 +266,7 @@ so_bind(int fd, int su, unsigned long addr, unsigned short port)
memset(&sa, 0, sizeof(sa));
sin->sin_family = AF_INET;
- hnputl(&sin->sin_addr.s_addr, addr);
+ memmove(&sin->sin_addr.s_addr, addr+IPv4off, IPv4addrlen);
hnputs(&sin->sin_port, port);
if(bind(fd, &sa, sizeof(sa)) < 0)
@@ -265,7 +277,7 @@ int
so_gethostbyname(char *host, char**hostv, int n)
{
int i;
- unsigned char buf[32], *p;
+ uchar buf[32], *p;
struct hostent *hp;
hp = gethostbyname(host);
diff --git a/emu/port/ipif6-posix.c b/emu/port/ipif6-posix.c
new file mode 100644
index 00000000..7f480984
--- /dev/null
+++ b/emu/port/ipif6-posix.c
@@ -0,0 +1,415 @@
+#ifdef sun
+#define uint uxuint
+#define ulong uxulong
+#define ushort uxushort
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#undef ulong
+#undef ushort
+#undef uint
+
+#include "dat.h"
+#include "fns.h"
+#include "ip.h"
+#include "error.h"
+
+int
+so_socket(int type)
+{
+ int fd, one;
+ int v6only;
+
+ switch(type) {
+ default:
+ error("bad protocol type");
+ case S_TCP:
+ type = SOCK_STREAM;
+ break;
+ case S_UDP:
+ type = SOCK_DGRAM;
+ break;
+ }
+
+ fd = socket(AF_INET6, type, 0);
+ if(fd < 0)
+ oserror();
+
+ /* OpenBSD has v6only fixed to 1, so the following will fail */
+ v6only = 0;
+ if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&v6only, sizeof v6only) < 0)
+ oserror();
+
+ if(type == SOCK_DGRAM){
+ one = 1;
+ setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&one, sizeof(one));
+ }else{
+ one = 1;
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one));
+ }
+ return fd;
+}
+
+int
+so_send(int sock, void *va, int len, void *hdr, int hdrlen)
+{
+ int r;
+ struct sockaddr_storage sa;
+ struct sockaddr_in6 *sin6;
+ char *h = hdr;
+
+ osenter();
+ if(hdr == 0)
+ r = write(sock, va, len);
+ else {
+ memset(&sa, 0, sizeof(sa));
+ sin6 = (struct sockaddr_in6*)&sa;
+ sin6->sin6_family = AF_INET6;
+ switch(hdrlen){
+ case OUdphdrlenv4:
+ v4tov6((uchar*)&sin6->sin6_addr, h);
+ memmove(&sin6->sin6_port, h+8, 2);
+ break;
+ case OUdphdrlen:
+ memmove((uchar*)&sin6->sin6_addr, h, IPaddrlen);
+ memmove(&sin6->sin6_port, h+2*IPaddrlen, 2); /* rport */
+ break;
+ default:
+ memmove((uchar*)&sin6->sin6_addr, h, IPaddrlen);
+ memmove(&sin6->sin6_port, h+3*IPaddrlen, 2);
+ break;
+ }
+ r = sendto(sock, va, len, 0, (struct sockaddr*)sin6, sizeof(*sin6));
+ }
+ osleave();
+ return r;
+}
+
+int
+so_recv(int sock, void *va, int len, void *hdr, int hdrlen)
+{
+ int r, l;
+ struct sockaddr_storage sa;
+ struct sockaddr_in6 *sin6;
+ char h[Udphdrlen];
+
+ osenter();
+ if(hdr == 0)
+ r = read(sock, va, len);
+ else {
+ sin6 = (struct sockaddr_in6*)&sa;
+ l = sizeof(sa);
+ r = recvfrom(sock, va, len, 0, (struct sockaddr*)&sa, &l);
+ if(r >= 0) {
+ memset(h, 0, sizeof(h));
+ switch(hdrlen){
+ case OUdphdrlenv4:
+ if(v6tov4(h, (uchar*)&sin6->sin6_addr) < 0) {
+ osleave();
+ error("OUdphdrlenv4 with IPv6 address");
+ }
+ memmove(h+2*IPv4addrlen, &sin6->sin6_port, 2);
+ break;
+ case OUdphdrlen:
+ memmove(h, (uchar*)&sin6->sin6_addr, IPaddrlen);
+ memmove(h+2*IPaddrlen, &sin6->sin6_port, 2);
+ break;
+ default:
+ memmove(h, (uchar*)&sin6->sin6_addr, IPaddrlen);
+ memmove(h+3*IPaddrlen, &sin6->sin6_port, 2);
+ break;
+ }
+
+ /* alas there's no way to get the local addr/port correctly. Pretend. */
+ memset(&sa, 0, sizeof(sa));
+ l = sizeof(sa);
+ getsockname(sock, (struct sockaddr*)&sa, &l);
+ switch(hdrlen){
+ case OUdphdrlenv4:
+ /*
+ * we get v6Unspecified/noaddr if local address cannot be determined.
+ * that's reasonable for ipv4 too.
+ */
+ if(ipcmp(v6Unspecified, (uchar*)&sin6->sin6_addr) != 0
+ && v6tov4(h+IPv4addrlen, (uchar*)&sin6->sin6_addr) < 0) {
+ osleave();
+ error("OUdphdrlenv4 with IPv6 address");
+ }
+ memmove(h+2*IPv4addrlen+2, &sin6->sin6_port, 2);
+ break;
+ case OUdphdrlen:
+ memmove(h+IPaddrlen, (uchar*)&sin6->sin6_addr, IPaddrlen);
+ memmove(h+2*IPaddrlen+2, &sin6->sin6_port, 2);
+ break;
+ default:
+ memmove(h+IPaddrlen, (uchar*)&sin6->sin6_addr, IPaddrlen);
+ memmove(h+2*IPaddrlen, (uchar*)&sin6->sin6_addr, IPaddrlen); /* ifcaddr */
+ memmove(h+3*IPaddrlen+2, &sin6->sin6_port, 2);
+ break;
+ }
+ memmove(hdr, h, hdrlen);
+ }
+ }
+ osleave();
+ return r;
+}
+
+void
+so_close(int sock)
+{
+ close(sock);
+}
+
+void
+so_connect(int fd, uchar *raddr, ushort rport)
+{
+ int r;
+ struct sockaddr_storage sa;
+ struct sockaddr_in6 *sin6;
+
+ memset(&sa, 0, sizeof(sa));
+ sin6 = (struct sockaddr_in6*)&sa;
+ sin6->sin6_family = AF_INET6;
+ hnputs(&sin6->sin6_port, rport);
+ memmove((uchar*)&sin6->sin6_addr, raddr, IPaddrlen);
+
+ osenter();
+ r = connect(fd, (struct sockaddr*)sin6, sizeof(*sin6));
+ osleave();
+ if(r < 0)
+ oserror();
+}
+
+void
+so_getsockname(int fd, uchar *laddr, ushort *lport)
+{
+ int len;
+ struct sockaddr_storage sa;
+ struct sockaddr_in6 *sin6;
+
+ len = sizeof(*sin6);
+ if(getsockname(fd, (struct sockaddr*)&sa, &len) < 0)
+ oserror();
+
+ sin6 = (struct sockaddr_in6*)&sa;
+ if(sin6->sin6_family != AF_INET6 || len != sizeof(*sin6))
+ error("not AF_INET6");
+
+ memmove(laddr, &sin6->sin6_addr, IPaddrlen);
+ *lport = nhgets(&sin6->sin6_port);
+}
+
+void
+so_listen(int fd)
+{
+ int r;
+
+ osenter();
+ r = listen(fd, 256);
+ osleave();
+ if(r < 0)
+ oserror();
+}
+
+int
+so_accept(int fd, uchar *raddr, ushort *rport)
+{
+ int nfd, len;
+ struct sockaddr_storage sa;
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6*)&sa;
+
+ len = sizeof(*sin6);
+ osenter();
+ nfd = accept(fd, (struct sockaddr*)&sa, &len);
+ osleave();
+ if(nfd < 0)
+ oserror();
+
+ if(sin6->sin6_family != AF_INET6 || len != sizeof(*sin6))
+ error("not AF_INET6");
+
+ memmove(raddr, &sin6->sin6_addr, IPaddrlen);
+ *rport = nhgets(&sin6->sin6_port);
+ return nfd;
+}
+
+void
+so_bind(int fd, int su, uchar *addr, ushort port)
+{
+ int i, one;
+ struct sockaddr_storage sa;
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6*)&sa;
+
+ one = 1;
+ if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0) {
+ oserrstr(up->genbuf, sizeof(up->genbuf));
+ print("setsockopt: %s", up->genbuf);
+ }
+
+ if(su) {
+ for(i = 600; i < 1024; i++) {
+ memset(&sa, 0, sizeof(sa));
+ sin6->sin6_family = AF_INET6;
+ memmove(&sin6->sin6_addr, addr, IPaddrlen);
+ hnputs(&sin6->sin6_port, i);
+
+ if(bind(fd, (struct sockaddr*)sin6, sizeof(*sin6)) >= 0)
+ return;
+ }
+ oserror();
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ sin6->sin6_family = AF_INET6;
+ memmove(&sin6->sin6_addr, addr, IPaddrlen);
+ hnputs(&sin6->sin6_port, port);
+
+ if(bind(fd, (struct sockaddr*)sin6, sizeof(*sin6)) < 0)
+ oserror();
+}
+
+static int
+resolve(char *name, char **hostv, int n, int isnumeric)
+{
+ int i;
+ struct addrinfo *res0, *r;
+ char buf[5*8];
+ uchar addr[IPaddrlen];
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = isnumeric? AI_NUMERICHOST: 0;
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ if(getaddrinfo(name, nil, &hints, &res0) < 0)
+ return 0;
+ i = 0;
+ for(r = res0; r != nil && i < n; r = r->ai_next) {
+ if(r->ai_family == AF_INET)
+ v4tov6(addr, (uchar*)&((struct sockaddr_in*)r->ai_addr)->sin_addr);
+ else if(r->ai_family == AF_INET6)
+ memmove(addr, &((struct sockaddr_in6*)r->ai_addr)->sin6_addr, IPaddrlen);
+ else
+ continue;
+
+ snprint(buf, sizeof buf, "%I", addr);
+ hostv[i++] = strdup(buf);
+ }
+
+ freeaddrinfo(res0);
+ return i;
+}
+
+int
+so_gethostbyname(char *host, char **hostv, int n)
+{
+ return resolve(host, hostv, n, 0);
+}
+
+int
+so_gethostbyaddr(char *addr, char **hostv, int n)
+{
+ return resolve(addr, hostv, n, 1);
+}
+
+int
+so_getservbyname(char *service, char *net, char *port)
+{
+ ushort p;
+ struct servent *s;
+
+ s = getservbyname(service, net);
+ if(s == 0)
+ return -1;
+ p = s->s_port;
+ sprint(port, "%d", nhgets(&p));
+ return 0;
+}
+
+int
+so_hangup(int fd, int nolinger)
+{
+ int r;
+ static struct linger l = {1, 0};
+
+ osenter();
+ if(nolinger)
+ setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&l, sizeof(l));
+ r = shutdown(fd, 2);
+ if(r >= 0)
+ r = close(fd);
+ osleave();
+ return r;
+}
+
+void
+arpadd(char *ipaddr, char *eaddr, int n)
+{
+#ifdef SIOCGARP
+ struct arpreq a;
+ struct sockaddr_in pa;
+ int s;
+ uchar addr[IPaddrlen];
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ memset(&a, 0, sizeof(a));
+ memset(&pa, 0, sizeof(pa));
+ pa.sin_family = AF_INET;
+ pa.sin_port = 0;
+ parseip(addr, ipaddr);
+ if(!isv4(addr)){
+ close(s);
+ error(Ebadarg);
+ }
+ memmove(&pa.sin_addr, ipaddr+IPv4off, IPv4addrlen);
+ memmove(&a.arp_pa, &pa, sizeof(pa));
+ while(ioctl(s, SIOCGARP, &a) != -1) {
+ ioctl(s, SIOCDARP, &a);
+ memset(&a.arp_ha, 0, sizeof(a.arp_ha));
+ }
+ a.arp_ha.sa_family = AF_UNSPEC;
+ parsemac((uchar*)a.arp_ha.sa_data, eaddr, 6);
+ a.arp_flags = ATF_PERM;
+ if(ioctl(s, SIOCSARP, &a) == -1) {
+ oserrstr(up->env->errstr, ERRMAX);
+ close(s);
+ error(up->env->errstr);
+ }
+ close(s);
+#else
+ error("arp not implemented");
+#endif
+}
+
+int
+so_mustbind(int restricted, int port)
+{
+ return restricted || port != 0;
+}
+
+void
+so_keepalive(int fd, int ms)
+{
+ int on;
+
+ on = 1;
+ setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&on, sizeof(on));
+#ifdef TCP_KEEPIDLE
+ if(ms <= 120000)
+ ms = 120000;
+ ms /= 1000;
+ setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, (char*)&ms, sizeof(ms));
+#endif
+}