Skip to content

Commit 422fdf4

Browse files
petrosyan-vancfriedt
authored andcommitted
samples: modem_cellular: add auto-APN detection and race-free DNS wait
This update makes the cellular-modem sample usable out-of-the-box on SIMs that require different APNs, without rebuilding the firmware. * Automatic APN selection * New Kconfig options * `CONFIG_SAMPLE_CELLULAR_MODEM_AUTO_APN` - enable logic * `CONFIG_SAMPLE_CELLULAR_APN_X` - APN for profile X * `CONFIG_SAMPLE_CELLULAR_IMSI_LIST_X` - IMSI list for profile X * The application now subscribes to the new `CELLULAR_EVENT_MODEM_INFO_CHANGED` event, waits for the IMSI, looks up the matching MCC+MNC and calls `cellular_set_apn()`. * DNS-server detection * `NET_EVENT_DNS_SERVER_ADD` may fire together with `NET_EVENT_L4_CONNECTED`; the previous wait timed out. * Replaced the two consecutive waits with a single call that waits for both events (`DNS_SERVER_ADD | L4_CONNECTED`) in any order. Signed-off-by: Van Petrosyan <[email protected]>
1 parent 17b5795 commit 422fdf4

File tree

3 files changed

+193
-11
lines changed

3 files changed

+193
-11
lines changed

samples/net/cellular_modem/Kconfig

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,52 @@ config SAMPLE_CELLULAR_MODEM_ENDPOINT_HOSTNAME
99
string "Endpoint hostname"
1010
default "test-endpoint.com"
1111

12+
config SAMPLE_CELLULAR_MODEM_AUTO_APN
13+
bool "Autodetect APN from SIM IMSI"
14+
help
15+
If enabled, the sample derives the APN from the SIM’s MCC + MNC.
16+
17+
menu "APN profiles for the application"
18+
depends on SAMPLE_CELLULAR_MODEM_AUTO_APN
19+
20+
config SAMPLE_CELLULAR_APN_0
21+
string "APN for profile #0"
22+
default ""
23+
help
24+
Leave empty to disable the profile.
25+
26+
config SAMPLE_CELLULAR_IMSI_LIST_0
27+
string "IMSI prefix list for profile #0"
28+
default ""
29+
help
30+
Space separated list of 5- or 6-digit MCC+MNC codes
31+
that should use the APN above.
32+
Example: 22801 22802 90143
33+
34+
config SAMPLE_CELLULAR_APN_1
35+
string "APN for profile #1"
36+
default ""
37+
38+
config SAMPLE_CELLULAR_IMSI_LIST_1
39+
string "IMSI prefix list for profile #1"
40+
default ""
41+
42+
config SAMPLE_CELLULAR_APN_2
43+
string "APN for profile #2"
44+
default ""
45+
46+
config SAMPLE_CELLULAR_IMSI_LIST_2
47+
string "IMSI prefix list for profile #2"
48+
default ""
49+
50+
config SAMPLE_CELLULAR_APN_3
51+
string "APN for profile #3"
52+
default ""
53+
54+
config SAMPLE_CELLULAR_IMSI_LIST_3
55+
string "IMSI prefix list for profile #3"
56+
default ""
57+
58+
endmenu
59+
1260
source "Kconfig.zephyr"

samples/net/cellular_modem/prj.conf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ CONFIG_MODEM=y
2525
CONFIG_PM_DEVICE=y
2626
CONFIG_MODEM_CELLULAR=y
2727

28+
# Dynamic APN configuration (uncomment if not needed)
29+
#CONFIG_MODEM_CELLULAR_APN="" # Remove default APN
30+
#CONFIG_SAMPLE_CELLULAR_MODEM_AUTO_APN=y
31+
#CONFIG_SAMPLE_CELLULAR_APN_0="shared.m2m.ch"
32+
#CONFIG_SAMPLE_CELLULAR_IMSI_LIST_0="22801"
33+
#CONFIG_SAMPLE_CELLULAR_APN_1="em"
34+
#CONFIG_SAMPLE_CELLULAR_IMSI_LIST_1="29505 90143 29509"
35+
2836
# Statistics
2937
CONFIG_MODEM_STATS=y
3038
CONFIG_SHELL=y

samples/net/cellular_modem/src/main.c

Lines changed: 137 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,135 @@ static void print_cellular_info(void)
8888
}
8989
}
9090

