Skip to content

Commit c55722b

Browse files
committed
net: shell: dns: Properly manage lifetime of callback data
DNS callback needs "struct shell *shell" data structure to pass as a parameter to shell print. How it was achieved previously is that it was packaged together with cosmetic "bool first" param into "struct net_shell_user_data" on the stack, and passed to the callback. The problem was that the original command handler then returned, so the "struct net_shell_user_data" on the stack was overwritten, and the callback crashed on accessing it. An obvious solution was to make that structure static, but that would leave to issues still, as turns out we allow system shell to be run as more than one concurrent instances. Next solution was to keep this structure on the stack, but block the command handler until callback is finished. However, that hit a deadlock due to not well thought out use of a mutex in the shell printing routines. The solution presented here is due to @nordic-krch, who noticed that "bool first" param is indeed cosmetic and not really required. Then we have only "struct shell *shell" to pass to the callback, and can do that in callback's pointer param directly, ditching "struct net_shell_user_data" which needs to be stored on the stack. Signed-off-by: Paul Sokolovsky <[email protected]>
1 parent 8d86773 commit c55722b

File tree

1 file changed

+10
-23
lines changed

1 file changed

+10
-23
lines changed

subsys/net/ip/net_shell.c

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,24 +1299,16 @@ static void dns_result_cb(enum dns_resolve_status status,
12991299
struct dns_addrinfo *info,
13001300
void *user_data)
13011301
{
1302-
struct net_shell_user_data *data = user_data;
1303-
const struct shell *shell = data->shell;
1304-
bool *first = data->user_data;
1302+
const struct shell *shell = user_data;
13051303

13061304
if (status == DNS_EAI_CANCELED) {
1307-
PR_WARNING("\nTimeout while resolving name.\n");
1308-
*first = false;
1305+
PR_WARNING("dns: Timeout while resolving name.\n");
13091306
return;
13101307
}
13111308

13121309
if (status == DNS_EAI_INPROGRESS && info) {
13131310
char addr[NET_IPV6_ADDR_LEN];
13141311

1315-
if (*first) {
1316-
PR("\n");
1317-
*first = false;
1318-
}
1319-
13201312
if (info->ai_family == AF_INET) {
13211313
net_addr_ntop(AF_INET,
13221314
&net_sin(&info->ai_addr)->sin_addr,
@@ -1328,25 +1320,25 @@ static void dns_result_cb(enum dns_resolve_status status,
13281320
} else {
13291321
strncpy(addr, "Invalid protocol family",
13301322
sizeof(addr));
1323+
/* strncpy() doesn't guarantee NUL byte at the end. */
1324+
addr[sizeof(addr) - 1] = 0;
13311325
}
13321326

1333-
PR("\t%s\n", addr);
1327+
PR("dns: %s\n", addr);
13341328
return;
13351329
}
13361330

13371331
if (status == DNS_EAI_ALLDONE) {
1338-
PR("All results received\n");
1339-
*first = false;
1332+
PR("dns: All results received\n");
13401333
return;
13411334
}
13421335

13431336
if (status == DNS_EAI_FAIL) {
1344-
PR_WARNING("No such name found.\n");
1345-
*first = false;
1337+
PR_WARNING("dns: No such name found.\n");
13461338
return;
13471339
}
13481340

1349-
PR_WARNING("Unhandled status %d received\n", status);
1341+
PR_WARNING("dns: Unhandled status %d received\n", status);
13501342
}
13511343

13521344
static void print_dns_info(const struct shell *shell,
@@ -1449,10 +1441,8 @@ static int cmd_net_dns_query(const struct shell *shell, size_t argc,
14491441

14501442
#if defined(CONFIG_DNS_RESOLVER)
14511443
#define DNS_TIMEOUT K_MSEC(2000) /* ms */
1452-
struct net_shell_user_data user_data;
14531444
enum dns_query_type qtype = DNS_QUERY_TYPE_A;
14541445
char *host, *type = NULL;
1455-
bool first = true;
14561446
int ret, arg = 1;
14571447

14581448
host = argv[arg++];
@@ -1479,11 +1469,8 @@ static int cmd_net_dns_query(const struct shell *shell, size_t argc,
14791469
}
14801470
}
14811471

1482-
user_data.shell = shell;
1483-
user_data.user_data = &first;
1484-
1485-
ret = dns_get_addr_info(host, qtype, NULL, dns_result_cb, &user_data,
1486-
DNS_TIMEOUT);
1472+
ret = dns_get_addr_info(host, qtype, NULL, dns_result_cb,
1473+
(void *)shell, DNS_TIMEOUT);
14871474
if (ret < 0) {
14881475
PR_WARNING("Cannot resolve '%s' (%d)\n", host, ret);
14891476
} else {

0 commit comments

Comments
 (0)