netbsd32_socket.c revision 1.1.4.1 1 /* $NetBSD: netbsd32_socket.c,v 1.1.4.1 2001/06/21 20:00:06 nathanw 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 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #if defined(_KERNEL_OPT)
32 #include "opt_ktrace.h"
33 #endif
34
35 /*
36 * Though COMPAT_OLDSOCK is needed only for COMPAT_43, SunOS, Linux,
37 * HP-UX, FreeBSD, Ultrix, OSF1, we define it unconditionally so that
38 * this would be LKM-safe.
39 */
40 #define COMPAT_OLDSOCK /* used by <sys/socket.h> */
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #define msg __msg /* Don't ask me! */
45 #include <sys/malloc.h>
46 #include <sys/mount.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <sys/socketvar.h>
50 #include <sys/mbuf.h>
51 #include <sys/ktrace.h>
52 #include <sys/file.h>
53 #include <sys/filedesc.h>
54 #include <sys/syscallargs.h>
55 #include <sys/proc.h>
56
57 #include <compat/netbsd32/netbsd32.h>
58 #include <compat/netbsd32/netbsd32_syscallargs.h>
59 #include <compat/netbsd32/netbsd32_conv.h>
60
61 /* note that the netbsd32_msghdr's iov really points to a struct iovec, not a netbsd32_iovec. */
62 static int recvit32 __P((struct proc *, int, struct netbsd32_msghdr *, struct iovec *, caddr_t,
63 register_t *));
64
65 int
66 netbsd32_recvmsg(p, v, retval)
67 struct proc *p;
68 void *v;
69 register_t *retval;
70 {
71 struct netbsd32_recvmsg_args /* {
72 syscallarg(int) s;
73 syscallarg(netbsd32_msghdrp_t) msg;
74 syscallarg(int) flags;
75 } */ *uap = v;
76 struct netbsd32_msghdr msg;
77 struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
78 int error;
79
80 error = copyin((caddr_t)(u_long)SCARG(uap, msg), (caddr_t)&msg,
81 sizeof(msg));
82 /* netbsd32_msghdr needs the iov pre-allocated */
83 if (error)
84 return (error);
85 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) {
86 if ((u_int)msg.msg_iovlen > IOV_MAX)
87 return (EMSGSIZE);
88 MALLOC(iov, struct iovec *,
89 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
90 M_WAITOK);
91 } else if ((u_int)msg.msg_iovlen > 0)
92 iov = aiov;
93 else
94 return (EMSGSIZE);
95 #ifdef COMPAT_OLDSOCK
96 msg.msg_flags = SCARG(uap, flags) &~ MSG_COMPAT;
97 #else
98 msg.msg_flags = SCARG(uap, flags);
99 #endif
100 uiov = (struct iovec *)(u_long)msg.msg_iov;
101 error = netbsd32_to_iovecin((struct netbsd32_iovec *)uiov,
102 iov, msg.msg_iovlen);
103 if (error)
104 goto done;
105 if ((error = recvit32(p, SCARG(uap, s), &msg, iov, (caddr_t)0, retval)) == 0) {
106 error = copyout((caddr_t)&msg, (caddr_t)(u_long)SCARG(uap, msg),
107 sizeof(msg));
108 }
109 done:
110 if (iov != aiov)
111 FREE(iov, M_IOV);
112 return (error);
113 }
114
115 int
116 recvit32(p, s, mp, iov, namelenp, retsize)
117 struct proc *p;
118 int s;
119 struct netbsd32_msghdr *mp;
120 struct iovec *iov;
121 caddr_t namelenp;
122 register_t *retsize;
123 {
124 struct file *fp;
125 struct uio auio;
126 int i;
127 int len, error;
128 struct mbuf *from = 0, *control = 0;
129 struct socket *so;
130 #ifdef KTRACE
131 struct iovec *ktriov = NULL;
132 #endif
133
134 /* getsock() will use the descriptor for us */
135 if ((error = getsock(p->p_fd, s, &fp)) != 0)
136 return (error);
137 auio.uio_iov = iov;
138 auio.uio_iovcnt = mp->msg_iovlen;
139 auio.uio_segflg = UIO_USERSPACE;
140 auio.uio_rw = UIO_READ;
141 auio.uio_procp = p;
142 auio.uio_offset = 0; /* XXX */
143 auio.uio_resid = 0;
144 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
145 #if 0
146 /* cannot happen iov_len is unsigned */
147 if (iov->iov_len < 0) {
148 error = EINVAL;
149 goto out1;
150 }
151 #endif
152 /*
153 * Reads return ssize_t because -1 is returned on error.
154 * Therefore we must restrict the length to SSIZE_MAX to
155 * avoid garbage return values.
156 */
157 auio.uio_resid += iov->iov_len;
158 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
159 error = EINVAL;
160 goto out1;
161 }
162 }
163 #ifdef KTRACE
164 if (KTRPOINT(p, KTR_GENIO)) {
165 int iovlen = auio.uio_iovcnt * sizeof(struct iovec);
166
167 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
168 memcpy((caddr_t)ktriov, (caddr_t)auio.uio_iov, iovlen);
169 }
170 #endif
171 len = auio.uio_resid;
172 so = (struct socket *)fp->f_data;
173 error = (*so->so_receive)(so, &from, &auio, NULL,
174 mp->msg_control ? &control : NULL, &mp->msg_flags);
175 if (error) {
176 if (auio.uio_resid != len && (error == ERESTART ||
177 error == EINTR || error == EWOULDBLOCK))
178 error = 0;
179 }
180 #ifdef KTRACE
181 if (ktriov != NULL) {
182 if (error == 0)
183 ktrgenio(p, s, UIO_READ, ktriov,
184 len - auio.uio_resid, error);
185 FREE(ktriov, M_TEMP);
186 }
187 #endif
188 if (error)
189 goto out;
190 *retsize = len - auio.uio_resid;
191 if (mp->msg_name) {
192 len = mp->msg_namelen;
193 if (len <= 0 || from == 0)
194 len = 0;
195 else {
196 #ifdef COMPAT_OLDSOCK
197 if (mp->msg_flags & MSG_COMPAT)
198 mtod(from, struct osockaddr *)->sa_family =
199 mtod(from, struct sockaddr *)->sa_family;
200 #endif
201 if (len > from->m_len)
202 len = from->m_len;
203 /* else if len < from->m_len ??? */
204 error = copyout(mtod(from, caddr_t),
205 (caddr_t)(u_long)mp->msg_name, (unsigned)len);
206 if (error)
207 goto out;
208 }
209 mp->msg_namelen = len;
210 if (namelenp &&
211 (error = copyout((caddr_t)&len, namelenp, sizeof(int)))) {
212 #ifdef COMPAT_OLDSOCK
213 if (mp->msg_flags & MSG_COMPAT)
214 error = 0; /* old recvfrom didn't check */
215 else
216 #endif
217 goto out;
218 }
219 }
220 if (mp->msg_control) {
221 #ifdef COMPAT_OLDSOCK
222 /*
223 * We assume that old recvmsg calls won't receive access
224 * rights and other control info, esp. as control info
225 * is always optional and those options didn't exist in 4.3.
226 * If we receive rights, trim the cmsghdr; anything else
227 * is tossed.
228 */
229 if (control && mp->msg_flags & MSG_COMPAT) {
230 if (mtod(control, struct cmsghdr *)->cmsg_level !=
231 SOL_SOCKET ||
232 mtod(control, struct cmsghdr *)->cmsg_type !=
233 SCM_RIGHTS) {
234 mp->msg_controllen = 0;
235 goto out;
236 }
237 control->m_len -= sizeof(struct cmsghdr);
238 control->m_data += sizeof(struct cmsghdr);
239 }
240 #endif
241 len = mp->msg_controllen;
242 if (len <= 0 || control == 0)
243 len = 0;
244 else {
245 struct mbuf *m = control;
246 caddr_t p = (caddr_t)(u_long)mp->msg_control;
247
248 do {
249 i = m->m_len;
250 if (len < i) {
251 mp->msg_flags |= MSG_CTRUNC;
252 i = len;
253 }
254 error = copyout(mtod(m, caddr_t), p,
255 (unsigned)i);
256 if (m->m_next)
257 i = ALIGN(i);
258 p += i;
259 len -= i;
260 if (error != 0 || len <= 0)
261 break;
262 } while ((m = m->m_next) != NULL);
263 len = p - (caddr_t)(u_long)mp->msg_control;
264 }
265 mp->msg_controllen = len;
266 }
267 out:
268 if (from)
269 m_freem(from);
270 if (control)
271 m_freem(control);
272 out1:
273 FILE_UNUSE(fp, p);
274 return (error);
275 }
276
277 int
278 netbsd32_sendmsg(p, v, retval)
279 struct proc *p;
280 void *v;
281 register_t *retval;
282 {
283 struct netbsd32_sendmsg_args /* {
284 syscallarg(int) s;
285 syscallarg(const netbsd32_msghdrp_t) msg;
286 syscallarg(int) flags;
287 } */ *uap = v;
288 struct msghdr msg;
289 struct netbsd32_msghdr msg32;
290 struct iovec aiov[UIO_SMALLIOV], *iov;
291 int error;
292
293 error = copyin((caddr_t)(u_long)SCARG(uap, msg),
294 (caddr_t)&msg32, sizeof(msg32));
295 if (error)
296 return (error);
297 netbsd32_to_msghdr(&msg32, &msg);
298 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) {
299 if ((u_int)msg.msg_iovlen > IOV_MAX)
300 return (EMSGSIZE);
301 MALLOC(iov, struct iovec *,
302 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
303 M_WAITOK);
304 } else if ((u_int)msg.msg_iovlen > 0)
305 iov = aiov;
306 else
307 return (EMSGSIZE);
308 error = netbsd32_to_iovecin((struct netbsd32_iovec *)msg.msg_iov,
309 iov, msg.msg_iovlen);
310 if (error)
311 goto done;
312 msg.msg_iov = iov;
313 #ifdef COMPAT_OLDSOCK
314 msg.msg_flags = 0;
315 #endif
316 /* Luckily we can use this directly */
317 error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
318 done:
319 if (iov != aiov)
320 FREE(iov, M_IOV);
321 return (error);
322 }
323
324 int
325 netbsd32_recvfrom(p, v, retval)
326 struct proc *p;
327 void *v;
328 register_t *retval;
329 {
330 struct netbsd32_recvfrom_args /* {
331 syscallarg(int) s;
332 syscallarg(netbsd32_voidp) buf;
333 syscallarg(netbsd32_size_t) len;
334 syscallarg(int) flags;
335 syscallarg(netbsd32_sockaddrp_t) from;
336 syscallarg(netbsd32_intp) fromlenaddr;
337 } */ *uap = v;
338 struct netbsd32_msghdr msg;
339 struct iovec aiov;
340 int error;
341
342 if (SCARG(uap, fromlenaddr)) {
343 error = copyin((caddr_t)(u_long)SCARG(uap, fromlenaddr),
344 (caddr_t)&msg.msg_namelen,
345 sizeof(msg.msg_namelen));
346 if (error)
347 return (error);
348 } else
349 msg.msg_namelen = 0;
350 msg.msg_name = SCARG(uap, from);
351 msg.msg_iov = NULL; /* ignored in recvit32(), uses iov */
352 msg.msg_iovlen = 1;
353 aiov.iov_base = (caddr_t)(u_long)SCARG(uap, buf);
354 aiov.iov_len = (u_long)SCARG(uap, len);
355 msg.msg_control = 0;
356 msg.msg_flags = SCARG(uap, flags);
357 return (recvit32(p, SCARG(uap, s), &msg, &aiov,
358 (caddr_t)(u_long)SCARG(uap, fromlenaddr), retval));
359 }
360
361 int
362 netbsd32_sendto(p, v, retval)
363 struct proc *p;
364 void *v;
365 register_t *retval;
366 {
367 struct netbsd32_sendto_args /* {
368 syscallarg(int) s;
369 syscallarg(const netbsd32_voidp) buf;
370 syscallarg(netbsd32_size_t) len;
371 syscallarg(int) flags;
372 syscallarg(const netbsd32_sockaddrp_t) to;
373 syscallarg(int) tolen;
374 } */ *uap = v;
375 struct msghdr msg;
376 struct iovec aiov;
377
378 msg.msg_name = (caddr_t)(u_long)SCARG(uap, to); /* XXX kills const */
379 msg.msg_namelen = SCARG(uap, tolen);
380 msg.msg_iov = &aiov;
381 msg.msg_iovlen = 1;
382 msg.msg_control = 0;
383 #ifdef COMPAT_OLDSOCK
384 msg.msg_flags = 0;
385 #endif
386 aiov.iov_base = (char *)(u_long)SCARG(uap, buf); /* XXX kills const */
387 aiov.iov_len = SCARG(uap, len);
388 return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval));
389 }
390