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