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 <string.h> 8*433d6423SLionel Sambuc #include <sys/ioctl.h> 9*433d6423SLionel Sambuc #include <sys/socket.h> 10*433d6423SLionel Sambuc #include <sys/types.h> 11*433d6423SLionel Sambuc #include <sys/ucred.h> 12*433d6423SLionel Sambuc #include <netinet/tcp.h> 13*433d6423SLionel Sambuc 14*433d6423SLionel Sambuc #include <net/gen/in.h> 15*433d6423SLionel Sambuc #include <net/gen/tcp.h> 16*433d6423SLionel Sambuc #include <net/gen/tcp_io.h> 17*433d6423SLionel Sambuc #include <net/gen/udp.h> 18*433d6423SLionel Sambuc #include <net/gen/udp_io.h> 19*433d6423SLionel Sambuc 20*433d6423SLionel Sambuc #include <minix/type.h> 21*433d6423SLionel Sambuc 22*433d6423SLionel Sambuc #define DEBUG 0 23*433d6423SLionel Sambuc 24*433d6423SLionel Sambuc static int _tcp_getsockopt(int sock, int level, int option_name, 25*433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len); 26*433d6423SLionel Sambuc static int _udp_getsockopt(int sock, int level, int option_name, 27*433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len); 28*433d6423SLionel Sambuc static int _uds_getsockopt(int sock, int level, int option_name, 29*433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len); 30*433d6423SLionel Sambuc static void getsockopt_copy(void *return_value, size_t return_len, 31*433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len); 32*433d6423SLionel Sambuc 33*433d6423SLionel Sambuc int getsockopt(int sock, int level, int option_name, 34*433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len) 35*433d6423SLionel Sambuc { 36*433d6423SLionel Sambuc int r; 37*433d6423SLionel Sambuc nwio_tcpopt_t tcpopt; 38*433d6423SLionel Sambuc nwio_udpopt_t udpopt; 39*433d6423SLionel Sambuc struct sockaddr_un uds_addr; 40*433d6423SLionel Sambuc 41*433d6423SLionel Sambuc r= ioctl(sock, NWIOGTCPOPT, &tcpopt); 42*433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 43*433d6423SLionel Sambuc { 44*433d6423SLionel Sambuc if (r == -1) 45*433d6423SLionel Sambuc { 46*433d6423SLionel Sambuc /* Bad file descriptor */ 47*433d6423SLionel Sambuc return -1; 48*433d6423SLionel Sambuc } 49*433d6423SLionel Sambuc return _tcp_getsockopt(sock, level, option_name, 50*433d6423SLionel Sambuc option_value, option_len); 51*433d6423SLionel Sambuc } 52*433d6423SLionel Sambuc 53*433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDPOPT, &udpopt); 54*433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 55*433d6423SLionel Sambuc { 56*433d6423SLionel Sambuc if (r == -1) 57*433d6423SLionel Sambuc { 58*433d6423SLionel Sambuc /* Bad file descriptor */ 59*433d6423SLionel Sambuc return -1; 60*433d6423SLionel Sambuc } 61*433d6423SLionel Sambuc return _udp_getsockopt(sock, level, option_name, 62*433d6423SLionel Sambuc option_value, option_len); 63*433d6423SLionel Sambuc } 64*433d6423SLionel Sambuc 65*433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSADDR, &uds_addr); 66*433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 67*433d6423SLionel Sambuc { 68*433d6423SLionel Sambuc if (r == -1) 69*433d6423SLionel Sambuc { 70*433d6423SLionel Sambuc /* Bad file descriptor */ 71*433d6423SLionel Sambuc return -1; 72*433d6423SLionel Sambuc } 73*433d6423SLionel Sambuc return _uds_getsockopt(sock, level, option_name, 74*433d6423SLionel Sambuc option_value, option_len); 75*433d6423SLionel Sambuc } 76*433d6423SLionel Sambuc 77*433d6423SLionel Sambuc 78*433d6423SLionel Sambuc #if DEBUG 79*433d6423SLionel Sambuc fprintf(stderr, "getsockopt: not implemented for fd %d\n", sock); 80*433d6423SLionel Sambuc #endif 81*433d6423SLionel Sambuc errno= ENOTSOCK; 82*433d6423SLionel Sambuc return -1; 83*433d6423SLionel Sambuc } 84*433d6423SLionel Sambuc 85*433d6423SLionel Sambuc static void getsockopt_copy(void *return_value, size_t return_len, 86*433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len) 87*433d6423SLionel Sambuc { 88*433d6423SLionel Sambuc /* copy as much data as possible */ 89*433d6423SLionel Sambuc if (*option_len < return_len) 90*433d6423SLionel Sambuc memcpy(option_value, return_value, *option_len); 91*433d6423SLionel Sambuc else 92*433d6423SLionel Sambuc memcpy(option_value, return_value, return_len); 93*433d6423SLionel Sambuc 94*433d6423SLionel Sambuc /* return length */ 95*433d6423SLionel Sambuc *option_len = return_len; 96*433d6423SLionel Sambuc } 97*433d6423SLionel Sambuc 98*433d6423SLionel Sambuc static int _tcp_getsockopt(int sock, int level, int option_name, 99*433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len) 100*433d6423SLionel Sambuc { 101*433d6423SLionel Sambuc int i, r, err; 102*433d6423SLionel Sambuc 103*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_REUSEADDR) 104*433d6423SLionel Sambuc { 105*433d6423SLionel Sambuc i = 1; /* Binds to TIME_WAIT sockets never cause errors */ 106*433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len); 107*433d6423SLionel Sambuc return 0; 108*433d6423SLionel Sambuc } 109*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_KEEPALIVE) 110*433d6423SLionel Sambuc { 111*433d6423SLionel Sambuc i = 1; /* Keepalive is always on */ 112*433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len); 113*433d6423SLionel Sambuc return 0; 114*433d6423SLionel Sambuc } 115*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_ERROR) 116*433d6423SLionel Sambuc { 117*433d6423SLionel Sambuc r = ioctl(sock, NWIOTCPGERROR, &err); 118*433d6423SLionel Sambuc if (r != 0) 119*433d6423SLionel Sambuc return r; 120*433d6423SLionel Sambuc 121*433d6423SLionel Sambuc getsockopt_copy(&err, sizeof(err), option_value, option_len); 122*433d6423SLionel Sambuc return 0; 123*433d6423SLionel Sambuc } 124*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_RCVBUF) 125*433d6423SLionel Sambuc { 126*433d6423SLionel Sambuc i = 32 * 1024; /* Receive buffer in the current 127*433d6423SLionel Sambuc * implementation 128*433d6423SLionel Sambuc */ 129*433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len); 130*433d6423SLionel Sambuc return 0; 131*433d6423SLionel Sambuc } 132*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_SNDBUF) 133*433d6423SLionel Sambuc { 134*433d6423SLionel Sambuc i = 32 * 1024; /* Send buffer in the current implementation */ 135*433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len); 136*433d6423SLionel Sambuc return 0; 137*433d6423SLionel Sambuc } 138*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_TYPE) 139*433d6423SLionel Sambuc { 140*433d6423SLionel Sambuc i = SOCK_STREAM; /* this is a TCP socket */ 141*433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len); 142*433d6423SLionel Sambuc return 0; 143*433d6423SLionel Sambuc } 144*433d6423SLionel Sambuc if (level == IPPROTO_TCP && option_name == TCP_NODELAY) 145*433d6423SLionel Sambuc { 146*433d6423SLionel Sambuc i = 0; /* nodelay is always off */ 147*433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len); 148*433d6423SLionel Sambuc return 0; 149*433d6423SLionel Sambuc } 150*433d6423SLionel Sambuc #if DEBUG 151*433d6423SLionel Sambuc fprintf(stderr, "_tcp_getsocketopt: level %d, name %d\n", 152*433d6423SLionel Sambuc level, option_name); 153*433d6423SLionel Sambuc #endif 154*433d6423SLionel Sambuc 155*433d6423SLionel Sambuc errno= ENOPROTOOPT; 156*433d6423SLionel Sambuc return -1; 157*433d6423SLionel Sambuc } 158*433d6423SLionel Sambuc 159*433d6423SLionel Sambuc static int _udp_getsockopt(int sock, int level, int option_name, 160*433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len) 161*433d6423SLionel Sambuc { 162*433d6423SLionel Sambuc int i; 163*433d6423SLionel Sambuc 164*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_TYPE) 165*433d6423SLionel Sambuc { 166*433d6423SLionel Sambuc i = SOCK_DGRAM; /* this is a UDP socket */ 167*433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len); 168*433d6423SLionel Sambuc return 0; 169*433d6423SLionel Sambuc } 170*433d6423SLionel Sambuc #if DEBUG 171*433d6423SLionel Sambuc fprintf(stderr, "_udp_getsocketopt: level %d, name %d\n", 172*433d6423SLionel Sambuc level, option_name); 173*433d6423SLionel Sambuc #endif 174*433d6423SLionel Sambuc 175*433d6423SLionel Sambuc errno= ENOSYS; 176*433d6423SLionel Sambuc return -1; 177*433d6423SLionel Sambuc } 178*433d6423SLionel Sambuc 179*433d6423SLionel Sambuc static int _uds_getsockopt(int sock, int level, int option_name, 180*433d6423SLionel Sambuc void *__restrict option_value, socklen_t *__restrict option_len) 181*433d6423SLionel Sambuc { 182*433d6423SLionel Sambuc int i, r; 183*433d6423SLionel Sambuc size_t size; 184*433d6423SLionel Sambuc 185*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_RCVBUF) 186*433d6423SLionel Sambuc { 187*433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSRCVBUF, &size); 188*433d6423SLionel Sambuc if (r == -1) { 189*433d6423SLionel Sambuc return r; 190*433d6423SLionel Sambuc } 191*433d6423SLionel Sambuc 192*433d6423SLionel Sambuc getsockopt_copy(&size, sizeof(size), option_value, option_len); 193*433d6423SLionel Sambuc return 0; 194*433d6423SLionel Sambuc } 195*433d6423SLionel Sambuc 196*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_SNDBUF) 197*433d6423SLionel Sambuc { 198*433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSSNDBUF, &size); 199*433d6423SLionel Sambuc if (r == -1) { 200*433d6423SLionel Sambuc return r; 201*433d6423SLionel Sambuc } 202*433d6423SLionel Sambuc 203*433d6423SLionel Sambuc getsockopt_copy(&size, sizeof(size), option_value, option_len); 204*433d6423SLionel Sambuc return 0; 205*433d6423SLionel Sambuc } 206*433d6423SLionel Sambuc 207*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_TYPE) 208*433d6423SLionel Sambuc { 209*433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSSOTYPE, &i); 210*433d6423SLionel Sambuc if (r == -1) { 211*433d6423SLionel Sambuc return r; 212*433d6423SLionel Sambuc } 213*433d6423SLionel Sambuc 214*433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len); 215*433d6423SLionel Sambuc return 0; 216*433d6423SLionel Sambuc } 217*433d6423SLionel Sambuc 218*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_PEERCRED) 219*433d6423SLionel Sambuc { 220*433d6423SLionel Sambuc struct uucred cred; 221*433d6423SLionel Sambuc 222*433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSPEERCRED, &cred); 223*433d6423SLionel Sambuc if (r == -1) { 224*433d6423SLionel Sambuc return -1; 225*433d6423SLionel Sambuc } 226*433d6423SLionel Sambuc 227*433d6423SLionel Sambuc getsockopt_copy(&cred, sizeof(struct uucred), option_value, 228*433d6423SLionel Sambuc option_len); 229*433d6423SLionel Sambuc return 0; 230*433d6423SLionel Sambuc } 231*433d6423SLionel Sambuc 232*433d6423SLionel Sambuc 233*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_REUSEADDR) 234*433d6423SLionel Sambuc { 235*433d6423SLionel Sambuc i = 1; /* as long as nobody is listen()ing on the address, 236*433d6423SLionel Sambuc * it can be reused without waiting for a 237*433d6423SLionel Sambuc * timeout to expire. 238*433d6423SLionel Sambuc */ 239*433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len); 240*433d6423SLionel Sambuc return 0; 241*433d6423SLionel Sambuc } 242*433d6423SLionel Sambuc 243*433d6423SLionel Sambuc if (level == SOL_SOCKET && option_name == SO_PASSCRED) 244*433d6423SLionel Sambuc { 245*433d6423SLionel Sambuc i = 1; /* option is always 'on' */ 246*433d6423SLionel Sambuc getsockopt_copy(&i, sizeof(i), option_value, option_len); 247*433d6423SLionel Sambuc return 0; 248*433d6423SLionel Sambuc } 249*433d6423SLionel Sambuc 250*433d6423SLionel Sambuc #if DEBUG 251*433d6423SLionel Sambuc fprintf(stderr, "_uds_getsocketopt: level %d, name %d\n", 252*433d6423SLionel Sambuc level, option_name); 253*433d6423SLionel Sambuc #endif 254*433d6423SLionel Sambuc 255*433d6423SLionel Sambuc errno= ENOSYS; 256*433d6423SLionel Sambuc return -1; 257*433d6423SLionel Sambuc } 258