xref: /illumos-gate/usr/src/uts/common/rpc/svc_gen.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  *  Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  *  Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved	*/
29 
30 /*
31  * Portions of this source code were derived from Berkeley 4.3 BSD
32  * under license from the Regents of the University of California.
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 #include <sys/types.h>
38 #include <sys/sysmacros.h>
39 #include <sys/param.h>
40 #include <sys/cmn_err.h>
41 #include <sys/debug.h>
42 #include <rpc/types.h>
43 #include <netinet/in.h>
44 #include <rpc/auth.h>
45 #include <rpc/clnt.h>
46 #include <sys/tiuser.h>
47 #include <sys/t_kuser.h>
48 #include <rpc/svc.h>
49 #include <sys/file.h>
50 #include <sys/user.h>
51 #include <sys/stream.h>
52 #include <sys/strsubr.h>
53 #include <sys/stropts.h>
54 #include <sys/tihdr.h>
55 #include <sys/timod.h>
56 #include <sys/sunddi.h>
57 #include <sys/fcntl.h>
58 #include <sys/errno.h>
59 
60 /*
61  * Create server-side kernel RPC `master' transport handle
62  *
63  * This is public interface for creation of a server RPC transport handle
64  * for a given file descriptor. This function is called from nfs_svc()
65  * and lm_svc().
66  *
67  * PSARC 2003/523 Contract Private Interface
68  * svc_tli_kcreate
69  * Changes must be reviewed by Solaris File Sharing
70  * Changes must be communicated to contract-2003-523@sun.com
71  *
72  * Arguments:
73  * - fp		 - connection end point
74  * - max_msgsize - max receive size
75  * - netid	 - netid
76  * - addrmask	 - address mask
77  * - nxprt       - filled with outgoing transport handle
78  * - sct	 - callout table to be registered with this transport handle
79  * - closeproc	 - optional pointer to a closeproc for this transport or NULL
80  * - id	         - RPC pool id (currently only NFS_SVCPOOL_ID or LM_SVCPOOL_ID)
81  * - hotstream	 - very MT-hot flag (TRUE for NFS, FALSE for Lock Manager)
82  *
83  * Description:
84  * - make sure rpcmod is on the stream
85  * - call T_INFO_REQ to get the transport service type info
86  * - call transport-type specific `create' routine (svc_clts_kcreate(),
87  *   svc_cots_kcreate()) to create and initialize transport for the stream
88  * - call svc_xprt_register() to register the transport handle into the
89  *   service thread pool
90  * - initialize transport-type independent fields (synchronization objects,
91  *   thread counts, callout table, closeproc)
92  * - optionally, for CLTS transports tell streams framework that the
93  *   stream can be MT-hot
94  * - call transport-type specific `start' function to tell rpcmod that
95  *   the transport is ready to receive.
96  */
97 int
98 svc_tli_kcreate(
99 	struct file	*fp,		/* connection end point */
100 	uint_t		max_msgsize,	/* max receive size */
101 	char		*netid,
102 	struct netbuf	*addrmask,
103 	SVCMASTERXPRT	**nxprt,
104 	SVC_CALLOUT_TABLE *sct,
105 	void		(*closeproc)(const SVCMASTERXPRT *),
106 	int		id,		/* thread pool  */
107 	bool_t		hotstream)
108 {
109 	queue_t		*wq;
110 	SVCMASTERXPRT	*xprt = NULL;	/* service handle */
111 	int		retval;
112 	struct strioctl strioc;
113 	struct T_info_ack tinfo;
114 	int		error;
115 	void		**vp;
116 	major_t		udpmaj;
117 
118 	RPCLOG(16, "svc_tli_kcreate: on file %p\n", (void *)fp);
119 
120 	if (fp == NULL || nxprt == NULL)
121 		return (EINVAL);
122 
123 	if (fp->f_vnode->v_stream == NULL)
124 		return (ENOSTR);
125 
126 	/*
127 	 * Make sure that an RPC interface module is on the stream.
128 	 */
129 	wq = fp->f_vnode->v_stream->sd_wrq;
130 	while ((wq = wq->q_next) != NULL) {
131 		if (strcmp(wq->q_qinfo->qi_minfo->mi_idname, "rpcmod") == 0)
132 			break;
133 	}
134 	if (!wq) {
135 		RPCLOG0(1, "svc_tli_kcreate: no RPC module on stream\n");
136 		return (EINVAL);
137 	}
138 
139 	/*
140 	 * Find out what type of transport this is.
141 	 */
142 	strioc.ic_cmd = TI_GETINFO;
143 	strioc.ic_timout = -1;
144 	strioc.ic_len = sizeof (tinfo);
145 	strioc.ic_dp = (char *)&tinfo;
146 	tinfo.PRIM_type = T_INFO_REQ;
147 
148 	error = strioctl(fp->f_vnode, I_STR, (intptr_t)&strioc, 0, K_TO_K,
149 	    CRED(), &retval);
150 	if (error || retval) {
151 		RPCLOG(1, "svc_tli_kcreate: getinfo ioctl: %d\n", error);
152 		return (error);
153 	}
154 
155 	/*
156 	 * Call transport-type specific `create' function.
157 	 * It will allocate transport structure.
158 	 */
159 	switch (tinfo.SERV_type) {
160 	case T_CLTS:
161 		error = svc_clts_kcreate(fp, max_msgsize, &tinfo, &xprt);
162 		break;
163 	case T_COTS:
164 	case T_COTS_ORD:
165 		error = svc_cots_kcreate(fp, max_msgsize, &tinfo, &xprt);
166 		break;
167 	default:
168 		RPCLOG(1, "svc_tli_kcreate: Bad service type %d\n",
169 		    tinfo.SERV_type);
170 		error = EINVAL;
171 	}
172 	if (error)
173 		return (error);
174 
175 	/*
176 	 * Initialize transport-type independent fields.
177 	 */
178 	xprt->xp_req_head = (mblk_t *)0;
179 	xprt->xp_req_tail = (mblk_t *)0;
180 	mutex_init(&xprt->xp_req_lock, NULL, MUTEX_DEFAULT, NULL);
181 	mutex_init(&xprt->xp_thread_lock, NULL, MUTEX_DEFAULT, NULL);
182 	xprt->xp_type = tinfo.SERV_type;
183 	xprt->xp_threads = 0;
184 	xprt->xp_detached_threads = 0;
185 	xprt->xp_fp = fp;
186 	xprt->xp_wq = wq;
187 	xprt->xp_closeproc = closeproc;
188 	xprt->xp_sct = sct;
189 	xprt->xp_netid = NULL;
190 	if (netid != NULL) {
191 		xprt->xp_netid = kmem_alloc(strlen(netid) + 1, KM_SLEEP);
192 		(void) strcpy(xprt->xp_netid, netid);
193 	}
194 
195 	xprt->xp_addrmask.len = 0;
196 	xprt->xp_addrmask.maxlen = 0;
197 	xprt->xp_addrmask.buf = NULL;
198 
199 	if (addrmask != NULL) {
200 		xprt->xp_addrmask = *addrmask;
201 	}
202 
203 	/*
204 	 * Register this transport handle after all fields have been
205 	 * initialized. The registration can fail only if we try to register
206 	 * with a non-existent pool (ENOENT) or a closing pool (EBUSY).
207 	 */
208 	if (error = svc_xprt_register(xprt, id)) {
209 		/* if there was an addrmask, caller will delete it */
210 		xprt->xp_addrmask.maxlen = 0;
211 		SVC_DESTROY(xprt);
212 		cmn_err(CE_WARN, "svc_tli_kcreate: xprt_register failed");
213 
214 		return (error);
215 	}
216 
217 	/*
218 	 * Set the private RPC cell in the module's data.
219 	 */
220 	vp = (void **)wq->q_ptr;
221 	vp[0] = xprt;
222 
223 	/*
224 	 * Inform the streams framework that the stream may be very MT hot.
225 	 */
226 	if (hotstream && tinfo.SERV_type == T_CLTS) {
227 		udpmaj = ddi_name_to_major("udp");
228 		if (udpmaj != (major_t)-1 &&
229 			getmajor(fp->f_vnode->v_rdev) == udpmaj)
230 			create_putlocks(wq, 1);
231 	}
232 
233 	*nxprt = xprt;
234 
235 	/*
236 	 * Tell rpcmod that the transport is fully initialized and
237 	 * ready to process requests.
238 	 */
239 	SVC_START(xprt);
240 
241 	return (0);
242 }
243