1 /***************************************************************************/ /**
2  * @file  sl_utility.c
3  *******************************************************************************
4  * # License
5  * <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
6  *******************************************************************************
7  *
8  * SPDX-License-Identifier: Zlib
9  *
10  * The licensor of this software is Silicon Laboratories Inc.
11  *
12  * This software is provided 'as-is', without any express or implied
13  * warranty. In no event will the authors be held liable for any damages
14  * arising from the use of this software.
15  *
16  * Permission is granted to anyone to use this software for any purpose,
17  * including commercial applications, and to alter it and redistribute it
18  * freely, subject to the following restrictions:
19  *
20  * 1. The origin of this software must not be misrepresented; you must not
21  *    claim that you wrote the original software. If you use this software
22  *    in a product, an acknowledgment in the product documentation would be
23  *    appreciated but is not required.
24  * 2. Altered source versions must be plainly marked as such, and must not be
25  *    misrepresented as being the original software.
26  * 3. This notice may not be removed or altered from any source distribution.
27  *
28  ******************************************************************************/
29 
30 #include <stdbool.h>
31 #include <stdlib.h>
32 #include "sl_utility.h"
33 #include "sl_constants.h"
34 #include "sl_string.h"
35 #include "cmsis_compiler.h"
36 #include <string.h>
37 #include <stdio.h>
38 
39 #ifdef SPRINTF_CHAR
40 #define SPRINTF(x) strlen(sprintf /**/ x)
41 #else
42 #define SPRINTF(x) ((size_t)sprintf x)
43 #endif
44 
45 #define DIGIT_VAL(c)                             \
46   (((c >= '0') && (c <= '9'))   ? (c - '0')      \
47    : ((c >= 'a') && (c <= 'z')) ? (c - 'a' + 10) \
48    : ((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 10) \
49                                 : -1)
50 typedef struct {
51   int base;
52   int len;
53 } data_t;
54 
55 extern char *strtok_r(char *, const char *, char **);
56 
convert_uint32_to_bytestream(uint16_t data,uint8_t * buffer)57 void convert_uint32_to_bytestream(uint16_t data, uint8_t *buffer)
58 {
59   buffer[0] = (uint8_t)(data & 0xFF);
60   buffer[1] = (uint8_t)((data >> 8) & 0xFF);
61   buffer[2] = (uint8_t)((data >> 16) & 0xFF);
62   buffer[3] = (uint8_t)((data >> 24) & 0xFF);
63   return;
64 }
65 
convert_string_to_sl_ipv4_address(char * line,sl_ipv4_address_t * ip)66 sl_status_t convert_string_to_sl_ipv4_address(char *line, sl_ipv4_address_t *ip)
67 {
68   char *lasts       = NULL;
69   const char *token = strtok_r(line, ".", &lasts);
70 
71   for (uint8_t i = 0; i < 4; i++, token = strtok_r(NULL, ".", &lasts)) {
72     if (token == NULL) {
73       return SL_STATUS_COMMAND_IS_INVALID;
74     }
75     ip->bytes[i] = (uint8_t)strtoul(token, 0, 0);
76   }
77   return SL_STATUS_OK;
78 }
79 
print_sl_ip_address(const sl_ip_address_t * sl_ip_address)80 void print_sl_ip_address(const sl_ip_address_t *sl_ip_address)
81 {
82   if (sl_ip_address == NULL) {
83     return;
84   }
85 
86   if (sl_ip_address->type == SL_IPV4) {
87     print_sl_ipv4_address(&sl_ip_address->ip.v4);
88   } else if (sl_ip_address->type == SL_IPV6) {
89     print_sl_ipv6_address(&sl_ip_address->ip.v6);
90   }
91 }
92 
print_sl_ipv4_address(const sl_ipv4_address_t * ip_address)93 void print_sl_ipv4_address(const sl_ipv4_address_t *ip_address)
94 {
95   printf("%d.%d.%d.%d", ip_address->bytes[0], ip_address->bytes[1], ip_address->bytes[2], ip_address->bytes[3]);
96 }
97 
print_sl_ipv6_address(const sl_ipv6_address_t * ip_address)98 void print_sl_ipv6_address(const sl_ipv6_address_t *ip_address)
99 {
100   char temp_buffer[46] = { 0 };
101   sl_inet_ntop6((const unsigned char *)(ip_address), (char *)temp_buffer, sizeof(temp_buffer));
102   printf("%s\r\n", temp_buffer);
103 }
104 
print_mac_address(const sl_mac_address_t * mac_address)105 void print_mac_address(const sl_mac_address_t *mac_address)
106 {
107   if (mac_address == NULL) {
108     return;
109   }
110   printf("%2X:%2X:%2X:%2X:%2X:%2X",
111          mac_address->octet[0],
112          mac_address->octet[1],
113          mac_address->octet[2],
114          mac_address->octet[3],
115          mac_address->octet[4],
116          mac_address->octet[5]);
117 }
118 
sl_inet_ntop6(const unsigned char * input,char * dst,uint32_t size)119 char *sl_inet_ntop6(const unsigned char *input, char *dst, uint32_t size)
120 {
121   char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
122   char *tp;
123   data_t best;
124   data_t cur;
125   unsigned int words[SL_IPV6_ADDRESS_LENGTH / 2];
126   int i;
127   unsigned int ip_big_endian[4];
128   const unsigned char *src;
129   src = (unsigned char *)&ip_big_endian;
130 
131   little_to_big_endian((const unsigned int *)input, (unsigned char *)ip_big_endian, SL_IPV6_ADDRESS_LENGTH);
132 
133   memset(words, '\0', sizeof words);
134   for (i = 0; i < SL_IPV6_ADDRESS_LENGTH; i += 2) {
135     int temp     = src[i];
136     words[i / 2] = (temp << 8) | src[i + 1];
137   }
138   best.base = -1;
139   cur.base  = -1;
140   best.len  = 0;
141   cur.len   = 0;
142   for (i = 0; i < (SL_IPV6_ADDRESS_LENGTH / 2); i++) {
143     if (words[i] == 0) {
144       if (cur.base == -1) {
145         cur.base = i;
146         cur.len  = 1;
147       } else
148         cur.len++;
149     } else {
150       if (cur.base != -1) {
151         if (best.base == -1 || cur.len > best.len)
152           best = cur;
153         cur.base = -1;
154       }
155     }
156   }
157   if ((cur.base != -1) && (best.base == -1 || cur.len > best.len))
158     best = cur;
159   if (best.base != -1 && best.len < 2)
160     best.base = -1;
161   /*
162    * Format the result.
163    */
164   tp = tmp;
165   for (i = 0; i < (SL_IPV6_ADDRESS_LENGTH / 2); i++) {
166     /* Are we inside the best run of 0x00's? */
167     if (best.base != -1 && i >= best.base && i < (best.base + best.len)) {
168       if (i == best.base)
169         *tp++ = ':';
170       continue;
171     }
172     /* Are we following an initial run of 0x00s or any real hex? */
173     if (i != 0)
174       *tp++ = ':';
175     tp += SPRINTF((tp, "%x", words[i]));
176   }
177   /* Was it a trailing run of 0x00's? */
178   if (best.base != -1 && (best.base + best.len) == (SL_IPV6_ADDRESS_LENGTH / 2))
179     *tp++ = ':';
180   *tp++ = '\0';
181   /*
182    * Check for overflow, copy, and we're done.
183    */
184   if ((uint32_t)(tp - tmp) > size) {
185     printf("\r\n Error \r\n");
186     return NULL;
187   }
188   return memcpy(dst, tmp, size);
189 }
190 
hex_digit_value(char ch)191 static int hex_digit_value(char ch)
192 {
193   if ('0' <= ch && ch <= '9')
194     return ch - '0';
195   if ('a' <= ch && ch <= 'f')
196     return ch - 'a' + 10;
197   if ('A' <= ch && ch <= 'F')
198     return ch - 'A' + 10;
199   return -1;
200 }
201 
little_to_big_endian(const unsigned int * source,unsigned char * result,unsigned int length)202 void little_to_big_endian(const unsigned int *source, unsigned char *result, unsigned int length)
203 {
204   unsigned char *temp;
205   unsigned int curr = 0;
206   length /= 4;
207 
208   for (unsigned int i = 0; i < length; i++) {
209     curr    = source[i];
210     temp    = &result[i * 4];
211     temp[3] = (curr & 0xFF);
212     temp[2] = ((curr >> 8) & 0xFF);
213     temp[1] = ((curr >> 16) & 0xFF);
214     temp[0] = ((curr >> 24) & 0xFF);
215   }
216 }
217 
sl_inet_pton6(const char * src,const char * src_endp,unsigned char * dst,unsigned int * ptr_result)218 int sl_inet_pton6(const char *src, const char *src_endp, unsigned char *dst, unsigned int *ptr_result)
219 {
220   unsigned char tmp[SL_IPV6_ADDRESS_LENGTH];
221   unsigned char *tp;
222   unsigned char *endp;
223   unsigned char *colonp;
224   const char *curtok __attribute__((__unused__));
225   int ch;
226   size_t xdigits_seen; /* Number of hex digits since colon.  */
227   unsigned int val;
228   tp     = memset(tmp, '\0', SL_IPV6_ADDRESS_LENGTH);
229   endp   = tp + SL_IPV6_ADDRESS_LENGTH;
230   colonp = NULL;
231 
232   /* Leading :: requires some special handling.  */
233   if (src == src_endp)
234     return 0;
235   if (*src == ':') {
236     ++src;
237     if (src == src_endp || *src != ':')
238       return 0;
239   }
240 
241   curtok       = src;
242   xdigits_seen = 0;
243   val          = 0;
244 
245   while (src < src_endp) {
246     ch        = *src++;
247     int digit = hex_digit_value((char)ch);
248     //printf(" digit :%d ",digit);
249     if (digit >= 0) {
250       if (xdigits_seen == 4)
251         return 0;
252       val <<= 4;
253       val |= digit;
254       if (val > 0xffff)
255         return 0;
256       ++xdigits_seen;
257       continue;
258     }
259     if (ch == ':') {
260       curtok = src;
261 
262       if (xdigits_seen == 0) {
263         if (colonp)
264           return 0;
265         colonp = tp;
266         continue;
267       } else if (src == src_endp)
268         return 0;
269       if (tp + 2 > endp)
270         return 0;
271 
272       *tp++ = (unsigned char)(val >> 8) & 0xff;
273       *tp++ = (unsigned char)val & 0xff;
274 
275       xdigits_seen = 0;
276       val          = 0;
277       continue;
278     }
279   }
280 
281   if (xdigits_seen > 0) {
282     if (tp + 2 > endp)
283       return 0;
284     *tp++ = (unsigned char)(val >> 8) & 0xff;
285     *tp++ = (unsigned char)val & 0xff;
286   }
287   if (colonp != NULL) {
288     /* Replace :: with zeros.  */
289     if (tp == endp)
290       /* :: would expand to a zero-width field.  */
291       return 0;
292     size_t n = tp - colonp;
293     memmove(endp - n, colonp, n);
294     memset(colonp, 0, endp - n - colonp);
295     tp = endp;
296   }
297   if (tp != endp)
298     return 0;
299 
300   memcpy(dst, tmp, SL_IPV6_ADDRESS_LENGTH);
301   little_to_big_endian((const unsigned int *)dst, (unsigned char *)ptr_result, SL_IPV6_ADDRESS_LENGTH);
302 
303   return 1;
304 }
305 
convert_string_to_mac_address(const char * line,sl_mac_address_t * mac)306 sl_status_t convert_string_to_mac_address(const char *line, sl_mac_address_t *mac)
307 {
308   // Verify we have the exact number of characters. Basic argument verification
309   if (sl_strnlen((char *)line, 18) != 17) {
310     return SL_STATUS_INVALID_PARAMETER;
311   }
312 
313   uint8_t index = 0;
314   while (index < 6) {
315     // Read all the data and verify validity
316     int char1 = DIGIT_VAL(line[0]);
317     int char2 = DIGIT_VAL(line[1]);
318     if (char1 == -1 || char2 == -1 || (line[2] != '\0' && line[2] != ':')) {
319       return SL_STATUS_INVALID_PARAMETER;
320     }
321 
322     // Store value
323     mac->octet[index++] = (uint8_t)((uint8_t)char1 << 4) + (uint8_t)char2;
324     line += 3;
325   }
326 
327   return SL_STATUS_OK;
328 }
329 
reverse_digits(unsigned char * xx,int no_digits)330 void reverse_digits(unsigned char *xx, int no_digits)
331 {
332   uint8_t temp;
333   for (int count = 0; count < (no_digits / 2); count++) {
334     temp                      = xx[count];
335     xx[count]                 = xx[no_digits - count - 1];
336     xx[no_digits - count - 1] = temp;
337   }
338 }
339 
print_firmware_version(const sl_wifi_firmware_version_t * firmware_version)340 void print_firmware_version(const sl_wifi_firmware_version_t *firmware_version)
341 {
342   printf("\r\nFirmware version is: %x%x.%d.%d.%d.%d.%d.%d\r\n",
343          firmware_version->chip_id,
344          firmware_version->rom_id,
345          firmware_version->major,
346          firmware_version->minor,
347          firmware_version->security_version,
348          firmware_version->patch_num,
349          firmware_version->customer_id,
350          firmware_version->build_num);
351 }
352 
sl_debug_log(const char * format,...)353 __WEAK void sl_debug_log(const char *format, ...)
354 {
355   UNUSED_PARAMETER(format);
356 }
357 
sl_redirect_log(const char * format,...)358 void sl_redirect_log(const char *format, ...)
359 {
360   UNUSED_PARAMETER(format);
361 }
362