1*433d6423SLionel Sambuc #include <sys/cdefs.h> 2*433d6423SLionel Sambuc #include "namespace.h" 3*433d6423SLionel Sambuc 4*433d6423SLionel Sambuc #include <assert.h> 5*433d6423SLionel Sambuc #include <errno.h> 6*433d6423SLionel Sambuc #include <stdio.h> 7*433d6423SLionel Sambuc #include <sys/ioctl.h> 8*433d6423SLionel Sambuc #include <sys/socket.h> 9*433d6423SLionel Sambuc #include <sys/types.h> 10*433d6423SLionel Sambuc #include <netinet/tcp.h> 11*433d6423SLionel Sambuc 12*433d6423SLionel Sambuc #include <net/gen/in.h> 13*433d6423SLionel Sambuc #include <net/gen/tcp.h> 14*433d6423SLionel Sambuc #include <net/gen/tcp_io.h> 15*433d6423SLionel Sambuc #include <net/gen/udp.h> 16*433d6423SLionel Sambuc #include <net/gen/udp_io.h> 17*433d6423SLionel Sambuc 18*433d6423SLionel Sambuc #define DEBUG 0 19*433d6423SLionel Sambuc 20*433d6423SLionel Sambuc static int _tcp_setsockopt(int sock, int level, int option_name, 21*433d6423SLionel Sambuc const void *option_value, socklen_t option_len); 22*433d6423SLionel Sambuc 23*433d6423SLionel Sambuc static int _udp_setsockopt(int sock, int level, int option_name, 24*433d6423SLionel Sambuc const void *option_value, socklen_t option_len); 25*433d6423SLionel Sambuc 26*433d6423SLionel Sambuc static int _uds_setsockopt(int sock, int level, int option_name, 27*433d6423SLionel Sambuc const void *option_value, socklen_t option_len); 28*433d6423SLionel Sambuc 29*433d6423SLionel Sambuc int setsockopt(int sock, int level, int option_name, 30*433d6423SLionel Sambuc const void *option_value, socklen_t option_len) 31*433d6423SLionel Sambuc { 32*433d6423SLionel Sambuc int r; 33*433d6423SLionel Sambuc nwio_tcpopt_t tcpopt; 34*433d6423SLionel Sambuc nwio_udpopt_t udpopt; 35*433d6423SLionel Sambuc struct sockaddr_un uds_addr; 36*433d6423SLionel Sambuc 37*433d6423SLionel Sambuc r= ioctl(sock, NWIOGTCPOPT, &tcpopt); 38*433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 39*433d6423SLionel Sambuc { 40*433d6423SLionel Sambuc if (r == -1) 41*433d6423SLionel Sambuc { 42*433d6423SLionel Sambuc /* Bad file descriptor */ 43*433d6423SLionel Sambuc return -1; 44*433d6423SLionel Sambuc } 45*433d6423SLionel Sambuc return _tcp_setsockopt(sock, level, option_name, 46*433d6423SLionel Sambuc option_value, option_len); 47*433d6423SLionel Sambuc } 48*433d6423SLionel Sambuc 49*433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDPOPT, &udpopt); 50*433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 51*433d6423SLionel Sambuc { 52*433d6423SLionel Sambuc if (r == -1) 53*433d6423SLionel Sambuc { 54*433d6423SLionel Sambuc /* Bad file descriptor */ 55*433d6423SLionel Sambuc return -1; 56*433d6423SLionel Sambuc } 57*433d6423SLionel Sambuc return _udp_setsockopt(sock, level, option_name, 58*433d6423SLionel Sambuc option_value, option_len); 59*433d6423SLionel Sambuc } 60*433d6423SLionel Sambuc 61*433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSADDR, &uds_addr); 62*433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 63*433d6423SLionel Sambuc { 64*433d6423SLionel Sambuc if (r == -1) 65*433d6423SLionel Sambuc { 66*433d6423SLionel Sambuc /* Bad file descriptor */ 67*433d6423SLionel Sambuc return -1; 68*433d6423SLionel Sambuc } 69*433d6423SLionel Sambuc return _uds_setsockopt(sock, level, option_name, 70*433d6423SLionel Sambuc option_value, option_len); 71*433d6423SLionel Sambuc } 72*433d6423SLionel Sambuc 73*433d6423SLionel Sambuc 74*433d6423SLionel Sambuc #if DEBUG 75*433d6423SLionel Sambuc fprintf(stderr, "setsockopt: not implemented for fd %d\n", sock); 76*433d6423SLionel Sambuc #endif 77*433d6423SLionel Sambuc errno= ENOTSOCK; 78*433d6423SLionel Sambuc return -1; 79*433d6423SLionel Sambuc } 80*433d6423SLionel Sambuc 81*433d6423SLionel Sambuc static int _tcp_setsockopt(int sock, int level, int option_name, 82*433d6423SLionel Sambuc const void *option_value, socklen_t option_len) 83*433d6423SLionel Sambuc { 84*433d6423SLionel Sambuc int i; 85*433d6423SLionel Sambuc 86*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_REUSEADDR) 87*433d6423SLionel Sambuc { 88*433d6423SLionel Sambuc if (option_len != sizeof(i)) 89*433d6423SLionel Sambuc { 90*433d6423SLionel Sambuc errno= EINVAL; 91*433d6423SLionel Sambuc return -1; 92*433d6423SLionel Sambuc } 93*433d6423SLionel Sambuc i= *(const int *)option_value; 94*433d6423SLionel Sambuc if (!i) 95*433d6423SLionel Sambuc { 96*433d6423SLionel Sambuc /* At the moment there is no way to turn off 97*433d6423SLionel Sambuc * reusing addresses. 98*433d6423SLionel Sambuc */ 99*433d6423SLionel Sambuc errno= ENOSYS; 100*433d6423SLionel Sambuc return -1; 101*433d6423SLionel Sambuc } 102*433d6423SLionel Sambuc return 0; 103*433d6423SLionel Sambuc } 104*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_KEEPALIVE) 105*433d6423SLionel Sambuc { 106*433d6423SLionel Sambuc if (option_len != sizeof(i)) 107*433d6423SLionel Sambuc { 108*433d6423SLionel Sambuc errno= EINVAL; 109*433d6423SLionel Sambuc return -1; 110*433d6423SLionel Sambuc } 111*433d6423SLionel Sambuc i= *(const int *)option_value; 112*433d6423SLionel Sambuc if (!i) 113*433d6423SLionel Sambuc { 114*433d6423SLionel Sambuc /* At the moment there is no way to turn off 115*433d6423SLionel Sambuc * keepalives. 116*433d6423SLionel Sambuc */ 117*433d6423SLionel Sambuc errno= ENOSYS; 118*433d6423SLionel Sambuc return -1; 119*433d6423SLionel Sambuc } 120*433d6423SLionel Sambuc return 0; 121*433d6423SLionel Sambuc } 122*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_RCVBUF) 123*433d6423SLionel Sambuc { 124*433d6423SLionel Sambuc if (option_len != sizeof(i)) 125*433d6423SLionel Sambuc { 126*433d6423SLionel Sambuc errno= EINVAL; 127*433d6423SLionel Sambuc return -1; 128*433d6423SLionel Sambuc } 129*433d6423SLionel Sambuc i= *(const int *)option_value; 130*433d6423SLionel Sambuc if (i > 32*1024) 131*433d6423SLionel Sambuc { 132*433d6423SLionel Sambuc /* The receive buffer is limited to 32K at the moment. 133*433d6423SLionel Sambuc */ 134*433d6423SLionel Sambuc errno= ENOSYS; 135*433d6423SLionel Sambuc return -1; 136*433d6423SLionel Sambuc } 137*433d6423SLionel Sambuc /* There is no way to reduce the receive buffer, do we have to 138*433d6423SLionel Sambuc * let this call fail for smaller buffers? 139*433d6423SLionel Sambuc */ 140*433d6423SLionel Sambuc return 0; 141*433d6423SLionel Sambuc } 142*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_SNDBUF) 143*433d6423SLionel Sambuc { 144*433d6423SLionel Sambuc if (option_len != sizeof(i)) 145*433d6423SLionel Sambuc { 146*433d6423SLionel Sambuc errno= EINVAL; 147*433d6423SLionel Sambuc return -1; 148*433d6423SLionel Sambuc } 149*433d6423SLionel Sambuc i= *(const int *)option_value; 150*433d6423SLionel Sambuc if (i > 32*1024) 151*433d6423SLionel Sambuc { 152*433d6423SLionel Sambuc /* The send buffer is limited to 32K at the moment. 153*433d6423SLionel Sambuc */ 154*433d6423SLionel Sambuc errno= ENOSYS; 155*433d6423SLionel Sambuc return -1; 156*433d6423SLionel Sambuc } 157*433d6423SLionel Sambuc /* There is no way to reduce the send buffer, do we have to 158*433d6423SLionel Sambuc * let this call fail for smaller buffers? 159*433d6423SLionel Sambuc */ 160*433d6423SLionel Sambuc return 0; 161*433d6423SLionel Sambuc } 162*433d6423SLionel Sambuc if (level == IPPROTO_TCP && option_name == TCP_NODELAY) 163*433d6423SLionel Sambuc { 164*433d6423SLionel Sambuc if (option_len != sizeof(i)) 165*433d6423SLionel Sambuc { 166*433d6423SLionel Sambuc errno= EINVAL; 167*433d6423SLionel Sambuc return -1; 168*433d6423SLionel Sambuc } 169*433d6423SLionel Sambuc i= *(const int *)option_value; 170*433d6423SLionel Sambuc if (i) 171*433d6423SLionel Sambuc { 172*433d6423SLionel Sambuc /* At the moment there is no way to turn on 173*433d6423SLionel Sambuc * nodelay. 174*433d6423SLionel Sambuc */ 175*433d6423SLionel Sambuc errno= ENOSYS; 176*433d6423SLionel Sambuc return -1; 177*433d6423SLionel Sambuc } 178*433d6423SLionel Sambuc return 0; 179*433d6423SLionel Sambuc } 180*433d6423SLionel Sambuc #if DEBUG 181*433d6423SLionel Sambuc fprintf(stderr, "_tcp_setsocketopt: level %d, name %d\n", 182*433d6423SLionel Sambuc level, option_name); 183*433d6423SLionel Sambuc #endif 184*433d6423SLionel Sambuc 185*433d6423SLionel Sambuc errno= ENOSYS; 186*433d6423SLionel Sambuc return -1; 187*433d6423SLionel Sambuc } 188*433d6423SLionel Sambuc 189*433d6423SLionel Sambuc static int _udp_setsockopt(int sock, int level, int option_name, 190*433d6423SLionel Sambuc const void *option_value, socklen_t option_len) 191*433d6423SLionel Sambuc { 192*433d6423SLionel Sambuc #if DEBUG 193*433d6423SLionel Sambuc fprintf(stderr, "_udp_setsocketopt: level %d, name %d\n", 194*433d6423SLionel Sambuc level, option_name); 195*433d6423SLionel Sambuc #endif 196*433d6423SLionel Sambuc 197*433d6423SLionel Sambuc errno= ENOSYS; 198*433d6423SLionel Sambuc return -1; 199*433d6423SLionel Sambuc } 200*433d6423SLionel Sambuc 201*433d6423SLionel Sambuc 202*433d6423SLionel Sambuc static int _uds_setsockopt(int sock, int level, int option_name, 203*433d6423SLionel Sambuc const void *option_value, socklen_t option_len) 204*433d6423SLionel Sambuc { 205*433d6423SLionel Sambuc int i; 206*433d6423SLionel Sambuc size_t size; 207*433d6423SLionel Sambuc 208*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_RCVBUF) 209*433d6423SLionel Sambuc { 210*433d6423SLionel Sambuc if (option_len != sizeof(size)) 211*433d6423SLionel Sambuc { 212*433d6423SLionel Sambuc errno= EINVAL; 213*433d6423SLionel Sambuc return -1; 214*433d6423SLionel Sambuc } 215*433d6423SLionel Sambuc size= *(const size_t *)option_value; 216*433d6423SLionel Sambuc return ioctl(sock, NWIOSUDSRCVBUF, &size); 217*433d6423SLionel Sambuc } 218*433d6423SLionel Sambuc 219*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_SNDBUF) 220*433d6423SLionel Sambuc { 221*433d6423SLionel Sambuc if (option_len != sizeof(size)) 222*433d6423SLionel Sambuc { 223*433d6423SLionel Sambuc errno= EINVAL; 224*433d6423SLionel Sambuc return -1; 225*433d6423SLionel Sambuc } 226*433d6423SLionel Sambuc size= *(const size_t *)option_value; 227*433d6423SLionel Sambuc return ioctl(sock, NWIOSUDSSNDBUF, &size); 228*433d6423SLionel Sambuc } 229*433d6423SLionel Sambuc 230*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_REUSEADDR) 231*433d6423SLionel Sambuc { 232*433d6423SLionel Sambuc if (option_len != sizeof(i)) 233*433d6423SLionel Sambuc { 234*433d6423SLionel Sambuc errno= EINVAL; 235*433d6423SLionel Sambuc return -1; 236*433d6423SLionel Sambuc } 237*433d6423SLionel Sambuc i= *(const int *)option_value; 238*433d6423SLionel Sambuc if (!i) 239*433d6423SLionel Sambuc { 240*433d6423SLionel Sambuc /* At the moment there is no way to turn off 241*433d6423SLionel Sambuc * reusing addresses. 242*433d6423SLionel Sambuc */ 243*433d6423SLionel Sambuc errno= ENOSYS; 244*433d6423SLionel Sambuc return -1; 245*433d6423SLionel Sambuc } 246*433d6423SLionel Sambuc return 0; 247*433d6423SLionel Sambuc } 248*433d6423SLionel Sambuc 249*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_PASSCRED) 250*433d6423SLionel Sambuc { 251*433d6423SLionel Sambuc if (option_len != sizeof(i)) 252*433d6423SLionel Sambuc { 253*433d6423SLionel Sambuc errno= EINVAL; 254*433d6423SLionel Sambuc return -1; 255*433d6423SLionel Sambuc } 256*433d6423SLionel Sambuc i= *(const int *)option_value; 257*433d6423SLionel Sambuc if (!i) 258*433d6423SLionel Sambuc { 259*433d6423SLionel Sambuc /* credentials can always be received. */ 260*433d6423SLionel Sambuc errno= ENOSYS; 261*433d6423SLionel Sambuc return -1; 262*433d6423SLionel Sambuc } 263*433d6423SLionel Sambuc return 0; 264*433d6423SLionel Sambuc } 265*433d6423SLionel Sambuc 266*433d6423SLionel Sambuc #if DEBUG 267*433d6423SLionel Sambuc fprintf(stderr, "_uds_setsocketopt: level %d, name %d\n", 268*433d6423SLionel Sambuc level, option_name); 269*433d6423SLionel Sambuc #endif 270*433d6423SLionel Sambuc 271*433d6423SLionel Sambuc errno= ENOSYS; 272*433d6423SLionel Sambuc return -1; 273*433d6423SLionel Sambuc } 274