162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/include/linux/sunrpc/addr.h 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Various routines for copying and comparing sockaddrs and for 662306a36Sopenharmony_ci * converting them to and from presentation format. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#ifndef _LINUX_SUNRPC_ADDR_H 962306a36Sopenharmony_ci#define _LINUX_SUNRPC_ADDR_H 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/socket.h> 1262306a36Sopenharmony_ci#include <linux/in.h> 1362306a36Sopenharmony_ci#include <linux/in6.h> 1462306a36Sopenharmony_ci#include <net/ipv6.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cisize_t rpc_ntop(const struct sockaddr *, char *, const size_t); 1762306a36Sopenharmony_cisize_t rpc_pton(struct net *, const char *, const size_t, 1862306a36Sopenharmony_ci struct sockaddr *, const size_t); 1962306a36Sopenharmony_cichar * rpc_sockaddr2uaddr(const struct sockaddr *, gfp_t); 2062306a36Sopenharmony_cisize_t rpc_uaddr2sockaddr(struct net *, const char *, const size_t, 2162306a36Sopenharmony_ci struct sockaddr *, const size_t); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic inline unsigned short rpc_get_port(const struct sockaddr *sap) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci switch (sap->sa_family) { 2662306a36Sopenharmony_ci case AF_INET: 2762306a36Sopenharmony_ci return ntohs(((struct sockaddr_in *)sap)->sin_port); 2862306a36Sopenharmony_ci case AF_INET6: 2962306a36Sopenharmony_ci return ntohs(((struct sockaddr_in6 *)sap)->sin6_port); 3062306a36Sopenharmony_ci } 3162306a36Sopenharmony_ci return 0; 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic inline void rpc_set_port(struct sockaddr *sap, 3562306a36Sopenharmony_ci const unsigned short port) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci switch (sap->sa_family) { 3862306a36Sopenharmony_ci case AF_INET: 3962306a36Sopenharmony_ci ((struct sockaddr_in *)sap)->sin_port = htons(port); 4062306a36Sopenharmony_ci break; 4162306a36Sopenharmony_ci case AF_INET6: 4262306a36Sopenharmony_ci ((struct sockaddr_in6 *)sap)->sin6_port = htons(port); 4362306a36Sopenharmony_ci break; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define IPV6_SCOPE_DELIMITER '%' 4862306a36Sopenharmony_ci#define IPV6_SCOPE_ID_LEN sizeof("%nnnnnnnnnn") 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic inline bool rpc_cmp_addr4(const struct sockaddr *sap1, 5162306a36Sopenharmony_ci const struct sockaddr *sap2) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sap1; 5462306a36Sopenharmony_ci const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sap2; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic inline bool __rpc_copy_addr4(struct sockaddr *dst, 6062306a36Sopenharmony_ci const struct sockaddr *src) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci const struct sockaddr_in *ssin = (struct sockaddr_in *) src; 6362306a36Sopenharmony_ci struct sockaddr_in *dsin = (struct sockaddr_in *) dst; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci dsin->sin_family = ssin->sin_family; 6662306a36Sopenharmony_ci dsin->sin_addr.s_addr = ssin->sin_addr.s_addr; 6762306a36Sopenharmony_ci return true; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 7162306a36Sopenharmony_cistatic inline bool rpc_cmp_addr6(const struct sockaddr *sap1, 7262306a36Sopenharmony_ci const struct sockaddr *sap2) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sap1; 7562306a36Sopenharmony_ci const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr)) 7862306a36Sopenharmony_ci return false; 7962306a36Sopenharmony_ci else if (ipv6_addr_type(&sin1->sin6_addr) & IPV6_ADDR_LINKLOCAL) 8062306a36Sopenharmony_ci return sin1->sin6_scope_id == sin2->sin6_scope_id; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return true; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic inline bool __rpc_copy_addr6(struct sockaddr *dst, 8662306a36Sopenharmony_ci const struct sockaddr *src) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci const struct sockaddr_in6 *ssin6 = (const struct sockaddr_in6 *) src; 8962306a36Sopenharmony_ci struct sockaddr_in6 *dsin6 = (struct sockaddr_in6 *) dst; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci dsin6->sin6_family = ssin6->sin6_family; 9262306a36Sopenharmony_ci dsin6->sin6_addr = ssin6->sin6_addr; 9362306a36Sopenharmony_ci dsin6->sin6_scope_id = ssin6->sin6_scope_id; 9462306a36Sopenharmony_ci return true; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci#else /* !(IS_ENABLED(CONFIG_IPV6) */ 9762306a36Sopenharmony_cistatic inline bool rpc_cmp_addr6(const struct sockaddr *sap1, 9862306a36Sopenharmony_ci const struct sockaddr *sap2) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci return false; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic inline bool __rpc_copy_addr6(struct sockaddr *dst, 10462306a36Sopenharmony_ci const struct sockaddr *src) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci return false; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci#endif /* !(IS_ENABLED(CONFIG_IPV6) */ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/** 11162306a36Sopenharmony_ci * rpc_cmp_addr - compare the address portion of two sockaddrs. 11262306a36Sopenharmony_ci * @sap1: first sockaddr 11362306a36Sopenharmony_ci * @sap2: second sockaddr 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * Just compares the family and address portion. Ignores port, but 11662306a36Sopenharmony_ci * compares the scope if it's a link-local address. 11762306a36Sopenharmony_ci * 11862306a36Sopenharmony_ci * Returns true if the addrs are equal, false if they aren't. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_cistatic inline bool rpc_cmp_addr(const struct sockaddr *sap1, 12162306a36Sopenharmony_ci const struct sockaddr *sap2) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci if (sap1->sa_family == sap2->sa_family) { 12462306a36Sopenharmony_ci switch (sap1->sa_family) { 12562306a36Sopenharmony_ci case AF_INET: 12662306a36Sopenharmony_ci return rpc_cmp_addr4(sap1, sap2); 12762306a36Sopenharmony_ci case AF_INET6: 12862306a36Sopenharmony_ci return rpc_cmp_addr6(sap1, sap2); 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci return false; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/** 13562306a36Sopenharmony_ci * rpc_cmp_addr_port - compare the address and port number of two sockaddrs. 13662306a36Sopenharmony_ci * @sap1: first sockaddr 13762306a36Sopenharmony_ci * @sap2: second sockaddr 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_cistatic inline bool rpc_cmp_addr_port(const struct sockaddr *sap1, 14062306a36Sopenharmony_ci const struct sockaddr *sap2) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci if (!rpc_cmp_addr(sap1, sap2)) 14362306a36Sopenharmony_ci return false; 14462306a36Sopenharmony_ci return rpc_get_port(sap1) == rpc_get_port(sap2); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/** 14862306a36Sopenharmony_ci * rpc_copy_addr - copy the address portion of one sockaddr to another 14962306a36Sopenharmony_ci * @dst: destination sockaddr 15062306a36Sopenharmony_ci * @src: source sockaddr 15162306a36Sopenharmony_ci * 15262306a36Sopenharmony_ci * Just copies the address portion and family. Ignores port, scope, etc. 15362306a36Sopenharmony_ci * Caller is responsible for making certain that dst is large enough to hold 15462306a36Sopenharmony_ci * the address in src. Returns true if address family is supported. Returns 15562306a36Sopenharmony_ci * false otherwise. 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cistatic inline bool rpc_copy_addr(struct sockaddr *dst, 15862306a36Sopenharmony_ci const struct sockaddr *src) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci switch (src->sa_family) { 16162306a36Sopenharmony_ci case AF_INET: 16262306a36Sopenharmony_ci return __rpc_copy_addr4(dst, src); 16362306a36Sopenharmony_ci case AF_INET6: 16462306a36Sopenharmony_ci return __rpc_copy_addr6(dst, src); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci return false; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/** 17062306a36Sopenharmony_ci * rpc_get_scope_id - return scopeid for a given sockaddr 17162306a36Sopenharmony_ci * @sa: sockaddr to get scopeid from 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * Returns the value of the sin6_scope_id for AF_INET6 addrs, or 0 if 17462306a36Sopenharmony_ci * not an AF_INET6 address. 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_cistatic inline u32 rpc_get_scope_id(const struct sockaddr *sa) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci if (sa->sa_family != AF_INET6) 17962306a36Sopenharmony_ci return 0; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return ((struct sockaddr_in6 *) sa)->sin6_scope_id; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci#endif /* _LINUX_SUNRPC_ADDR_H */ 185