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