1 /* $NetBSD: netbsd32_socket.c,v 1.19 2006/03/19 22:39:28 matt 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.19 2006/03/19 22:39:28 matt 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 lwp *, 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 iov = (struct iovec *)malloc( 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, 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(l, s, mp, iov, namelenp, retsize) 112 struct lwp *l; 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 struct proc *p; 126 #ifdef KTRACE 127 struct iovec *ktriov = NULL; 128 #endif 129 p = l->l_proc; 130 131 /* getsock() will use the descriptor for us */ 132 if ((error = getsock(p->p_fd, s, &fp)) != 0) 133 return (error); 134 auio.uio_iov = iov; 135 auio.uio_iovcnt = mp->msg_iovlen; 136 auio.uio_rw = UIO_READ; 137 auio.uio_vmspace = l->l_proc->p_vmspace; 138 auio.uio_offset = 0; /* XXX */ 139 auio.uio_resid = 0; 140 for (i = 0; i < mp->msg_iovlen; i++, iov++) { 141 #if 0 142 /* cannot happen iov_len is unsigned */ 143 if (iov->iov_len < 0) { 144 error = EINVAL; 145 goto out1; 146 } 147 #endif 148 /* 149 * Reads return ssize_t because -1 is returned on error. 150 * Therefore we must restrict the length to SSIZE_MAX to 151 * avoid garbage return values. 152 */ 153 auio.uio_resid += iov->iov_len; 154 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 155 error = EINVAL; 156 goto out1; 157 } 158 } 159 #ifdef KTRACE 160 if (KTRPOINT(p, KTR_GENIO)) { 161 int iovlen = auio.uio_iovcnt * sizeof(struct iovec); 162 163 ktriov = (struct iovec *)malloc(iovlen, M_TEMP, M_WAITOK); 164 memcpy((caddr_t)ktriov, (caddr_t)auio.uio_iov, iovlen); 165 } 166 #endif 167 len = auio.uio_resid; 168 so = (struct socket *)fp->f_data; 169 error = (*so->so_receive)(so, &from, &auio, NULL, 170 mp->msg_control ? &control : NULL, &mp->msg_flags); 171 if (error) { 172 if (auio.uio_resid != len && (error == ERESTART || 173 error == EINTR || error == EWOULDBLOCK)) 174 error = 0; 175 } 176 #ifdef KTRACE 177 if (ktriov != NULL) { 178 if (error == 0) 179 ktrgenio(l, s, UIO_READ, ktriov, 180 len - auio.uio_resid, error); 181 FREE(ktriov, M_TEMP); 182 } 183 #endif 184 if (error) 185 goto out; 186 *retsize = len - auio.uio_resid; 187 if (mp->msg_name) { 188 len = mp->msg_namelen; 189 if (len <= 0 || from == 0) 190 len = 0; 191 else { 192 if (len > from->m_len) 193 len = from->m_len; 194 /* else if len < from->m_len ??? */ 195 error = copyout(mtod(from, caddr_t), 196 (caddr_t)NETBSD32PTR64(mp->msg_name), 197 (unsigned)len); 198 if (error) 199 goto out; 200 } 201 mp->msg_namelen = len; 202 if (namelenp && 203 (error = copyout((caddr_t)&len, namelenp, sizeof(int)))) 204 goto out; 205 } 206 if (mp->msg_control) { 207 len = mp->msg_controllen; 208 if (len <= 0 || control == 0) 209 len = 0; 210 else { 211 struct mbuf *m = control; 212 caddr_t cp = (caddr_t)NETBSD32PTR64(mp->msg_control); 213 214 do { 215 i = m->m_len; 216 if (len < i) { 217 mp->msg_flags |= MSG_CTRUNC; 218 i = len; 219 } 220 error = copyout(mtod(m, caddr_t), cp, 221 (unsigned)i); 222 if (m->m_next) 223 i = ALIGN(i); 224 cp += i; 225 len -= i; 226 if (error != 0 || len <= 0) 227 break; 228 } while ((m = m->m_next) != NULL); 229 len = cp - (caddr_t)NETBSD32PTR64(mp->msg_control); 230 } 231 mp->msg_controllen = len; 232 } 233 out: 234 if (from) 235 m_freem(from); 236 if (control) 237 m_freem(control); 238 out1: 239 FILE_UNUSE(fp, l); 240 return (error); 241 } 242 243 int 244 netbsd32_sendmsg(l, v, retval) 245 struct lwp *l; 246 void *v; 247 register_t *retval; 248 { 249 struct netbsd32_sendmsg_args /* { 250 syscallarg(int) s; 251 syscallarg(const netbsd32_msghdrp_t) msg; 252 syscallarg(int) flags; 253 } */ *uap = v; 254 struct msghdr msg; 255 struct netbsd32_msghdr msg32; 256 struct iovec aiov[UIO_SMALLIOV], *iov; 257 int error; 258 259 error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, msg)), (caddr_t)&msg32, 260 sizeof(msg32)); 261 if (error) 262 return (error); 263 netbsd32_to_msghdr(&msg32, &msg); 264 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) { 265 if ((u_int)msg.msg_iovlen > IOV_MAX) 266 return (EMSGSIZE); 267 iov = (struct iovec *)malloc( 268 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV, 269 M_WAITOK); 270 } else if ((u_int)msg.msg_iovlen > 0) 271 iov = aiov; 272 else 273 return (EMSGSIZE); 274 error = netbsd32_to_iovecin((struct netbsd32_iovec *)msg.msg_iov, 275 iov, msg.msg_iovlen); 276 if (error) 277 goto done; 278 msg.msg_iov = iov; 279 /* Luckily we can use this directly */ 280 error = sendit(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval); 281 done: 282 if (iov != aiov) 283 FREE(iov, M_IOV); 284 return (error); 285 } 286 287 int 288 netbsd32_recvfrom(l, v, retval) 289 struct lwp *l; 290 void *v; 291 register_t *retval; 292 { 293 struct netbsd32_recvfrom_args /* { 294 syscallarg(int) s; 295 syscallarg(netbsd32_voidp) buf; 296 syscallarg(netbsd32_size_t) len; 297 syscallarg(int) flags; 298 syscallarg(netbsd32_sockaddrp_t) from; 299 syscallarg(netbsd32_intp) fromlenaddr; 300 } */ *uap = v; 301 struct netbsd32_msghdr msg; 302 struct iovec aiov; 303 int error; 304 305 if (SCARG(uap, fromlenaddr)) { 306 error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, fromlenaddr)), 307 (caddr_t)&msg.msg_namelen, sizeof(msg.msg_namelen)); 308 if (error) 309 return (error); 310 } else 311 msg.msg_namelen = 0; 312 msg.msg_name = SCARG(uap, from); 313 msg.msg_iov = 0; /* ignored in recvit32(), uses iov */ 314 msg.msg_iovlen = 1; 315 aiov.iov_base = (caddr_t)NETBSD32PTR64(SCARG(uap, buf)); 316 aiov.iov_len = (u_long)SCARG(uap, len); 317 msg.msg_control = 0; 318 msg.msg_flags = SCARG(uap, flags); 319 return (recvit32(l, SCARG(uap, s), &msg, &aiov, 320 (caddr_t)NETBSD32PTR64(SCARG(uap, fromlenaddr)), retval)); 321 } 322 323 int 324 netbsd32_sendto(l, v, retval) 325 struct lwp *l; 326 void *v; 327 register_t *retval; 328 { 329 struct netbsd32_sendto_args /* { 330 syscallarg(int) s; 331 syscallarg(const netbsd32_voidp) buf; 332 syscallarg(netbsd32_size_t) len; 333 syscallarg(int) flags; 334 syscallarg(const netbsd32_sockaddrp_t) to; 335 syscallarg(int) tolen; 336 } */ *uap = v; 337 struct msghdr msg; 338 struct iovec aiov; 339 340 msg.msg_name = (caddr_t)NETBSD32PTR64(SCARG(uap, to)); /* XXX kills const */ 341 msg.msg_namelen = SCARG(uap, tolen); 342 msg.msg_iov = &aiov; 343 msg.msg_iovlen = 1; 344 msg.msg_control = 0; 345 aiov.iov_base = (char *)NETBSD32PTR64(SCARG(uap, buf)); /* XXX kills const */ 346 aiov.iov_len = SCARG(uap, len); 347 return (sendit(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval)); 348 } 349