xref: /minix/minix/lib/libc/sys/socket.c (revision 045e0ed3)
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
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 
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
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 
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 
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 
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 
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