1433d6423SLionel Sambuc #include <sys/cdefs.h> 2433d6423SLionel Sambuc #include "namespace.h" 3*c38dbb97SDavid van Moolenbroek #include <lib.h> 4433d6423SLionel Sambuc 5*c38dbb97SDavid 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 31*c38dbb97SDavid van Moolenbroek /* 32*c38dbb97SDavid van Moolenbroek * Set socket options. 33*c38dbb97SDavid van Moolenbroek */ 34*c38dbb97SDavid van Moolenbroek static int 35*c38dbb97SDavid van Moolenbroek __setsockopt(int fd, int level, int option_name, const void * option_value, 36*c38dbb97SDavid van Moolenbroek socklen_t option_len) 37*c38dbb97SDavid van Moolenbroek { 38*c38dbb97SDavid van Moolenbroek message m; 39*c38dbb97SDavid van Moolenbroek 40*c38dbb97SDavid van Moolenbroek memset(&m, 0, sizeof(m)); 41*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockopt.fd = fd; 42*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockopt.level = level; 43*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockopt.name = option_name; 44*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockopt.buf = (vir_bytes)option_value; 45*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockopt.len = option_len; 46*c38dbb97SDavid van Moolenbroek 47*c38dbb97SDavid van Moolenbroek return _syscall(VFS_PROC_NR, VFS_SETSOCKOPT, &m); 48*c38dbb97SDavid van Moolenbroek } 49*c38dbb97SDavid van Moolenbroek 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 58*c38dbb97SDavid van Moolenbroek r = __setsockopt(sock, level, option_name, option_value, option_len); 59*c38dbb97SDavid van Moolenbroek if (r != -1 || errno != ENOTSOCK) 60*c38dbb97SDavid van Moolenbroek return r; 61*c38dbb97SDavid 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 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 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 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 270433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_PASSCRED) 271433d6423SLionel Sambuc { 272433d6423SLionel Sambuc if (option_len != sizeof(i)) 273433d6423SLionel Sambuc { 274433d6423SLionel Sambuc errno= EINVAL; 275433d6423SLionel Sambuc return -1; 276433d6423SLionel Sambuc } 277433d6423SLionel Sambuc i= *(const int *)option_value; 278433d6423SLionel Sambuc if (!i) 279433d6423SLionel Sambuc { 280433d6423SLionel Sambuc /* credentials can always be received. */ 281433d6423SLionel Sambuc errno= ENOSYS; 282433d6423SLionel Sambuc return -1; 283433d6423SLionel Sambuc } 284433d6423SLionel Sambuc return 0; 285433d6423SLionel Sambuc } 286433d6423SLionel Sambuc 287433d6423SLionel Sambuc #if DEBUG 288433d6423SLionel Sambuc fprintf(stderr, "_uds_setsocketopt: level %d, name %d\n", 289433d6423SLionel Sambuc level, option_name); 290433d6423SLionel Sambuc #endif 291433d6423SLionel Sambuc 292433d6423SLionel Sambuc errno= ENOSYS; 293433d6423SLionel Sambuc return -1; 294433d6423SLionel Sambuc } 295