sd-radv: Add Router Advertisement functionality
Add Router Advertisement header files, data structures and core functionality that is quite similar to other parts of networkd.
This commit is contained in:
parent
7d5cac19b5
commit
204f99d21e
|
@ -25,6 +25,31 @@
|
|||
#include "list.h"
|
||||
#include "sparse-endian.h"
|
||||
|
||||
enum RAdvState {
|
||||
SD_RADV_STATE_IDLE = 0,
|
||||
SD_RADV_STATE_ADVERTISING = 1,
|
||||
};
|
||||
typedef enum RAdvState RAdvState;
|
||||
|
||||
struct sd_radv {
|
||||
unsigned n_ref;
|
||||
RAdvState state;
|
||||
|
||||
int ifindex;
|
||||
|
||||
sd_event *event;
|
||||
int event_priority;
|
||||
|
||||
struct ether_addr mac_addr;
|
||||
uint8_t hop_limit;
|
||||
uint8_t flags;
|
||||
uint32_t mtu;
|
||||
uint16_t lifetime;
|
||||
|
||||
unsigned n_prefixes;
|
||||
LIST_HEAD(sd_radv_prefix, prefixes);
|
||||
};
|
||||
|
||||
struct sd_radv_prefix {
|
||||
unsigned n_ref;
|
||||
|
||||
|
|
|
@ -19,9 +19,11 @@
|
|||
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "sd-radv.h"
|
||||
|
||||
#include "macro.h"
|
||||
#include "alloc-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "icmp6-util.h"
|
||||
|
@ -31,6 +33,263 @@
|
|||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
_public_ int sd_radv_new(sd_radv **ret) {
|
||||
_cleanup_(sd_radv_unrefp) sd_radv *ra = NULL;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
ra = new0(sd_radv, 1);
|
||||
if (!ra)
|
||||
return -ENOMEM;
|
||||
|
||||
ra->n_ref = 1;
|
||||
|
||||
LIST_HEAD_INIT(ra->prefixes);
|
||||
|
||||
*ret = ra;
|
||||
ra = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_attach_event(sd_radv *ra, sd_event *event, int64_t priority) {
|
||||
int r;
|
||||
|
||||
assert_return(ra, -EINVAL);
|
||||
assert_return(!ra->event, -EBUSY);
|
||||
|
||||
if (event)
|
||||
ra->event = sd_event_ref(event);
|
||||
else {
|
||||
r = sd_event_default(&ra->event);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ra->event_priority = priority;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_detach_event(sd_radv *ra) {
|
||||
|
||||
assert_return(ra, -EINVAL);
|
||||
|
||||
ra->event = sd_event_unref(ra->event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ sd_event *sd_radv_get_event(sd_radv *ra) {
|
||||
assert_return(ra, NULL);
|
||||
|
||||
return ra->event;
|
||||
}
|
||||
|
||||
_public_ sd_radv *sd_radv_ref(sd_radv *ra) {
|
||||
if (!ra)
|
||||
return NULL;
|
||||
|
||||
assert(ra->n_ref > 0);
|
||||
ra->n_ref++;
|
||||
|
||||
return ra;
|
||||
}
|
||||
|
||||
_public_ sd_radv *sd_radv_unref(sd_radv *ra) {
|
||||
if (!ra)
|
||||
return NULL;
|
||||
|
||||
assert(ra->n_ref > 0);
|
||||
ra->n_ref--;
|
||||
|
||||
if (ra->n_ref > 0)
|
||||
return NULL;
|
||||
|
||||
while (ra->prefixes) {
|
||||
sd_radv_prefix *p = ra->prefixes;
|
||||
|
||||
LIST_REMOVE(prefix, ra->prefixes, p);
|
||||
sd_radv_prefix_unref(p);
|
||||
}
|
||||
|
||||
sd_radv_detach_event(ra);
|
||||
return mfree(ra);
|
||||
}
|
||||
|
||||
_public_ int sd_radv_stop(sd_radv *ra) {
|
||||
assert_return(ra, -EINVAL);
|
||||
|
||||
log_radv("Stopping IPv6 Router Advertisement daemon");
|
||||
|
||||
ra->state = SD_RADV_STATE_IDLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_start(sd_radv *ra) {
|
||||
assert_return(ra, -EINVAL);
|
||||
assert_return(ra->event, -EINVAL);
|
||||
assert_return(ra->ifindex > 0, -EINVAL);
|
||||
|
||||
if (ra->state != SD_RADV_STATE_IDLE)
|
||||
return 0;
|
||||
|
||||
ra->state = SD_RADV_STATE_ADVERTISING;
|
||||
|
||||
log_radv("Started IPv6 Router Advertisement daemon");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_set_ifindex(sd_radv *ra, int ifindex) {
|
||||
assert_return(ra, -EINVAL);
|
||||
assert_return(ifindex >= -1, -EINVAL);
|
||||
|
||||
if (ra->state != SD_RADV_STATE_IDLE)
|
||||
return -EBUSY;
|
||||
|
||||
ra->ifindex = ifindex;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr) {
|
||||
assert_return(ra, -EINVAL);
|
||||
|
||||
if (ra->state != SD_RADV_STATE_IDLE)
|
||||
return -EBUSY;
|
||||
|
||||
if (mac_addr)
|
||||
ra->mac_addr = *mac_addr;
|
||||
else
|
||||
zero(ra->mac_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu) {
|
||||
assert_return(ra, -EINVAL);
|
||||
assert_return(mtu >= 1280, -EINVAL);
|
||||
|
||||
if (ra->state != SD_RADV_STATE_IDLE)
|
||||
return -EBUSY;
|
||||
|
||||
ra->mtu = mtu;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit) {
|
||||
assert_return(ra, -EINVAL);
|
||||
|
||||
if (ra->state != SD_RADV_STATE_IDLE)
|
||||
return -EBUSY;
|
||||
|
||||
ra->hop_limit = hop_limit;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_set_router_lifetime(sd_radv *ra, uint32_t router_lifetime) {
|
||||
assert_return(ra, -EINVAL);
|
||||
|
||||
if (ra->state != SD_RADV_STATE_IDLE)
|
||||
return -EBUSY;
|
||||
|
||||
/* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the
|
||||
preference value MUST be set to (00) by the sender..." */
|
||||
if (router_lifetime == 0 &&
|
||||
(ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
|
||||
return -ETIME;
|
||||
|
||||
ra->lifetime = router_lifetime;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_set_managed_information(sd_radv *ra, int managed) {
|
||||
assert_return(ra, -EINVAL);
|
||||
|
||||
if (ra->state != SD_RADV_STATE_IDLE)
|
||||
return -EBUSY;
|
||||
|
||||
SET_FLAG(ra->flags, ND_RA_FLAG_MANAGED, managed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_set_other_information(sd_radv *ra, int other) {
|
||||
assert_return(ra, -EINVAL);
|
||||
|
||||
if (ra->state != SD_RADV_STATE_IDLE)
|
||||
return -EBUSY;
|
||||
|
||||
SET_FLAG(ra->flags, ND_RA_FLAG_OTHER, other);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_set_preference(sd_radv *ra, unsigned preference) {
|
||||
int r = 0;
|
||||
|
||||
assert_return(ra, -EINVAL);
|
||||
assert_return(IN_SET(preference,
|
||||
SD_NDISC_PREFERENCE_LOW,
|
||||
SD_NDISC_PREFERENCE_MEDIUM,
|
||||
SD_NDISC_PREFERENCE_HIGH), -EINVAL);
|
||||
|
||||
ra->flags = (ra->flags & ~(0x3 << 3)) | (preference << 3);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
|
||||
sd_radv_prefix *cur;
|
||||
_cleanup_free_ char *addr_p = NULL;
|
||||
|
||||
assert_return(ra, -EINVAL);
|
||||
|
||||
if (!p)
|
||||
return -EINVAL;
|
||||
|
||||
LIST_FOREACH(prefix, cur, ra->prefixes) {
|
||||
int r;
|
||||
|
||||
r = in_addr_prefix_intersect(AF_INET6,
|
||||
(union in_addr_union*) &cur->opt.in6_addr,
|
||||
cur->opt.prefixlen,
|
||||
(union in_addr_union*) &p->opt.in6_addr,
|
||||
p->opt.prefixlen);
|
||||
if (r > 0) {
|
||||
_cleanup_free_ char *addr_cur = NULL;
|
||||
|
||||
(void) in_addr_to_string(AF_INET6,
|
||||
(union in_addr_union*) &cur->opt.in6_addr,
|
||||
&addr_cur);
|
||||
(void) in_addr_to_string(AF_INET6,
|
||||
(union in_addr_union*) &p->opt.in6_addr,
|
||||
&addr_p);
|
||||
|
||||
log_radv("IPv6 prefix %s/%u already configured, ignoring %s/%u",
|
||||
addr_cur, cur->opt.prefixlen,
|
||||
addr_p, p->opt.prefixlen);
|
||||
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
p = sd_radv_prefix_ref(p);
|
||||
|
||||
LIST_APPEND(prefix, ra->prefixes, p);
|
||||
|
||||
ra->n_prefixes++;
|
||||
|
||||
(void) in_addr_to_string(AF_INET6, (union in_addr_union*) &p->opt.in6_addr, &addr_p);
|
||||
log_radv("Added prefix %s/%d", addr_p, p->opt.prefixlen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_radv_prefix_new(sd_radv_prefix **ret) {
|
||||
_cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
|
||||
|
||||
|
@ -53,6 +312,8 @@ _public_ int sd_radv_prefix_new(sd_radv_prefix **ret) {
|
|||
p->opt.preferred_lifetime = htobe32(604800);
|
||||
p->opt.valid_lifetime = htobe32(2592000);
|
||||
|
||||
LIST_INIT(prefix, p);
|
||||
|
||||
*ret = p;
|
||||
p = NULL;
|
||||
|
||||
|
|
|
@ -25,14 +25,39 @@
|
|||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-ndisc.h"
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
typedef struct sd_radv sd_radv;
|
||||
typedef struct sd_radv_prefix sd_radv_prefix;
|
||||
|
||||
/* Router Advertisment */
|
||||
int sd_radv_new(sd_radv **ret);
|
||||
sd_radv *sd_radv_ref(sd_radv *ra);
|
||||
sd_radv *sd_radv_unref(sd_radv *ra);
|
||||
|
||||
int sd_radv_attach_event(sd_radv *ra, sd_event *event, int64_t priority);
|
||||
int sd_radv_detach_event(sd_radv *nd);
|
||||
sd_event *sd_radv_get_event(sd_radv *ra);
|
||||
|
||||
int sd_radv_start(sd_radv *ra);
|
||||
int sd_radv_stop(sd_radv *ra);
|
||||
|
||||
int sd_radv_set_ifindex(sd_radv *ra, int interface_index);
|
||||
int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr);
|
||||
int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu);
|
||||
int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit);
|
||||
int sd_radv_set_router_lifetime(sd_radv *ra, uint32_t router_lifetime);
|
||||
int sd_radv_set_managed_information(sd_radv *ra, int managed);
|
||||
int sd_radv_set_other_information(sd_radv *ra, int other);
|
||||
int sd_radv_set_preference(sd_radv *ra, unsigned preference);
|
||||
int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p);
|
||||
|
||||
/* Advertised prefixes */
|
||||
int sd_radv_prefix_new(sd_radv_prefix **ret);
|
||||
sd_radv_prefix *sd_radv_prefix_ref(sd_radv_prefix *ra);
|
||||
|
|
Loading…
Reference in New Issue