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