]>
git.ipfire.org Git - people/ms/libloc.git/blob - src/libloc/address.h
bc1d7444c1db4baf9eab7a61e9a714cd50934c34
2 libloc - A library to determine the location of someone on the Internet
4 Copyright (C) 2022 IPFire Development Team <info@ipfire.org>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library 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 GNU
14 Lesser General Public License for more details.
17 #ifndef LIBLOC_ADDRESS_H
18 #define LIBLOC_ADDRESS_H
23 #include <netinet/in.h>
26 All of these functions are private and for internal use only
29 const char* loc_address_str(const struct in6_addr
* address
);
31 static inline int loc_address_family(const struct in6_addr
* address
) {
32 if (IN6_IS_ADDR_V4MAPPED(address
))
38 static inline unsigned int loc_address_family_bit_length(const int family
) {
52 Checks whether prefix is valid for the given address
54 static inline int loc_address_valid_prefix(const struct in6_addr
* address
, unsigned int prefix
) {
55 const int family
= loc_address_family(address
);
57 // What is the largest possible prefix?
58 const unsigned int bit_length
= loc_address_family_bit_length(family
);
60 if (prefix
<= bit_length
)
66 static inline int loc_address_cmp(const struct in6_addr
* a1
, const struct in6_addr
* a2
) {
67 for (unsigned int i
= 0; i
< 16; i
++) {
68 if (a1
->s6_addr
[i
] > a2
->s6_addr
[i
])
71 else if (a1
->s6_addr
[i
] < a2
->s6_addr
[i
])
78 #define foreach_octet_in_address(octet, address) \
79 for (octet = (IN6_IS_ADDR_V4MAPPED(address) ? 12 : 0); octet <= 15; octet++)
81 #define foreach_octet_in_address_reverse(octet, address) \
82 for (octet = 15; octet >= (IN6_IS_ADDR_V4MAPPED(address) ? 12 : 0); octet--)
84 static inline int loc_address_all_zeroes(const struct in6_addr
* address
) {
87 foreach_octet_in_address(octet
, address
) {
88 if (address
->s6_addr
[octet
])
95 static inline int loc_address_all_ones(const struct in6_addr
* address
) {
98 foreach_octet_in_address(octet
, address
) {
99 if (address
->s6_addr
[octet
] < 255)
106 static inline int loc_address_get_bit(const struct in6_addr
* address
, unsigned int i
) {
107 return ((address
->s6_addr
[i
/ 8] >> (7 - (i
% 8))) & 1);
110 static inline void loc_address_set_bit(struct in6_addr
* address
, unsigned int i
, unsigned int val
) {
111 address
->s6_addr
[i
/ 8] ^= (-val
^ address
->s6_addr
[i
/ 8]) & (1 << (7 - (i
% 8)));
114 static inline struct in6_addr
loc_prefix_to_bitmask(const unsigned int prefix
) {
115 struct in6_addr bitmask
;
117 for (unsigned int i
= 0; i
< 16; i
++)
118 bitmask
.s6_addr
[i
] = 0;
120 for (int i
= prefix
, j
= 0; i
> 0; i
-= 8, j
++) {
122 bitmask
.s6_addr
[j
] = 0xff;
124 bitmask
.s6_addr
[j
] = 0xff << (8 - i
);
130 static inline unsigned int loc_address_bit_length(const struct in6_addr
* address
) {
132 foreach_octet_in_address(octet
, address
) {
133 if (address
->s6_addr
[octet
])
134 return (15 - octet
) * 8 + 32 - __builtin_clz(address
->s6_addr
[octet
]);
140 static inline int loc_address_reset(struct in6_addr
* address
, int family
) {
143 address
->s6_addr32
[0] = 0x00000000;
144 address
->s6_addr32
[1] = 0x00000000;
145 address
->s6_addr32
[2] = 0x00000000;
146 address
->s6_addr32
[3] = 0x00000000;
150 address
->s6_addr32
[0] = 0x00000000;
151 address
->s6_addr32
[1] = 0x00000000;
152 address
->s6_addr32
[2] = htonl(0xffff);
153 address
->s6_addr32
[3] = 0x00000000;
160 static inline int loc_address_reset_last(struct in6_addr
* address
, int family
) {
163 address
->s6_addr32
[0] = 0xffffffff;
164 address
->s6_addr32
[1] = 0xffffffff;
165 address
->s6_addr32
[2] = 0xffffffff;
166 address
->s6_addr32
[3] = 0xffffffff;
170 address
->s6_addr32
[0] = 0x00000000;
171 address
->s6_addr32
[1] = 0x00000000;
172 address
->s6_addr32
[2] = htonl(0xffff);
173 address
->s6_addr32
[3] = 0xffffffff;
180 static inline struct in6_addr
loc_address_and(
181 const struct in6_addr
* address
, const struct in6_addr
* bitmask
) {
184 // Perform bitwise AND
185 for (unsigned int i
= 0; i
< 4; i
++)
186 a
.s6_addr32
[i
] = address
->s6_addr32
[i
] & bitmask
->s6_addr32
[i
];
191 static inline struct in6_addr
loc_address_or(
192 const struct in6_addr
* address
, const struct in6_addr
* bitmask
) {
195 // Perform bitwise OR
196 for (unsigned int i
= 0; i
< 4; i
++)
197 a
.s6_addr32
[i
] = address
->s6_addr32
[i
] | ~bitmask
->s6_addr32
[i
];
202 static inline int loc_address_sub(struct in6_addr
* result
,
203 const struct in6_addr
* address1
, const struct in6_addr
* address2
) {
204 int family1
= loc_address_family(address1
);
205 int family2
= loc_address_family(address2
);
207 // Address family must match
208 if (family1
!= family2
) {
214 int r
= loc_address_reset(result
, family1
);
221 foreach_octet_in_address_reverse(octet
, address1
) {
222 int x
= address1
->s6_addr
[octet
] - address2
->s6_addr
[octet
] + remainder
;
224 // Store remainder for the next iteration
225 remainder
= (x
>> 8);
227 result
->s6_addr
[octet
] = x
& 0xff;
233 static inline void loc_address_increment(struct in6_addr
* address
) {
234 // Prevent overflow when everything is ones
235 if (loc_address_all_ones(address
))
239 foreach_octet_in_address_reverse(octet
, address
) {
240 if (address
->s6_addr
[octet
] < 255) {
241 address
->s6_addr
[octet
]++;
244 address
->s6_addr
[octet
] = 0;
249 static inline void loc_address_decrement(struct in6_addr
* address
) {
250 // Prevent underflow when everything is ones
251 if (loc_address_all_zeroes(address
))
255 foreach_octet_in_address_reverse(octet
, address
) {
256 if (address
->s6_addr
[octet
] > 0) {
257 address
->s6_addr
[octet
]--;
263 static inline int loc_address_count_trailing_zero_bits(const struct in6_addr
* address
) {
267 foreach_octet_in_address_reverse(octet
, address
) {
268 if (address
->s6_addr
[octet
]) {
269 zeroes
+= __builtin_ctz(address
->s6_addr
[octet
]);
278 #endif /* LIBLOC_PRIVATE */
280 #endif /* LIBLOC_ADDRESS_H */