91+
#ifdef CONFIG_SAMPLE_CELLULAR_MODEM_AUTO_APN
92+
93+
struct apn_profile {
94+
const char *apn;
95+
const char *imsi_list;
96+
};
97+
98+
/* Build the static table */
99+
static const struct apn_profile apn_profiles[] = {
100+
{ CONFIG_SAMPLE_CELLULAR_APN_0, CONFIG_SAMPLE_CELLULAR_IMSI_LIST_0 },
101+
{ CONFIG_SAMPLE_CELLULAR_APN_1, CONFIG_SAMPLE_CELLULAR_IMSI_LIST_1 },
102+
{ CONFIG_SAMPLE_CELLULAR_APN_2, CONFIG_SAMPLE_CELLULAR_IMSI_LIST_2 },
103+
{ CONFIG_SAMPLE_CELLULAR_APN_3, CONFIG_SAMPLE_CELLULAR_IMSI_LIST_3 },
104+
};
105+
106+
107+
/* Helper function to skip whitespace */
108+
static const char *skip_whitespace(const char *ptr)
109+
{
110+
while (*ptr == ' ' || *ptr == '\t') {
111+
++ptr;
112+
}
113+
return ptr;
114+
}
115+
116+
/* Helper function to find the end of current profile entry */
117+
static bool list_matches_imsi(const char *list, const char *imsi)
118+
{
119+
for (const char *p = list; *p; ) {
120+
p = skip_whitespace(p);
121+
if (!*p) {
122+
break;
123+
}
124+
125+
/* copy one token from the list */
126+
char tok[7];
127+
size_t len = 0;
128+
129+
while (*p && *p != ' ' && *p != '\t' && *p != ',' && len < sizeof(tok) - 1) {
130+
tok[len++] = *p++;
131+
}
132+
tok[len] = '\0';
133+
134+
if (len >= 5 && len <= 6 && !strncmp(imsi, tok, len)) {
135+
return true; /* prefix matches */
136+
}
137+
}
138+
return false;
139+
}
140+
141+
static int modem_cellular_find_apn(char *dst, size_t dst_sz, const char *key)
142+
{
143+
for (size_t i = 0; i < ARRAY_SIZE(apn_profiles); i++) {
144+
const struct apn_profile *p = &apn_profiles[i];
145+
146+
if (p->apn[0] == '\0') {
147+
continue;
148+
}
149+
150+
if (p->apn[0] && list_matches_imsi(p->imsi_list, key)) {
151+
strncpy(dst, p->apn, dst_sz - 1);
152+
dst[dst_sz - 1] = '\0';
153+
return 0;
154+
}
155+
}
156+
157+
return -ENOENT;
158+
}
159+
160+
static void modem_event_cb(const struct device *dev, enum cellular_event evt, const void *payload,
161+
void *user_data)
162+
{
163+
ARG_UNUSED(user_data);
164+
165+
if (evt != CELLULAR_EVENT_MODEM_INFO_CHANGED) {
166+
return;
167+
}
168+
169+
const struct cellular_evt_modem_info *mi = payload;
170+
171+
if (!mi || mi->field != CELLULAR_MODEM_INFO_SIM_IMSI) {
172+
return; /* not the IMSI notification */
173+
}
174+
175+
char imsi[32] = {0};
176+
177+
if (cellular_get_modem_info(dev, CELLULAR_MODEM_INFO_SIM_IMSI, imsi, sizeof(imsi)) != 0) {
178+
return;
179+
}
180+
181+
/* Buffer for the APN we may discover */
182+
char apn[32] = {0};
183+
184+
/* Try MCC+MNC with 6 digits first, then 5 digits */
185+
for (size_t len = 6; len >= 5; len--) {
186+
if (strlen(imsi) < len) {
187+
continue;
188+
}
189+
190+
char key[7] = {0};
191+
192+
memcpy(key, imsi, len);
193+
194+
if (modem_cellular_find_apn(apn, sizeof(apn), key) == 0) {
195+
int rc = cellular_set_apn(dev, apn);
196+
197+
switch (rc) {
198+
case 0:
199+
printk("Auto-selected APN: %s\n", apn);
200+
break;
201+
case -EALREADY:
202+
printk("APN %s already active\n", apn);
203+
break;
204+
case -EBUSY:
205+
printk("Driver busy, cannot change APN now\n");
206+
break;
207+
default:
208+
printk("Driver rejected APN %s (err %d)\n", apn, rc);
209+
break;
210+
}
211+
return;
212+
}
213+
}
214+
215+
printk("No APN profile matches IMSI %s - waiting for manual APN\n", imsi);
216+
}
217+
218+
#endif
219+
91220
static void sample_dns_request_result(enum dns_resolve_status status, struct dns_addrinfo *info,
92221
void *user_data)
93222
{
@@ -283,6 +412,11 @@ int main(void)
283412
uint16_t *port;
284413
int ret;
285414

415+
#ifdef CONFIG_SAMPLE_CELLULAR_MODEM_AUTO_APN
416+
/* subscribe before powering the modem so we catch the IMSI event */
417+
cellular_set_callback(modem, CELLULAR_EVENT_MODEM_INFO_CHANGED, modem_event_cb, NULL);
418+
#endif
419+
286420
init_sample_test_packet();
287421

288422
printk("Powering on modem\n");
@@ -295,23 +429,15 @@ int main(void)
295429
return -1;
296430
}
297431

298-
printk("Waiting for L4 connected\n");
299-
ret = net_mgmt_event_wait_on_iface(iface, NET_EVENT_L4_CONNECTED, NULL, NULL, NULL,
300-
K_SECONDS(120));
432+
printk("Waiting for L4 connected & DNS server added\n");
433+
ret = net_mgmt_event_wait_on_iface(iface, NET_EVENT_L4_CONNECTED | NET_EVENT_DNS_SERVER_ADD,
434+
NULL, NULL, NULL, K_SECONDS(120));
301435

302436
if (ret != 0) {
303437
printk("L4 was not connected in time\n");
304438
return -1;
305439
}
306440

307-
printk("Waiting for DNS server added\n");
308-
ret = net_mgmt_event_wait_on_iface(iface, NET_EVENT_DNS_SERVER_ADD, NULL, NULL, NULL,
309-
K_SECONDS(10));
310-
if (ret) {
311-
printk("DNS server was not added in time\n");
312-
return -1;
313-
}
314-
315441
printk("Retrieving cellular info\n");
316442
print_cellular_info();
317443

0 commit comments

Comments
 (0)