1 /* $NetBSD: netbsd32_socket.c,v 1.1 2001/02/08 13:19:34 mrg 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) && !defined(_LKM) 32 #include "opt_ktrace.h" 33 #endif 34 35 /* 36 * Though COMPAT_OLDSOCK is needed only for COMPAT_43, SunOS, Linux, 37 * HP-UX, FreeBSD, Ultrix, OSF1, we define it unconditionally so that 38 * this would be LKM-safe. 39 */ 40 #define COMPAT_OLDSOCK /* used by <sys/socket.h> */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #define msg __msg /* Don't ask me! */ 45 #include <sys/malloc.h> 46 #include <sys/mount.h> 47 #include <sys/socket.h> 48 #include <sys/sockio.h> 49 #include <sys/socketvar.h> 50 #include <sys/mbuf.h> 51 #include <sys/ktrace.h> 52 #include <sys/file.h> 53 #include <sys/filedesc.h> 54 #include <sys/syscallargs.h> 55 #include <sys/proc.h> 56 57 #include <compat/netbsd32/netbsd32.h> 58 #include <compat/netbsd32/netbsd32_syscallargs.h> 59 #include <compat/netbsd32/netbsd32_conv.h> 60 61 /* note that the netbsd32_msghdr's iov really points to a struct iovec, not a netbsd32_iovec. */ 62 static int recvit32 __P((struct proc *, int, struct netbsd32_msghdr *, struct iovec *, caddr_t, 63 register_t *)); 64 65 int 66 netbsd32_recvmsg(p, v, retval) 67 struct proc *p; 68 void *v; 69 register_t *retval; 70 { 71 struct netbsd32_recvmsg_args /* { 72 syscallarg(int) s; 73 syscallarg(netbsd32_msghdrp_t) msg; 74 syscallarg(int) flags; 75 } */ *uap = v; 76 struct netbsd32_msghdr msg; 77 struct iovec aiov[UIO_SMALLIOV], *uiov, *iov; 78 int error; 79 80 error = copyin((caddr_t)(u_long)SCARG(uap, msg), (caddr_t)&msg, 81 sizeof(msg)); 82 /* netbsd32_msghdr needs the iov pre-allocated */ 83 if (error) 84 return (error); 85 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) { 86 if ((u_int)msg.msg_iovlen > IOV_MAX) 87 return (EMSGSIZE); 88 MALLOC(iov, struct iovec *, 89 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV, 90 M_WAITOK); 91 } else if ((u_int)msg.msg_iovlen > 0) 92 iov = aiov; 93 else 94 return (EMSGSIZE); 95 #ifdef COMPAT_OLDSOCK 96 msg.msg_flags = SCARG(uap, flags) &~ MSG_COMPAT; 97 #else 98 msg.msg_flags = SCARG(uap, flags); 99 #endif 100 uiov = (struct iovec *)(u_long)msg.msg_iov; 101 error = netbsd32_to_iovecin((struct netbsd32_iovec *)uiov, 102 iov, msg.msg_iovlen); 103 if (error) 104 goto done; 105 if ((error = recvit32(p, SCARG(uap, s), &msg, iov, (caddr_t)0, retval)) == 0) { 106 error = copyout((caddr_t)&msg, (caddr_t)(u_long)SCARG(uap, msg), 107 sizeof(msg)); 108 } 109 done: 110 if (iov != aiov) 111 FREE(iov, M_IOV); 112 return (error); 113 } 114 115 int 116 recvit32(p, s, mp, iov, namelenp, retsize) 117 struct proc *p; 118 int s; 119 struct netbsd32_msghdr *mp; 120 struct iovec *iov; 121 caddr_t namelenp; 122 register_t *retsize; 123 { 124 struct file *fp; 125 struct uio auio; 126 int i; 127 int len, error; 128 struct mbuf *from = 0, *control = 0; 129 struct socket *so; 130 #ifdef KTRACE 131 struct iovec *ktriov = NULL; 132 #endif 133 134 /* getsock() will use the descriptor for us */ 135 if ((error = getsock(p->p_fd, s, &fp)) != 0) 136 return (error); 137 auio.uio_iov = iov; 138 auio.uio_iovcnt = mp->msg_iovlen; 139 auio.uio_segflg = UIO_USERSPACE; 140 auio.uio_rw = UIO_READ; 141 auio.uio_procp = p; 142 auio.uio_offset = 0; /* XXX */ 143 auio.uio_resid = 0; 144 for (i = 0; i < mp->msg_iovlen; i++, iov++) { 145 #if 0 146 /* cannot happen iov_len is unsigned */ 147 if (iov->iov_len < 0) { 148 error = EINVAL; 149 goto out1; 150 } 151 #endif 152 /* 153 * Reads return ssize_t because -1 is returned on error. 154 * Therefore we must restrict the length to SSIZE_MAX to 155 * avoid garbage return values. 156 */ 157 auio.uio_resid += iov->iov_len; 158 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 159 error = EINVAL; 160 goto out1; 161 } 162 } 163 #ifdef KTRACE 164 if (KTRPOINT(p, KTR_GENIO)) { 165 int iovlen = auio.uio_iovcnt * sizeof(struct iovec); 166 167 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); 168 memcpy((caddr_t)ktriov, (caddr_t)auio.uio_iov, iovlen); 169 } 170 #endif 171 len = auio.uio_resid; 172 so = (struct socket *)fp->f_data; 173 error = (*so->so_receive)(so, &from, &auio, NULL, 174 mp->msg_control ? &control : NULL, &mp->msg_flags); 175 if (error) { 176 if (auio.uio_resid != len && (error == ERESTART || 177 error == EINTR || error == EWOULDBLOCK)) 178 error = 0; 179 } 180 #ifdef KTRACE 181 if (ktriov != NULL) { 182 if (error == 0) 183 ktrgenio(p, s, UIO_READ, ktriov, 184 len - auio.uio_resid, error); 185 FREE(ktriov, M_TEMP); 186 } 187 #endif 188 if (error) 189 goto out; 190 *retsize = len - auio.uio_resid; 191 if (mp->msg_name) { 192 len = mp->msg_namelen; 193 if (len <= 0 || from == 0) 194 len = 0; 195 else { 196 #ifdef COMPAT_OLDSOCK 197 if (mp->msg_flags & MSG_COMPAT) 198 mtod(from, struct osockaddr *)->sa_family = 199 mtod(from, struct sockaddr *)->sa_family; 200 #endif 201 if (len > from->m_len) 202 len = from->m_len; 203 /* else if len < from->m_len ??? */ 204 error = copyout(mtod(from, caddr_t), 205 (caddr_t)(u_long)mp->msg_name, (unsigned)len); 206 if (error) 207 goto out; 208 } 209 mp->msg_namelen = len; 210 if (namelenp && 211 (error = copyout((caddr_t)&len, namelenp, sizeof(int)))) { 212 #ifdef COMPAT_OLDSOCK 213 if (mp->msg_flags & MSG_COMPAT) 214 error = 0; /* old recvfrom didn't check */ 215 else 216 #endif 217 goto out; 218 } 219 } 220 if (mp->msg_control) { 221 #ifdef COMPAT_OLDSOCK 222 /* 223 * We assume that old recvmsg calls won't receive access 224 * rights and other control info, esp. as control info 225 * is always optional and those options didn't exist in 4.3. 226 * If we receive rights, trim the cmsghdr; anything else 227 * is tossed. 228 */ 229 if (control && mp->msg_flags & MSG_COMPAT) { 230 if (mtod(control, struct cmsghdr *)->cmsg_level != 231 SOL_SOCKET || 232 mtod(control, struct cmsghdr *)->cmsg_type != 233 SCM_RIGHTS) { 234 mp->msg_controllen = 0; 235 goto out; 236 } 237 control->m_len -= sizeof(struct cmsghdr); 238 control->m_data += sizeof(struct cmsghdr); 239 } 240 #endif 241 len = mp->msg_controllen; 242 if (len <= 0 || control == 0) 243 len = 0; 244 else { 245 struct mbuf *m = control; 246 caddr_t p = (caddr_t)(u_long)mp->msg_control; 247 248 do { 249 i = m->m_len; 250 if (len < i) { 251 mp->msg_flags |= MSG_CTRUNC; 252 i = len; 253 } 254 error = copyout(mtod(m, caddr_t), p, 255 (unsigned)i); 256 if (m->m_next) 257 i = ALIGN(i); 258 p += i; 259 len -= i; 260 if (error != 0 || len <= 0) 261 break; 262 } while ((m = m->m_next) != NULL); 263 len = p - (caddr_t)(u_long)mp->msg_control; 264 } 265 mp->msg_controllen = len; 266 } 267 out: 268 if (from) 269 m_freem(from); 270 if (control) 271 m_freem(control); 272 out1: 273 FILE_UNUSE(fp, p); 274 return (error); 275 } 276 277 int 278 netbsd32_sendmsg(p, v, retval) 279 struct proc *p; 280 void *v; 281 register_t *retval; 282 { 283 struct netbsd32_sendmsg_args /* { 284 syscallarg(int) s; 285 syscallarg(const netbsd32_msghdrp_t) msg; 286 syscallarg(int) flags; 287 } */ *uap = v; 288 struct msghdr msg; 289 struct netbsd32_msghdr msg32; 290 struct iovec aiov[UIO_SMALLIOV], *iov; 291 int error; 292 293 error = copyin((caddr_t)(u_long)SCARG(uap, msg), 294 (caddr_t)&msg32, sizeof(msg32)); 295 if (error) 296 return (error); 297 netbsd32_to_msghdr(&msg32, &msg); 298 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) { 299 if ((u_int)msg.msg_iovlen > IOV_MAX) 300 return (EMSGSIZE); 301 MALLOC(iov, struct iovec *, 302 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV, 303 M_WAITOK); 304 } else if ((u_int)msg.msg_iovlen > 0) 305 iov = aiov; 306 else 307 return (EMSGSIZE); 308 error = netbsd32_to_iovecin((struct netbsd32_iovec *)msg.msg_iov, 309 iov, msg.msg_iovlen); 310 if (error) 311 goto done; 312 msg.msg_iov = iov; 313 #ifdef COMPAT_OLDSOCK 314 msg.msg_flags = 0; 315 #endif 316 /* Luckily we can use this directly */ 317 error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval); 318 done: 319 if (iov != aiov) 320 FREE(iov, M_IOV); 321 return (error); 322 } 323 324 int 325 netbsd32_recvfrom(p, v, retval) 326 struct proc *p; 327 void *v; 328 register_t *retval; 329 { 330 struct netbsd32_recvfrom_args /* { 331 syscallarg(int) s; 332 syscallarg(netbsd32_voidp) buf; 333 syscallarg(netbsd32_size_t) len; 334 syscallarg(int) flags; 335 syscallarg(netbsd32_sockaddrp_t) from; 336 syscallarg(netbsd32_intp) fromlenaddr; 337 } */ *uap = v; 338 struct netbsd32_msghdr msg; 339 struct iovec aiov; 340 int error; 341 342 if (SCARG(uap, fromlenaddr)) { 343 error = copyin((caddr_t)(u_long)SCARG(uap, fromlenaddr), 344 (caddr_t)&msg.msg_namelen, 345 sizeof(msg.msg_namelen)); 346 if (error) 347 return (error); 348 } else 349 msg.msg_namelen = 0; 350 msg.msg_name = SCARG(uap, from); 351 msg.msg_iov = NULL; /* ignored in recvit32(), uses iov */ 352 msg.msg_iovlen = 1; 353 aiov.iov_base = (caddr_t)(u_long)SCARG(uap, buf); 354 aiov.iov_len = (u_long)SCARG(uap, len); 355 msg.msg_control = 0; 356 msg.msg_flags = SCARG(uap, flags); 357 return (recvit32(p, SCARG(uap, s), &msg, &aiov, 358 (caddr_t)(u_long)SCARG(uap, fromlenaddr), retval)); 359 } 360 361 int 362 netbsd32_sendto(p, v, retval) 363 struct proc *p; 364 void *v; 365 register_t *retval; 366 { 367 struct netbsd32_sendto_args /* { 368 syscallarg(int) s; 369 syscallarg(const netbsd32_voidp) buf; 370 syscallarg(netbsd32_size_t) len; 371 syscallarg(int) flags; 372 syscallarg(const netbsd32_sockaddrp_t) to; 373 syscallarg(int) tolen; 374 } */ *uap = v; 375 struct msghdr msg; 376 struct iovec aiov; 377 378 msg.msg_name = (caddr_t)(u_long)SCARG(uap, to); /* XXX kills const */ 379 msg.msg_namelen = SCARG(uap, tolen); 380 msg.msg_iov = &aiov; 381 msg.msg_iovlen = 1; 382 msg.msg_control = 0; 383 #ifdef COMPAT_OLDSOCK 384 msg.msg_flags = 0; 385 #endif 386 aiov.iov_base = (char *)(u_long)SCARG(uap, buf); /* XXX kills const */ 387 aiov.iov_len = SCARG(uap, len); 388 return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval)); 389 } 390