1433d6423SLionel Sambuc #include <sys/cdefs.h>
2433d6423SLionel Sambuc #include "namespace.h"
3c38dbb97SDavid van Moolenbroek #include <lib.h>
4433d6423SLionel Sambuc
5433d6423SLionel Sambuc #include <assert.h>
6433d6423SLionel Sambuc #include <errno.h>
7433d6423SLionel Sambuc #include <stdio.h>
8433d6423SLionel Sambuc #include <string.h>
9433d6423SLionel Sambuc #include <sys/ioctl.h>
10433d6423SLionel Sambuc #include <sys/socket.h>
11433d6423SLionel Sambuc #include <sys/types.h>
12433d6423SLionel Sambuc #include <sys/ucred.h>
13433d6423SLionel Sambuc #include <netinet/tcp.h>
14433d6423SLionel Sambuc
15433d6423SLionel Sambuc #include <net/gen/in.h>
16433d6423SLionel Sambuc #include <net/gen/tcp.h>
17433d6423SLionel Sambuc #include <net/gen/tcp_io.h>
18433d6423SLionel Sambuc #include <net/gen/udp.h>
19433d6423SLionel Sambuc #include <net/gen/udp_io.h>
20433d6423SLionel Sambuc
21433d6423SLionel Sambuc #include <minix/type.h>
22433d6423SLionel Sambuc
23433d6423SLionel Sambuc #define DEBUG 0
24433d6423SLionel Sambuc
25433d6423SLionel Sambuc static int _tcp_getsockopt(int sock, int level, int option_name,
26433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len);
27433d6423SLionel Sambuc static int _udp_getsockopt(int sock, int level, int option_name,
28433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len);
29433d6423SLionel Sambuc static int _uds_getsockopt(int sock, int level, int option_name,
30433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len);
31433d6423SLionel Sambuc static void getsockopt_copy(void *return_value, size_t return_len,
32433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len);
33433d6423SLionel Sambuc
34c38dbb97SDavid van Moolenbroek /*
35c38dbb97SDavid van Moolenbroek * Get socket options.
36c38dbb97SDavid van Moolenbroek */
37c38dbb97SDavid van Moolenbroek static int
__getsockopt(int fd,int level,int option_name,void * __restrict option_value,socklen_t * __restrict option_len)38c38dbb97SDavid van Moolenbroek __getsockopt(int fd, int level, int option_name,
39c38dbb97SDavid van Moolenbroek void * __restrict option_value, socklen_t * __restrict option_len)
40c38dbb97SDavid van Moolenbroek {
41c38dbb97SDavid van Moolenbroek message m;
42c38dbb97SDavid van Moolenbroek
43c38dbb97SDavid van Moolenbroek if (option_len == NULL) {
44c38dbb97SDavid van Moolenbroek errno = EFAULT;
45c38dbb97SDavid van Moolenbroek return -1;
46c38dbb97SDavid van Moolenbroek }
47c38dbb97SDavid van Moolenbroek
48c38dbb97SDavid van Moolenbroek memset(&m, 0, sizeof(m));
49c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockopt.fd = fd;
50c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockopt.level = level;
51c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockopt.name = option_name;
52c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockopt.buf = (vir_bytes)option_value;
53c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockopt.len = *option_len;
54c38dbb97SDavid van Moolenbroek
55c38dbb97SDavid van Moolenbroek if (_syscall(VFS_PROC_NR, VFS_GETSOCKOPT, &m) < 0)
56c38dbb97SDavid van Moolenbroek return -1;
57c38dbb97SDavid van Moolenbroek
58c38dbb97SDavid van Moolenbroek *option_len = m.m_vfs_lc_socklen.len;
59c38dbb97SDavid van Moolenbroek return 0;
60c38dbb97SDavid van Moolenbroek }
61c38dbb97SDavid van Moolenbroek
getsockopt(int sock,int level,int option_name,void * __restrict option_value,socklen_t * __restrict option_len)62433d6423SLionel Sambuc int getsockopt(int sock, int level, int option_name,
63433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len)
64433d6423SLionel Sambuc {
65433d6423SLionel Sambuc int r;
66433d6423SLionel Sambuc nwio_tcpopt_t tcpopt;
67433d6423SLionel Sambuc nwio_udpopt_t udpopt;
68433d6423SLionel Sambuc struct sockaddr_un uds_addr;
69433d6423SLionel Sambuc
70c38dbb97SDavid van Moolenbroek r = __getsockopt(sock, level, option_name, option_value, option_len);
7184ed480eSDavid van Moolenbroek if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS))
72c38dbb97SDavid van Moolenbroek return r;
73c38dbb97SDavid van Moolenbroek
74433d6423SLionel Sambuc r= ioctl(sock, NWIOGTCPOPT, &tcpopt);
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 _tcp_getsockopt(sock, level, option_name,
83433d6423SLionel Sambuc option_value, option_len);
84433d6423SLionel Sambuc }
85433d6423SLionel Sambuc
86433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDPOPT, &udpopt);
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 _udp_getsockopt(sock, level, option_name,
95433d6423SLionel Sambuc option_value, option_len);
96433d6423SLionel Sambuc }
97433d6423SLionel Sambuc
98433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSADDR, &uds_addr);
99433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY)
100433d6423SLionel Sambuc {
101433d6423SLionel Sambuc if (r == -1)
102433d6423SLionel Sambuc {
103433d6423SLionel Sambuc /* Bad file descriptor */
104433d6423SLionel Sambuc return -1;
105433d6423SLionel Sambuc }
106433d6423SLionel Sambuc return _uds_getsockopt(sock, level, option_name,
107433d6423SLionel Sambuc option_value, option_len);
108433d6423SLionel Sambuc }
109433d6423SLionel Sambuc
110433d6423SLionel Sambuc errno = ENOTSOCK;
111433d6423SLionel Sambuc return -1;
112433d6423SLionel Sambuc }
113433d6423SLionel Sambuc
getsockopt_copy(void * return_value,size_t return_len,void * __restrict option_value,socklen_t * __restrict option_len)114433d6423SLionel Sambuc static void getsockopt_copy(void *return_value, size_t return_len,
115433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len)
116433d6423SLionel Sambuc {
117433d6423SLionel Sambuc /* copy as much data as possible */
118433d6423SLionel Sambuc if (*option_len < return_len)
119433d6423SLionel Sambuc memcpy(option_value, return_value, *option_len);
120433d6423SLionel Sambuc else
121433d6423SLionel Sambuc memcpy(option_value, return_value, return_len);
122433d6423SLionel Sambuc
123433d6423SLionel Sambuc /* return length */
124433d6423SLionel Sambuc *option_len = return_len;
125433d6423SLionel Sambuc }
126433d6423SLionel Sambuc
_tcp_getsockopt(int sock,int level,int option_name,void * __restrict option_value,socklen_t * __restrict option_len)127433d6423SLionel Sambuc static int _tcp_getsockopt(int sock, int level, int option_name,
128433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len)
129433d6423SLionel Sambuc {
130433d6423SLionel Sambuc int i, r, err;
131433d6423SLionel Sambuc
132433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
133433d6423SLionel Sambuc {
134433d6423SLionel Sambuc i = 1; /* Binds to TIME_WAIT sockets never cause errors */
135433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len);
136433d6423SLionel Sambuc return 0;
137433d6423SLionel Sambuc }
138433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_KEEPALIVE)
139433d6423SLionel Sambuc {
140433d6423SLionel Sambuc i = 1; /* Keepalive is always on */
141433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len);
142433d6423SLionel Sambuc return 0;
143433d6423SLionel Sambuc }
144433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_ERROR)
145433d6423SLionel Sambuc {
146433d6423SLionel Sambuc r = ioctl(sock, NWIOTCPGERROR, &err);
147433d6423SLionel Sambuc if (r != 0)
148433d6423SLionel Sambuc return r;
149433d6423SLionel Sambuc
150433d6423SLionel Sambuc getsockopt_copy(&err, sizeof(err), option_value, option_len);
151433d6423SLionel Sambuc return 0;
152433d6423SLionel Sambuc }
153433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_RCVBUF)
154433d6423SLionel Sambuc {
155433d6423SLionel Sambuc i = 32 * 1024; /* Receive buffer in the current
156433d6423SLionel Sambuc * implementation
157433d6423SLionel Sambuc */
158433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len);
159433d6423SLionel Sambuc return 0;
160433d6423SLionel Sambuc }
161433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_SNDBUF)
162433d6423SLionel Sambuc {
163433d6423SLionel Sambuc i = 32 * 1024; /* Send buffer in the current implementation */
164433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len);
165433d6423SLionel Sambuc return 0;
166433d6423SLionel Sambuc }
167433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_TYPE)
168433d6423SLionel Sambuc {
169433d6423SLionel Sambuc i = SOCK_STREAM; /* this is a TCP socket */
170433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len);
171433d6423SLionel Sambuc return 0;
172433d6423SLionel Sambuc }
173433d6423SLionel Sambuc if (level == IPPROTO_TCP && option_name == TCP_NODELAY)
174433d6423SLionel Sambuc {
175433d6423SLionel Sambuc i = 0; /* nodelay is always off */
176433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len);
177433d6423SLionel Sambuc return 0;
178433d6423SLionel Sambuc }
179433d6423SLionel Sambuc #if DEBUG
180433d6423SLionel Sambuc fprintf(stderr, "_tcp_getsocketopt: level %d, name %d\n",
181433d6423SLionel Sambuc level, option_name);
182433d6423SLionel Sambuc #endif
183433d6423SLionel Sambuc
184433d6423SLionel Sambuc errno= ENOPROTOOPT;
185433d6423SLionel Sambuc return -1;
186433d6423SLionel Sambuc }
187433d6423SLionel Sambuc
_udp_getsockopt(int sock,int level,int option_name,void * __restrict option_value,socklen_t * __restrict option_len)188433d6423SLionel Sambuc static int _udp_getsockopt(int sock, int level, int option_name,
189433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len)
190433d6423SLionel Sambuc {
191433d6423SLionel Sambuc int i;
192433d6423SLionel Sambuc
193433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_TYPE)
194433d6423SLionel Sambuc {
195433d6423SLionel Sambuc i = SOCK_DGRAM; /* this is a UDP socket */
196433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len);
197433d6423SLionel Sambuc return 0;
198433d6423SLionel Sambuc }
199433d6423SLionel Sambuc #if DEBUG
200433d6423SLionel Sambuc fprintf(stderr, "_udp_getsocketopt: level %d, name %d\n",
201433d6423SLionel Sambuc level, option_name);
202433d6423SLionel Sambuc #endif
203433d6423SLionel Sambuc
204433d6423SLionel Sambuc errno= ENOSYS;
205433d6423SLionel Sambuc return -1;
206433d6423SLionel Sambuc }
207433d6423SLionel Sambuc
_uds_getsockopt(int sock,int level,int option_name,void * __restrict option_value,socklen_t * __restrict option_len)208433d6423SLionel Sambuc static int _uds_getsockopt(int sock, int level, int option_name,
209433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len)
210433d6423SLionel Sambuc {
211433d6423SLionel Sambuc int i, r;
212433d6423SLionel Sambuc size_t size;
213433d6423SLionel Sambuc
214433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_RCVBUF)
215433d6423SLionel Sambuc {
216433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSRCVBUF, &size);
217433d6423SLionel Sambuc if (r == -1) {
218433d6423SLionel Sambuc return r;
219433d6423SLionel Sambuc }
220433d6423SLionel Sambuc
221433d6423SLionel Sambuc getsockopt_copy(&size, sizeof(size), option_value, option_len);
222433d6423SLionel Sambuc return 0;
223433d6423SLionel Sambuc }
224433d6423SLionel Sambuc
225433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_SNDBUF)
226433d6423SLionel Sambuc {
227433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSSNDBUF, &size);
228433d6423SLionel Sambuc if (r == -1) {
229433d6423SLionel Sambuc return r;
230433d6423SLionel Sambuc }
231433d6423SLionel Sambuc
232433d6423SLionel Sambuc getsockopt_copy(&size, sizeof(size), option_value, option_len);
233433d6423SLionel Sambuc return 0;
234433d6423SLionel Sambuc }
235433d6423SLionel Sambuc
236433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_TYPE)
237433d6423SLionel Sambuc {
238433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSSOTYPE, &i);
239433d6423SLionel Sambuc if (r == -1) {
240433d6423SLionel Sambuc return r;
241433d6423SLionel Sambuc }
242433d6423SLionel Sambuc
243433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len);
244433d6423SLionel Sambuc return 0;
245433d6423SLionel Sambuc }
246433d6423SLionel Sambuc
247*27852ebeSDavid van Moolenbroek #ifdef SO_PEERCRED
248433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_PEERCRED)
249433d6423SLionel Sambuc {
250433d6423SLionel Sambuc struct uucred cred;
251433d6423SLionel Sambuc
252433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSPEERCRED, &cred);
253433d6423SLionel Sambuc if (r == -1) {
254433d6423SLionel Sambuc return -1;
255433d6423SLionel Sambuc }
256433d6423SLionel Sambuc
257433d6423SLionel Sambuc getsockopt_copy(&cred, sizeof(struct uucred), option_value,
258433d6423SLionel Sambuc option_len);
259433d6423SLionel Sambuc return 0;
260433d6423SLionel Sambuc }
261*27852ebeSDavid van Moolenbroek #endif
262433d6423SLionel Sambuc
263433d6423SLionel Sambuc
264433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
265433d6423SLionel Sambuc {
266433d6423SLionel Sambuc i = 1; /* as long as nobody is listen()ing on the address,
267433d6423SLionel Sambuc * it can be reused without waiting for a
268433d6423SLionel Sambuc * timeout to expire.
269433d6423SLionel Sambuc */
270433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len);
271433d6423SLionel Sambuc return 0;
272433d6423SLionel Sambuc }
273433d6423SLionel Sambuc
274*27852ebeSDavid van Moolenbroek #ifdef SO_PASSCRED
275433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_PASSCRED)
276433d6423SLionel Sambuc {
277433d6423SLionel Sambuc i = 1; /* option is always 'on' */
278433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len);
279433d6423SLionel Sambuc return 0;
280433d6423SLionel Sambuc }
281*27852ebeSDavid van Moolenbroek #endif
282433d6423SLionel Sambuc
283433d6423SLionel Sambuc #if DEBUG
284433d6423SLionel Sambuc fprintf(stderr, "_uds_getsocketopt: level %d, name %d\n",
285433d6423SLionel Sambuc level, option_name);
286433d6423SLionel Sambuc #endif
287433d6423SLionel Sambuc
288433d6423SLionel Sambuc errno= ENOSYS;
289433d6423SLionel Sambuc return -1;
290433d6423SLionel Sambuc }
291