1433d6423SLionel Sambuc #include <sys/cdefs.h>
2433d6423SLionel Sambuc #include "namespace.h"
3c38dbb97SDavid van Moolenbroek #include <lib.h>
4433d6423SLionel Sambuc
5433d6423SLionel Sambuc #ifdef __weak_alias
6433d6423SLionel Sambuc __weak_alias(socket, __socket30)
7433d6423SLionel Sambuc #endif
8433d6423SLionel Sambuc
9433d6423SLionel Sambuc #include <errno.h>
10433d6423SLionel Sambuc #include <fcntl.h>
11433d6423SLionel Sambuc #include <signal.h>
12433d6423SLionel Sambuc #include <stdio.h>
135dd8da10SDavid van Moolenbroek #include <string.h>
14433d6423SLionel Sambuc #include <unistd.h>
15433d6423SLionel Sambuc #include <sys/socket.h>
167f5f010bSBen Gras
175dd8da10SDavid van Moolenbroek #include <sys/ioctl.h>
18433d6423SLionel Sambuc #include <sys/ioc_net.h>
197f5f010bSBen Gras #include <net/hton.h>
207f5f010bSBen Gras #include <net/gen/in.h>
217f5f010bSBen Gras #include <net/gen/ether.h>
227f5f010bSBen Gras #include <net/gen/eth_hdr.h>
237f5f010bSBen Gras #include <net/gen/eth_io.h>
247f5f010bSBen Gras #include <net/gen/ip_hdr.h>
257f5f010bSBen Gras #include <net/gen/ip_io.h>
267f5f010bSBen Gras #include <net/gen/udp.h>
277f5f010bSBen Gras #include <net/gen/udp_hdr.h>
287f5f010bSBen Gras #include <net/gen/udp_io.h>
297f5f010bSBen Gras #include <net/gen/dhcp.h>
30433d6423SLionel Sambuc
31433d6423SLionel Sambuc #include <net/netlib.h>
32433d6423SLionel Sambuc #include <netinet/in.h>
33433d6423SLionel Sambuc
34433d6423SLionel Sambuc #define DEBUG 0
35433d6423SLionel Sambuc
36433d6423SLionel Sambuc static int _tcp_socket(int type, int protocol);
37433d6423SLionel Sambuc static int _udp_socket(int type, int protocol);
38433d6423SLionel Sambuc static int _uds_socket(int type, int protocol);
397f5f010bSBen Gras static int _raw_socket(int type, int protocol);
40433d6423SLionel Sambuc static void _socket_flags(int type, int *result);
41433d6423SLionel Sambuc
42c38dbb97SDavid van Moolenbroek /*
43c38dbb97SDavid van Moolenbroek * Create a socket.
44c38dbb97SDavid van Moolenbroek */
45c38dbb97SDavid van Moolenbroek static int
__socket(int domain,int type,int protocol)46c38dbb97SDavid van Moolenbroek __socket(int domain, int type, int protocol)
47c38dbb97SDavid van Moolenbroek {
48c38dbb97SDavid van Moolenbroek message m;
49c38dbb97SDavid van Moolenbroek
50c38dbb97SDavid van Moolenbroek memset(&m, 0, sizeof(m));
51c38dbb97SDavid van Moolenbroek m.m_lc_vfs_socket.domain = domain;
52c38dbb97SDavid van Moolenbroek m.m_lc_vfs_socket.type = type;
53c38dbb97SDavid van Moolenbroek m.m_lc_vfs_socket.protocol = protocol;
54c38dbb97SDavid van Moolenbroek
55c38dbb97SDavid van Moolenbroek return _syscall(VFS_PROC_NR, VFS_SOCKET, &m);
56c38dbb97SDavid van Moolenbroek }
57c38dbb97SDavid van Moolenbroek
socket(int domain,int type,int protocol)58433d6423SLionel Sambuc int socket(int domain, int type, int protocol)
59433d6423SLionel Sambuc {
60c38dbb97SDavid van Moolenbroek int r, sock_type;
61c38dbb97SDavid van Moolenbroek
62c38dbb97SDavid van Moolenbroek r = __socket(domain, type, protocol);
63*84ed480eSDavid van Moolenbroek if (r != -1 || (errno != EAFNOSUPPORT && errno != ENOSYS))
64c38dbb97SDavid van Moolenbroek return r;
65433d6423SLionel Sambuc
66433d6423SLionel Sambuc sock_type = type & ~SOCK_FLAGS_MASK;
67433d6423SLionel Sambuc
68433d6423SLionel Sambuc #if DEBUG
69433d6423SLionel Sambuc fprintf(stderr, "socket: domain %d, type %d, protocol %d\n",
70433d6423SLionel Sambuc domain, type, protocol);
71433d6423SLionel Sambuc #endif
72433d6423SLionel Sambuc
73c38dbb97SDavid van Moolenbroek if (domain == AF_UNIX)
74433d6423SLionel Sambuc return _uds_socket(type, protocol);
75433d6423SLionel Sambuc
76c38dbb97SDavid van Moolenbroek if (domain == AF_INET) {
77c38dbb97SDavid van Moolenbroek switch (sock_type) {
78c38dbb97SDavid van Moolenbroek case SOCK_STREAM:
79433d6423SLionel Sambuc return _tcp_socket(type, protocol);
80c38dbb97SDavid van Moolenbroek case SOCK_DGRAM:
81433d6423SLionel Sambuc return _udp_socket(type, protocol);
82c38dbb97SDavid van Moolenbroek case SOCK_RAW:
837f5f010bSBen Gras return _raw_socket(type, protocol);
84c38dbb97SDavid van Moolenbroek default:
85433d6423SLionel Sambuc errno = EPROTOTYPE;
86433d6423SLionel Sambuc return -1;
87433d6423SLionel Sambuc }
88c38dbb97SDavid van Moolenbroek }
89c38dbb97SDavid van Moolenbroek
90c38dbb97SDavid van Moolenbroek errno = EAFNOSUPPORT;
91c38dbb97SDavid van Moolenbroek return -1;
92c38dbb97SDavid van Moolenbroek }
93433d6423SLionel Sambuc
94433d6423SLionel Sambuc static void
_socket_flags(int type,int * result)95433d6423SLionel Sambuc _socket_flags(int type, int *result)
96433d6423SLionel Sambuc {
97433d6423SLionel Sambuc /* Process socket flags */
98433d6423SLionel Sambuc if (type & SOCK_CLOEXEC) {
99433d6423SLionel Sambuc *result |= O_CLOEXEC;
100433d6423SLionel Sambuc }
101433d6423SLionel Sambuc if (type & SOCK_NONBLOCK) {
102433d6423SLionel Sambuc *result |= O_NONBLOCK;
103433d6423SLionel Sambuc }
104433d6423SLionel Sambuc if (type & SOCK_NOSIGPIPE) {
105433d6423SLionel Sambuc *result |= O_NOSIGPIPE;
106433d6423SLionel Sambuc }
107433d6423SLionel Sambuc }
108433d6423SLionel Sambuc
_tcp_socket(int type,int protocol)109433d6423SLionel Sambuc static int _tcp_socket(int type, int protocol)
110433d6423SLionel Sambuc {
111433d6423SLionel Sambuc int flags = O_RDWR;
112433d6423SLionel Sambuc
113433d6423SLionel Sambuc if (protocol != 0 && protocol != IPPROTO_TCP)
114433d6423SLionel Sambuc {
115433d6423SLionel Sambuc #if DEBUG
116433d6423SLionel Sambuc fprintf(stderr, "socket(tcp): bad protocol %d\n", protocol);
117433d6423SLionel Sambuc #endif
118433d6423SLionel Sambuc errno= EPROTONOSUPPORT;
119433d6423SLionel Sambuc return -1;
120433d6423SLionel Sambuc }
121433d6423SLionel Sambuc
122433d6423SLionel Sambuc _socket_flags(type, &flags);
123433d6423SLionel Sambuc
124433d6423SLionel Sambuc return open(TCP_DEVICE, flags);
125433d6423SLionel Sambuc }
126433d6423SLionel Sambuc
_udp_socket(int type,int protocol)127433d6423SLionel Sambuc static int _udp_socket(int type, int protocol)
128433d6423SLionel Sambuc {
129433d6423SLionel Sambuc int r, fd, t_errno, flags = O_RDWR;
130433d6423SLionel Sambuc struct sockaddr_in sin;
131433d6423SLionel Sambuc
132433d6423SLionel Sambuc if (protocol != 0 && protocol != IPPROTO_UDP)
133433d6423SLionel Sambuc {
134433d6423SLionel Sambuc #if DEBUG
135433d6423SLionel Sambuc fprintf(stderr, "socket(udp): bad protocol %d\n", protocol);
136433d6423SLionel Sambuc #endif
137433d6423SLionel Sambuc errno= EPROTONOSUPPORT;
138433d6423SLionel Sambuc return -1;
139433d6423SLionel Sambuc }
140433d6423SLionel Sambuc _socket_flags(type, &flags);
141433d6423SLionel Sambuc fd= open(UDP_DEVICE, flags);
142433d6423SLionel Sambuc if (fd == -1)
143433d6423SLionel Sambuc return fd;
144433d6423SLionel Sambuc
145433d6423SLionel Sambuc /* Bind is implict for UDP sockets? */
146433d6423SLionel Sambuc sin.sin_family= AF_INET;
147433d6423SLionel Sambuc sin.sin_addr.s_addr= INADDR_ANY;
148433d6423SLionel Sambuc sin.sin_port= 0;
149433d6423SLionel Sambuc r= bind(fd, (struct sockaddr *)&sin, sizeof(sin));
150433d6423SLionel Sambuc if (r != 0)
151433d6423SLionel Sambuc {
152433d6423SLionel Sambuc t_errno= errno;
153433d6423SLionel Sambuc close(fd);
154433d6423SLionel Sambuc errno= t_errno;
155433d6423SLionel Sambuc return -1;
156433d6423SLionel Sambuc }
157433d6423SLionel Sambuc return fd;
158433d6423SLionel Sambuc }
159433d6423SLionel Sambuc
_raw_socket(int type,int protocol)1607f5f010bSBen Gras static int _raw_socket(int type, int protocol)
1617f5f010bSBen Gras {
1625dd8da10SDavid van Moolenbroek int fd, flags = O_RDWR;
1637f5f010bSBen Gras nwio_ipopt_t ipopt;
1647f5f010bSBen Gras int result;
1657f5f010bSBen Gras
1667f5f010bSBen Gras if (protocol != IPPROTO_ICMP && protocol != IPPROTO_UDP && protocol != 0)
1677f5f010bSBen Gras {
1687f5f010bSBen Gras #if DEBUG
1697f5f010bSBen Gras fprintf(stderr, "socket(icmp): bad protocol %d\n", protocol);
1707f5f010bSBen Gras #endif
1717f5f010bSBen Gras errno= EPROTONOSUPPORT;
1727f5f010bSBen Gras return -1;
1737f5f010bSBen Gras }
1747f5f010bSBen Gras _socket_flags(type, &flags);
1757f5f010bSBen Gras fd= open(IP_DEVICE, flags);
1767f5f010bSBen Gras if (fd == -1)
1777f5f010bSBen Gras return fd;
1787f5f010bSBen Gras
1797f5f010bSBen Gras memset(&ipopt, 0, sizeof(ipopt));
1807f5f010bSBen Gras
1817f5f010bSBen Gras ipopt.nwio_flags= NWIO_COPY;
1827f5f010bSBen Gras
1837f5f010bSBen Gras if(protocol) {
1847f5f010bSBen Gras ipopt.nwio_flags |= NWIO_PROTOSPEC;
1857f5f010bSBen Gras ipopt.nwio_proto = protocol;
1867f5f010bSBen Gras }
1877f5f010bSBen Gras
1887f5f010bSBen Gras result = ioctl (fd, NWIOSIPOPT, &ipopt);
1897f5f010bSBen Gras if (result<0) {
1907f5f010bSBen Gras close(fd);
1917f5f010bSBen Gras return -1;
1927f5f010bSBen Gras }
1937f5f010bSBen Gras
1947f5f010bSBen Gras result = ioctl (fd, NWIOGIPOPT, &ipopt);
1957f5f010bSBen Gras if (result<0) {
1967f5f010bSBen Gras close(fd);
1977f5f010bSBen Gras return -1;
1987f5f010bSBen Gras }
1997f5f010bSBen Gras
2007f5f010bSBen Gras return fd;
2017f5f010bSBen Gras }
2027f5f010bSBen Gras
_uds_socket(int type,int protocol)203433d6423SLionel Sambuc static int _uds_socket(int type, int protocol)
204433d6423SLionel Sambuc {
205433d6423SLionel Sambuc int fd, r, flags = O_RDWR, sock_type;
206c38dbb97SDavid van Moolenbroek
207c38dbb97SDavid van Moolenbroek sock_type = type & ~SOCK_FLAGS_MASK;
208c38dbb97SDavid van Moolenbroek if (sock_type != SOCK_STREAM &&
209c38dbb97SDavid van Moolenbroek sock_type != SOCK_DGRAM &&
210c38dbb97SDavid van Moolenbroek sock_type != SOCK_SEQPACKET) {
211c38dbb97SDavid van Moolenbroek errno = EPROTOTYPE;
212c38dbb97SDavid van Moolenbroek return -1;
213c38dbb97SDavid van Moolenbroek }
214c38dbb97SDavid van Moolenbroek
215433d6423SLionel Sambuc if (protocol != 0)
216433d6423SLionel Sambuc {
217433d6423SLionel Sambuc #if DEBUG
218433d6423SLionel Sambuc fprintf(stderr, "socket(uds): bad protocol %d\n", protocol);
219433d6423SLionel Sambuc #endif
220433d6423SLionel Sambuc errno= EPROTONOSUPPORT;
221433d6423SLionel Sambuc return -1;
222433d6423SLionel Sambuc }
223433d6423SLionel Sambuc
224433d6423SLionel Sambuc _socket_flags(type, &flags);
225433d6423SLionel Sambuc fd= open(UDS_DEVICE, flags);
226433d6423SLionel Sambuc if (fd == -1) {
227433d6423SLionel Sambuc return fd;
228433d6423SLionel Sambuc }
229433d6423SLionel Sambuc
230433d6423SLionel Sambuc /* set the type for the socket via ioctl (SOCK_DGRAM,
231433d6423SLionel Sambuc * SOCK_STREAM, SOCK_SEQPACKET, etc)
232433d6423SLionel Sambuc */
233433d6423SLionel Sambuc r= ioctl(fd, NWIOSUDSTYPE, &sock_type);
234433d6423SLionel Sambuc if (r == -1) {
235433d6423SLionel Sambuc int ioctl_errno;
236433d6423SLionel Sambuc
237433d6423SLionel Sambuc /* if that failed rollback socket creation */
238433d6423SLionel Sambuc ioctl_errno= errno;
239433d6423SLionel Sambuc close(fd);
240433d6423SLionel Sambuc
241433d6423SLionel Sambuc /* return the error thrown by the call to ioctl */
242433d6423SLionel Sambuc errno= ioctl_errno;
243433d6423SLionel Sambuc return -1;
244433d6423SLionel Sambuc }
245433d6423SLionel Sambuc
246433d6423SLionel Sambuc return fd;
247433d6423SLionel Sambuc }
248