4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
27 #include <netinet/in.h>
28 #include <libinetutil.h>
33 #include <libsocket_priv.h>
36 * Internet utility functions.
40 * Given a host-order address, calculate client's default net mask.
41 * Consult netmasks database to see if net is further subnetted.
42 * We'll only snag the first netmask that matches our criteria.
43 * We return the resultant netmask in host order.
46 get_netmask4(const struct in_addr
*n_addrp
, struct in_addr
*s_addrp
)
48 struct in_addr hp
, tp
;
51 * First check if VLSM is in use.
53 hp
.s_addr
= htonl(n_addrp
->s_addr
);
54 if (getnetmaskbyaddr(hp
, &tp
) == 0) {
55 s_addrp
->s_addr
= ntohl(tp
.s_addr
);
60 * Fall back on standard classed networks.
62 if (IN_CLASSA(n_addrp
->s_addr
))
63 s_addrp
->s_addr
= IN_CLASSA_NET
;
64 else if (IN_CLASSB(n_addrp
->s_addr
))
65 s_addrp
->s_addr
= IN_CLASSB_NET
;
66 else if (IN_CLASSC(n_addrp
->s_addr
))
67 s_addrp
->s_addr
= IN_CLASSC_NET
;
69 s_addrp
->s_addr
= IN_CLASSE_NET
;
73 * Checks if the IP addresses `ssp1' and `ssp2' are equal.
76 sockaddrcmp(const struct sockaddr_storage
*ssp1
,
77 const struct sockaddr_storage
*ssp2
)
79 struct in_addr addr1
, addr2
;
80 const struct in6_addr
*addr6p1
, *addr6p2
;
82 if (ssp1
->ss_family
!= ssp2
->ss_family
)
88 switch (ssp1
->ss_family
) {
90 addr1
= ((const struct sockaddr_in
*)ssp1
)->sin_addr
;
91 addr2
= ((const struct sockaddr_in
*)ssp2
)->sin_addr
;
92 return (addr1
.s_addr
== addr2
.s_addr
);
94 addr6p1
= &((const struct sockaddr_in6
*)ssp1
)->sin6_addr
;
95 addr6p2
= &((const struct sockaddr_in6
*)ssp2
)->sin6_addr
;
96 return (IN6_ARE_ADDR_EQUAL(addr6p1
, addr6p2
));
102 * Stores the netmask in `mask' for the given prefixlen `plen' and also sets
103 * `sa_family' in `mask'. Because this function does not require aligned
104 * access to the data inside of the sockaddr_in/6 structures, the code can
105 * use offsetof() to find the right place in the incoming structure. Why is
106 * using that beneficial? Less issues with lint. When using a direct cast
107 * of the struct sockaddr_storage structure to sockaddr_in6, a lint warning
108 * is generated because the former is composed of 16bit & 8bit elements whilst
109 * sockaddr_in6 has a 32bit alignment requirement.
112 plen2mask(uint_t prefixlen
, sa_family_t af
, struct sockaddr
*mask
)
117 if (prefixlen
> IP_ABITS
)
119 bzero(mask
, sizeof (struct sockaddr_in
));
120 addr
= (uint8_t *)mask
;
121 addr
+= offsetof(struct sockaddr_in
, sin_addr
);
123 if (prefixlen
> IPV6_ABITS
)
125 bzero(mask
, sizeof (struct sockaddr_in6
));
126 addr
= (uint8_t *)mask
;
127 addr
+= offsetof(struct sockaddr_in6
, sin6_addr
);
129 mask
->sa_family
= af
;
131 while (prefixlen
> 0) {
132 if (prefixlen
>= 8) {
137 *addr
|= 1 << (8 - prefixlen
);
144 * Convert a mask to a prefix length.
145 * Returns prefix length on success, -1 otherwise.
146 * The comments (above) for plen2mask about the use of `mask' also apply
147 * to this function and the choice to use offsetof here too.
150 mask2plen(const struct sockaddr
*mask
)
157 if (mask
->sa_family
== AF_INET
) {
159 addr
= (uint8_t *)mask
;
160 addr
+= offsetof(struct sockaddr_in
, sin_addr
);
163 addr
= (uint8_t *)mask
;
164 addr
+= offsetof(struct sockaddr_in6
, sin6_addr
);
167 while (*addr
== 0xff) {
177 last
= (last
<< 1) & 0xff;
184 * Returns B_TRUE if the address in `ss' is INADDR_ANY for IPv4 or
185 * :: for IPv6. Otherwise, returns B_FALSE.
188 sockaddrunspec(const struct sockaddr
*ss
)
190 struct sockaddr_storage data
;
192 switch (ss
->sa_family
) {
194 (void) memcpy(&data
, ss
, sizeof (struct sockaddr_in
));
195 return (((struct sockaddr_in
*)&data
)->sin_addr
.s_addr
==
198 (void) memcpy(&data
, ss
, sizeof (struct sockaddr_in6
));
199 return (IN6_IS_ADDR_UNSPECIFIED(
200 &((struct sockaddr_in6
*)&data
)->sin6_addr
));