1433d6423SLionel Sambuc #include <sys/cdefs.h> 2433d6423SLionel Sambuc #include "namespace.h" 3*c38dbb97SDavid van Moolenbroek #include <lib.h> 4433d6423SLionel Sambuc 5433d6423SLionel Sambuc #include <unistd.h> 6433d6423SLionel Sambuc #include <stdint.h> 7433d6423SLionel Sambuc #include <stdlib.h> 8433d6423SLionel Sambuc #include <limits.h> 9433d6423SLionel Sambuc #include <errno.h> 10433d6423SLionel Sambuc #include <stdio.h> 11433d6423SLionel Sambuc #include <string.h> 12433d6423SLionel Sambuc #include <sys/ioctl.h> 13433d6423SLionel Sambuc #include <sys/socket.h> 14433d6423SLionel Sambuc #include <sys/types.h> 15433d6423SLionel Sambuc #include <sys/stat.h> 16433d6423SLionel Sambuc #include <netinet/in.h> 17433d6423SLionel Sambuc 18433d6423SLionel Sambuc #include <net/gen/in.h> 19433d6423SLionel Sambuc #include <net/gen/tcp.h> 20433d6423SLionel Sambuc #include <net/gen/tcp_io.h> 21433d6423SLionel Sambuc #include <net/gen/udp.h> 22433d6423SLionel Sambuc #include <net/gen/udp_io.h> 23433d6423SLionel Sambuc #include <sys/un.h> 24433d6423SLionel Sambuc 25433d6423SLionel Sambuc #include <minix/config.h> 26433d6423SLionel Sambuc #include <minix/const.h> 27433d6423SLionel Sambuc 28433d6423SLionel Sambuc #define DEBUG 0 29433d6423SLionel Sambuc 30433d6423SLionel Sambuc static int _tcp_bind(int sock, const struct sockaddr *address, 31433d6423SLionel Sambuc socklen_t address_len, nwio_tcpconf_t *tcpconfp); 32433d6423SLionel Sambuc static int _udp_bind(int sock, const struct sockaddr *address, 33433d6423SLionel Sambuc socklen_t address_len, nwio_udpopt_t *udpoptp); 34433d6423SLionel Sambuc static int _uds_bind(int sock, const struct sockaddr *address, 35433d6423SLionel Sambuc socklen_t address_len, struct sockaddr_un *uds_addr); 36433d6423SLionel Sambuc 37*c38dbb97SDavid van Moolenbroek /* 38*c38dbb97SDavid van Moolenbroek * Bind a socket to a local address. 39*c38dbb97SDavid van Moolenbroek */ 40*c38dbb97SDavid van Moolenbroek static int 41*c38dbb97SDavid van Moolenbroek __bind(int fd, const struct sockaddr * address, socklen_t address_len) 42*c38dbb97SDavid van Moolenbroek { 43*c38dbb97SDavid van Moolenbroek message m; 44*c38dbb97SDavid van Moolenbroek 45*c38dbb97SDavid van Moolenbroek memset(&m, 0, sizeof(m)); 46*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.fd = fd; 47*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.addr = (vir_bytes)address; 48*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.addr_len = address_len; 49*c38dbb97SDavid van Moolenbroek 50*c38dbb97SDavid van Moolenbroek return _syscall(VFS_PROC_NR, VFS_BIND, &m); 51*c38dbb97SDavid van Moolenbroek } 52*c38dbb97SDavid van Moolenbroek 53433d6423SLionel Sambuc int bind(int sock, const struct sockaddr *address, socklen_t address_len) 54433d6423SLionel Sambuc { 55433d6423SLionel Sambuc int r; 56433d6423SLionel Sambuc nwio_tcpconf_t tcpconf; 57433d6423SLionel Sambuc nwio_udpopt_t udpopt; 58433d6423SLionel Sambuc struct sockaddr_un uds_addr; 59433d6423SLionel Sambuc 60*c38dbb97SDavid van Moolenbroek r = __bind(sock, address, address_len); 61*c38dbb97SDavid van Moolenbroek if (r != -1 || errno != ENOTSOCK) 62*c38dbb97SDavid van Moolenbroek return r; 63*c38dbb97SDavid van Moolenbroek 64433d6423SLionel Sambuc r= ioctl(sock, NWIOGTCPCONF, &tcpconf); 65433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 66433d6423SLionel Sambuc { 67433d6423SLionel Sambuc if (r == -1) 68433d6423SLionel Sambuc return r; 69433d6423SLionel Sambuc r= _tcp_bind(sock, address, address_len, &tcpconf); 70433d6423SLionel Sambuc #if DEBUG 71433d6423SLionel Sambuc if (r == -1) 72433d6423SLionel Sambuc { 73433d6423SLionel Sambuc int t_errno= errno; 74433d6423SLionel Sambuc fprintf(stderr, "bind(tcp) failed: %s\n", 75433d6423SLionel Sambuc strerror(errno)); 76433d6423SLionel Sambuc errno= t_errno; 77433d6423SLionel Sambuc } 78433d6423SLionel Sambuc #endif 79433d6423SLionel Sambuc return r; 80433d6423SLionel Sambuc } 81433d6423SLionel Sambuc 82433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDPOPT, &udpopt); 83433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 84433d6423SLionel Sambuc { 85433d6423SLionel Sambuc if (r == -1) 86433d6423SLionel Sambuc return r; 87433d6423SLionel Sambuc return _udp_bind(sock, address, address_len, &udpopt); 88433d6423SLionel Sambuc } 89433d6423SLionel Sambuc 90433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSADDR, &uds_addr); 91433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 92433d6423SLionel Sambuc { 93433d6423SLionel Sambuc if (r == -1) 94433d6423SLionel Sambuc return r; 95433d6423SLionel Sambuc return _uds_bind(sock, address, address_len, &uds_addr); 96433d6423SLionel Sambuc } 97433d6423SLionel Sambuc 98*c38dbb97SDavid van Moolenbroek errno = ENOTSOCK; 99433d6423SLionel Sambuc return -1; 100433d6423SLionel Sambuc } 101433d6423SLionel Sambuc 102433d6423SLionel Sambuc static int _tcp_bind(int sock, const struct sockaddr *address, 103433d6423SLionel Sambuc socklen_t address_len, nwio_tcpconf_t *tcpconfp) 104433d6423SLionel Sambuc { 105433d6423SLionel Sambuc int r; 106433d6423SLionel Sambuc nwio_tcpconf_t tcpconf; 107433d6423SLionel Sambuc struct sockaddr_in *sinp; 108433d6423SLionel Sambuc 109433d6423SLionel Sambuc sinp= (struct sockaddr_in *) __UNCONST(address); 110433d6423SLionel Sambuc if (sinp->sin_family != AF_INET || address_len < sizeof(*sinp)) 111433d6423SLionel Sambuc { 112433d6423SLionel Sambuc #if DEBUG 113433d6423SLionel Sambuc fprintf(stderr, "bind(tcp): sin_family = %d, len = %d\n", 114433d6423SLionel Sambuc sinp->sin_family, address_len); 115433d6423SLionel Sambuc #endif 116433d6423SLionel Sambuc errno= EAFNOSUPPORT; 117433d6423SLionel Sambuc return -1; 118433d6423SLionel Sambuc } 119433d6423SLionel Sambuc 120433d6423SLionel Sambuc if (sinp->sin_addr.s_addr != INADDR_ANY && 121433d6423SLionel Sambuc sinp->sin_addr.s_addr != tcpconfp->nwtc_locaddr) 122433d6423SLionel Sambuc { 123433d6423SLionel Sambuc errno= EADDRNOTAVAIL; 124433d6423SLionel Sambuc return -1; 125433d6423SLionel Sambuc } 126433d6423SLionel Sambuc 127433d6423SLionel Sambuc tcpconf.nwtc_flags= 0; 128433d6423SLionel Sambuc 129433d6423SLionel Sambuc if (sinp->sin_port == 0) 130433d6423SLionel Sambuc tcpconf.nwtc_flags |= NWTC_LP_SEL; 131433d6423SLionel Sambuc else 132433d6423SLionel Sambuc { 133433d6423SLionel Sambuc tcpconf.nwtc_flags |= NWTC_LP_SET; 134433d6423SLionel Sambuc tcpconf.nwtc_locport= sinp->sin_port; 135433d6423SLionel Sambuc } 136433d6423SLionel Sambuc 137433d6423SLionel Sambuc r= ioctl(sock, NWIOSTCPCONF, &tcpconf); 138433d6423SLionel Sambuc return r; 139433d6423SLionel Sambuc } 140433d6423SLionel Sambuc 141433d6423SLionel Sambuc static int _udp_bind(int sock, const struct sockaddr *address, 142433d6423SLionel Sambuc socklen_t address_len, nwio_udpopt_t *udpoptp) 143433d6423SLionel Sambuc { 144433d6423SLionel Sambuc int r; 145433d6423SLionel Sambuc unsigned long curr_flags; 146433d6423SLionel Sambuc nwio_udpopt_t udpopt; 147433d6423SLionel Sambuc struct sockaddr_in *sinp; 148433d6423SLionel Sambuc 149433d6423SLionel Sambuc sinp= (struct sockaddr_in *) __UNCONST(address); 150433d6423SLionel Sambuc if (sinp->sin_family != AF_INET || address_len < sizeof(*sinp)) 151433d6423SLionel Sambuc { 152433d6423SLionel Sambuc #if DEBUG 153433d6423SLionel Sambuc fprintf(stderr, "bind(udp): sin_family = %d, len = %d\n", 154433d6423SLionel Sambuc sinp->sin_family, address_len); 155433d6423SLionel Sambuc #endif 156433d6423SLionel Sambuc errno= EAFNOSUPPORT; 157433d6423SLionel Sambuc return -1; 158433d6423SLionel Sambuc } 159433d6423SLionel Sambuc 160433d6423SLionel Sambuc if (sinp->sin_addr.s_addr != INADDR_ANY && 161433d6423SLionel Sambuc sinp->sin_addr.s_addr != udpoptp->nwuo_locaddr) 162433d6423SLionel Sambuc { 163433d6423SLionel Sambuc errno= EADDRNOTAVAIL; 164433d6423SLionel Sambuc return -1; 165433d6423SLionel Sambuc } 166433d6423SLionel Sambuc 167433d6423SLionel Sambuc udpopt.nwuo_flags= 0; 168433d6423SLionel Sambuc 169433d6423SLionel Sambuc if (sinp->sin_port == 0) 170433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_LP_SEL; 171433d6423SLionel Sambuc else 172433d6423SLionel Sambuc { 173433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_LP_SET; 174433d6423SLionel Sambuc udpopt.nwuo_locport= sinp->sin_port; 175433d6423SLionel Sambuc } 176433d6423SLionel Sambuc 177433d6423SLionel Sambuc curr_flags= udpoptp->nwuo_flags; 178433d6423SLionel Sambuc if (!(curr_flags & NWUO_ACC_MASK)) 179433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_EXCL; 180433d6423SLionel Sambuc if (!(curr_flags & (NWUO_EN_LOC|NWUO_DI_LOC))) 181433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_EN_LOC; 182433d6423SLionel Sambuc if (!(curr_flags & (NWUO_EN_BROAD|NWUO_DI_BROAD))) 183433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_EN_BROAD; 184433d6423SLionel Sambuc if (!(curr_flags & (NWUO_RP_SET|NWUO_RP_ANY))) 185433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_RP_ANY; 186433d6423SLionel Sambuc if (!(curr_flags & (NWUO_RA_SET|NWUO_RA_ANY))) 187433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_RA_ANY; 188433d6423SLionel Sambuc if (!(curr_flags & (NWUO_RWDATONLY|NWUO_RWDATALL))) 189433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_RWDATALL; 190433d6423SLionel Sambuc if (!(curr_flags & (NWUO_EN_IPOPT|NWUO_DI_IPOPT))) 191433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_DI_IPOPT; 192433d6423SLionel Sambuc 193433d6423SLionel Sambuc r= ioctl(sock, NWIOSUDPOPT, &udpopt); 194433d6423SLionel Sambuc return r; 195433d6423SLionel Sambuc } 196433d6423SLionel Sambuc 197433d6423SLionel Sambuc static int _uds_bind(int sock, const struct sockaddr *address, 198433d6423SLionel Sambuc socklen_t address_len, struct sockaddr_un *uds_addr) 199433d6423SLionel Sambuc { 200433d6423SLionel Sambuc int r; 201433d6423SLionel Sambuc int did_mknod; 202433d6423SLionel Sambuc 203433d6423SLionel Sambuc if (address == NULL) { 204433d6423SLionel Sambuc errno = EFAULT; 205433d6423SLionel Sambuc return -1; 206433d6423SLionel Sambuc } 207433d6423SLionel Sambuc 208433d6423SLionel Sambuc did_mknod = 0; 209433d6423SLionel Sambuc 210433d6423SLionel Sambuc r = mknod(((struct sockaddr_un *) __UNCONST(address))->sun_path, 211433d6423SLionel Sambuc S_IFSOCK|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0); 212433d6423SLionel Sambuc 213433d6423SLionel Sambuc if (r == -1 && errno != EEXIST) { 214433d6423SLionel Sambuc return -1; 215433d6423SLionel Sambuc } else if (r == 0) { 216433d6423SLionel Sambuc did_mknod = 1; 217433d6423SLionel Sambuc } 218433d6423SLionel Sambuc 219433d6423SLionel Sambuc /* perform the bind */ 220433d6423SLionel Sambuc r= ioctl(sock, NWIOSUDSADDR, (void *) __UNCONST(address)); 221433d6423SLionel Sambuc 222433d6423SLionel Sambuc if (r == -1 && did_mknod) { 223433d6423SLionel Sambuc 224433d6423SLionel Sambuc /* bind() failed in pfs, so we roll back the 225433d6423SLionel Sambuc * file system change 226433d6423SLionel Sambuc */ 227433d6423SLionel Sambuc unlink(((struct sockaddr_un *) __UNCONST(address))->sun_path); 228433d6423SLionel Sambuc } 229433d6423SLionel Sambuc 230433d6423SLionel Sambuc return r; 231433d6423SLionel Sambuc } 232