]>
git.ipfire.org Git - people/ms/libloc.git/blob - src/libloc/address.h
f4c0ee330bc0df62b1dfcc4a2476800d081d2bc2
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>
25 #include <libloc/compat.h>
28 All of these functions are private and for internal use only
31 const char* loc_address_str(const struct in6_addr
* address
);
32 int loc_address_parse(struct in6_addr
* address
, unsigned int* prefix
, const char* string
);
34 static inline int loc_address_family(const struct in6_addr
* address
) {
35 if (IN6_IS_ADDR_V4MAPPED(address
))
41 static inline unsigned int loc_address_family_bit_length(const int family
) {
55 Checks whether prefix is valid for the given address
57 static inline int loc_address_valid_prefix(const struct in6_addr
* address
, unsigned int prefix
) {
58 const int family
= loc_address_family(address
);
60 // What is the largest possible prefix?
61 const unsigned int bit_length
= loc_address_family_bit_length(family
);
63 if (prefix
<= bit_length
)
69 static inline int loc_address_cmp(const struct in6_addr
* a1
, const struct in6_addr
* a2
) {
70 for (unsigned int i
= 0; i
< 16; i
++) {
71 if (a1
->s6_addr
[i
] > a2
->s6_addr
[i
])
74 else if (a1
->s6_addr
[i
] < a2
->s6_addr
[i
])
81 #define foreach_octet_in_address(octet, address) \
82 for (octet = (IN6_IS_ADDR_V4MAPPED(address) ? 12 : 0); octet <= 15; octet++)
84 #define foreach_octet_in_address_reverse(octet, address) \
85 for (octet = 15; octet >= (IN6_IS_ADDR_V4MAPPED(address) ? 12 : 0); octet--)
87 static inline int loc_address_all_zeroes(const struct in6_addr
* address
) {
90 foreach_octet_in_address(octet
, address
) {
91 if (address
->s6_addr
[octet
])
98 static inline int loc_address_all_ones(const struct in6_addr
* address
) {
101 foreach_octet_in_address(octet
, address
) {
102 if (address
->s6_addr
[octet
] < 255)
109 static inline int loc_address_get_bit(const struct in6_addr
* address
, unsigned int i
) {
110 return ((address
->s6_addr
[i
/ 8] >> (7 - (i
% 8))) & 1);
113 static inline void loc_address_set_bit(struct in6_addr
* address
, unsigned int i
, unsigned int val
) {
114 address
->s6_addr
[i
/ 8] ^= (-val
^ address
->s6_addr
[i
/ 8]) & (1 << (7 - (i
% 8)));
117 static inline struct in6_addr
loc_prefix_to_bitmask(const unsigned int prefix
) {
118 struct in6_addr bitmask
;
120 for (unsigned int i
= 0; i
< 16; i
++)
121 bitmask
.s6_addr
[i
] = 0;
123 for (int i
= prefix
, j
= 0; i
> 0; i
-= 8, j
++) {
125 bitmask
.s6_addr
[j
] = 0xff;
127 bitmask
.s6_addr
[j
] = 0xff << (8 - i
);
133 static inline unsigned int loc_address_bit_length(const struct in6_addr
* address
) {
135 foreach_octet_in_address(octet
, address
) {
136 if (address
->s6_addr
[octet
])
137 return (15 - octet
) * 8 + 32 - __builtin_clz(address
->s6_addr
[octet
]);
143 static inline int loc_address_reset(struct in6_addr
* address
, int family
) {
146 address
->s6_addr32
[0] = 0x00000000;
147 address
->s6_addr32
[1] = 0x00000000;
148 address
->s6_addr32
[2] = 0x00000000;
149 address
->s6_addr32
[3] = 0x00000000;
153 address
->s6_addr32
[0] = 0x00000000;
154 address
->s6_addr32
[1] = 0x00000000;
155 address
->s6_addr32
[2] = htonl(0xffff);
156 address
->s6_addr32
[3] = 0x00000000;
163 static inline int loc_address_reset_last(struct in6_addr
* address
, int family
) {
166 address
->s6_addr32
[0] = 0xffffffff;
167 address
->s6_addr32
[1] = 0xffffffff;
168 address
->s6_addr32
[2] = 0xffffffff;
169 address
->s6_addr32
[3] = 0xffffffff;
173 address
->s6_addr32
[0] = 0x00000000;
174 address
->s6_addr32
[1] = 0x00000000;
175 address
->s6_addr32
[2] = htonl(0xffff);
176 address
->s6_addr32
[3] = 0xffffffff;
183 static inline struct in6_addr
loc_address_and(
184 const struct in6_addr
* address
, const struct in6_addr
* bitmask
) {
187 // Perform bitwise AND
188 for (unsigned int i
= 0; i
< 4; i
++)
189 a
.s6_addr32
[i
] = address
->s6_addr32
[i
] & bitmask
->s6_addr32
[i
];
194 static inline struct in6_addr
loc_address_or(
195 const struct in6_addr
* address
, const struct in6_addr
* bitmask
) {
198 // Perform bitwise OR
199 for (unsigned int i
= 0; i
< 4; i
++)
200 a
.s6_addr32
[i
] = address
->s6_addr32
[i
] | ~bitmask
->s6_addr32
[i
];
205 static inline int loc_address_sub(struct in6_addr
* result
,
206 const struct in6_addr
* address1
, const struct in6_addr
* address2
) {
207 int family1
= loc_address_family(address1
);
208 int family2
= loc_address_family(address2
);
210 // Address family must match
211 if (family1
!= family2
) {
217 int r
= loc_address_reset(result
, family1
);
224 foreach_octet_in_address_reverse(octet
, address1
) {
225 int x
= address1
->s6_addr
[octet
] - address2
->s6_addr
[octet
] + remainder
;
227 // Store remainder for the next iteration
228 remainder
= (x
>> 8);
230 result
->s6_addr
[octet
] = x
& 0xff;
236 static inline void loc_address_increment(struct in6_addr
* address
) {
237 // Prevent overflow when everything is ones
238 if (loc_address_all_ones(address
))
242 foreach_octet_in_address_reverse(octet
, address
) {
243 if (address
->s6_addr
[octet
] < 255) {
244 address
->s6_addr
[octet
]++;
247 address
->s6_addr
[octet
] = 0;
252 static inline void loc_address_decrement(struct in6_addr
* address
) {
253 // Prevent underflow when everything is ones
254 if (loc_address_all_zeroes(address
))
258 foreach_octet_in_address_reverse(octet
, address
) {
259 if (address
->s6_addr
[octet
] > 0) {
260 address
->s6_addr
[octet
]--;
263 address
->s6_addr
[octet
] = 255;
268 static inline int loc_address_count_trailing_zero_bits(const struct in6_addr
* address
) {
272 foreach_octet_in_address_reverse(octet
, address
) {
273 if (address
->s6_addr
[octet
]) {
274 zeroes
+= __builtin_ctz(address
->s6_addr
[octet
]);
283 #endif /* LIBLOC_PRIVATE */
285 #endif /* LIBLOC_ADDRESS_H */