Skip to content

Commit b5443d7

Browse files
committed
fix: Prevent Invalid location requests
Fixes test_shell failure caused by invalid Wi-Fi location data. Root cause: The location library can send cloud location requests with Wi-Fi data containing 0 access points, causing CBOR encoding failures (error 13/EINVAL). Occasionally, encoding of Wi-Fi APs fails when the maximum number of APs (10) is obtained. This is likely due to an encoding buffer size issue in the nRF Cloud encoding libraries. Changes: - Add validation in location module to reject cloud location requests from the location library that have no valid cellular or Wi-Fi data, preventing invalid requests from reaching the cloud module. - Add validation in cloud module to check Wi-Fi data has cnt > 0 before including it in location requests, preventing CBOR encoding errors. - Update tests and lower maximum CONFIG_LOCATION_METHOD_WIFI_SCANNING_RESULTS_MAX_CNT to 8 to prevent encoding errors seen when finding 10 APs due to potential memory issue with CBOR buffer being too low (LOCATION_GET_CBOR_MAX_SIZE hardcoded to 1024). Signed-off-by: Simen S. Røstad <simen.rostad@nordicsemi.no>
1 parent 1a4d13c commit b5443d7

5 files changed

Lines changed: 365 additions & 5 deletions

File tree

app/boards/thingy91x_nrf9151_ns.conf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ CONFIG_LOCATION_REQUEST_DEFAULT_WIFI_TIMEOUT=10000
4646
CONFIG_LOCATION_WORKQUEUE_STACK_SIZE=4096
4747

4848
# Align this with CONFIG_NRF_WIFI_SCAN_MAX_BSS_CNT
49-
CONFIG_LOCATION_METHOD_WIFI_SCANNING_RESULTS_MAX_CNT=10
49+
CONFIG_LOCATION_METHOD_WIFI_SCANNING_RESULTS_MAX_CNT=8
5050
# Align this with CONFIG_LOCATION_METHOD_WIFI_SCANNING_RESULTS_MAX_CNT
51-
CONFIG_NRF_WIFI_SCAN_MAX_BSS_CNT=10
51+
CONFIG_NRF_WIFI_SCAN_MAX_BSS_CNT=8
5252

5353
# Debug logging
5454
CONFIG_APP_POWER_LOG_LEVEL_DBG=y

