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
__bind(int fd,const struct sockaddr * address,socklen_t address_len)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
bind(int sock,const struct sockaddr * address,socklen_t address_len)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
_tcp_bind(int sock,const struct sockaddr * address,socklen_t address_len,nwio_tcpconf_t * tcpconfp)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
_udp_bind(int sock,const struct sockaddr * address,socklen_t address_len,nwio_udpopt_t * udpoptp)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
_uds_bind(int sock,const struct sockaddr * address,socklen_t address_len,struct sockaddr_un * uds_addr)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