Skip to content

Commit

Permalink
Add pico_w network driver support for setting dhcp_hostname
Browse files Browse the repository at this point in the history
Adds support for setting `dhcp_hostname` from `sta_config_options()` and/or
`ap_config_options()`, or, if undefined, sets the 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.

Closes #1094

Signed-off-by: Winford <winford@object.stream>
  • Loading branch information
UncleGrumpy committed Dec 23, 2024
1 parent a779d17 commit 08e8831
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added menuconfig option for enabling USE_USB_SERIAL, eg. serial over USB for certain ESP32-S2 boards etc.
- Partial support for `erlang:fun_info/2`
- Added support for `registered_name` in `erlang:process_info/2` and `Process.info/2`
- Added support to Pico-W network driver for setting `dhcp_hostname`
(see issue 1094)[https://github.com/atomvm/AtomVM/issues/1094].

### Fixed
- ESP32: improved sntp sync speed from a cold boot.
Expand Down
122 changes: 122 additions & 0 deletions src/platforms/rp2/src/lib/networkdriver.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,15 @@
#pragma GCC diagnostic pop

#define PORT_REPLY_SIZE (TUPLE_SIZE(2) + REF_SIZE)
#define DEFAULT_HOSTNAME_SIZE (strlen("atomvm-") + 12 + 1)
#define MAX_HOSTNAME_SIZE (32 + 1)

static const char *const ap_atom = ATOM_STR("\x2", "ap");
static const char *const ap_channel_atom = ATOM_STR("\xA", "ap_channel");
static const char *const ap_sta_connected_atom = ATOM_STR("\x10", "ap_sta_connected");
static const char *const ap_sta_disconnected_atom = ATOM_STR("\x13", "ap_sta_disconnected");
static const char *const ap_started_atom = ATOM_STR("\xA", "ap_started");
static const char *const dhcp_hostname_atom = ATOM_STR("\xD", "dhcp_hostname");
static const char *const host_atom = ATOM_STR("\x4", "host");
static const char *const psk_atom = ATOM_STR("\x3", "psk");
static const char *const sntp_atom = ATOM_STR("\x4", "sntp");
Expand Down Expand Up @@ -79,6 +82,8 @@ struct NetworkDriverData
int stas_count;
uint8_t *stas_mac;
struct dhcp_config *dhcp_config;
char *hostname;
char *ap_hostname;
queue_t queue;
};

Expand Down Expand Up @@ -211,10 +216,30 @@ static void send_sntp_sync(struct timeval *tv)
END_WITH_STACK_HEAP(heap, driver_data->global);
}

// param should be pointer to malloc'd destination to copy device hostname
// return ok atom or error as atom
static term get_default_device_name(char *name, GlobalContext *global)
{
uint8_t mac[6];
// Device name is used for AP mode ssid (if undefined), and for the
// default dhcp_hostname on both interfaces. It seems the interface
// parameter is ignored and both interfaces have the same MAC address.
int err = cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_AP, mac);
if (err) {
return globalcontext_make_atom(global, ATOM_STR("\x10", "device_mac_error"));
}

size_t buf_size = DEFAULT_HOSTNAME_SIZE;
snprintf(name, buf_size,
"atomvm-%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return OK_ATOM;
}

static term start_sta(term sta_config, GlobalContext *global)
{
term ssid_term = interop_kv_get_value(sta_config, ssid_atom, global);
term pass_term = interop_kv_get_value(sta_config, psk_atom, global);
term hostname_term = interop_kv_get_value(sta_config, dhcp_hostname_atom, global);

//
// Check parameters
Expand All @@ -235,8 +260,53 @@ static term start_sta(term sta_config, GlobalContext *global)
return BADARG_ATOM;
}
}
if (term_is_invalid_term(hostname_term)) {
driver_data->hostname = malloc(DEFAULT_HOSTNAME_SIZE);
if (IS_NULL_PTR(driver_data->hostname)) {
free(ssid);
free(psk);
return OUT_OF_MEMORY_ATOM;
} else {
term error = get_default_device_name(driver_data->hostname, global);
if (error != OK_ATOM) {
free(ssid);
free(psk);
free(driver_data->hostname);
return error;
}
}
} else {
int ok = 0;
char *buf = malloc(MAX_HOSTNAME_SIZE);
if (IS_NULL_PTR(buf)) {
free(ssid);
free(psk);
return OUT_OF_MEMORY_ATOM;
} else {
buf = interop_term_to_string(hostname_term, &ok);
}
if (!ok || IS_NULL_PTR(buf)) {
free(ssid);
free(psk);
return BADARG_ATOM;
}
size_t buf_size = strlen(buf);
driver_data->hostname = malloc(buf_size);
if (IS_NULL_PTR(driver_data->hostname)) {
free(ssid);
free(psk);
free(buf);
return OUT_OF_MEMORY_ATOM;
}
memcpy(driver_data->hostname, buf, buf_size);
free(buf);
}

