1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2014 Intel Corporation. All rights reserved.
6 #include <netinet/icmp6.h>
10 #include "alloc-util.h"
11 #include "ndisc-internal.h"
12 #include "ndisc-router-internal.h"
14 static sd_ndisc_router
* ndisc_router_free(sd_ndisc_router
*rt
) {
18 icmp6_packet_unref(rt
->packet
);
19 set_free(rt
->options
);
23 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router
, sd_ndisc_router
, ndisc_router_free
);
25 sd_ndisc_router
* ndisc_router_new(ICMP6Packet
*packet
) {
30 rt
= new(sd_ndisc_router
, 1);
34 *rt
= (sd_ndisc_router
) {
36 .packet
= icmp6_packet_ref(packet
),
37 .iterator
= ITERATOR_FIRST
,
43 int sd_ndisc_router_set_sender_address(sd_ndisc_router
*rt
, const struct in6_addr
*addr
) {
44 assert_return(rt
, -EINVAL
);
46 return icmp6_packet_set_sender_address(rt
->packet
, addr
);
49 int sd_ndisc_router_get_sender_address(sd_ndisc_router
*rt
, struct in6_addr
*ret
) {
50 assert_return(rt
, -EINVAL
);
52 return icmp6_packet_get_sender_address(rt
->packet
, ret
);
55 int sd_ndisc_router_get_timestamp(sd_ndisc_router
*rt
, clockid_t clock
, uint64_t *ret
) {
56 assert_return(rt
, -EINVAL
);
57 assert_return(ret
, -EINVAL
);
59 return icmp6_packet_get_timestamp(rt
->packet
, clock
, ret
);
62 #define DEFINE_GET_TIMESTAMP(name) \
63 int sd_ndisc_router_##name##_timestamp( \
64 sd_ndisc_router *rt, \
71 assert_return(rt, -EINVAL); \
72 assert_return(ret, -EINVAL); \
74 r = sd_ndisc_router_##name(rt, &s); \
78 r = sd_ndisc_router_get_timestamp(rt, clock, &t); \
82 *ret = time_span_to_stamp(s, t); \
86 DEFINE_GET_TIMESTAMP(get_lifetime
);
87 DEFINE_GET_TIMESTAMP(prefix_get_valid_lifetime
);
88 DEFINE_GET_TIMESTAMP(prefix_get_preferred_lifetime
);
89 DEFINE_GET_TIMESTAMP(route_get_lifetime
);
90 DEFINE_GET_TIMESTAMP(rdnss_get_lifetime
);
91 DEFINE_GET_TIMESTAMP(dnssl_get_lifetime
);
92 DEFINE_GET_TIMESTAMP(prefix64_get_lifetime
);
94 int ndisc_router_parse(sd_ndisc
*nd
, sd_ndisc_router
*rt
) {
95 const struct nd_router_advert
*a
;
101 if (rt
->packet
->raw_size
< sizeof(struct nd_router_advert
))
102 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
),
103 "Too small to be a router advertisement, ignoring.");
105 a
= (const struct nd_router_advert
*) rt
->packet
->raw_packet
;
106 assert(a
->nd_ra_type
== ND_ROUTER_ADVERT
);
107 assert(a
->nd_ra_code
== 0);
109 rt
->hop_limit
= a
->nd_ra_curhoplimit
;
110 rt
->flags
= a
->nd_ra_flags_reserved
; /* the first 8 bits */
111 rt
->lifetime_usec
= be16_sec_to_usec(a
->nd_ra_router_lifetime
, /* max_as_infinity = */ false);
112 rt
->reachable_time_usec
= be32_msec_to_usec(a
->nd_ra_reachable
, /* mas_as_infinity = */ false);
113 rt
->retransmission_time_usec
= be32_msec_to_usec(a
->nd_ra_retransmit
, /* max_as_infinity = */ false);
115 /* RFC 4191 section 2.2
116 * Prf (Default Router Preference)
117 * 2-bit signed integer. Indicates whether to prefer this router over other default routers. If the
118 * Router Lifetime is zero, the preference value MUST be set to (00) by the sender and MUST be
119 * ignored by the receiver. If the Reserved (10) value is received, the receiver MUST treat the value
120 * as if it were (00). */
121 rt
->preference
= (rt
->flags
>> 3) & 3;
122 if (rt
->preference
== SD_NDISC_PREFERENCE_RESERVED
)
123 rt
->preference
= SD_NDISC_PREFERENCE_MEDIUM
;
125 r
= ndisc_parse_options(rt
->packet
, &rt
->options
);
127 return log_ndisc_errno(nd
, r
, "Failed to parse NDisc options in router advertisement message, ignoring: %m");
132 int sd_ndisc_router_get_hop_limit(sd_ndisc_router
*rt
, uint8_t *ret
) {
133 assert_return(rt
, -EINVAL
);
134 assert_return(ret
, -EINVAL
);
136 *ret
= rt
->hop_limit
;
140 int sd_ndisc_router_get_reachable_time(sd_ndisc_router
*rt
, uint64_t *ret
) {
141 assert_return(rt
, -EINVAL
);
142 assert_return(ret
, -EINVAL
);
144 *ret
= rt
->reachable_time_usec
;
148 int sd_ndisc_router_get_retransmission_time(sd_ndisc_router
*rt
, uint64_t *ret
) {
149 assert_return(rt
, -EINVAL
);
150 assert_return(ret
, -EINVAL
);
152 *ret
= rt
->retransmission_time_usec
;
156 int sd_ndisc_router_get_flags(sd_ndisc_router
*rt
, uint64_t *ret
) {
157 assert_return(rt
, -EINVAL
);
158 assert_return(ret
, -EINVAL
);
160 sd_ndisc_option
*p
= ndisc_option_get_by_type(rt
->options
, SD_NDISC_OPTION_FLAGS_EXTENSION
);
162 *ret
= rt
->flags
| (p
? p
->extended_flags
: 0);
166 int sd_ndisc_router_get_lifetime(sd_ndisc_router
*rt
, uint64_t *ret
) {
167 assert_return(rt
, -EINVAL
);
170 *ret
= rt
->lifetime_usec
;
172 return rt
->lifetime_usec
> 0; /* Indicate if the router is still valid or not. */
175 int sd_ndisc_router_get_preference(sd_ndisc_router
*rt
, uint8_t *ret
) {
176 assert_return(rt
, -EINVAL
);
177 assert_return(ret
, -EINVAL
);
179 *ret
= rt
->preference
;
183 int sd_ndisc_router_get_sender_mac(sd_ndisc_router
*rt
, struct ether_addr
*ret
) {
184 assert_return(rt
, -EINVAL
);
186 return ndisc_option_get_mac(rt
->options
, SD_NDISC_OPTION_SOURCE_LL_ADDRESS
, ret
);
189 int sd_ndisc_router_get_mtu(sd_ndisc_router
*rt
, uint32_t *ret
) {
190 assert_return(rt
, -EINVAL
);
191 assert_return(ret
, -EINVAL
);
193 sd_ndisc_option
*p
= ndisc_option_get_by_type(rt
->options
, SD_NDISC_OPTION_MTU
);
201 int sd_ndisc_router_get_captive_portal(sd_ndisc_router
*rt
, const char **ret
) {
202 assert_return(rt
, -EINVAL
);
203 assert_return(ret
, -EINVAL
);
205 sd_ndisc_option
*p
= ndisc_option_get_by_type(rt
->options
, SD_NDISC_OPTION_CAPTIVE_PORTAL
);
209 *ret
= p
->captive_portal
;
213 int sd_ndisc_router_option_rewind(sd_ndisc_router
*rt
) {
214 assert_return(rt
, -EINVAL
);
216 rt
->iterator
= ITERATOR_FIRST
;
217 return sd_ndisc_router_option_next(rt
);
220 int sd_ndisc_router_option_next(sd_ndisc_router
*rt
) {
221 assert_return(rt
, -EINVAL
);
223 return set_iterate(rt
->options
, &rt
->iterator
, (void**) &rt
->current_option
);
226 int sd_ndisc_router_option_get_type(sd_ndisc_router
*rt
, uint8_t *ret
) {
227 assert_return(rt
, -EINVAL
);
228 assert_return(ret
, -EINVAL
);
230 if (!rt
->current_option
)
233 *ret
= rt
->current_option
->type
;
237 int sd_ndisc_router_option_is_type(sd_ndisc_router
*rt
, uint8_t type
) {
241 assert_return(rt
, -EINVAL
);
243 r
= sd_ndisc_router_option_get_type(rt
, &t
);
250 int sd_ndisc_router_option_get_raw(sd_ndisc_router
*rt
, const uint8_t **ret
, size_t *ret_size
) {
251 assert_return(rt
, -EINVAL
);
253 if (!rt
->current_option
)
256 return ndisc_option_parse(rt
->packet
, rt
->current_option
->offset
, NULL
, ret_size
, ret
);
259 #define DEFINE_GETTER(name, type, element, element_type) \
260 int sd_ndisc_router_##name##_get_##element( \
261 sd_ndisc_router *rt, \
262 element_type *ret) { \
266 assert_return(rt, -EINVAL); \
267 assert_return(ret, -EINVAL); \
269 r = sd_ndisc_router_option_is_type(rt, type); \
273 return -EMEDIUMTYPE; \
275 *ret = rt->current_option->name.element; \
279 DEFINE_GETTER(prefix
, SD_NDISC_OPTION_PREFIX_INFORMATION
, flags
, uint8_t);
280 DEFINE_GETTER(prefix
, SD_NDISC_OPTION_PREFIX_INFORMATION
, prefixlen
, uint8_t);
281 DEFINE_GETTER(prefix
, SD_NDISC_OPTION_PREFIX_INFORMATION
, address
, struct in6_addr
);
282 DEFINE_GETTER(prefix
, SD_NDISC_OPTION_PREFIX_INFORMATION
, valid_lifetime
, uint64_t);
283 DEFINE_GETTER(prefix
, SD_NDISC_OPTION_PREFIX_INFORMATION
, preferred_lifetime
, uint64_t);
285 DEFINE_GETTER(route
, SD_NDISC_OPTION_ROUTE_INFORMATION
, preference
, uint8_t);
286 DEFINE_GETTER(route
, SD_NDISC_OPTION_ROUTE_INFORMATION
, prefixlen
, uint8_t);
287 DEFINE_GETTER(route
, SD_NDISC_OPTION_ROUTE_INFORMATION
, address
, struct in6_addr
);
288 DEFINE_GETTER(route
, SD_NDISC_OPTION_ROUTE_INFORMATION
, lifetime
, uint64_t);
290 DEFINE_GETTER(rdnss
, SD_NDISC_OPTION_RDNSS
, lifetime
, uint64_t);
292 int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router
*rt
, const struct in6_addr
**ret
) {
295 assert_return(rt
, -EINVAL
);
296 assert_return(ret
, -EINVAL
);
298 r
= sd_ndisc_router_option_is_type(rt
, SD_NDISC_OPTION_RDNSS
);
304 *ret
= rt
->current_option
->rdnss
.addresses
;
305 return (int) rt
->current_option
->rdnss
.n_addresses
;
308 DEFINE_GETTER(dnssl
, SD_NDISC_OPTION_DNSSL
, domains
, char**);
309 DEFINE_GETTER(dnssl
, SD_NDISC_OPTION_DNSSL
, lifetime
, uint64_t);
311 DEFINE_GETTER(prefix64
, SD_NDISC_OPTION_PREF64
, prefixlen
, uint8_t);
312 DEFINE_GETTER(prefix64
, SD_NDISC_OPTION_PREF64
, prefix
, struct in6_addr
);
313 DEFINE_GETTER(prefix64
, SD_NDISC_OPTION_PREF64
, lifetime
, uint64_t);