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