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