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