Skip to content

Commit 3799ea5

Browse files
committed
Set inique dhcp_hostname, or configured name on pico_w
Correctly set `dhcp_hostname` from `sta_config_options()` and/or `ap_config_options()`, or, if undefined, sets a unique hostname to the default device name of `atomvm-${DEVICE_MAC}`. Formerly all pico_w devices tried to register to an access point with the factory default `PicoW` hostname, which would make all subsequent pico devices to connect to an access point, after the first one, unreachable by hostname, and cause unpredictable problems for some routers. Fixes #1094 on release-0.6 branch IMPORTANT: DO NOT FORWARD this commit to main branch. Breaking changes for rp2 (formerly rp2040) platform necessitate a seaprate PR to fix this issue for release-0.6, a fix has already been submitted to main branch (PR #1173). Signed-off-by: Winford <[email protected]>
1 parent f556340 commit 3799ea5

File tree

2 files changed

+136
-26
lines changed

2 files changed

+136
-26
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ memory error
5858
- Fixed possible concurrency problems in ESP32 UART driver
5959
- Fixed concurrency and memory leak related to links and monitors
6060
- Fixed issues with parsing of line references for stack traces
61+
- Correctly set Pico-W unique hostname, use `dhcp_hostname` if present in config.
62+
(see issue 1094)[https://github.com/atomvm/AtomVM/issues/1094].
6163

6264
### Changed
6365

src/platforms/rp2040/src/lib/networkdriver.c

+134-26
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,14 @@
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

4344
static const char *const ap_atom = ATOM_STR("\x2", "ap");
4445
static const char *const ap_channel_atom = ATOM_STR("\xA", "ap_channel");
4546
static const char *const ap_sta_connected_atom = ATOM_STR("\x10", "ap_sta_connected");
4647
static const char *const ap_sta_disconnected_atom = ATOM_STR("\x13", "ap_sta_disconnected");
4748
static const char *const ap_started_atom = ATOM_STR("\xA", "ap_started");
49+
static const char *const dhcp_hostname_atom = ATOM_STR("\xD", "dhcp_hostname");
4850
static const char *const host_atom = ATOM_STR("\x4", "host");
4951
static const char *const psk_atom = ATOM_STR("\x3", "psk");
5052
static 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+
214236
static 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-
276328
static 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)
705809
void 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

Comments
 (0)