xref: /minix3/minix/lib/libc/sys/socket.c (revision 5dd8da10c5368f1f7c641252b24203c14ed8d051)
1433d6423SLionel Sambuc #include <sys/cdefs.h>
2433d6423SLionel Sambuc #include "namespace.h"
3433d6423SLionel Sambuc 
4433d6423SLionel Sambuc #ifdef __weak_alias
5433d6423SLionel Sambuc __weak_alias(socket, __socket30)
6433d6423SLionel Sambuc #endif
7433d6423SLionel Sambuc 
8433d6423SLionel Sambuc #include <errno.h>
9433d6423SLionel Sambuc #include <fcntl.h>
10433d6423SLionel Sambuc #include <signal.h>
11433d6423SLionel Sambuc #include <stdio.h>
12*5dd8da10SDavid van Moolenbroek #include <string.h>
13433d6423SLionel Sambuc #include <unistd.h>
14433d6423SLionel Sambuc #include <sys/socket.h>
157f5f010bSBen Gras 
16*5dd8da10SDavid van Moolenbroek #include <sys/ioctl.h>
17433d6423SLionel Sambuc #include <sys/ioc_net.h>
187f5f010bSBen Gras #include <net/hton.h>
197f5f010bSBen Gras #include <net/gen/in.h>
207f5f010bSBen Gras #include <net/gen/ether.h>
217f5f010bSBen Gras #include <net/gen/eth_hdr.h>
227f5f010bSBen Gras #include <net/gen/eth_io.h>
237f5f010bSBen Gras #include <net/gen/ip_hdr.h>
247f5f010bSBen Gras #include <net/gen/ip_io.h>
257f5f010bSBen Gras #include <net/gen/udp.h>
267f5f010bSBen Gras #include <net/gen/udp_hdr.h>
277f5f010bSBen Gras #include <net/gen/udp_io.h>
287f5f010bSBen Gras #include <net/gen/dhcp.h>
29433d6423SLionel Sambuc 
30433d6423SLionel Sambuc #include <net/netlib.h>
31433d6423SLionel Sambuc #include <netinet/in.h>
32433d6423SLionel Sambuc 
33433d6423SLionel Sambuc #define DEBUG 0
34433d6423SLionel Sambuc 
35433d6423SLionel Sambuc static int _tcp_socket(int type, int protocol);
36433d6423SLionel Sambuc static int _udp_socket(int type, int protocol);
37433d6423SLionel Sambuc static int _uds_socket(int type, int protocol);
387f5f010bSBen Gras static int _raw_socket(int type, int protocol);
39433d6423SLionel Sambuc static void _socket_flags(int type, int *result);
40433d6423SLionel Sambuc 
41433d6423SLionel Sambuc int socket(int domain, int type, int protocol)
42433d6423SLionel Sambuc {
43433d6423SLionel Sambuc 	int sock_type;
44433d6423SLionel Sambuc 
45433d6423SLionel Sambuc 	sock_type = type & ~SOCK_FLAGS_MASK;
46433d6423SLionel Sambuc 
47433d6423SLionel Sambuc #if DEBUG
48433d6423SLionel Sambuc 	fprintf(stderr, "socket: domain %d, type %d, protocol %d\n",
49433d6423SLionel Sambuc 		domain, type, protocol);
50433d6423SLionel Sambuc #endif
51433d6423SLionel Sambuc 	if (domain != AF_INET && domain != AF_UNIX)
52433d6423SLionel Sambuc 	{
53433d6423SLionel Sambuc #if DEBUG
54433d6423SLionel Sambuc 		fprintf(stderr, "socket: bad domain %d\n", domain);
55433d6423SLionel Sambuc #endif
56433d6423SLionel Sambuc 		errno= EAFNOSUPPORT;
57433d6423SLionel Sambuc 		return -1;
58433d6423SLionel Sambuc 	}
59433d6423SLionel Sambuc 
60433d6423SLionel Sambuc 	if (domain == AF_UNIX && (sock_type == SOCK_STREAM ||
61433d6423SLionel Sambuc 				  sock_type == SOCK_DGRAM ||
62433d6423SLionel Sambuc 				  sock_type == SOCK_SEQPACKET))
63433d6423SLionel Sambuc 		return _uds_socket(type, protocol);
64433d6423SLionel Sambuc 
65433d6423SLionel Sambuc 	if (domain == AF_INET && sock_type == SOCK_STREAM)
66433d6423SLionel Sambuc 		return _tcp_socket(type, protocol);
67433d6423SLionel Sambuc 
68433d6423SLionel Sambuc 	if (domain == AF_INET && sock_type == SOCK_DGRAM)
69433d6423SLionel Sambuc 		return _udp_socket(type, protocol);
70433d6423SLionel Sambuc 
717f5f010bSBen Gras 	if (domain == AF_INET && sock_type == SOCK_RAW && protocol == IPPROTO_ICMP)
727f5f010bSBen Gras 		return _raw_socket(type, protocol);
737f5f010bSBen Gras 
747f5f010bSBen Gras 	if (domain == AF_INET && sock_type == SOCK_RAW && protocol == IPPROTO_UDP)
757f5f010bSBen Gras 		return _raw_socket(type, protocol);
767f5f010bSBen Gras 
77433d6423SLionel Sambuc #if DEBUG
78433d6423SLionel Sambuc 	fprintf(stderr, "socket: nothing for domain %d, type %d, protocol %d\n",
79433d6423SLionel Sambuc 		domain, type, protocol);
80433d6423SLionel Sambuc #endif
81433d6423SLionel Sambuc 	errno= EPROTOTYPE;
82433d6423SLionel Sambuc 	return -1;
83433d6423SLionel Sambuc }
84433d6423SLionel Sambuc 
85433d6423SLionel Sambuc static void
86433d6423SLionel Sambuc _socket_flags(int type, int *result)
87433d6423SLionel Sambuc {
88433d6423SLionel Sambuc 	/* Process socket flags */
89433d6423SLionel Sambuc 	if (type & SOCK_CLOEXEC) {
90433d6423SLionel Sambuc 		*result |= O_CLOEXEC;
91433d6423SLionel Sambuc 	}
92433d6423SLionel Sambuc 	if (type & SOCK_NONBLOCK) {
93433d6423SLionel Sambuc 		*result |= O_NONBLOCK;
94433d6423SLionel Sambuc 	}
95433d6423SLionel Sambuc 	if (type & SOCK_NOSIGPIPE) {
96433d6423SLionel Sambuc 		*result |= O_NOSIGPIPE;
97433d6423SLionel Sambuc 	}
98433d6423SLionel Sambuc }
99433d6423SLionel Sambuc 
100433d6423SLionel Sambuc static int _tcp_socket(int type, int protocol)
101433d6423SLionel Sambuc {
102433d6423SLionel Sambuc 	int flags = O_RDWR;
103433d6423SLionel Sambuc 
104433d6423SLionel Sambuc 	if (protocol != 0 && protocol != IPPROTO_TCP)
105433d6423SLionel Sambuc 	{
106433d6423SLionel Sambuc #if DEBUG
107433d6423SLionel Sambuc 		fprintf(stderr, "socket(tcp): bad protocol %d\n", protocol);
108433d6423SLionel Sambuc #endif
109433d6423SLionel Sambuc 		errno= EPROTONOSUPPORT;
110433d6423SLionel Sambuc 		return -1;
111433d6423SLionel Sambuc 	}
112433d6423SLionel Sambuc 
113433d6423SLionel Sambuc 	_socket_flags(type, &flags);
114433d6423SLionel Sambuc 
115433d6423SLionel Sambuc 	return open(TCP_DEVICE, flags);
116433d6423SLionel Sambuc }
117433d6423SLionel Sambuc 
118433d6423SLionel Sambuc static int _udp_socket(int type, int protocol)
119433d6423SLionel Sambuc {
120433d6423SLionel Sambuc 	int r, fd, t_errno, flags = O_RDWR;
121433d6423SLionel Sambuc 	struct sockaddr_in sin;
122433d6423SLionel Sambuc 
123433d6423SLionel Sambuc 	if (protocol != 0 && protocol != IPPROTO_UDP)
124433d6423SLionel Sambuc 	{
125433d6423SLionel Sambuc #if DEBUG
126433d6423SLionel Sambuc 		fprintf(stderr, "socket(udp): bad protocol %d\n", protocol);
127433d6423SLionel Sambuc #endif
128433d6423SLionel Sambuc 		errno= EPROTONOSUPPORT;
129433d6423SLionel Sambuc 		return -1;
130433d6423SLionel Sambuc 	}
131433d6423SLionel Sambuc 	_socket_flags(type, &flags);
132433d6423SLionel Sambuc 	fd= open(UDP_DEVICE, flags);
133433d6423SLionel Sambuc 	if (fd == -1)
134433d6423SLionel Sambuc 		return fd;
135433d6423SLionel Sambuc 
136433d6423SLionel Sambuc 	/* Bind is implict for UDP sockets? */
137433d6423SLionel Sambuc 	sin.sin_family= AF_INET;
138433d6423SLionel Sambuc 	sin.sin_addr.s_addr= INADDR_ANY;
139433d6423SLionel Sambuc 	sin.sin_port= 0;
140433d6423SLionel Sambuc 	r= bind(fd, (struct sockaddr *)&sin, sizeof(sin));
141433d6423SLionel Sambuc 	if (r != 0)
142433d6423SLionel Sambuc 	{
143433d6423SLionel Sambuc 		t_errno= errno;
144433d6423SLionel Sambuc 		close(fd);
145433d6423SLionel Sambuc 		errno= t_errno;
146433d6423SLionel Sambuc 		return -1;
147433d6423SLionel Sambuc 	}
148433d6423SLionel Sambuc 	return fd;
149433d6423SLionel Sambuc }
150433d6423SLionel Sambuc 
1517f5f010bSBen Gras static int _raw_socket(int type, int protocol)
1527f5f010bSBen Gras {
153*5dd8da10SDavid van Moolenbroek 	int fd, flags = O_RDWR;
1547f5f010bSBen Gras 	nwio_ipopt_t ipopt;
1557f5f010bSBen Gras 	int result;
1567f5f010bSBen Gras 
1577f5f010bSBen Gras 	if (protocol != IPPROTO_ICMP && protocol != IPPROTO_UDP && protocol != 0)
1587f5f010bSBen Gras 	{
1597f5f010bSBen Gras #if DEBUG
1607f5f010bSBen Gras 		fprintf(stderr, "socket(icmp): bad protocol %d\n", protocol);
1617f5f010bSBen Gras #endif
1627f5f010bSBen Gras 		errno= EPROTONOSUPPORT;
1637f5f010bSBen Gras 		return -1;
1647f5f010bSBen Gras 	}
1657f5f010bSBen Gras 	_socket_flags(type, &flags);
1667f5f010bSBen Gras 	fd= open(IP_DEVICE, flags);
1677f5f010bSBen Gras 	if (fd == -1)
1687f5f010bSBen Gras 		return fd;
1697f5f010bSBen Gras 
1707f5f010bSBen Gras 	memset(&ipopt, 0, sizeof(ipopt));
1717f5f010bSBen Gras 
1727f5f010bSBen Gras         ipopt.nwio_flags= NWIO_COPY;
1737f5f010bSBen Gras 
1747f5f010bSBen Gras 	if(protocol) {
1757f5f010bSBen Gras         	ipopt.nwio_flags |= NWIO_PROTOSPEC;
1767f5f010bSBen Gras 	        ipopt.nwio_proto = protocol;
1777f5f010bSBen Gras 	}
1787f5f010bSBen Gras 
1797f5f010bSBen Gras         result = ioctl (fd, NWIOSIPOPT, &ipopt);
1807f5f010bSBen Gras         if (result<0) {
1817f5f010bSBen Gras 		close(fd);
1827f5f010bSBen Gras 		return -1;
1837f5f010bSBen Gras 	}
1847f5f010bSBen Gras 
1857f5f010bSBen Gras         result = ioctl (fd, NWIOGIPOPT, &ipopt);
1867f5f010bSBen Gras         if (result<0) {
1877f5f010bSBen Gras 		close(fd);
1887f5f010bSBen Gras 		return -1;
1897f5f010bSBen Gras 	}
1907f5f010bSBen Gras 
1917f5f010bSBen Gras 	return fd;
1927f5f010bSBen Gras }
1937f5f010bSBen Gras 
194433d6423SLionel Sambuc static int _uds_socket(int type, int protocol)
195433d6423SLionel Sambuc {
196433d6423SLionel Sambuc 	int fd, r, flags = O_RDWR, sock_type;
197433d6423SLionel Sambuc 	if (protocol != 0)
198433d6423SLionel Sambuc 	{
199433d6423SLionel Sambuc #if DEBUG
200433d6423SLionel Sambuc 		fprintf(stderr, "socket(uds): bad protocol %d\n", protocol);
201433d6423SLionel Sambuc #endif
202433d6423SLionel Sambuc 		errno= EPROTONOSUPPORT;
203433d6423SLionel Sambuc 		return -1;
204433d6423SLionel Sambuc 	}
205433d6423SLionel Sambuc 
206433d6423SLionel Sambuc 	_socket_flags(type, &flags);
207433d6423SLionel Sambuc 	fd= open(UDS_DEVICE, flags);
208433d6423SLionel Sambuc 	if (fd == -1) {
209433d6423SLionel Sambuc 		return fd;
210433d6423SLionel Sambuc 	}
211433d6423SLionel Sambuc 
212433d6423SLionel Sambuc 	/* set the type for the socket via ioctl (SOCK_DGRAM,
213433d6423SLionel Sambuc 	 * SOCK_STREAM, SOCK_SEQPACKET, etc)
214433d6423SLionel Sambuc 	 */
215433d6423SLionel Sambuc 	sock_type = type & ~SOCK_FLAGS_MASK;
216433d6423SLionel Sambuc 	r= ioctl(fd, NWIOSUDSTYPE, &sock_type);
217433d6423SLionel Sambuc 	if (r == -1) {
218433d6423SLionel Sambuc 		int ioctl_errno;
219433d6423SLionel Sambuc 
220433d6423SLionel Sambuc 		/* if that failed rollback socket creation */
221433d6423SLionel Sambuc 		ioctl_errno= errno;
222433d6423SLionel Sambuc 		close(fd);
223433d6423SLionel Sambuc 
224433d6423SLionel Sambuc 		/* return the error thrown by the call to ioctl */
225433d6423SLionel Sambuc 		errno= ioctl_errno;
226433d6423SLionel Sambuc 		return -1;
227433d6423SLionel Sambuc 	}
228433d6423SLionel Sambuc 
229433d6423SLionel Sambuc 	return fd;
230433d6423SLionel Sambuc }
231