18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2009, Oracle. All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Convert socket addresses to presentation addresses and universal 68c2ecf20Sopenharmony_ci * addresses, and vice versa. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Universal addresses are introduced by RFC 1833 and further refined by 98c2ecf20Sopenharmony_ci * recent RFCs describing NFSv4. The universal address format is part 108c2ecf20Sopenharmony_ci * of the external (network) interface provided by rpcbind version 3 118c2ecf20Sopenharmony_ci * and 4, and by NFSv4. Such an address is a string containing a 128c2ecf20Sopenharmony_ci * presentation format IP address followed by a port number in 138c2ecf20Sopenharmony_ci * "hibyte.lobyte" format. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * IPv6 addresses can also include a scope ID, typically denoted by 168c2ecf20Sopenharmony_ci * a '%' followed by a device name or a non-negative integer. Refer to 178c2ecf20Sopenharmony_ci * RFC 4291, Section 2.2 for details on IPv6 presentation formats. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <net/ipv6.h> 218c2ecf20Sopenharmony_ci#include <linux/sunrpc/addr.h> 228c2ecf20Sopenharmony_ci#include <linux/sunrpc/msg_prot.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include <linux/export.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic size_t rpc_ntop6_noscopeid(const struct sockaddr *sap, 298c2ecf20Sopenharmony_ci char *buf, const int buflen) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; 328c2ecf20Sopenharmony_ci const struct in6_addr *addr = &sin6->sin6_addr; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci /* 358c2ecf20Sopenharmony_ci * RFC 4291, Section 2.2.2 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * Shorthanded ANY address 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci if (ipv6_addr_any(addr)) 408c2ecf20Sopenharmony_ci return snprintf(buf, buflen, "::"); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* 438c2ecf20Sopenharmony_ci * RFC 4291, Section 2.2.2 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * Shorthanded loopback address 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci if (ipv6_addr_loopback(addr)) 488c2ecf20Sopenharmony_ci return snprintf(buf, buflen, "::1"); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci /* 518c2ecf20Sopenharmony_ci * RFC 4291, Section 2.2.3 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * Special presentation address format for mapped v4 548c2ecf20Sopenharmony_ci * addresses. 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ci if (ipv6_addr_v4mapped(addr)) 578c2ecf20Sopenharmony_ci return snprintf(buf, buflen, "::ffff:%pI4", 588c2ecf20Sopenharmony_ci &addr->s6_addr32[3]); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* 618c2ecf20Sopenharmony_ci * RFC 4291, Section 2.2.1 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_ci return snprintf(buf, buflen, "%pI6c", addr); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic size_t rpc_ntop6(const struct sockaddr *sap, 678c2ecf20Sopenharmony_ci char *buf, const size_t buflen) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; 708c2ecf20Sopenharmony_ci char scopebuf[IPV6_SCOPE_ID_LEN]; 718c2ecf20Sopenharmony_ci size_t len; 728c2ecf20Sopenharmony_ci int rc; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci len = rpc_ntop6_noscopeid(sap, buf, buflen); 758c2ecf20Sopenharmony_ci if (unlikely(len == 0)) 768c2ecf20Sopenharmony_ci return len; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) 798c2ecf20Sopenharmony_ci return len; 808c2ecf20Sopenharmony_ci if (sin6->sin6_scope_id == 0) 818c2ecf20Sopenharmony_ci return len; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci rc = snprintf(scopebuf, sizeof(scopebuf), "%c%u", 848c2ecf20Sopenharmony_ci IPV6_SCOPE_DELIMITER, sin6->sin6_scope_id); 858c2ecf20Sopenharmony_ci if (unlikely((size_t)rc >= sizeof(scopebuf))) 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci len += rc; 898c2ecf20Sopenharmony_ci if (unlikely(len >= buflen)) 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci strcat(buf, scopebuf); 938c2ecf20Sopenharmony_ci return len; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#else /* !IS_ENABLED(CONFIG_IPV6) */ 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic size_t rpc_ntop6_noscopeid(const struct sockaddr *sap, 998c2ecf20Sopenharmony_ci char *buf, const int buflen) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci return 0; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic size_t rpc_ntop6(const struct sockaddr *sap, 1058c2ecf20Sopenharmony_ci char *buf, const size_t buflen) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci return 0; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci#endif /* !IS_ENABLED(CONFIG_IPV6) */ 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int rpc_ntop4(const struct sockaddr *sap, 1138c2ecf20Sopenharmony_ci char *buf, const size_t buflen) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci const struct sockaddr_in *sin = (struct sockaddr_in *)sap; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return snprintf(buf, buflen, "%pI4", &sin->sin_addr); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/** 1218c2ecf20Sopenharmony_ci * rpc_ntop - construct a presentation address in @buf 1228c2ecf20Sopenharmony_ci * @sap: socket address 1238c2ecf20Sopenharmony_ci * @buf: construction area 1248c2ecf20Sopenharmony_ci * @buflen: size of @buf, in bytes 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci * Plants a %NUL-terminated string in @buf and returns the length 1278c2ecf20Sopenharmony_ci * of the string, excluding the %NUL. Otherwise zero is returned. 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_cisize_t rpc_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci switch (sap->sa_family) { 1328c2ecf20Sopenharmony_ci case AF_INET: 1338c2ecf20Sopenharmony_ci return rpc_ntop4(sap, buf, buflen); 1348c2ecf20Sopenharmony_ci case AF_INET6: 1358c2ecf20Sopenharmony_ci return rpc_ntop6(sap, buf, buflen); 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_ntop); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic size_t rpc_pton4(const char *buf, const size_t buflen, 1438c2ecf20Sopenharmony_ci struct sockaddr *sap, const size_t salen) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct sockaddr_in *sin = (struct sockaddr_in *)sap; 1468c2ecf20Sopenharmony_ci u8 *addr = (u8 *)&sin->sin_addr.s_addr; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (buflen > INET_ADDRSTRLEN || salen < sizeof(struct sockaddr_in)) 1498c2ecf20Sopenharmony_ci return 0; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci memset(sap, 0, sizeof(struct sockaddr_in)); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (in4_pton(buf, buflen, addr, '\0', NULL) == 0) 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci sin->sin_family = AF_INET; 1578c2ecf20Sopenharmony_ci return sizeof(struct sockaddr_in); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 1618c2ecf20Sopenharmony_cistatic int rpc_parse_scope_id(struct net *net, const char *buf, 1628c2ecf20Sopenharmony_ci const size_t buflen, const char *delim, 1638c2ecf20Sopenharmony_ci struct sockaddr_in6 *sin6) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci char p[IPV6_SCOPE_ID_LEN + 1]; 1668c2ecf20Sopenharmony_ci size_t len; 1678c2ecf20Sopenharmony_ci u32 scope_id = 0; 1688c2ecf20Sopenharmony_ci struct net_device *dev; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if ((buf + buflen) == delim) 1718c2ecf20Sopenharmony_ci return 1; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (*delim != IPV6_SCOPE_DELIMITER) 1748c2ecf20Sopenharmony_ci return 0; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci len = (buf + buflen) - delim - 1; 1808c2ecf20Sopenharmony_ci if (len > IPV6_SCOPE_ID_LEN) 1818c2ecf20Sopenharmony_ci return 0; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci memcpy(p, delim + 1, len); 1848c2ecf20Sopenharmony_ci p[len] = 0; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci dev = dev_get_by_name(net, p); 1878c2ecf20Sopenharmony_ci if (dev != NULL) { 1888c2ecf20Sopenharmony_ci scope_id = dev->ifindex; 1898c2ecf20Sopenharmony_ci dev_put(dev); 1908c2ecf20Sopenharmony_ci } else { 1918c2ecf20Sopenharmony_ci if (kstrtou32(p, 10, &scope_id) != 0) 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci sin6->sin6_scope_id = scope_id; 1968c2ecf20Sopenharmony_ci return 1; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen, 2008c2ecf20Sopenharmony_ci struct sockaddr *sap, const size_t salen) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; 2038c2ecf20Sopenharmony_ci u8 *addr = (u8 *)&sin6->sin6_addr.in6_u; 2048c2ecf20Sopenharmony_ci const char *delim; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (buflen > (INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN) || 2078c2ecf20Sopenharmony_ci salen < sizeof(struct sockaddr_in6)) 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci memset(sap, 0, sizeof(struct sockaddr_in6)); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (in6_pton(buf, buflen, addr, IPV6_SCOPE_DELIMITER, &delim) == 0) 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (!rpc_parse_scope_id(net, buf, buflen, delim, sin6)) 2168c2ecf20Sopenharmony_ci return 0; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci sin6->sin6_family = AF_INET6; 2198c2ecf20Sopenharmony_ci return sizeof(struct sockaddr_in6); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci#else 2228c2ecf20Sopenharmony_cistatic size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen, 2238c2ecf20Sopenharmony_ci struct sockaddr *sap, const size_t salen) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci return 0; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci#endif 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci/** 2308c2ecf20Sopenharmony_ci * rpc_pton - Construct a sockaddr in @sap 2318c2ecf20Sopenharmony_ci * @net: applicable network namespace 2328c2ecf20Sopenharmony_ci * @buf: C string containing presentation format IP address 2338c2ecf20Sopenharmony_ci * @buflen: length of presentation address in bytes 2348c2ecf20Sopenharmony_ci * @sap: buffer into which to plant socket address 2358c2ecf20Sopenharmony_ci * @salen: size of buffer in bytes 2368c2ecf20Sopenharmony_ci * 2378c2ecf20Sopenharmony_ci * Returns the size of the socket address if successful; otherwise 2388c2ecf20Sopenharmony_ci * zero is returned. 2398c2ecf20Sopenharmony_ci * 2408c2ecf20Sopenharmony_ci * Plants a socket address in @sap and returns the size of the 2418c2ecf20Sopenharmony_ci * socket address, if successful. Returns zero if an error 2428c2ecf20Sopenharmony_ci * occurred. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cisize_t rpc_pton(struct net *net, const char *buf, const size_t buflen, 2458c2ecf20Sopenharmony_ci struct sockaddr *sap, const size_t salen) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci unsigned int i; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci for (i = 0; i < buflen; i++) 2508c2ecf20Sopenharmony_ci if (buf[i] == ':') 2518c2ecf20Sopenharmony_ci return rpc_pton6(net, buf, buflen, sap, salen); 2528c2ecf20Sopenharmony_ci return rpc_pton4(buf, buflen, sap, salen); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_pton); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/** 2578c2ecf20Sopenharmony_ci * rpc_sockaddr2uaddr - Construct a universal address string from @sap. 2588c2ecf20Sopenharmony_ci * @sap: socket address 2598c2ecf20Sopenharmony_ci * @gfp_flags: allocation mode 2608c2ecf20Sopenharmony_ci * 2618c2ecf20Sopenharmony_ci * Returns a %NUL-terminated string in dynamically allocated memory; 2628c2ecf20Sopenharmony_ci * otherwise NULL is returned if an error occurred. Caller must 2638c2ecf20Sopenharmony_ci * free the returned string. 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_cichar *rpc_sockaddr2uaddr(const struct sockaddr *sap, gfp_t gfp_flags) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci char portbuf[RPCBIND_MAXUADDRPLEN]; 2688c2ecf20Sopenharmony_ci char addrbuf[RPCBIND_MAXUADDRLEN]; 2698c2ecf20Sopenharmony_ci unsigned short port; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci switch (sap->sa_family) { 2728c2ecf20Sopenharmony_ci case AF_INET: 2738c2ecf20Sopenharmony_ci if (rpc_ntop4(sap, addrbuf, sizeof(addrbuf)) == 0) 2748c2ecf20Sopenharmony_ci return NULL; 2758c2ecf20Sopenharmony_ci port = ntohs(((struct sockaddr_in *)sap)->sin_port); 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci case AF_INET6: 2788c2ecf20Sopenharmony_ci if (rpc_ntop6_noscopeid(sap, addrbuf, sizeof(addrbuf)) == 0) 2798c2ecf20Sopenharmony_ci return NULL; 2808c2ecf20Sopenharmony_ci port = ntohs(((struct sockaddr_in6 *)sap)->sin6_port); 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci default: 2838c2ecf20Sopenharmony_ci return NULL; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (snprintf(portbuf, sizeof(portbuf), 2878c2ecf20Sopenharmony_ci ".%u.%u", port >> 8, port & 0xff) > (int)sizeof(portbuf)) 2888c2ecf20Sopenharmony_ci return NULL; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) > sizeof(addrbuf)) 2918c2ecf20Sopenharmony_ci return NULL; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci return kstrdup(addrbuf, gfp_flags); 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci/** 2978c2ecf20Sopenharmony_ci * rpc_uaddr2sockaddr - convert a universal address to a socket address. 2988c2ecf20Sopenharmony_ci * @net: applicable network namespace 2998c2ecf20Sopenharmony_ci * @uaddr: C string containing universal address to convert 3008c2ecf20Sopenharmony_ci * @uaddr_len: length of universal address string 3018c2ecf20Sopenharmony_ci * @sap: buffer into which to plant socket address 3028c2ecf20Sopenharmony_ci * @salen: size of buffer 3038c2ecf20Sopenharmony_ci * 3048c2ecf20Sopenharmony_ci * @uaddr does not have to be '\0'-terminated, but kstrtou8() and 3058c2ecf20Sopenharmony_ci * rpc_pton() require proper string termination to be successful. 3068c2ecf20Sopenharmony_ci * 3078c2ecf20Sopenharmony_ci * Returns the size of the socket address if successful; otherwise 3088c2ecf20Sopenharmony_ci * zero is returned. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_cisize_t rpc_uaddr2sockaddr(struct net *net, const char *uaddr, 3118c2ecf20Sopenharmony_ci const size_t uaddr_len, struct sockaddr *sap, 3128c2ecf20Sopenharmony_ci const size_t salen) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')]; 3158c2ecf20Sopenharmony_ci u8 portlo, porthi; 3168c2ecf20Sopenharmony_ci unsigned short port; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (uaddr_len > RPCBIND_MAXUADDRLEN) 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci memcpy(buf, uaddr, uaddr_len); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci buf[uaddr_len] = '\0'; 3248c2ecf20Sopenharmony_ci c = strrchr(buf, '.'); 3258c2ecf20Sopenharmony_ci if (unlikely(c == NULL)) 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci if (unlikely(kstrtou8(c + 1, 10, &portlo) != 0)) 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci *c = '\0'; 3318c2ecf20Sopenharmony_ci c = strrchr(buf, '.'); 3328c2ecf20Sopenharmony_ci if (unlikely(c == NULL)) 3338c2ecf20Sopenharmony_ci return 0; 3348c2ecf20Sopenharmony_ci if (unlikely(kstrtou8(c + 1, 10, &porthi) != 0)) 3358c2ecf20Sopenharmony_ci return 0; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci port = (unsigned short)((porthi << 8) | portlo); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci *c = '\0'; 3408c2ecf20Sopenharmony_ci if (rpc_pton(net, buf, strlen(buf), sap, salen) == 0) 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci switch (sap->sa_family) { 3448c2ecf20Sopenharmony_ci case AF_INET: 3458c2ecf20Sopenharmony_ci ((struct sockaddr_in *)sap)->sin_port = htons(port); 3468c2ecf20Sopenharmony_ci return sizeof(struct sockaddr_in); 3478c2ecf20Sopenharmony_ci case AF_INET6: 3488c2ecf20Sopenharmony_ci ((struct sockaddr_in6 *)sap)->sin6_port = htons(port); 3498c2ecf20Sopenharmony_ci return sizeof(struct sockaddr_in6); 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_uaddr2sockaddr); 355