sobota, 11 marca 2023

LPC1769 - LWIP - DHCP Vendor ID

W tym poście chciałbym opisać sposób wykonania modyfikacji LWIP, dotyczącej dołożenia parametru Vendor ID.

W protokole DHCP ustawienie opcji 60 czyli tzw. Vendor Class Id. W niej umieszczone są unikatowe informacje o urządzeniu np. nazwa wraz z numerem seryjnym, czy sam numer.

Biblioteka LWIP domyślnie nie posiada tej funkcji możliwej do uruchomienia. Natomiast dosyć łatwo można ją dołożyć.

Na samym początku należy przygotować funkcję zapisującą potrzebne dane:

  1. static int vendor_class_len = 0;
  2. static char * vendor_class_buf = NULL;
  3.  
  4. err_t dhcp_set_vendor_class_identifier(uint8_t len, char *str) {
  5.   if (len == 0) { return ERR_ARG; }
  6.  
  7.   if (str == NULL) { return ERR_ARG; }
  8.  
  9.   vendor_class_buf = (char *)mem_malloc(len + 1);
  10.   if (vendor_class_buf == NULL) { return ERR_MEM; }
  11.   vendor_class_len = len;
  12.   memcpy(vendor_class_buf, str, len);
  13.  
  14.   return 0;
  15. }

Funkcja można wywołać np. w dhcp_start(struct netif *netif):

  1. char vendorTmp[40] = {0x00};
  2.  
  3. err_t
  4. dhcp_start(struct netif *netif)
  5. {
  6.   struct dhcp *dhcp;
  7.   err_t result = ERR_OK;
  8.   extern volatile uint8_t serialNumber[3];
  9.   uint8_t arraySize = sprintf(vendorTmp, "KKK-Test KK_V4.9w %x%x%x", serialNumber[0], serialNumber[1], serialNumber[2]);
  10.   dhcp_set_vendor_class_identifier((arraySize), &vendorTmp[0]);
  11.  

W powyższym przypadku wykorzystuję funkcję sprintf do sformatowania ciągu znaków z wprowadzeniem numeru seryjnego.

Wprowadzanie danych do ramki DHCP musimy wpisać w trzech funkcjach dhcp_renew, dhcp_rebind oraz dhcp_select.

  1. #if LWIP_NETIF_HOSTNAME
  2.     dhcp_option_hostname(dhcp, netif);
  3. #endif /* LWIP_NETIF_HOSTNAME */
  4.  
  5. #ifdef LWIP_DHCP_VENDOR_ID
  6.     if (vendor_class_buf != NULL) {
  7.       const char *p = (const char*)vendor_class_buf;
  8.       if (vendor_class_len > 0) {
  9.         uint8_t len = 0;
  10.         size_t available = DHCP_OPTIONS_LEN - dhcp->options_out_len - 3;
  11.         len = LWIP_MIN(vendor_class_len, available);
  12.         dhcp_option(dhcp, DHCP_OPTION_US, len);
  13.         while (len--) {
  14.           dhcp_option_byte(dhcp, *p++);
  15.         }
  16.       }
  17.     }
  18. #endif

Powyższy kod sprawdza dostępność wolnego miejsca, jeśli będzie go za mało to w ramce zostanie umieszczony nie pełny ciąg znaków. 

Można to umieścić w osobnej funkcji:

  1. #ifdef LWIP_DHCP_VENDOR_ID
  2. static void
  3. dhcp_option_vendor_id(struct dhcp *dhcp, struct netif *netif)
  4. {
  5.     if (vendor_class_buf != NULL) {
  6.         const char *p = (const char*)vendor_class_buf;
  7.         if (vendor_class_len > 0) {
  8.             u8_t len = 0;
  9.             size_t available = DHCP_OPTIONS_LEN - dhcp->options_out_len - 3;
  10.             len = LWIP_MIN(vendor_class_len, available);
  11.             dhcp_option(dhcp, DHCP_OPTION_US, len);
  12.             while (len--) {
  13.                 dhcp_option_byte(dhcp, *p++);
  14.             }
  15.         }
  16.     }
  17. }
  18. #endif

Dzięki takiemu zabiegowi, jest trochę przejrzyściej:

  1. #if LWIP_NETIF_HOSTNAME
  2.     dhcp_option_hostname(dhcp, netif);
  3. #endif /* LWIP_NETIF_HOSTNAME */
  4.  
  5. #ifdef LWIP_DHCP_VENDOR_ID
  6.     dhcp_option_vendor_id(dhcp, netif);
  7. #endif /* LWIP_DHCP_VENDOR_ID */

Dodatkowo należy pamiętać o modyfikacji parametru DHCP_OPTIONS_LEN:

  1. #define DHCP_OPTIONS_LEN 150U //DHCP_MIN_OPTIONS_LEN