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 "%Z%%M% %I% %E% 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@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@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 bcopy(ret->addr.buf, bound_addr->buf, ret->addr.len); 350 bound_addr->len = ret->addr.len; 351 } 352 (void) t_kfree(tiptr, (char *)req, T_BIND); 353 (void) t_kfree(tiptr, (char *)ret, T_BIND); 354 return (error); 355 } 356 357 void 358 clnt_init(void) 359 { 360 clnt_cots_init(); 361 clnt_clts_init(); 362 } 363 364 void 365 clnt_fini(void) 366 { 367 clnt_clts_fini(); 368 clnt_cots_fini(); 369 } 370 371 call_table_t * 372 call_table_init(int size) 373 { 374 call_table_t *ctp; 375 int i; 376 377 ctp = kmem_alloc(sizeof (call_table_t) * size, KM_SLEEP); 378 379 for (i = 0; i < size; i++) { 380 ctp[i].ct_call_next = (calllist_t *)&ctp[i]; 381 ctp[i].ct_call_prev = (calllist_t *)&ctp[i]; 382 mutex_init(&ctp[i].ct_lock, NULL, MUTEX_DEFAULT, NULL); 383 ctp[i].ct_len = 0; 384 } 385 386 return (ctp); 387 } 388