diff options
Diffstat (limited to 'src/libsystemd-network/sd-ndisc-router-solicit.c')
-rw-r--r-- | src/libsystemd-network/sd-ndisc-router-solicit.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/src/libsystemd-network/sd-ndisc-router-solicit.c b/src/libsystemd-network/sd-ndisc-router-solicit.c new file mode 100644 index 0000000..04e7c26 --- /dev/null +++ b/src/libsystemd-network/sd-ndisc-router-solicit.c @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include <netinet/icmp6.h> + +#include "sd-radv.h" + +#include "alloc-util.h" +#include "in-addr-util.h" +#include "ndisc-option.h" +#include "ndisc-router-solicit-internal.h" +#include "radv-internal.h" + +static sd_ndisc_router_solicit* ndisc_router_solicit_free(sd_ndisc_router_solicit *rs) { + if (!rs) + return NULL; + + icmp6_packet_unref(rs->packet); + set_free(rs->options); + return mfree(rs); +} + +DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router_solicit, sd_ndisc_router_solicit, ndisc_router_solicit_free); + +sd_ndisc_router_solicit* ndisc_router_solicit_new(ICMP6Packet *packet) { + sd_ndisc_router_solicit *rs; + + assert(packet); + + rs = new(sd_ndisc_router_solicit, 1); + if (!rs) + return NULL; + + *rs = (sd_ndisc_router_solicit) { + .n_ref = 1, + .packet = icmp6_packet_ref(packet), + }; + + return rs; +} + +int ndisc_router_solicit_parse(sd_radv *ra, sd_ndisc_router_solicit *rs) { + int r; + + assert(rs); + assert(rs->packet); + + if (rs->packet->raw_size < sizeof(struct nd_router_solicit)) + return log_radv_errno(ra, SYNTHETIC_ERRNO(EBADMSG), + "Too small to be a router solicit, ignoring."); + + const struct nd_router_solicit *a = (const struct nd_router_solicit*) rs->packet->raw_packet; + assert(a); + assert(a->nd_rs_type == ND_ROUTER_SOLICIT); + assert(a->nd_rs_code == 0); + + r = ndisc_parse_options(rs->packet, &rs->options); + if (r < 0) + return log_radv_errno(ra, r, "Failed to parse NDisc options in router solicit, ignoring datagram: %m"); + + /* RFC 4861 section 4.1. + * Source link-layer address: + * The link-layer address of the sender, if known. MUST NOT be included if the Source + * Address is the unspecified address. Otherwise, it SHOULD be included on link + * layers that have addresses. */ + if (ndisc_option_get_mac(rs->options, SD_NDISC_OPTION_SOURCE_LL_ADDRESS, NULL) >= 0&& + sd_ndisc_router_solicit_get_sender_address(rs, NULL) == -ENODATA) + return log_radv_errno(ra, SYNTHETIC_ERRNO(EBADMSG), + "Router Solicitation message from null address unexpectedly contains source link-layer address option, ignoring datagaram."); + + return 0; +} + +int sd_ndisc_router_solicit_get_sender_address(sd_ndisc_router_solicit *rs, struct in6_addr *ret) { + assert_return(rs, -EINVAL); + + return icmp6_packet_get_sender_address(rs->packet, ret); +} + +int sd_ndisc_router_solicit_get_sender_mac(sd_ndisc_router_solicit *rs, struct ether_addr *ret) { + assert_return(rs, -EINVAL); + + return ndisc_option_get_mac(rs->options, SD_NDISC_OPTION_SOURCE_LL_ADDRESS, ret); +} |