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