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