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 Jul 3, 2024
1 parent c3f7030 commit 7d3972b
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Support for `erlang:apply/2`
- Support for `lists:keystore/4`
- Support for `erlang:size/1` bif
- Added support to Pico-W network driver for setting `dhcp_hostname`
(see issue 1094)[https://github.com/atomvm/AtomVM/issues/1094].

### Changed

Expand Down
141 changes: 123 additions & 18 deletions src/platforms/rp2040/src/lib/networkdriver.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,14 @@

#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 @@ -80,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 @@ -212,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 @@ -236,8 +260,53 @@ static term start_sta(term sta_config, GlobalContext *global)
return BADARG_ATOM;
}
}
if (term_is_invalid_term(hostname_term)) {
size_t buf_size = DEFAULT_HOSTNAME_SIZE;
driver_data->hostname = malloc(buf_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;
}
driver_data->hostname = malloc(strlen(buf) + 1);
if (IS_NULL_PTR(driver_data->hostname)) {
free(ssid);
free(psk);
free(buf);
return OUT_OF_MEMORY_ATOM;
}
memcpy(driver_data->hostname, buf, strlen(buf) + 1);
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 All @@ -254,23 +323,6 @@ static term start_sta(term sta_config, GlobalContext *global)
return OK_ATOM;
}

// 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)
{
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"));
}

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 void network_driver_do_cyw43_assoc(GlobalContext *glb)
{
int max_stas;
Expand Down Expand Up @@ -382,6 +434,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 All @@ -392,7 +445,7 @@ static term start_ap(term ap_config, GlobalContext *global)
if (IS_NULL_PTR(ssid)) {
return OUT_OF_MEMORY_ATOM;
}
term error = get_default_device_name(ssid);
term error = get_default_device_name(ssid, global);
if (error != OK_ATOM) {
free(ssid);
return error;
Expand Down Expand Up @@ -426,6 +479,52 @@ 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;
}
driver_data->ap_hostname = malloc(strlen(buf) + 1);
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, strlen(buf) + 1);
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 @@ -712,6 +811,12 @@ void network_driver_init(GlobalContext *global)
void network_driver_destroy(GlobalContext *global)
{
if (driver_data) {
if (driver_data->hostname) {
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 7d3972b

Please sign in to comment.