ndisc-option: fix parsing/building extended flags

The flags part of the option is 6 bytes. Let's read/write one by one.

Fixes https://github.com/systemd/systemd/pull/43620#discussion_r3913713018.
This commit is contained in:
Yu Watanabe
2026-09-23 16:33:34 +02:00
committed by Luca Boccassi
parent 1299c9cc9e
commit b628909430
2 changed files with 15 additions and 5 deletions
+7 -2
View File
@@ -871,7 +871,10 @@ static int ndisc_option_parse_flags_extension(Set **options, size_t offset, size
if (opt[0] != SD_NDISC_OPTION_FLAGS_EXTENSION) if (opt[0] != SD_NDISC_OPTION_FLAGS_EXTENSION)
return -EBADMSG; return -EBADMSG;
uint64_t flags = (unaligned_read_be64(opt) & UINT64_C(0xffffffffffff0000)) >> 8; uint64_t flags = 0;
for (size_t i = 2; i < 8; i++)
flags |= ((uint64_t) opt[i]) << ((i - 1) * 8);
return ndisc_option_add_flags_extension(options, offset, flags); return ndisc_option_add_flags_extension(options, offset, flags);
} }
@@ -884,10 +887,12 @@ static int ndisc_option_build_flags_extension(const sd_ndisc_option *option, uin
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
unaligned_write_be64(buf, (option->extended_flags & UINT64_C(0x00ffffffffffff00)) << 8);
buf[0] = SD_NDISC_OPTION_FLAGS_EXTENSION; buf[0] = SD_NDISC_OPTION_FLAGS_EXTENSION;
buf[1] = 1; buf[1] = 1;
for (size_t i = 2; i < 8; i++)
buf[i] = (option->extended_flags >> ((i - 1) * 8)) & 0xff;
*ret = TAKE_PTR(buf); *ret = TAKE_PTR(buf);
return 0; return 0;
} }
+8 -3
View File
@@ -105,6 +105,7 @@ static void router_dump(sd_ndisc_router *rt) {
log_info("Hop limit: %u", hop_limit); log_info("Hop limit: %u", hop_limit);
assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0); assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
ASSERT_EQ(flags & UINT64_C(0x00ffffffffffff00), UINT64_C(0x0066554433221100));
log_info("Flags: <%s|%s>", log_info("Flags: <%s|%s>",
flags & ND_RA_FLAG_OTHER ? "OTHER" : "", flags & ND_RA_FLAG_OTHER ? "OTHER" : "",
flags & ND_RA_FLAG_MANAGED ? "MANAGED" : ""); flags & ND_RA_FLAG_MANAGED ? "MANAGED" : "");
@@ -218,7 +219,7 @@ static void router_dump(sd_ndisc_router *rt) {
static int send_ra(uint8_t flags) { static int send_ra(uint8_t flags) {
uint8_t advertisement[] = { uint8_t advertisement[] = {
/* struct nd_router_advert */ /* struct nd_router_advert */
0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4, 0x86, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x00, 0xb4,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */ /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4, 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
@@ -235,6 +236,8 @@ static int send_ra(uint8_t flags) {
0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */ /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
/* type = 0x1a (SD_NDISC_OPTION_FLAGS_EXTENSION), length = 8 */
0x1a, 0x01, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
}; };
advertisement[5] = flags; advertisement[5] = flags;
@@ -269,7 +272,7 @@ static void test_callback_ra(sd_ndisc *nd, sd_ndisc_event_t event, void *message
router_dump(rt); router_dump(rt);
assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0); assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
assert_se(flags == flags_array[idx]); ASSERT_EQ(flags & 0xff, flags_array[idx]);
idx++; idx++;
log_debug("%s: Got event 0x%02" PRIx64, __func__, flags); log_debug("%s: Got event 0x%02" PRIx64, __func__, flags);
@@ -404,7 +407,7 @@ TEST(rs) {
static int send_ra_invalid_domain(uint8_t flags) { static int send_ra_invalid_domain(uint8_t flags) {
uint8_t advertisement[] = { uint8_t advertisement[] = {
/* struct nd_router_advert */ /* struct nd_router_advert */
0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4, 0x86, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x00, 0xb4,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */ /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4, 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
@@ -432,6 +435,8 @@ static int send_ra_invalid_domain(uint8_t flags) {
0xdb, 0x12, 0x9c, 0x75, 0x22, 0x5f, 0x12, 0x00, 0xdb, 0x12, 0x9c, 0x75, 0x22, 0x5f, 0x12, 0x00,
/* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */ /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
/* type = 0x1a (SD_NDISC_OPTION_FLAGS_EXTENSION), length = 8 */
0x1a, 0x01, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
}; };
advertisement[5] = flags; advertisement[5] = flags;