2 * Copyright 2009 Oracle. All rights reserved.
4 * This file is part of nfs-utils.
6 * nfs-utils is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * nfs-utils is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>.
20 #ifndef NFS_UTILS_SOCKADDR_H
21 #define NFS_UTILS_SOCKADDR_H
31 #include <sys/socket.h>
32 #include <netinet/in.h>
35 * This type is for defining buffers that contain network socket
38 * Casting a "struct sockaddr *" to the address of a "struct
39 * sockaddr_storage" breaks C aliasing rules. The "union
40 * nfs_sockaddr" type follows C aliasing rules yet specifically
41 * allows converting pointers to it between "struct sockaddr *"
42 * and a few other network sockaddr-related pointer types.
44 * Note that this union is much smaller than a sockaddr_storage.
45 * It should be used only for AF_INET or AF_INET6 socket addresses.
46 * An AF_LOCAL sockaddr_un, for example, will clearly not fit into
47 * a buffer of this type.
51 struct sockaddr_in s4;
52 struct sockaddr_in6 s6;
55 #if SIZEOF_SOCKLEN_T - 0 == 0
56 #define socklen_t unsigned int
59 #define SIZEOF_SOCKADDR_UNKNOWN (socklen_t)0
60 #define SIZEOF_SOCKADDR_IN (socklen_t)sizeof(struct sockaddr_in)
63 #define SIZEOF_SOCKADDR_IN6 (socklen_t)sizeof(struct sockaddr_in6)
64 #else /* !IPV6_SUPPORTED */
65 #define SIZEOF_SOCKADDR_IN6 SIZEOF_SOCKADDR_UNKNOWN
66 #endif /* !IPV6_SUPPORTED */
69 * nfs_sockaddr_length - return the size in bytes of a socket address
70 * @sap: pointer to socket address
72 * Returns the size in bytes of @sap, or zero if the family is
75 static inline socklen_t
76 nfs_sockaddr_length(const struct sockaddr *sap)
78 switch (sap->sa_family) {
80 return SIZEOF_SOCKADDR_IN;
82 return SIZEOF_SOCKADDR_IN6;
84 return SIZEOF_SOCKADDR_UNKNOWN;
87 static inline uint16_t
88 get_port4(const struct sockaddr *sap)
90 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
91 return ntohs(sin->sin_port);
95 static inline uint16_t
96 get_port6(const struct sockaddr *sap)
98 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
99 return ntohs(sin6->sin6_port);
101 #else /* !IPV6_SUPPORTED */
102 static inline uint16_t
103 get_port6(__attribute__ ((unused)) const struct sockaddr *sap)
107 #endif /* !IPV6_SUPPORTED */
110 * nfs_get_port - extract port value from a socket address
111 * @sap: pointer to socket address
113 * Returns port value in host byte order, or zero if the
114 * socket address contains an unrecognized family.
116 static inline uint16_t
117 nfs_get_port(const struct sockaddr *sap)
119 switch (sap->sa_family) {
121 return get_port4(sap);
123 return get_port6(sap);
129 set_port4(struct sockaddr *sap, const uint16_t port)
131 struct sockaddr_in *sin = (struct sockaddr_in *)sap;
132 sin->sin_port = htons(port);
135 #ifdef IPV6_SUPPORTED
137 set_port6(struct sockaddr *sap, const uint16_t port)
139 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
140 sin6->sin6_port = htons(port);
142 #else /* !IPV6_SUPPORTED */
144 set_port6(__attribute__ ((unused)) struct sockaddr *sap,
145 __attribute__ ((unused)) const uint16_t port)
148 #endif /* !IPV6_SUPPORTED */
151 * nfs_set_port - set port value in a socket address
152 * @sap: pointer to socket address
153 * @port: port value to set
157 nfs_set_port(struct sockaddr *sap, const uint16_t port)
159 switch (sap->sa_family) {
161 set_port4(sap, port);
164 set_port6(sap, port);
170 * nfs_is_v4_loopback - test to see if socket address is AF_INET loopback
171 * @sap: pointer to socket address
173 * Returns true if the socket address is the standard IPv4 loopback
174 * address; otherwise false is returned.
177 nfs_is_v4_loopback(const struct sockaddr *sap)
179 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
181 if (sin->sin_family != AF_INET)
183 if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
189 compare_sockaddr4(const struct sockaddr *sa1, const struct sockaddr *sa2)
191 const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
192 const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
193 return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
196 #ifdef IPV6_SUPPORTED
198 compare_sockaddr6(const struct sockaddr *sa1, const struct sockaddr *sa2)
200 const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
201 const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
202 const struct in6_addr *saddr1 = &sin1->sin6_addr;
203 const struct in6_addr *saddr2 = &sin2->sin6_addr;
205 if (IN6_IS_ADDR_LINKLOCAL(saddr1) && IN6_IS_ADDR_LINKLOCAL(saddr2))
206 if (sin1->sin6_scope_id != sin2->sin6_scope_id)
209 return IN6_ARE_ADDR_EQUAL(saddr1, saddr2);
211 #else /* !IPV6_SUPPORTED */
213 compare_sockaddr6(__attribute__ ((unused)) const struct sockaddr *sa1,
214 __attribute__ ((unused)) const struct sockaddr *sa2)
218 #endif /* !IPV6_SUPPORTED */
221 * nfs_compare_sockaddr - compare two socket addresses for equality
222 * @sa1: pointer to a socket address
223 * @sa2: pointer to a socket address
225 * Returns true if the two socket addresses contain equivalent
226 * network addresses; otherwise false is returned.
229 nfs_compare_sockaddr(const struct sockaddr *sa1, const struct sockaddr *sa2)
231 if (sa1 == NULL || sa2 == NULL)
234 if (sa1->sa_family == sa2->sa_family)
235 switch (sa1->sa_family) {
237 return compare_sockaddr4(sa1, sa2);
239 return compare_sockaddr6(sa1, sa2);
245 #endif /* !NFS_UTILS_SOCKADDR_H */