35
35
#include <hardware/rtc.h>
36
36
#include <lwip/apps/sntp.h>
37
37
#include <pico/cyw43_arch.h>
38
+ #include <string.h>
38
39
39
40
#pragma GCC diagnostic pop
40
41
41
42
#define PORT_REPLY_SIZE (TUPLE_SIZE(2) + REF_SIZE)
43
+ #define DEFAULT_HOSTNAME_FMT "atomvm-%02x%02x%02x%02x%02x%02x"
44
+ #define DEFAULT_HOSTNAME_SIZE (strlen("atomvm-") + 12 + 1)
42
45
43
46
static const char * const ap_atom = ATOM_STR ("\x2" , "ap" );
44
47
static const char * const ap_channel_atom = ATOM_STR ("\xA" , "ap_channel" );
45
48
static const char * const ap_sta_connected_atom = ATOM_STR ("\x10" , "ap_sta_connected" );
46
49
static const char * const ap_sta_disconnected_atom = ATOM_STR ("\x13" , "ap_sta_disconnected" );
47
50
static const char * const ap_started_atom = ATOM_STR ("\xA" , "ap_started" );
51
+ static const char * const dhcp_hostname_atom = ATOM_STR ("\xD" , "dhcp_hostname" );
48
52
static const char * const host_atom = ATOM_STR ("\x4" , "host" );
49
53
static const char * const psk_atom = ATOM_STR ("\x3" , "psk" );
50
54
static const char * const sntp_atom = ATOM_STR ("\x4" , "sntp" );
@@ -79,6 +83,8 @@ struct NetworkDriverData
79
83
int stas_count ;
80
84
uint8_t * stas_mac ;
81
85
struct dhcp_config * dhcp_config ;
86
+ char * hostname ;
87
+ char * ap_hostname ;
82
88
queue_t queue ;
83
89
};
84
90
@@ -100,6 +106,14 @@ struct NetworkDriverEvent
100
106
};
101
107
};
102
108
109
+ enum DriverErrorCodeType
110
+ {
111
+ DriverOK ,
112
+ DriverBADARG ,
113
+ DriverMACError ,
114
+ DriverOOM
115
+ };
116
+
103
117
// Callbacks do not allow for user data
104
118
// netif->state is actually pointing to &cyw43_state
105
119
static struct NetworkDriverData * driver_data ;
@@ -120,6 +134,26 @@ static term tuple_from_addr(Heap *heap, uint32_t addr)
120
134
return port_heap_create_tuple_n (heap , 4 , terms );
121
135
}
122
136
137
+ static term error_code_to_term (int error , GlobalContext * global )
138
+ {
139
+ switch (error ) {
140
+ case DriverOK :
141
+ return OK_ATOM ;
142
+ break ;
143
+ case DriverBADARG :
144
+ return BADARG_ATOM ;
145
+ break ;
146
+ case DriverMACError :
147
+ return globalcontext_make_atom (global , ATOM_STR ("\x10" , "device_mac_error" ));
148
+ break ;
149
+ case DriverOOM :
150
+ return OUT_OF_MEMORY_ATOM ;
151
+ break ;
152
+ default :
153
+ return BADARG_ATOM ;
154
+ }
155
+ }
156
+
123
157
static void send_term (Heap * heap , term t )
124
158
{
125
159
term ref = term_from_ref_ticks (driver_data -> ref_ticks , heap );
@@ -211,15 +245,60 @@ static void send_sntp_sync(struct timeval *tv)
211
245
END_WITH_STACK_HEAP (heap , driver_data -> global );
212
246
}
213
247
248
+ static enum DriverErrorCodeType write_default_device_name (size_t size , char * * out )
249
+ {
250
+ uint8_t mac [6 ];
251
+ // Device name is used for AP mode ssid (if undefined), and for the
252
+ // default dhcp_hostname on both interfaces. It seems the interface
253
+ // parameter is ignored and both interfaces have the same MAC address.
254
+ int err = cyw43_wifi_get_mac (& cyw43_state , CYW43_ITF_STA , mac );
255
+ if (UNLIKELY (err )) {
256
+ return DriverMACError ;
257
+ }
258
+ * out = malloc (size );
259
+ if (IS_NULL_PTR (out )) {
260
+ return DriverOOM ;
261
+ }
262
+ snprintf (* out , size ,
263
+ DEFAULT_HOSTNAME_FMT , mac [0 ], mac [1 ], mac [2 ], mac [3 ], mac [4 ], mac [5 ]);
264
+ return DriverOK ;
265
+ }
266
+
267
+ static enum DriverErrorCodeType set_interface_dhcp_name (term dhcp_name , char * * out )
268
+ {
269
+ if (term_is_invalid_term (dhcp_name )) {
270
+ enum DriverErrorCodeType ok_ret = write_default_device_name (DEFAULT_HOSTNAME_SIZE , out );
271
+ if (UNLIKELY (ok_ret != DriverOK )) {
272
+ free (out );
273
+ cyw43_arch_disable_sta_mode ();
274
+ return ok_ret ;
275
+ }
276
+ } else {
277
+ int ok = 0 ;
278
+ * out = interop_term_to_string (dhcp_name , & ok );
279
+ if (!ok || IS_NULL_PTR (out )) {
280
+ if (out != NULL ) {
281
+ free (out );
282
+ cyw43_arch_disable_sta_mode ();
283
+ return DriverBADARG ;
284
+ }
285
+ cyw43_arch_disable_sta_mode ();
286
+ return DriverOOM ;
287
+ }
288
+ }
289
+ return DriverOK ;
290
+ }
291
+
214
292
static term start_sta (term sta_config , GlobalContext * global )
215
293
{
216
294
term ssid_term = interop_kv_get_value (sta_config , ssid_atom , global );
217
295
term pass_term = interop_kv_get_value (sta_config , psk_atom , global );
296
+ term hostname_term = interop_kv_get_value (sta_config , dhcp_hostname_atom , global );
218
297
219
298
//
220
299
// Check parameters
221
300
//
222
- if (term_is_invalid_term (ssid_term )) {
301
+ if (UNLIKELY ( term_is_invalid_term (ssid_term ) )) {
223
302
return BADARG_ATOM ;
224
303
}
225
304
int ok = 0 ;
@@ -230,13 +309,21 @@ static term start_sta(term sta_config, GlobalContext *global)
230
309
char * psk = NULL ;
231
310
if (!term_is_invalid_term (pass_term )) {
232
311
psk = interop_term_to_string (pass_term , & ok );
233
- if (!ok ) {
312
+ if (UNLIKELY ( !ok ) ) {
234
313
free (ssid );
235
314
return BADARG_ATOM ;
236
315
}
237
316
}
238
317
239
- cyw43_arch_enable_sta_mode ();
318
+ enum DriverErrorCodeType ret = set_interface_dhcp_name (hostname_term , & driver_data -> hostname );
319
+ if (UNLIKELY (ret != DriverOK )) {
320
+ free (ssid );
321
+ free (psk );
322
+ return error_code_to_term (ret , global );
323
+ }
324
+
325
+ netif_set_hostname (& cyw43_state .netif [CYW43_ITF_STA ], driver_data -> hostname );
326
+
240
327
uint32_t auth = (psk == NULL ) ? CYW43_AUTH_OPEN : CYW43_AUTH_WPA2_MIXED_PSK ;
241
328
int result = cyw43_arch_wifi_connect_async (ssid , psk , auth );
242
329
// We need to set the callback after calling connect async because it's
@@ -247,32 +334,14 @@ static term start_sta(term sta_config, GlobalContext *global)
247
334
free (ssid );
248
335
free (psk );
249
336
if (result != 0 ) {
337
+ free (driver_data -> hostname );
338
+ cyw43_arch_disable_sta_mode ();
250
339
return BADARG_ATOM ;
251
340
}
252
341
253
342
return OK_ATOM ;
254
343
}
255
344
256
- static char * get_default_device_name ()
257
- {
258
- uint8_t mac [6 ];
259
- // Device name is used for AP mode. It seems the interface parameter is
260
- // ignored and both interfaces have the same MAC address.
261
- int err = cyw43_wifi_get_mac (& cyw43_state , CYW43_ITF_AP , mac );
262
- if (err ) {
263
- return NULL ;
264
- }
265
-
266
- size_t buf_size = strlen ("atomvm-" ) + 12 + 1 ;
267
- char * buf = malloc (buf_size );
268
- if (IS_NULL_PTR (buf )) {
269
- return NULL ;
270
- }
271
- snprintf (buf , buf_size ,
272
- "atomvm-%02x%02x%02x%02x%02x%02x" , mac [0 ], mac [1 ], mac [2 ], mac [3 ], mac [4 ], mac [5 ]);
273
- return buf ;
274
- }
275
-
276
345
static void network_driver_do_cyw43_assoc (GlobalContext * glb )
277
346
{
278
347
int max_stas ;
@@ -384,13 +453,18 @@ static term start_ap(term ap_config, GlobalContext *global)
384
453
term ssid_term = interop_kv_get_value (ap_config , ssid_atom , global );
385
454
term pass_term = interop_kv_get_value (ap_config , psk_atom , global );
386
455
term channel_term = interop_kv_get_value (ap_config , ap_channel_atom , global );
456
+ term hostname_term = interop_kv_get_value (ap_config , dhcp_hostname_atom , global );
387
457
388
458
//
389
459
// Check parameters
390
460
//
391
461
char * ssid = NULL ;
392
462
if (term_is_invalid_term (ssid_term )) {
393
- ssid = get_default_device_name ();
463
+ enum DriverErrorCodeType ret = write_default_device_name (DEFAULT_HOSTNAME_SIZE , & ssid );
464
+ if (UNLIKELY (ret != DriverOK )) {
465
+ free (ssid );
466
+ return error_code_to_term (ret , global );
467
+ }
394
468
} else {
395
469
int ok = 0 ;
396
470
ssid = interop_term_to_string (ssid_term , & ok );
@@ -402,11 +476,11 @@ static term start_ap(term ap_config, GlobalContext *global)
402
476
if (!term_is_invalid_term (pass_term )) {
403
477
int ok = 0 ;
404
478
psk = interop_term_to_string (pass_term , & ok );
405
- if (strlen (psk ) < 8 ) {
479
+ if (UNLIKELY ( strlen (psk ) < 8 ) ) {
406
480
free (ssid );
407
481
return BADARG_ATOM ;
408
482
}
409
- if (!ok ) {
483
+ if (UNLIKELY ( !ok ) ) {
410
484
free (ssid );
411
485
return BADARG_ATOM ;
412
486
}
@@ -419,9 +493,18 @@ static term start_ap(term ap_config, GlobalContext *global)
419
493
}
420
494
}
421
495
496
+ enum DriverErrorCodeType ret = set_interface_dhcp_name (hostname_term , & driver_data -> ap_hostname );
497
+ if (UNLIKELY (ret != DriverOK )) {
498
+ free (ssid );
499
+ free (psk );
500
+ return error_code_to_term (ret , global );
501
+ }
502
+
422
503
uint32_t auth = (psk == NULL ) ? CYW43_AUTH_OPEN : CYW43_AUTH_WPA2_AES_PSK ;
423
504
cyw43_state .assoc_cb = network_driver_cyw43_assoc_cb ;
424
505
cyw43_arch_enable_ap_mode (ssid , psk , auth );
506
+ // Set hostname after enabling AP mode otherwise hostname will revert to "PicoW"
507
+ netif_set_hostname (& cyw43_state .netif [CYW43_ITF_AP ], driver_data -> ap_hostname );
425
508
send_ap_started (global );
426
509
free (ssid );
427
510
free (psk );
@@ -574,17 +657,18 @@ static void start_network(Context *ctx, term pid, term ref, term config)
574
657
return ;
575
658
}
576
659
660
+ // Always enable sta mode so the bus is initialized and we get a MAC
661
+ // address. This is done before configuring the interface because the
662
+ // MAC is added to the default hostname, and default ssid in ap mode.
663
+ // (i.e. atomvm-0123456789ab)
664
+ cyw43_arch_enable_sta_mode ();
577
665
if (!term_is_invalid_term (sta_config )) {
578
666
term result_atom = start_sta (sta_config , ctx -> global );
579
667
if (result_atom != OK_ATOM ) {
580
668
term error = port_create_error_tuple (ctx , result_atom );
581
669
port_send_reply (ctx , pid , ref , error );
582
670
return ;
583
671
}
584
- } else {
585
- // Always enable sta mode so the bus is initialized and we get a MAC
586
- // address.
587
- cyw43_arch_enable_sta_mode ();
588
672
}
589
673
590
674
if (!term_is_invalid_term (ap_config )) {
@@ -705,6 +789,10 @@ void network_driver_init(GlobalContext *global)
705
789
void network_driver_destroy (GlobalContext * global )
706
790
{
707
791
if (driver_data ) {
792
+ free (driver_data -> hostname );
793
+ if (driver_data -> ap_hostname ) {
794
+ free (driver_data -> ap_hostname );
795
+ }
708
796
free (driver_data -> sntp_hostname );
709
797
free (driver_data -> stas_mac );
710
798
if (driver_data -> dhcp_config ) {
0 commit comments