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