1433d6423SLionel Sambuc #include <sys/cdefs.h>
2433d6423SLionel Sambuc #include "namespace.h"
3c38dbb97SDavid van Moolenbroek #include <lib.h>
4433d6423SLionel Sambuc
5433d6423SLionel Sambuc #include <unistd.h>
6433d6423SLionel Sambuc #include <stdint.h>
7433d6423SLionel Sambuc #include <stdlib.h>
8433d6423SLionel Sambuc #include <limits.h>
9433d6423SLionel Sambuc #include <errno.h>
10433d6423SLionel Sambuc #include <stdio.h>
11433d6423SLionel Sambuc #include <string.h>
12433d6423SLionel Sambuc #include <sys/ioctl.h>
13433d6423SLionel Sambuc #include <sys/socket.h>
14433d6423SLionel Sambuc #include <sys/types.h>
15433d6423SLionel Sambuc #include <sys/stat.h>
16433d6423SLionel Sambuc #include <netinet/in.h>
17433d6423SLionel Sambuc
18433d6423SLionel Sambuc #include <net/gen/in.h>
19433d6423SLionel Sambuc #include <net/gen/tcp.h>
20433d6423SLionel Sambuc #include <net/gen/tcp_io.h>
21433d6423SLionel Sambuc #include <net/gen/udp.h>
22433d6423SLionel Sambuc #include <net/gen/udp_io.h>
23433d6423SLionel Sambuc #include <sys/un.h>
24433d6423SLionel Sambuc
25433d6423SLionel Sambuc #include <minix/config.h>
26433d6423SLionel Sambuc #include <minix/const.h>
27433d6423SLionel Sambuc
28433d6423SLionel Sambuc #define DEBUG 0
29433d6423SLionel Sambuc
30433d6423SLionel Sambuc static int _tcp_bind(int sock, const struct sockaddr *address,
31433d6423SLionel Sambuc socklen_t address_len, nwio_tcpconf_t *tcpconfp);
32433d6423SLionel Sambuc static int _udp_bind(int sock, const struct sockaddr *address,
33433d6423SLionel Sambuc socklen_t address_len, nwio_udpopt_t *udpoptp);
34433d6423SLionel Sambuc static int _uds_bind(int sock, const struct sockaddr *address,
35433d6423SLionel Sambuc socklen_t address_len, struct sockaddr_un *uds_addr);
36433d6423SLionel Sambuc
37c38dbb97SDavid van Moolenbroek /*
38c38dbb97SDavid van Moolenbroek * Bind a socket to a local address.
39c38dbb97SDavid van Moolenbroek */
40c38dbb97SDavid van Moolenbroek static int
__bind(int fd,const struct sockaddr * address,socklen_t address_len)41c38dbb97SDavid van Moolenbroek __bind(int fd, const struct sockaddr * address, socklen_t address_len)
42c38dbb97SDavid van Moolenbroek {
43c38dbb97SDavid van Moolenbroek message m;
44c38dbb97SDavid van Moolenbroek
45c38dbb97SDavid van Moolenbroek memset(&m, 0, sizeof(m));
46c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.fd = fd;
47c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.addr = (vir_bytes)address;
48c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.addr_len = address_len;
49c38dbb97SDavid van Moolenbroek
50c38dbb97SDavid van Moolenbroek return _syscall(VFS_PROC_NR, VFS_BIND, &m);
51c38dbb97SDavid van Moolenbroek }
52c38dbb97SDavid van Moolenbroek
bind(int sock,const struct sockaddr * address,socklen_t address_len)53433d6423SLionel Sambuc int bind(int sock, const struct sockaddr *address, socklen_t address_len)
54433d6423SLionel Sambuc {
55433d6423SLionel Sambuc int r;
56433d6423SLionel Sambuc nwio_tcpconf_t tcpconf;
57433d6423SLionel Sambuc nwio_udpopt_t udpopt;
58433d6423SLionel Sambuc struct sockaddr_un uds_addr;
59433d6423SLionel Sambuc
60c38dbb97SDavid van Moolenbroek r = __bind(sock, address, address_len);
61*84ed480eSDavid van Moolenbroek if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS))
62c38dbb97SDavid van Moolenbroek return r;
63c38dbb97SDavid van Moolenbroek
64433d6423SLionel Sambuc r= ioctl(sock, NWIOGTCPCONF, &tcpconf);
65433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY)
66433d6423SLionel Sambuc {
67433d6423SLionel Sambuc if (r == -1)
68433d6423SLionel Sambuc return r;
69433d6423SLionel Sambuc r= _tcp_bind(sock, address, address_len, &tcpconf);
70433d6423SLionel Sambuc #if DEBUG
71433d6423SLionel Sambuc if (r == -1)
72433d6423SLionel Sambuc {
73433d6423SLionel Sambuc int t_errno= errno;
74433d6423SLionel Sambuc fprintf(stderr, "bind(tcp) failed: %s\n",
75433d6423SLionel Sambuc strerror(errno));
76433d6423SLionel Sambuc errno= t_errno;
77433d6423SLionel Sambuc }
78433d6423SLionel Sambuc #endif
79433d6423SLionel Sambuc return r;
80433d6423SLionel Sambuc }
81433d6423SLionel Sambuc
82433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDPOPT, &udpopt);
83433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY)
84433d6423SLionel Sambuc {
85433d6423SLionel Sambuc if (r == -1)
86433d6423SLionel Sambuc return r;
87433d6423SLionel Sambuc return _udp_bind(sock, address, address_len, &udpopt);
88433d6423SLionel Sambuc }
89433d6423SLionel Sambuc
90433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSADDR, &uds_addr);
91433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY)
92433d6423SLionel Sambuc {
93433d6423SLionel Sambuc if (r == -1)
94433d6423SLionel Sambuc return r;
95433d6423SLionel Sambuc return _uds_bind(sock, address, address_len, &uds_addr);
96433d6423SLionel Sambuc }
97433d6423SLionel Sambuc
98c38dbb97SDavid van Moolenbroek errno = ENOTSOCK;
99433d6423SLionel Sambuc return -1;
100433d6423SLionel Sambuc }
101433d6423SLionel Sambuc
_tcp_bind(int sock,const struct sockaddr * address,socklen_t address_len,nwio_tcpconf_t * tcpconfp)102433d6423SLionel Sambuc static int _tcp_bind(int sock, const struct sockaddr *address,
103433d6423SLionel Sambuc socklen_t address_len, nwio_tcpconf_t *tcpconfp)
104433d6423SLionel Sambuc {
105433d6423SLionel Sambuc int r;
106433d6423SLionel Sambuc nwio_tcpconf_t tcpconf;
107433d6423SLionel Sambuc struct sockaddr_in *sinp;
108433d6423SLionel Sambuc
109433d6423SLionel Sambuc sinp= (struct sockaddr_in *) __UNCONST(address);
110433d6423SLionel Sambuc if (sinp->sin_family != AF_INET || address_len < sizeof(*sinp))
111433d6423SLionel Sambuc {
112433d6423SLionel Sambuc #if DEBUG
113433d6423SLionel Sambuc fprintf(stderr, "bind(tcp): sin_family = %d, len = %d\n",
114433d6423SLionel Sambuc sinp->sin_family, address_len);
115433d6423SLionel Sambuc #endif
116433d6423SLionel Sambuc errno= EAFNOSUPPORT;
117433d6423SLionel Sambuc return -1;
118433d6423SLionel Sambuc }
119433d6423SLionel Sambuc
120433d6423SLionel Sambuc if (sinp->sin_addr.s_addr != INADDR_ANY &&
121433d6423SLionel Sambuc sinp->sin_addr.s_addr != tcpconfp->nwtc_locaddr)
122433d6423SLionel Sambuc {
123433d6423SLionel Sambuc errno= EADDRNOTAVAIL;
124433d6423SLionel Sambuc return -1;
125433d6423SLionel Sambuc }
126433d6423SLionel Sambuc
127433d6423SLionel Sambuc tcpconf.nwtc_flags= 0;
128433d6423SLionel Sambuc
129433d6423SLionel Sambuc if (sinp->sin_port == 0)
130433d6423SLionel Sambuc tcpconf.nwtc_flags |= NWTC_LP_SEL;
131433d6423SLionel Sambuc else
132433d6423SLionel Sambuc {
133433d6423SLionel Sambuc tcpconf.nwtc_flags |= NWTC_LP_SET;
134433d6423SLionel Sambuc tcpconf.nwtc_locport= sinp->sin_port;
135433d6423SLionel Sambuc }
136433d6423SLionel Sambuc
137433d6423SLionel Sambuc r= ioctl(sock, NWIOSTCPCONF, &tcpconf);
138433d6423SLionel Sambuc return r;
139433d6423SLionel Sambuc }
140433d6423SLionel Sambuc
_udp_bind(int sock,const struct sockaddr * address,socklen_t address_len,nwio_udpopt_t * udpoptp)141433d6423SLionel Sambuc static int _udp_bind(int sock, const struct sockaddr *address,
142433d6423SLionel Sambuc socklen_t address_len, nwio_udpopt_t *udpoptp)
143433d6423SLionel Sambuc {
144433d6423SLionel Sambuc int r;
145433d6423SLionel Sambuc unsigned long curr_flags;
146433d6423SLionel Sambuc nwio_udpopt_t udpopt;
147433d6423SLionel Sambuc struct sockaddr_in *sinp;
148433d6423SLionel Sambuc
149433d6423SLionel Sambuc sinp= (struct sockaddr_in *) __UNCONST(address);
150433d6423SLionel Sambuc if (sinp->sin_family != AF_INET || address_len < sizeof(*sinp))
151433d6423SLionel Sambuc {
152433d6423SLionel Sambuc #if DEBUG
153433d6423SLionel Sambuc fprintf(stderr, "bind(udp): sin_family = %d, len = %d\n",
154433d6423SLionel Sambuc sinp->sin_family, address_len);
155433d6423SLionel Sambuc #endif
156433d6423SLionel Sambuc errno= EAFNOSUPPORT;
157433d6423SLionel Sambuc return -1;
158433d6423SLionel Sambuc }
159433d6423SLionel Sambuc
160433d6423SLionel Sambuc if (sinp->sin_addr.s_addr != INADDR_ANY &&
161433d6423SLionel Sambuc sinp->sin_addr.s_addr != udpoptp->nwuo_locaddr)
162433d6423SLionel Sambuc {
163433d6423SLionel Sambuc errno= EADDRNOTAVAIL;
164433d6423SLionel Sambuc return -1;
165433d6423SLionel Sambuc }
166433d6423SLionel Sambuc
167433d6423SLionel Sambuc udpopt.nwuo_flags= 0;
168433d6423SLionel Sambuc
169433d6423SLionel Sambuc if (sinp->sin_port == 0)
170433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_LP_SEL;
171433d6423SLionel Sambuc else
172433d6423SLionel Sambuc {
173433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_LP_SET;
174433d6423SLionel Sambuc udpopt.nwuo_locport= sinp->sin_port;
175433d6423SLionel Sambuc }
176433d6423SLionel Sambuc
177433d6423SLionel Sambuc curr_flags= udpoptp->nwuo_flags;
178433d6423SLionel Sambuc if (!(curr_flags & NWUO_ACC_MASK))
179433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_EXCL;
180433d6423SLionel Sambuc if (!(curr_flags & (NWUO_EN_LOC|NWUO_DI_LOC)))
181433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_EN_LOC;
182433d6423SLionel Sambuc if (!(curr_flags & (NWUO_EN_BROAD|NWUO_DI_BROAD)))
183433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_EN_BROAD;
184433d6423SLionel Sambuc if (!(curr_flags & (NWUO_RP_SET|NWUO_RP_ANY)))
185433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_RP_ANY;
186433d6423SLionel Sambuc if (!(curr_flags & (NWUO_RA_SET|NWUO_RA_ANY)))
187433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_RA_ANY;
188433d6423SLionel Sambuc if (!(curr_flags & (NWUO_RWDATONLY|NWUO_RWDATALL)))
189433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_RWDATALL;
190433d6423SLionel Sambuc if (!(curr_flags & (NWUO_EN_IPOPT|NWUO_DI_IPOPT)))
191433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_DI_IPOPT;
192433d6423SLionel Sambuc
193433d6423SLionel Sambuc r= ioctl(sock, NWIOSUDPOPT, &udpopt);
194433d6423SLionel Sambuc return r;
195433d6423SLionel Sambuc }
196433d6423SLionel Sambuc
_uds_bind(int sock,const struct sockaddr * address,socklen_t address_len,struct sockaddr_un * uds_addr)197433d6423SLionel Sambuc static int _uds_bind(int sock, const struct sockaddr *address,
198433d6423SLionel Sambuc socklen_t address_len, struct sockaddr_un *uds_addr)
199433d6423SLionel Sambuc {
200433d6423SLionel Sambuc int r;
201433d6423SLionel Sambuc int did_mknod;
202433d6423SLionel Sambuc
203433d6423SLionel Sambuc if (address == NULL) {
204433d6423SLionel Sambuc errno = EFAULT;
205433d6423SLionel Sambuc return -1;
206433d6423SLionel Sambuc }
207433d6423SLionel Sambuc
208433d6423SLionel Sambuc did_mknod = 0;
209433d6423SLionel Sambuc
210433d6423SLionel Sambuc r = mknod(((struct sockaddr_un *) __UNCONST(address))->sun_path,
211433d6423SLionel Sambuc S_IFSOCK|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0);
212433d6423SLionel Sambuc
213433d6423SLionel Sambuc if (r == -1 && errno != EEXIST) {
214433d6423SLionel Sambuc return -1;
215433d6423SLionel Sambuc } else if (r == 0) {
216433d6423SLionel Sambuc did_mknod = 1;
217433d6423SLionel Sambuc }
218433d6423SLionel Sambuc
219433d6423SLionel Sambuc /* perform the bind */
220433d6423SLionel Sambuc r= ioctl(sock, NWIOSUDSADDR, (void *) __UNCONST(address));
221433d6423SLionel Sambuc
222433d6423SLionel Sambuc if (r == -1 && did_mknod) {
223433d6423SLionel Sambuc
224433d6423SLionel Sambuc /* bind() failed in pfs, so we roll back the
225433d6423SLionel Sambuc * file system change
226433d6423SLionel Sambuc */
227433d6423SLionel Sambuc unlink(((struct sockaddr_un *) __UNCONST(address))->sun_path);
228433d6423SLionel Sambuc }
229433d6423SLionel Sambuc
230433d6423SLionel Sambuc return r;
231433d6423SLionel Sambuc }
232