Home | History | Annotate | Download | only in rpc
      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 (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
     27 /*	  All Rights Reserved  	*/
     28 
     29 /*
     30  * Portions of this source code were derived from Berkeley 4.3 BSD
     31  * under license from the Regents of the University of California.
     32  */
     33 
     34 #pragma ident	"@(#)clnt_gen.c	1.53	06/09/11 SMI"
     35 
     36 #include <sys/param.h>
     37 #include <sys/types.h>
     38 #include <rpc/types.h>
     39 #include <netinet/in.h>
     40 #include <rpc/auth.h>
     41 #include <rpc/clnt.h>
     42 #include <sys/tiuser.h>
     43 #include <sys/t_kuser.h>
     44 #include <rpc/svc.h>
     45 #include <rpc/xdr.h>
     46 #include <sys/file.h>
     47 #include <sys/user.h>
     48 #include <sys/proc.h>
     49 #include <sys/vnode.h>
     50 #include <sys/stream.h>
     51 #include <sys/tihdr.h>
     52 #include <sys/fcntl.h>
     53 #include <sys/socket.h>
     54 #include <sys/sysmacros.h>
     55 #include <sys/errno.h>
     56 #include <sys/cred.h>
     57 #include <sys/systm.h>
     58 #include <sys/cmn_err.h>
     59 
     60 #define	NC_INET		"inet"
     61 
     62 #define	MAX_PRIV	(IPPORT_RESERVED-1)
     63 #define	MIN_PRIV	(IPPORT_RESERVED/2)
     64 
     65 ushort_t clnt_udp_last_used = MIN_PRIV;
     66 ushort_t clnt_tcp_last_used = MIN_PRIV;
     67 
     68 /*
     69  * PSARC 2003/523 Contract Private Interface
     70  * clnt_tli_kcreate
     71  * Changes must be reviewed by Solaris File Sharing
     72  * Changes must be communicated to contract-2003-523 (at) sun.com
     73  */
     74 int
     75 clnt_tli_kcreate(
     76 	struct knetconfig	*config,
     77 	struct netbuf		*svcaddr,	/* Servers address */
     78 	rpcprog_t		prog,		/* Program number */
     79 	rpcvers_t		vers,		/* Version number */
     80 	uint_t			max_msgsize,
     81 	int			retries,
     82 	struct cred		*cred,
     83 	CLIENT			**ncl)
     84 {
     85 	CLIENT			*cl;		/* Client handle */
     86 	int			error;
     87 	int			family = AF_UNSPEC;
     88 
     89 	error = 0;
     90 	cl = NULL;
     91 
     92 	RPCLOG(8, "clnt_tli_kcreate: prog %x", prog);
     93 	RPCLOG(8, ", vers %d", vers);
     94 	RPCLOG(8, ", knc_semantics %d", config->knc_semantics);
     95 	RPCLOG(8, ", knc_protofmly %s", config->knc_protofmly);
     96 	RPCLOG(8, ", knc_proto %s\n", config->knc_proto);
     97 
     98 	if (config == NULL || config->knc_protofmly == NULL || ncl == NULL) {
     99 		RPCLOG0(1, "clnt_tli_kcreate: bad config or handle\n");
    100 		return (EINVAL);
    101 	}
    102 
    103 	switch (config->knc_semantics) {
    104 	case NC_TPI_CLTS:
    105 		RPCLOG0(8, "clnt_tli_kcreate: CLTS selected\n");
    106 		error = clnt_clts_kcreate(config, svcaddr, prog, vers,
    107 						retries, cred, &cl);
    108 		if (error != 0) {
    109 			RPCLOG(1,
    110 			"clnt_tli_kcreate: clnt_clts_kcreate failed error %d\n",
    111 			    error);
    112 			return (error);
    113 		}
    114 		break;
    115 
    116 	case NC_TPI_COTS:
    117 	case NC_TPI_COTS_ORD:
    118 		RPCLOG0(8, "clnt_tli_kcreate: COTS selected\n");
    119 		if (strcmp(config->knc_protofmly, NC_INET) == 0)
    120 			family = AF_INET;
    121 		else if (strcmp(config->knc_protofmly, NC_INET6) == 0)
    122 			family = AF_INET6;
    123 		error = clnt_cots_kcreate(config->knc_rdev, svcaddr, family,
    124 		    prog, vers, max_msgsize, cred, &cl);
    125 		if (error != 0) {
    126 			RPCLOG(1,
    127 			"clnt_tli_kcreate: clnt_cots_kcreate failed error %d\n",
    128 			error);
    129 			return (error);
    130 		}
    131 		break;
    132 	case NC_TPI_RDMA:
    133 		RPCLOG0(8, "clnt_tli_kcreate: RDMA selected\n");
    134 		/*
    135 		 * RDMA doesn't support TSOL. It's better to
    136 		 * disallow it here.
    137 		 */
    138 		if (is_system_labeled()) {
    139 			RPCLOG0(1, "clnt_tli_kcreate: tsol not supported\n");
    140 			return (EPROTONOSUPPORT);
    141 		}
    142 
    143 		if (strcmp(config->knc_protofmly, NC_INET) == 0)
    144 			family = AF_INET;
    145 		else if (strcmp(config->knc_protofmly, NC_INET6) == 0)
    146 			family = AF_INET6;
    147 		error = clnt_rdma_kcreate(config->knc_proto,
    148 		    (void *)config->knc_rdev, svcaddr, family, prog, vers, cred,
    149 		    &cl);
    150 		if (error != 0) {
    151 			RPCLOG(1,
    152 			"clnt_tli_kcreate: clnt_rdma_kcreate failed error %d\n",
    153 			error);
    154 			return (error);
    155 		}
    156 		break;
    157 	default:
    158 		error = EINVAL;
    159 		RPCLOG(1, "clnt_tli_kcreate: Bad service type %d\n",
    160 		    config->knc_semantics);
    161 		return (error);
    162 	}
    163 	*ncl = cl;
    164 	return (0);
    165 }
    166 
    167 /*
    168  * "Kinit" a client handle by calling the appropriate cots or clts routine.
    169  *
    170  * PSARC 2003/523 Contract Private Interface
    171  * clnt_tli_kinit
    172  * Changes must be reviewed by Solaris File Sharing
    173  * Changes must be communicated to contract-2003-523 (at) sun.com
    174  */
    175 int
    176 clnt_tli_kinit(
    177 	CLIENT		*h,
    178 	struct knetconfig *config,
    179 	struct netbuf	*addr,
    180 	uint_t		max_msgsize,
    181 	int		retries,
    182 	struct cred	*cred)
    183 {
    184 	int error = 0;
    185 	int family = AF_UNSPEC;
    186 
    187 	switch (config->knc_semantics) {
    188 	case NC_TPI_CLTS:
    189 		clnt_clts_kinit(h, addr, retries, cred);
    190 		break;
    191 	case NC_TPI_COTS:
    192 	case NC_TPI_COTS_ORD:
    193 		RPCLOG0(2, "clnt_tli_kinit: COTS selected\n");
    194 		if (strcmp(config->knc_protofmly, NC_INET) == 0)
    195 			family = AF_INET;
    196 		else if (strcmp(config->knc_protofmly, NC_INET6) == 0)
    197 			family = AF_INET6;
    198 		clnt_cots_kinit(h, config->knc_rdev, family,
    199 		    addr, max_msgsize, cred);
    200 		break;
    201 	case NC_TPI_RDMA:
    202 		RPCLOG0(2, "clnt_tli_kinit: RDMA selected\n");
    203 		clnt_rdma_kinit(h, config->knc_proto,
    204 		    (void *)config->knc_rdev, addr, cred);
    205 		break;
    206 	default:
    207 		error = EINVAL;
    208 	}
    209 
    210 	return (error);
    211 }
    212 
    213 
    214 /*
    215  * try to bind to a reserved port
    216  */
    217 int
    218 bindresvport(
    219 	TIUSER		*tiptr,
    220 	struct netbuf	*addr,
    221 	struct netbuf	*bound_addr,
    222 	bool_t		tcp)
    223 {
    224 	struct sockaddr_in	*sin;
    225 	struct sockaddr_in6	*sin6;
    226 	bool_t 			ipv6_flag = 0;
    227 	int			i;
    228 	struct t_bind		*req;
    229 	struct t_bind		*ret;
    230 	int			error;
    231 	bool_t			loop_twice;
    232 	int			start;
    233 	int			stop;
    234 	ushort_t			*last_used;
    235 
    236 	if ((error = t_kalloc(tiptr, T_BIND, T_ADDR, (char **)&req)) != 0) {
    237 		RPCLOG(1, "bindresvport: t_kalloc %d\n", error);
    238 		return (error);
    239 	}
    240 
    241 	if ((error = t_kalloc(tiptr, T_BIND, T_ADDR, (char **)&ret)) != 0) {
    242 		RPCLOG(1, "bindresvport: t_kalloc %d\n", error);
    243 		(void) t_kfree(tiptr, (char *)req, T_BIND);
    244 		return (error);
    245 	}
    246 
    247 	/* now separate IPv4 and IPv6 by looking at len of tiptr.addr */
    248 	if (tiptr->tp_info.addr == sizeof (struct sockaddr_in6)) {
    249 		/* it's IPv6 */
    250 		ipv6_flag = 1;
    251 		sin6 = (struct sockaddr_in6 *)req->addr.buf;
    252 		sin6->sin6_family = AF_INET6;
    253 		bzero((char *)&sin6->sin6_addr, sizeof (struct in6_addr));
    254 		req->addr.len = sizeof (struct sockaddr_in6);
    255 	} else {
    256 		/* LINTED pointer alignment */
    257 		sin = (struct sockaddr_in *)req->addr.buf;
    258 		sin->sin_family = AF_INET;
    259 		sin->sin_addr.s_addr = INADDR_ANY;
    260 		req->addr.len = sizeof (struct sockaddr_in);
    261 	}
    262 
    263 	/*
    264 	 * Caller wants to bind to a specific port, so don't bother with the
    265 	 * loop that binds to the next free one.
    266 	 */
    267 	if (addr) {
    268 		if (ipv6_flag) {
    269 			sin6->sin6_port =
    270 				((struct sockaddr_in6 *)addr->buf)->sin6_port;
    271 		} else {
    272 			sin->sin_port =
    273 				((struct sockaddr_in *)addr->buf)->sin_port;
    274 		}
    275 		RPCLOG(8, "bindresvport: calling t_kbind tiptr = %p\n",
    276 		    (void *)tiptr);
    277 		if ((error = t_kbind(tiptr, req, ret)) != 0) {
    278 			RPCLOG(1, "bindresvport: t_kbind: %d\n", error);
    279 			/*
    280 			 * The unbind is called in case the bind failed
    281 			 * with an EINTR potentially leaving the
    282 			 * transport in bound state.
    283 			 */
    284 			if (error == EINTR)
    285 				(void) t_kunbind(tiptr);
    286 		} else if (bcmp(req->addr.buf, ret->addr.buf,
    287 				ret->addr.len) != 0) {
    288 			RPCLOG0(1, "bindresvport: bcmp error\n");
    289 			(void) t_kunbind(tiptr);
    290 			error = EADDRINUSE;
    291 		}
    292 	} else {
    293 		if (tcp)
    294 			last_used = &clnt_tcp_last_used;
    295 		else
    296 			last_used = &clnt_udp_last_used;
    297 		error = EADDRINUSE;
    298 		stop = MIN_PRIV;
    299 
    300 		start = (*last_used == MIN_PRIV ? MAX_PRIV : *last_used - 1);
    301 		loop_twice = (start < MAX_PRIV ? TRUE : FALSE);
    302 
    303 bindresvport_again:
    304 		for (i = start;
    305 		    (error == EADDRINUSE || error == EADDRNOTAVAIL) &&
    306 		    i >= stop; i--) {
    307 			if (ipv6_flag)
    308 				sin6->sin6_port = htons(i);
    309 			else
    310 				sin->sin_port = htons(i);
    311 			RPCLOG(8, "bindresvport: calling t_kbind tiptr = 0%p\n",
    312 			    (void *)tiptr);
    313 			if ((error = t_kbind(tiptr, req, ret)) != 0) {
    314 				RPCLOG(1, "bindresvport: t_kbind: %d\n", error);
    315 				/*
    316 				 * The unbind is called in case the bind failed
    317 				 * with an EINTR potentially leaving the
    318 				 * transport in bound state.
    319 				 */
    320 				if (error == EINTR)
    321 					(void) t_kunbind(tiptr);
    322 			} else if (bcmp(req->addr.buf, ret->addr.buf,
    323 			    ret->addr.len) != 0) {
    324 				RPCLOG0(1, "bindresvport: bcmp error\n");
    325 				(void) t_kunbind(tiptr);
    326 				error = EADDRINUSE;
    327 			} else
    328 				error = 0;
    329 		}
    330 		if (!error) {
    331 			if (ipv6_flag) {
    332 				RPCLOG(8, "bindresvport: port assigned %d\n",
    333 					sin6->sin6_port);
    334 				*last_used = ntohs(sin6->sin6_port);
    335 			} else {
    336 				RPCLOG(8, "bindresvport: port assigned %d\n",
    337 					sin->sin_port);
    338 				*last_used = ntohs(sin->sin_port);
    339 			}
    340 		} else if (loop_twice) {
    341 			loop_twice = FALSE;
    342 			start = MAX_PRIV;
    343 			stop = *last_used + 1;
    344 			goto bindresvport_again;
    345 		}
    346 	}
    347 
    348 	if (!error && bound_addr) {
    349 		if (bound_addr->maxlen < ret->addr.len) {
    350 			kmem_free(bound_addr->buf, bound_addr->maxlen);
    351 			bound_addr->buf = kmem_zalloc(ret->addr.len, KM_SLEEP);
    352 			bound_addr->maxlen = ret->addr.len;
    353 		}
    354 		bcopy(ret->addr.buf, bound_addr->buf, ret->addr.len);
    355 		bound_addr->len = ret->addr.len;
    356 	}
    357 	(void) t_kfree(tiptr, (char *)req, T_BIND);
    358 	(void) t_kfree(tiptr, (char *)ret, T_BIND);
    359 	return (error);
    360 }
    361 
    362 void
    363 clnt_init(void)
    364 {
    365 	clnt_cots_init();
    366 	clnt_clts_init();
    367 }
    368 
    369 void
    370 clnt_fini(void)
    371 {
    372 	clnt_clts_fini();
    373 	clnt_cots_fini();
    374 }
    375 
    376 call_table_t *
    377 call_table_init(int size)
    378 {
    379 	call_table_t *ctp;
    380 	int i;
    381 
    382 	ctp = kmem_alloc(sizeof (call_table_t) * size, KM_SLEEP);
    383 
    384 	for (i = 0; i < size; i++) {
    385 		ctp[i].ct_call_next = (calllist_t *)&ctp[i];
    386 		ctp[i].ct_call_prev = (calllist_t *)&ctp[i];
    387 		mutex_init(&ctp[i].ct_lock, NULL, MUTEX_DEFAULT, NULL);
    388 		ctp[i].ct_len = 0;
    389 	}
    390 
    391 	return (ctp);
    392 }
    393