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(a1: &sin1->sin6_addr, a2: &sin2->sin6_addr)) |
78 | return false; |
79 | else if (ipv6_addr_type(addr: &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(sap: sap1) == rpc_get_port(sap: 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 | |