cyw43_arch_enable_sta_mode();

// hostname must be set after enabling sta mode, or it will be overwritten to factory "PicoW".
netif_set_hostname(&cyw43_state.netif[CYW43_ITF_STA], driver_data->hostname);

uint32_t auth = (psk == NULL) ? CYW43_AUTH_OPEN : CYW43_AUTH_WPA2_MIXED_PSK;
int result = cyw43_arch_wifi_connect_async(ssid, psk, auth);
// We need to set the callback after calling connect async because it's
Expand Down Expand Up @@ -384,6 +454,7 @@ static term start_ap(term ap_config, GlobalContext *global)
term ssid_term = interop_kv_get_value(ap_config, ssid_atom, global);
term pass_term = interop_kv_get_value(ap_config, psk_atom, global);
term channel_term = interop_kv_get_value(ap_config, ap_channel_atom, global);
term hostname_term = interop_kv_get_value(ap_config, dhcp_hostname_atom, global);

//
// Check parameters
Expand Down Expand Up @@ -419,6 +490,53 @@ static term start_ap(term ap_config, GlobalContext *global)
}
}

if (term_is_invalid_term(hostname_term)) {
driver_data->ap_hostname = malloc(DEFAULT_HOSTNAME_SIZE);
if (IS_NULL_PTR(driver_data->ap_hostname)) {
free(ssid);
free(psk);
return OUT_OF_MEMORY_ATOM;
} else {
term error = get_default_device_name(driver_data->ap_hostname, global);
if (error != OK_ATOM) {
free(ssid);
free(psk);
free(driver_data->ap_hostname);
return error;
}
}
} else {
int ok = 0;
char *buf = malloc(MAX_HOSTNAME_SIZE);
if (IS_NULL_PTR(buf)) {
free(ssid);
free(psk);
return OUT_OF_MEMORY_ATOM;
} else {
buf = interop_term_to_string(hostname_term, &ok);
}
if (UNLIKELY(!ok || buf == NULL)) {
free(ssid);
free(psk);
if (buf != NULL) {
free(buf);
}
return BADARG_ATOM;
}
size_t buf_size = srtlen(buf);
driver_data->ap_hostname = malloc(buf_size);
if (IS_NULL_PTR(driver_data->ap_hostname)) {
free(ssid);
free(psk);
free(buf);
return OUT_OF_MEMORY_ATOM;
}
memcpy(driver_data->ap_hostname, buf, buf_size);
free(buf);
}

netif_set_hostname(&cyw43_state.netif[CYW43_ITF_AP], driver_data->ap_hostname);

uint32_t auth = (psk == NULL) ? CYW43_AUTH_OPEN : CYW43_AUTH_WPA2_AES_PSK;
cyw43_state.assoc_cb = network_driver_cyw43_assoc_cb;
cyw43_arch_enable_ap_mode(ssid, psk, auth);
Expand Down Expand Up @@ -705,6 +823,10 @@ void network_driver_init(GlobalContext *global)
void network_driver_destroy(GlobalContext *global)
{
if (driver_data) {
free(driver_data->hostname);
if (driver_data->ap_hostname) {
free(driver_data->ap_hostname);
}
free(driver_data->sntp_hostname);
free(driver_data->stas_mac);
if (driver_data->dhcp_config) {
Expand Down

0 comments on commit 08e8831

Please sign in to comment.