xref: /minix3/minix/lib/libc/sys/bind.c (revision 03de4d97b49f6be0f827bcf030d487febfc78953)
1 #include <sys/cdefs.h>
2 #include "namespace.h"
3 #include <lib.h>
4 
5 #include <unistd.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <limits.h>
9 #include <errno.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <sys/ioctl.h>
13 #include <sys/socket.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <netinet/in.h>
17 
18 #include <net/gen/in.h>
19 #include <net/gen/tcp.h>
20 #include <net/gen/tcp_io.h>
21 #include <net/gen/udp.h>
22 #include <net/gen/udp_io.h>
23 #include <sys/un.h>
24 
25 #include <minix/config.h>
26 #include <minix/const.h>
27 
28 #define DEBUG 0
29 
30 static int _tcp_bind(int sock, const struct sockaddr *address,
31 	socklen_t address_len, nwio_tcpconf_t *tcpconfp);
32 static int _udp_bind(int sock, const struct sockaddr *address,
33 	socklen_t address_len, nwio_udpopt_t *udpoptp);
34 static int _uds_bind(int sock, const struct sockaddr *address,
35 	socklen_t address_len, struct sockaddr_un *uds_addr);
36 
37 /*
38  * Bind a socket to a local address.
39  */
40 static int
41 __bind(int fd, const struct sockaddr * address, socklen_t address_len)
42 {
43 	message m;
44 
45 	memset(&m, 0, sizeof(m));
46 	m.m_lc_vfs_sockaddr.fd = fd;
47 	m.m_lc_vfs_sockaddr.addr = (vir_bytes)address;
48 	m.m_lc_vfs_sockaddr.addr_len = address_len;
49 
50 	return _syscall(VFS_PROC_NR, VFS_BIND, &m);
51 }
52 
53 int bind(int sock, const struct sockaddr *address, socklen_t address_len)
54 {
55 	int r;
56 	nwio_tcpconf_t tcpconf;
57 	nwio_udpopt_t udpopt;
58 	struct sockaddr_un uds_addr;
59 
60 	r = __bind(sock, address, address_len);
61 	if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS))
62 		return r;
63 
64 	r= ioctl(sock, NWIOGTCPCONF, &tcpconf);
65 	if (r != -1 || errno != ENOTTY)
66 	{
67 		if (r == -1)
68 			return r;
69 		r= _tcp_bind(sock, address, address_len, &tcpconf);
70 #if DEBUG
71 		if (r == -1)
72 		{
73 			int t_errno= errno;
74 			fprintf(stderr, "bind(tcp) failed: %s\n",
75 				strerror(errno));
76 			errno= t_errno;
77 		}
78 #endif
79 		return r;
80 	}
81 
82 	r= ioctl(sock, NWIOGUDPOPT, &udpopt);
83 	if (r != -1 || errno != ENOTTY)
84 	{
85 		if (r == -1)
86 			return r;
87 		return _udp_bind(sock, address, address_len, &udpopt);
88 	}
89 
90 	r= ioctl(sock, NWIOGUDSADDR, &uds_addr);
91 	if (r != -1 || errno != ENOTTY)
92 	{
93 		if (r == -1)
94 			return r;
95 		return _uds_bind(sock, address, address_len, &uds_addr);
96 	}
97 
98 	errno = ENOTSOCK;
99 	return -1;
100 }
101 
102 static int _tcp_bind(int sock, const struct sockaddr *address,
103 	socklen_t address_len, nwio_tcpconf_t *tcpconfp)
104 {
105 	int r;
106 	nwio_tcpconf_t tcpconf;
107 	struct sockaddr_in *sinp;
108 
109 	sinp= (struct sockaddr_in *) __UNCONST(address);
110 	if (sinp->sin_family != AF_INET || address_len < sizeof(*sinp))
111 	{
112 #if DEBUG
113 		fprintf(stderr, "bind(tcp): sin_family = %d, len = %d\n",
114 			sinp->sin_family, address_len);
115 #endif
116 		errno= EAFNOSUPPORT;
117 		return -1;
118 	}
119 
120 	if (sinp->sin_addr.s_addr != INADDR_ANY &&
121 		sinp->sin_addr.s_addr != tcpconfp->nwtc_locaddr)
122 	{
123 		errno= EADDRNOTAVAIL;
124 		return -1;
125 	}
126 
127 	tcpconf.nwtc_flags= 0;
128 
129 	if (sinp->sin_port == 0)
130 		tcpconf.nwtc_flags |= NWTC_LP_SEL;
131 	else
132 	{
133 		tcpconf.nwtc_flags |= NWTC_LP_SET;
134 		tcpconf.nwtc_locport= sinp->sin_port;
135 	}
136 
137 	r= ioctl(sock, NWIOSTCPCONF, &tcpconf);
138 	return r;
139 }
140 
141 static int _udp_bind(int sock, const struct sockaddr *address,
142 	socklen_t address_len, nwio_udpopt_t *udpoptp)
143 {
144 	int r;
145 	unsigned long curr_flags;
146 	nwio_udpopt_t udpopt;
147 	struct sockaddr_in *sinp;
148 
149 	sinp= (struct sockaddr_in *) __UNCONST(address);
150 	if (sinp->sin_family != AF_INET || address_len < sizeof(*sinp))
151 	{
152 #if DEBUG
153 		fprintf(stderr, "bind(udp): sin_family = %d, len = %d\n",
154 			sinp->sin_family, address_len);
155 #endif
156 		errno= EAFNOSUPPORT;
157 		return -1;
158 	}
159 
160 	if (sinp->sin_addr.s_addr != INADDR_ANY &&
161 		sinp->sin_addr.s_addr != udpoptp->nwuo_locaddr)
162 	{
163 		errno= EADDRNOTAVAIL;
164 		return -1;
165 	}
166 
167 	udpopt.nwuo_flags= 0;
168 
169 	if (sinp->sin_port == 0)
170 		udpopt.nwuo_flags |= NWUO_LP_SEL;
171 	else
172 	{
173 		udpopt.nwuo_flags |= NWUO_LP_SET;
174 		udpopt.nwuo_locport= sinp->sin_port;
175 	}
176 
177 	curr_flags= udpoptp->nwuo_flags;
178 	if (!(curr_flags & NWUO_ACC_MASK))
179 		udpopt.nwuo_flags |= NWUO_EXCL;
180 	if (!(curr_flags & (NWUO_EN_LOC|NWUO_DI_LOC)))
181 		udpopt.nwuo_flags |= NWUO_EN_LOC;
182 	if (!(curr_flags & (NWUO_EN_BROAD|NWUO_DI_BROAD)))
183 		udpopt.nwuo_flags |= NWUO_EN_BROAD;
184 	if (!(curr_flags & (NWUO_RP_SET|NWUO_RP_ANY)))
185 		udpopt.nwuo_flags |= NWUO_RP_ANY;
186 	if (!(curr_flags & (NWUO_RA_SET|NWUO_RA_ANY)))
187 		udpopt.nwuo_flags |= NWUO_RA_ANY;
188 	if (!(curr_flags & (NWUO_RWDATONLY|NWUO_RWDATALL)))
189 		udpopt.nwuo_flags |= NWUO_RWDATALL;
190 	if (!(curr_flags & (NWUO_EN_IPOPT|NWUO_DI_IPOPT)))
191 		udpopt.nwuo_flags |= NWUO_DI_IPOPT;
192 
193 	r= ioctl(sock, NWIOSUDPOPT, &udpopt);
194 	return r;
195 }
196 
197 static int _uds_bind(int sock, const struct sockaddr *address,
198 	socklen_t address_len, struct sockaddr_un *uds_addr)
199 {
200 	int r;
201 	int did_mknod;
202 
203 	if (address == NULL) {
204 		errno = EFAULT;
205 		return -1;
206 	}
207 
208 	did_mknod = 0;
209 
210 	r = mknod(((struct sockaddr_un *) __UNCONST(address))->sun_path,
211 		S_IFSOCK|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0);
212 
213 	if (r == -1 && errno != EEXIST) {
214 		return -1;
215 	} else if (r == 0) {
216 		did_mknod = 1;
217 	}
218 
219 	/* perform the bind */
220 	r= ioctl(sock, NWIOSUDSADDR, (void *) __UNCONST(address));
221 
222 	if (r == -1 && did_mknod) {
223 
224 		/* bind() failed in pfs, so we roll back the
225 		 * file system change
226 		 */
227 		unlink(((struct sockaddr_un *) __UNCONST(address))->sun_path);
228 	}
229 
230 	return r;
231 }
232