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