17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 22*6935f61bSMarcel Telka 23*6935f61bSMarcel Telka /* 24*6935f61bSMarcel Telka * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 25*6935f61bSMarcel Telka */ 26*6935f61bSMarcel Telka 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate /* 320bfcf696Sgt29601 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 337c478bd9Sstevel@tonic-gate * Use is subject to license terms. 347c478bd9Sstevel@tonic-gate */ 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate /* SVr4.0 1.1 */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate /* 397c478bd9Sstevel@tonic-gate * Miscellaneous support routines for kernel implementation of RPC. 407c478bd9Sstevel@tonic-gate */ 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <sys/param.h> 437c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 447c478bd9Sstevel@tonic-gate #include <sys/user.h> 457c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 467c478bd9Sstevel@tonic-gate #include <sys/stream.h> 477c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 487c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 497c478bd9Sstevel@tonic-gate #include <sys/socket.h> 507c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 517c478bd9Sstevel@tonic-gate #include <sys/timod.h> 527c478bd9Sstevel@tonic-gate #include <sys/tiuser.h> 537c478bd9Sstevel@tonic-gate #include <sys/systm.h> 547c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 557c478bd9Sstevel@tonic-gate #include <sys/debug.h> 56546f41c4SDan Kruchinin #include <sys/sdt.h> 577c478bd9Sstevel@tonic-gate #include <netinet/in.h> 587c478bd9Sstevel@tonic-gate #include <rpc/types.h> 597c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 607c478bd9Sstevel@tonic-gate #include <rpc/clnt.h> 617c478bd9Sstevel@tonic-gate #include <rpc/rpcb_prot.h> 627c478bd9Sstevel@tonic-gate #include <rpc/pmap_prot.h> 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate static int strtoi(char *, char **); 657c478bd9Sstevel@tonic-gate static void grow_netbuf(struct netbuf *, size_t); 667c478bd9Sstevel@tonic-gate static void loopb_u2t(const char *, struct netbuf *); 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate #define RPC_PMAP_TIMEOUT 15 690bfcf696Sgt29601 /* 700bfcf696Sgt29601 * define for max length of an ip address and port address, the value was 710bfcf696Sgt29601 * calculated using INET6_ADDRSTRLEN (46) + max port address (12) + 720bfcf696Sgt29601 * seperator "."'s in port address (2) + null (1) = 61. 730bfcf696Sgt29601 * Then there is IPV6_TOKEN_LEN which is 64, so the value is 64 to be safe. 740bfcf696Sgt29601 */ 750bfcf696Sgt29601 #define RPC_MAX_IP_LENGTH 64 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate /* 787c478bd9Sstevel@tonic-gate * Kernel level debugging aid. The global variable "rpclog" is a bit 797c478bd9Sstevel@tonic-gate * mask which allows various types of debugging messages to be printed 807c478bd9Sstevel@tonic-gate * out. 817c478bd9Sstevel@tonic-gate * 827c478bd9Sstevel@tonic-gate * rpclog & 1 will cause actual failures to be printed. 837c478bd9Sstevel@tonic-gate * rpclog & 2 will cause informational messages to be 847c478bd9Sstevel@tonic-gate * printed on the client side of rpc. 857c478bd9Sstevel@tonic-gate * rpclog & 4 will cause informational messages to be 867c478bd9Sstevel@tonic-gate * printed on the server side of rpc. 877c478bd9Sstevel@tonic-gate * rpclog & 8 will cause informational messages for rare events to be 887c478bd9Sstevel@tonic-gate * printed on the client side of rpc. 897c478bd9Sstevel@tonic-gate * rpclog & 16 will cause informational messages for rare events to be 907c478bd9Sstevel@tonic-gate * printed on the server side of rpc. 917c478bd9Sstevel@tonic-gate * rpclog & 32 will cause informational messages for rare events to be 927c478bd9Sstevel@tonic-gate * printed on the common client/server code paths of rpc. 937c478bd9Sstevel@tonic-gate * rpclog & 64 will cause informational messages for manipulation 947c478bd9Sstevel@tonic-gate * client-side COTS dispatch list to be printed. 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate uint_t rpclog = 0; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate void 1017c478bd9Sstevel@tonic-gate rpc_poptimod(vnode_t *vp) 1027c478bd9Sstevel@tonic-gate { 1037c478bd9Sstevel@tonic-gate int error, isfound, ret; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate error = strioctl(vp, I_FIND, (intptr_t)"timod", 0, K_TO_K, kcred, 1067c478bd9Sstevel@tonic-gate &isfound); 1077c478bd9Sstevel@tonic-gate if (error) { 1087c478bd9Sstevel@tonic-gate RPCLOG(1, "rpc_poptimod: I_FIND strioctl error %d\n", error); 1097c478bd9Sstevel@tonic-gate return; 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate if (isfound) { 1127c478bd9Sstevel@tonic-gate /* 1137c478bd9Sstevel@tonic-gate * Pop timod module 1147c478bd9Sstevel@tonic-gate */ 1157c478bd9Sstevel@tonic-gate error = strioctl(vp, I_POP, 0, 0, K_TO_K, kcred, &ret); 1167c478bd9Sstevel@tonic-gate if (error) { 1177c478bd9Sstevel@tonic-gate RPCLOG(1, "rpc_poptimod: I_POP strioctl error %d\n", 1187c478bd9Sstevel@tonic-gate error); 1197c478bd9Sstevel@tonic-gate return; 1207c478bd9Sstevel@tonic-gate } 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate /* 1250bfcf696Sgt29601 * Check the passed in ip address for correctness (limited) and return its 1260bfcf696Sgt29601 * type. 1270bfcf696Sgt29601 * 1280bfcf696Sgt29601 * an ipv4 looks like this: 1290bfcf696Sgt29601 * "IP.IP.IP.IP.PORT[top byte].PORT[bottom byte]" 1300bfcf696Sgt29601 * 1310bfcf696Sgt29601 * an ipv6 looks like this: 1320bfcf696Sgt29601 * fec0:A02::2:202:4FCD 1330bfcf696Sgt29601 * or 1340bfcf696Sgt29601 * ::10.9.2.1 1350bfcf696Sgt29601 */ 1360bfcf696Sgt29601 int 1370bfcf696Sgt29601 rpc_iptype( 1380bfcf696Sgt29601 char *ipaddr, 1390bfcf696Sgt29601 int *typeval) 1400bfcf696Sgt29601 { 1410bfcf696Sgt29601 char *cp; 1420bfcf696Sgt29601 int chcnt = 0; 1430bfcf696Sgt29601 int coloncnt = 0; 1440bfcf696Sgt29601 int dotcnt = 0; 1450bfcf696Sgt29601 int numcnt = 0; 1460bfcf696Sgt29601 int hexnumcnt = 0; 1470bfcf696Sgt29601 int othercnt = 0; 1480bfcf696Sgt29601 1490bfcf696Sgt29601 cp = ipaddr; 1500bfcf696Sgt29601 1510bfcf696Sgt29601 /* search for the different type of characters in the ip address */ 1520bfcf696Sgt29601 while ((*cp != '\0') && (chcnt < RPC_MAX_IP_LENGTH)) { 1530bfcf696Sgt29601 switch (*cp) { 1540bfcf696Sgt29601 case ':': 1550bfcf696Sgt29601 coloncnt++; 1560bfcf696Sgt29601 break; 1570bfcf696Sgt29601 case '.': 1580bfcf696Sgt29601 dotcnt++; 1590bfcf696Sgt29601 break; 1600bfcf696Sgt29601 case '0': 1610bfcf696Sgt29601 case '1': 1620bfcf696Sgt29601 case '2': 1630bfcf696Sgt29601 case '3': 1640bfcf696Sgt29601 case '4': 1650bfcf696Sgt29601 case '5': 1660bfcf696Sgt29601 case '6': 1670bfcf696Sgt29601 case '7': 1680bfcf696Sgt29601 case '8': 1690bfcf696Sgt29601 case '9': 1700bfcf696Sgt29601 numcnt++; 1710bfcf696Sgt29601 break; 1720bfcf696Sgt29601 case 'a': 1730bfcf696Sgt29601 case 'A': 1740bfcf696Sgt29601 case 'b': 1750bfcf696Sgt29601 case 'B': 1760bfcf696Sgt29601 case 'c': 1770bfcf696Sgt29601 case 'C': 1780bfcf696Sgt29601 case 'd': 1790bfcf696Sgt29601 case 'D': 1800bfcf696Sgt29601 case 'e': 1810bfcf696Sgt29601 case 'E': 1820bfcf696Sgt29601 case 'f': 1830bfcf696Sgt29601 case 'F': 1840bfcf696Sgt29601 hexnumcnt++; 1850bfcf696Sgt29601 break; 1860bfcf696Sgt29601 default: 1870bfcf696Sgt29601 othercnt++; 1880bfcf696Sgt29601 break; 1890bfcf696Sgt29601 } 1900bfcf696Sgt29601 chcnt++; 1910bfcf696Sgt29601 cp++; 1920bfcf696Sgt29601 } 1930bfcf696Sgt29601 1940bfcf696Sgt29601 /* check for bad ip strings */ 1950bfcf696Sgt29601 if ((chcnt == RPC_MAX_IP_LENGTH) || (othercnt)) 1960bfcf696Sgt29601 return (-1); 1970bfcf696Sgt29601 1980bfcf696Sgt29601 /* if we have a coloncnt, it can only be an ipv6 address */ 1990bfcf696Sgt29601 if (coloncnt) { 2000bfcf696Sgt29601 if ((coloncnt < 2) || (coloncnt > 7)) 2010bfcf696Sgt29601 return (-1); 2020bfcf696Sgt29601 2030bfcf696Sgt29601 *typeval = AF_INET6; 2040bfcf696Sgt29601 } else { 2050bfcf696Sgt29601 /* since there are no colons, make sure it is ipv4 */ 2060bfcf696Sgt29601 if ((hexnumcnt) || (dotcnt != 5)) 2070bfcf696Sgt29601 return (-1); 2080bfcf696Sgt29601 2090bfcf696Sgt29601 *typeval = AF_INET; 2100bfcf696Sgt29601 } 2110bfcf696Sgt29601 return (0); 2120bfcf696Sgt29601 } 2130bfcf696Sgt29601 2140bfcf696Sgt29601 /* 2157c478bd9Sstevel@tonic-gate * Return a port number from a sockaddr_in expressed in universal address 2167c478bd9Sstevel@tonic-gate * format. Note that this routine does not work for address families other 2177c478bd9Sstevel@tonic-gate * than INET. Eventually, we should replace this routine with one that 2187c478bd9Sstevel@tonic-gate * contacts the rpcbind running locally. 2197c478bd9Sstevel@tonic-gate */ 2207c478bd9Sstevel@tonic-gate int 2217c478bd9Sstevel@tonic-gate rpc_uaddr2port(int af, char *addr) 2227c478bd9Sstevel@tonic-gate { 2237c478bd9Sstevel@tonic-gate int p1; 2247c478bd9Sstevel@tonic-gate int p2; 2257c478bd9Sstevel@tonic-gate char *next, *p; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate if (af == AF_INET) { 2287c478bd9Sstevel@tonic-gate /* 2297c478bd9Sstevel@tonic-gate * A struct sockaddr_in expressed in universal address 2307c478bd9Sstevel@tonic-gate * format looks like: 2317c478bd9Sstevel@tonic-gate * 2327c478bd9Sstevel@tonic-gate * "IP.IP.IP.IP.PORT[top byte].PORT[bottom byte]" 2337c478bd9Sstevel@tonic-gate * 2347c478bd9Sstevel@tonic-gate * Where each component expresses as a character, 2357c478bd9Sstevel@tonic-gate * the corresponding part of the IP address 2367c478bd9Sstevel@tonic-gate * and port number. 2377c478bd9Sstevel@tonic-gate * Thus 127.0.0.1, port 2345 looks like: 2387c478bd9Sstevel@tonic-gate * 2397c478bd9Sstevel@tonic-gate * 49 50 55 46 48 46 48 46 49 46 57 46 52 49 2407c478bd9Sstevel@tonic-gate * 1 2 7 . 0 . 0 . 1 . 9 . 4 1 2417c478bd9Sstevel@tonic-gate * 2427c478bd9Sstevel@tonic-gate * 2345 = 929base16 = 9.32+9 = 9.41 2437c478bd9Sstevel@tonic-gate */ 2447c478bd9Sstevel@tonic-gate (void) strtoi(addr, &next); 2457c478bd9Sstevel@tonic-gate (void) strtoi(next, &next); 2467c478bd9Sstevel@tonic-gate (void) strtoi(next, &next); 2477c478bd9Sstevel@tonic-gate (void) strtoi(next, &next); 2487c478bd9Sstevel@tonic-gate p1 = strtoi(next, &next); 2497c478bd9Sstevel@tonic-gate p2 = strtoi(next, &next); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate } else if (af == AF_INET6) { 2527c478bd9Sstevel@tonic-gate /* 2537c478bd9Sstevel@tonic-gate * An IPv6 address is expressed in following two formats 2547c478bd9Sstevel@tonic-gate * fec0:A02::2:202:4FCD or 2557c478bd9Sstevel@tonic-gate * ::10.9.2.1 2567c478bd9Sstevel@tonic-gate * An universal address will have porthi.portlo appended to 2577c478bd9Sstevel@tonic-gate * v6 address. So always look for the last two dots when 2587c478bd9Sstevel@tonic-gate * extracting port number. 2597c478bd9Sstevel@tonic-gate */ 2607c478bd9Sstevel@tonic-gate next = addr; 2617c478bd9Sstevel@tonic-gate while (next = strchr(next, '.')) { 2627c478bd9Sstevel@tonic-gate p = ++next; 2637c478bd9Sstevel@tonic-gate next = strchr(next, '.'); 2647c478bd9Sstevel@tonic-gate next++; 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate p1 = strtoi(p, &p); 2677c478bd9Sstevel@tonic-gate p2 = strtoi(p, &p); 2687c478bd9Sstevel@tonic-gate RPCLOG(1, "rpc_uaddr2port: IPv6 port %d\n", ((p1 << 8) + p2)); 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate return ((p1 << 8) + p2); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * Modified strtol(3). Should we be using mi_strtol() instead? 2767c478bd9Sstevel@tonic-gate */ 2777c478bd9Sstevel@tonic-gate static int 2787c478bd9Sstevel@tonic-gate strtoi(char *str, char **ptr) 2797c478bd9Sstevel@tonic-gate { 2807c478bd9Sstevel@tonic-gate int c; 2817c478bd9Sstevel@tonic-gate int val; 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate for (val = 0, c = *str++; c >= '0' && c <= '9'; c = *str++) { 2847c478bd9Sstevel@tonic-gate val *= 10; 2857c478bd9Sstevel@tonic-gate val += c - '0'; 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate *ptr = str; 2887c478bd9Sstevel@tonic-gate return (val); 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate /* 2927c478bd9Sstevel@tonic-gate * Utilities for manipulating netbuf's. 2937c478bd9Sstevel@tonic-gate * 2947c478bd9Sstevel@tonic-gate * Note that loopback addresses are not null-terminated, so these utilities 2957c478bd9Sstevel@tonic-gate * typically use the strn* string routines. 2967c478bd9Sstevel@tonic-gate */ 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate /* 2997c478bd9Sstevel@tonic-gate * Utilities to patch a port number (for NC_INET protocols) or a 3007c478bd9Sstevel@tonic-gate * port name (for NC_LOOPBACK) into a network address. 3017c478bd9Sstevel@tonic-gate */ 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * PSARC 2003/523 Contract Private Interface 3067c478bd9Sstevel@tonic-gate * put_inet_port 3077c478bd9Sstevel@tonic-gate * Changes must be reviewed by Solaris File Sharing 3087c478bd9Sstevel@tonic-gate * Changes must be communicated to contract-2003-523@sun.com 3097c478bd9Sstevel@tonic-gate */ 3107c478bd9Sstevel@tonic-gate void 3117c478bd9Sstevel@tonic-gate put_inet_port(struct netbuf *addr, ushort_t port) 3127c478bd9Sstevel@tonic-gate { 3137c478bd9Sstevel@tonic-gate /* 3147c478bd9Sstevel@tonic-gate * Easy - we always patch an unsigned short on top of an 3157c478bd9Sstevel@tonic-gate * unsigned short. No changes to addr's len or maxlen are 3167c478bd9Sstevel@tonic-gate * necessary. 3177c478bd9Sstevel@tonic-gate */ 3187c478bd9Sstevel@tonic-gate ((struct sockaddr_in *)(addr->buf))->sin_port = port; 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate void 3227c478bd9Sstevel@tonic-gate put_inet6_port(struct netbuf *addr, ushort_t port) 3237c478bd9Sstevel@tonic-gate { 3247c478bd9Sstevel@tonic-gate ((struct sockaddr_in6 *)(addr->buf))->sin6_port = port; 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate void 3287c478bd9Sstevel@tonic-gate put_loopback_port(struct netbuf *addr, char *port) 3297c478bd9Sstevel@tonic-gate { 3307c478bd9Sstevel@tonic-gate char *dot; 3317c478bd9Sstevel@tonic-gate char *newbuf; 3327c478bd9Sstevel@tonic-gate int newlen; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate /* 3367c478bd9Sstevel@tonic-gate * We must make sure the addr has enough space for us, 3377c478bd9Sstevel@tonic-gate * patch in `port', and then adjust addr's len and maxlen 3387c478bd9Sstevel@tonic-gate * to reflect the change. 3397c478bd9Sstevel@tonic-gate */ 3407c478bd9Sstevel@tonic-gate if ((dot = strnrchr(addr->buf, '.', addr->len)) == (char *)NULL) 3417c478bd9Sstevel@tonic-gate return; 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate newlen = (int)((dot - addr->buf + 1) + strlen(port)); 3447c478bd9Sstevel@tonic-gate if (newlen > addr->maxlen) { 3457c478bd9Sstevel@tonic-gate newbuf = kmem_zalloc(newlen, KM_SLEEP); 3467c478bd9Sstevel@tonic-gate bcopy(addr->buf, newbuf, addr->len); 3477c478bd9Sstevel@tonic-gate kmem_free(addr->buf, addr->maxlen); 3487c478bd9Sstevel@tonic-gate addr->buf = newbuf; 3497c478bd9Sstevel@tonic-gate addr->len = addr->maxlen = newlen; 3507c478bd9Sstevel@tonic-gate dot = strnrchr(addr->buf, '.', addr->len); 3517c478bd9Sstevel@tonic-gate } else { 3527c478bd9Sstevel@tonic-gate addr->len = newlen; 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate (void) strncpy(++dot, port, strlen(port)); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* 3597c478bd9Sstevel@tonic-gate * Convert a loopback universal address to a loopback transport address. 3607c478bd9Sstevel@tonic-gate */ 3617c478bd9Sstevel@tonic-gate static void 3627c478bd9Sstevel@tonic-gate loopb_u2t(const char *ua, struct netbuf *addr) 3637c478bd9Sstevel@tonic-gate { 3647c478bd9Sstevel@tonic-gate size_t stringlen = strlen(ua) + 1; 3657c478bd9Sstevel@tonic-gate const char *univp; /* ptr into universal addr */ 3667c478bd9Sstevel@tonic-gate char *transp; /* ptr into transport addr */ 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* Make sure the netbuf will be big enough. */ 3697c478bd9Sstevel@tonic-gate if (addr->maxlen < stringlen) { 3707c478bd9Sstevel@tonic-gate grow_netbuf(addr, stringlen); 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate univp = ua; 3747c478bd9Sstevel@tonic-gate transp = addr->buf; 3757c478bd9Sstevel@tonic-gate while (*univp != NULL) { 3767c478bd9Sstevel@tonic-gate if (*univp == '\\' && *(univp+1) == '\\') { 3777c478bd9Sstevel@tonic-gate *transp = '\\'; 3787c478bd9Sstevel@tonic-gate univp += 2; 3797c478bd9Sstevel@tonic-gate } else if (*univp == '\\') { 3807c478bd9Sstevel@tonic-gate /* octal character */ 3817c478bd9Sstevel@tonic-gate *transp = (((*(univp+1) - '0') & 3) << 6) + 3827c478bd9Sstevel@tonic-gate (((*(univp+2) - '0') & 7) << 3) + 3837c478bd9Sstevel@tonic-gate ((*(univp+3) - '0') & 7); 3847c478bd9Sstevel@tonic-gate univp += 4; 3857c478bd9Sstevel@tonic-gate } else { 3867c478bd9Sstevel@tonic-gate *transp = *univp; 3877c478bd9Sstevel@tonic-gate univp++; 3887c478bd9Sstevel@tonic-gate } 3897c478bd9Sstevel@tonic-gate transp++; 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate addr->len = (unsigned int)(transp - addr->buf); 3937c478bd9Sstevel@tonic-gate ASSERT(addr->len <= addr->maxlen); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 3977c478bd9Sstevel@tonic-gate * Make sure the given netbuf has a maxlen at least as big as the given 3987c478bd9Sstevel@tonic-gate * length. 3997c478bd9Sstevel@tonic-gate */ 4007c478bd9Sstevel@tonic-gate static void 4017c478bd9Sstevel@tonic-gate grow_netbuf(struct netbuf *nb, size_t length) 4027c478bd9Sstevel@tonic-gate { 4037c478bd9Sstevel@tonic-gate char *newbuf; 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate if (nb->maxlen >= length) 4067c478bd9Sstevel@tonic-gate return; 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate newbuf = kmem_zalloc(length, KM_SLEEP); 4097c478bd9Sstevel@tonic-gate bcopy(nb->buf, newbuf, nb->len); 4107c478bd9Sstevel@tonic-gate kmem_free(nb->buf, nb->maxlen); 4117c478bd9Sstevel@tonic-gate nb->buf = newbuf; 4127c478bd9Sstevel@tonic-gate nb->maxlen = (unsigned int)length; 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate /* 416546f41c4SDan Kruchinin * XXX: xdr_pmap is here, because it's the only XDR function 417546f41c4SDan Kruchinin * of portmap protocol. If there'll be more portmap functions, 418546f41c4SDan Kruchinin * it would be better to put them to a separate file. 419546f41c4SDan Kruchinin */ 420546f41c4SDan Kruchinin bool_t 421546f41c4SDan Kruchinin xdr_pmap(XDR *xdrs, PMAP *objp) 422546f41c4SDan Kruchinin { 423546f41c4SDan Kruchinin if (!xdr_rpcprog(xdrs, &objp->pm_prog)) 424546f41c4SDan Kruchinin return (FALSE); 425546f41c4SDan Kruchinin if (!xdr_rpcvers(xdrs, &objp->pm_vers)) 426546f41c4SDan Kruchinin return (FALSE); 427546f41c4SDan Kruchinin if (!xdr_rpcprot(xdrs, &objp->pm_prot)) 428546f41c4SDan Kruchinin return (FALSE); 429546f41c4SDan Kruchinin if (!xdr_u_int(xdrs, &objp->pm_port)) 430546f41c4SDan Kruchinin return (FALSE); 431546f41c4SDan Kruchinin 432546f41c4SDan Kruchinin return (TRUE); 433546f41c4SDan Kruchinin } 434546f41c4SDan Kruchinin 435546f41c4SDan Kruchinin /* 436546f41c4SDan Kruchinin * Get remote port via PORTMAP protocol version 2 (works for IPv4 only) 437546f41c4SDan Kruchinin * according to RFC 1833, section 3. 438546f41c4SDan Kruchinin */ 439546f41c4SDan Kruchinin static enum clnt_stat 440546f41c4SDan Kruchinin portmap_getport(struct knetconfig *config, rpcprog_t prog, rpcvers_t vers, 441546f41c4SDan Kruchinin struct netbuf *addr, struct timeval tmo) 442546f41c4SDan Kruchinin { 443546f41c4SDan Kruchinin enum clnt_stat status; 444546f41c4SDan Kruchinin CLIENT *client = NULL; 445546f41c4SDan Kruchinin k_sigset_t oldmask; 446546f41c4SDan Kruchinin k_sigset_t newmask; 447546f41c4SDan Kruchinin ushort_t port = 0; 448546f41c4SDan Kruchinin struct pmap parms; 449546f41c4SDan Kruchinin 450546f41c4SDan Kruchinin ASSERT(strcmp(config->knc_protofmly, NC_INET) == 0); 451546f41c4SDan Kruchinin 452546f41c4SDan Kruchinin bzero(&parms, sizeof (parms)); 453546f41c4SDan Kruchinin parms.pm_prog = prog; 454546f41c4SDan Kruchinin parms.pm_vers = vers; 455546f41c4SDan Kruchinin if (strcmp(config->knc_proto, NC_TCP) == 0) { 456546f41c4SDan Kruchinin parms.pm_prot = IPPROTO_TCP; 457546f41c4SDan Kruchinin } else { /* NC_UDP */ 458546f41c4SDan Kruchinin parms.pm_prot = IPPROTO_UDP; 459546f41c4SDan Kruchinin } 460546f41c4SDan Kruchinin 461546f41c4SDan Kruchinin 462546f41c4SDan Kruchinin /* 463546f41c4SDan Kruchinin * Mask all signals before doing RPC network operations 464546f41c4SDan Kruchinin * in the same way rpcbind_getaddr() does (see comments 465546f41c4SDan Kruchinin * there). 466546f41c4SDan Kruchinin */ 467546f41c4SDan Kruchinin sigfillset(&newmask); 468546f41c4SDan Kruchinin sigreplace(&newmask, &oldmask); 469546f41c4SDan Kruchinin 470546f41c4SDan Kruchinin if (clnt_tli_kcreate(config, addr, PMAPPROG, 471546f41c4SDan Kruchinin PMAPVERS, 0, 0, CRED(), &client)) { 472546f41c4SDan Kruchinin sigreplace(&oldmask, (k_sigset_t *)NULL); 473546f41c4SDan Kruchinin return (RPC_TLIERROR); 474546f41c4SDan Kruchinin } 475546f41c4SDan Kruchinin 476546f41c4SDan Kruchinin client->cl_nosignal = 1; 477546f41c4SDan Kruchinin status = CLNT_CALL(client, PMAPPROC_GETPORT, 478546f41c4SDan Kruchinin xdr_pmap, (char *)&parms, 479546f41c4SDan Kruchinin xdr_u_short, (char *)&port, tmo); 480546f41c4SDan Kruchinin 481546f41c4SDan Kruchinin sigreplace(&oldmask, (k_sigset_t *)NULL); 482546f41c4SDan Kruchinin if (status != RPC_SUCCESS) 483546f41c4SDan Kruchinin goto out; 484546f41c4SDan Kruchinin if (port == 0) { 485546f41c4SDan Kruchinin status = RPC_PROGNOTREGISTERED; 486546f41c4SDan Kruchinin goto out; 487546f41c4SDan Kruchinin } 488546f41c4SDan Kruchinin 489546f41c4SDan Kruchinin put_inet_port(addr, ntohs(port)); 490546f41c4SDan Kruchinin 491546f41c4SDan Kruchinin out: 492546f41c4SDan Kruchinin auth_destroy(client->cl_auth); 493546f41c4SDan Kruchinin clnt_destroy(client); 494546f41c4SDan Kruchinin 495546f41c4SDan Kruchinin return (status); 496546f41c4SDan Kruchinin } 497546f41c4SDan Kruchinin 498546f41c4SDan Kruchinin /* 4997c478bd9Sstevel@tonic-gate * Try to get the address for the desired service by using the rpcbind 5007c478bd9Sstevel@tonic-gate * protocol. Ignores signals. If addr is a loopback address, it is 501*6935f61bSMarcel Telka * expected to be initialized to "localhost.". 502546f41c4SDan Kruchinin * rpcbind_getaddr() is able to work with RPCBIND protocol version 3 and 4 503546f41c4SDan Kruchinin * and PORTMAP protocol version 2. 504546f41c4SDan Kruchinin * It tries version 4 at first, then version 3 and finally (if both failed) 505546f41c4SDan Kruchinin * it tries portmapper protocol version 2. 5067c478bd9Sstevel@tonic-gate */ 5077c478bd9Sstevel@tonic-gate enum clnt_stat 5087c478bd9Sstevel@tonic-gate rpcbind_getaddr(struct knetconfig *config, rpcprog_t prog, rpcvers_t vers, 5097c478bd9Sstevel@tonic-gate struct netbuf *addr) 5107c478bd9Sstevel@tonic-gate { 5117c478bd9Sstevel@tonic-gate char *ua = NULL; 5127c478bd9Sstevel@tonic-gate enum clnt_stat status; 5137c478bd9Sstevel@tonic-gate RPCB parms; 5147c478bd9Sstevel@tonic-gate struct timeval tmo; 5157c478bd9Sstevel@tonic-gate k_sigset_t oldmask; 5167c478bd9Sstevel@tonic-gate k_sigset_t newmask; 5177c478bd9Sstevel@tonic-gate ushort_t port; 5180bfcf696Sgt29601 int iptype; 519546f41c4SDan Kruchinin rpcvers_t rpcbv; 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate /* 5227c478bd9Sstevel@tonic-gate * Call rpcbind (local or remote) to get an address we can use 5237c478bd9Sstevel@tonic-gate * in an RPC client handle. 5247c478bd9Sstevel@tonic-gate */ 5257c478bd9Sstevel@tonic-gate tmo.tv_sec = RPC_PMAP_TIMEOUT; 5267c478bd9Sstevel@tonic-gate tmo.tv_usec = 0; 5277c478bd9Sstevel@tonic-gate parms.r_prog = prog; 5287c478bd9Sstevel@tonic-gate parms.r_vers = vers; 5297c478bd9Sstevel@tonic-gate parms.r_addr = parms.r_owner = ""; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate if (strcmp(config->knc_protofmly, NC_INET) == 0) { 532546f41c4SDan Kruchinin put_inet_port(addr, htons(PMAPPORT)); 533546f41c4SDan Kruchinin 5347c478bd9Sstevel@tonic-gate if (strcmp(config->knc_proto, NC_TCP) == 0) 5357c478bd9Sstevel@tonic-gate parms.r_netid = "tcp"; 5367c478bd9Sstevel@tonic-gate else 5377c478bd9Sstevel@tonic-gate parms.r_netid = "udp"; 538546f41c4SDan Kruchinin 5397c478bd9Sstevel@tonic-gate } else if (strcmp(config->knc_protofmly, NC_INET6) == 0) { 5407c478bd9Sstevel@tonic-gate if (strcmp(config->knc_proto, NC_TCP) == 0) 5417c478bd9Sstevel@tonic-gate parms.r_netid = "tcp6"; 5427c478bd9Sstevel@tonic-gate else 5437c478bd9Sstevel@tonic-gate parms.r_netid = "udp6"; 5447c478bd9Sstevel@tonic-gate put_inet6_port(addr, htons(PMAPPORT)); 5457c478bd9Sstevel@tonic-gate } else if (strcmp(config->knc_protofmly, NC_LOOPBACK) == 0) { 5467c478bd9Sstevel@tonic-gate ASSERT(strnrchr(addr->buf, '.', addr->len) != NULL); 5477c478bd9Sstevel@tonic-gate if (config->knc_semantics == NC_TPI_COTS_ORD) 5487c478bd9Sstevel@tonic-gate parms.r_netid = "ticotsord"; 5497c478bd9Sstevel@tonic-gate else if (config->knc_semantics == NC_TPI_COTS) 5507c478bd9Sstevel@tonic-gate parms.r_netid = "ticots"; 5517c478bd9Sstevel@tonic-gate else 5527c478bd9Sstevel@tonic-gate parms.r_netid = "ticlts"; 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate put_loopback_port(addr, "rpc"); 5557c478bd9Sstevel@tonic-gate } else { 5567c478bd9Sstevel@tonic-gate status = RPC_UNKNOWNPROTO; 5577c478bd9Sstevel@tonic-gate goto out; 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate /* 561546f41c4SDan Kruchinin * Try RPCBIND versions 4 and 3 (if 4 fails). 562546f41c4SDan Kruchinin */ 563546f41c4SDan Kruchinin for (rpcbv = RPCBVERS4; rpcbv >= RPCBVERS; rpcbv--) { 564546f41c4SDan Kruchinin CLIENT *client = NULL; 565546f41c4SDan Kruchinin 566546f41c4SDan Kruchinin if (ua != NULL) { 567546f41c4SDan Kruchinin xdr_free(xdr_wrapstring, (char *)&ua); 568546f41c4SDan Kruchinin ua = NULL; 569546f41c4SDan Kruchinin } 570546f41c4SDan Kruchinin 571546f41c4SDan Kruchinin /* 5727c478bd9Sstevel@tonic-gate * Mask signals for the duration of the handle creation and 5737c478bd9Sstevel@tonic-gate * RPC calls. This allows relatively normal operation with a 5747c478bd9Sstevel@tonic-gate * signal already posted to our thread (e.g., when we are 5757c478bd9Sstevel@tonic-gate * sending an NLM_CANCEL in response to catching a signal). 5767c478bd9Sstevel@tonic-gate * 5777c478bd9Sstevel@tonic-gate * Any further exit paths from this routine must restore 5787c478bd9Sstevel@tonic-gate * the original signal mask. 5797c478bd9Sstevel@tonic-gate */ 5807c478bd9Sstevel@tonic-gate sigfillset(&newmask); 5817c478bd9Sstevel@tonic-gate sigreplace(&newmask, &oldmask); 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate if (clnt_tli_kcreate(config, addr, RPCBPROG, 584546f41c4SDan Kruchinin rpcbv, 0, 0, CRED(), &client)) { 5857c478bd9Sstevel@tonic-gate status = RPC_TLIERROR; 5867c478bd9Sstevel@tonic-gate sigreplace(&oldmask, (k_sigset_t *)NULL); 587546f41c4SDan Kruchinin continue; 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate client->cl_nosignal = 1; 591546f41c4SDan Kruchinin status = CLNT_CALL(client, RPCBPROC_GETADDR, 5927c478bd9Sstevel@tonic-gate xdr_rpcb, (char *)&parms, 593546f41c4SDan Kruchinin xdr_wrapstring, (char *)&ua, tmo); 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate sigreplace(&oldmask, (k_sigset_t *)NULL); 596546f41c4SDan Kruchinin auth_destroy(client->cl_auth); 597546f41c4SDan Kruchinin clnt_destroy(client); 5987c478bd9Sstevel@tonic-gate 599546f41c4SDan Kruchinin if (status == RPC_SUCCESS) { 6007c478bd9Sstevel@tonic-gate if (ua == NULL || *ua == NULL) { 6017c478bd9Sstevel@tonic-gate status = RPC_PROGNOTREGISTERED; 602546f41c4SDan Kruchinin continue; 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 605546f41c4SDan Kruchinin break; 606546f41c4SDan Kruchinin } 607546f41c4SDan Kruchinin } 608546f41c4SDan Kruchinin if (status != RPC_SUCCESS) 609546f41c4SDan Kruchinin goto try_portmap; 610546f41c4SDan Kruchinin 6117c478bd9Sstevel@tonic-gate /* 6127c478bd9Sstevel@tonic-gate * Convert the universal address to the transport address. 6137c478bd9Sstevel@tonic-gate * Theoretically, we should call the local rpcbind to translate 6147c478bd9Sstevel@tonic-gate * from the universal address to the transport address, but it gets 6157c478bd9Sstevel@tonic-gate * complicated (e.g., there's no direct way to tell rpcbind that we 6167c478bd9Sstevel@tonic-gate * want an IP address instead of a loopback address). Note that 6177c478bd9Sstevel@tonic-gate * the transport address is potentially host-specific, so we can't 6187c478bd9Sstevel@tonic-gate * just ask the remote rpcbind, because it might give us the wrong 6197c478bd9Sstevel@tonic-gate * answer. 6207c478bd9Sstevel@tonic-gate */ 6217c478bd9Sstevel@tonic-gate if (strcmp(config->knc_protofmly, NC_INET) == 0) { 6220bfcf696Sgt29601 /* make sure that the ip address is the correct type */ 6230bfcf696Sgt29601 if (rpc_iptype(ua, &iptype) != 0) { 6240bfcf696Sgt29601 status = RPC_UNKNOWNADDR; 625546f41c4SDan Kruchinin goto try_portmap; 6260bfcf696Sgt29601 } 6270bfcf696Sgt29601 port = rpc_uaddr2port(iptype, ua); 6287c478bd9Sstevel@tonic-gate put_inet_port(addr, ntohs(port)); 6297c478bd9Sstevel@tonic-gate } else if (strcmp(config->knc_protofmly, NC_INET6) == 0) { 6300bfcf696Sgt29601 /* make sure that the ip address is the correct type */ 6310bfcf696Sgt29601 if (rpc_iptype(ua, &iptype) != 0) { 6320bfcf696Sgt29601 status = RPC_UNKNOWNADDR; 633546f41c4SDan Kruchinin goto try_portmap; 6340bfcf696Sgt29601 } 6350bfcf696Sgt29601 port = rpc_uaddr2port(iptype, ua); 6367c478bd9Sstevel@tonic-gate put_inet6_port(addr, ntohs(port)); 6377c478bd9Sstevel@tonic-gate } else if (strcmp(config->knc_protofmly, NC_LOOPBACK) == 0) { 6387c478bd9Sstevel@tonic-gate loopb_u2t(ua, addr); 6397c478bd9Sstevel@tonic-gate } else { 6407c478bd9Sstevel@tonic-gate /* "can't happen" - should have been checked for above */ 6417c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "rpcbind_getaddr: bad protocol family"); 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate 644546f41c4SDan Kruchinin try_portmap: 645546f41c4SDan Kruchinin if (status != RPC_SUCCESS && 646546f41c4SDan Kruchinin strcmp(config->knc_protofmly, NC_INET) == 0) { 647546f41c4SDan Kruchinin /* 648546f41c4SDan Kruchinin * For IPv4 try to get remote port via PORTMAP protocol. 649546f41c4SDan Kruchinin * NOTE: if we're here, then all attempts to get remote 650546f41c4SDan Kruchinin * port via RPCBIND protocol failed. 651546f41c4SDan Kruchinin */ 652546f41c4SDan Kruchinin 653546f41c4SDan Kruchinin DTRACE_PROBE1(try__portmap, enum clnt_stat, status); 654546f41c4SDan Kruchinin status = portmap_getport(config, prog, vers, addr, tmo); 6557c478bd9Sstevel@tonic-gate } 656546f41c4SDan Kruchinin 657546f41c4SDan Kruchinin out: 6587c478bd9Sstevel@tonic-gate if (ua != NULL) 6597c478bd9Sstevel@tonic-gate xdr_free(xdr_wrapstring, (char *)&ua); 6607c478bd9Sstevel@tonic-gate return (status); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate static const char *tpiprims[] = { 6647c478bd9Sstevel@tonic-gate "T_CONN_REQ 0 connection request", 6657c478bd9Sstevel@tonic-gate "T_CONN_RES 1 connection response", 6667c478bd9Sstevel@tonic-gate "T_DISCON_REQ 2 disconnect request", 6677c478bd9Sstevel@tonic-gate "T_DATA_REQ 3 data request", 6687c478bd9Sstevel@tonic-gate "T_EXDATA_REQ 4 expedited data request", 6697c478bd9Sstevel@tonic-gate "T_INFO_REQ 5 information request", 6707c478bd9Sstevel@tonic-gate "T_BIND_REQ 6 bind request", 6717c478bd9Sstevel@tonic-gate "T_UNBIND_REQ 7 unbind request", 6727c478bd9Sstevel@tonic-gate "T_UNITDATA_REQ 8 unitdata request", 6737c478bd9Sstevel@tonic-gate "T_OPTMGMT_REQ 9 manage options req", 6747c478bd9Sstevel@tonic-gate "T_ORDREL_REQ 10 orderly release req", 6757c478bd9Sstevel@tonic-gate "T_CONN_IND 11 connection indication", 6767c478bd9Sstevel@tonic-gate "T_CONN_CON 12 connection confirmation", 6777c478bd9Sstevel@tonic-gate "T_DISCON_IND 13 disconnect indication", 6787c478bd9Sstevel@tonic-gate "T_DATA_IND 14 data indication", 6797c478bd9Sstevel@tonic-gate "T_EXDATA_IND 15 expeditied data indication", 6807c478bd9Sstevel@tonic-gate "T_INFO_ACK 16 information acknowledgment", 6817c478bd9Sstevel@tonic-gate "T_BIND_ACK 17 bind acknowledment", 6827c478bd9Sstevel@tonic-gate "T_ERROR_ACK 18 error acknowledgment", 6837c478bd9Sstevel@tonic-gate "T_OK_ACK 19 ok acknowledgment", 6847c478bd9Sstevel@tonic-gate "T_UNITDATA_IND 20 unitdata indication", 6857c478bd9Sstevel@tonic-gate "T_UDERROR_IND 21 unitdata error indication", 6867c478bd9Sstevel@tonic-gate "T_OPTMGMT_ACK 22 manage options ack", 6877c478bd9Sstevel@tonic-gate "T_ORDREL_IND 23 orderly release ind" 6887c478bd9Sstevel@tonic-gate }; 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate const char * 6927c478bd9Sstevel@tonic-gate rpc_tpiprim2name(uint_t prim) 6937c478bd9Sstevel@tonic-gate { 6947c478bd9Sstevel@tonic-gate if (prim > (sizeof (tpiprims) / sizeof (tpiprims[0]) - 1)) 6957c478bd9Sstevel@tonic-gate return ("unknown primitive"); 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate return (tpiprims[prim]); 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate static const char *tpierrs[] = { 7017c478bd9Sstevel@tonic-gate "error zero 0", 7027c478bd9Sstevel@tonic-gate "TBADADDR 1 incorrect addr format", 7037c478bd9Sstevel@tonic-gate "TBADOPT 2 incorrect option format", 7047c478bd9Sstevel@tonic-gate "TACCES 3 incorrect permissions", 7057c478bd9Sstevel@tonic-gate "TBADF 4 illegal transport fd", 7067c478bd9Sstevel@tonic-gate "TNOADDR 5 couldn't allocate addr", 7077c478bd9Sstevel@tonic-gate "TOUTSTATE 6 out of state", 7087c478bd9Sstevel@tonic-gate "TBADSEQ 7 bad call sequnce number", 7097c478bd9Sstevel@tonic-gate "TSYSERR 8 system error", 7107c478bd9Sstevel@tonic-gate "TLOOK 9 event requires attention", 7117c478bd9Sstevel@tonic-gate "TBADDATA 10 illegal amount of data", 7127c478bd9Sstevel@tonic-gate "TBUFOVFLW 11 buffer not large enough", 7137c478bd9Sstevel@tonic-gate "TFLOW 12 flow control", 7147c478bd9Sstevel@tonic-gate "TNODATA 13 no data", 7157c478bd9Sstevel@tonic-gate "TNODIS 14 discon_ind not found on q", 7167c478bd9Sstevel@tonic-gate "TNOUDERR 15 unitdata error not found", 7177c478bd9Sstevel@tonic-gate "TBADFLAG 16 bad flags", 7187c478bd9Sstevel@tonic-gate "TNOREL 17 no ord rel found on q", 7197c478bd9Sstevel@tonic-gate "TNOTSUPPORT 18 primitive not supported", 7207c478bd9Sstevel@tonic-gate "TSTATECHNG 19 state is in process of changing" 7217c478bd9Sstevel@tonic-gate }; 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate const char * 7257c478bd9Sstevel@tonic-gate rpc_tpierr2name(uint_t err) 7267c478bd9Sstevel@tonic-gate { 7277c478bd9Sstevel@tonic-gate if (err > (sizeof (tpierrs) / sizeof (tpierrs[0]) - 1)) 7287c478bd9Sstevel@tonic-gate return ("unknown error"); 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate return (tpierrs[err]); 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate /* 7347c478bd9Sstevel@tonic-gate * derive the code from user land inet_top6 7357c478bd9Sstevel@tonic-gate * convert IPv6 binary address into presentation (printable) format 7367c478bd9Sstevel@tonic-gate */ 7377c478bd9Sstevel@tonic-gate #define INADDRSZ 4 7387c478bd9Sstevel@tonic-gate #define IN6ADDRSZ 16 7397c478bd9Sstevel@tonic-gate #define INT16SZ 2 7407c478bd9Sstevel@tonic-gate const char * 7417c478bd9Sstevel@tonic-gate kinet_ntop6(src, dst, size) 7427c478bd9Sstevel@tonic-gate uchar_t *src; 7437c478bd9Sstevel@tonic-gate char *dst; 7447c478bd9Sstevel@tonic-gate size_t size; 7457c478bd9Sstevel@tonic-gate { 7467c478bd9Sstevel@tonic-gate /* 7477c478bd9Sstevel@tonic-gate * Note that int32_t and int16_t need only be "at least" large enough 7487c478bd9Sstevel@tonic-gate * to contain a value of the specified size. On some systems, like 7497c478bd9Sstevel@tonic-gate * Crays, there is no such thing as an integer variable with 16 bits. 7507c478bd9Sstevel@tonic-gate * Keep this in mind if you think this function should have been coded 7517c478bd9Sstevel@tonic-gate * to use pointer overlays. All the world's not a VAX. 7527c478bd9Sstevel@tonic-gate */ 7537c478bd9Sstevel@tonic-gate char tmp[sizeof ("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; 7547c478bd9Sstevel@tonic-gate char *tp; 7557c478bd9Sstevel@tonic-gate struct { int base, len; } best, cur; 7567c478bd9Sstevel@tonic-gate uint_t words[IN6ADDRSZ / INT16SZ]; 7577c478bd9Sstevel@tonic-gate int i; 7587c478bd9Sstevel@tonic-gate size_t len; /* this is used to track the sprintf len */ 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate /* 7617c478bd9Sstevel@tonic-gate * Preprocess: 7627c478bd9Sstevel@tonic-gate * Copy the input (bytewise) array into a wordwise array. 7637c478bd9Sstevel@tonic-gate * Find the longest run of 0x00's in src[] for :: shorthanding. 7647c478bd9Sstevel@tonic-gate */ 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate bzero(words, sizeof (words)); 7677c478bd9Sstevel@tonic-gate for (i = 0; i < IN6ADDRSZ; i++) 7687c478bd9Sstevel@tonic-gate words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); 7697c478bd9Sstevel@tonic-gate best.base = -1; 7707c478bd9Sstevel@tonic-gate cur.base = -1; 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { 7737c478bd9Sstevel@tonic-gate if (words[i] == 0) { 7747c478bd9Sstevel@tonic-gate if (cur.base == -1) 7757c478bd9Sstevel@tonic-gate cur.base = i, cur.len = 1; 7767c478bd9Sstevel@tonic-gate else 7777c478bd9Sstevel@tonic-gate cur.len++; 7787c478bd9Sstevel@tonic-gate } else { 7797c478bd9Sstevel@tonic-gate if (cur.base != -1) { 7807c478bd9Sstevel@tonic-gate if (best.base == -1 || cur.len > best.len) 7817c478bd9Sstevel@tonic-gate best = cur; 7827c478bd9Sstevel@tonic-gate cur.base = -1; 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate } 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate if (cur.base != -1) { 7877c478bd9Sstevel@tonic-gate if (best.base == -1 || cur.len > best.len) 7887c478bd9Sstevel@tonic-gate best = cur; 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate if (best.base != -1 && best.len < 2) 7927c478bd9Sstevel@tonic-gate best.base = -1; 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate /* 7957c478bd9Sstevel@tonic-gate * Format the result. 7967c478bd9Sstevel@tonic-gate */ 7977c478bd9Sstevel@tonic-gate tp = tmp; 7987c478bd9Sstevel@tonic-gate for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { 7997c478bd9Sstevel@tonic-gate /* Are we inside the best run of 0x00's? */ 8007c478bd9Sstevel@tonic-gate if (best.base != -1 && i >= best.base && 8017c478bd9Sstevel@tonic-gate i < (best.base + best.len)) { 8027c478bd9Sstevel@tonic-gate if (i == best.base) 8037c478bd9Sstevel@tonic-gate *tp++ = ':'; 8047c478bd9Sstevel@tonic-gate continue; 8057c478bd9Sstevel@tonic-gate } 8067c478bd9Sstevel@tonic-gate /* Are we following an initial run of 0x00s or any real hex? */ 8077c478bd9Sstevel@tonic-gate if (i != 0) 8087c478bd9Sstevel@tonic-gate *tp++ = ':'; 8097c478bd9Sstevel@tonic-gate (void) sprintf(tp, "%x", words[i]); 8107c478bd9Sstevel@tonic-gate len = strlen(tp); 8117c478bd9Sstevel@tonic-gate tp += len; 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate /* Was it a trailing run of 0x00's? */ 8147c478bd9Sstevel@tonic-gate if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) 8157c478bd9Sstevel@tonic-gate *tp++ = ':'; 8167c478bd9Sstevel@tonic-gate *tp++ = '\0'; 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate /* 8197c478bd9Sstevel@tonic-gate * Check for overflow, copy, and we're done. 8207c478bd9Sstevel@tonic-gate */ 8217c478bd9Sstevel@tonic-gate if ((int)(tp - tmp) > size) { 8227c478bd9Sstevel@tonic-gate return (NULL); 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate (void) strcpy(dst, tmp); 8257c478bd9Sstevel@tonic-gate return (dst); 8267c478bd9Sstevel@tonic-gate } 827