netbsd32_socket.c revision 1.36.4.1 1 /* $NetBSD: netbsd32_socket.c,v 1.36.4.1 2010/05/30 05:17:15 rmind Exp $ */
2
3 /*
4 * Copyright (c) 1998, 2001 Matthew R. Green
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: netbsd32_socket.c,v 1.36.4.1 2010/05/30 05:17:15 rmind Exp $");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #define msg __msg /* Don't ask me! */
35 #include <sys/mount.h>
36 #include <sys/socket.h>
37 #include <sys/sockio.h>
38 #include <sys/socketvar.h>
39 #include <sys/mbuf.h>
40 #include <sys/ktrace.h>
41 #include <sys/file.h>
42 #include <sys/filedesc.h>
43 #include <sys/syscallargs.h>
44 #include <sys/proc.h>
45 #include <sys/dirent.h>
46
47 #include <compat/netbsd32/netbsd32.h>
48 #include <compat/netbsd32/netbsd32_syscallargs.h>
49 #include <compat/netbsd32/netbsd32_conv.h>
50
51 /*
52 * Note that the netbsd32_msghdr's iov really points to a struct iovec,
53 * not a netbsd32_iovec.
54 */
55 static int recvit32(struct lwp *, int, struct netbsd32_msghdr *,
56 struct iovec *, void *, register_t *);
57
58 int
59 netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap, register_t *retval)
60 {
61 /* {
62 syscallarg(int) s;
63 syscallarg(netbsd32_msghdrp_t) msg;
64 syscallarg(int) flags;
65 } */
66 struct netbsd32_msghdr msg;
67 struct iovec aiov[UIO_SMALLIOV], *iov;
68 struct netbsd32_iovec *iov32;
69 size_t iovsz;
70 int error;
71
72 error = copyin(SCARG_P32(uap, msg), &msg, sizeof(msg));
73 /* netbsd32_msghdr needs the iov pre-allocated */
74 if (error)
75 return (error);
76 iovsz = msg.msg_iovlen * sizeof(struct iovec);
77 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) {
78 if ((u_int)msg.msg_iovlen > IOV_MAX)
79 return (EMSGSIZE);
80 iov = kmem_alloc(iovsz, KM_SLEEP);
81 } else
82 iov = aiov;
83 msg.msg_flags = SCARG(uap, flags);
84 iov32 = NETBSD32PTR64(msg.msg_iov);
85 error = netbsd32_to_iovecin(iov32, iov, msg.msg_iovlen);
86 if (error)
87 goto done;
88 if ((error = recvit32(l, SCARG(uap, s), &msg, iov, (void *)0,
89 retval)) == 0) {
90 error = copyout(&msg, SCARG_P32(uap, msg), sizeof(msg));
91 }
92 done:
93 if (iov != aiov)
94 kmem_free(iov, iovsz);
95 return (error);
96 }
97
98 int
99 recvit32(struct lwp *l, int s, struct netbsd32_msghdr *mp, struct iovec *iov, void *namelenp, register_t *retsize)
100 {
101 struct uio auio;
102 struct mbuf *from = 0, *control = 0;
103 struct socket *so;
104 struct iovec *ktriov = NULL;
105 size_t len, iovsz;
106 int i, error;
107
108 /* fd_getsock() will use the descriptor for us */
109 if ((error = fd_getsock(s, &so)) != 0)
110 return (error);
111 auio.uio_iov = iov;
112 auio.uio_iovcnt = mp->msg_iovlen;
113 auio.uio_rw = UIO_READ;
114 auio.uio_vmspace = l->l_proc->p_vmspace;
115 auio.uio_offset = 0; /* XXX */
116 auio.uio_resid = 0;
117 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
118 /*
119 * Reads return ssize_t because -1 is returned on error.
120 * Therefore we must restrict the length to SSIZE_MAX to
121 * avoid garbage return values.
122 */
123 auio.uio_resid += iov->iov_len;
124 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
125 error = EINVAL;
126 goto out1;
127 }
128 }
129
130 iovsz = mp->msg_iovlen * sizeof(struct iovec);
131 if (ktrpoint(KTR_GENIO)) {
132 ktriov = kmem_alloc(iovsz, KM_SLEEP);
133 memcpy(ktriov, auio.uio_iov, iovsz);
134 }
135
136 len = auio.uio_resid;
137 error = (*so->so_receive)(so, &from, &auio, NULL,
138 NETBSD32PTR64(mp->msg_control) ? &control : NULL,
139 &mp->msg_flags);
140 if (error) {
141 if (auio.uio_resid != len && (error == ERESTART ||
142 error == EINTR || error == EWOULDBLOCK))
143 error = 0;
144 }
145
146 if (ktriov != NULL) {
147 ktrgeniov(s, UIO_READ, ktriov, len - auio.uio_resid, error);
148 kmem_free(ktriov, iovsz);
149 }
150
151 if (error)
152 goto out;
153 *retsize = len - auio.uio_resid;
154 if (NETBSD32PTR64(mp->msg_name)) {
155 len = mp->msg_namelen;
156 if (len <= 0 || from == 0)
157 len = 0;
158 else {
159 if (len > from->m_len)
160 len = from->m_len;
161 /* else if len < from->m_len ??? */
162 error = copyout(mtod(from, void *),
163 (void *)NETBSD32PTR64(mp->msg_name),
164 (unsigned)len);
165 if (error)
166 goto out;
167 }
168 mp->msg_namelen = len;
169 if (namelenp &&
170 (error = copyout((void *)&len, namelenp, sizeof(int))))
171 goto out;
172 }
173 if (NETBSD32PTR64(mp->msg_control)) {
174 len = mp->msg_controllen;
175 if (len <= 0 || control == 0)
176 len = 0;
177 else {
178 struct mbuf *m = control;
179 void *cp = (void *)NETBSD32PTR64(mp->msg_control);
180
181 do {
182 i = m->m_len;
183 if (len < i) {
184 mp->msg_flags |= MSG_CTRUNC;
185 i = len;
186 }
187 error = copyout(mtod(m, void *), cp,
188 (unsigned)i);
189 if (m->m_next)
190 i = ALIGN(i);
191 cp = (char *)cp + i;
192 len -= i;
193 if (error != 0 || len <= 0)
194 break;
195 } while ((m = m->m_next) != NULL);
196 len = (char *)cp - (char *)NETBSD32PTR64(mp->msg_control);
197 }
198 mp->msg_controllen = len;
199 }
200 out:
201 if (from)
202 m_freem(from);
203 if (control)
204 m_freem(control);
205 out1:
206 fd_putfile(s);
207 return (error);
208 }
209
210 int
211 netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap, register_t *retval)
212 {
213 /* {
214 syscallarg(int) s;
215 syscallarg(const netbsd32_msghdrp_t) msg;
216 syscallarg(int) flags;
217 } */
218 struct msghdr msg;
219 struct netbsd32_msghdr msg32;
220 struct iovec aiov[UIO_SMALLIOV], *iov;
221 struct netbsd32_iovec *iov32;
222 size_t iovsz;
223 int error;
224
225 error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
226 if (error)
227 return (error);
228 netbsd32_to_msghdr(&msg32, &msg);
229
230 iovsz = msg.msg_iovlen * sizeof(struct iovec);
231 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) {
232 if ((u_int)msg.msg_iovlen > IOV_MAX)
233 return (EMSGSIZE);
234 iov = kmem_alloc(iovsz, KM_SLEEP);
235 } else
236 iov = aiov;
237
238 iov32 = NETBSD32PTR64(msg32.msg_iov);
239 error = netbsd32_to_iovecin(iov32, iov, msg.msg_iovlen);
240 if (error)
241 goto done;
242 msg.msg_iov = iov;
243 msg.msg_flags = 0;
244
245 /* Luckily we can use this directly */
246 /* XXX: dsl (June'07) The cmsg alignment rules differ ! */
247 error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
248 done:
249 if (iov != aiov)
250 kmem_free(iov, iovsz);
251 return (error);
252 }
253
254 int
255 netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap, register_t *retval)
256 {
257 /* {
258 syscallarg(int) s;
259 syscallarg(netbsd32_voidp) buf;
260 syscallarg(netbsd32_size_t) len;
261 syscallarg(int) flags;
262 syscallarg(netbsd32_sockaddrp_t) from;
263 syscallarg(netbsd32_intp) fromlenaddr;
264 } */
265 struct netbsd32_msghdr msg;
266 struct iovec aiov;
267 int error;
268
269 if (SCARG_P32(uap, fromlenaddr)) {
270 error = copyin(SCARG_P32(uap, fromlenaddr),
271 &msg.msg_namelen, sizeof(msg.msg_namelen));
272 if (error)
273 return (error);
274 } else
275 msg.msg_namelen = 0;
276 msg.msg_name = SCARG(uap, from);
277 NETBSD32PTR32(msg.msg_iov, 0); /* ignored in recvit32(), uses iov */
278 msg.msg_iovlen = 1;
279 aiov.iov_base = SCARG_P32(uap, buf);
280 aiov.iov_len = (u_long)SCARG(uap, len);
281 NETBSD32PTR32(msg.msg_control, 0);
282 msg.msg_flags = SCARG(uap, flags);
283 return (recvit32(l, SCARG(uap, s), &msg, &aiov,
284 SCARG_P32(uap, fromlenaddr), retval));
285 }
286
287 int
288 netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap, register_t *retval)
289 {
290 /* {
291 syscallarg(int) s;
292 syscallarg(const netbsd32_voidp) buf;
293 syscallarg(netbsd32_size_t) len;
294 syscallarg(int) flags;
295 syscallarg(const netbsd32_sockaddrp_t) to;
296 syscallarg(int) tolen;
297 } */
298 struct msghdr msg;
299 struct iovec aiov;
300
301 msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */
302 msg.msg_namelen = SCARG(uap, tolen);
303 msg.msg_iov = &aiov;
304 msg.msg_iovlen = 1;
305 msg.msg_control = 0;
306 aiov.iov_base = SCARG_P32(uap, buf); /* XXX kills const */
307 aiov.iov_len = SCARG(uap, len);
308 msg.msg_flags = 0;
309 return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
310 }
311