1 #include <sys/cdefs.h> 2 #include "namespace.h" 3 #include <lib.h> 4 5 #include <unistd.h> 6 #include <stdint.h> 7 #include <stdlib.h> 8 #include <limits.h> 9 #include <errno.h> 10 #include <stdio.h> 11 #include <string.h> 12 #include <sys/ioctl.h> 13 #include <sys/socket.h> 14 #include <sys/types.h> 15 #include <sys/stat.h> 16 #include <netinet/in.h> 17 18 #include <net/gen/in.h> 19 #include <net/gen/tcp.h> 20 #include <net/gen/tcp_io.h> 21 #include <net/gen/udp.h> 22 #include <net/gen/udp_io.h> 23 #include <sys/un.h> 24 25 #include <minix/config.h> 26 #include <minix/const.h> 27 28 #define DEBUG 0 29 30 static int _tcp_bind(int sock, const struct sockaddr *address, 31 socklen_t address_len, nwio_tcpconf_t *tcpconfp); 32 static int _udp_bind(int sock, const struct sockaddr *address, 33 socklen_t address_len, nwio_udpopt_t *udpoptp); 34 static int _uds_bind(int sock, const struct sockaddr *address, 35 socklen_t address_len, struct sockaddr_un *uds_addr); 36 37 /* 38 * Bind a socket to a local address. 39 */ 40 static int 41 __bind(int fd, const struct sockaddr * address, socklen_t address_len) 42 { 43 message m; 44 45 memset(&m, 0, sizeof(m)); 46 m.m_lc_vfs_sockaddr.fd = fd; 47 m.m_lc_vfs_sockaddr.addr = (vir_bytes)address; 48 m.m_lc_vfs_sockaddr.addr_len = address_len; 49 50 return _syscall(VFS_PROC_NR, VFS_BIND, &m); 51 } 52 53 int bind(int sock, const struct sockaddr *address, socklen_t address_len) 54 { 55 int r; 56 nwio_tcpconf_t tcpconf; 57 nwio_udpopt_t udpopt; 58 struct sockaddr_un uds_addr; 59 60 r = __bind(sock, address, address_len); 61 if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS)) 62 return r; 63 64 r= ioctl(sock, NWIOGTCPCONF, &tcpconf); 65 if (r != -1 || errno != ENOTTY) 66 { 67 if (r == -1) 68 return r; 69 r= _tcp_bind(sock, address, address_len, &tcpconf); 70 #if DEBUG 71 if (r == -1) 72 { 73 int t_errno= errno; 74 fprintf(stderr, "bind(tcp) failed: %s\n", 75 strerror(errno)); 76 errno= t_errno; 77 } 78 #endif 79 return r; 80 } 81 82 r= ioctl(sock, NWIOGUDPOPT, &udpopt); 83 if (r != -1 || errno != ENOTTY) 84 { 85 if (r == -1) 86 return r; 87 return _udp_bind(sock, address, address_len, &udpopt); 88 } 89 90 r= ioctl(sock, NWIOGUDSADDR, &uds_addr); 91 if (r != -1 || errno != ENOTTY) 92 { 93 if (r == -1) 94 return r; 95 return _uds_bind(sock, address, address_len, &uds_addr); 96 } 97 98 errno = ENOTSOCK; 99 return -1; 100 } 101 102 static int _tcp_bind(int sock, const struct sockaddr *address, 103 socklen_t address_len, nwio_tcpconf_t *tcpconfp) 104 { 105 int r; 106 nwio_tcpconf_t tcpconf; 107 struct sockaddr_in *sinp; 108 109 sinp= (struct sockaddr_in *) __UNCONST(address); 110 if (sinp->sin_family != AF_INET || address_len < sizeof(*sinp)) 111 { 112 #if DEBUG 113 fprintf(stderr, "bind(tcp): sin_family = %d, len = %d\n", 114 sinp->sin_family, address_len); 115 #endif 116 errno= EAFNOSUPPORT; 117 return -1; 118 } 119 120 if (sinp->sin_addr.s_addr != INADDR_ANY && 121 sinp->sin_addr.s_addr != tcpconfp->nwtc_locaddr) 122 { 123 errno= EADDRNOTAVAIL; 124 return -1; 125 } 126 127 tcpconf.nwtc_flags= 0; 128 129 if (sinp->sin_port == 0) 130 tcpconf.nwtc_flags |= NWTC_LP_SEL; 131 else 132 { 133 tcpconf.nwtc_flags |= NWTC_LP_SET; 134 tcpconf.nwtc_locport= sinp->sin_port; 135 } 136 137 r= ioctl(sock, NWIOSTCPCONF, &tcpconf); 138 return r; 139 } 140 141 static int _udp_bind(int sock, const struct sockaddr *address, 142 socklen_t address_len, nwio_udpopt_t *udpoptp) 143 { 144 int r; 145 unsigned long curr_flags; 146 nwio_udpopt_t udpopt; 147 struct sockaddr_in *sinp; 148 149 sinp= (struct sockaddr_in *) __UNCONST(address); 150 if (sinp->sin_family != AF_INET || address_len < sizeof(*sinp)) 151 { 152 #if DEBUG 153 fprintf(stderr, "bind(udp): sin_family = %d, len = %d\n", 154 sinp->sin_family, address_len); 155 #endif 156 errno= EAFNOSUPPORT; 157 return -1; 158 } 159 160 if (sinp->sin_addr.s_addr != INADDR_ANY && 161 sinp->sin_addr.s_addr != udpoptp->nwuo_locaddr) 162 { 163 errno= EADDRNOTAVAIL; 164 return -1; 165 } 166 167 udpopt.nwuo_flags= 0; 168 169 if (sinp->sin_port == 0) 170 udpopt.nwuo_flags |= NWUO_LP_SEL; 171 else 172 { 173 udpopt.nwuo_flags |= NWUO_LP_SET; 174 udpopt.nwuo_locport= sinp->sin_port; 175 } 176 177 curr_flags= udpoptp->nwuo_flags; 178 if (!(curr_flags & NWUO_ACC_MASK)) 179 udpopt.nwuo_flags |= NWUO_EXCL; 180 if (!(curr_flags & (NWUO_EN_LOC|NWUO_DI_LOC))) 181 udpopt.nwuo_flags |= NWUO_EN_LOC; 182 if (!(curr_flags & (NWUO_EN_BROAD|NWUO_DI_BROAD))) 183 udpopt.nwuo_flags |= NWUO_EN_BROAD; 184 if (!(curr_flags & (NWUO_RP_SET|NWUO_RP_ANY))) 185 udpopt.nwuo_flags |= NWUO_RP_ANY; 186 if (!(curr_flags & (NWUO_RA_SET|NWUO_RA_ANY))) 187 udpopt.nwuo_flags |= NWUO_RA_ANY; 188 if (!(curr_flags & (NWUO_RWDATONLY|NWUO_RWDATALL))) 189 udpopt.nwuo_flags |= NWUO_RWDATALL; 190 if (!(curr_flags & (NWUO_EN_IPOPT|NWUO_DI_IPOPT))) 191 udpopt.nwuo_flags |= NWUO_DI_IPOPT; 192 193 r= ioctl(sock, NWIOSUDPOPT, &udpopt); 194 return r; 195 } 196 197 static int _uds_bind(int sock, const struct sockaddr *address, 198 socklen_t address_len, struct sockaddr_un *uds_addr) 199 { 200 int r; 201 int did_mknod; 202 203 if (address == NULL) { 204 errno = EFAULT; 205 return -1; 206 } 207 208 did_mknod = 0; 209 210 r = mknod(((struct sockaddr_un *) __UNCONST(address))->sun_path, 211 S_IFSOCK|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0); 212 213 if (r == -1 && errno != EEXIST) { 214 return -1; 215 } else if (r == 0) { 216 did_mknod = 1; 217 } 218 219 /* perform the bind */ 220 r= ioctl(sock, NWIOSUDSADDR, (void *) __UNCONST(address)); 221 222 if (r == -1 && did_mknod) { 223 224 /* bind() failed in pfs, so we roll back the 225 * file system change 226 */ 227 unlink(((struct sockaddr_un *) __UNCONST(address))->sun_path); 228 } 229 230 return r; 231 } 232