1433d6423SLionel Sambuc #include <sys/cdefs.h> 2433d6423SLionel Sambuc #include "namespace.h" 3433d6423SLionel Sambuc 4433d6423SLionel Sambuc #ifdef __weak_alias 5433d6423SLionel Sambuc __weak_alias(socket, __socket30) 6433d6423SLionel Sambuc #endif 7433d6423SLionel Sambuc 8433d6423SLionel Sambuc #include <errno.h> 9433d6423SLionel Sambuc #include <fcntl.h> 10433d6423SLionel Sambuc #include <signal.h> 11433d6423SLionel Sambuc #include <stdio.h> 12*5dd8da10SDavid van Moolenbroek #include <string.h> 13433d6423SLionel Sambuc #include <unistd.h> 14433d6423SLionel Sambuc #include <sys/socket.h> 157f5f010bSBen Gras 16*5dd8da10SDavid van Moolenbroek #include <sys/ioctl.h> 17433d6423SLionel Sambuc #include <sys/ioc_net.h> 187f5f010bSBen Gras #include <net/hton.h> 197f5f010bSBen Gras #include <net/gen/in.h> 207f5f010bSBen Gras #include <net/gen/ether.h> 217f5f010bSBen Gras #include <net/gen/eth_hdr.h> 227f5f010bSBen Gras #include <net/gen/eth_io.h> 237f5f010bSBen Gras #include <net/gen/ip_hdr.h> 247f5f010bSBen Gras #include <net/gen/ip_io.h> 257f5f010bSBen Gras #include <net/gen/udp.h> 267f5f010bSBen Gras #include <net/gen/udp_hdr.h> 277f5f010bSBen Gras #include <net/gen/udp_io.h> 287f5f010bSBen Gras #include <net/gen/dhcp.h> 29433d6423SLionel Sambuc 30433d6423SLionel Sambuc #include <net/netlib.h> 31433d6423SLionel Sambuc #include <netinet/in.h> 32433d6423SLionel Sambuc 33433d6423SLionel Sambuc #define DEBUG 0 34433d6423SLionel Sambuc 35433d6423SLionel Sambuc static int _tcp_socket(int type, int protocol); 36433d6423SLionel Sambuc static int _udp_socket(int type, int protocol); 37433d6423SLionel Sambuc static int _uds_socket(int type, int protocol); 387f5f010bSBen Gras static int _raw_socket(int type, int protocol); 39433d6423SLionel Sambuc static void _socket_flags(int type, int *result); 40433d6423SLionel Sambuc 41433d6423SLionel Sambuc int socket(int domain, int type, int protocol) 42433d6423SLionel Sambuc { 43433d6423SLionel Sambuc int sock_type; 44433d6423SLionel Sambuc 45433d6423SLionel Sambuc sock_type = type & ~SOCK_FLAGS_MASK; 46433d6423SLionel Sambuc 47433d6423SLionel Sambuc #if DEBUG 48433d6423SLionel Sambuc fprintf(stderr, "socket: domain %d, type %d, protocol %d\n", 49433d6423SLionel Sambuc domain, type, protocol); 50433d6423SLionel Sambuc #endif 51433d6423SLionel Sambuc if (domain != AF_INET && domain != AF_UNIX) 52433d6423SLionel Sambuc { 53433d6423SLionel Sambuc #if DEBUG 54433d6423SLionel Sambuc fprintf(stderr, "socket: bad domain %d\n", domain); 55433d6423SLionel Sambuc #endif 56433d6423SLionel Sambuc errno= EAFNOSUPPORT; 57433d6423SLionel Sambuc return -1; 58433d6423SLionel Sambuc } 59433d6423SLionel Sambuc 60433d6423SLionel Sambuc if (domain == AF_UNIX && (sock_type == SOCK_STREAM || 61433d6423SLionel Sambuc sock_type == SOCK_DGRAM || 62433d6423SLionel Sambuc sock_type == SOCK_SEQPACKET)) 63433d6423SLionel Sambuc return _uds_socket(type, protocol); 64433d6423SLionel Sambuc 65433d6423SLionel Sambuc if (domain == AF_INET && sock_type == SOCK_STREAM) 66433d6423SLionel Sambuc return _tcp_socket(type, protocol); 67433d6423SLionel Sambuc 68433d6423SLionel Sambuc if (domain == AF_INET && sock_type == SOCK_DGRAM) 69433d6423SLionel Sambuc return _udp_socket(type, protocol); 70433d6423SLionel Sambuc 717f5f010bSBen Gras if (domain == AF_INET && sock_type == SOCK_RAW && protocol == IPPROTO_ICMP) 727f5f010bSBen Gras return _raw_socket(type, protocol); 737f5f010bSBen Gras 747f5f010bSBen Gras if (domain == AF_INET && sock_type == SOCK_RAW && protocol == IPPROTO_UDP) 757f5f010bSBen Gras return _raw_socket(type, protocol); 767f5f010bSBen Gras 77433d6423SLionel Sambuc #if DEBUG 78433d6423SLionel Sambuc fprintf(stderr, "socket: nothing for domain %d, type %d, protocol %d\n", 79433d6423SLionel Sambuc domain, type, protocol); 80433d6423SLionel Sambuc #endif 81433d6423SLionel Sambuc errno= EPROTOTYPE; 82433d6423SLionel Sambuc return -1; 83433d6423SLionel Sambuc } 84433d6423SLionel Sambuc 85433d6423SLionel Sambuc static void 86433d6423SLionel Sambuc _socket_flags(int type, int *result) 87433d6423SLionel Sambuc { 88433d6423SLionel Sambuc /* Process socket flags */ 89433d6423SLionel Sambuc if (type & SOCK_CLOEXEC) { 90433d6423SLionel Sambuc *result |= O_CLOEXEC; 91433d6423SLionel Sambuc } 92433d6423SLionel Sambuc if (type & SOCK_NONBLOCK) { 93433d6423SLionel Sambuc *result |= O_NONBLOCK; 94433d6423SLionel Sambuc } 95433d6423SLionel Sambuc if (type & SOCK_NOSIGPIPE) { 96433d6423SLionel Sambuc *result |= O_NOSIGPIPE; 97433d6423SLionel Sambuc } 98433d6423SLionel Sambuc } 99433d6423SLionel Sambuc 100433d6423SLionel Sambuc static int _tcp_socket(int type, int protocol) 101433d6423SLionel Sambuc { 102433d6423SLionel Sambuc int flags = O_RDWR; 103433d6423SLionel Sambuc 104433d6423SLionel Sambuc if (protocol != 0 && protocol != IPPROTO_TCP) 105433d6423SLionel Sambuc { 106433d6423SLionel Sambuc #if DEBUG 107433d6423SLionel Sambuc fprintf(stderr, "socket(tcp): bad protocol %d\n", protocol); 108433d6423SLionel Sambuc #endif 109433d6423SLionel Sambuc errno= EPROTONOSUPPORT; 110433d6423SLionel Sambuc return -1; 111433d6423SLionel Sambuc } 112433d6423SLionel Sambuc 113433d6423SLionel Sambuc _socket_flags(type, &flags); 114433d6423SLionel Sambuc 115433d6423SLionel Sambuc return open(TCP_DEVICE, flags); 116433d6423SLionel Sambuc } 117433d6423SLionel Sambuc 118433d6423SLionel Sambuc static int _udp_socket(int type, int protocol) 119433d6423SLionel Sambuc { 120433d6423SLionel Sambuc int r, fd, t_errno, flags = O_RDWR; 121433d6423SLionel Sambuc struct sockaddr_in sin; 122433d6423SLionel Sambuc 123433d6423SLionel Sambuc if (protocol != 0 && protocol != IPPROTO_UDP) 124433d6423SLionel Sambuc { 125433d6423SLionel Sambuc #if DEBUG 126433d6423SLionel Sambuc fprintf(stderr, "socket(udp): bad protocol %d\n", protocol); 127433d6423SLionel Sambuc #endif 128433d6423SLionel Sambuc errno= EPROTONOSUPPORT; 129433d6423SLionel Sambuc return -1; 130433d6423SLionel Sambuc } 131433d6423SLionel Sambuc _socket_flags(type, &flags); 132433d6423SLionel Sambuc fd= open(UDP_DEVICE, flags); 133433d6423SLionel Sambuc if (fd == -1) 134433d6423SLionel Sambuc return fd; 135433d6423SLionel Sambuc 136433d6423SLionel Sambuc /* Bind is implict for UDP sockets? */ 137433d6423SLionel Sambuc sin.sin_family= AF_INET; 138433d6423SLionel Sambuc sin.sin_addr.s_addr= INADDR_ANY; 139433d6423SLionel Sambuc sin.sin_port= 0; 140433d6423SLionel Sambuc r= bind(fd, (struct sockaddr *)&sin, sizeof(sin)); 141433d6423SLionel Sambuc if (r != 0) 142433d6423SLionel Sambuc { 143433d6423SLionel Sambuc t_errno= errno; 144433d6423SLionel Sambuc close(fd); 145433d6423SLionel Sambuc errno= t_errno; 146433d6423SLionel Sambuc return -1; 147433d6423SLionel Sambuc } 148433d6423SLionel Sambuc return fd; 149433d6423SLionel Sambuc } 150433d6423SLionel Sambuc 1517f5f010bSBen Gras static int _raw_socket(int type, int protocol) 1527f5f010bSBen Gras { 153*5dd8da10SDavid van Moolenbroek int fd, flags = O_RDWR; 1547f5f010bSBen Gras nwio_ipopt_t ipopt; 1557f5f010bSBen Gras int result; 1567f5f010bSBen Gras 1577f5f010bSBen Gras if (protocol != IPPROTO_ICMP && protocol != IPPROTO_UDP && protocol != 0) 1587f5f010bSBen Gras { 1597f5f010bSBen Gras #if DEBUG 1607f5f010bSBen Gras fprintf(stderr, "socket(icmp): bad protocol %d\n", protocol); 1617f5f010bSBen Gras #endif 1627f5f010bSBen Gras errno= EPROTONOSUPPORT; 1637f5f010bSBen Gras return -1; 1647f5f010bSBen Gras } 1657f5f010bSBen Gras _socket_flags(type, &flags); 1667f5f010bSBen Gras fd= open(IP_DEVICE, flags); 1677f5f010bSBen Gras if (fd == -1) 1687f5f010bSBen Gras return fd; 1697f5f010bSBen Gras 1707f5f010bSBen Gras memset(&ipopt, 0, sizeof(ipopt)); 1717f5f010bSBen Gras 1727f5f010bSBen Gras ipopt.nwio_flags= NWIO_COPY; 1737f5f010bSBen Gras 1747f5f010bSBen Gras if(protocol) { 1757f5f010bSBen Gras ipopt.nwio_flags |= NWIO_PROTOSPEC; 1767f5f010bSBen Gras ipopt.nwio_proto = protocol; 1777f5f010bSBen Gras } 1787f5f010bSBen Gras 1797f5f010bSBen Gras result = ioctl (fd, NWIOSIPOPT, &ipopt); 1807f5f010bSBen Gras if (result<0) { 1817f5f010bSBen Gras close(fd); 1827f5f010bSBen Gras return -1; 1837f5f010bSBen Gras } 1847f5f010bSBen Gras 1857f5f010bSBen Gras result = ioctl (fd, NWIOGIPOPT, &ipopt); 1867f5f010bSBen Gras if (result<0) { 1877f5f010bSBen Gras close(fd); 1887f5f010bSBen Gras return -1; 1897f5f010bSBen Gras } 1907f5f010bSBen Gras 1917f5f010bSBen Gras return fd; 1927f5f010bSBen Gras } 1937f5f010bSBen Gras 194433d6423SLionel Sambuc static int _uds_socket(int type, int protocol) 195433d6423SLionel Sambuc { 196433d6423SLionel Sambuc int fd, r, flags = O_RDWR, sock_type; 197433d6423SLionel Sambuc if (protocol != 0) 198433d6423SLionel Sambuc { 199433d6423SLionel Sambuc #if DEBUG 200433d6423SLionel Sambuc fprintf(stderr, "socket(uds): bad protocol %d\n", protocol); 201433d6423SLionel Sambuc #endif 202433d6423SLionel Sambuc errno= EPROTONOSUPPORT; 203433d6423SLionel Sambuc return -1; 204433d6423SLionel Sambuc } 205433d6423SLionel Sambuc 206433d6423SLionel Sambuc _socket_flags(type, &flags); 207433d6423SLionel Sambuc fd= open(UDS_DEVICE, flags); 208433d6423SLionel Sambuc if (fd == -1) { 209433d6423SLionel Sambuc return fd; 210433d6423SLionel Sambuc } 211433d6423SLionel Sambuc 212433d6423SLionel Sambuc /* set the type for the socket via ioctl (SOCK_DGRAM, 213433d6423SLionel Sambuc * SOCK_STREAM, SOCK_SEQPACKET, etc) 214433d6423SLionel Sambuc */ 215433d6423SLionel Sambuc sock_type = type & ~SOCK_FLAGS_MASK; 216433d6423SLionel Sambuc r= ioctl(fd, NWIOSUDSTYPE, &sock_type); 217433d6423SLionel Sambuc if (r == -1) { 218433d6423SLionel Sambuc int ioctl_errno; 219433d6423SLionel Sambuc 220433d6423SLionel Sambuc /* if that failed rollback socket creation */ 221433d6423SLionel Sambuc ioctl_errno= errno; 222433d6423SLionel Sambuc close(fd); 223433d6423SLionel Sambuc 224433d6423SLionel Sambuc /* return the error thrown by the call to ioctl */ 225433d6423SLionel Sambuc errno= ioctl_errno; 226433d6423SLionel Sambuc return -1; 227433d6423SLionel Sambuc } 228433d6423SLionel Sambuc 229433d6423SLionel Sambuc return fd; 230433d6423SLionel Sambuc } 231