]> git.ipfire.org Git - people/ms/libloc.git/blame - src/libloc/address.h
address: Rename in6_addr_get_bit/in6_addr_set_bit to loc_address_*
[people/ms/libloc.git] / src / libloc / address.h
CommitLineData
0b1fef38
MT
1/*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2022 IPFire Development Team <info@ipfire.org>
5
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.
10
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.
15*/
16
17#ifndef LIBLOC_ADDRESS_H
18#define LIBLOC_ADDRESS_H
19
20#ifdef LIBLOC_PRIVATE
21
22#include <errno.h>
23#include <netinet/in.h>
24
25/*
26 All of these functions are private and for internal use only
27*/
28
29static inline int loc_address_family(const struct in6_addr* address) {
30 if (IN6_IS_ADDR_V4MAPPED(address))
31 return AF_INET;
32 else
33 return AF_INET6;
34}
35
9c1e2943 36static inline int loc_address_cmp(const struct in6_addr* a1, const struct in6_addr* a2) {
0b1fef38
MT
37 for (unsigned int i = 0; i < 16; i++) {
38 if (a1->s6_addr[i] > a2->s6_addr[i])
39 return 1;
40
41 else if (a1->s6_addr[i] < a2->s6_addr[i])
42 return -1;
43 }
44
45 return 0;
46}
47
d698ca09 48static inline int loc_address_get_bit(const struct in6_addr* address, unsigned int i) {
0b1fef38
MT
49 return ((address->s6_addr[i / 8] >> (7 - (i % 8))) & 1);
50}
51
d698ca09 52static inline void loc_address_set_bit(struct in6_addr* address, unsigned int i, unsigned int val) {
0b1fef38
MT
53 address->s6_addr[i / 8] ^= (-val ^ address->s6_addr[i / 8]) & (1 << (7 - (i % 8)));
54}
55
56static inline struct in6_addr loc_prefix_to_bitmask(const unsigned int prefix) {
57 struct in6_addr bitmask;
58
59 for (unsigned int i = 0; i < 16; i++)
60 bitmask.s6_addr[i] = 0;
61
62 for (int i = prefix, j = 0; i > 0; i -= 8, j++) {
63 if (i >= 8)
64 bitmask.s6_addr[j] = 0xff;
65 else
66 bitmask.s6_addr[j] = 0xff << (8 - i);
67 }
68
69 return bitmask;
70}
71
72static inline unsigned int __loc_address6_bit_length(const struct in6_addr* address) {
73 unsigned int length = 128;
74
75 for (int octet = 0; octet <= 15; octet++) {
76 if (address->s6_addr[octet]) {
77 length -= __builtin_clz(address->s6_addr[octet]) - 24;
78 break;
79 } else
80 length -= 8;
81 }
82
83 return length;
84}
85
86static inline unsigned int __loc_address4_bit_length(const struct in6_addr* address) {
87 unsigned int length = 32;
88
89 for (int octet = 12; octet <= 15; octet++) {
90 if (address->s6_addr[octet]) {
91 length -= __builtin_clz(address->s6_addr[octet]) - 24;
92 break;
93 } else
94 length -= 8;
95 }
96
97 return length;
98}
99
100static inline unsigned int loc_address_bit_length(const struct in6_addr* address) {
101 if (IN6_IS_ADDR_V4MAPPED(address))
102 return __loc_address4_bit_length(address);
103 else
104 return __loc_address6_bit_length(address);
105}
106
107static inline int loc_address_reset(struct in6_addr* address, int family) {
108 switch (family) {
109 case AF_INET6:
110 address->s6_addr32[0] = 0x0000;
111 address->s6_addr32[1] = 0x0000;
112 address->s6_addr32[2] = 0x0000;
113 address->s6_addr32[3] = 0x0000;
114 return 0;
115
116 case AF_INET:
117 address->s6_addr32[0] = 0x0000;
118 address->s6_addr32[1] = 0x0000;
119 address->s6_addr32[2] = htonl(0xffff);
120 address->s6_addr32[3] = 0x0000;
121 return 0;
122 }
123
124 return -1;
125}
126
127static inline int loc_address_reset_last(struct in6_addr* address, int family) {
128 switch (family) {
129 case AF_INET6:
130 address->s6_addr32[0] = 0xffff;
131 address->s6_addr32[1] = 0xffff;
132 address->s6_addr32[2] = 0xffff;
133 address->s6_addr32[3] = 0xffff;
134 return 0;
135
136 case AF_INET:
137 address->s6_addr32[0] = 0x0000;
138 address->s6_addr32[1] = 0x0000;
139 address->s6_addr32[2] = htonl(0xffff);
140 address->s6_addr32[3] = 0xffff;
141 return 0;
142 }
143
144 return -1;
145}
146
147static inline struct in6_addr loc_address_and(
148 const struct in6_addr* address, const struct in6_addr* bitmask) {
149 struct in6_addr a;
150
151 // Perform bitwise AND
152 for (unsigned int i = 0; i < 4; i++)
153 a.s6_addr32[i] = address->s6_addr32[i] & bitmask->s6_addr32[i];
154
155 return a;
156}
157
158static inline struct in6_addr loc_address_or(
159 const struct in6_addr* address, const struct in6_addr* bitmask) {
160 struct in6_addr a;
161
162 // Perform bitwise OR
163 for (unsigned int i = 0; i < 4; i++)
164 a.s6_addr32[i] = address->s6_addr32[i] | ~bitmask->s6_addr32[i];
165
166 return a;
167}
168
169static inline int __loc_address6_sub(struct in6_addr* result,
170 const struct in6_addr* address1, const struct in6_addr* address2) {
171 int remainder = 0;
172
173 for (int octet = 15; octet >= 0; octet--) {
174 int x = address1->s6_addr[octet] - address2->s6_addr[octet] + remainder;
175
176 // Store remainder for the next iteration
177 remainder = (x >> 8);
178
179 result->s6_addr[octet] = x & 0xff;
180 }
181
182 return 0;
183}
184
185static inline int __loc_address4_sub(struct in6_addr* result,
186 const struct in6_addr* address1, const struct in6_addr* address2) {
187 int remainder = 0;
188
189 for (int octet = 15; octet >= 12; octet--) {
190 int x = address1->s6_addr[octet] - address2->s6_addr[octet] + remainder;
191
192 // Store remainder for the next iteration
193 remainder = (x >> 8);
194
195 result->s6_addr[octet] = x & 0xff;
196 }
197
198 return 0;
199}
200
201static inline int loc_address_sub(struct in6_addr* result,
202 const struct in6_addr* address1, const struct in6_addr* address2) {
203 // XXX should be using loc_address_family
204 int family1 = IN6_IS_ADDR_V4MAPPED(address1) ? AF_INET : AF_INET6;
205 int family2 = IN6_IS_ADDR_V4MAPPED(address2) ? AF_INET : AF_INET6;
206
207 // Address family must match
208 if (family1 != family2) {
209 errno = EINVAL;
210 return 1;
211 }
212
213 // Clear result
214 int r = loc_address_reset(result, family1);
215 if (r)
216 return r;
217
218 switch (family1) {
219 case AF_INET6:
220 return __loc_address6_sub(result, address1, address2);
221
222 case AF_INET:
223 return __loc_address4_sub(result, address1, address2);
224
225 default:
226 errno = ENOTSUP;
227 return 1;
228 }
229}
230
231static inline struct in6_addr address_increment(const struct in6_addr* address) {
232 struct in6_addr a = *address;
233
234 for (int octet = 15; octet >= 0; octet--) {
235 if (a.s6_addr[octet] < 255) {
236 a.s6_addr[octet]++;
237 break;
238 } else {
239 a.s6_addr[octet] = 0;
240 }
241 }
242
243 return a;
244}
245
246static inline struct in6_addr address_decrement(const struct in6_addr* address) {
247 struct in6_addr a = *address;
248
249 for (int octet = 15; octet >= 0; octet--) {
250 if (a.s6_addr[octet] > 0) {
251 a.s6_addr[octet]--;
252 break;
253 }
254 }
255
256 return a;
257}
258
259static inline int loc_address_family_bit_length(const int family) {
260 switch (family) {
261 case AF_INET6:
262 return 128;
263
264 case AF_INET:
265 return 32;
266
267 default:
268 return -1;
269 }
270}
271
272static inline int loc_address_all_zeroes(const struct in6_addr* address) {
273 struct in6_addr all_zeroes = IN6ADDR_ANY_INIT;
274
275 const int family = loc_address_family(address);
276
277 int r = loc_address_reset(&all_zeroes, family);
278 if (r)
279 return r;
280
9c1e2943 281 if (loc_address_cmp(address, &all_zeroes) == 0)
0b1fef38
MT
282 return 1;
283
284 return 0;
285}
286
287static inline int loc_address_count_trailing_zero_bits(const struct in6_addr* address) {
288 int zeroes = 0;
289
290 for (int octet = 15; octet >= 0; octet--) {
291 if (address->s6_addr[octet]) {
292 zeroes += __builtin_ctz(address->s6_addr[octet]);
293 break;
294 } else
295 zeroes += 8;
296 }
297
298 return zeroes;
299}
300
301#endif /* LIBLOC_PRIVATE */
302
303#endif /* LIBLOC_ADDRESS_H */