1 /* $NetBSD: netbsd32_socket.c,v 1.37 2010/04/23 15:19:20 rmind 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: netbsd32_socket.c,v 1.37 2010/04/23 15:19:20 rmind Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #define msg __msg /* Don't ask me! */ 35 #include <sys/mount.h> 36 #include <sys/socket.h> 37 #include <sys/sockio.h> 38 #include <sys/socketvar.h> 39 #include <sys/mbuf.h> 40 #include <sys/ktrace.h> 41 #include <sys/file.h> 42 #include <sys/filedesc.h> 43 #include <sys/syscallargs.h> 44 #include <sys/proc.h> 45 #include <sys/dirent.h> 46 47 #include <compat/netbsd32/netbsd32.h> 48 #include <compat/netbsd32/netbsd32_syscallargs.h> 49 #include <compat/netbsd32/netbsd32_conv.h> 50 51 /* 52 * Note that the netbsd32_msghdr's iov really points to a struct iovec, 53 * not a netbsd32_iovec. 54 */ 55 static int recvit32(struct lwp *, int, struct netbsd32_msghdr *, 56 struct iovec *, void *, register_t *); 57 58 int 59 netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap, register_t *retval) 60 { 61 /* { 62 syscallarg(int) s; 63 syscallarg(netbsd32_msghdrp_t) msg; 64 syscallarg(int) flags; 65 } */ 66 struct netbsd32_msghdr msg; 67 struct iovec aiov[UIO_SMALLIOV], *iov; 68 struct netbsd32_iovec *iov32; 69 size_t iovsz; 70 int error; 71 72 error = copyin(SCARG_P32(uap, msg), &msg, sizeof(msg)); 73 /* netbsd32_msghdr needs the iov pre-allocated */ 74 if (error) 75 return (error); 76 iovsz = msg.msg_iovlen * sizeof(struct iovec); 77 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) { 78 if ((u_int)msg.msg_iovlen > IOV_MAX) 79 return (EMSGSIZE); 80 iov = kmem_alloc(iovsz, KM_SLEEP); 81 } else 82 iov = aiov; 83 msg.msg_flags = SCARG(uap, flags); 84 iov32 = NETBSD32PTR64(msg.msg_iov); 85 error = netbsd32_to_iovecin(iov32, iov, msg.msg_iovlen); 86 if (error) 87 goto done; 88 if ((error = recvit32(l, SCARG(uap, s), &msg, iov, (void *)0, 89 retval)) == 0) { 90 error = copyout(&msg, SCARG_P32(uap, msg), sizeof(msg)); 91 } 92 done: 93 if (iov != aiov) 94 kmem_free(iov, iovsz); 95 return (error); 96 } 97 98 int 99 recvit32(struct lwp *l, int s, struct netbsd32_msghdr *mp, struct iovec *iov, void *namelenp, register_t *retsize) 100 { 101 struct uio auio; 102 struct mbuf *from = 0, *control = 0; 103 struct socket *so; 104 struct iovec *ktriov = NULL; 105 size_t len, iovsz; 106 int i, error; 107 108 /* fd_getsock() will use the descriptor for us */ 109 if ((error = fd_getsock(s, &so)) != 0) 110 return (error); 111 auio.uio_iov = iov; 112 auio.uio_iovcnt = mp->msg_iovlen; 113 auio.uio_rw = UIO_READ; 114 auio.uio_vmspace = l->l_proc->p_vmspace; 115 auio.uio_offset = 0; /* XXX */ 116 auio.uio_resid = 0; 117 for (i = 0; i < mp->msg_iovlen; i++, iov++) { 118 /* 119 * Reads return ssize_t because -1 is returned on error. 120 * Therefore we must restrict the length to SSIZE_MAX to 121 * avoid garbage return values. 122 */ 123 auio.uio_resid += iov->iov_len; 124 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 125 error = EINVAL; 126 goto out1; 127 } 128 } 129 130 iovsz = mp->msg_iovlen * sizeof(struct iovec); 131 if (ktrpoint(KTR_GENIO)) { 132 ktriov = kmem_alloc(iovsz, KM_SLEEP); 133 memcpy(ktriov, auio.uio_iov, iovsz); 134 } 135 136 len = auio.uio_resid; 137 error = (*so->so_receive)(so, &from, &auio, NULL, 138 NETBSD32PTR64(mp->msg_control) ? &control : NULL, 139 &mp->msg_flags); 140 if (error) { 141 if (auio.uio_resid != len && (error == ERESTART || 142 error == EINTR || error == EWOULDBLOCK)) 143 error = 0; 144 } 145 146 if (ktriov != NULL) { 147 ktrgeniov(s, UIO_READ, ktriov, len - auio.uio_resid, error); 148 kmem_free(ktriov, iovsz); 149 } 150 151 if (error) 152 goto out; 153 *retsize = len - auio.uio_resid; 154 if (NETBSD32PTR64(mp->msg_name)) { 155 len = mp->msg_namelen; 156 if (len <= 0 || from == 0) 157 len = 0; 158 else { 159 if (len > from->m_len) 160 len = from->m_len; 161 /* else if len < from->m_len ??? */ 162 error = copyout(mtod(from, void *), 163 (void *)NETBSD32PTR64(mp->msg_name), 164 (unsigned)len); 165 if (error) 166 goto out; 167 } 168 mp->msg_namelen = len; 169 if (namelenp && 170 (error = copyout((void *)&len, namelenp, sizeof(int)))) 171 goto out; 172 } 173 if (NETBSD32PTR64(mp->msg_control)) { 174 len = mp->msg_controllen; 175 if (len <= 0 || control == 0) 176 len = 0; 177 else { 178 struct mbuf *m = control; 179 void *cp = (void *)NETBSD32PTR64(mp->msg_control); 180 181 do { 182 i = m->m_len; 183 if (len < i) { 184 mp->msg_flags |= MSG_CTRUNC; 185 i = len; 186 } 187 error = copyout(mtod(m, void *), cp, 188 (unsigned)i); 189 if (m->m_next) 190 i = ALIGN(i); 191 cp = (char *)cp + i; 192 len -= i; 193 if (error != 0 || len <= 0) 194 break; 195 } while ((m = m->m_next) != NULL); 196 len = (char *)cp - (char *)NETBSD32PTR64(mp->msg_control); 197 } 198 mp->msg_controllen = len; 199 } 200 out: 201 if (from) 202 m_freem(from); 203 if (control) 204 m_freem(control); 205 out1: 206 fd_putfile(s); 207 return (error); 208 } 209 210 int 211 netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap, register_t *retval) 212 { 213 /* { 214 syscallarg(int) s; 215 syscallarg(const netbsd32_msghdrp_t) msg; 216 syscallarg(int) flags; 217 } */ 218 struct msghdr msg; 219 struct netbsd32_msghdr msg32; 220 struct iovec aiov[UIO_SMALLIOV], *iov; 221 struct netbsd32_iovec *iov32; 222 size_t iovsz; 223 int error; 224 225 error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32)); 226 if (error) 227 return (error); 228 netbsd32_to_msghdr(&msg32, &msg); 229 230 iovsz = msg.msg_iovlen * sizeof(struct iovec); 231 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) { 232 if ((u_int)msg.msg_iovlen > IOV_MAX) 233 return (EMSGSIZE); 234 iov = kmem_alloc(iovsz, KM_SLEEP); 235 } else 236 iov = aiov; 237 238 iov32 = NETBSD32PTR64(msg32.msg_iov); 239 error = netbsd32_to_iovecin(iov32, iov, msg.msg_iovlen); 240 if (error) 241 goto done; 242 msg.msg_iov = iov; 243 msg.msg_flags = 0; 244 245 /* Luckily we can use this directly */ 246 /* XXX: dsl (June'07) The cmsg alignment rules differ ! */ 247 error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval); 248 done: 249 if (iov != aiov) 250 kmem_free(iov, iovsz); 251 return (error); 252 } 253 254 int 255 netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap, register_t *retval) 256 { 257 /* { 258 syscallarg(int) s; 259 syscallarg(netbsd32_voidp) buf; 260 syscallarg(netbsd32_size_t) len; 261 syscallarg(int) flags; 262 syscallarg(netbsd32_sockaddrp_t) from; 263 syscallarg(netbsd32_intp) fromlenaddr; 264 } */ 265 struct netbsd32_msghdr msg; 266 struct iovec aiov; 267 int error; 268 269 if (SCARG_P32(uap, fromlenaddr)) { 270 error = copyin(SCARG_P32(uap, fromlenaddr), 271 &msg.msg_namelen, sizeof(msg.msg_namelen)); 272 if (error) 273 return (error); 274 } else 275 msg.msg_namelen = 0; 276 msg.msg_name = SCARG(uap, from); 277 NETBSD32PTR32(msg.msg_iov, 0); /* ignored in recvit32(), uses iov */ 278 msg.msg_iovlen = 1; 279 aiov.iov_base = SCARG_P32(uap, buf); 280 aiov.iov_len = (u_long)SCARG(uap, len); 281 NETBSD32PTR32(msg.msg_control, 0); 282 msg.msg_flags = SCARG(uap, flags); 283 return (recvit32(l, SCARG(uap, s), &msg, &aiov, 284 SCARG_P32(uap, fromlenaddr), retval)); 285 } 286 287 int 288 netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap, register_t *retval) 289 { 290 /* { 291 syscallarg(int) s; 292 syscallarg(const netbsd32_voidp) buf; 293 syscallarg(netbsd32_size_t) len; 294 syscallarg(int) flags; 295 syscallarg(const netbsd32_sockaddrp_t) to; 296 syscallarg(int) tolen; 297 } */ 298 struct msghdr msg; 299 struct iovec aiov; 300 301 msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */ 302 msg.msg_namelen = SCARG(uap, tolen); 303 msg.msg_iov = &aiov; 304 msg.msg_iovlen = 1; 305 msg.msg_control = 0; 306 aiov.iov_base = SCARG_P32(uap, buf); /* XXX kills const */ 307 aiov.iov_len = SCARG(uap, len); 308 msg.msg_flags = 0; 309 return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval); 310 } 311