xref: /minix3/minix/lib/libc/sys/socket.c (revision 84ed480ef770e26a28565a26c8ef94ba01312a41)
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