rpc_generic.c revision 213756
1215207Sgnn/* $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $ */ 2283927Sjhb 3215207Sgnn/* 4215207Sgnn * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5215207Sgnn * unrestricted use provided that this legend is included on all tape 6215207Sgnn * media and as a part of the software program in whole or part. Users 7215207Sgnn * may copy or modify Sun RPC without charge, but are not authorized 8215207Sgnn * to license or distribute it to anyone else except as part of a product or 9215207Sgnn * program developed by the user. 10215207Sgnn * 11215207Sgnn * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12215207Sgnn * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13215207Sgnn * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14215207Sgnn * 15215207Sgnn * Sun RPC is provided with no support and without any obligation on the 16215207Sgnn * part of Sun Microsystems, Inc. to assist in its use, correction, 17215207Sgnn * modification or enhancement. 18215207Sgnn * 19215207Sgnn * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20215207Sgnn * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21215207Sgnn * OR ANY PART THEREOF. 22215207Sgnn * 23215207Sgnn * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24215207Sgnn * or profits or other special, indirect and consequential damages, even if 25215207Sgnn * Sun has been advised of the possibility of such damages. 26215207Sgnn * 27215207Sgnn * Sun Microsystems, Inc. 28215207Sgnn * 2550 Garcia Avenue 29215207Sgnn * Mountain View, California 94043 30215207Sgnn */ 31215207Sgnn/* 32215207Sgnn * Copyright (c) 1986-1991 by Sun Microsystems Inc. 33215207Sgnn */ 34215207Sgnn 35215207Sgnn/* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */ 36215207Sgnn#include <sys/cdefs.h> 37215207Sgnn__FBSDID("$FreeBSD: head/sys/rpc/rpc_generic.c 213756 2010-10-13 00:57:14Z rmacklem $"); 38215207Sgnn 39215207Sgnn/* 40215207Sgnn * rpc_generic.c, Miscl routines for RPC. 41215207Sgnn * 42215207Sgnn */ 43215207Sgnn 44215207Sgnn#include "opt_inet6.h" 45215207Sgnn 46215207Sgnn#include <sys/param.h> 47215207Sgnn#include <sys/kernel.h> 48215207Sgnn#include <sys/malloc.h> 49215207Sgnn#include <sys/mbuf.h> 50215207Sgnn#include <sys/module.h> 51215207Sgnn#include <sys/proc.h> 52215207Sgnn#include <sys/protosw.h> 53215207Sgnn#include <sys/sbuf.h> 54215207Sgnn#include <sys/systm.h> 55215207Sgnn#include <sys/socket.h> 56215207Sgnn#include <sys/socketvar.h> 57215207Sgnn#include <sys/syslog.h> 58215207Sgnn 59215207Sgnn#include <net/vnet.h> 60215207Sgnn 61215207Sgnn#include <rpc/rpc.h> 62215207Sgnn#include <rpc/nettype.h> 63215207Sgnn 64215207Sgnn#include <rpc/rpc_com.h> 65215207Sgnn 66215207Sgnnextern u_long sb_max_adj; /* not defined in socketvar.h */ 67215207Sgnn 68215207Sgnn#if __FreeBSD_version < 700000 69215207Sgnn#define strrchr rindex 70215207Sgnn#endif 71215207Sgnn 72215207Sgnnstruct handle { 73215207Sgnn NCONF_HANDLE *nhandle; 74215207Sgnn int nflag; /* Whether NETPATH or NETCONFIG */ 75215207Sgnn int nettype; 76215207Sgnn}; 77215207Sgnn 78215207Sgnnstatic const struct _rpcnettype { 79215207Sgnn const char *name; 80215207Sgnn const int type; 81215207Sgnn} _rpctypelist[] = { 82215207Sgnn { "netpath", _RPC_NETPATH }, 83215207Sgnn { "visible", _RPC_VISIBLE }, 84215207Sgnn { "circuit_v", _RPC_CIRCUIT_V }, 85215207Sgnn { "datagram_v", _RPC_DATAGRAM_V }, 86215207Sgnn { "circuit_n", _RPC_CIRCUIT_N }, 87215207Sgnn { "datagram_n", _RPC_DATAGRAM_N }, 88215207Sgnn { "tcp", _RPC_TCP }, 89215207Sgnn { "udp", _RPC_UDP }, 90215207Sgnn { 0, _RPC_NONE } 91215207Sgnn}; 92215207Sgnn 93215207Sgnnstruct netid_af { 94215207Sgnn const char *netid; 95215207Sgnn int af; 96215207Sgnn int protocol; 97215207Sgnn}; 98215207Sgnn 99215207Sgnnstatic const struct netid_af na_cvt[] = { 100215207Sgnn { "udp", AF_INET, IPPROTO_UDP }, 101215207Sgnn { "tcp", AF_INET, IPPROTO_TCP }, 102215207Sgnn#ifdef INET6 103215207Sgnn { "udp6", AF_INET6, IPPROTO_UDP }, 104215207Sgnn { "tcp6", AF_INET6, IPPROTO_TCP }, 105215207Sgnn#endif 106215207Sgnn { "local", AF_LOCAL, 0 } 107215207Sgnn}; 108215207Sgnn 109215207Sgnnstruct rpc_createerr rpc_createerr; 110215207Sgnn 111215207Sgnn/* 112215207Sgnn * Find the appropriate buffer size 113215207Sgnn */ 114215207Sgnnu_int 115215207Sgnn/*ARGSUSED*/ 116215207Sgnn__rpc_get_t_size(int af, int proto, int size) 117215207Sgnn{ 118215207Sgnn int defsize; 119215207Sgnn 120215207Sgnn switch (proto) { 121215207Sgnn case IPPROTO_TCP: 122215207Sgnn defsize = 64 * 1024; /* XXX */ 123215207Sgnn break; 124215207Sgnn case IPPROTO_UDP: 125215207Sgnn defsize = UDPMSGSIZE; 126215207Sgnn break; 127215207Sgnn default: 128215207Sgnn defsize = RPC_MAXDATASIZE; 129215207Sgnn break; 130215207Sgnn } 131215207Sgnn if (size == 0) 132215207Sgnn return defsize; 133215207Sgnn 134215207Sgnn /* Check whether the value is within the upper max limit */ 135215207Sgnn return (size > sb_max_adj ? (u_int)sb_max_adj : (u_int)size); 136215207Sgnn} 137215207Sgnn 138215207Sgnn/* 139215207Sgnn * Find the appropriate address buffer size 140215207Sgnn */ 141215207Sgnnu_int 142215207Sgnn__rpc_get_a_size(af) 143215207Sgnn int af; 144215207Sgnn{ 145215207Sgnn switch (af) { 146215207Sgnn case AF_INET: 147215207Sgnn return sizeof (struct sockaddr_in); 148215207Sgnn#ifdef INET6 149215207Sgnn case AF_INET6: 150215207Sgnn return sizeof (struct sockaddr_in6); 151215207Sgnn#endif 152215207Sgnn case AF_LOCAL: 153215207Sgnn return sizeof (struct sockaddr_un); 154215207Sgnn default: 155215207Sgnn break; 156215207Sgnn } 157215207Sgnn return ((u_int)RPC_MAXADDRSIZE); 158215207Sgnn} 159215207Sgnn 160215207Sgnn#if 0 161215207Sgnn 162215207Sgnn/* 163215207Sgnn * Used to ping the NULL procedure for clnt handle. 164 * Returns NULL if fails, else a non-NULL pointer. 165 */ 166void * 167rpc_nullproc(clnt) 168 CLIENT *clnt; 169{ 170 struct timeval TIMEOUT = {25, 0}; 171 172 if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, 173 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { 174 return (NULL); 175 } 176 return ((void *) clnt); 177} 178 179#endif 180 181int 182__rpc_socket2sockinfo(struct socket *so, struct __rpc_sockinfo *sip) 183{ 184 int type, proto; 185 struct sockaddr *sa; 186 sa_family_t family; 187 struct sockopt opt; 188 int error; 189 190 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 191 if (error) 192 return 0; 193 194 sip->si_alen = sa->sa_len; 195 family = sa->sa_family; 196 free(sa, M_SONAME); 197 198 opt.sopt_dir = SOPT_GET; 199 opt.sopt_level = SOL_SOCKET; 200 opt.sopt_name = SO_TYPE; 201 opt.sopt_val = &type; 202 opt.sopt_valsize = sizeof type; 203 opt.sopt_td = NULL; 204 error = sogetopt(so, &opt); 205 if (error) 206 return 0; 207 208 /* XXX */ 209 if (family != AF_LOCAL) { 210 if (type == SOCK_STREAM) 211 proto = IPPROTO_TCP; 212 else if (type == SOCK_DGRAM) 213 proto = IPPROTO_UDP; 214 else 215 return 0; 216 } else 217 proto = 0; 218 219 sip->si_af = family; 220 sip->si_proto = proto; 221 sip->si_socktype = type; 222 223 return 1; 224} 225 226/* 227 * Linear search, but the number of entries is small. 228 */ 229int 230__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip) 231{ 232 int i; 233 234 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) 235 if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || ( 236 strcmp(nconf->nc_netid, "unix") == 0 && 237 strcmp(na_cvt[i].netid, "local") == 0)) { 238 sip->si_af = na_cvt[i].af; 239 sip->si_proto = na_cvt[i].protocol; 240 sip->si_socktype = 241 __rpc_seman2socktype((int)nconf->nc_semantics); 242 if (sip->si_socktype == -1) 243 return 0; 244 sip->si_alen = __rpc_get_a_size(sip->si_af); 245 return 1; 246 } 247 248 return 0; 249} 250 251struct socket * 252__rpc_nconf2socket(const struct netconfig *nconf) 253{ 254 struct __rpc_sockinfo si; 255 struct socket *so; 256 int error; 257 258 if (!__rpc_nconf2sockinfo(nconf, &si)) 259 return 0; 260 261 so = NULL; 262 error = socreate(si.si_af, &so, si.si_socktype, si.si_proto, 263 curthread->td_ucred, curthread); 264 265 if (error) 266 return NULL; 267 else 268 return so; 269} 270 271char * 272taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf) 273{ 274 struct __rpc_sockinfo si; 275 276 if (!__rpc_nconf2sockinfo(nconf, &si)) 277 return NULL; 278 return __rpc_taddr2uaddr_af(si.si_af, nbuf); 279} 280 281struct netbuf * 282uaddr2taddr(const struct netconfig *nconf, const char *uaddr) 283{ 284 struct __rpc_sockinfo si; 285 286 if (!__rpc_nconf2sockinfo(nconf, &si)) 287 return NULL; 288 return __rpc_uaddr2taddr_af(si.si_af, uaddr); 289} 290 291char * 292__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) 293{ 294 char *ret; 295 struct sbuf sb; 296 struct sockaddr_in *sin; 297 struct sockaddr_un *sun; 298 char namebuf[INET_ADDRSTRLEN]; 299#ifdef INET6 300 struct sockaddr_in6 *sin6; 301 char namebuf6[INET6_ADDRSTRLEN]; 302#endif 303 u_int16_t port; 304 305 sbuf_new(&sb, NULL, 0, SBUF_AUTOEXTEND); 306 307 switch (af) { 308 case AF_INET: 309 sin = nbuf->buf; 310 if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf) 311 == NULL) 312 return NULL; 313 port = ntohs(sin->sin_port); 314 if (sbuf_printf(&sb, "%s.%u.%u", namebuf, 315 ((uint32_t)port) >> 8, 316 port & 0xff) < 0) 317 return NULL; 318 break; 319#ifdef INET6 320 case AF_INET6: 321 sin6 = nbuf->buf; 322 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) 323 == NULL) 324 return NULL; 325 port = ntohs(sin6->sin6_port); 326 if (sbuf_printf(&sb, "%s.%u.%u", namebuf6, 327 ((uint32_t)port) >> 8, 328 port & 0xff) < 0) 329 return NULL; 330 break; 331#endif 332 case AF_LOCAL: 333 sun = nbuf->buf; 334 if (sbuf_printf(&sb, "%.*s", (int)(sun->sun_len - 335 offsetof(struct sockaddr_un, sun_path)), 336 sun->sun_path) < 0) 337 return (NULL); 338 break; 339 default: 340 return NULL; 341 } 342 343 sbuf_finish(&sb); 344 ret = strdup(sbuf_data(&sb), M_RPC); 345 sbuf_delete(&sb); 346 347 return ret; 348} 349 350struct netbuf * 351__rpc_uaddr2taddr_af(int af, const char *uaddr) 352{ 353 struct netbuf *ret = NULL; 354 char *addrstr, *p; 355 unsigned port, portlo, porthi; 356 struct sockaddr_in *sin; 357#ifdef INET6 358 struct sockaddr_in6 *sin6; 359#endif 360 struct sockaddr_un *sun; 361 362 port = 0; 363 sin = NULL; 364 addrstr = strdup(uaddr, M_RPC); 365 if (addrstr == NULL) 366 return NULL; 367 368 /* 369 * AF_LOCAL addresses are expected to be absolute 370 * pathnames, anything else will be AF_INET or AF_INET6. 371 */ 372 if (*addrstr != '/') { 373 p = strrchr(addrstr, '.'); 374 if (p == NULL) 375 goto out; 376 portlo = (unsigned)strtol(p + 1, NULL, 10); 377 *p = '\0'; 378 379 p = strrchr(addrstr, '.'); 380 if (p == NULL) 381 goto out; 382 porthi = (unsigned)strtol(p + 1, NULL, 10); 383 *p = '\0'; 384 port = (porthi << 8) | portlo; 385 } 386 387 ret = (struct netbuf *)malloc(sizeof *ret, M_RPC, M_WAITOK); 388 if (ret == NULL) 389 goto out; 390 391 switch (af) { 392 case AF_INET: 393 sin = (struct sockaddr_in *)malloc(sizeof *sin, M_RPC, 394 M_WAITOK); 395 if (sin == NULL) 396 goto out; 397 memset(sin, 0, sizeof *sin); 398 sin->sin_family = AF_INET; 399 sin->sin_port = htons(port); 400 if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) { 401 free(sin, M_RPC); 402 free(ret, M_RPC); 403 ret = NULL; 404 goto out; 405 } 406 sin->sin_len = ret->maxlen = ret->len = sizeof *sin; 407 ret->buf = sin; 408 break; 409#ifdef INET6 410 case AF_INET6: 411 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6, M_RPC, 412 M_WAITOK); 413 if (sin6 == NULL) 414 goto out; 415 memset(sin6, 0, sizeof *sin6); 416 sin6->sin6_family = AF_INET6; 417 sin6->sin6_port = htons(port); 418 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { 419 free(sin6, M_RPC); 420 free(ret, M_RPC); 421 ret = NULL; 422 goto out; 423 } 424 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6; 425 ret->buf = sin6; 426 break; 427#endif 428 case AF_LOCAL: 429 sun = (struct sockaddr_un *)malloc(sizeof *sun, M_RPC, 430 M_WAITOK); 431 if (sun == NULL) 432 goto out; 433 memset(sun, 0, sizeof *sun); 434 sun->sun_family = AF_LOCAL; 435 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1); 436 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun); 437 ret->buf = sun; 438 break; 439 default: 440 break; 441 } 442out: 443 free(addrstr, M_RPC); 444 return ret; 445} 446 447int 448__rpc_seman2socktype(int semantics) 449{ 450 switch (semantics) { 451 case NC_TPI_CLTS: 452 return SOCK_DGRAM; 453 case NC_TPI_COTS_ORD: 454 return SOCK_STREAM; 455 case NC_TPI_RAW: 456 return SOCK_RAW; 457 default: 458 break; 459 } 460 461 return -1; 462} 463 464int 465__rpc_socktype2seman(int socktype) 466{ 467 switch (socktype) { 468 case SOCK_DGRAM: 469 return NC_TPI_CLTS; 470 case SOCK_STREAM: 471 return NC_TPI_COTS_ORD; 472 case SOCK_RAW: 473 return NC_TPI_RAW; 474 default: 475 break; 476 } 477 478 return -1; 479} 480 481/* 482 * Returns the type of the network as defined in <rpc/nettype.h> 483 * If nettype is NULL, it defaults to NETPATH. 484 */ 485static int 486getnettype(const char *nettype) 487{ 488 int i; 489 490 if ((nettype == NULL) || (nettype[0] == 0)) { 491 return (_RPC_NETPATH); /* Default */ 492 } 493 494#if 0 495 nettype = strlocase(nettype); 496#endif 497 for (i = 0; _rpctypelist[i].name; i++) 498 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { 499 return (_rpctypelist[i].type); 500 } 501 return (_rpctypelist[i].type); 502} 503 504/* 505 * For the given nettype (tcp or udp only), return the first structure found. 506 * This should be freed by calling freenetconfigent() 507 */ 508struct netconfig * 509__rpc_getconfip(const char *nettype) 510{ 511 char *netid; 512 static char *netid_tcp = (char *) NULL; 513 static char *netid_udp = (char *) NULL; 514 struct netconfig *dummy; 515 516 if (!netid_udp && !netid_tcp) { 517 struct netconfig *nconf; 518 void *confighandle; 519 520 if (!(confighandle = setnetconfig())) { 521 log(LOG_ERR, "rpc: failed to open " NETCONFIG); 522 return (NULL); 523 } 524 while ((nconf = getnetconfig(confighandle)) != NULL) { 525 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 526 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 527 netid_tcp = strdup(nconf->nc_netid, 528 M_RPC); 529 } else 530 if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 531 netid_udp = strdup(nconf->nc_netid, 532 M_RPC); 533 } 534 } 535 } 536 endnetconfig(confighandle); 537 } 538 if (strcmp(nettype, "udp") == 0) 539 netid = netid_udp; 540 else if (strcmp(nettype, "tcp") == 0) 541 netid = netid_tcp; 542 else { 543 return (NULL); 544 } 545 if ((netid == NULL) || (netid[0] == 0)) { 546 return (NULL); 547 } 548 dummy = getnetconfigent(netid); 549 return (dummy); 550} 551 552/* 553 * Returns the type of the nettype, which should then be used with 554 * __rpc_getconf(). 555 * 556 * For simplicity in the kernel, we don't support the NETPATH 557 * environment variable. We behave as userland would then NETPATH is 558 * unset, i.e. iterate over all visible entries in netconfig. 559 */ 560void * 561__rpc_setconf(nettype) 562 const char *nettype; 563{ 564 struct handle *handle; 565 566 handle = (struct handle *) malloc(sizeof (struct handle), 567 M_RPC, M_WAITOK); 568 switch (handle->nettype = getnettype(nettype)) { 569 case _RPC_NETPATH: 570 case _RPC_CIRCUIT_N: 571 case _RPC_DATAGRAM_N: 572 if (!(handle->nhandle = setnetconfig())) 573 goto failed; 574 handle->nflag = TRUE; 575 break; 576 case _RPC_VISIBLE: 577 case _RPC_CIRCUIT_V: 578 case _RPC_DATAGRAM_V: 579 case _RPC_TCP: 580 case _RPC_UDP: 581 if (!(handle->nhandle = setnetconfig())) { 582 log(LOG_ERR, "rpc: failed to open " NETCONFIG); 583 goto failed; 584 } 585 handle->nflag = FALSE; 586 break; 587 default: 588 goto failed; 589 } 590 591 return (handle); 592 593failed: 594 free(handle, M_RPC); 595 return (NULL); 596} 597 598/* 599 * Returns the next netconfig struct for the given "net" type. 600 * __rpc_setconf() should have been called previously. 601 */ 602struct netconfig * 603__rpc_getconf(void *vhandle) 604{ 605 struct handle *handle; 606 struct netconfig *nconf; 607 608 handle = (struct handle *)vhandle; 609 if (handle == NULL) { 610 return (NULL); 611 } 612 for (;;) { 613 if (handle->nflag) { 614 nconf = getnetconfig(handle->nhandle); 615 if (nconf && !(nconf->nc_flag & NC_VISIBLE)) 616 continue; 617 } else { 618 nconf = getnetconfig(handle->nhandle); 619 } 620 if (nconf == NULL) 621 break; 622 if ((nconf->nc_semantics != NC_TPI_CLTS) && 623 (nconf->nc_semantics != NC_TPI_COTS) && 624 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 625 continue; 626 switch (handle->nettype) { 627 case _RPC_VISIBLE: 628 if (!(nconf->nc_flag & NC_VISIBLE)) 629 continue; 630 /* FALLTHROUGH */ 631 case _RPC_NETPATH: /* Be happy */ 632 break; 633 case _RPC_CIRCUIT_V: 634 if (!(nconf->nc_flag & NC_VISIBLE)) 635 continue; 636 /* FALLTHROUGH */ 637 case _RPC_CIRCUIT_N: 638 if ((nconf->nc_semantics != NC_TPI_COTS) && 639 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 640 continue; 641 break; 642 case _RPC_DATAGRAM_V: 643 if (!(nconf->nc_flag & NC_VISIBLE)) 644 continue; 645 /* FALLTHROUGH */ 646 case _RPC_DATAGRAM_N: 647 if (nconf->nc_semantics != NC_TPI_CLTS) 648 continue; 649 break; 650 case _RPC_TCP: 651 if (((nconf->nc_semantics != NC_TPI_COTS) && 652 (nconf->nc_semantics != NC_TPI_COTS_ORD)) || 653 (strcmp(nconf->nc_protofmly, NC_INET) 654#ifdef INET6 655 && strcmp(nconf->nc_protofmly, NC_INET6)) 656#else 657 ) 658#endif 659 || 660 strcmp(nconf->nc_proto, NC_TCP)) 661 continue; 662 break; 663 case _RPC_UDP: 664 if ((nconf->nc_semantics != NC_TPI_CLTS) || 665 (strcmp(nconf->nc_protofmly, NC_INET) 666#ifdef INET6 667 && strcmp(nconf->nc_protofmly, NC_INET6)) 668#else 669 ) 670#endif 671 || 672 strcmp(nconf->nc_proto, NC_UDP)) 673 continue; 674 break; 675 } 676 break; 677 } 678 return (nconf); 679} 680 681void 682__rpc_endconf(vhandle) 683 void * vhandle; 684{ 685 struct handle *handle; 686 687 handle = (struct handle *) vhandle; 688 if (handle == NULL) { 689 return; 690 } 691 endnetconfig(handle->nhandle); 692 free(handle, M_RPC); 693} 694 695int 696__rpc_sockisbound(struct socket *so) 697{ 698 struct sockaddr *sa; 699 int error, bound; 700 701 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 702 if (error) 703 return (0); 704 705 switch (sa->sa_family) { 706 case AF_INET: 707 bound = (((struct sockaddr_in *) sa)->sin_port != 0); 708 break; 709#ifdef INET6 710 case AF_INET6: 711 bound = (((struct sockaddr_in6 *) sa)->sin6_port != 0); 712 break; 713#endif 714 case AF_LOCAL: 715 /* XXX check this */ 716 bound = (((struct sockaddr_un *) sa)->sun_path[0] != '\0'); 717 break; 718 default: 719 bound = FALSE; 720 break; 721 } 722 723 free(sa, M_SONAME); 724 725 return bound; 726} 727 728/* 729 * Implement XDR-style API for RPC call. 730 */ 731enum clnt_stat 732clnt_call_private( 733 CLIENT *cl, /* client handle */ 734 struct rpc_callextra *ext, /* call metadata */ 735 rpcproc_t proc, /* procedure number */ 736 xdrproc_t xargs, /* xdr routine for args */ 737 void *argsp, /* pointer to args */ 738 xdrproc_t xresults, /* xdr routine for results */ 739 void *resultsp, /* pointer to results */ 740 struct timeval utimeout) /* seconds to wait before giving up */ 741{ 742 XDR xdrs; 743 struct mbuf *mreq; 744 struct mbuf *mrep; 745 enum clnt_stat stat; 746 747 MGET(mreq, M_WAIT, MT_DATA); 748 MCLGET(mreq, M_WAIT); 749 mreq->m_len = 0; 750 751 xdrmbuf_create(&xdrs, mreq, XDR_ENCODE); 752 if (!xargs(&xdrs, argsp)) { 753 m_freem(mreq); 754 return (RPC_CANTENCODEARGS); 755 } 756 XDR_DESTROY(&xdrs); 757 758 stat = CLNT_CALL_MBUF(cl, ext, proc, mreq, &mrep, utimeout); 759 m_freem(mreq); 760 761 if (stat == RPC_SUCCESS) { 762 xdrmbuf_create(&xdrs, mrep, XDR_DECODE); 763 if (!xresults(&xdrs, resultsp)) { 764 XDR_DESTROY(&xdrs); 765 return (RPC_CANTDECODERES); 766 } 767 XDR_DESTROY(&xdrs); 768 } 769 770 return (stat); 771} 772 773/* 774 * Bind a socket to a privileged IP port 775 */ 776int 777bindresvport(struct socket *so, struct sockaddr *sa) 778{ 779 int old, error, af; 780 bool_t freesa = FALSE; 781 struct sockaddr_in *sin; 782#ifdef INET6 783 struct sockaddr_in6 *sin6; 784#endif 785 struct sockopt opt; 786 int proto, portrange, portlow; 787 u_int16_t *portp; 788 socklen_t salen; 789 790 if (sa == NULL) { 791 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 792 if (error) 793 return (error); 794 freesa = TRUE; 795 af = sa->sa_family; 796 salen = sa->sa_len; 797 memset(sa, 0, sa->sa_len); 798 } else { 799 af = sa->sa_family; 800 salen = sa->sa_len; 801 } 802 803 switch (af) { 804 case AF_INET: 805 proto = IPPROTO_IP; 806 portrange = IP_PORTRANGE; 807 portlow = IP_PORTRANGE_LOW; 808 sin = (struct sockaddr_in *)sa; 809 portp = &sin->sin_port; 810 break; 811#ifdef INET6 812 case AF_INET6: 813 proto = IPPROTO_IPV6; 814 portrange = IPV6_PORTRANGE; 815 portlow = IPV6_PORTRANGE_LOW; 816 sin6 = (struct sockaddr_in6 *)sa; 817 portp = &sin6->sin6_port; 818 break; 819#endif 820 default: 821 return (EPFNOSUPPORT); 822 } 823 824 sa->sa_family = af; 825 sa->sa_len = salen; 826 827 if (*portp == 0) { 828 CURVNET_SET(so->so_vnet); 829 bzero(&opt, sizeof(opt)); 830 opt.sopt_dir = SOPT_GET; 831 opt.sopt_level = proto; 832 opt.sopt_name = portrange; 833 opt.sopt_val = &old; 834 opt.sopt_valsize = sizeof(old); 835 error = sogetopt(so, &opt); 836 if (error) { 837 CURVNET_RESTORE(); 838 goto out; 839 } 840 841 opt.sopt_dir = SOPT_SET; 842 opt.sopt_val = &portlow; 843 error = sosetopt(so, &opt); 844 CURVNET_RESTORE(); 845 if (error) 846 goto out; 847 } 848 849 error = sobind(so, sa, curthread); 850 851 if (*portp == 0) { 852 if (error) { 853 opt.sopt_dir = SOPT_SET; 854 opt.sopt_val = &old; 855 CURVNET_SET(so->so_vnet); 856 sosetopt(so, &opt); 857 CURVNET_RESTORE(); 858 } 859 } 860out: 861 if (freesa) 862 free(sa, M_SONAME); 863 864 return (error); 865} 866 867/* 868 * Kernel module glue 869 */ 870static int 871krpc_modevent(module_t mod, int type, void *data) 872{ 873 874 return (0); 875} 876static moduledata_t krpc_mod = { 877 "krpc", 878 krpc_modevent, 879 NULL, 880}; 881DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY); 882 883/* So that loader and kldload(2) can find us, wherever we are.. */ 884MODULE_VERSION(krpc, 1); 885