From 87ad6c5f221f37a86571706451a37e7b1f7b7008 Mon Sep 17 00:00:00 2001 From: Amin Ben Ramdhane Date: Tue, 16 Aug 2022 10:41:11 +0000 Subject: [PATCH] T#8504: DHCPv4 options value is not implemented as standard --- dmtree/tr181/dhcpv4.c | 42 ++++++----- libbbf_api/dmcommon.c | 147 +++++++++++++++++++++++++++++++++++++ libbbf_api/dmcommon.h | 13 ++++ test/files/etc/config/dhcp | 4 +- 4 files changed, 185 insertions(+), 21 deletions(-) diff --git a/dmtree/tr181/dhcpv4.c b/dmtree/tr181/dhcpv4.c index d5a342d9..1b9354be 100644 --- a/dmtree/tr181/dhcpv4.c +++ b/dmtree/tr181/dhcpv4.c @@ -891,8 +891,7 @@ static int browseDHCPv4ServerPoolOptionInst(struct dmctx *dmctx, DMNODE *parent_ struct dhcp_args *curr_dhcp_args = (struct dhcp_args *)prev_data; struct uci_list *dhcp_options_list = NULL; struct uci_section *dmmap_sect = NULL; - char **dhcpv4_option = NULL, *inst = NULL, *dhcpv4_tag, *dhcpv4_value; - size_t length = 0; + char *inst = NULL, *dhcpv4_tag, *dhcpv4_value; struct dhcp_client_option_args dhcp_client_opt_args = {0}; dmuci_get_value_by_section_list(curr_dhcp_args->sections->config_section, "dhcp_option", &dhcp_options_list); @@ -901,16 +900,18 @@ static int browseDHCPv4ServerPoolOptionInst(struct dmctx *dmctx, DMNODE *parent_ struct uci_element *e = NULL; uci_foreach_element(dhcp_options_list, e) { + char buf[512] = {0}; - dhcpv4_option = strsplit(e->name, ",", &length); - if (!dhcpv4_option) - continue; + snprintf(buf, sizeof(buf), "%s", e->name); + char *p = strchr(buf, ','); + if (p) + *p = 0; - if ((dmmap_sect = get_dup_section_in_dmmap_eq("dmmap_dhcp", "servpool_option", section_name(curr_dhcp_args->sections->config_section), "option_tag", dhcpv4_option[0])) == NULL) { + if ((dmmap_sect = get_dup_section_in_dmmap_eq("dmmap_dhcp", "servpool_option", section_name(curr_dhcp_args->sections->config_section), "option_tag", buf)) == NULL) { dmuci_add_section_bbfdm("dmmap_dhcp", "servpool_option", &dmmap_sect); - dmuci_set_value_by_section_bbfdm(dmmap_sect, "option_tag", dhcpv4_option[0]); + dmuci_set_value_by_section_bbfdm(dmmap_sect, "option_tag", buf); dmuci_set_value_by_section_bbfdm(dmmap_sect, "section_name", section_name(curr_dhcp_args->sections->config_section)); - dmuci_set_value_by_section_bbfdm(dmmap_sect, "option_value", length > 1 ? dhcpv4_option[1] : ""); + dmuci_set_value_by_section_bbfdm(dmmap_sect, "option_value", p ? p + 1 : ""); } } } @@ -2090,11 +2091,12 @@ static int get_DHCPv4ServerPoolClientOption_Tag(char *refparam, struct dmctx *ct static int get_DHCPv4ServerPoolClientOption_Value(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { + const char *tag_option = ((struct client_options_args *)data)->tag; const char *tag_value = ((struct client_options_args *)data)->value; char hex[256] = {0}; - if (tag_value && *tag_value) - convert_string_to_hex(tag_value, hex, sizeof(hex)); + if (DM_STRLEN(tag_option) && DM_STRLEN(tag_value)) + convert_str_option_to_hex(DM_STRTOL(tag_option), tag_value, hex, sizeof(hex)); *value = (*hex) ? dmstrdup(hex) : ""; return 0; @@ -2653,11 +2655,12 @@ static int set_DHCPv4ClientSentOption_Tag(char *refparam, struct dmctx *ctx, voi static int get_DHCPv4ClientSentOption_Value(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { + const char *tag_option = ((struct dhcp_client_option_args *)data)->option_tag; const char *tag_value = ((struct dhcp_client_option_args *)data)->value; char hex[256] = {0}; - if (tag_value && *tag_value) - convert_string_to_hex(tag_value, hex, sizeof(hex)); + if (DM_STRLEN(tag_option) && DM_STRLEN(tag_value)) + convert_str_option_to_hex(DM_STRTOL(tag_option), tag_value, hex, sizeof(hex)); *value = (*hex) ? dmstrdup(hex) : ""; return 0; @@ -2675,7 +2678,7 @@ static int set_DHCPv4ClientSentOption_Value(char *refparam, struct dmctx *ctx, v return FAULT_9007; break; case VALUESET: - convert_hex_to_string(value, res, sizeof(res)); + convert_hex_option_to_string(DM_STRTOL(dhcp_client_s->option_tag), value, res, sizeof(res)); if (dhcp_client_s->client_sect) { option_name = get_dhcp_option_name(DM_STRTOL(dhcp_client_s->option_tag)); @@ -2988,11 +2991,12 @@ static int set_DHCPv4ServerPoolOption_Tag(char *refparam, struct dmctx *ctx, voi static int get_DHCPv4ServerPoolOption_Value(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { + const char *tag_option = ((struct dhcp_client_option_args *)data)->option_tag; const char *tag_value = ((struct dhcp_client_option_args *)data)->value; char hex[256] = {0}; - if (tag_value && *tag_value) - convert_string_to_hex(tag_value, hex, sizeof(hex)); + if (DM_STRLEN(tag_option) && DM_STRLEN(tag_value)) + convert_str_option_to_hex(DM_STRTOL(tag_option), tag_value, hex, sizeof(hex)); *value = (*hex) ? dmstrdup(hex) : ""; return 0; @@ -3026,7 +3030,7 @@ static int set_DHCPv4ServerPoolOption_Value(char *refparam, struct dmctx *ctx, v } } - convert_hex_to_string(value, res, sizeof(res)); + convert_hex_option_to_string(DM_STRTOL(dhcp_client_s->option_tag), value, res, sizeof(res)); if (option_enabled) { char new_tag_value[512] = {0}, old_tag_value[128] = {0}; @@ -3296,8 +3300,8 @@ static int get_DHCPv4RelayForwarding_UserClassID(char *refparam, struct dmctx *c dmuci_get_value_by_section_string(user_class_s, "userclass", &ucid); - if (ucid && *ucid) - convert_string_to_hex(ucid, hex, sizeof(hex)); + if (DM_STRLEN(ucid)) + convert_str_option_to_hex(77, ucid, hex, sizeof(hex)); *value = (*hex) ? dmstrdup(hex) : ""; } @@ -3326,7 +3330,7 @@ static int set_DHCPv4RelayForwarding_UserClassID(char *refparam, struct dmctx *c if (user_class_s) { char res[256] = {0}; - convert_hex_to_string(value, res, sizeof(res)); + convert_hex_option_to_string(77, value, res, sizeof(res)); dmuci_set_value_by_section(user_class_s, "userclass", res); } } diff --git a/libbbf_api/dmcommon.c b/libbbf_api/dmcommon.c index ec339c40..11091d45 100644 --- a/libbbf_api/dmcommon.c +++ b/libbbf_api/dmcommon.c @@ -66,6 +66,77 @@ char *IPPrefix[] = {"^$", "^/(3[0-2]|[012]?[0-9])$", "^((25[0-5]|2[0-4][0-9]|[01 char *IPv4Prefix[] = {"^$", "^/(3[0-2]|[012]?[0-9])$", "^((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])/(3[0-2]|[012]?[0-9])$", NULL}; char *IPv6Prefix[] = {"^$", "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/(12[0-8]|1[0-1][0-9]|[0-9]?[0-9])$", NULL}; +struct option_tag_type TYPE_TAG_ARRAY[] = { +{1, OPTION_IP, 4}, +{2, OPTION_INT, 4}, +{3, OPTION_IP, 4}, +{4, OPTION_IP, 4}, +{5, OPTION_IP, 4}, +{6, OPTION_IP, 4}, +{7, OPTION_IP, 4}, +{8, OPTION_IP, 4}, +{9, OPTION_IP, 4}, +{10, OPTION_IP, 4}, +{11, OPTION_IP, 4}, +{13, OPTION_INT, 2}, +{16, OPTION_IP, 4}, +{19, OPTION_INT, 1}, +{20, OPTION_INT, 1}, +{21, OPTION_IP, 4}, +{22, OPTION_INT, 2}, +{23, OPTION_INT, 1}, +{24, OPTION_INT, 4}, +{25, OPTION_INT, 2}, +{26, OPTION_INT, 2}, +{27, OPTION_INT, 1}, +{28, OPTION_IP, 4}, +{29, OPTION_INT, 1}, +{30, OPTION_INT, 1}, +{31, OPTION_INT, 1}, +{32, OPTION_IP, 4}, +{33, OPTION_IP, 4}, +{34, OPTION_INT, 1}, +{35, OPTION_INT, 4}, +{36, OPTION_INT, 1}, +{37, OPTION_INT, 1}, +{38, OPTION_INT, 4}, +{39, OPTION_INT, 1}, +{41, OPTION_IP, 4}, +{42, OPTION_IP, 4}, +{44, OPTION_IP, 4}, +{45, OPTION_IP, 4}, +{46, OPTION_INT, 1}, +{48, OPTION_IP, 4}, +{49, OPTION_IP, 4}, +{50, OPTION_IP, 4}, +{51, OPTION_IP, 4}, +{52, OPTION_INT, 1}, +{53, OPTION_INT, 1}, +{54, OPTION_INT, 4}, +{57, OPTION_INT, 2}, +{58, OPTION_INT, 4}, +{59, OPTION_INT, 4}, +{65, OPTION_IP, 4}, +{68, OPTION_IP, 4}, +{69, OPTION_IP, 4}, +{70, OPTION_IP, 4}, +{71, OPTION_IP, 4}, +{72, OPTION_IP, 4}, +{73, OPTION_IP, 4}, +{74, OPTION_IP, 4}, +{75, OPTION_IP, 4}, +{76, OPTION_IP, 4}, +{118, OPTION_IP, 4}, +{145, OPTION_INT, 1}, +{152, OPTION_INT, 4}, +{153, OPTION_INT, 4}, +{154, OPTION_INT, 4}, +{155, OPTION_INT, 4}, +{156, OPTION_INT, 1}, +{157, OPTION_INT, 1}, +{159, OPTION_INT, 4} +}; + pid_t get_pid(const char *pname) { DIR* dir; @@ -1110,6 +1181,82 @@ void convert_hex_to_string(const char *hex, char *str, size_t size) str[pos] = '\0'; } +void convert_str_option_to_hex(unsigned int tag, const char *str, char *hex, size_t size) +{ + int idx = -1; + + for (int i = 0; i < ARRAY_SIZE(TYPE_TAG_ARRAY); i++) { + if (TYPE_TAG_ARRAY[i].tag == tag) { + idx = i; + break; + } + } + + if (idx > 0) { + char *pch = NULL, *spch = NULL; + unsigned pos = 0; + char buf[512] = {0}; + + DM_STRNCPY(buf, str, sizeof(buf)); + for (pch = strtok_r(buf, ",", &spch); pch != NULL; pch = strtok_r(NULL, ",", &spch)) { + if (TYPE_TAG_ARRAY[idx].type == OPTION_IP) { + struct in_addr ip_bin; + + if (!inet_aton(pch, &ip_bin)) + continue; + + unsigned int ip = ntohl(ip_bin.s_addr); + pos += snprintf(&hex[pos], size - pos, "%08X", ip); + } else { + long int val = DM_STRTOL(pch); + pos += snprintf(&hex[pos], size - pos, (TYPE_TAG_ARRAY[idx].len == 4) ? "%08lX" : (TYPE_TAG_ARRAY[idx].len == 2) ? "%04lX" : "%02lX", val); + } + } + } else { + convert_string_to_hex(str, hex, size); + } +} + +void convert_hex_option_to_string(unsigned int tag, const char *hex, char *str, size_t size) +{ + int idx = -1; + + for (int i = 0; i < ARRAY_SIZE(TYPE_TAG_ARRAY); i++) { + if (TYPE_TAG_ARRAY[i].tag == tag) { + idx = i; + break; + } + } + + if (idx > 0) { + unsigned pos = 0; + unsigned int str_len = DM_STRLEN(hex); + unsigned int len = TYPE_TAG_ARRAY[idx].len * 2; + char buf[16] = {0}; + + for (int i = 0; i + len <= str_len; i = i + len) { + DM_STRNCPY(buf, &hex[i], len + 1); + if (TYPE_TAG_ARRAY[idx].type == OPTION_IP) { + struct in_addr addr; + unsigned int ip; + + sscanf(buf, "%X", &ip); + addr.s_addr = htonl(ip); + char *ipaddr = inet_ntoa(addr); + pos += snprintf(&str[pos], size - pos, "%s,", ipaddr); + } else { + int a = (int)strtol(buf, NULL, 16); + pos += snprintf(&str[pos], size - pos, "%d,", a); + } + } + + if (pos) + str[pos - 1] = 0; + } else { + convert_hex_to_string(hex, str, size); + } +} + bool match(const char *string, const char *pattern) { regex_t re; diff --git a/libbbf_api/dmcommon.h b/libbbf_api/dmcommon.h index 91df4fad..60e9995e 100644 --- a/libbbf_api/dmcommon.h +++ b/libbbf_api/dmcommon.h @@ -164,6 +164,11 @@ enum fs_size_type_enum { FS_SIZE_USED, }; +enum option_type_enum { + OPTION_IP, + OPTION_INT +}; + #define IPPING_PATH "/usr/share/bbfdm/ipping_launch" #define IPPING_STOP dmcmd("/bin/sh", 2, IPPING_PATH, "stop"); #define DOWNLOAD_DIAGNOSTIC_PATH "/usr/share/bbfdm/download_launch" @@ -204,6 +209,12 @@ struct browse_args { char *value; }; +struct option_tag_type { + int tag; + int type; + int len; +}; + pid_t get_pid(const char *pname); int check_file(char *path); char *cidr2netmask(int bits); @@ -263,6 +274,8 @@ int dm_time_utc_format(time_t ts, char **dst); int dm_time_format(time_t ts, char **dst); void convert_string_to_hex(const char *str, char *hex, size_t size); void convert_hex_to_string(const char *hex, char *str, size_t size); +void convert_str_option_to_hex(unsigned int tag, const char *str, char *hex, size_t size); +void convert_hex_option_to_string(unsigned int tag, const char *hex, char *str, size_t size); bool match(const char *string, const char *pattern); int dm_validate_string(char *value, int min_length, int max_length, char *enumeration[], char *pattern[]); int dm_validate_boolean(char *value); diff --git a/test/files/etc/config/dhcp b/test/files/etc/config/dhcp index 2a69bea7..e502ad99 100644 --- a/test/files/etc/config/dhcp +++ b/test/files/etc/config/dhcp @@ -41,8 +41,8 @@ config dhcp 'lan' list ra_flags 'managed-config' list ra_flags 'other-config' list dhcp_option '26,1470' - list dhcp_option '3,192.168.1.254' - list dhcp_option '6,iopsys.eu' + list dhcp_option '3,192.168.1.30,192.168.1.254' + list dhcp_option '6,192.168.1.1' config dhcp 'wan' option interface 'wan'