drivers: modem: ublox-sara-r4: automatic setting of APN

During communication initialisation, the IMSI of the inserted SIM
card is evaluated to determine the APN. This is done by comparing
the first 5 characters of the IMSI to a list of known providers.
The list can be given in Kconfig.

To enable this functionality, set following bool in Kconfig:
MODEM_UBLOX_SARA_AUTODETECT_APN

To set a list of providers, set following string:
MODEM_UBLOX_SARA_AUTODETECT_APN_PROFILES

If the provider can not be found in the list, the APN given in
following entry is used as a fallback:
MODEM_UBLOX_SARA_R4_APN

Signed-off-by: Hans Wilmers <hans@wilmers.no>
This commit is contained in:
Hans Wilmers 2020-04-23 14:07:55 +02:00 committed by Kumar Gala
commit fdd89efd3a
2 changed files with 170 additions and 0 deletions

View file

@ -65,6 +65,19 @@ config MODEM_UBLOX_SARA_R4_APN
for the network connection context. This value is specific to
the network provider and may need to be changed.
config MODEM_UBLOX_SARA_AUTODETECT_APN
bool "detect APN automatically"
help
Enable automatic detection of the APN, based on the IMSI
If the detection fails, the configured APN will be used
config MODEM_UBLOX_SARA_AUTODETECT_APN_PROFILES
string "list of profiles to search when autodetecting APN"
default "hologram=23450, wm=20601 29505 29509 23450 53703 90143"
help
Set a comma separated list of profiles, each containing of:
<apn>=<IMSI_1> ... <IMSI_n>
config MODEM_UBLOX_SARA_R4_MANUAL_MCCMNO
string "MCC/MNOfor establishing network connection"
help

View file

