1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * linux/include/linux/sunrpc/addr.h 4 * 5 * Various routines for copying and comparing sockaddrs and for 6 * converting them to and from presentation format. 7 */ 8 #ifndef _LINUX_SUNRPC_ADDR_H 9 #define _LINUX_SUNRPC_ADDR_H 10 11 #include <linux/socket.h> 12 #include <linux/in.h> 13 #include <linux/in6.h> 14 #include <net/ipv6.h> 15 16 size_t rpc_ntop(const struct sockaddr *, char *, const size_t); 17 size_t rpc_pton(struct net *, const char *, const size_t, 18 struct sockaddr *, const size_t); 19 char * rpc_sockaddr2uaddr(const struct sockaddr *, gfp_t); 20 size_t rpc_uaddr2sockaddr(struct net *, const char *, const size_t, 21 struct sockaddr *, const size_t); 22 23 static inline unsigned short rpc_get_port(const struct sockaddr *sap) 24 { 25 switch (sap->sa_family) { 26 case AF_INET: 27 return ntohs(((struct sockaddr_in *)sap)->sin_port); 28 case AF_INET6: 29 return ntohs(((struct sockaddr_in6 *)sap)->sin6_port); 30 } 31 return 0; 32 } 33 34 static inline void rpc_set_port(struct sockaddr *sap, 35 const unsigned short port) 36 { 37 switch (sap->sa_family) { 38 case AF_INET: 39 ((struct sockaddr_in *)sap)->sin_port = htons(port); 40 break; 41 case AF_INET6: 42 ((struct sockaddr_in6 *)sap)->sin6_port = htons(port); 43 break; 44 } 45 } 46 47 #define IPV6_SCOPE_DELIMITER '%' 48 #define IPV6_SCOPE_ID_LEN sizeof("%nnnnnnnnnn") 49 50 static inline bool rpc_cmp_addr4(const struct sockaddr *sap1, 51 const struct sockaddr *sap2) 52 { 53 const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sap1; 54 const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sap2; 55 56 return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr; 57 } 58 59 static inline bool __rpc_copy_addr4(struct sockaddr *dst, 60 const struct sockaddr *src) 61 { 62 const struct sockaddr_in *ssin = (struct sockaddr_in *) src; 63 struct sockaddr_in *dsin = (struct sockaddr_in *) dst; 64 65 dsin->sin_family = ssin->sin_family; 66 dsin->sin_addr.s_addr = ssin->sin_addr.s_addr; 67 return true; 68 } 69 70 #if IS_ENABLED(CONFIG_IPV6) 71 static inline bool rpc_cmp_addr6(const struct sockaddr *sap1, 72 const struct sockaddr *sap2) 73 { 74 const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sap1; 75 const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2; 76 77 if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr)) 78 return false; 79 else if (ipv6_addr_type(&sin1->sin6_addr) & IPV6_ADDR_LINKLOCAL) 80 return sin1->sin6_scope_id == sin2->sin6_scope_id; 81 82 return true; 83 } 84 85 static inline bool __rpc_copy_addr6(struct sockaddr *dst, 86 const struct sockaddr *src) 87 { 88 const struct sockaddr_in6 *ssin6 = (const struct sockaddr_in6 *) src; 89 struct sockaddr_in6 *dsin6 = (struct sockaddr_in6 *) dst; 90 91 dsin6->sin6_family = ssin6->sin6_family; 92 dsin6->sin6_addr = ssin6->sin6_addr; 93 dsin6->sin6_scope_id = ssin6->sin6_scope_id; 94 return true; 95 } 96 #else /* !(IS_ENABLED(CONFIG_IPV6) */ 97 static inline bool rpc_cmp_addr6(const struct sockaddr *sap1, 98 const struct sockaddr *sap2) 99 { 100 return false; 101 } 102 103 static inline bool __rpc_copy_addr6(struct sockaddr *dst, 104 const struct sockaddr *src) 105 { 106 return false; 107 } 108 #endif /* !(IS_ENABLED(CONFIG_IPV6) */ 109 110 /** 111 * rpc_cmp_addr - compare the address portion of two sockaddrs. 112 * @sap1: first sockaddr 113 * @sap2: second sockaddr 114 * 115 * Just compares the family and address portion. Ignores port, but 116 * compares the scope if it's a link-local address. 117 * 118 * Returns true if the addrs are equal, false if they aren't. 119 */ 120 static inline bool rpc_cmp_addr(const struct sockaddr *sap1, 121 const struct sockaddr *sap2) 122 { 123 if (sap1->sa_family == sap2->sa_family) { 124 switch (sap1->sa_family) { 125 case AF_INET: 126 return rpc_cmp_addr4(sap1, sap2); 127 case AF_INET6: 128 return rpc_cmp_addr6(sap1, sap2); 129 } 130 } 131 return false; 132 } 133 134 /** 135 * rpc_cmp_addr_port - compare the address and port number of two sockaddrs. 136 * @sap1: first sockaddr 137 * @sap2: second sockaddr 138 */ 139 static inline bool rpc_cmp_addr_port(const struct sockaddr *sap1, 140 const struct sockaddr *sap2) 141 { 142 if (!rpc_cmp_addr(sap1, sap2)) 143 return false; 144 return rpc_get_port(sap1) == rpc_get_port(sap2); 145 } 146 147 /** 148 * rpc_copy_addr - copy the address portion of one sockaddr to another 149 * @dst: destination sockaddr 150 * @src: source sockaddr 151 * 152 * Just copies the address portion and family. Ignores port, scope, etc. 153 * Caller is responsible for making certain that dst is large enough to hold 154 * the address in src. Returns true if address family is supported. Returns 155 * false otherwise. 156 */ 157 static inline bool rpc_copy_addr(struct sockaddr *dst, 158 const struct sockaddr *src) 159 { 160 switch (src->sa_family) { 161 case AF_INET: 162 return __rpc_copy_addr4(dst, src); 163 case AF_INET6: 164 return __rpc_copy_addr6(dst, src); 165 } 166 return false; 167 } 168 169 /** 170 * rpc_get_scope_id - return scopeid for a given sockaddr 171 * @sa: sockaddr to get scopeid from 172 * 173 * Returns the value of the sin6_scope_id for AF_INET6 addrs, or 0 if 174 * not an AF_INET6 address. 175 */ 176 static inline u32 rpc_get_scope_id(const struct sockaddr *sa) 177 { 178 if (sa->sa_family != AF_INET6) 179 return 0; 180 181 return ((struct sockaddr_in6 *) sa)->sin6_scope_id; 182 } 183 184 #endif /* _LINUX_SUNRPC_ADDR_H */ 185