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