@ -21,6 +21,10 @@ LOG_MODULE_REGISTER(modem_ublox_sara_r4, CONFIG_MODEM_LOG_LEVEL);
#include <net/net_offload.h>
#include <net/socket_offload.h>
#if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
#include <stdio.h>
#endif
#include "modem_context.h"
#include "modem_socket.h"
#include "modem_cmd_handler.h"
@ -89,6 +93,8 @@ static struct modem_pin modem_pins[] = {
#define MDM_MODEL_LENGTH 16
#define MDM_REVISION_LENGTH 64
#define MDM_IMEI_LENGTH 16
#define MDM_IMSI_LENGTH 16
#define MDM_APN_LENGTH 32
#define RSSI_TIMEOUT_SECS 30
@ -145,11 +151,16 @@ struct modem_data {
char mdm_model[MDM_MODEL_LENGTH];
char mdm_revision[MDM_REVISION_LENGTH];
char mdm_imei[MDM_IMEI_LENGTH];
char mdm_imsi[MDM_IMSI_LENGTH];
#if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_VARIANT)
/* modem variant */
int mdm_variant;
#endif
#if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
/* APN */
char mdm_apn[MDM_APN_LENGTH];
#endif
/* modem state */
int ev_creg;
@ -199,6 +210,90 @@ static int modem_atoi(const char *s, const int err_value,
return ret;
}
#if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
/* the list of SIM profiles. Global scope, so the app can change it */
const char *modem_sim_profiles =
CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN_PROFILES;
int find_apn(char *apn, int apnlen, const char *profiles, const char *imsi)
{
int rc = -1;
/* try to find a match */
char *s = strstr(profiles, imsi);
if (s) {
char *eos;
/* find the assignment operator preceding the match */
while (s >= profiles && !strchr("=", *s)) {
s--;
}
/* find the apn preceding the assignment operator */
while (s >= profiles && strchr(" =", *s)) {
s--;
}
/* mark end of apn string */
eos = s+1;
/* find first character of the apn */
while (s >= profiles && !strchr(" ,", *s)) {
s--;
}
s++;
/* copy the key */
if (s >= profiles) {
int len = eos - s;
if (len < apnlen) {
memcpy(apn, s, len);
apn[len] = '\0';
rc = 0;
} else {
LOG_ERR("buffer overflow");
}
}
}
return rc;
}
/* try to detect APN automatically, based on IMSI */
int modem_detect_apn(const char *imsi)
{
int rc = -1;
if (imsi != NULL && strlen(imsi) >= 5) {
/* extract MMC and MNC from IMSI */
char mmcmnc[6];
*mmcmnc = 0;
strncat(mmcmnc, imsi, sizeof(mmcmnc)-1);
/* try to find a matching IMSI, and assign the APN */
rc = find_apn(mdata.mdm_apn,
sizeof(mdata.mdm_apn),
modem_sim_profiles,
mmcmnc);
if (rc < 0) {
rc = find_apn(mdata.mdm_apn,
sizeof(mdata.mdm_apn),
modem_sim_profiles,
"*");
}
}
if (rc == 0) {
LOG_INF("Assign APN: \"%s\"", log_strdup(mdata.mdm_apn));
}
return rc;
}
#endif
/* send binary data via the +USO[ST/WR] commands */
static ssize_t send_socket_data(struct modem_socket *sock,
const struct sockaddr *dst_addr,
@ -380,6 +475,24 @@ MODEM_CMD_DEFINE(on_cmd_atcmdinfo_imei)
return 0;
}
/* Handler: <IMSI> */
MODEM_CMD_DEFINE(on_cmd_atcmdinfo_imsi)
{
size_t out_len;
out_len = net_buf_linearize(mdata.mdm_imsi, sizeof(mdata.mdm_imsi) - 1,
data->rx_buf, 0, len);
mdata.mdm_imsi[out_len] = '\0';
LOG_INF("IMSI: %s", log_strdup(mdata.mdm_imsi));
#if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
/* set the APN automatically */
modem_detect_apn(mdata.mdm_imsi);
#endif
return 0;
}
#if !defined(CONFIG_MODEM_UBLOX_SARA_U2)
/*
* Handler: +CESQ: <rxlev>[0],<ber>[1],<rscp>[2],<ecn0>[3],<rsrq>[4],<rsrp>[5]
@ -802,18 +915,23 @@ static void modem_reset(void)
SETUP_CMD("AT+CGMM", "", on_cmd_atcmdinfo_model, 0U, ""),
SETUP_CMD("AT+CGMR", "", on_cmd_atcmdinfo_revision, 0U, ""),
SETUP_CMD("AT+CGSN", "", on_cmd_atcmdinfo_imei, 0U, ""),
SETUP_CMD("AT+CIMI", "", on_cmd_atcmdinfo_imsi, 0U, ""),
#if !defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
/* setup PDP context definition */
SETUP_CMD_NOHANDLE("AT+CGDCONT=1,\"IP\",\""
CONFIG_MODEM_UBLOX_SARA_R4_APN "\""),
/* start functionality */
SETUP_CMD_NOHANDLE("AT+CFUN=1"),
#endif
};
#if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_VARIANT)
static struct setup_cmd post_setup_cmds_u2[] = {
#if !defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
/* set the APN */
SETUP_CMD_NOHANDLE("AT+UPSD=0,1,\""
CONFIG_MODEM_UBLOX_SARA_R4_APN "\""),
#endif
/* set dynamic IP */
SETUP_CMD_NOHANDLE("AT+UPSD=0,7,\"0.0.0.0\""),
/* activate the GPRS connection */
@ -837,6 +955,14 @@ static void modem_reset(void)
};
restart:
#if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
mdata.mdm_apn[0] = '\0';
strncat(mdata.mdm_apn,
CONFIG_MODEM_UBLOX_SARA_R4_APN,
sizeof(mdata.mdm_apn)-1);
#endif
/* stop RSSI delay work */
k_delayed_work_cancel(&mdata.rssi_query_work);
@ -871,6 +997,25 @@ restart:
goto error;
}
#if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
/* autodetect APN from IMSI */
char cmd[sizeof("AT+CGDCONT=1,\"IP\",\"\"")+MDM_APN_LENGTH];
snprintf(cmd, sizeof(cmd), "AT+CGDCONT=1,\"IP\",\"%s\"", mdata.mdm_apn);
/* setup PDP context definition */
ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
NULL, 0,
(const char *)cmd,
&mdata.sem_response,
MDM_REGISTRATION_TIMEOUT);
ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
NULL, 0,
"AT+CFUN=1",
&mdata.sem_response,
MDM_REGISTRATION_TIMEOUT);
#endif
if (strlen(CONFIG_MODEM_UBLOX_SARA_R4_MANUAL_MCCMNO) > 0) {
/* use manual MCC/MNO entry */
@ -950,6 +1095,18 @@ restart:
#if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_VARIANT)
if (mdata.mdm_variant == MDM_VARIANT_UBLOX_U2) {
#if defined(CONFIG_MODEM_UBLOX_SARA_AUTODETECT_APN)
/* setup PDP context definition */
char cmd[sizeof("AT+UPSD=0,1,\"%s\"")+MDM_APN_LENGTH];
snprintf(cmd, sizeof(cmd), "AT+UPSD=0,1,\"%s\"", mdata.mdm_apn);
ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler,
NULL, 0,
(const char *)cmd,
&mdata.sem_response,
MDM_REGISTRATION_TIMEOUT);
#endif
ret = modem_cmd_handler_setup_cmds(&mctx.iface,
&mctx.cmd_handler,
post_setup_cmds_u2,