xref: /netbsd-src/sys/compat/netbsd32/netbsd32_socket.c (revision 17dd36da8292193180754d5047c0926dbb56818c)
1 /*	$NetBSD: netbsd32_socket.c,v 1.1 2001/02/08 13:19:34 mrg 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) && !defined(_LKM)
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