udhcpc6: fix udhcp_find_option to actually find DHCP6 options

udhcp_insert_new_option treats code for IPv6 as follows:

new->data[D6_OPT_CODE] = code >> 8;
new->data[D6_OPT_CODE + 1] = code & 0xff;

udhcp_find_option tests the code as follows:

while (opt_list && opt_list->data[OPT_CODE] < code)
...
if (opt_list && opt_list->data[OPT_CODE] == code)

So yes, OPT_CODE and D6_OPT_CODE are both 0, but the D6_OPT_CLIENTID =
1 value means that the 1 is in the seconds byte, and udhcp_find_option
is only looking at the first byte,  So the send_d6_release can never
find it the created option.

function                                             old     new   delta
udhcp_find_option                                     28      53     +25
attach_option                                        276     284      +8
udhcpc6_main                                        2602    2607      +5
perform_d6_release                                   262     267      +5
udhcpd_main                                         1518    1520      +2
udhcpc_main                                         2542    2544      +2
add_serverid_and_clientid_options                     46      48      +2
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 7/0 up/down: 49/0)               Total: 49 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko
2021-12-12 17:13:54 +01:00
parent 9b67880719
commit e67b80f473
5 changed files with 34 additions and 14 deletions

View File

@ -404,14 +404,29 @@ void FAST_FUNC udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code,
#endif
/* Find option 'code' in opt_list */
struct option_set* FAST_FUNC udhcp_find_option(struct option_set *opt_list, uint8_t code)
struct option_set* FAST_FUNC udhcp_find_option(struct option_set *opt_list, uint8_t code, bool dhcpv6)
{
while (opt_list && opt_list->data[OPT_CODE] < code)
opt_list = opt_list->next;
IF_NOT_UDHCPC6(bool dhcpv6 = 0;)
uint8_t cur_code;
if (opt_list && opt_list->data[OPT_CODE] == code)
return opt_list;
return NULL;
for (;;) {
if (!opt_list)
return opt_list; /* NULL */
if (!dhcpv6) {
cur_code = opt_list->data[OPT_CODE];
} else {
//FIXME: add support for code > 0xff
if (opt_list->data[D6_OPT_CODE] != 0)
return NULL;
cur_code = opt_list->data[D6_OPT_CODE + 1];
}
if (cur_code >= code) {
if (cur_code == code)
return opt_list;
return NULL;
}
opt_list = opt_list->next;
}
}
/* Parse string to IP in network order */
@ -499,7 +514,7 @@ static NOINLINE void attach_option(
}
#endif
existing = udhcp_find_option(*opt_list, optflag->code);
existing = udhcp_find_option(*opt_list, optflag->code, dhcpv6);
if (!existing) {
/* make a new option */
uint8_t *p = udhcp_insert_new_option(opt_list, optflag->code, length, dhcpv6);