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