socksyscalls.c revision 7f9e9054de030261b1a0e55ae05c5d8682590697
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * CDDL HEADER START
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The contents of this file are subject to the terms of the
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * Common Development and Distribution License (the "License").
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * You may not use this file except in compliance with the License.
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
fa9e4066f08beec538e775443c5be79dd423fcabahrens * or http://www.opensolaris.org/os/licensing.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * See the License for the specific language governing permissions
fa9e4066f08beec538e775443c5be79dd423fcabahrens * and limitations under the License.
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * When distributing Covered Code, include this CDDL HEADER in each
fa9e4066f08beec538e775443c5be79dd423fcabahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If applicable, add the following below this CDDL HEADER, with the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * fields enclosed by brackets "[]" replaced with your own identifying
fa9e4066f08beec538e775443c5be79dd423fcabahrens * information: Portions Copyright [yyyy] [name of copyright owner]
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * CDDL HEADER END
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens
8d18220deb04ec7b12410cd90deb4d45e66d49bfMark J Musante/*
daec38ecb4fb5e73e4ca9e99be84f6b8c50c02faJoe Stein * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
9dc3941c735ef88de46e850f745aa556d3a071a5Sašo Kiselkov * Use is subject to license terms.
c3d26abc9ee97b4f60233556aadeb57e0bd30bb9Matthew Ahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/types.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/t_lock.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/param.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/systm.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/buf.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/conf.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/cred.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/kmem.h>
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson#include <sys/sysmacros.h>
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson#include <sys/vfs.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/vnode.h>
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson#include <sys/debug.h>
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson#include <sys/errno.h>
09c9d376e8ccb8fbba74f33cc268964464092b62George Wilson#include <sys/time.h>
13506d1eefbbc37e2f12a0528831d9f6d4c361d7maybee#include <sys/file.h>
e05725b117836db173257fae43fb0746eb857fb5bonwick#include <sys/user.h>
13506d1eefbbc37e2f12a0528831d9f6d4c361d7maybee#include <sys/stream.h>
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson#include <sys/strsubr.h>
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson#include <sys/strsun.h>
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson#include <sys/sunddi.h>
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson#include <sys/esunddi.h>
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson#include <sys/flock.h>
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson#include <sys/modctl.h>
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson#include <sys/cmn_err.h>
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson#include <sys/vmsystm.h>
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece#include <sys/policy.h>
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece#include <sys/socket.h>
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens#include <sys/socketvar.h>
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece#include <sys/isa_defs.h>
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece#include <sys/inttypes.h>
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece#include <sys/systm.h>
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece#include <sys/cpuvar.h>
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece#include <sys/filio.h>
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece#include <sys/sendfile.h>
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece#include <sys/ddi.h>
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece#include <vm/seg.h>
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece#include <vm/seg_map.h>
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece#include <vm/seg_kpm.h>
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
22e30981d82a0b6dc89253596ededafae8655e00George Wilson#include <fs/sockfs/nl7c.h>
22e30981d82a0b6dc89253596ededafae8655e00George Wilson#include <fs/sockfs/sockcommon.h>
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson#include <fs/sockfs/socktpi.h>
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
22e30981d82a0b6dc89253596ededafae8655e00George Wilson#ifdef SOCK_TEST
22e30981d82a0b6dc89253596ededafae8655e00George Wilsonint do_useracc = 1; /* Controlled by setting SO_DEBUG to 4 */
22e30981d82a0b6dc89253596ededafae8655e00George Wilson#else
22e30981d82a0b6dc89253596ededafae8655e00George Wilson#define do_useracc 1
22e30981d82a0b6dc89253596ededafae8655e00George Wilson#endif /* SOCK_TEST */
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
22e30981d82a0b6dc89253596ededafae8655e00George Wilsonextern int xnet_truncate_print;
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
22e30981d82a0b6dc89253596ededafae8655e00George Wilson/*
09c9d376e8ccb8fbba74f33cc268964464092b62George Wilson * Note: DEF_IOV_MAX is defined and used as it is in "fs/vncalls.c"
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * as there isn't a formal definition of IOV_MAX ???
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson#define MSG_MAXIOVLEN 16
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson/*
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * Kernel component of socket creation.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson *
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * The socket library determines which version number to use.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * First the library calls this with a NULL devpath. If this fails
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * to find a transport (using solookup) the library will look in /etc/netconfig
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * for the appropriate transport. If one is found it will pass in the
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * devpath for the kernel to use.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonint
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonso_socket(int family, int type, int protocol, char *devpath, int version)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson{
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson struct sonode *so;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick vnode_t *vp;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson struct file *fp;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick int fd;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson int error;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (devpath != NULL) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson char *buf;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson size_t kdevpathlen = 0;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson if ((error = copyinstr(devpath, buf,
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson MAXPATHLEN, &kdevpathlen)) != 0) {
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson kmem_free(buf, MAXPATHLEN);
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson return (set_errno(error));
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson }
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson so = socket_create(family, type, protocol, buf, NULL,
b515258426fed6c7311fd3f1dea697cfbd4085c6Matthew Ahrens SOCKET_SLEEP, version, CRED(), &error);
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson kmem_free(buf, MAXPATHLEN);
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson } else {
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson so = socket_create(family, type, protocol, NULL, NULL,
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson SOCKET_SLEEP, version, CRED(), &error);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson if (so == NULL)
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson return (set_errno(error));
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson /* Allocate a file descriptor for the socket */
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson vp = SOTOV(so);
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson if (error = falloc(vp, FWRITE|FREAD, &fp, &fd)) {
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson (void) socket_close(so, 0, CRED());
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson socket_destroy(so);
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson return (set_errno(error));
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson }
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /*
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson * Now fill in the entries that falloc reserved
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson mutex_exit(&fp->f_tlock);
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson setf(fd, fp);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (fd);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson}
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson/*
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson * Map from a file descriptor to a socket node.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * Returns with the file descriptor held i.e. the caller has to
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * use releasef when done with the file descriptor.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsonstruct sonode *
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsongetsonode(int sock, int *errorp, file_t **fpp)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson{
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson file_t *fp;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson vnode_t *vp;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson struct sonode *so;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if ((fp = getf(sock)) == NULL) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson *errorp = EBADF;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson eprintline(*errorp);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (NULL);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson vp = fp->f_vnode;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /* Check if it is a socket */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (vp->v_type != VSOCK) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson releasef(sock);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson *errorp = ENOTSOCK;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson eprintline(*errorp);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (NULL);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /*
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * Use the stream head to find the real socket vnode.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * This is needed when namefs sits above sockfs.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (vp->v_stream) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson ASSERT(vp->v_stream->sd_vnode);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson vp = vp->v_stream->sd_vnode;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson so = VTOSO(vp);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (so->so_version == SOV_STREAM) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson releasef(sock);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *errorp = ENOTSOCK;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson eprintsoline(so, *errorp);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson return (NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson } else {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson so = VTOSO(vp);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (fpp)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *fpp = fp;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson return (so);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson}
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson/*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Allocate and copyin a sockaddr.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Ensures NULL termination for AF_UNIX addresses by extending them
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * with one NULL byte if need be. Verifies that the length is not
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * excessive to prevent an application from consuming all of kernel
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * memory. Returns NULL when an error occurred.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonstatic struct sockaddr *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsoncopyin_name(struct sonode *so, struct sockaddr *name, socklen_t *namelenp,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson int *errorp)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson{
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson char *faddr;
fa9e4066f08beec538e775443c5be79dd423fcabahrens size_t namelen = (size_t)*namelenp;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens ASSERT(namelen != 0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (namelen > SO_MAXARGSIZE) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens *errorp = EINVAL;
fa9e4066f08beec538e775443c5be79dd423fcabahrens eprintsoline(so, *errorp);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (NULL);
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens faddr = (char *)kmem_alloc(namelen, KM_SLEEP);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (copyin(name, faddr, namelen)) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens kmem_free(faddr, namelen);
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson *errorp = EFAULT;
fa9e4066f08beec538e775443c5be79dd423fcabahrens eprintsoline(so, *errorp);
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson return (NULL);
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson }
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
fa9e4066f08beec538e775443c5be79dd423fcabahrens /*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Add space for NULL termination if needed.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Do a quick check if the last byte is NUL.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (so->so_family == AF_UNIX && faddr[namelen - 1] != '\0') {
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Check if there is any NULL termination */
fa9e4066f08beec538e775443c5be79dd423fcabahrens size_t i;
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick int foundnull = 0;
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick for (i = sizeof (name->sa_family); i < namelen; i++) {
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick if (faddr[i] == '\0') {
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick foundnull = 1;
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson }
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson }
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (!foundnull) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Add extra byte for NUL padding */
fa9e4066f08beec538e775443c5be79dd423fcabahrens char *nfaddr;
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson nfaddr = (char *)kmem_alloc(namelen + 1, KM_SLEEP);
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson bcopy(faddr, nfaddr, namelen);
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson kmem_free(faddr, namelen);
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson /* NUL terminate */
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson nfaddr[namelen] = '\0';
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson namelen++;
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson ASSERT((socklen_t)namelen == namelen);
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson *namelenp = (socklen_t)namelen;
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson faddr = nfaddr;
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson }
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson }
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson return ((struct sockaddr *)faddr);
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson}
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson/*
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson * Copy from kaddr/klen to uaddr/ulen. Updates ulenp if non-NULL.
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson */
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilsonstatic int
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilsoncopyout_arg(void *uaddr, socklen_t ulen, void *ulenp,
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson void *kaddr, socklen_t klen)
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson{
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson if (uaddr != NULL) {
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson if (ulen > klen)
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson ulen = klen;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (ulen != 0) {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (copyout(kaddr, uaddr, ulen))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick return (EFAULT);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick } else
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick ulen = 0;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (ulenp != NULL) {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (copyout(&ulen, ulenp, sizeof (ulen)))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick return (EFAULT);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick return (0);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick}
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/*
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * Copy from kaddr/klen to uaddr/ulen. Updates ulenp if non-NULL.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * If klen is greater than ulen it still uses the non-truncated
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * klen to update ulenp.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwickstatic int
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwickcopyout_name(void *uaddr, socklen_t ulen, void *ulenp,
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick void *kaddr, socklen_t klen)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick{
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (uaddr != NULL) {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (ulen >= klen)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick ulen = klen;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick else if (ulen != 0 && xnet_truncate_print) {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick printf("sockfs: truncating copyout of address using "
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick "XNET semantics for pid = %d. Lengths %d, %d\n",
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick curproc->p_pid, klen, ulen);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (ulen != 0) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (copyout(kaddr, uaddr, ulen))
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (EFAULT);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson } else
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson klen = 0;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson } else
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson klen = 0;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (ulenp != NULL) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (copyout(&klen, ulenp, sizeof (klen)))
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (EFAULT);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (0);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson}
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson/*
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * The socketpair() code in libsocket creates two sockets (using
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * the /etc/netconfig fallback if needed) before calling this routine
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * to connect the two sockets together.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson *
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * For a SOCK_STREAM socketpair a listener is needed - in that case this
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * routine will create a new file descriptor as part of accepting the
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * connection. The library socketpair() will check if svs[2] has changed
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * in which case it will close the changed fd.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson *
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * Note that this code could use the TPI feature of accepting the connection
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * on the listening endpoint. However, that would require significant changes
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * to soaccept.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonint
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonso_socketpair(int sv[2])
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson{
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson int svs[2];
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson struct sonode *so1, *so2;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson int error;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson struct sockaddr_ux *name;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson size_t namelen;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson sotpi_info_t *sti1;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson sotpi_info_t *sti2;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson dprint(1, ("so_socketpair(%p)\n", (void *)sv));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = useracc(sv, sizeof (svs), B_WRITE);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (error && do_useracc)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (set_errno(EFAULT));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (copyin(sv, svs, sizeof (svs)))
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (set_errno(EFAULT));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if ((so1 = getsonode(svs[0], &error, NULL)) == NULL)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (set_errno(error));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if ((so2 = getsonode(svs[1], &error, NULL)) == NULL) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson releasef(svs[0]);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (set_errno(error));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (so1->so_family != AF_UNIX || so2->so_family != AF_UNIX) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = EOPNOTSUPP;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson goto done;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson sti1 = SOTOTPI(so1);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson sti2 = SOTOTPI(so2);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /*
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * The code below makes assumptions about the "sockfs" implementation.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * So make sure that the correct implementation is really used.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson ASSERT(so1->so_ops == &sotpi_sonodeops);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson ASSERT(so2->so_ops == &sotpi_sonodeops);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (so1->so_type == SOCK_DGRAM) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /*
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * Bind both sockets and connect them with each other.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * Need to allocate name/namelen for soconnect.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = socket_bind(so1, NULL, 0, _SOBIND_UNSPEC, CRED());
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (error) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson eprintsoline(so1, error);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson goto done;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = socket_bind(so2, NULL, 0, _SOBIND_UNSPEC, CRED());
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (error) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson eprintsoline(so2, error);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson goto done;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson namelen = sizeof (struct sockaddr_ux);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson name = kmem_alloc(namelen, KM_SLEEP);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson name->sou_family = AF_UNIX;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson name->sou_addr = sti2->sti_ux_laddr;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = socket_connect(so1,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson (struct sockaddr *)name,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson (socklen_t)namelen,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson 0, _SOCONNECT_NOXLATE, CRED());
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (error) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kmem_free(name, namelen);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson eprintsoline(so1, error);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson goto done;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson name->sou_addr = sti1->sti_ux_laddr;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = socket_connect(so2,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson (struct sockaddr *)name,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson (socklen_t)namelen,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson 0, _SOCONNECT_NOXLATE, CRED());
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kmem_free(name, namelen);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (error) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson eprintsoline(so2, error);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson goto done;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
c39a2aae1e2c439d156021edfc20910dad7f9891George Wilson releasef(svs[0]);
c39a2aae1e2c439d156021edfc20910dad7f9891George Wilson releasef(svs[1]);
c39a2aae1e2c439d156021edfc20910dad7f9891George Wilson } else {
c39a2aae1e2c439d156021edfc20910dad7f9891George Wilson /*
c39a2aae1e2c439d156021edfc20910dad7f9891George Wilson * Bind both sockets, with so1 being a listener.
c39a2aae1e2c439d156021edfc20910dad7f9891George Wilson * Connect so2 to so1 - nonblocking to avoid waiting for
c39a2aae1e2c439d156021edfc20910dad7f9891George Wilson * soaccept to complete.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * Accept a connection on so1. Pass out the new fd as sv[0].
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * The library will detect the changed fd and close
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * the original one.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson struct sonode *nso;
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct vnode *nvp;
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct file *nfp;
fa9e4066f08beec538e775443c5be79dd423fcabahrens int nfd;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens /*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * We could simply call socket_listen() here (which would do the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * binding automatically) if the code didn't rely on passing
fa9e4066f08beec538e775443c5be79dd423fcabahrens * _SOBIND_NOXLATE to the TPI implementation of socket_bind().
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens error = socket_bind(so1, NULL, 0, _SOBIND_UNSPEC|
fa9e4066f08beec538e775443c5be79dd423fcabahrens _SOBIND_NOXLATE|_SOBIND_LISTEN|_SOBIND_SOCKETPAIR,
fa9e4066f08beec538e775443c5be79dd423fcabahrens CRED());
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (error) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens eprintsoline(so1, error);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson goto done;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson error = socket_bind(so2, NULL, 0, _SOBIND_UNSPEC, CRED());
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (error) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens eprintsoline(so2, error);
fa9e4066f08beec538e775443c5be79dd423fcabahrens goto done;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens namelen = sizeof (struct sockaddr_ux);
fa9e4066f08beec538e775443c5be79dd423fcabahrens name = kmem_alloc(namelen, KM_SLEEP);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson name->sou_family = AF_UNIX;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson name->sou_addr = sti1->sti_ux_laddr;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = socket_connect(so2,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson (struct sockaddr *)name,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson (socklen_t)namelen,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson FNONBLOCK, _SOCONNECT_NOXLATE, CRED());
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson kmem_free(name, namelen);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (error) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (error != EINPROGRESS) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson eprintsoline(so2, error); goto done;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = socket_accept(so1, 0, CRED(), &nso);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (error) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson eprintsoline(so1, error);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson goto done;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /* wait for so2 being SS_CONNECTED ignoring signals */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mutex_enter(&so2->so_lock);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = sowaitconnected(so2, 0, 1);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mutex_exit(&so2->so_lock);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (error != 0) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson (void) socket_close(nso, 0, CRED());
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson socket_destroy(nso);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson eprintsoline(so2, error);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson goto done;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson nvp = SOTOV(nso);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (error = falloc(nvp, FWRITE|FREAD, &nfp, &nfd)) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson (void) socket_close(nso, 0, CRED());
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson socket_destroy(nso);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson eprintsoline(nso, error);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson goto done;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * fill in the entries that falloc reserved
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mutex_exit(&nfp->f_tlock);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson setf(nfd, nfp);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson releasef(svs[0]);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson releasef(svs[1]);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson svs[0] = nfd;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * The socketpair library routine will close the original
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * svs[0] when this code passes out a different file
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * descriptor.
22e30981d82a0b6dc89253596ededafae8655e00George Wilson */
22e30981d82a0b6dc89253596ededafae8655e00George Wilson if (copyout(svs, sv, sizeof (svs))) {
22e30981d82a0b6dc89253596ededafae8655e00George Wilson (void) closeandsetf(nfd, NULL);
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson eprintline(EFAULT);
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson return (set_errno(EFAULT));
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson }
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson }
22e30981d82a0b6dc89253596ededafae8655e00George Wilson return (0);
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
22e30981d82a0b6dc89253596ededafae8655e00George Wilsondone:
22e30981d82a0b6dc89253596ededafae8655e00George Wilson releasef(svs[0]);
22e30981d82a0b6dc89253596ededafae8655e00George Wilson releasef(svs[1]);
22e30981d82a0b6dc89253596ededafae8655e00George Wilson return (set_errno(error));
22e30981d82a0b6dc89253596ededafae8655e00George Wilson}
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilsonint
22e30981d82a0b6dc89253596ededafae8655e00George Wilsonbind(int sock, struct sockaddr *name, socklen_t namelen, int version)
22e30981d82a0b6dc89253596ededafae8655e00George Wilson{
22e30981d82a0b6dc89253596ededafae8655e00George Wilson struct sonode *so;
22e30981d82a0b6dc89253596ededafae8655e00George Wilson int error;
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson dprint(1, ("bind(%d, %p, %d)\n",
22e30981d82a0b6dc89253596ededafae8655e00George Wilson sock, (void *)name, namelen));
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
22e30981d82a0b6dc89253596ededafae8655e00George Wilson if ((so = getsonode(sock, &error, NULL)) == NULL)
22e30981d82a0b6dc89253596ededafae8655e00George Wilson return (set_errno(error));
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson /* Allocate and copyin name */
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson /*
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson * X/Open test does not expect EFAULT with NULL name and non-zero
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson * namelen.
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson */
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson if (name != NULL && namelen != 0) {
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson ASSERT(MUTEX_NOT_HELD(&so->so_lock));
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson name = copyin_name(so, name, &namelen, &error);
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson if (name == NULL) {
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson releasef(sock);
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson return (set_errno(error));
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson }
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson } else {
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson name = NULL;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson namelen = 0;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson }
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson switch (version) {
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson default:
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = socket_bind(so, name, namelen, 0, CRED());
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson break;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson case SOV_XPG4_2:
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = socket_bind(so, name, namelen, _SOBIND_XPG4_2, CRED());
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson break;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson case SOV_SOCKBSD:
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson error = socket_bind(so, name, namelen, _SOBIND_SOCKBSD, CRED());
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson break;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsondone:
22e30981d82a0b6dc89253596ededafae8655e00George Wilson releasef(sock);
22e30981d82a0b6dc89253596ededafae8655e00George Wilson if (name != NULL)
22e30981d82a0b6dc89253596ededafae8655e00George Wilson kmem_free(name, (size_t)namelen);
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
22e30981d82a0b6dc89253596ededafae8655e00George Wilson if (error)
22e30981d82a0b6dc89253596ededafae8655e00George Wilson return (set_errno(error));
22e30981d82a0b6dc89253596ededafae8655e00George Wilson return (0);
22e30981d82a0b6dc89253596ededafae8655e00George Wilson}
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
22e30981d82a0b6dc89253596ededafae8655e00George Wilson/* ARGSUSED2 */
22e30981d82a0b6dc89253596ededafae8655e00George Wilsonint
22e30981d82a0b6dc89253596ededafae8655e00George Wilsonlisten(int sock, int backlog, int version)
22e30981d82a0b6dc89253596ededafae8655e00George Wilson{
22e30981d82a0b6dc89253596ededafae8655e00George Wilson struct sonode *so;
22e30981d82a0b6dc89253596ededafae8655e00George Wilson int error;
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
22e30981d82a0b6dc89253596ededafae8655e00George Wilson dprint(1, ("listen(%d, %d)\n",
22e30981d82a0b6dc89253596ededafae8655e00George Wilson sock, backlog));
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
22e30981d82a0b6dc89253596ededafae8655e00George Wilson if ((so = getsonode(sock, &error, NULL)) == NULL)
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson return (set_errno(error));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
22e30981d82a0b6dc89253596ededafae8655e00George Wilson error = socket_listen(so, backlog, CRED());
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
22e30981d82a0b6dc89253596ededafae8655e00George Wilson releasef(sock);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (error)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (set_errno(error));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*ARGSUSED3*/
fa9e4066f08beec538e775443c5be79dd423fcabahrensint
fa9e4066f08beec538e775443c5be79dd423fcabahrensaccept(int sock, struct sockaddr *name, socklen_t *namelenp, int version)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct sonode *so;
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick file_t *fp;
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick int error;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson socklen_t namelen;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson struct sonode *nso;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson struct vnode *nvp;
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct file *nfp;
be082110c08433beadb738ad3be035a73d995ea8George Wilson int nfd;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson struct sockaddr *addrp;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson socklen_t addrlen;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens dprint(1, ("accept(%d, %p, %p)\n",
fa9e4066f08beec538e775443c5be79dd423fcabahrens sock, (void *)name, (void *)namelenp));
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((so = getsonode(sock, &error, &fp)) == NULL)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (set_errno(error));
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick if (name != NULL) {
a33cae9802e94744efee12a7a77c89360645eae8Tim Haley ASSERT(MUTEX_NOT_HELD(&so->so_lock));
a33cae9802e94744efee12a7a77c89360645eae8Tim Haley if (copyin(namelenp, &namelen, sizeof (namelen))) {
a33cae9802e94744efee12a7a77c89360645eae8Tim Haley releasef(sock);
a33cae9802e94744efee12a7a77c89360645eae8Tim Haley return (set_errno(EFAULT));
a33cae9802e94744efee12a7a77c89360645eae8Tim Haley }
a33cae9802e94744efee12a7a77c89360645eae8Tim Haley if (namelen != 0) {
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick error = useracc(name, (size_t)namelen, B_WRITE);
be082110c08433beadb738ad3be035a73d995ea8George Wilson if (error && do_useracc) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens releasef(sock);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (set_errno(EFAULT));
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson }
fa9e4066f08beec538e775443c5be79dd423fcabahrens } else
fa9e4066f08beec538e775443c5be79dd423fcabahrens name = NULL;
fa9e4066f08beec538e775443c5be79dd423fcabahrens } else {
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick namelen = 0;
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick }
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick /*
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick * Allocate the user fd before socket_accept() in order to
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick * catch EMFILE errors before calling socket_accept().
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick */
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick if ((nfd = ufalloc(0)) == -1) {
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick eprintsoline(so, EMFILE);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick releasef(sock);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick return (set_errno(EMFILE));
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick }
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick error = socket_accept(so, fp->f_flag, CRED(), &nso);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick if (error) {
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick setf(nfd, NULL);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick releasef(sock);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick return (set_errno(error));
22e30981d82a0b6dc89253596ededafae8655e00George Wilson }
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick nvp = SOTOV(nso);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick ASSERT(MUTEX_NOT_HELD(&nso->so_lock));
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick if (namelen != 0) {
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick addrlen = so->so_max_addr_len;
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick addrp = (struct sockaddr *)kmem_alloc(addrlen, KM_SLEEP);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick if ((error = socket_getpeername(nso, (struct sockaddr *)addrp,
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick &addrlen, B_TRUE, CRED())) == 0) {
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick error = copyout_name(name, namelen, namelenp,
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick addrp, addrlen);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick } else {
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick ASSERT(error == EINVAL || error == ENOTCONN);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick error = ECONNABORTED;
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick }
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick kmem_free(addrp, so->so_max_addr_len);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick }
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick if (error) {
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick setf(nfd, NULL);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick (void) socket_close(nso, 0, CRED());
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick socket_destroy(nso);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick releasef(sock);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick return (set_errno(error));
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick }
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick if (error = falloc(NULL, FWRITE|FREAD, &nfp, NULL)) {
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick setf(nfd, NULL);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick (void) socket_close(nso, 0, CRED());
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick socket_destroy(nso);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson eprintsoline(so, error);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson releasef(sock);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(error));
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick }
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick /*
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick * fill in the entries that falloc reserved
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick */
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick nfp->f_vnode = nvp;
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick mutex_exit(&nfp->f_tlock);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick setf(nfd, nfp);
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick /*
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick * Copy FNDELAY and FNONBLOCK from listener to acceptor
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick */
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick if (so->so_state & (SS_NDELAY|SS_NONBLOCK)) {
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick uint_t oflag = nfp->f_flag;
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick int arg = 0;
a15215608b8bd90f714f6db21ee623b584607cb6Jeff Bonwick
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson if (so->so_state & SS_NONBLOCK)
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson arg |= FNONBLOCK;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson else if (so->so_state & SS_NDELAY)
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson arg |= FNDELAY;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson /*
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson * This code is a simplification of the F_SETFL code in fcntl()
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson * Ignore any errors from VOP_SETFL.
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if ((error = VOP_SETFL(nvp, oflag, arg, nfp->f_cred, NULL))
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson != 0) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson eprintsoline(so, error);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = 0;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson } else {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson mutex_enter(&nfp->f_tlock);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson nfp->f_flag &= ~FMASK | (FREAD|FWRITE);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson nfp->f_flag |= arg;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson mutex_exit(&nfp->f_tlock);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson releasef(sock);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (nfd);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson}
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonint
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonconnect(int sock, struct sockaddr *name, socklen_t namelen, int version)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson{
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson struct sonode *so;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson file_t *fp;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson int error;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson dprint(1, ("connect(%d, %p, %d)\n",
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson sock, (void *)name, namelen));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if ((so = getsonode(sock, &error, &fp)) == NULL)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (set_errno(error));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /* Allocate and copyin name */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (namelen != 0) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson ASSERT(MUTEX_NOT_HELD(&so->so_lock));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson name = copyin_name(so, name, &namelen, &error);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (name == NULL) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson releasef(sock);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (set_errno(error));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson } else
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson name = NULL;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = socket_connect(so, name, namelen, fp->f_flag,
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick (version != SOV_XPG4_2) ? 0 : _SOCONNECT_XPG4_2, CRED());
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson releasef(sock);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (name)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kmem_free(name, (size_t)namelen);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (error)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (set_errno(error));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (0);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson}
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson/*ARGSUSED2*/
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonint
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonshutdown(int sock, int how, int version)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson{
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson struct sonode *so;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson int error;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson dprint(1, ("shutdown(%d, %d)\n",
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson sock, how));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if ((so = getsonode(sock, &error, NULL)) == NULL)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (set_errno(error));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
fa9e4066f08beec538e775443c5be79dd423fcabahrens error = socket_shutdown(so, how, CRED());
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson releasef(sock);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (error)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (set_errno(error));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (0);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson}
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * Common receive routine.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonstatic ssize_t
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonrecvit(int sock,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson struct nmsghdr *msg,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson struct uio *uiop,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson int flags,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson socklen_t *namelenp,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson socklen_t *controllenp,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson int *flagsp)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson{
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson struct sonode *so;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson file_t *fp;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson void *name;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson socklen_t namelen;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson void *control;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson socklen_t controllen;
fa9e4066f08beec538e775443c5be79dd423fcabahrens ssize_t len;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson int error;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick if ((so = getsonode(sock, &error, &fp)) == NULL)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (set_errno(error));
fa9e4066f08beec538e775443c5be79dd423fcabahrens
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson len = uiop->uio_resid;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson uiop->uio_fmode = fp->f_flag;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson uiop->uio_extflg = UIO_COPY_CACHED;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
fa9e4066f08beec538e775443c5be79dd423fcabahrens name = msg->msg_name;
fa9e4066f08beec538e775443c5be79dd423fcabahrens namelen = msg->msg_namelen;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick control = msg->msg_control;
fa9e4066f08beec538e775443c5be79dd423fcabahrens controllen = msg->msg_controllen;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson msg->msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson MSG_DONTWAIT | MSG_XPG4_2);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = socket_recvmsg(so, msg, uiop, CRED());
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (error) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens releasef(sock);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (set_errno(error));
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens lwp_stat_update(LWP_STAT_MSGRCV, 1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens releasef(sock);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick error = copyout_name(name, namelen, namelenp,
fa9e4066f08beec538e775443c5be79dd423fcabahrens msg->msg_name, msg->msg_namelen);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (error)
5f5f7a6f9c8e9c1587a54e690556d756ec67558cahrens goto err;
5f5f7a6f9c8e9c1587a54e690556d756ec67558cahrens
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (flagsp != NULL) {
5f5f7a6f9c8e9c1587a54e690556d756ec67558cahrens /*
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * Clear internal flag.
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick */
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick msg->msg_flags &= ~MSG_XPG4_2;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens /*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Determine MSG_CTRUNC. sorecvmsg sets MSG_CTRUNC only
fa9e4066f08beec538e775443c5be79dd423fcabahrens * when controllen is zero and there is control data to
fa9e4066f08beec538e775443c5be79dd423fcabahrens * copy out.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (controllen != 0 &&
fa9e4066f08beec538e775443c5be79dd423fcabahrens (msg->msg_controllen > controllen || control == NULL)) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson dprint(1, ("recvit: CTRUNC %d %d %p\n",
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson msg->msg_controllen, controllen, control));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson msg->msg_flags |= MSG_CTRUNC;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (copyout(&msg->msg_flags, flagsp,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson sizeof (msg->msg_flags))) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = EFAULT;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson goto err;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /*
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * Note: This MUST be done last. There can be no "goto err" after this
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * point since it could make so_closefds run twice on some part
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * of the file descriptor array.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (controllen != 0) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (!(flags & MSG_XPG4_2)) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /*
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * Good old msg_accrights can only return a multiple
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * of 4 bytes.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson controllen &= ~((int)sizeof (uint32_t) - 1);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = copyout_arg(control, controllen, controllenp,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson msg->msg_control, msg->msg_controllen);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (error)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson goto err;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (msg->msg_controllen > controllen || control == NULL) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (control == NULL)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson controllen = 0;
22e30981d82a0b6dc89253596ededafae8655e00George Wilson so_closefds(msg->msg_control, msg->msg_controllen,
22e30981d82a0b6dc89253596ededafae8655e00George Wilson !(flags & MSG_XPG4_2), controllen);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (msg->msg_namelen != 0)
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson kmem_free(msg->msg_name, (size_t)msg->msg_namelen);
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson if (msg->msg_controllen != 0)
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson kmem_free(msg->msg_control, (size_t)msg->msg_controllen);
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson return (len - uiop->uio_resid);
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
22e30981d82a0b6dc89253596ededafae8655e00George Wilsonerr:
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson /*
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson * If we fail and the control part contains file descriptors
22e30981d82a0b6dc89253596ededafae8655e00George Wilson * we have to close the fd's.
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson */
22e30981d82a0b6dc89253596ededafae8655e00George Wilson if (msg->msg_controllen != 0)
22e30981d82a0b6dc89253596ededafae8655e00George Wilson so_closefds(msg->msg_control, msg->msg_controllen,
22e30981d82a0b6dc89253596ededafae8655e00George Wilson !(flags & MSG_XPG4_2), 0);
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson if (msg->msg_namelen != 0)
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson kmem_free(msg->msg_name, (size_t)msg->msg_namelen);
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson if (msg->msg_controllen != 0)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kmem_free(msg->msg_control, (size_t)msg->msg_controllen);
22e30981d82a0b6dc89253596ededafae8655e00George Wilson return (set_errno(error));
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson}
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson/*
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson * Native system call
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson */
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilsonssize_t
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilsonrecv(int sock, void *buffer, size_t len, int flags)
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson{
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson struct nmsghdr lmsg;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson struct uio auio;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson struct iovec aiov[1];
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson dprint(1, ("recv(%d, %p, %ld, %d)\n",
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson sock, buffer, len, flags));
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson if ((ssize_t)len < 0) {
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson return (set_errno(EINVAL));
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson }
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson aiov[0].iov_base = buffer;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson aiov[0].iov_len = len;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson auio.uio_loffset = 0;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson auio.uio_iov = aiov;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson auio.uio_iovcnt = 1;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson auio.uio_resid = len;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson auio.uio_segflg = UIO_USERSPACE;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson auio.uio_limit = 0;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson lmsg.msg_namelen = 0;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson lmsg.msg_controllen = 0;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson lmsg.msg_flags = 0;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson return (recvit(sock, &lmsg, &auio, flags, NULL, NULL, NULL));
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson}
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilsonssize_t
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilsonrecvfrom(int sock, void *buffer, size_t len, int flags,
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson struct sockaddr *name, socklen_t *namelenp)
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson{
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson struct nmsghdr lmsg;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson struct uio auio;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson struct iovec aiov[1];
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson dprint(1, ("recvfrom(%d, %p, %ld, %d, %p, %p)\n",
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson sock, buffer, len, flags, (void *)name, (void *)namelenp));
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson if ((ssize_t)len < 0) {
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson return (set_errno(EINVAL));
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson }
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson aiov[0].iov_base = buffer;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson aiov[0].iov_len = len;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson auio.uio_loffset = 0;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson auio.uio_iov = aiov;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson auio.uio_iovcnt = 1;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson auio.uio_resid = len;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson auio.uio_segflg = UIO_USERSPACE;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson auio.uio_limit = 0;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson lmsg.msg_name = (char *)name;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson if (namelenp != NULL) {
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson if (copyin(namelenp, &lmsg.msg_namelen,
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson sizeof (lmsg.msg_namelen)))
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson return (set_errno(EFAULT));
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson } else {
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson lmsg.msg_namelen = 0;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson }
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson lmsg.msg_controllen = 0;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson lmsg.msg_flags = 0;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson return (recvit(sock, &lmsg, &auio, flags, namelenp, NULL, NULL));
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson}
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson/*
22e30981d82a0b6dc89253596ededafae8655e00George Wilson * Uses the MSG_XPG4_2 flag to determine if the caller is using
22e30981d82a0b6dc89253596ededafae8655e00George Wilson * struct omsghdr or struct nmsghdr.
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson */
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilsonssize_t
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsonrecvmsg(int sock, struct nmsghdr *msg, int flags)
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson{
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson STRUCT_DECL(nmsghdr, u_lmsg);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson STRUCT_HANDLE(nmsghdr, umsgptr);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson struct nmsghdr lmsg;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson struct uio auio;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson struct iovec aiov[MSG_MAXIOVLEN];
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson int iovcnt;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson ssize_t len;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson int i;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson int *flagsp;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson model_t model;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson dprint(1, ("recvmsg(%d, %p, %d)\n",
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson sock, (void *)msg, flags));
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson model = get_udatamodel();
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson STRUCT_INIT(u_lmsg, model);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson STRUCT_SET_HANDLE(umsgptr, model, msg);
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson if (flags & MSG_XPG4_2) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (copyin(msg, STRUCT_BUF(u_lmsg), STRUCT_SIZE(u_lmsg)))
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson return (set_errno(EFAULT));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson flagsp = STRUCT_FADDR(umsgptr, msg_flags);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson } else {
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson /*
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson * Assumes that nmsghdr and omsghdr are identically shaped
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson * except for the added msg_flags field.
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson */
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson if (copyin(msg, STRUCT_BUF(u_lmsg),
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick SIZEOF_STRUCT(omsghdr, model)))
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(EFAULT));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson STRUCT_FSET(u_lmsg, msg_flags, 0);
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick flagsp = NULL;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick /*
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * Code below us will kmem_alloc memory and hang it
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick * off msg_control and msg_name fields. This forces
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * us to copy the structure to its native form.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick lmsg.msg_name = STRUCT_FGETP(u_lmsg, msg_name);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson lmsg.msg_namelen = STRUCT_FGET(u_lmsg, msg_namelen);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson lmsg.msg_iov = STRUCT_FGETP(u_lmsg, msg_iov);
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson lmsg.msg_iovlen = STRUCT_FGET(u_lmsg, msg_iovlen);
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson lmsg.msg_control = STRUCT_FGETP(u_lmsg, msg_control);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson iovcnt = lmsg.msg_iovlen;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson if (iovcnt <= 0 || iovcnt > MSG_MAXIOVLEN) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(EMSGSIZE));
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson#ifdef _SYSCALL32_IMPL
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /*
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson * 32-bit callers need to have their iovec expanded, while ensuring
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * that they can't move more than 2Gbytes of data in a single call.
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson */
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson if (model == DATAMODEL_ILP32) {
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson struct iovec32 aiov32[MSG_MAXIOVLEN];
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson ssize32_t count32;
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (copyin((struct iovec32 *)lmsg.msg_iov, aiov32,
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson iovcnt * sizeof (struct iovec32)))
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(EFAULT));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson count32 = 0;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson for (i = 0; i < iovcnt; i++) {
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick ssize32_t iovlen32;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick iovlen32 = aiov32[i].iov_len;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson count32 += iovlen32;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick if (iovlen32 < 0 || count32 < 0)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(EINVAL));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson aiov[i].iov_len = iovlen32;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson aiov[i].iov_base =
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson (caddr_t)(uintptr_t)aiov32[i].iov_base;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson } else
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick#endif /* _SYSCALL32_IMPL */
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick if (copyin(lmsg.msg_iov, aiov, iovcnt * sizeof (struct iovec))) {
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick return (set_errno(EFAULT));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick len = 0;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson for (i = 0; i < iovcnt; i++) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson ssize_t iovlen = aiov[i].iov_len;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson len += iovlen;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (iovlen < 0 || len < 0) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(EINVAL));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_loffset = 0;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_iov = aiov;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_iovcnt = iovcnt;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_resid = len;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_segflg = UIO_USERSPACE;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_limit = 0;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick if (lmsg.msg_control != NULL &&
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson (do_useracc == 0 ||
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson useracc(lmsg.msg_control, lmsg.msg_controllen,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson B_WRITE) != 0)) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(EFAULT));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (recvit(sock, &lmsg, &auio, flags,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson STRUCT_FADDR(umsgptr, msg_namelen),
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson STRUCT_FADDR(umsgptr, msg_controllen), flagsp));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson}
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson/*
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * Common send function.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilsonstatic ssize_t
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilsonsendit(int sock, struct nmsghdr *msg, struct uio *uiop, int flags)
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson{
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson struct sonode *so;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson file_t *fp;
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson void *name;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson socklen_t namelen;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson void *control;
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson socklen_t controllen;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson ssize_t len;
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson int error;
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if ((so = getsonode(sock, &error, &fp)) == NULL)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(error));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson uiop->uio_fmode = fp->f_flag;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (so->so_family == AF_UNIX)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson uiop->uio_extflg = UIO_COPY_CACHED;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson else
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson uiop->uio_extflg = UIO_COPY_DEFAULT;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /* Allocate and copyin name and control */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson name = msg->msg_name;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson namelen = msg->msg_namelen;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (name != NULL && namelen != 0) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson ASSERT(MUTEX_NOT_HELD(&so->so_lock));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson name = copyin_name(so,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson (struct sockaddr *)name,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson &namelen, &error);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (name == NULL)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson goto done3;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /* copyin_name null terminates addresses for AF_UNIX */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson msg->msg_namelen = namelen;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson msg->msg_name = name;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson } else {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson msg->msg_name = name = NULL;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson msg->msg_namelen = namelen = 0;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson control = msg->msg_control;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson controllen = msg->msg_controllen;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if ((control != NULL) && (controllen != 0)) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /*
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * Verify that the length is not excessive to prevent
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * an application from consuming all of kernel memory.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (controllen > SO_MAXARGSIZE) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson error = EINVAL;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson goto done2;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson control = kmem_alloc(controllen, KM_SLEEP);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson ASSERT(MUTEX_NOT_HELD(&so->so_lock));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (copyin(msg->msg_control, control, controllen)) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson error = EFAULT;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson goto done1;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson msg->msg_control = control;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson } else {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson msg->msg_control = control = NULL;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson msg->msg_controllen = controllen = 0;
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson }
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson len = uiop->uio_resid;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson msg->msg_flags = flags;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson error = socket_sendmsg(so, msg, uiop, CRED());
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilsondone1:
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson if (control != NULL)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson kmem_free(control, controllen);
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilsondone2:
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (name != NULL)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson kmem_free(name, namelen);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsondone3:
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (error != 0) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson releasef(sock);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(error));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson lwp_stat_update(LWP_STAT_MSGSND, 1);
bf16b11e8deb633dd6c4296d46e92399d1582df4Matthew Ahrens releasef(sock);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (len - uiop->uio_resid);
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson}
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson/*
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson * Native system call
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonssize_t
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilsonsend(int sock, void *buffer, size_t len, int flags)
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson{
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson struct nmsghdr lmsg;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson struct uio auio;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson struct iovec aiov[1];
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson dprint(1, ("send(%d, %p, %ld, %d)\n",
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson sock, buffer, len, flags));
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson if ((ssize_t)len < 0) {
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson return (set_errno(EINVAL));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson aiov[0].iov_base = buffer;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson aiov[0].iov_len = len;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_loffset = 0;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_iov = aiov;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_iovcnt = 1;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_resid = len;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_segflg = UIO_USERSPACE;
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson auio.uio_limit = 0;
bf16b11e8deb633dd6c4296d46e92399d1582df4Matthew Ahrens
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson lmsg.msg_name = NULL;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson lmsg.msg_control = NULL;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (!(flags & MSG_XPG4_2)) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /*
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson * In order to be compatible with the libsocket/sockmod
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * implementation we set EOR for all send* calls.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson flags |= MSG_EOR;
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson }
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson return (sendit(sock, &lmsg, &auio, flags));
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson}
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson/*
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson * Uses the MSG_XPG4_2 flag to determine if the caller is using
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson * struct omsghdr or struct nmsghdr.
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson */
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilsonssize_t
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsonsendmsg(int sock, struct nmsghdr *msg, int flags)
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson{
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson struct nmsghdr lmsg;
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson STRUCT_DECL(nmsghdr, u_lmsg);
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson struct uio auio;
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson struct iovec aiov[MSG_MAXIOVLEN];
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson int iovcnt;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson ssize_t len;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson int i;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson model_t model;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson dprint(1, ("sendmsg(%d, %p, %d)\n", sock, (void *)msg, flags));
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson model = get_udatamodel();
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson STRUCT_INIT(u_lmsg, model);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (flags & MSG_XPG4_2) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (copyin(msg, (char *)STRUCT_BUF(u_lmsg),
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson STRUCT_SIZE(u_lmsg)))
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson return (set_errno(EFAULT));
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson } else {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /*
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson * Assumes that nmsghdr and omsghdr are identically shaped
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * except for the added msg_flags field.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (copyin(msg, (char *)STRUCT_BUF(u_lmsg),
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson SIZEOF_STRUCT(omsghdr, model)))
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson return (set_errno(EFAULT));
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson /*
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * In order to be compatible with the libsocket/sockmod
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * implementation we set EOR for all send* calls.
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson flags |= MSG_EOR;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /*
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson * Code below us will kmem_alloc memory and hang it
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * off msg_control and msg_name fields. This forces
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * us to copy the structure to its native form.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson lmsg.msg_name = STRUCT_FGETP(u_lmsg, msg_name);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson lmsg.msg_namelen = STRUCT_FGET(u_lmsg, msg_namelen);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson lmsg.msg_iov = STRUCT_FGETP(u_lmsg, msg_iov);
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson lmsg.msg_iovlen = STRUCT_FGET(u_lmsg, msg_iovlen);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson lmsg.msg_control = STRUCT_FGETP(u_lmsg, msg_control);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson iovcnt = lmsg.msg_iovlen;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson if (iovcnt <= 0 || iovcnt > MSG_MAXIOVLEN) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /*
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * Unless this is XPG 4.2 we allow iovcnt == 0 to
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson * be compatible with SunOS 4.X and 4.4BSD.
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (iovcnt != 0 || (flags & MSG_XPG4_2))
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(EMSGSIZE));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson#ifdef _SYSCALL32_IMPL
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /*
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * 32-bit callers need to have their iovec expanded, while ensuring
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * that they can't move more than 2Gbytes of data in a single call.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (model == DATAMODEL_ILP32) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson struct iovec32 aiov32[MSG_MAXIOVLEN];
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson ssize32_t count32;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
8d18220deb04ec7b12410cd90deb4d45e66d49bfMark J Musante if (iovcnt != 0 &&
8d18220deb04ec7b12410cd90deb4d45e66d49bfMark J Musante copyin((struct iovec32 *)lmsg.msg_iov, aiov32,
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson iovcnt * sizeof (struct iovec32)))
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(EFAULT));
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson count32 = 0;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson for (i = 0; i < iovcnt; i++) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson ssize32_t iovlen32;
bf16b11e8deb633dd6c4296d46e92399d1582df4Matthew Ahrens
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson iovlen32 = aiov32[i].iov_len;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson count32 += iovlen32;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson if (iovlen32 < 0 || count32 < 0)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(EINVAL));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson aiov[i].iov_len = iovlen32;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson aiov[i].iov_base =
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson (caddr_t)(uintptr_t)aiov32[i].iov_base;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson }
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson } else
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson#endif /* _SYSCALL32_IMPL */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (iovcnt != 0 &&
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson copyin(lmsg.msg_iov, aiov,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson (unsigned)iovcnt * sizeof (struct iovec))) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(EFAULT));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson len = 0;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson for (i = 0; i < iovcnt; i++) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson ssize_t iovlen = aiov[i].iov_len;
8d18220deb04ec7b12410cd90deb4d45e66d49bfMark J Musante len += iovlen;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (iovlen < 0 || len < 0) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(EINVAL));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson auio.uio_loffset = 0;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson auio.uio_iov = aiov;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_iovcnt = iovcnt;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_resid = len;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_segflg = UIO_USERSPACE;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson auio.uio_limit = 0;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson return (sendit(sock, &lmsg, &auio, flags));
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson}
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonssize_t
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwicksendto(int sock, void *buffer, size_t len, int flags,
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick struct sockaddr *name, socklen_t namelen)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson{
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson struct nmsghdr lmsg;
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct uio auio;
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct iovec aiov[1];
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens dprint(1, ("sendto(%d, %p, %ld, %d, %p, %d)\n",
fa9e4066f08beec538e775443c5be79dd423fcabahrens sock, buffer, len, flags, (void *)name, namelen));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if ((ssize_t)len < 0) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(EINVAL));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson aiov[0].iov_base = buffer;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson aiov[0].iov_len = len;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_loffset = 0;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_iov = aiov;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_iovcnt = 1;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_resid = len;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_segflg = UIO_USERSPACE;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson auio.uio_limit = 0;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson lmsg.msg_name = (char *)name;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson lmsg.msg_namelen = namelen;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson lmsg.msg_control = NULL;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (!(flags & MSG_XPG4_2)) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * In order to be compatible with the libsocket/sockmod
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * implementation we set EOR for all send* calls.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson flags |= MSG_EOR;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (sendit(sock, &lmsg, &auio, flags));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson}
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson/*ARGSUSED3*/
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsonint
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsongetpeername(int sock, struct sockaddr *name, socklen_t *namelenp, int version)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson{
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson struct sonode *so;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson int error;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson socklen_t namelen;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson socklen_t sock_addrlen;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson struct sockaddr *sock_addrp;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson dprint(1, ("getpeername(%d, %p, %p)\n",
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson sock, (void *)name, (void *)namelenp));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if ((so = getsonode(sock, &error, NULL)) == NULL)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson goto bad;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson ASSERT(MUTEX_NOT_HELD(&so->so_lock));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (copyin(namelenp, &namelen, sizeof (namelen)) ||
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson (name == NULL && namelen != 0)) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson error = EFAULT;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson goto rel_out;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson sock_addrlen = so->so_max_addr_len;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson sock_addrp = (struct sockaddr *)kmem_alloc(sock_addrlen, KM_SLEEP);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if ((error = socket_getpeername(so, sock_addrp, &sock_addrlen,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson B_FALSE, CRED())) == 0) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson ASSERT(sock_addrlen <= so->so_max_addr_len);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson error = copyout_name(name, namelen, namelenp,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson (void *)sock_addrp, sock_addrlen);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson kmem_free(sock_addrp, so->so_max_addr_len);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsonrel_out:
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson releasef(sock);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonbad: return (error != 0 ? set_errno(error) : 0);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson}
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya/*ARGSUSED3*/
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Suryaint
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Suryagetsockname(int sock, struct sockaddr *name,
fa9e4066f08beec538e775443c5be79dd423fcabahrens socklen_t *namelenp, int version)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson struct sonode *so;
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya int error;
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya socklen_t namelen, sock_addrlen;
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct sockaddr *sock_addrp;
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya dprint(1, ("getsockname(%d, %p, %p)\n",
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya sock, (void *)name, (void *)namelenp));
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya if ((so = getsonode(sock, &error, NULL)) == NULL)
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya goto bad;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson ASSERT(MUTEX_NOT_HELD(&so->so_lock));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (copyin(namelenp, &namelen, sizeof (namelen)) ||
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson (name == NULL && namelen != 0)) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson error = EFAULT;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson goto rel_out;
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya }
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya sock_addrlen = so->so_max_addr_len;
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya sock_addrp = (struct sockaddr *)kmem_alloc(sock_addrlen, KM_SLEEP);
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya if ((error = socket_getsockname(so, sock_addrp, &sock_addrlen,
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya CRED())) == 0) {
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya ASSERT(MUTEX_NOT_HELD(&so->so_lock));
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya ASSERT(sock_addrlen <= so->so_max_addr_len);
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya error = copyout_name(name, namelen, namelenp,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson (void *)sock_addrp, sock_addrlen);
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick kmem_free(sock_addrp, so->so_max_addr_len);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsonrel_out:
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson releasef(sock);
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwickbad: return (error != 0 ? set_errno(error) : 0);
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick}
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick/*ARGSUSED5*/
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Suryaint
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Suryagetsockopt(int sock,
fa9e4066f08beec538e775443c5be79dd423fcabahrens int level,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson int option_name,
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick void *option_value,
fa9e4066f08beec538e775443c5be79dd423fcabahrens socklen_t *option_lenp,
fa9e4066f08beec538e775443c5be79dd423fcabahrens int version)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct sonode *so;
fa9e4066f08beec538e775443c5be79dd423fcabahrens socklen_t optlen, optlen_res;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson void *optval;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson int error;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
fa9e4066f08beec538e775443c5be79dd423fcabahrens dprint(1, ("getsockopt(%d, %d, %d, %p, %p)\n",
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick sock, level, option_name, option_value, (void *)option_lenp));
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick if ((so = getsonode(sock, &error, NULL)) == NULL)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(error));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson ASSERT(MUTEX_NOT_HELD(&so->so_lock));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (copyin(option_lenp, &optlen, sizeof (optlen))) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson releasef(sock);
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya return (set_errno(EFAULT));
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya }
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya /*
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya * Verify that the length is not excessive to prevent
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * an application from consuming all of kernel memory.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick if (optlen > SO_MAXARGSIZE) {
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick error = EINVAL;
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya releasef(sock);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (set_errno(error));
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya optval = kmem_alloc(optlen, KM_SLEEP);
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya optlen_res = optlen;
1e9bd7ec42f2d3bf854c2da35310901194833267Prakash Surya error = socket_getsockopt(so, level, option_name, optval,
fa9e4066f08beec538e775443c5be79dd423fcabahrens &optlen_res, (version != SOV_XPG4_2) ? 0 : _SOGETSOCKOPT_XPG4_2,
fa9e4066f08beec538e775443c5be79dd423fcabahrens CRED());
fa9e4066f08beec538e775443c5be79dd423fcabahrens releasef(sock);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (error) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens kmem_free(optval, optlen);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (set_errno(error));
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens error = copyout_arg(option_value, optlen, option_lenp,
fa9e4066f08beec538e775443c5be79dd423fcabahrens optval, optlen_res);
fa9e4066f08beec538e775443c5be79dd423fcabahrens kmem_free(optval, optlen);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (error)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(error));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (0);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson}
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson/*ARGSUSED5*/
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsonint
fa9e4066f08beec538e775443c5be79dd423fcabahrenssetsockopt(int sock,
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley int level,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson int option_name,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson void *option_value,
fa9e4066f08beec538e775443c5be79dd423fcabahrens socklen_t option_len,
fa9e4066f08beec538e775443c5be79dd423fcabahrens int version)
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson{
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson struct sonode *so;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson intptr_t buffer[2];
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley void *optval = NULL;
fb09f5aad449c97fe309678f3f604982b563a96fMadhav Suresh int error;
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley
fa9e4066f08beec538e775443c5be79dd423fcabahrens dprint(1, ("setsockopt(%d, %d, %d, %p, %d)\n",
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson sock, level, option_name, option_value, option_len));
5ad820458efd0fdb914baff9c1447c22b819fa23nd
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((so = getsonode(sock, &error, NULL)) == NULL)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (set_errno(error));
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (option_value != NULL) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (option_len != 0) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /*
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * Verify that the length is not excessive to prevent
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * an application from consuming all of kernel memory.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (option_len > SO_MAXARGSIZE) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = EINVAL;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson goto done2;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson optval = option_len <= sizeof (buffer) ?
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson &buffer : kmem_alloc((size_t)option_len, KM_SLEEP);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson ASSERT(MUTEX_NOT_HELD(&so->so_lock));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (copyin(option_value, optval, (size_t)option_len)) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = EFAULT;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson goto done1;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson } else
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson option_len = 0;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = socket_setsockopt(so, level, option_name, optval,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson (t_uscalar_t)option_len, CRED());
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsondone1:
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (optval != buffer)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kmem_free(optval, (size_t)option_len);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsondone2:
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson releasef(sock);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (error)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (set_errno(error));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (0);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson}
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson/*
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * Add config info when name is non-NULL; delete info when name is NULL.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * name could be a device name or a module name and are user address.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonint
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonsockconfig(int family, int type, int protocol, char *name)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson{
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson char *kdevpath = NULL; /* Copied in devpath string */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson char *kmodule = NULL;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson size_t pathlen = 0;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson int error = 0;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson dprint(1, ("sockconfig(%d, %d, %d, %p)\n",
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson family, type, protocol, (void *)name));
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (secpolicy_net_config(CRED(), B_FALSE) != 0)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (set_errno(EPERM));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /*
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * By default set the kdevpath and kmodule to NULL to delete an entry.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * Otherwise when name is not NULL, set the kdevpath or kmodule
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * value to add an entry.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (name != NULL) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Adding an entry.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Copyin the name.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * This also makes it possible to check for too long pathnames.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * Compress the space needed for the name before passing it
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * to soconfig - soconfig will store the string until
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * the configuration is removed.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson char *buf;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if ((error = copyinstr(name, buf, MAXPATHLEN, &pathlen)) != 0) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson kmem_free(buf, MAXPATHLEN);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson goto done;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (strncmp(buf, "/dev", strlen("/dev")) == 0) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /* For device */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /*
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * Special handling for NCA:
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson *
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * DEV_NCA is never opened even if an application
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens * requests for AF_NCA. The device opened is instead a
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens * predefined AF_INET transport (NCA_INET_DEV).
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens *
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens * Prior to Volo (PSARC/2007/587) NCA would determine
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens * the device using a lookup, which worked then because
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens * all protocols were based on TPI. Since TPI is no
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * longer the default, we have to explicitly state
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * which device to use.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (strcmp(buf, NCA_DEV) == 0) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /* only support entry <28, 2, 0> */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (family != AF_NCA || type != SOCK_STREAM ||
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson protocol != 0) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson kmem_free(buf, MAXPATHLEN);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = EINVAL;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson goto done;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson pathlen = strlen(NCA_INET_DEV) + 1;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson kdevpath = kmem_alloc(pathlen, KM_SLEEP);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson bcopy(NCA_INET_DEV, kdevpath, pathlen);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kdevpath[pathlen - 1] = '\0';
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson } else {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kdevpath = kmem_alloc(pathlen, KM_SLEEP);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson bcopy(buf, kdevpath, pathlen);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson kdevpath[pathlen - 1] = '\0';
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson } else {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /* For socket module */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kmodule = kmem_alloc(pathlen, KM_SLEEP);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson bcopy(buf, kmodule, pathlen);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson kmodule[pathlen - 1] = '\0';
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick pathlen = 0;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (strcmp(kmodule, "tcp") == 0) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /* Get the tcp device name for fallback */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (family == 2) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson pathlen = strlen("/dev/tcp") + 1;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kdevpath = kmem_alloc(pathlen,
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick KM_SLEEP);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson bcopy("/dev/tcp", kdevpath,
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick pathlen);
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm kdevpath[pathlen - 1] = '\0';
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm } else {
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick ASSERT(family == 26);
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick pathlen = strlen("/dev/tcp6") + 1;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick kdevpath = kmem_alloc(pathlen,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson KM_SLEEP);
9eb57f7f3fbb970d4b9b89dcd5ecf543fe2414d5George Wilson bcopy("/dev/tcp6", kdevpath, pathlen);
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick kdevpath[pathlen - 1] = '\0';
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick }
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick } else if (strcmp(kmodule, "udp") == 0) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /* Get the udp device name for fallback */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (family == 2) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson pathlen = strlen("/dev/udp") + 1;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kdevpath = kmem_alloc(pathlen,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson KM_SLEEP);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson bcopy("/dev/udp", kdevpath, pathlen);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kdevpath[pathlen - 1] = '\0';
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson } else {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson ASSERT(family == 26);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson pathlen = strlen("/dev/udp6") + 1;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kdevpath = kmem_alloc(pathlen,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson KM_SLEEP);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson bcopy("/dev/udp6", kdevpath, pathlen);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kdevpath[pathlen - 1] = '\0';
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson } else if (strcmp(kmodule, "icmp") == 0) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /* Get the icmp device name for fallback */
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (family == 2) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson pathlen = strlen("/dev/rawip") + 1;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kdevpath = kmem_alloc(pathlen,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson KM_SLEEP);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson bcopy("/dev/rawip", kdevpath, pathlen);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kdevpath[pathlen - 1] = '\0';
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick } else {
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick ASSERT(family == 26);
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick pathlen = strlen("/dev/rawip6") + 1;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick kdevpath = kmem_alloc(pathlen,
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick KM_SLEEP);
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick bcopy("/dev/rawip6", kdevpath, pathlen);
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick kdevpath[pathlen - 1] = '\0';
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick }
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick }
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick }
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kmem_free(buf, MAXPATHLEN);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = soconfig(family, type, protocol, kdevpath, (int)pathlen,
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson kmodule);
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilsondone:
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if (error) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson eprintline(error);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (set_errno(error));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (0);
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson}
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson/*
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson * Sendfile is implemented through two schemes, direct I/O or by
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson * caching in the filesystem page cache. We cache the input file by
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * default and use direct I/O only if sendfile_max_size is set
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * appropriately as explained below. Note that this logic is consistent
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * with other filesystems where caching is turned on by default
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * unless explicitly turned off by using the DIRECTIO ioctl.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * We choose a slightly different scheme here. One can turn off
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * caching by setting sendfile_max_size to 0. One can also enable
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * caching of files <= sendfile_max_size by setting sendfile_max_size
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * to an appropriate value. By default sendfile_max_size is set to the
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * maximum value so that all files are cached. In future, we may provide
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * better interfaces for caching the file.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Sendfile through Direct I/O (Zero copy)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * --------------------------------------
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * As disks are normally slower than the network, we can't have a
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * single thread that reads the disk and writes to the network. We
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * need to have parallelism. This is done by having the sendfile
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * thread create another thread that reads from the filesystem
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * and queues it for network processing. In this scheme, the data
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * is never copied anywhere i.e it is zero copy unlike the other
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * scheme.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * We have a sendfile queue (snfq) where each sendfile
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * request (snf_req_t) is queued for processing by a thread. Number
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * of threads is dynamically allocated and they exit if they are idling
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * beyond a specified amount of time. When each request (snf_req_t) is
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * processed by a thread, it produces a number of mblk_t structures to
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * be consumed by the sendfile thread. snf_deque and snf_enque are
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * used for consuming and producing mblks. Size of the filesystem
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * read is determined by the tunable (sendfile_read_size). A single
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * mblk holds sendfile_read_size worth of data (except the last
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * read of the file) which is sent down as a whole to the network.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * sendfile_read_size is set to 1 MB as this seems to be the optimal
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * value for the UFS filesystem backed by a striped storage array.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Synchronisation between read (producer) and write (consumer) threads.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * --------------------------------------------------------------------
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * sr_lock protects sr_ib_head and sr_ib_tail. The lock is held while
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * adding and deleting items in this list. Error can happen anytime
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * during read or write. There could be unprocessed mblks in the
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * sr_ib_XXX list when a read or write error occurs. Whenever error
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * is encountered, we need two things to happen :
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * a) One of the threads need to clean the mblks.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * b) When one thread encounters an error, the other should stop.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * For (a), we don't want to penalize the reader thread as it could do
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * some useful work processing other requests. For (b), the error can
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * be detected by examining sr_read_error or sr_write_error.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * sr_lock protects sr_read_error and sr_write_error. If both reader and
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * writer encounters error, we need to report the write error back to
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * the application as that's what would have happened if the operations
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * were done sequentially. With this in mind, following should work :
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * - Check for errors before read or write.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * - If the reader encounters error, set the error in sr_read_error.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Check sr_write_error, if it is set, send cv_signal as it is
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * waiting for reader to complete. If it is not set, the writer
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * is either running sinking data to the network or blocked
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * because of flow control. For handling the latter case, we
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * always send a signal. In any case, it will examine sr_read_error
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * and return. sr_read_error is marked with SR_READ_DONE to tell
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * the writer that the reader is done in all the cases.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * - If the writer encounters error, set the error in sr_write_error.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * The reader thread is either blocked because of flow control or
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * running reading data from the disk. For the former, we need to
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * wakeup the thread. Again to keep it simple, we always wake up
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * the reader thread. Then, wait for the read thread to complete
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * if it is not done yet. Cleanup and return.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * High and low water marks for the read thread.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * --------------------------------------------
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * If sendfile() is used to send data over a slow network, we need to
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * make sure that the read thread does not produce data at a faster
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * rate than the network. This can happen if the disk is faster than
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * the network. In such a case, we don't want to build a very large queue.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * But we would still like to get all of the network throughput possible.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * This implies that network should never block waiting for data.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * As there are lot of disk throughput/network throughput combinations
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * possible, it is difficult to come up with an accurate number.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * A typical 10K RPM disk has a max seek latency 17ms and rotational
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * latency of 3ms for reading a disk block. Thus, the total latency to
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * initiate a new read, transfer data from the disk and queue for
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * transmission would take about a max of 25ms. Todays max transfer rate
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * for network is 100MB/sec. If the thread is blocked because of flow
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * control, it would take 25ms to get new data ready for transmission.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * We have to make sure that network is not idling, while we are initiating
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * new transfers. So, at 100MB/sec, to keep network busy we would need
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * 2.5MB of data. Rounding off, we keep the low water mark to be 3MB of data.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * We need to pick a high water mark so that the woken up thread would
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * do considerable work before blocking again to prevent thrashing. Currently,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * we pick this to be 10 times that of the low water mark.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Sendfile with segmap caching (One copy from page cache to mblks).
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * ----------------------------------------------------------------
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * We use the segmap cache for caching the file, if the size of file
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * is <= sendfile_max_size. In this case we don't use threads as VM
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * is reasonably fast enough to keep up with the network. If the underlying
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * transport allows, we call segmap_getmapflt() to map MAXBSIZE (8K) worth
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * of data into segmap space, and use the virtual address from segmap
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * directly through desballoc() to avoid copy. Once the transport is done
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * with the data, the mapping will be released through segmap_release()
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * called by the call-back routine.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * If zero-copy is not allowed by the transport, we simply call VOP_READ()
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * to copy the data from the filesystem into our temporary network buffer.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * To disable caching, set sendfile_max_size to 0.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonuint_t sendfile_read_size = 1024 * 1024;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson#define SENDFILE_REQ_LOWAT 3 * 1024 * 1024
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonuint_t sendfile_req_lowat = SENDFILE_REQ_LOWAT;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonuint_t sendfile_req_hiwat = 10 * SENDFILE_REQ_LOWAT;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonstruct sendfile_stats sf_stats;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonstruct sendfile_queue *snfq;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonclock_t snfq_timeout;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonoff64_t sendfile_max_size;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonstatic void snf_enque(snf_req_t *, mblk_t *);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonstatic mblk_t *snf_deque(snf_req_t *);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonvoid
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonsendfile_init(void)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson{
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson snfq = kmem_zalloc(sizeof (struct sendfile_queue), KM_SLEEP);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mutex_init(&snfq->snfq_lock, NULL, MUTEX_DEFAULT, NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson cv_init(&snfq->snfq_cv, NULL, CV_DEFAULT, NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson snfq->snfq_max_threads = max_ncpus;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson snfq_timeout = SNFQ_TIMEOUT;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /* Cache all files by default. */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson sendfile_max_size = MAXOFFSET_T;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson}
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson/*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Queues a mblk_t for network processing.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonstatic void
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonsnf_enque(snf_req_t *sr, mblk_t *mp)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson{
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mp->b_next = NULL;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mutex_enter(&sr->sr_lock);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (sr->sr_mp_head == NULL) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson sr->sr_mp_head = sr->sr_mp_tail = mp;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson cv_signal(&sr->sr_cv);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson } else {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson sr->sr_mp_tail->b_next = mp;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson sr->sr_mp_tail = mp;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson sr->sr_qlen += MBLKL(mp);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson while ((sr->sr_qlen > sr->sr_hiwat) &&
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson (sr->sr_write_error == 0)) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson sf_stats.ss_full_waits++;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson cv_wait(&sr->sr_cv, &sr->sr_lock);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mutex_exit(&sr->sr_lock);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson}
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson/*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * De-queues a mblk_t for network processing.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonstatic mblk_t *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonsnf_deque(snf_req_t *sr)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson{
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mblk_t *mp;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mutex_enter(&sr->sr_lock);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * If we have encountered an error on read or read is
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * completed and no more mblks, return NULL.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * We need to check for NULL sr_mp_head also as
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * the reads could have completed and there is
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * nothing more to come.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (((sr->sr_read_error & ~SR_READ_DONE) != 0) ||
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson ((sr->sr_read_error & SR_READ_DONE) &&
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson sr->sr_mp_head == NULL)) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mutex_exit(&sr->sr_lock);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson return (NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * To start with neither SR_READ_DONE is marked nor
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * the error is set. When we wake up from cv_wait,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * following are the possibilities :
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * a) sr_read_error is zero and mblks are queued.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * b) sr_read_error is set to SR_READ_DONE
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * and mblks are queued.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * c) sr_read_error is set to SR_READ_DONE
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * and no mblks.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * d) sr_read_error is set to some error other
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * than SR_READ_DONE.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson while ((sr->sr_read_error == 0) && (sr->sr_mp_head == NULL)) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson sf_stats.ss_empty_waits++;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson cv_wait(&sr->sr_cv, &sr->sr_lock);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /* Handle (a) and (b) first - the normal case. */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (((sr->sr_read_error & ~SR_READ_DONE) == 0) &&
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick (sr->sr_mp_head != NULL)) {
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick mp = sr->sr_mp_head;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick sr->sr_mp_head = mp->b_next;
09c9d376e8ccb8fbba74f33cc268964464092b62George Wilson sr->sr_qlen -= MBLKL(mp);
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick if (sr->sr_qlen < sr->sr_lowat)
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick cv_signal(&sr->sr_cv);
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick mutex_exit(&sr->sr_lock);
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm mp->b_next = NULL;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (mp);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /* Handle (c) and (d). */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson mutex_exit(&sr->sr_lock);
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley return (NULL);
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley}
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick/*
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson * Reads data from the filesystem and queues it for network processing.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwickvoid
44cd46cadd9aab751dae6a4023c1cb5bf316d274billmsnf_async_read(snf_req_t *sr)
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick{
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson size_t iosize;
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm u_offset_t fileoff;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick u_offset_t size;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick int ret_size;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick int error;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick file_t *fp;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick mblk_t *mp;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson struct vnode *vp;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick int extra = 0;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson int maxblk = 0;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson int wroff = 0;
5f5f7a6f9c8e9c1587a54e690556d756ec67558cahrens struct sonode *so;
5f5f7a6f9c8e9c1587a54e690556d756ec67558cahrens
5f5f7a6f9c8e9c1587a54e690556d756ec67558cahrens fp = sr->sr_fp;
5f5f7a6f9c8e9c1587a54e690556d756ec67558cahrens size = sr->sr_file_size;
5f5f7a6f9c8e9c1587a54e690556d756ec67558cahrens fileoff = sr->sr_file_off;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Ignore the error for filesystems that doesn't support DIRECTIO.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson (void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_ON, 0,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson kcred, NULL, NULL);
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick vp = sr->sr_vp;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick if (vp->v_type == VSOCK) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson stdata_t *stp;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Get the extra space to insert a header and a trailer.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson so = VTOSO(vp);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson stp = vp->v_stream;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (stp == NULL) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson wroff = so->so_proto_props.sopp_wroff;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson maxblk = so->so_proto_props.sopp_maxblk;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson extra = wroff + so->so_proto_props.sopp_tail;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson } else {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson wroff = (int)(stp->sd_wroff);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson maxblk = (int)(stp->sd_maxblk);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson extra = wroff + (int)(stp->sd_tail);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson while ((size != 0) && (sr->sr_write_error == 0)) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson iosize = (int)MIN(sr->sr_maxpsz, size);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * For sockets acting as an SSL proxy, we
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * need to adjust the size to the maximum
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * SSL record size set in the stream head.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (vp->v_type == VSOCK && !SOCK_IS_NONSTR(so) &&
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson SOTOTPI(so)->sti_kssl_ctx != NULL)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson iosize = (int)MIN(iosize, maxblk);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (is_system_labeled()) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson mp = allocb_cred(iosize + extra, CRED(),
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson curproc->p_pid);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson } else {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson mp = allocb(iosize + extra, BPRI_MED);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (mp == NULL) {
30beaff42d8240ebf5386e8b7a14e3d137a1631fGeorge Wilson error = EAGAIN;
30beaff42d8240ebf5386e8b7a14e3d137a1631fGeorge Wilson break;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson mp->b_rptr += wroff;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson ret_size = soreadfile(fp, mp->b_rptr, fileoff, &error, iosize);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /* Error or Reached EOF ? */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if ((error != 0) || (ret_size == 0)) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson freeb(mp);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson break;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson mp->b_wptr = mp->b_rptr + ret_size;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson snf_enque(sr, mp);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson size -= ret_size;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson fileoff += ret_size;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson (void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_OFF, 0,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson kcred, NULL, NULL);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson mutex_enter(&sr->sr_lock);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson sr->sr_read_error = error;
30beaff42d8240ebf5386e8b7a14e3d137a1631fGeorge Wilson sr->sr_read_error |= SR_READ_DONE;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson cv_signal(&sr->sr_cv);
30beaff42d8240ebf5386e8b7a14e3d137a1631fGeorge Wilson mutex_exit(&sr->sr_lock);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson}
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonvoid
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilsonsnf_async_thread(void)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson{
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson snf_req_t *sr;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson callb_cpr_t cprinfo;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson clock_t time_left = 1;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson CALLB_CPR_INIT(&cprinfo, &snfq->snfq_lock, callb_generic_cpr, "snfq");
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson mutex_enter(&snfq->snfq_lock);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson for (;;) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /*
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * If we didn't find a entry, then block until woken up
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * again and then look through the queues again.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson while ((sr = snfq->snfq_req_head) == NULL) {
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson CALLB_CPR_SAFE_BEGIN(&cprinfo);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (time_left <= 0) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson snfq->snfq_svc_threads--;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson CALLB_CPR_EXIT(&cprinfo);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson thread_exit();
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson /* NOTREACHED */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson snfq->snfq_idle_cnt++;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson time_left = cv_reltimedwait(&snfq->snfq_cv,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson &snfq->snfq_lock, snfq_timeout, TR_CLOCK_TICK);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson snfq->snfq_idle_cnt--;
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece CALLB_CPR_SAFE_END(&cprinfo, &snfq->snfq_lock);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson }
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson snfq->snfq_req_head = sr->sr_next;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson snfq->snfq_req_cnt--;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson mutex_exit(&snfq->snfq_lock);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson snf_async_read(sr);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson mutex_enter(&snfq->snfq_lock);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson }
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson}
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reecesnf_req_t *
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reececreate_thread(int operation, struct vnode *vp, file_t *fp,
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece u_offset_t fileoff, u_offset_t size)
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece{
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece snf_req_t *sr;
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece stdata_t *stp;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson sr = (snf_req_t *)kmem_zalloc(sizeof (snf_req_t), KM_SLEEP);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson sr->sr_vp = vp;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson sr->sr_fp = fp;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson stp = vp->v_stream;
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece /*
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece * store sd_qn_maxpsz into sr_maxpsz while we have stream head.
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson * stream might be closed before thread returns from snf_async_read.
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (stp != NULL && stp->sd_qn_maxpsz > 0) {
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson sr->sr_maxpsz = MIN(MAXBSIZE, stp->sd_qn_maxpsz);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson } else {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson sr->sr_maxpsz = MAXBSIZE;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson sr->sr_operation = operation;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson sr->sr_file_off = fileoff;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson sr->sr_file_size = size;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson sr->sr_hiwat = sendfile_req_hiwat;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson sr->sr_lowat = sendfile_req_lowat;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson mutex_init(&sr->sr_lock, NULL, MUTEX_DEFAULT, NULL);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson cv_init(&sr->sr_cv, NULL, CV_DEFAULT, NULL);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson /*
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson * See whether we need another thread for servicing this
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson * request. If there are already enough requests queued
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson * for the threads, create one if not exceeding
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson * snfq_max_threads.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson mutex_enter(&snfq->snfq_lock);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson if (snfq->snfq_req_cnt >= snfq->snfq_idle_cnt &&
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson snfq->snfq_svc_threads < snfq->snfq_max_threads) {
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece (void) thread_create(NULL, 0, &snf_async_thread, 0, 0, &p0,
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece TS_RUN, minclsyspri);
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece snfq->snfq_svc_threads++;
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece }
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece if (snfq->snfq_req_head == NULL) {
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece snfq->snfq_req_head = snfq->snfq_req_tail = sr;
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece cv_signal(&snfq->snfq_cv);
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece } else {
2a104a5236475eb73aa41eaaf3ed9f3ccbe0ca55Alex Reece snfq->snfq_req_tail->sr_next = sr;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson snfq->snfq_req_tail = sr;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson }
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson snfq->snfq_req_cnt++;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson mutex_exit(&snfq->snfq_lock);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson return (sr);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson}
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilsonint
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilsonsnf_direct_io(file_t *fp, file_t *rfp, u_offset_t fileoff, u_offset_t size,
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson ssize_t *count)
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson{
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson snf_req_t *sr;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson mblk_t *mp;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson int iosize;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson int error = 0;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson short fflag;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson struct vnode *vp;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson int ksize;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson struct nmsghdr msg;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
daec38ecb4fb5e73e4ca9e99be84f6b8c50c02faJoe Stein ksize = 0;
daec38ecb4fb5e73e4ca9e99be84f6b8c50c02faJoe Stein *count = 0;
daec38ecb4fb5e73e4ca9e99be84f6b8c50c02faJoe Stein bzero(&msg, sizeof (msg));
daec38ecb4fb5e73e4ca9e99be84f6b8c50c02faJoe Stein
daec38ecb4fb5e73e4ca9e99be84f6b8c50c02faJoe Stein vp = fp->f_vnode;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson fflag = fp->f_flag;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson if ((sr = create_thread(READ_OP, vp, rfp, fileoff, size)) == NULL)
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson return (EAGAIN);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson /*
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * We check for read error in snf_deque. It has to check
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson * for successful READ_DONE and return NULL, and we might
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson * as well make an additional check there.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson while ((mp = snf_deque(sr)) != NULL) {
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (ISSIG(curthread, JUSTLOOKING)) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson freeb(mp);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson error = EINTR;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson break;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson iosize = MBLKL(mp);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson if (error != 0) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (mp != NULL)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson freeb(mp);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson break;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson ksize += iosize;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson *count = ksize;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson mutex_enter(&sr->sr_lock);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson sr->sr_write_error = error;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson /* Look at the big comments on why we cv_signal here. */
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson cv_signal(&sr->sr_cv);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /* Wait for the reader to complete always. */
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson while (!(sr->sr_read_error & SR_READ_DONE)) {
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson cv_wait(&sr->sr_cv, &sr->sr_lock);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson /* If there is no write error, check for read error. */
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson if (error == 0)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson error = (sr->sr_read_error & ~SR_READ_DONE);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson if (error != 0) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson mblk_t *next_mp;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson mp = sr->sr_mp_head;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson while (mp != NULL) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson next_mp = mp->b_next;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson mp->b_next = NULL;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson freeb(mp);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson mp = next_mp;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson mutex_exit(&sr->sr_lock);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson kmem_free(sr, sizeof (snf_req_t));
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson return (error);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson}
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson/* Maximum no.of pages allocated by vpm for sendfile at a time */
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson#define SNF_VPMMAXPGS (VPMMAXPGS/2)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson/*
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson * Maximum no.of elements in the list returned by vpm, including
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson * NULL for the last entry
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define SNF_MAXVMAPS (SNF_VPMMAXPGS + 1)
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrenstypedef struct {
fa9e4066f08beec538e775443c5be79dd423fcabahrens unsigned int snfv_ref;
fa9e4066f08beec538e775443c5be79dd423fcabahrens frtn_t snfv_frtn;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson vnode_t *snfv_vp;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson struct vmap snfv_vml[SNF_MAXVMAPS];
fa9e4066f08beec538e775443c5be79dd423fcabahrens} snf_vmap_desbinfo;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsontypedef struct {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson frtn_t snfi_frtn;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson caddr_t snfi_base;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson uint_t snfi_mapoff;
fa9e4066f08beec538e775443c5be79dd423fcabahrens size_t snfi_len;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson vnode_t *snfi_vp;
fa9e4066f08beec538e775443c5be79dd423fcabahrens} snf_smap_desbinfo;
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson/*
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson * The callback function used for vpm mapped mblks called when the last ref of
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson * the mblk is dropped which normally occurs when TCP receives the ack. But it
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson * can be the driver too due to lazy reclaim.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsonvoid
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilsonsnf_vmap_desbfree(snf_vmap_desbinfo *snfv)
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson{
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson ASSERT(snfv->snfv_ref != 0);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (atomic_add_32_nv(&snfv->snfv_ref, -1) == 0) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson vpm_unmap_pages(snfv->snfv_vml, S_READ);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson VN_RELE(snfv->snfv_vp);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson kmem_free(snfv, sizeof (snf_vmap_desbinfo));
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson}
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson/*
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * The callback function used for segmap'ped mblks called when the last ref of
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * the mblk is dropped which normally occurs when TCP receives the ack. But it
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson * can be the driver too due to lazy reclaim.
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson */
468c413a79615e77179e8d98f22a7e513a8135bdTim Haleyvoid
fa9e4066f08beec538e775443c5be79dd423fcabahrenssnf_smap_desbfree(snf_smap_desbinfo *snfi)
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick{
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick if (! IS_KPM_ADDR(snfi->snfi_base)) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /*
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * We don't need to call segmap_fault(F_SOFTUNLOCK) for
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * segmap_kpm as long as the latter never falls back to
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * "use_segmap_range". (See segmap_getmapflt().)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson *
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * Using S_OTHER saves an redundant hat_setref() in
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick * segmap_unlock()
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley */
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley (void) segmap_fault(kas.a_hat, segkmap,
fa9e4066f08beec538e775443c5be79dd423fcabahrens (caddr_t)(uintptr_t)(((uintptr_t)snfi->snfi_base +
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson snfi->snfi_mapoff) & PAGEMASK), snfi->snfi_len,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson F_SOFTUNLOCK, S_OTHER);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson (void) segmap_release(segkmap, snfi->snfi_base, SM_DONTNEED);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson VN_RELE(snfi->snfi_vp);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson kmem_free(snfi, sizeof (*snfi));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson}
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson/*
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * Use segmap or vpm instead of bcopy to send down a desballoca'ed, mblk.
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick * When segmap is used, the mblk contains a segmap slot of no more
fa9e4066f08beec538e775443c5be79dd423fcabahrens * than MAXBSIZE.
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley *
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley * With vpm, a maximum of SNF_MAXVMAPS page-sized mappings can be obtained
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens * in each iteration and sent by socket_sendmblk until an error occurs or
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * the requested size has been transferred. An mblk is esballoca'ed from
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens * each mapped page and a chain of these mblk is sent to the transport layer.
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens * vpm will be called to unmap the pages when all mblks have been freed by
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens * free_func.
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens *
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens * At the end of the whole sendfile() operation, we wait till the data from
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens * the last mblk is ack'ed by the transport before returning so that the
b1be2892dd07cf9a97d47ad06334cdc879196aafMatthew Ahrens * caller of sendfile() can safely modify the file content.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilsonint
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilsonsnf_segmap(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t total_size,
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson ssize_t *count, boolean_t nowait)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson{
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson caddr_t base;
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson int mapoff;
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley vnode_t *vp;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson mblk_t *mp = NULL;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson int chain_size;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson int error;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson short fflag;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson int ksize;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson struct vattr va;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson boolean_t dowait = B_FALSE;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson struct nmsghdr msg;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson vp = fp->f_vnode;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson fflag = fp->f_flag;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson ksize = 0;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson bzero(&msg, sizeof (msg));
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson for (;;) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (ISSIG(curthread, JUSTLOOKING)) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson error = EINTR;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson break;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (vpm_enable) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson snf_vmap_desbinfo *snfv;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mblk_t *nmp;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson int mblk_size;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson int maxsize;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson int i;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mapoff = fileoff & PAGEOFFSET;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson maxsize = MIN((SNF_VPMMAXPGS * PAGESIZE), total_size);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson snfv = kmem_zalloc(sizeof (snf_vmap_desbinfo),
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson KM_SLEEP);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /* Get vpm mappings for maxsize with read access */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (vpm_map_pages(fvp, fileoff, (size_t)maxsize,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson (VPM_FETCHPAGE), snfv->snfv_vml, SNF_MAXVMAPS,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson NULL, S_READ) != 0) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson kmem_free(snfv, sizeof (snf_vmap_desbinfo));
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = EIO;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson goto out;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson snfv->snfv_frtn.free_func = snf_vmap_desbfree;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson snfv->snfv_frtn.free_arg = (caddr_t)snfv;
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Construct the mblk chain from the page mappings */
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson chain_size = 0;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson for (i = 0; (snfv->snfv_vml[i].vs_addr != NULL) &&
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson total_size > 0; i++) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson ASSERT(chain_size < maxsize);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson mblk_size = MIN(snfv->snfv_vml[i].vs_len -
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson mapoff, total_size);
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson nmp = esballoca(
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson (uchar_t *)snfv->snfv_vml[i].vs_addr +
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson mapoff, mblk_size, BPRI_HI,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson &snfv->snfv_frtn);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson /*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * We return EAGAIN after unmapping the pages
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * if we cannot allocate the the head of the
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * chain. Otherwise, we continue sending the
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * mblks constructed so far.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (nmp == NULL) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (i == 0) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson vpm_unmap_pages(snfv->snfv_vml,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson S_READ);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson kmem_free(snfv,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson sizeof (snf_vmap_desbinfo));
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson error = EAGAIN;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick goto out;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Mark this dblk with the zero-copy flag */
fa9e4066f08beec538e775443c5be79dd423fcabahrens nmp->b_datap->db_struioflag |= STRUIO_ZC;
fa9e4066f08beec538e775443c5be79dd423fcabahrens nmp->b_wptr += mblk_size;
fa9e4066f08beec538e775443c5be79dd423fcabahrens chain_size += mblk_size;
fa9e4066f08beec538e775443c5be79dd423fcabahrens fileoff += mblk_size;
fa9e4066f08beec538e775443c5be79dd423fcabahrens total_size -= mblk_size;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick snfv->snfv_ref++;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick mapoff = 0;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (i > 0)
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson linkb(mp, nmp);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson else
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley mp = nmp;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
fa9e4066f08beec538e775443c5be79dd423fcabahrens VN_HOLD(fvp);
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson snfv->snfv_vp = fvp;
88ecc943b4eb72f7c4fbbd8435997b85ef171fc3George Wilson } else {
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* vpm not supported. fallback to segmap */
fa9e4066f08beec538e775443c5be79dd423fcabahrens snf_smap_desbinfo *snfi;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick mapoff = fileoff & MAXBOFFSET;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson chain_size = MAXBSIZE - mapoff;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (chain_size > total_size)
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick chain_size = total_size;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /*
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley * we don't forcefault because we'll call
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * segmap_fault(F_SOFTLOCK) next.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson *
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * S_READ will get the ref bit set (by either
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * segmap_getmapflt() or segmap_fault()) and page
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * shared locked.
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson base = segmap_getmapflt(segkmap, fvp, fileoff,
fa9e4066f08beec538e775443c5be79dd423fcabahrens chain_size, segmap_kpm ? SM_FAULT : 0, S_READ);
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson snfi = kmem_alloc(sizeof (*snfi), KM_SLEEP);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson snfi->snfi_len = (size_t)roundup(mapoff+chain_size,
16a4a8074274d2d7cc408589cf6359f4a378c861George Wilson PAGESIZE)- (mapoff & PAGEMASK);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /*
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * We must call segmap_fault() even for segmap_kpm
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * because that's how error gets returned.
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley * (segmap_getmapflt() never fails but segmap_fault()
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson * does.)
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (segmap_fault(kas.a_hat, segkmap,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson (caddr_t)(uintptr_t)(((uintptr_t)base + mapoff) &
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson PAGEMASK), snfi->snfi_len,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson F_SOFTLOCK, S_READ) != 0) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson (void) segmap_release(segkmap, base, 0);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson kmem_free(snfi, sizeof (*snfi));
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = EIO;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson goto out;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson snfi->snfi_frtn.free_func = snf_smap_desbfree;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson snfi->snfi_frtn.free_arg = (caddr_t)snfi;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson snfi->snfi_base = base;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson snfi->snfi_mapoff = mapoff;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mp = esballoca((uchar_t *)base + mapoff, chain_size,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson BPRI_HI, &snfi->snfi_frtn);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (mp == NULL) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson (void) segmap_fault(kas.a_hat, segkmap,
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley (caddr_t)(uintptr_t)(((uintptr_t)base +
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick mapoff) & PAGEMASK), snfi->snfi_len,
fa9e4066f08beec538e775443c5be79dd423fcabahrens F_SOFTUNLOCK, S_OTHER);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson (void) segmap_release(segkmap, base, 0);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson kmem_free(snfi, sizeof (*snfi));
fa9e4066f08beec538e775443c5be79dd423fcabahrens freemsg(mp);
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick error = EAGAIN;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson goto out;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick }
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick VN_HOLD(fvp);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson snfi->snfi_vp = fvp;
9eb57f7f3fbb970d4b9b89dcd5ecf543fe2414d5George Wilson mp->b_wptr += chain_size;
9eb57f7f3fbb970d4b9b89dcd5ecf543fe2414d5George Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /* Mark this dblk with the zero-copy flag */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson mp->b_datap->db_struioflag |= STRUIO_ZC;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson fileoff += chain_size;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson total_size -= chain_size;
9eb57f7f3fbb970d4b9b89dcd5ecf543fe2414d5George Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (total_size == 0 && !nowait) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson ASSERT(!dowait);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson dowait = B_TRUE;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mp->b_datap->db_struioflag |= STRUIO_ZCNOTIFY;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (error != 0) {
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson /*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * mp contains the mblks that were not sent by
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley * socket_sendmblk. Use its size to update *count
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley */
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson *count = ksize + (chain_size - msgdsize(mp));
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley if (mp != NULL)
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley freemsg(mp);
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley return (error);
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley }
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley ksize += chain_size;
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley if (total_size == 0)
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley goto done;
468c413a79615e77179e8d98f22a7e513a8135bdTim Haley
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson (void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson va.va_mask = AT_SIZE;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (error)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson break;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /* Read as much as possible. */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (fileoff >= va.va_size)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson break;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (total_size + fileoff > va.va_size)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson total_size = va.va_size - fileoff;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonout:
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsondone:
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson *count = ksize;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson if (dowait) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens stdata_t *stp;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson stp = vp->v_stream;
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (stp == NULL) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct sonode *so;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick so = VTOSO(vp);
fa9e4066f08beec538e775443c5be79dd423fcabahrens error = so_zcopy_wait(so);
fa9e4066f08beec538e775443c5be79dd423fcabahrens } else {
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson mutex_enter(&stp->sd_lock);
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson while (!(stp->sd_flag & STZCNOTIFY)) {
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson if (cv_wait_sig(&stp->sd_zcopy_wait,
22e30981d82a0b6dc89253596ededafae8655e00George Wilson &stp->sd_lock) == 0) {
2e4c998613148111f2fc5371085331ffb39122ffGeorge Wilson error = EINTR;
09c9d376e8ccb8fbba74f33cc268964464092b62George Wilson break;
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson }
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson }
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson stp->sd_flag &= ~STZCNOTIFY;
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson mutex_exit(&stp->sd_lock);
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson }
80eb36f241abf8c076119fb4c49a55fd61ebc710George Wilson }
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm return (error);
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm}
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm
44cd46cadd9aab751dae6a4023c1cb5bf316d274billmint
44cd46cadd9aab751dae6a4023c1cb5bf316d274billmsnf_cache(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t size,
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson uint_t maxpsz, ssize_t *count)
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm{
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm struct vnode *vp;
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm mblk_t *mp;
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm int iosize;
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm int extra = 0;
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm int error;
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm short fflag;
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm int ksize;
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm int ioflag;
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm struct uio auio;
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm struct iovec aiov;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson struct vattr va;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson int maxblk = 0;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson int wroff = 0;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson struct sonode *so;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson struct nmsghdr msg;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson vp = fp->f_vnode;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (vp->v_type == VSOCK) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson stdata_t *stp;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Get the extra space to insert a header and a trailer.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson so = VTOSO(vp);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson stp = vp->v_stream;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (stp == NULL) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson wroff = so->so_proto_props.sopp_wroff;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson maxblk = so->so_proto_props.sopp_maxblk;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson extra = wroff + so->so_proto_props.sopp_tail;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson } else {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson wroff = (int)(stp->sd_wroff);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson maxblk = (int)(stp->sd_maxblk);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson extra = wroff + (int)(stp->sd_tail);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson bzero(&msg, sizeof (msg));
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson fflag = fp->f_flag;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson ksize = 0;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson auio.uio_iov = &aiov;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson auio.uio_iovcnt = 1;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson auio.uio_segflg = UIO_SYSSPACE;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson auio.uio_llimit = MAXOFFSET_T;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson auio.uio_fmode = fflag;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson auio.uio_extflg = UIO_COPY_CACHED;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson ioflag = auio.uio_fmode & (FSYNC|FDSYNC|FRSYNC);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /* If read sync is not asked for, filter sync flags */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if ((ioflag & FRSYNC) == 0)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson ioflag &= ~(FSYNC|FDSYNC);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson for (;;) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (ISSIG(curthread, JUSTLOOKING)) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = EINTR;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson break;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson iosize = (int)MIN(maxpsz, size);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * For sockets acting as an SSL proxy, we
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * need to adjust the size to the maximum
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * SSL record size set in the stream head.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (vp->v_type == VSOCK && !SOCK_IS_NONSTR(so) &&
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson SOTOTPI(so)->sti_kssl_ctx != NULL)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson iosize = (int)MIN(iosize, maxblk);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (is_system_labeled()) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mp = allocb_cred(iosize + extra, CRED(),
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson curproc->p_pid);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson } else {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mp = allocb(iosize + extra, BPRI_MED);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (mp == NULL) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = EAGAIN;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson break;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mp->b_rptr += wroff;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson aiov.iov_base = (caddr_t)mp->b_rptr;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson aiov.iov_len = iosize;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson auio.uio_loffset = fileoff;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson auio.uio_resid = iosize;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = VOP_READ(fvp, &auio, ioflag, fp->f_cred, NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson iosize -= auio.uio_resid;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (error == EINTR && iosize != 0)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = 0;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (error != 0 || iosize == 0) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson freeb(mp);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson break;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson mp->b_wptr = mp->b_rptr + iosize;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (error != 0) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *count = ksize;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (mp != NULL)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson freeb(mp);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson return (error);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson ksize += iosize;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson size -= iosize;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (size == 0)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson goto done;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson fileoff += iosize;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson (void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson va.va_mask = AT_SIZE;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (error)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson break;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /* Read as much as possible. */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (fileoff >= va.va_size)
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson size = 0;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson else if (size + fileoff > va.va_size)
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson size = va.va_size - fileoff;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson }
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilsondone:
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson *count = ksize;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson return (error);
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson}
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson#if defined(_SYSCALL32_IMPL) || defined(_ILP32)
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson/*
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson * Largefile support for 32 bit applications only.
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson */
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilsonint
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilsonsosendfile64(file_t *fp, file_t *rfp, const struct ksendfilevec64 *sfv,
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson ssize32_t *count32)
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson{
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson ssize32_t sfv_len;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson u_offset_t sfv_off, va_size;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson struct vnode *vp, *fvp, *realvp;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson struct vattr va;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson stdata_t *stp;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson ssize_t count = 0;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson int error = 0;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson boolean_t dozcopy = B_FALSE;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson uint_t maxpsz;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson sfv_len = (ssize32_t)sfv->sfv_len;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson if (sfv_len < 0) {
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson error = EINVAL;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson goto out;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson }
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson if (sfv_len == 0) goto out;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson sfv_off = (u_offset_t)sfv->sfv_off;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson /* Same checks as in pread */
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson if (sfv_off > MAXOFFSET_T) {
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson error = EINVAL;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson goto out;
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson }
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson if (sfv_off + sfv_len > MAXOFFSET_T)
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson sfv_len = (ssize32_t)(MAXOFFSET_T - sfv_off);
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson /*
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson * There are no more checks on sfv_len. So, we cast it to
0f7643c7376dd69a08acbfc9d1d7d548b10c846aGeorge Wilson * u_offset_t and share the snf_direct_io/snf_cache code between
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm * 32 bit and 64 bit.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * TODO: should do nbl_need_check() like read()?
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (sfv_len > sendfile_max_size) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson sf_stats.ss_file_not_cached++;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = snf_direct_io(fp, rfp, sfv_off, (u_offset_t)sfv_len,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson &count);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson goto out;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson fvp = rfp->f_vnode;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (VOP_REALVP(fvp, &realvp, NULL) == 0)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson fvp = realvp;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Grab the lock as a reader to prevent the file size
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * from changing underneath.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson (void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson va.va_mask = AT_SIZE;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson va_size = va.va_size;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if ((error != 0) || (va_size == 0) || (sfv_off >= va_size)) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson goto out;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /* Read as much as possible. */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (sfv_off + sfv_len > va_size)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson sfv_len = va_size - sfv_off;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson vp = fp->f_vnode;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson stp = vp->v_stream;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * When the NOWAIT flag is not set, we enable zero-copy only if the
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * transfer size is large enough. This prevents performance loss
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * when the caller sends the file piece by piece.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (sfv_len >= MAXBSIZE && (sfv_len >= (va_size >> 1) ||
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson (sfv->sfv_flag & SFV_NOWAIT) || sfv_len >= 0x1000000) &&
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson !vn_has_flocks(fvp) && !(fvp->v_flag & VNOMAP)) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson uint_t copyflag;
fa9e4066f08beec538e775443c5be79dd423fcabahrens copyflag = stp != NULL ? stp->sd_copyflag :
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick VTOSO(vp)->so_proto_props.sopp_zcopyflag;
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick if ((copyflag & (STZCVMSAFE|STZCVMUNSAFE)) == 0) {
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm int on = 1;
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm if (socket_setsockopt(VTOSO(vp), SOL_SOCKET,
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm SO_SND_COPYAVOID, &on, sizeof (on), CRED()) == 0)
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm dozcopy = B_TRUE;
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson } else {
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson dozcopy = copyflag & STZCVMSAFE;
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm }
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson }
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson if (dozcopy) {
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson sf_stats.ss_file_segmap++;
fa9e4066f08beec538e775443c5be79dd423fcabahrens error = snf_segmap(fp, fvp, sfv_off, (u_offset_t)sfv_len,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson &count, ((sfv->sfv_flag & SFV_NOWAIT) != 0));
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson } else {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (vp->v_type == VSOCK && stp == NULL) {
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick sonode_t *so = VTOSO(vp);
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson maxpsz = so->so_proto_props.sopp_maxpsz;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson } else if (stp != NULL) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson maxpsz = stp->sd_qn_maxpsz;
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson } else {
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick maxpsz = maxphys;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (maxpsz == INFPSZ)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson maxpsz = maxphys;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson else
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson maxpsz = roundup(maxpsz, MAXBSIZE);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson sf_stats.ss_file_cached++;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson error = snf_cache(fp, fvp, sfv_off, (u_offset_t)sfv_len,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson maxpsz, &count);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonout:
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson releasef(sfv->sfv_fd);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson *count32 = (ssize32_t)count;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson return (error);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson}
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson#endif
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson#ifdef _SYSCALL32_IMPL
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson/*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * recv32(), recvfrom32(), send32(), sendto32(): intentionally return a
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * ssize_t rather than ssize32_t; see the comments above read32 for details.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonssize_t
44cd46cadd9aab751dae6a4023c1cb5bf316d274billmrecv32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags)
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilson{
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilson return (recv(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags));
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilson}
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilson
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsonssize_t
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilsonrecvfrom32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags,
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilson caddr32_t name, caddr32_t namelenp)
d6e555bdd793b8bc8fe57d5f12c3d69c813d0661George Wilson{
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm return (recvfrom(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags,
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm (void *)(uintptr_t)name, (void *)(uintptr_t)namelenp));
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm}
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsonssize_t
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilsonsend32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags)
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm{
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson return (send(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags));
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm}
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm
44cd46cadd9aab751dae6a4023c1cb5bf316d274billmssize_t
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonsendto32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags,
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm caddr32_t name, socklen_t namelen)
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm{
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick return (sendto(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags,
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick (void *)(uintptr_t)name, namelen));
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson}
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson#endif /* _SYSCALL32_IMPL */
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson/*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Function wrappers (mostly around the sonode switch) for
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * backward compatibility.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
22e30981d82a0b6dc89253596ededafae8655e00George Wilson
22e30981d82a0b6dc89253596ededafae8655e00George Wilsonint
aeb1c1b609b02f03e8e7448beb88384ebc713525gwsoaccept(struct sonode *so, int fflag, struct sonode **nsop)
aeb1c1b609b02f03e8e7448beb88384ebc713525gw{
aeb1c1b609b02f03e8e7448beb88384ebc713525gw return (socket_accept(so, fflag, CRED(), nsop));
aeb1c1b609b02f03e8e7448beb88384ebc713525gw}
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonint
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonsobind(struct sonode *so, struct sockaddr *name, socklen_t namelen,
aeb1c1b609b02f03e8e7448beb88384ebc713525gw int backlog, int flags)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson{
aeb1c1b609b02f03e8e7448beb88384ebc713525gw int error;
aeb1c1b609b02f03e8e7448beb88384ebc713525gw
aeb1c1b609b02f03e8e7448beb88384ebc713525gw error = socket_bind(so, name, namelen, flags, CRED());
aeb1c1b609b02f03e8e7448beb88384ebc713525gw if (error == 0 && backlog != 0)
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm return (socket_listen(so, backlog, CRED()));
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm return (error);
5f5f7a6f9c8e9c1587a54e690556d756ec67558cahrens}
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm
44cd46cadd9aab751dae6a4023c1cb5bf316d274billmint
44cd46cadd9aab751dae6a4023c1cb5bf316d274billmsolisten(struct sonode *so, int backlog)
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm{
09c9d376e8ccb8fbba74f33cc268964464092b62George Wilson return (socket_listen(so, backlog, CRED()));
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensint
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonsoconnect(struct sonode *so, const struct sockaddr *name, socklen_t namelen,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson int fflag, int flags)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson{
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson return (socket_connect(so, name, namelen, fflag, flags, CRED()));
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson}
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonint
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonsorecvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson{
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson return (socket_recvmsg(so, msg, uiop, CRED()));
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson}
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonint
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonsosendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson{
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick return (socket_sendmsg(so, msg, uiop, CRED()));
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilson}
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilson
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilsonint
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilsonsoshutdown(struct sonode *so, int how)
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilson{
0713e232b7712cd27d99e1e935ebb8d5de61c57dGeorge Wilson return (socket_shutdown(so, how, CRED()));
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson}
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilsonint
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilsonsogetsockopt(struct sonode *so, int level, int option_name, void *optval,
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilson socklen_t *optlenp, int flags)
03f8c366886542ed249a15d755ae78ea4e775d9dGeorge Wilson{
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson return (socket_getsockopt(so, level, option_name, optval, optlenp,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson flags, CRED()));
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson}
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonint
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonsosetsockopt(struct sonode *so, int level, int option_name, const void *optval,
ecc2d604e885a75cc75e647b5641af99d5a6f4a6bonwick t_uscalar_t optlen)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson{
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson return (socket_setsockopt(so, level, option_name, optval, optlen,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson CRED()));
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson}
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson/*
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * Because this is backward compatibility interface it only needs to be
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson * able to handle the creation of TPI sockfs sockets.
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonstruct sonode *
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilsonsocreate(struct sockparams *sp, int family, int type, int protocol, int version,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson int *errorp)
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson{
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson struct sonode *so;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson ASSERT(sp != NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson so = sp->sp_smod_info->smod_sock_create_func(sp, family, type, protocol,
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson version, SOCKET_SLEEP, errorp, CRED());
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if (so == NULL) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson SOCKPARAMS_DEC_REF(sp);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson } else {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson if ((*errorp = SOP_INIT(so, NULL, CRED(), SOCKET_SLEEP)) == 0) {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson /* Cannot fail, only bumps so_count */
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson (void) VOP_OPEN(&SOTOV(so), FREAD|FWRITE, CRED(), NULL);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson } else {
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson socket_destroy(so);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson so = NULL;
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson }
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson return (so);
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson}
8363e80ae72609660f6090766ca8c2c18aa53f0cGeorge Wilson