3939#pragma GCC diagnostic pop
4040
4141#define PORT_REPLY_SIZE (TUPLE_SIZE(2) + REF_SIZE)
42+ #define DEFAULT_HOSTNAME_SIZE (strlen("atomvm-") + 12 + 1)
4243
4344static const char * const ap_atom = ATOM_STR ("\x2" , "ap" );
4445static const char * const ap_channel_atom = ATOM_STR ("\xA" , "ap_channel" );
4546static const char * const ap_sta_connected_atom = ATOM_STR ("\x10" , "ap_sta_connected" );
4647static const char * const ap_sta_disconnected_atom = ATOM_STR ("\x13" , "ap_sta_disconnected" );
4748static const char * const ap_started_atom = ATOM_STR ("\xA" , "ap_started" );
49+ static const char * const dhcp_hostname_atom = ATOM_STR ("\xD" , "dhcp_hostname" );
4850static const char * const host_atom = ATOM_STR ("\x4" , "host" );
4951static const char * const psk_atom = ATOM_STR ("\x3" , "psk" );
5052static const char * const sntp_atom = ATOM_STR ("\x4" , "sntp" );
@@ -79,6 +81,8 @@ struct NetworkDriverData
7981 int stas_count ;
8082 uint8_t * stas_mac ;
8183 struct dhcp_config * dhcp_config ;
84+ char * hostname ;
85+ char * ap_hostname ;
8286 queue_t queue ;
8387};
8488
@@ -211,10 +215,29 @@ static void send_sntp_sync(struct timeval *tv)
211215 END_WITH_STACK_HEAP (heap , driver_data -> global );
212216}
213217
218+ // param should be pointer to malloc'd destination to copy device hostname
219+ // return ok atom or error as atom
220+ static term get_default_device_name (char * name , GlobalContext * global )
221+ {
222+ uint8_t mac [6 ];
223+ // Device name is used for AP mode ssid (if undefined), and for the
224+ // default dhcp_hostname on both interfaces. It seems the interface
225+ // parameter is ignored and both interfaces have the same MAC address.
226+ int err = cyw43_wifi_get_mac (& cyw43_state , CYW43_ITF_STA , mac );
227+ if (err ) {
228+ return globalcontext_make_atom (global , ATOM_STR ("\x10" , "device_mac_error" ));
229+ }
230+ size_t buf_size = DEFAULT_HOSTNAME_SIZE ;
231+ snprintf (name , buf_size ,
232+ "atomvm-%02x%02x%02x%02x%02x%02x" , mac [0 ], mac [1 ], mac [2 ], mac [3 ], mac [4 ], mac [5 ]);
233+ return OK_ATOM ;
234+ }
235+
214236static term start_sta (term sta_config , GlobalContext * global )
215237{
216238 term ssid_term = interop_kv_get_value (sta_config , ssid_atom , global );
217239 term pass_term = interop_kv_get_value (sta_config , psk_atom , global );
240+ term hostname_term = interop_kv_get_value (sta_config , dhcp_hostname_atom , global );
218241
219242 //
220243 // Check parameters
@@ -236,7 +259,54 @@ static term start_sta(term sta_config, GlobalContext *global)
236259 }
237260 }
238261
239- cyw43_arch_enable_sta_mode ();
262+ if (term_is_invalid_term (hostname_term )) {
263+ driver_data -> hostname = malloc (DEFAULT_HOSTNAME_SIZE );
264+ if (IS_NULL_PTR (driver_data -> hostname )) {
265+ free (ssid );
266+ free (psk );
267+ cyw43_arch_disable_sta_mode ();
268+ return OUT_OF_MEMORY_ATOM ;
269+ } else {
270+ term error = get_default_device_name (driver_data -> hostname , global );
271+ if (error != OK_ATOM ) {
272+ free (ssid );
273+ free (psk );
274+ free (driver_data -> hostname );
275+ cyw43_arch_disable_sta_mode ();
276+ return error ;
277+ }
278+ }
279+ } else {
280+ int ok = 0 ;
281+ char * buf = interop_term_to_string (hostname_term , & ok );
282+ if (!ok || IS_NULL_PTR (buf )) {
283+ free (ssid );
284+ free (psk );
285+ if (buf != NULL ) {
286+ free (buf );
287+ cyw43_arch_disable_sta_mode ();
288+ return BADARG_ATOM ;
289+ }
290+ cyw43_arch_disable_sta_mode ();
291+ return OUT_OF_MEMORY_ATOM ;
292+ }
293+ size_t buf_size = strlen (buf );
294+ driver_data -> hostname = malloc (buf_size );
295+ if (IS_NULL_PTR (driver_data -> hostname )) {
296+ free (ssid );
297+ free (psk );
298+ free (buf );
299+ cyw43_arch_disable_sta_mode ();
300+ return OUT_OF_MEMORY_ATOM ;
301+ }
302+ memcpy (driver_data -> hostname , buf , buf_size );
303+ free (buf );
304+ }
305+
306+ // hostname must be set after enabling sta mode, because it is erased by
307+ // cyw43_arch_enable_sta_mode and reset to factory "PicoW".
308+ netif_set_hostname (& cyw43_state .netif [CYW43_ITF_STA ], driver_data -> hostname );
309+
240310 uint32_t auth = (psk == NULL ) ? CYW43_AUTH_OPEN : CYW43_AUTH_WPA2_MIXED_PSK ;
241311 int result = cyw43_arch_wifi_connect_async (ssid , psk , auth );
242312 // We need to set the callback after calling connect async because it's
@@ -247,32 +317,14 @@ static term start_sta(term sta_config, GlobalContext *global)
247317 free (ssid );
248318 free (psk );
249319 if (result != 0 ) {
320+ free (driver_data -> hostname );
321+ cyw43_arch_disable_sta_mode ();
250322 return BADARG_ATOM ;
251323 }
252324
253325 return OK_ATOM ;
254326}
255327
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-
276328static void network_driver_do_cyw43_assoc (GlobalContext * glb )
277329{
278330 int max_stas ;
@@ -384,13 +436,23 @@ static term start_ap(term ap_config, GlobalContext *global)
384436 term ssid_term = interop_kv_get_value (ap_config , ssid_atom , global );
385437 term pass_term = interop_kv_get_value (ap_config , psk_atom , global );
386438 term channel_term = interop_kv_get_value (ap_config , ap_channel_atom , global );
439+ term hostname_term = interop_kv_get_value (ap_config , dhcp_hostname_atom , global );
387440
388441 //
389442 // Check parameters
390443 //
391444 char * ssid = NULL ;
392445 if (term_is_invalid_term (ssid_term )) {
393- ssid = get_default_device_name ();
446+ ssid = malloc (DEFAULT_HOSTNAME_SIZE );
447+ if (IS_NULL_PTR (ssid )) {
448+ return OUT_OF_MEMORY_ATOM ;
449+ } else {
450+ term error = get_default_device_name (ssid , global );
451+ if (error != OK_ATOM ) {
452+ free (ssid );
453+ return error ;
454+ }
455+ }
394456 } else {
395457 int ok = 0 ;
396458 ssid = interop_term_to_string (ssid_term , & ok );
@@ -419,9 +481,50 @@ static term start_ap(term ap_config, GlobalContext *global)
419481 }
420482 }
421483
484+ if (term_is_invalid_term (hostname_term )) {
485+ driver_data -> ap_hostname = malloc (DEFAULT_HOSTNAME_SIZE );
486+ if (IS_NULL_PTR (driver_data -> ap_hostname )) {
487+ free (ssid );
488+ free (psk );
489+ return OUT_OF_MEMORY_ATOM ;
490+ } else {
491+ term error = get_default_device_name (driver_data -> ap_hostname , global );
492+ if (error != OK_ATOM ) {
493+ free (ssid );
494+ free (psk );
495+ free (driver_data -> ap_hostname );
496+ return error ;
497+ }
498+ }
499+ } else {
500+ int ok = 0 ;
501+ char * buf = interop_term_to_string (hostname_term , & ok );
502+ if (UNLIKELY (!ok || buf == NULL )) {
503+ free (ssid );
504+ free (psk );
505+ if (buf != NULL ) {
506+ free (buf );
507+ return ERROR_ATOM ;
508+ }
509+ return OUT_OF_MEMORY_ATOM ;
510+ }
511+ size_t buf_size = strlen (buf );
512+ driver_data -> ap_hostname = malloc (buf_size );
513+ if (IS_NULL_PTR (driver_data -> ap_hostname )) {
514+ free (ssid );
515+ free (psk );
516+ free (buf );
517+ return OUT_OF_MEMORY_ATOM ;
518+ }
519+ memcpy (driver_data -> ap_hostname , buf , buf_size );
520+ free (buf );
521+ }
522+
422523 uint32_t auth = (psk == NULL ) ? CYW43_AUTH_OPEN : CYW43_AUTH_WPA2_AES_PSK ;
423524 cyw43_state .assoc_cb = network_driver_cyw43_assoc_cb ;
424525 cyw43_arch_enable_ap_mode (ssid , psk , auth );
526+ // Set hostname after enabling AP mode otherwise hostname will revert to "PicoW"
527+ netif_set_hostname (& cyw43_state .netif [CYW43_ITF_AP ], driver_data -> ap_hostname );
425528 send_ap_started (global );
426529 free (ssid );
427530 free (psk );
@@ -574,17 +677,18 @@ static void start_network(Context *ctx, term pid, term ref, term config)
574677 return ;
575678 }
576679
680+ // Always enable sta mode so the bus is initialized and we get a MAC
681+ // address. This is done before configuring the interface because the
682+ // MAC is added to the default hostname, and default ssid in ap mode.
683+ // (i.e. atomvm-0123456789ab)
684+ cyw43_arch_enable_sta_mode ();
577685 if (!term_is_invalid_term (sta_config )) {
578686 term result_atom = start_sta (sta_config , ctx -> global );
579687 if (result_atom != OK_ATOM ) {
580688 term error = port_create_error_tuple (ctx , result_atom );
581689 port_send_reply (ctx , pid , ref , error );
582690 return ;
583691 }
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 ();
588692 }
589693
590694 if (!term_is_invalid_term (ap_config )) {
@@ -705,6 +809,10 @@ void network_driver_init(GlobalContext *global)
705809void network_driver_destroy (GlobalContext * global )
706810{
707811 if (driver_data ) {
812+ free (driver_data -> hostname );
813+ if (driver_data -> ap_hostname ) {
814+ free (driver_data -> ap_hostname );
815+ }
708816 free (driver_data -> sntp_hostname );
709817 free (driver_data -> stas_mac );
710818 if (driver_data -> dhcp_config ) {
0 commit comments