From ae7edc2a93f7163e9858c6a6b03ff3aa077bd928 Mon Sep 17 00:00:00 2001 From: Liu Han Date: Fri, 4 Jun 2021 16:36:38 +0800 Subject: [PATCH] lwip/dhcp: add 60 option for vendor class identify Closes https://github.com/espressif/esp-idf/issues/6786 --- src/core/ipv4/dhcp.c | 164 ++++++++++++++++++++++++++++++++++- src/include/lwip/dhcp.h | 5 ++ src/include/lwip/prot/dhcp.h | 3 +- test/unit/lwipopts.h | 1 + 4 files changed, 170 insertions(+), 3 deletions(-) diff --git a/src/core/ipv4/dhcp.c b/src/core/ipv4/dhcp.c index 268fc9b17..d307cd805 100644 --- a/src/core/ipv4/dhcp.c +++ b/src/core/ipv4/dhcp.c @@ -127,6 +127,11 @@ #define LWIP_DHCP_PROVIDE_DNS_SERVERS 0 #endif +#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER +#define DHCP_OPTION_VSI_MAX 16 +static u32_t dhcp_option_vsi[DHCP_OPTION_VSI_MAX] = {0}; +#endif + /** Option handling: options are parsed in dhcp_parse_reply * and saved in an array where other functions can load them from. * This might be moved into the struct dhcp (not necessarily since @@ -144,6 +149,10 @@ enum dhcp_option_idx { #if ESP_DHCP DHCP_OPTION_IDX_MTU, #endif /* ESP_DHCP */ +#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER + DHCP_OPTION_IDX_VSI, + DHCP_OPTION_IDX_VSI_LAST = DHCP_OPTION_IDX_VSI + DHCP_OPTION_VSI_MAX -1, +#endif /* ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ #if LWIP_DHCP_PROVIDE_DNS_SERVERS DHCP_OPTION_IDX_DNS_SERVER, DHCP_OPTION_IDX_DNS_SERVER_LAST = DHCP_OPTION_IDX_DNS_SERVER + LWIP_DHCP_PROVIDE_DNS_SERVERS - 1, @@ -167,6 +176,9 @@ static u8_t dhcp_discover_request_options[] = { DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_ROUTER, DHCP_OPTION_BROADCAST +#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER + , DHCP_OPTION_VSI +#endif /* ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ #if LWIP_DHCP_PROVIDE_DNS_SERVERS , DHCP_OPTION_DNS_SERVER #endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ @@ -224,6 +236,12 @@ static u16_t dhcp_option_hostname(u16_t options_out_len, u8_t *options, struct n #if ESP_DHCP && !ESP_DHCP_DISABLE_CLIENT_ID static u16_t dhcp_option_client_id(struct netif *netif, struct dhcp_msg *msg_out, u16_t options_out_len); #endif /* ESP_DHCP && !ESP_DHCP_DISABLE_CLIENT_ID */ + +#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER +/* set dhcp option60 */ +static u16_t dhcp_option_vendor_class_identifier(struct netif *netif, struct dhcp_msg *msg_out, u16_t options_out_len); +#endif /* ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ + /* always add the DHCP options trailer to end and pad */ static void dhcp_option_trailer(u16_t options_out_len, u8_t *options, struct pbuf *p_out); @@ -350,6 +368,14 @@ dhcp_handle_offer(struct netif *netif, struct dhcp_msg *msg_in) LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + + /* Vendor Specific Information */ +#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER + for (u8_t n = 0; (n < DHCP_OPTION_VSI_MAX) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_VSI + n); n++) { + dhcp_option_vsi[n] = lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_VSI + n)); + } +#endif /* ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ + /* obtain the server address */ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) { dhcp->request_timeout = 0; /* stop timer */ @@ -410,6 +436,11 @@ dhcp_select(struct netif *netif) options_out_len = dhcp_option_client_id(netif, msg_out, options_out_len); #endif /* ESP_DHCP && !ESP_DHCP_DISABLE_CLIENT_ID */ +#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER + options_out_len = dhcp_option_vendor_class_identifier(netif, msg_out, options_out_len); +#endif /* ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ + + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_SERVER_ID, 4); options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr)))); @@ -658,9 +689,9 @@ dhcp_handle_ack(struct netif *netif, struct dhcp_msg *msg_in) { struct dhcp *dhcp = netif_dhcp_data(netif); -#if LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV +#if LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV || !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER u8_t n; -#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV */ +#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV || !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ #if LWIP_DHCP_GET_NTP_SRV ip4_addr_t ntp_server_addrs[LWIP_DHCP_MAX_NTP_SERVERS]; #endif @@ -694,6 +725,14 @@ dhcp_handle_ack(struct netif *netif, struct dhcp_msg *msg_in) } } #endif /* ESP_DHCP */ + + /* Vendor Specific Information */ +#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER + for (n = 0; (n < DHCP_OPTION_VSI_MAX) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_VSI + n); n++) { + dhcp_option_vsi[n] = lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_VSI + n)); + } +#endif /* ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ + /* renewal period given? */ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) { /* remember given rebind period */ @@ -1062,6 +1101,10 @@ dhcp_decline(struct netif *netif) options_out_len = dhcp_option_client_id(netif, msg_out, options_out_len); #endif /* ESP_DHCP && !ESP_DHCP_DISABLE_CLIENT_ID */ +#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER + options_out_len = dhcp_option_vendor_class_identifier(netif, msg_out, options_out_len); +#endif /* ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ + LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_BACKING_OFF, msg_out, DHCP_DECLINE, &options_out_len); dhcp_option_trailer(options_out_len, msg_out->options, p_out); @@ -1123,6 +1166,10 @@ dhcp_discover(struct netif *netif) #if !ESP_DHCP_DISABLE_CLIENT_ID options_out_len = dhcp_option_client_id(netif, msg_out, options_out_len); #endif /* !ESP_DHCP_DISABLE_CLIENT_ID */ + +#if !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER + options_out_len = dhcp_option_vendor_class_identifier(netif, msg_out, options_out_len); +#endif /* !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ #endif/* ESP_DHCP */ options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); @@ -1368,6 +1415,10 @@ dhcp_renew(struct netif *netif) options_out_len = dhcp_option_client_id(netif, msg_out, options_out_len); #endif /* ESP_DHCP && !ESP_DHCP_DISABLE_CLIENT_ID */ +#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER + options_out_len = dhcp_option_vendor_class_identifier(netif, msg_out, options_out_len); +#endif /* ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ + LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_RENEWING, msg_out, DHCP_REQUEST, &options_out_len); dhcp_option_trailer(options_out_len, msg_out->options, p_out); @@ -1427,6 +1478,10 @@ dhcp_rebind(struct netif *netif) options_out_len = dhcp_option_client_id(netif, msg_out, options_out_len); #endif /* ESP_DHCP && !ESP_DHCP_DISABLE_CLIENT_ID */ +#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER + options_out_len = dhcp_option_vendor_class_identifier(netif, msg_out, options_out_len); +#endif /* ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ + LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REBINDING, msg_out, DHCP_DISCOVER, &options_out_len); dhcp_option_trailer(options_out_len, msg_out->options, p_out); @@ -1488,6 +1543,10 @@ dhcp_reboot(struct netif *netif) options_out_len = dhcp_option_client_id(netif, msg_out, options_out_len); #endif /* ESP_DHCP && !ESP_DHCP_DISABLE_CLIENT_ID */ +#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER + options_out_len = dhcp_option_vendor_class_identifier(netif, msg_out, options_out_len); +#endif /* ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ + LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REBOOTING, msg_out, DHCP_REQUEST, &options_out_len); dhcp_option_trailer(options_out_len, msg_out->options, p_out); @@ -1559,6 +1618,10 @@ dhcp_release_and_stop(struct netif *netif) options_out_len = dhcp_option_client_id(netif, msg_out, options_out_len); #endif /* ESP_DHCP && !ESP_DHCP_DISABLE_CLIENT_ID */ +#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER + options_out_len = dhcp_option_vendor_class_identifier(netif, msg_out, options_out_len); +#endif /* ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ + LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, dhcp->state, msg_out, DHCP_RELEASE, &options_out_len); dhcp_option_trailer(options_out_len, msg_out->options, p_out); @@ -1719,6 +1782,95 @@ dhcp_option_client_id(struct netif *netif, struct dhcp_msg *msg_out, u16_t optio } #endif /* ESP_DHCP && !ESP_DHCP_DISABLE_CLIENT_ID */ +#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER +static u8_t vendor_class_len = 0; +static char *vendor_class_buf = NULL; + +err_t +dhcp_set_vendor_class_identifier(u8_t len, char *str) +{ + if (len == 0 || str == NULL) { + return ERR_ARG; + } + + if (vendor_class_buf && vendor_class_len != len) { + mem_free(vendor_class_buf); + vendor_class_buf = NULL; + } + + if (!vendor_class_buf) { + vendor_class_buf = (char *)mem_malloc(len + 1); + if (vendor_class_buf == NULL) { + return ERR_MEM; + } + + vendor_class_len = len; + } + + memcpy(vendor_class_buf, str, len); + return ERR_OK; +} + +err_t +dhcp_get_vendor_specific_information(u8_t len, char *str) +{ + u8_t copy_len = 0; + + if (len == 0 || str == NULL) { + return ERR_ARG; + } + + copy_len = LWIP_MIN(len, sizeof(dhcp_option_vsi)); + + memcpy(str, dhcp_option_vsi, copy_len); + + return ERR_OK; +} + +static u16_t +dhcp_option_vendor_class_identifier(struct netif *netif, struct dhcp_msg *msg_out, u16_t options_out_len) +{ + size_t i; + int available; + const char *p = NULL; + u8_t len = 0; + + if (netif == NULL || msg_out == NULL) { + return ERR_ARG; + } + + /* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME and 1 byte for trailer) */ + + available = DHCP_OPTIONS_LEN - options_out_len - 3; + LWIP_ASSERT("DHCP: problem unfolding DHCP options - too short on memory!", 0 <= available); + + if (vendor_class_buf && vendor_class_len) { + p = vendor_class_buf; + LWIP_ASSERT("DHCP: vendor_class_len is too long!", vendor_class_len <= available); + len = vendor_class_len; + } else { +#if LWIP_NETIF_HOSTNAME + if (netif->hostname != NULL) { + size_t namelen = strlen(netif->hostname); + if ((namelen > 0) && (namelen < 0xFF)) { + p = netif->hostname; + LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available); + len = (u8_t)namelen; + } + } +#endif + } + + len = LWIP_MIN(len, available); + if (p) { + options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_VCI, len); + for (i = 0; i < len; i ++) { + options_out_len = dhcp_option_byte(options_out_len, msg_out->options, p[i]); + } + } + return options_out_len; +} +#endif /* ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ /** * Extract the DHCP message and the DHCP options. @@ -1867,6 +2019,9 @@ dhcp_parse_reply(struct pbuf *p, struct dhcp *dhcp) LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); decode_idx = DHCP_OPTION_IDX_T2; break; + case (DHCP_OPTION_VSI): + decode_idx = DHCP_OPTION_IDX_VSI; + break; default: decode_len = 0; LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", (u16_t)op)); @@ -1896,7 +2051,10 @@ dhcp_parse_reply(struct pbuf *p, struct dhcp *dhcp) if (decode_len > 4) { /* decode more than one u32_t */ u16_t next_val_offset; +#if ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER + /* correct DHCP VCI data might not be aligned, so remove it. */ LWIP_ERROR("decode_len %% 4 == 0", decode_len % 4 == 0, return ERR_VAL;); +#endif /* ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ dhcp_got_option(dhcp, decode_idx); dhcp_set_option_value(dhcp, decode_idx, lwip_htonl(value)); decode_len = (u8_t)(decode_len - 4); @@ -1913,6 +2071,8 @@ dhcp_parse_reply(struct pbuf *p, struct dhcp *dhcp) #if ESP_DHCP } else if (decode_len == 2) { value = (u32_t)lwip_htons((u16_t)value); + } else if (decode_len == 3) { + value = lwip_ntohl(value); #endif /* ESP_DHCP */ } else { LWIP_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;); diff --git a/src/include/lwip/dhcp.h b/src/include/lwip/dhcp.h index 962cc2ee2..8a528219d 100644 --- a/src/include/lwip/dhcp.h +++ b/src/include/lwip/dhcp.h @@ -159,6 +159,11 @@ void dhcp_fine_tmr(void); extern void dhcp_set_ntp_servers(u8_t num_ntp_servers, const ip4_addr_t* ntp_server_addrs); #endif /* LWIP_DHCP_GET_NTP_SRV */ +#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER +err_t dhcp_set_vendor_class_identifier(u8_t len, char *str); +err_t dhcp_get_vendor_specific_information(u8_t len, char *str); +#endif /* ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER */ + #define netif_dhcp_data(netif) ((struct dhcp*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP)) #ifdef __cplusplus diff --git a/src/include/lwip/prot/dhcp.h b/src/include/lwip/prot/dhcp.h index ba03d4159..4fc5fb48e 100644 --- a/src/include/lwip/prot/dhcp.h +++ b/src/include/lwip/prot/dhcp.h @@ -159,7 +159,8 @@ typedef enum { #define DHCP_OPTION_T1 58 /* T1 renewal time */ #define DHCP_OPTION_T2 59 /* T2 rebinding time */ -#define DHCP_OPTION_US 60 +#define DHCP_OPTION_VCI 60 +#define DHCP_OPTION_VSI 43 #define DHCP_OPTION_CLIENT_ID 61 #define DHCP_OPTION_TFTP_SERVERNAME 66 #define DHCP_OPTION_BOOTFILE 67 diff --git a/test/unit/lwipopts.h b/test/unit/lwipopts.h index 4630b3a25..ee419ad40 100644 --- a/test/unit/lwipopts.h +++ b/test/unit/lwipopts.h @@ -105,6 +105,7 @@ #define ESP_DHCP_DEBUG 1 #define ESP_THREAD_PROTECTION 0 #define ESP_DHCP_DISABLE_CLIENT_ID 0 +#define ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER 0 #ifdef IP_NAPT #define IP_NAPT_MAX 16