1 #include <sys/cdefs.h>
2 #include "namespace.h"
3 #include <lib.h>
4
5 #ifdef __weak_alias
6 __weak_alias(socket, __socket30)
7 #endif
8
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <signal.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <sys/socket.h>
16
17 #include <sys/ioctl.h>
18 #include <sys/ioc_net.h>
19 #include <net/hton.h>
20 #include <net/gen/in.h>
21 #include <net/gen/ether.h>
22 #include <net/gen/eth_hdr.h>
23 #include <net/gen/eth_io.h>
24 #include <net/gen/ip_hdr.h>
25 #include <net/gen/ip_io.h>
26 #include <net/gen/udp.h>
27 #include <net/gen/udp_hdr.h>
28 #include <net/gen/udp_io.h>
29 #include <net/gen/dhcp.h>
30
31 #include <net/netlib.h>
32 #include <netinet/in.h>
33
34 #define DEBUG 0
35
36 static int _tcp_socket(int type, int protocol);
37 static int _udp_socket(int type, int protocol);
38 static int _uds_socket(int type, int protocol);
39 static int _raw_socket(int type, int protocol);
40 static void _socket_flags(int type, int *result);
41
42 /*
43 * Create a socket.
44 */
45 static int
__socket(int domain,int type,int protocol)46 __socket(int domain, int type, int protocol)
47 {
48 message m;
49
50 memset(&m, 0, sizeof(m));
51 m.m_lc_vfs_socket.domain = domain;
52 m.m_lc_vfs_socket.type = type;
53 m.m_lc_vfs_socket.protocol = protocol;
54
55 return _syscall(VFS_PROC_NR, VFS_SOCKET, &m);
56 }
57
socket(int domain,int type,int protocol)58 int socket(int domain, int type, int protocol)
59 {
60 int r, sock_type;
61
62 r = __socket(domain, type, protocol);
63 if (r != -1 || (errno != EAFNOSUPPORT && errno != ENOSYS))
64 return r;
65
66 sock_type = type & ~SOCK_FLAGS_MASK;
67
68 #if DEBUG
69 fprintf(stderr, "socket: domain %d, type %d, protocol %d\n",
70 domain, type, protocol);
71 #endif
72
73 if (domain == AF_UNIX)
74 return _uds_socket(type, protocol);
75
76 if (domain == AF_INET) {
77 switch (sock_type) {
78 case SOCK_STREAM:
79 return _tcp_socket(type, protocol);
80 case SOCK_DGRAM:
81 return _udp_socket(type, protocol);
82 case SOCK_RAW:
83 return _raw_socket(type, protocol);
84 default:
85 errno = EPROTOTYPE;
86 return -1;
87 }
88 }
89
90 errno = EAFNOSUPPORT;
91 return -1;
92 }
93
94 static void
_socket_flags(int type,int * result)95 _socket_flags(int type, int *result)
96 {
97 /* Process socket flags */
98 if (type & SOCK_CLOEXEC) {
99 *result |= O_CLOEXEC;
100 }
101 if (type & SOCK_NONBLOCK) {
102 *result |= O_NONBLOCK;
103 }
104 if (type & SOCK_NOSIGPIPE) {
105 *result |= O_NOSIGPIPE;
106 }
107 }
108
_tcp_socket(int type,int protocol)109 static int _tcp_socket(int type, int protocol)
110 {
111 int flags = O_RDWR;
112
113 if (protocol != 0 && protocol != IPPROTO_TCP)
114 {
115 #if DEBUG
116 fprintf(stderr, "socket(tcp): bad protocol %d\n", protocol);
117 #endif
118 errno= EPROTONOSUPPORT;
119 return -1;
120 }
121
122 _socket_flags(type, &flags);
123
124 return open(TCP_DEVICE, flags);
125 }
126
_udp_socket(int type,int protocol)127 static int _udp_socket(int type, int protocol)
128 {
129 int r, fd, t_errno, flags = O_RDWR;
130 struct sockaddr_in sin;
131
132 if (protocol != 0 && protocol != IPPROTO_UDP)
133 {
134 #if DEBUG
135 fprintf(stderr, "socket(udp): bad protocol %d\n", protocol);
136 #endif
137 errno= EPROTONOSUPPORT;
138 return -1;
139 }
140 _socket_flags(type, &flags);
141 fd= open(UDP_DEVICE, flags);
142 if (fd == -1)
143 return fd;
144
145 /* Bind is implict for UDP sockets? */
146 sin.sin_family= AF_INET;
147 sin.sin_addr.s_addr= INADDR_ANY;
148 sin.sin_port= 0;
149 r= bind(fd, (struct sockaddr *)&sin, sizeof(sin));
150 if (r != 0)
151 {
152 t_errno= errno;
153 close(fd);
154 errno= t_errno;
155 return -1;
156 }
157 return fd;
158 }
159
_raw_socket(int type,int protocol)160 static int _raw_socket(int type, int protocol)
161 {
162 int fd, flags = O_RDWR;
163 nwio_ipopt_t ipopt;
164 int result;
165
166 if (protocol != IPPROTO_ICMP && protocol != IPPROTO_UDP && protocol != 0)
167 {
168 #if DEBUG
169 fprintf(stderr, "socket(icmp): bad protocol %d\n", protocol);
170 #endif
171 errno= EPROTONOSUPPORT;
172 return -1;
173 }
174 _socket_flags(type, &flags);
175 fd= open(IP_DEVICE, flags);
176 if (fd == -1)
177 return fd;
178
179 memset(&ipopt, 0, sizeof(ipopt));
180
181 ipopt.nwio_flags= NWIO_COPY;
182
183 if(protocol) {
184 ipopt.nwio_flags |= NWIO_PROTOSPEC;
185 ipopt.nwio_proto = protocol;
186 }
187
188 result = ioctl (fd, NWIOSIPOPT, &ipopt);
189 if (result<0) {
190 close(fd);
191 return -1;
192 }
193
194 result = ioctl (fd, NWIOGIPOPT, &ipopt);
195 if (result<0) {
196 close(fd);
197 return -1;
198 }
199
200 return fd;
201 }
202
_uds_socket(int type,int protocol)203 static int _uds_socket(int type, int protocol)
204 {
205 int fd, r, flags = O_RDWR, sock_type;
206
207 sock_type = type & ~SOCK_FLAGS_MASK;
208 if (sock_type != SOCK_STREAM &&
209 sock_type != SOCK_DGRAM &&
210 sock_type != SOCK_SEQPACKET) {
211 errno = EPROTOTYPE;
212 return -1;
213 }
214
215 if (protocol != 0)
216 {
217 #if DEBUG
218 fprintf(stderr, "socket(uds): bad protocol %d\n", protocol);
219 #endif
220 errno= EPROTONOSUPPORT;
221 return -1;
222 }
223
224 _socket_flags(type, &flags);
225 fd= open(UDS_DEVICE, flags);
226 if (fd == -1) {
227 return fd;
228 }
229
230 /* set the type for the socket via ioctl (SOCK_DGRAM,
231 * SOCK_STREAM, SOCK_SEQPACKET, etc)
232 */
233 r= ioctl(fd, NWIOSUDSTYPE, &sock_type);
234 if (r == -1) {
235 int ioctl_errno;
236
237 /* if that failed rollback socket creation */
238 ioctl_errno= errno;
239 close(fd);
240
241 /* return the error thrown by the call to ioctl */
242 errno= ioctl_errno;
243 return -1;
244 }
245
246 return fd;
247 }
248