xref: /minix3/minix/lib/libc/sys/setsockopt.c (revision 27852ebe53d5bf221cf5058cb7e858fa8fa8895e)
1433d6423SLionel Sambuc #include <sys/cdefs.h>
2433d6423SLionel Sambuc #include "namespace.h"
3c38dbb97SDavid van Moolenbroek #include <lib.h>
4433d6423SLionel Sambuc 
5c38dbb97SDavid van Moolenbroek #include <string.h>
6433d6423SLionel Sambuc #include <assert.h>
7433d6423SLionel Sambuc #include <errno.h>
8433d6423SLionel Sambuc #include <stdio.h>
9433d6423SLionel Sambuc #include <sys/ioctl.h>
10433d6423SLionel Sambuc #include <sys/socket.h>
11433d6423SLionel Sambuc #include <sys/types.h>
12433d6423SLionel Sambuc #include <netinet/tcp.h>
13433d6423SLionel Sambuc 
14433d6423SLionel Sambuc #include <net/gen/in.h>
15433d6423SLionel Sambuc #include <net/gen/tcp.h>
16433d6423SLionel Sambuc #include <net/gen/tcp_io.h>
17433d6423SLionel Sambuc #include <net/gen/udp.h>
18433d6423SLionel Sambuc #include <net/gen/udp_io.h>
19433d6423SLionel Sambuc 
20433d6423SLionel Sambuc #define DEBUG 0
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc static int _tcp_setsockopt(int sock, int level, int option_name,
23433d6423SLionel Sambuc 	const void *option_value, socklen_t option_len);
24433d6423SLionel Sambuc 
25433d6423SLionel Sambuc static int _udp_setsockopt(int sock, int level, int option_name,
26433d6423SLionel Sambuc 	const void *option_value, socklen_t option_len);
27433d6423SLionel Sambuc 
28433d6423SLionel Sambuc static int _uds_setsockopt(int sock, int level, int option_name,
29433d6423SLionel Sambuc 	const void *option_value, socklen_t option_len);
30433d6423SLionel Sambuc 
31c38dbb97SDavid van Moolenbroek /*
32c38dbb97SDavid van Moolenbroek  * Set socket options.
33c38dbb97SDavid van Moolenbroek  */
34c38dbb97SDavid van Moolenbroek static int
__setsockopt(int fd,int level,int option_name,const void * option_value,socklen_t option_len)35c38dbb97SDavid van Moolenbroek __setsockopt(int fd, int level, int option_name, const void * option_value,
36c38dbb97SDavid van Moolenbroek 	socklen_t option_len)
37c38dbb97SDavid van Moolenbroek {
38c38dbb97SDavid van Moolenbroek 	message m;
39c38dbb97SDavid van Moolenbroek 
40c38dbb97SDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
41c38dbb97SDavid van Moolenbroek 	m.m_lc_vfs_sockopt.fd = fd;
42c38dbb97SDavid van Moolenbroek 	m.m_lc_vfs_sockopt.level = level;
43c38dbb97SDavid van Moolenbroek 	m.m_lc_vfs_sockopt.name = option_name;
44c38dbb97SDavid van Moolenbroek 	m.m_lc_vfs_sockopt.buf = (vir_bytes)option_value;
45c38dbb97SDavid van Moolenbroek 	m.m_lc_vfs_sockopt.len = option_len;
46c38dbb97SDavid van Moolenbroek 
47c38dbb97SDavid van Moolenbroek 	return _syscall(VFS_PROC_NR, VFS_SETSOCKOPT, &m);
48c38dbb97SDavid van Moolenbroek }
49c38dbb97SDavid van Moolenbroek 
setsockopt(int sock,int level,int option_name,const void * option_value,socklen_t option_len)50433d6423SLionel Sambuc int setsockopt(int sock, int level, int option_name,
51433d6423SLionel Sambuc         const void *option_value, socklen_t option_len)
52433d6423SLionel Sambuc {
53433d6423SLionel Sambuc 	int r;
54433d6423SLionel Sambuc 	nwio_tcpopt_t tcpopt;
55433d6423SLionel Sambuc 	nwio_udpopt_t udpopt;
56433d6423SLionel Sambuc 	struct sockaddr_un uds_addr;
57433d6423SLionel Sambuc 
58c38dbb97SDavid van Moolenbroek 	r = __setsockopt(sock, level, option_name, option_value, option_len);
5984ed480eSDavid van Moolenbroek 	if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS))
60c38dbb97SDavid van Moolenbroek 		return r;
61c38dbb97SDavid van Moolenbroek 
62433d6423SLionel Sambuc 	r= ioctl(sock, NWIOGTCPOPT, &tcpopt);
63433d6423SLionel Sambuc 	if (r != -1 || errno != ENOTTY)
64433d6423SLionel Sambuc 	{
65433d6423SLionel Sambuc 		if (r == -1)
66433d6423SLionel Sambuc 		{
67433d6423SLionel Sambuc 			/* Bad file descriptor */
68433d6423SLionel Sambuc 			return -1;
69433d6423SLionel Sambuc 		}
70433d6423SLionel Sambuc 		return _tcp_setsockopt(sock, level, option_name,
71433d6423SLionel Sambuc 			option_value, option_len);
72433d6423SLionel Sambuc 	}
73433d6423SLionel Sambuc 
74433d6423SLionel Sambuc 	r= ioctl(sock, NWIOGUDPOPT, &udpopt);
75433d6423SLionel Sambuc 	if (r != -1 || errno != ENOTTY)
76433d6423SLionel Sambuc 	{
77433d6423SLionel Sambuc 		if (r == -1)
78433d6423SLionel Sambuc 		{
79433d6423SLionel Sambuc 			/* Bad file descriptor */
80433d6423SLionel Sambuc 			return -1;
81433d6423SLionel Sambuc 		}
82433d6423SLionel Sambuc 		return _udp_setsockopt(sock, level, option_name,
83433d6423SLionel Sambuc 			option_value, option_len);
84433d6423SLionel Sambuc 	}
85433d6423SLionel Sambuc 
86433d6423SLionel Sambuc 	r= ioctl(sock, NWIOGUDSADDR, &uds_addr);
87433d6423SLionel Sambuc 	if (r != -1 || errno != ENOTTY)
88433d6423SLionel Sambuc 	{
89433d6423SLionel Sambuc 		if (r == -1)
90433d6423SLionel Sambuc 		{
91433d6423SLionel Sambuc 			/* Bad file descriptor */
92433d6423SLionel Sambuc 			return -1;
93433d6423SLionel Sambuc 		}
94433d6423SLionel Sambuc 		return _uds_setsockopt(sock, level, option_name,
95433d6423SLionel Sambuc 			option_value, option_len);
96433d6423SLionel Sambuc 	}
97433d6423SLionel Sambuc 
98433d6423SLionel Sambuc 	errno = ENOTSOCK;
99433d6423SLionel Sambuc 	return -1;
100433d6423SLionel Sambuc }
101433d6423SLionel Sambuc 
_tcp_setsockopt(int sock,int level,int option_name,const void * option_value,socklen_t option_len)102433d6423SLionel Sambuc static int _tcp_setsockopt(int sock, int level, int option_name,
103433d6423SLionel Sambuc 	const void *option_value, socklen_t option_len)
104433d6423SLionel Sambuc {
105433d6423SLionel Sambuc 	int i;
106433d6423SLionel Sambuc 
107433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
108433d6423SLionel Sambuc 	{
109433d6423SLionel Sambuc 		if (option_len != sizeof(i))
110433d6423SLionel Sambuc 		{
111433d6423SLionel Sambuc 			errno= EINVAL;
112433d6423SLionel Sambuc 			return -1;
113433d6423SLionel Sambuc 		}
114433d6423SLionel Sambuc 		i= *(const int *)option_value;
115433d6423SLionel Sambuc 		if (!i)
116433d6423SLionel Sambuc 		{
117433d6423SLionel Sambuc 			/* At the moment there is no way to turn off
118433d6423SLionel Sambuc 			 * reusing addresses.
119433d6423SLionel Sambuc 			 */
120433d6423SLionel Sambuc 			errno= ENOSYS;
121433d6423SLionel Sambuc 			return -1;
122433d6423SLionel Sambuc 		}
123433d6423SLionel Sambuc 		return 0;
124433d6423SLionel Sambuc 	}
125433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_KEEPALIVE)
126433d6423SLionel Sambuc 	{
127433d6423SLionel Sambuc 		if (option_len != sizeof(i))
128433d6423SLionel Sambuc 		{
129433d6423SLionel Sambuc 			errno= EINVAL;
130433d6423SLionel Sambuc 			return -1;
131433d6423SLionel Sambuc 		}
132433d6423SLionel Sambuc 		i= *(const int *)option_value;
133433d6423SLionel Sambuc 		if (!i)
134433d6423SLionel Sambuc 		{
135433d6423SLionel Sambuc 			/* At the moment there is no way to turn off
136433d6423SLionel Sambuc 			 * keepalives.
137433d6423SLionel Sambuc 			 */
138433d6423SLionel Sambuc 			errno= ENOSYS;
139433d6423SLionel Sambuc 			return -1;
140433d6423SLionel Sambuc 		}
141433d6423SLionel Sambuc 		return 0;
142433d6423SLionel Sambuc 	}
143433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_RCVBUF)
144433d6423SLionel Sambuc 	{
145433d6423SLionel Sambuc 		if (option_len != sizeof(i))
146433d6423SLionel Sambuc 		{
147433d6423SLionel Sambuc 			errno= EINVAL;
148433d6423SLionel Sambuc 			return -1;
149433d6423SLionel Sambuc 		}
150433d6423SLionel Sambuc 		i= *(const int *)option_value;
151433d6423SLionel Sambuc 		if (i > 32*1024)
152433d6423SLionel Sambuc 		{
153433d6423SLionel Sambuc 			/* The receive buffer is limited to 32K at the moment.
154433d6423SLionel Sambuc 			 */
155433d6423SLionel Sambuc 			errno= ENOSYS;
156433d6423SLionel Sambuc 			return -1;
157433d6423SLionel Sambuc 		}
158433d6423SLionel Sambuc 		/* There is no way to reduce the receive buffer, do we have to
159433d6423SLionel Sambuc 		 * let this call fail for smaller buffers?
160433d6423SLionel Sambuc 		 */
161433d6423SLionel Sambuc 		return 0;
162433d6423SLionel Sambuc 	}
163433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_SNDBUF)
164433d6423SLionel Sambuc 	{
165433d6423SLionel Sambuc 		if (option_len != sizeof(i))
166433d6423SLionel Sambuc 		{
167433d6423SLionel Sambuc 			errno= EINVAL;
168433d6423SLionel Sambuc 			return -1;
169433d6423SLionel Sambuc 		}
170433d6423SLionel Sambuc 		i= *(const int *)option_value;
171433d6423SLionel Sambuc 		if (i > 32*1024)
172433d6423SLionel Sambuc 		{
173433d6423SLionel Sambuc 			/* The send buffer is limited to 32K at the moment.
174433d6423SLionel Sambuc 			 */
175433d6423SLionel Sambuc 			errno= ENOSYS;
176433d6423SLionel Sambuc 			return -1;
177433d6423SLionel Sambuc 		}
178433d6423SLionel Sambuc 		/* There is no way to reduce the send buffer, do we have to
179433d6423SLionel Sambuc 		 * let this call fail for smaller buffers?
180433d6423SLionel Sambuc 		 */
181433d6423SLionel Sambuc 		return 0;
182433d6423SLionel Sambuc 	}
183433d6423SLionel Sambuc 	if (level == IPPROTO_TCP && option_name == TCP_NODELAY)
184433d6423SLionel Sambuc 	{
185433d6423SLionel Sambuc 		if (option_len != sizeof(i))
186433d6423SLionel Sambuc 		{
187433d6423SLionel Sambuc 			errno= EINVAL;
188433d6423SLionel Sambuc 			return -1;
189433d6423SLionel Sambuc 		}
190433d6423SLionel Sambuc 		i= *(const int *)option_value;
191433d6423SLionel Sambuc 		if (i)
192433d6423SLionel Sambuc 		{
193433d6423SLionel Sambuc 			/* At the moment there is no way to turn on
194433d6423SLionel Sambuc 			 * nodelay.
195433d6423SLionel Sambuc 			 */
196433d6423SLionel Sambuc 			errno= ENOSYS;
197433d6423SLionel Sambuc 			return -1;
198433d6423SLionel Sambuc 		}
199433d6423SLionel Sambuc 		return 0;
200433d6423SLionel Sambuc 	}
201433d6423SLionel Sambuc #if DEBUG
202433d6423SLionel Sambuc 	fprintf(stderr, "_tcp_setsocketopt: level %d, name %d\n",
203433d6423SLionel Sambuc 		level, option_name);
204433d6423SLionel Sambuc #endif
205433d6423SLionel Sambuc 
206433d6423SLionel Sambuc 	errno= ENOSYS;
207433d6423SLionel Sambuc 	return -1;
208433d6423SLionel Sambuc }
209433d6423SLionel Sambuc 
_udp_setsockopt(int sock,int level,int option_name,const void * option_value,socklen_t option_len)210433d6423SLionel Sambuc static int _udp_setsockopt(int sock, int level, int option_name,
211433d6423SLionel Sambuc 	const void *option_value, socklen_t option_len)
212433d6423SLionel Sambuc {
213433d6423SLionel Sambuc #if DEBUG
214433d6423SLionel Sambuc 	fprintf(stderr, "_udp_setsocketopt: level %d, name %d\n",
215433d6423SLionel Sambuc 		level, option_name);
216433d6423SLionel Sambuc #endif
217433d6423SLionel Sambuc 
218433d6423SLionel Sambuc 	errno= ENOSYS;
219433d6423SLionel Sambuc 	return -1;
220433d6423SLionel Sambuc }
221433d6423SLionel Sambuc 
222433d6423SLionel Sambuc 
_uds_setsockopt(int sock,int level,int option_name,const void * option_value,socklen_t option_len)223433d6423SLionel Sambuc static int _uds_setsockopt(int sock, int level, int option_name,
224433d6423SLionel Sambuc 	const void *option_value, socklen_t option_len)
225433d6423SLionel Sambuc {
226433d6423SLionel Sambuc 	int i;
227433d6423SLionel Sambuc 	size_t size;
228433d6423SLionel Sambuc 
229433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_RCVBUF)
230433d6423SLionel Sambuc 	{
231433d6423SLionel Sambuc 		if (option_len != sizeof(size))
232433d6423SLionel Sambuc 		{
233433d6423SLionel Sambuc 			errno= EINVAL;
234433d6423SLionel Sambuc 			return -1;
235433d6423SLionel Sambuc 		}
236433d6423SLionel Sambuc 		size= *(const size_t *)option_value;
237433d6423SLionel Sambuc 		return ioctl(sock, NWIOSUDSRCVBUF, &size);
238433d6423SLionel Sambuc 	}
239433d6423SLionel Sambuc 
240433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_SNDBUF)
241433d6423SLionel Sambuc 	{
242433d6423SLionel Sambuc 		if (option_len != sizeof(size))
243433d6423SLionel Sambuc 		{
244433d6423SLionel Sambuc 			errno= EINVAL;
245433d6423SLionel Sambuc 			return -1;
246433d6423SLionel Sambuc 		}
247433d6423SLionel Sambuc 		size= *(const size_t *)option_value;
248433d6423SLionel Sambuc 		return ioctl(sock, NWIOSUDSSNDBUF, &size);
249433d6423SLionel Sambuc 	}
250433d6423SLionel Sambuc 
251433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
252433d6423SLionel Sambuc 	{
253433d6423SLionel Sambuc 		if (option_len != sizeof(i))
254433d6423SLionel Sambuc 		{
255433d6423SLionel Sambuc 			errno= EINVAL;
256433d6423SLionel Sambuc 			return -1;
257433d6423SLionel Sambuc 		}
258433d6423SLionel Sambuc 		i= *(const int *)option_value;
259433d6423SLionel Sambuc 		if (!i)
260433d6423SLionel Sambuc 		{
261433d6423SLionel Sambuc 			/* At the moment there is no way to turn off
262433d6423SLionel Sambuc 			 * reusing addresses.
263433d6423SLionel Sambuc 			 */
264433d6423SLionel Sambuc 			errno= ENOSYS;
265433d6423SLionel Sambuc 			return -1;
266433d6423SLionel Sambuc 		}
267433d6423SLionel Sambuc 		return 0;
268433d6423SLionel Sambuc 	}
269433d6423SLionel Sambuc 
270*27852ebeSDavid van Moolenbroek #ifdef SO_PASSCRED
271433d6423SLionel Sambuc 	if (level == SOL_SOCKET && option_name == SO_PASSCRED)
272433d6423SLionel Sambuc 	{
273433d6423SLionel Sambuc 		if (option_len != sizeof(i))
274433d6423SLionel Sambuc 		{
275433d6423SLionel Sambuc 			errno= EINVAL;
276433d6423SLionel Sambuc 			return -1;
277433d6423SLionel Sambuc 		}
278433d6423SLionel Sambuc 		i= *(const int *)option_value;
279433d6423SLionel Sambuc 		if (!i)
280433d6423SLionel Sambuc 		{
281433d6423SLionel Sambuc 			/* credentials can always be received. */
282433d6423SLionel Sambuc 			errno= ENOSYS;
283433d6423SLionel Sambuc 			return -1;
284433d6423SLionel Sambuc 		}
285433d6423SLionel Sambuc 		return 0;
286433d6423SLionel Sambuc 	}
287*27852ebeSDavid van Moolenbroek #endif
288433d6423SLionel Sambuc 
289433d6423SLionel Sambuc #if DEBUG
290433d6423SLionel Sambuc 	fprintf(stderr, "_uds_setsocketopt: level %d, name %d\n",
291433d6423SLionel Sambuc 		level, option_name);
292433d6423SLionel Sambuc #endif
293433d6423SLionel Sambuc 
294433d6423SLionel Sambuc 	errno= ENOSYS;
295433d6423SLionel Sambuc 	return -1;
296433d6423SLionel Sambuc }
297