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