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