diff options
| author | forsyth <forsyth@vitanuova.com> | 2010-11-27 16:29:55 +0000 |
|---|---|---|
| committer | forsyth <forsyth@vitanuova.com> | 2010-11-27 16:29:55 +0000 |
| commit | 9adf220f1d2c1df54cc4d55c578d08741a5c280c (patch) | |
| tree | 9007aeed4096f8ce65efacb6426116fd2ec659d2 /emu | |
| parent | 6ce09f7706f6999009db17a5db2512eedece7f3f (diff) | |
20101127-1629
Diffstat (limited to 'emu')
| -rw-r--r-- | emu/DragonFly/emu | 2 | ||||
| -rw-r--r-- | emu/DragonFly/emu-g | 2 | ||||
| -rw-r--r-- | emu/FreeBSD/emu | 2 | ||||
| -rw-r--r-- | emu/Linux/emu-g | 2 | ||||
| -rw-r--r-- | emu/Linux/emu-wrt | 2 | ||||
| -rw-r--r-- | emu/MacOSX/emu | 2 | ||||
| -rw-r--r-- | emu/MacOSX/emu-g | 2 | ||||
| -rw-r--r-- | emu/NetBSD/emu | 2 | ||||
| -rw-r--r-- | emu/Nt/ipif.c | 2 | ||||
| -rw-r--r-- | emu/Nt/ipif6.c | 413 | ||||
| -rw-r--r-- | emu/OpenBSD/emu | 2 | ||||
| -rw-r--r-- | emu/Unixware/emu | 2 | ||||
| -rw-r--r-- | emu/port/devip.c | 45 | ||||
| -rw-r--r-- | emu/port/ip.h | 13 | ||||
| -rw-r--r-- | emu/port/ipif-posix.c | 46 | ||||
| -rw-r--r-- | emu/port/ipif6-posix.c | 415 |
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 +} |