app/src/modules/cloud/cloud_location.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,15 @@ static void handle_cloud_location_request(const struct location_data_cloud *requ
6363
#endif
6464

6565
#if defined(CONFIG_LOCATION_METHOD_WIFI)
66-
if (request->wifi_data != NULL) {
66+
if (request->wifi_data != NULL && request->wifi_data->cnt > 0) {
6767
/* Cast away const: nRF Cloud API limitation - struct fields are non-const
6868
* but the data is not modified by the API
6969
*/
7070
loc_req.wifi_info = (struct wifi_scan_info *)request->wifi_data; /* NOSONAR */
7171

7272
LOG_DBG("Wi-Fi data present: %d APs", request->wifi_data->cnt);
73+
} else if (request->wifi_data != NULL && request->wifi_data->cnt == 0) {
74+
LOG_DBG("Wi-Fi scan found 0 APs, omitting Wi-Fi data from location request");
7375
}
7476
#endif
7577

app/src/modules/location/location.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,10 +415,39 @@ static void location_event_handler(const struct location_event_data *event_data)
415415

416416
location_print_data_details(event_data->method, &event_data->fallback.details);
417417
break;
418-
case LOCATION_EVT_CLOUD_LOCATION_EXT_REQUEST:
418+
case LOCATION_EVT_CLOUD_LOCATION_EXT_REQUEST: {
419419
LOG_DBG("Cloud location request received from location library");
420420

421-
/* Cancel the current location request since we're now using cloud-based location */
421+
bool has_valid_data = false;
422+
423+
#if defined(CONFIG_LOCATION_METHOD_CELLULAR)
424+
if (event_data->cloud_location_request.cell_data != NULL) {
425+
has_valid_data = true;
426+
LOG_DBG("Cellular data present");
427+
}
428+
#endif
429+
#if defined(CONFIG_LOCATION_METHOD_WIFI)
430+
if (event_data->cloud_location_request.wifi_data != NULL &&
431+
event_data->cloud_location_request.wifi_data->cnt > 0) {
432+
has_valid_data = true;
433+
LOG_DBG("Wi-Fi data present: %d APs",
434+
event_data->cloud_location_request.wifi_data->cnt);
435+
}
436+
#endif
437+
438+
if (!has_valid_data) {
439+
LOG_WRN("Cloud location request has no valid cellular or Wi-Fi data, "
440+
"letting the library fall back to the next method");
441+
/* Send error result to allow fallback to next method */
442+
location_cloud_location_ext_result_set(LOCATION_EXT_RESULT_ERROR, NULL);
443+
break;
444+
}
445+
446+
/* Cancel the current location request to avoid falling back to the next
447+
* location source. Treat the fact that we have found Wi-Fi APs and/or cellular data
448+
* as a successful location request, even if we don't know whether the
449+
* cloud is able to resolve data to a location or not.
450+
*/
422451
int err = location_request_cancel();
423452

424453
if (err) {
@@ -430,6 +459,7 @@ static void location_event_handler(const struct location_event_data *event_data)
430459
cloud_request_send(&event_data->cloud_location_request);
431460
status_send(LOCATION_SEARCH_DONE);
432461
break;
462+
}
433463
#if defined(CONFIG_NRF_CLOUD_AGNSS)
434464
case LOCATION_EVT_GNSS_ASSISTANCE_REQUEST:
435465
LOG_DBG("A-GNSS assistance request received from location library");

tests/module/cloud/src/cloud_module_test.c

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,13 +246,15 @@ void setUp(void)
246246
RESET_FAKE(nrf_cloud_coap_disconnect);
247247
RESET_FAKE(nrf_cloud_coap_json_message_send);
248248
RESET_FAKE(nrf_cloud_coap_location_send);
249+
RESET_FAKE(nrf_cloud_coap_location_get);
249250
RESET_FAKE(nrf_cloud_coap_shadow_get);
250251
RESET_FAKE(nrf_cloud_coap_patch);
251252
RESET_FAKE(date_time_now);
252253
RESET_FAKE(nrf_provisioning_init);
253254
RESET_FAKE(nrf_provisioning_trigger_manually);
254255
RESET_FAKE(storage_batch_read);
255256
RESET_FAKE(nrf_cloud_coap_sensor_send);
257+
RESET_FAKE(location_cloud_location_ext_result_set);
256258

257259
nrf_cloud_client_id_get_fake.custom_fake = nrf_cloud_client_id_get_custom_fake;
258260
nrf_provisioning_init_fake.custom_fake = nrf_provisioning_init_custom_fake;
@@ -263,6 +265,7 @@ void setUp(void)
263265

264266
/* Set default return values */
265267
nrf_cloud_coap_location_send_fake.return_val = 0;
268+
nrf_cloud_coap_location_get_fake.return_val = 0;
266269
storage_batch_read_fake.return_val = -EAGAIN;
267270

268271
/* Clear all channels */
@@ -608,6 +611,161 @@ void test_gnss_location_data_handling(void)
608611
}
609612
}
610613

614+
/* Test cloud location request with valid Wi-Fi data */
615+
void test_cloud_location_request_with_valid_wifi(void)
616+
{
617+
int err;
618+
struct wifi_scan_result mock_aps[2] = {
619+
{.ssid = {0}, .ssid_length = 0, .rssi = -50, .channel = 1},
620+
{.ssid = {0}, .ssid_length = 0, .rssi = -60, .channel = 6}
621+
};
622+
struct wifi_scan_info mock_wifi_info = {
623+
.ap_info = mock_aps,
624+
.cnt = 2
625+
};
626+
struct location_data_cloud mock_cloud_request = {
627+
.cell_data = NULL,
628+
.wifi_data = &mock_wifi_info
629+
};
630+
struct location_msg location_msg = {
631+
.type = LOCATION_CLOUD_REQUEST,
632+
.cloud_request = mock_cloud_request
633+
};
634+
struct storage_msg passthrough_msg = {
635+
.type = STORAGE_MODE_PASSTHROUGH
636+
};
637+
struct storage_msg storage_data_msg = {
638+
.type = STORAGE_DATA,
639+
.data_type = STORAGE_TYPE_LOCATION,
640+
.data_len = sizeof(struct location_msg)
641+
};
642+
643+
memcpy(storage_data_msg.buffer, &location_msg, sizeof(location_msg));
644+
645+
connect_cloud();
646+
647+
err = zbus_chan_pub(&STORAGE_CHAN, &passthrough_msg, K_NO_WAIT);
648+
TEST_ASSERT_EQUAL(0, err);
649+
k_sleep(K_MSEC(10));
650+
651+
/* Send cloud location request with valid Wi-Fi data */
652+
err = zbus_chan_pub(&STORAGE_DATA_CHAN, &storage_data_msg, K_NO_WAIT);
653+
TEST_ASSERT_EQUAL(0, err);
654+
k_sleep(K_MSEC(PROCESSING_DELAY_MS));
655+
656+
/* Verify that location request was sent to nRF Cloud */
657+
TEST_ASSERT_EQUAL(1, nrf_cloud_coap_location_get_fake.call_count);
658+
659+
/* Verify request was not NULL */
660+
if (nrf_cloud_coap_location_get_fake.call_count > 0) {
661+
TEST_ASSERT_NOT_NULL(nrf_cloud_coap_location_get_fake.arg0_val);
662+
}
663+
}
664+
665+
/* Test cloud location request with 0 Wi-Fi APs still sends request */
666+
void test_cloud_location_request_with_zero_wifi_aps(void)
667+
{
668+
int err;
669+
struct wifi_scan_info mock_wifi_info = {
670+
.ap_info = NULL,
671+
.cnt = 0
672+
};
673+
struct location_data_cloud mock_cloud_request = {
674+
.cell_data = NULL,
675+
.wifi_data = &mock_wifi_info
676+
};
677+
struct location_msg location_msg = {
678+
.type = LOCATION_CLOUD_REQUEST,
679+
.cloud_request = mock_cloud_request
680+
};
681+
struct storage_msg passthrough_msg = {
682+
.type = STORAGE_MODE_PASSTHROUGH
683+
};
684+
struct storage_msg storage_data_msg = {
685+
.type = STORAGE_DATA,
686+
.data_type = STORAGE_TYPE_LOCATION,
687+
.data_len = sizeof(struct location_msg)
688+
};
689+
690+
memcpy(storage_data_msg.buffer, &location_msg, sizeof(location_msg));
691+
692+
connect_cloud();
693+
694+
err = zbus_chan_pub(&STORAGE_CHAN, &passthrough_msg, K_NO_WAIT);
695+
TEST_ASSERT_EQUAL(0, err);
696+
k_sleep(K_MSEC(10));
697+
698+
/* Send cloud location request with 0 Wi-Fi APs */
699+
err = zbus_chan_pub(&STORAGE_DATA_CHAN, &storage_data_msg, K_NO_WAIT);
700+
TEST_ASSERT_EQUAL(0, err);
701+
k_sleep(K_MSEC(PROCESSING_DELAY_MS));
702+
703+
/* Verify that location request was still sent (Wi-Fi omitted internally) */
704+
TEST_ASSERT_EQUAL(1, nrf_cloud_coap_location_get_fake.call_count);
705+
706+
/* Verify request was not NULL */
707+
if (nrf_cloud_coap_location_get_fake.call_count > 0) {
708+
TEST_ASSERT_NOT_NULL(nrf_cloud_coap_location_get_fake.arg0_val);
709+
}
710+
}
711+
712+
/* Test cloud location request with cellular data and 0 Wi-Fi APs */
713+
void test_cloud_location_request_cellular_with_zero_wifi_aps(void)
714+
{
715+
int err;
716+
struct lte_lc_cell mock_cell = {
717+
.mcc = 242,
718+
.mnc = 1,
719+
.id = 12345,
720+
.tac = 678
721+
};
722+
struct lte_lc_cells_info mock_cells_info = {
723+
.current_cell = mock_cell,
724+
.ncells_count = 0
725+
};
726+
struct wifi_scan_info mock_wifi_info = {
727+
.ap_info = NULL,
728+
.cnt = 0
729+
};
730+
struct location_data_cloud mock_cloud_request = {
731+
.cell_data = &mock_cells_info,
732+
.wifi_data = &mock_wifi_info
733+
};
734+
struct location_msg location_msg = {
735+
.type = LOCATION_CLOUD_REQUEST,
736+
.cloud_request = mock_cloud_request
737+
};
738+
struct storage_msg passthrough_msg = {
739+
.type = STORAGE_MODE_PASSTHROUGH
740+
};
741+
struct storage_msg storage_data_msg = {
742+
.type = STORAGE_DATA,
743+
.data_type = STORAGE_TYPE_LOCATION,
744+
.data_len = sizeof(struct location_msg)
745+
};
746+
747+
memcpy(storage_data_msg.buffer, &location_msg, sizeof(location_msg));
748+
749+
connect_cloud();
750+
751+
err = zbus_chan_pub(&STORAGE_CHAN, &passthrough_msg, K_NO_WAIT);
752+
TEST_ASSERT_EQUAL(0, err);
753+
k_sleep(K_MSEC(10));
754+
755+
/* Send cloud location request with cellular data and 0 Wi-Fi APs */
756+
err = zbus_chan_pub(&STORAGE_DATA_CHAN, &storage_data_msg, K_NO_WAIT);
757+
TEST_ASSERT_EQUAL(0, err);
758+
k_sleep(K_MSEC(PROCESSING_DELAY_MS));
759+
760+
/* Verify that location request was sent (cellular used, Wi-Fi omitted) */
761+
TEST_ASSERT_EQUAL(1, nrf_cloud_coap_location_get_fake.call_count);
762+
763+
/* Verify request was not NULL */
764+
if (nrf_cloud_coap_location_get_fake.call_count > 0) {
765+
TEST_ASSERT_NOT_NULL(nrf_cloud_coap_location_get_fake.arg0_val);
766+
}
767+
}
768+
611769
void test_storage_data_battery_sent_to_cloud(void)
612770
{
613771
int err;

0 commit comments

Comments
 (0)