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 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 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); 71*84ed480eSDavid 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 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 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 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 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 247433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_PEERCRED) 248433d6423SLionel Sambuc { 249433d6423SLionel Sambuc struct uucred cred; 250433d6423SLionel Sambuc 251433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSPEERCRED, &cred); 252433d6423SLionel Sambuc if (r == -1) { 253433d6423SLionel Sambuc return -1; 254433d6423SLionel Sambuc } 255433d6423SLionel Sambuc 256433d6423SLionel Sambuc getsockopt_copy(&cred, sizeof(struct uucred), option_value, 257433d6423SLionel Sambuc option_len); 258433d6423SLionel Sambuc return 0; 259433d6423SLionel Sambuc } 260433d6423SLionel Sambuc 261433d6423SLionel Sambuc 262433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_REUSEADDR) 263433d6423SLionel Sambuc { 264433d6423SLionel Sambuc i = 1; /* as long as nobody is listen()ing on the address, 265433d6423SLionel Sambuc * it can be reused without waiting for a 266433d6423SLionel Sambuc * timeout to expire. 267433d6423SLionel Sambuc */ 268433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len); 269433d6423SLionel Sambuc return 0; 270433d6423SLionel Sambuc } 271433d6423SLionel Sambuc 272433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_PASSCRED) 273433d6423SLionel Sambuc { 274433d6423SLionel Sambuc i = 1; /* option is always 'on' */ 275433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len); 276433d6423SLionel Sambuc return 0; 277433d6423SLionel Sambuc } 278433d6423SLionel Sambuc 279433d6423SLionel Sambuc #if DEBUG 280433d6423SLionel Sambuc fprintf(stderr, "_uds_getsocketopt: level %d, name %d\n", 281433d6423SLionel Sambuc level, option_name); 282433d6423SLionel Sambuc #endif 283433d6423SLionel Sambuc 284433d6423SLionel Sambuc errno= ENOSYS; 285433d6423SLionel Sambuc return -1; 286433d6423SLionel Sambuc } 287