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
25 #include <sys/socket.h>
26 #include <netinet/in.h>
29 * This type is for defining buffers that contain network socket
32 * Casting a "struct sockaddr *" to the address of a "struct
33 * sockaddr_storage" breaks C aliasing rules. The "union
34 * nfs_sockaddr" type follows C aliasing rules yet specifically
35 * allows converting pointers to it between "struct sockaddr *"
36 * and a few other network sockaddr-related pointer types.
38 * Note that this union is much smaller than a sockaddr_storage.
39 * It should be used only for AF_INET or AF_INET6 socket addresses.
40 * An AF_LOCAL sockaddr_un, for example, will clearly not fit into
41 * a buffer of this type.
45 struct sockaddr_in s4;
46 struct sockaddr_in6 s6;
49 #if SIZEOF_SOCKLEN_T - 0 == 0
50 #define socklen_t unsigned int
53 #define SIZEOF_SOCKADDR_UNKNOWN (socklen_t)0
54 #define SIZEOF_SOCKADDR_IN (socklen_t)sizeof(struct sockaddr_in)
57 #define SIZEOF_SOCKADDR_IN6 (socklen_t)sizeof(struct sockaddr_in6)
58 #else /* !IPV6_SUPPORTED */
59 #define SIZEOF_SOCKADDR_IN6 SIZEOF_SOCKADDR_UNKNOWN
60 #endif /* !IPV6_SUPPORTED */
63 * nfs_sockaddr_length - return the size in bytes of a socket address
64 * @sap: pointer to socket address
66 * Returns the size in bytes of @sap, or zero if the family is
69 static inline socklen_t
70 nfs_sockaddr_length(const struct sockaddr *sap)
72 switch (sap->sa_family) {
74 return SIZEOF_SOCKADDR_IN;
76 return SIZEOF_SOCKADDR_IN6;
78 return SIZEOF_SOCKADDR_UNKNOWN;
81 static inline uint16_t
82 get_port4(const struct sockaddr *sap)
84 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
85 return ntohs(sin->sin_port);
89 static inline uint16_t
90 get_port6(const struct sockaddr *sap)
92 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
93 return ntohs(sin6->sin6_port);
95 #else /* !IPV6_SUPPORTED */
96 static inline uint16_t
97 get_port6(__attribute__ ((unused)) const struct sockaddr *sap)
101 #endif /* !IPV6_SUPPORTED */
104 * nfs_get_port - extract port value from a socket address
105 * @sap: pointer to socket address
107 * Returns port value in host byte order, or zero if the
108 * socket address contains an unrecognized family.
110 static inline uint16_t
111 nfs_get_port(const struct sockaddr *sap)
113 switch (sap->sa_family) {
115 return get_port4(sap);
117 return get_port6(sap);
123 set_port4(struct sockaddr *sap, const uint16_t port)
125 struct sockaddr_in *sin = (struct sockaddr_in *)sap;
126 sin->sin_port = htons(port);
129 #ifdef IPV6_SUPPORTED
131 set_port6(struct sockaddr *sap, const uint16_t port)
133 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
134 sin6->sin6_port = htons(port);
136 #else /* !IPV6_SUPPORTED */
138 set_port6(__attribute__ ((unused)) struct sockaddr *sap,
139 __attribute__ ((unused)) const uint16_t port)
142 #endif /* !IPV6_SUPPORTED */
145 * nfs_set_port - set port value in a socket address
146 * @sap: pointer to socket address
147 * @port: port value to set
151 nfs_set_port(struct sockaddr *sap, const uint16_t port)
153 switch (sap->sa_family) {
155 set_port4(sap, port);
158 set_port6(sap, port);
164 * nfs_is_v4_loopback - test to see if socket address is AF_INET loopback
165 * @sap: pointer to socket address
167 * Returns true if the socket address is the standard IPv4 loopback
168 * address; otherwise false is returned.
171 nfs_is_v4_loopback(const struct sockaddr *sap)
173 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
175 if (sin->sin_family != AF_INET)
177 if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
183 compare_sockaddr4(const struct sockaddr *sa1, const struct sockaddr *sa2)
185 const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
186 const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
187 return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
190 #ifdef IPV6_SUPPORTED
192 compare_sockaddr6(const struct sockaddr *sa1, const struct sockaddr *sa2)
194 const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
195 const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
197 if ((IN6_IS_ADDR_LINKLOCAL((char *)&sin1->sin6_addr) &&
198 IN6_IS_ADDR_LINKLOCAL((char *)&sin2->sin6_addr)) ||
199 (IN6_IS_ADDR_SITELOCAL((char *)&sin1->sin6_addr) &&
200 IN6_IS_ADDR_SITELOCAL((char *)&sin2->sin6_addr)))
201 if (sin1->sin6_scope_id != sin2->sin6_scope_id)
204 return IN6_ARE_ADDR_EQUAL((char *)&sin1->sin6_addr,
205 (char *)&sin2->sin6_addr);
207 #else /* !IPV6_SUPPORTED */
209 compare_sockaddr6(__attribute__ ((unused)) const struct sockaddr *sa1,
210 __attribute__ ((unused)) const struct sockaddr *sa2)
214 #endif /* !IPV6_SUPPORTED */
217 * nfs_compare_sockaddr - compare two socket addresses for equality
218 * @sa1: pointer to a socket address
219 * @sa2: pointer to a socket address
221 * Returns true if the two socket addresses contain equivalent
222 * network addresses; otherwise false is returned.
225 nfs_compare_sockaddr(const struct sockaddr *sa1, const struct sockaddr *sa2)
227 if (sa1 == NULL || sa2 == NULL)
230 if (sa1->sa_family == sa2->sa_family)
231 switch (sa1->sa_family) {
233 return compare_sockaddr4(sa1, sa2);
235 return compare_sockaddr6(sa1, sa2);
241 #endif /* !NFS_UTILS_SOCKADDR_H */