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
svc_tli_kcreate(struct file * fp,uint_t max_msgsize,char * netid,struct netbuf * addrmask,SVCMASTERXPRT ** nxprt,SVC_CALLOUT_TABLE * sct,void (* closeproc)(const SVCMASTERXPRT *),int id,bool_t hotstream)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