1 /* $NetBSD: netbsd32_socket.c,v 1.15 2005/08/19 04:24:38 christos 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 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: netbsd32_socket.c,v 1.15 2005/08/19 04:24:38 christos Exp $"); 33 34 #if defined(_KERNEL_OPT) 35 #include "opt_ktrace.h" 36 #endif 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #define msg __msg /* Don't ask me! */ 41 #include <sys/malloc.h> 42 #include <sys/mount.h> 43 #include <sys/socket.h> 44 #include <sys/sockio.h> 45 #include <sys/socketvar.h> 46 #include <sys/mbuf.h> 47 #include <sys/ktrace.h> 48 #include <sys/file.h> 49 #include <sys/filedesc.h> 50 #include <sys/sa.h> 51 #include <sys/syscallargs.h> 52 #include <sys/proc.h> 53 #include <sys/dirent.h> 54 55 #include <compat/netbsd32/netbsd32.h> 56 #include <compat/netbsd32/netbsd32_syscallargs.h> 57 #include <compat/netbsd32/netbsd32_conv.h> 58 59 /* note that the netbsd32_msghdr's iov really points to a struct iovec, not a netbsd32_iovec. */ 60 static int recvit32 __P((struct proc *, int, struct netbsd32_msghdr *, struct iovec *, caddr_t, 61 register_t *)); 62 63 int 64 netbsd32_recvmsg(l, v, retval) 65 struct lwp *l; 66 void *v; 67 register_t *retval; 68 { 69 struct netbsd32_recvmsg_args /* { 70 syscallarg(int) s; 71 syscallarg(netbsd32_msghdrp_t) msg; 72 syscallarg(int) flags; 73 } */ *uap = v; 74 struct netbsd32_msghdr msg; 75 struct iovec aiov[UIO_SMALLIOV], *uiov, *iov; 76 int error; 77 78 error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, msg)), (caddr_t)&msg, 79 sizeof(msg)); 80 /* netbsd32_msghdr needs the iov pre-allocated */ 81 if (error) 82 return (error); 83 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) { 84 if ((u_int)msg.msg_iovlen > IOV_MAX) 85 return (EMSGSIZE); 86 MALLOC(iov, struct iovec *, 87 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV, 88 M_WAITOK); 89 } else if ((u_int)msg.msg_iovlen > 0) 90 iov = aiov; 91 else 92 return (EMSGSIZE); 93 msg.msg_flags = SCARG(uap, flags); 94 uiov = (struct iovec *)NETBSD32PTR64(msg.msg_iov); 95 error = netbsd32_to_iovecin((struct netbsd32_iovec *)uiov, 96 iov, msg.msg_iovlen); 97 if (error) 98 goto done; 99 if ((error = recvit32(l->l_proc, SCARG(uap, s), &msg, iov, (caddr_t)0, 100 retval)) == 0) { 101 error = copyout((caddr_t)&msg, 102 (caddr_t)NETBSD32PTR64(SCARG(uap, msg)), sizeof(msg)); 103 } 104 done: 105 if (iov != aiov) 106 FREE(iov, M_IOV); 107 return (error); 108 } 109 110 int 111 recvit32(p, s, mp, iov, namelenp, retsize) 112 struct proc *p; 113 int s; 114 struct netbsd32_msghdr *mp; 115 struct iovec *iov; 116 caddr_t namelenp; 117 register_t *retsize; 118 { 119 struct file *fp; 120 struct uio auio; 121 int i; 122 int len, error; 123 struct mbuf *from = 0, *control = 0; 124 struct socket *so; 125 #ifdef KTRACE 126 struct iovec *ktriov = NULL; 127 #endif 128 129 /* getsock() will use the descriptor for us */ 130 if ((error = getsock(p->p_fd, s, &fp)) != 0) 131 return (error); 132 auio.uio_iov = iov; 133 auio.uio_iovcnt = mp->msg_iovlen; 134 auio.uio_segflg = UIO_USERSPACE; 135 auio.uio_rw = UIO_READ; 136 auio.uio_procp = p; 137 auio.uio_offset = 0; /* XXX */ 138 auio.uio_resid = 0; 139 for (i = 0; i < mp->msg_iovlen; i++, iov++) { 140 #if 0 141 /* cannot happen iov_len is unsigned */ 142 if (iov->iov_len < 0) { 143 error = EINVAL; 144 goto out1; 145 } 146 #endif 147 /* 148 * Reads return ssize_t because -1 is returned on error. 149 * Therefore we must restrict the length to SSIZE_MAX to 150 * avoid garbage return values. 151 */ 152 auio.uio_resid += iov->iov_len; 153 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 154 error = EINVAL; 155 goto out1; 156 } 157 } 158 #ifdef KTRACE 159 if (KTRPOINT(p, KTR_GENIO)) { 160 int iovlen = auio.uio_iovcnt * sizeof(struct iovec); 161 162 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); 163 memcpy((caddr_t)ktriov, (caddr_t)auio.uio_iov, iovlen); 164 } 165 #endif 166 len = auio.uio_resid; 167 so = (struct socket *)fp->f_data; 168 error = (*so->so_receive)(so, &from, &auio, NULL, 169 mp->msg_control ? &control : NULL, &mp->msg_flags); 170 if (error) { 171 if (auio.uio_resid != len && (error == ERESTART || 172 error == EINTR || error == EWOULDBLOCK)) 173 error = 0; 174 } 175 #ifdef KTRACE 176 if (ktriov != NULL) { 177 if (error == 0) 178 ktrgenio(p, s, UIO_READ, ktriov, 179 len - auio.uio_resid, error); 180 FREE(ktriov, M_TEMP); 181 } 182 #endif 183 if (error) 184 goto out; 185 *retsize = len - auio.uio_resid; 186 if (mp->msg_name) { 187 len = mp->msg_namelen; 188 if (len <= 0 || from == 0) 189 len = 0; 190 else { 191 if (len > from->m_len) 192 len = from->m_len; 193 /* else if len < from->m_len ??? */ 194 error = copyout(mtod(from, caddr_t), 195 (caddr_t)NETBSD32PTR64(mp->msg_name), 196 (unsigned)len); 197 if (error) 198 goto out; 199 } 200 mp->msg_namelen = len; 201 if (namelenp && 202 (error = copyout((caddr_t)&len, namelenp, sizeof(int)))) 203 goto out; 204 } 205 if (mp->msg_control) { 206 len = mp->msg_controllen; 207 if (len <= 0 || control == 0) 208 len = 0; 209 else { 210 struct mbuf *m = control; 211 caddr_t cp = (caddr_t)NETBSD32PTR64(mp->msg_control); 212 213 do { 214 i = m->m_len; 215 if (len < i) { 216 mp->msg_flags |= MSG_CTRUNC; 217 i = len; 218 } 219 error = copyout(mtod(m, caddr_t), cp, 220 (unsigned)i); 221 if (m->m_next) 222 i = ALIGN(i); 223 cp += i; 224 len -= i; 225 if (error != 0 || len <= 0) 226 break; 227 } while ((m = m->m_next) != NULL); 228 len = cp - (caddr_t)NETBSD32PTR64(mp->msg_control); 229 } 230 mp->msg_controllen = len; 231 } 232 out: 233 if (from) 234 m_freem(from); 235 if (control) 236 m_freem(control); 237 out1: 238 FILE_UNUSE(fp, p); 239 return (error); 240 } 241 242 int 243 netbsd32_sendmsg(l, v, retval) 244 struct lwp *l; 245 void *v; 246 register_t *retval; 247 { 248 struct netbsd32_sendmsg_args /* { 249 syscallarg(int) s; 250 syscallarg(const netbsd32_msghdrp_t) msg; 251 syscallarg(int) flags; 252 } */ *uap = v; 253 struct msghdr msg; 254 struct netbsd32_msghdr msg32; 255 struct iovec aiov[UIO_SMALLIOV], *iov; 256 int error; 257 258 error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, msg)), (caddr_t)&msg32, 259 sizeof(msg32)); 260 if (error) 261 return (error); 262 netbsd32_to_msghdr(&msg32, &msg); 263 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) { 264 if ((u_int)msg.msg_iovlen > IOV_MAX) 265 return (EMSGSIZE); 266 MALLOC(iov, struct iovec *, 267 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV, 268 M_WAITOK); 269 } else if ((u_int)msg.msg_iovlen > 0) 270 iov = aiov; 271 else 272 return (EMSGSIZE); 273 error = netbsd32_to_iovecin((struct netbsd32_iovec *)msg.msg_iov, 274 iov, msg.msg_iovlen); 275 if (error) 276 goto done; 277 msg.msg_iov = iov; 278 /* Luckily we can use this directly */ 279 error = sendit(l->l_proc, SCARG(uap, s), &msg, SCARG(uap, flags), retval); 280 done: 281 if (iov != aiov) 282 FREE(iov, M_IOV); 283 return (error); 284 } 285 286 int 287 netbsd32_recvfrom(l, v, retval) 288 struct lwp *l; 289 void *v; 290 register_t *retval; 291 { 292 struct netbsd32_recvfrom_args /* { 293 syscallarg(int) s; 294 syscallarg(netbsd32_voidp) buf; 295 syscallarg(netbsd32_size_t) len; 296 syscallarg(int) flags; 297 syscallarg(netbsd32_sockaddrp_t) from; 298 syscallarg(netbsd32_intp) fromlenaddr; 299 } */ *uap = v; 300 struct netbsd32_msghdr msg; 301 struct iovec aiov; 302 int error; 303 304 if (SCARG(uap, fromlenaddr)) { 305 error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, fromlenaddr)), 306 (caddr_t)&msg.msg_namelen, sizeof(msg.msg_namelen)); 307 if (error) 308 return (error); 309 } else 310 msg.msg_namelen = 0; 311 msg.msg_name = SCARG(uap, from); 312 msg.msg_iov = 0; /* ignored in recvit32(), uses iov */ 313 msg.msg_iovlen = 1; 314 aiov.iov_base = (caddr_t)NETBSD32PTR64(SCARG(uap, buf)); 315 aiov.iov_len = (u_long)SCARG(uap, len); 316 msg.msg_control = 0; 317 msg.msg_flags = SCARG(uap, flags); 318 return (recvit32(l->l_proc, SCARG(uap, s), &msg, &aiov, 319 (caddr_t)NETBSD32PTR64(SCARG(uap, fromlenaddr)), retval)); 320 } 321 322 int 323 netbsd32_sendto(l, v, retval) 324 struct lwp *l; 325 void *v; 326 register_t *retval; 327 { 328 struct netbsd32_sendto_args /* { 329 syscallarg(int) s; 330 syscallarg(const netbsd32_voidp) buf; 331 syscallarg(netbsd32_size_t) len; 332 syscallarg(int) flags; 333 syscallarg(const netbsd32_sockaddrp_t) to; 334 syscallarg(int) tolen; 335 } */ *uap = v; 336 struct msghdr msg; 337 struct iovec aiov; 338 339 msg.msg_name = (caddr_t)NETBSD32PTR64(SCARG(uap, to)); /* XXX kills const */ 340 msg.msg_namelen = SCARG(uap, tolen); 341 msg.msg_iov = &aiov; 342 msg.msg_iovlen = 1; 343 msg.msg_control = 0; 344 aiov.iov_base = (char *)NETBSD32PTR64(SCARG(uap, buf)); /* XXX kills const */ 345 aiov.iov_len = SCARG(uap, len); 346 return (sendit(l->l_proc, SCARG(uap, s), &msg, SCARG(uap, flags), retval)); 347 } 348