Skip to content

Commit

Permalink
pdn: make pdp_context_dynamic_params_get common
Browse files Browse the repository at this point in the history
- convert
link_api_pdp_context_dynamic_params_get
to
pdn_pdp_context_dynamic_params_get
and use it on both SLM and MOSH

Signed-off-by: Oguzhan Turk <stkyoht@hotmail.com>
  • Loading branch information
TaeZStkyoht committed Jan 3, 2025
1 parent d1fa9c0 commit 73ee8bd
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 306 deletions.
19 changes: 8 additions & 11 deletions applications/serial_lte_modem/src/slm_ppp.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,19 +210,16 @@ static int ppp_start_internal(void)
return -EADDRNOTAVAIL;
}

ret = pdn_dynamic_params_get(PDP_CID, &ctx->ipcp.my_options.dns1_address,
&ctx->ipcp.my_options.dns2_address, &mtu);
if (ret) {
/* If any error happened on pdn getting with IPv4, try to parse with IPv6 */
ret = pdn_dynamic_params_get_v6(PDP_CID, NULL, NULL, &mtu);
if (ret && ret != -EBADMSG) {
return ret;
}
}
struct pdp_context_info populated_info = {};
populated_info.cid = PDP_CID;

Check warning on line 214 in applications/serial_lte_modem/src/slm_ppp.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

LINE_SPACING

applications/serial_lte_modem/src/slm_ppp.c:214 Missing a blank line after declarations
ret = pdn_pdp_context_dynamic_params_get(&populated_info);

if (mtu) {
if (populated_info.ipv4_mtu) {
/* Set the PPP MTU to that of the LTE link. */
mtu = MIN(populated_info.ipv4_mtu, sizeof(ppp_data_buf));
} else if (populated_info.ipv6_mtu) {
/* Set the PPP MTU to that of the LTE link. */
mtu = MIN(mtu, sizeof(ppp_data_buf));
mtu = MIN(populated_info.ipv6_mtu, sizeof(ppp_data_buf));
} else {
LOG_DBG("Could not retrieve MTU, using fallback value.");
mtu = CONFIG_SLM_PPP_FALLBACK_MTU;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,9 @@ Modem libraries
* :ref:`pdn_readme` library:

* Added the :c:func:`pdn_dynamic_params_get_v6` function to get PDN parameters for IPv6-only.
* Changed logic DNS record expectation. Because ISP sends sometimes 1 and even 0.
* Changed logic DNS record expectation, because ISP sometimes sends 1 and even 0.
* Remove :c:func:`pdn_dynamic_params_get` and :c:func:`pdn_dynamic_params_get_v6`
* move :c:func:`link_api_pdp_context_dynamic_params_get` to common place as :c:func:`pdn_pdp_context_dynamic_params_get`

* :ref:`lte_lc_readme` library:

Expand Down
43 changes: 23 additions & 20 deletions include/modem/pdn.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
extern "C" {
#endif

#define AT_CMD_PDP_CONTEXT_READ_PDP_TYPE_STR_MAX_LEN (6 + 1)
#define APN_STR_MAX_LEN 64

/**
* @file pdn.h
* @brief Public APIs for the PDN library.
Expand Down Expand Up @@ -54,6 +57,24 @@ struct pdn_pdp_opt {
uint8_t secure_pco;
};

struct pdp_context_info {
uint32_t cid;
uint32_t ipv4_mtu;
uint32_t ipv6_mtu;
uint32_t pdn_id;
bool pdn_id_valid;
bool ctx_active;
char pdp_type_str[AT_CMD_PDP_CONTEXT_READ_PDP_TYPE_STR_MAX_LEN];
char apn_str[APN_STR_MAX_LEN];
char pdp_type;
struct in_addr ip_addr4;
struct in6_addr ip_addr6;
struct in_addr dns_addr4_primary;
struct in_addr dns_addr4_secondary;
struct in6_addr dns_addr6_primary;
struct in6_addr dns_addr6_secondary;
};

/** @brief PDN library event */
enum pdn_event {
/** +CNEC ESM error code */
Expand Down Expand Up @@ -183,29 +204,11 @@ int pdn_id_get(uint8_t cid);
/**
* @brief Retrieve dynamic parameters of a given PDP context.
*
* @param cid The PDP context ID.
* @param[out] dns4_pri The address of the primary IPv4 DNS server. Optional, can be NULL.
* @param[out] dns4_sec The address of the secondary IPv4 DNS server. Optional, can be NULL.
* @param[out] ipv4_mtu The IPv4 MTU. Optional, can be NULL.
* @param[inout] populated_info PDP context info.
*
* @return Zero on success or an error code on failure.
*/
int pdn_dynamic_params_get(uint8_t cid, struct in_addr *dns4_pri,
struct in_addr *dns4_sec, unsigned int *ipv4_mtu);

/**
* @brief Retrieve dynamic parameters of a given PDP context.
*
* @param cid The PDP context ID.
* @param[out] dns6_pri The address of the primary IPv6 DNS server. Optional, can be NULL.
* @param[out] dns6_sec The address of the secondary IPv6 DNS server. Optional, can be NULL.
* @param[out] ipv6_mtu The IPv6 MTU. Optional, can be NULL.
*
* @return Zero on success or an error code on failure.
*/
int pdn_dynamic_params_get_v6(uint8_t cid, struct in6_addr *dns6_pri,
struct in6_addr *dns6_sec, unsigned int *ipv6_mtu);

int pdn_pdp_context_dynamic_params_get(struct pdp_context_info *populated_info);
/**
* @brief Retrieve the default Access Point Name (APN).
*
Expand Down
251 changes: 144 additions & 107 deletions lib/pdn/pdn.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,20 @@ LOG_MODULE_REGISTER(pdn, CONFIG_PDN_LOG_LEVEL);
#define PDN_ACT_REASON_IPV4_ONLY (0)
#define PDN_ACT_REASON_IPV6_ONLY (1)

#define APN_STR_MAX_LEN 64

#define MODEM_CFUN_POWER_OFF 0
#define MODEM_CFUN_NORMAL 1
#define MODEM_CFUN_ACTIVATE_LTE 21

#define AT_CMD_PDP_CONTEXT_READ_IP_ADDR_STR_MAX_LEN (255)

#define AT_CMD_PDP_CONTEXT_READ_INFO \
"AT+CGCONTRDP=%d" /* Use sprintf to add CID into command */
#define AT_CMD_PDP_CONTEXT_READ_INFO_DNS_ADDR_PRIMARY_INDEX 6
#define AT_CMD_PDP_CONTEXT_READ_INFO_DNS_ADDR_SECONDARY_INDEX 7
#define AT_CMD_PDP_CONTEXT_READ_INFO_MTU_INDEX 12

#define AT_CMD_PDP_CONTEXT_READ_RSP_DELIM "\r\n"

static K_MUTEX_DEFINE(list_mutex);

static sys_slist_t pdn_contexts = SYS_SLIST_STATIC_INIT(&pdn_context);
Expand Down Expand Up @@ -614,124 +622,153 @@ int pdn_id_get(uint8_t cid)
return strtoul(p + 1, NULL, 10);
}

int pdn_dynamic_params_get(uint8_t cid, struct in_addr *dns4_pri,
struct in_addr *dns4_sec, unsigned int *ipv4_mtu)
static int pdn_sa_family_from_ip_string(const char *src)
{
int matched;
const char *fmt;
unsigned int mtu;
char dns4_pri_str[INET_ADDRSTRLEN];
char dns4_sec_str[INET_ADDRSTRLEN];
char at_cmd[sizeof("AT+CGCONTRDP=10")];

/* Initialize out variables with default */
if (dns4_pri) {
memset(dns4_pri, 0, sizeof(struct in_addr));
}
if (dns4_sec) {
memset(dns4_sec, 0, sizeof(struct in_addr));
}
if (ipv4_mtu) {
*ipv4_mtu = 0;
}

if (snprintf(at_cmd, sizeof(at_cmd), "AT+CGCONTRDP=%u", cid) >= sizeof(at_cmd)) {
return -E2BIG;
}
/* "+CGCONTRDP: 0,,"example.com","","","198.276.154.230","12.34.56.78",,,,,1464" */
fmt = "+CGCONTRDP: %*u,,\"%*[^\"]\",\"\",\"\",\"%15[0-9.]\",\"%15[0-9.]\",,,,,%u";
char buf[INET6_ADDRSTRLEN];

/* If IPv4 is enabled, it will be the first response line. */
matched = nrf_modem_at_scanf(at_cmd, fmt, &dns4_pri_str, &dns4_sec_str, &mtu);

if (matched < 1) {
return -EBADMSG;
}

if (dns4_pri) {
if (zsock_inet_pton(AF_INET, dns4_pri_str, dns4_pri) != 1) {
return -EADDRNOTAVAIL;
}
}
if (dns4_sec) {
if (matched >= 2) {
if (zsock_inet_pton(AF_INET, dns4_sec_str, dns4_sec) != 1) {
return -EADDRNOTAVAIL;
}
}
}
if (ipv4_mtu) {
/* If we matched the MTU, copy it here, otherwise report zero */
if (matched == 3) {
*ipv4_mtu = mtu;
} else {
*ipv4_mtu = 0;
}
if (inet_pton(AF_INET, src, buf)) {
return AF_INET;
} else if (inet_pton(AF_INET6, src, buf)) {
return AF_INET6;
}

return 0;
return -1;
}

int pdn_dynamic_params_get_v6(uint8_t cid, struct in6_addr *dns6_pri,
struct in6_addr *dns6_sec, unsigned int *ipv6_mtu)
int pdn_pdp_context_dynamic_params_get(struct pdp_context_info *populated_info)
{
int matched;
const char *fmt;
unsigned int mtu;
char dns6_pri_str[INET6_ADDRSTRLEN];
char dns6_sec_str[INET6_ADDRSTRLEN];
char at_cmd[sizeof("AT+CGCONTRDP=10")];

/* Initialize out variables with default */
if (dns6_pri) {
memset(dns6_pri, 0, sizeof(struct in6_addr));
}
if (dns6_sec) {
memset(dns6_sec, 0, sizeof(struct in6_addr));
}
if (ipv6_mtu) {
*ipv6_mtu = 0;
}

if (snprintf(at_cmd, sizeof(at_cmd), "AT+CGCONTRDP=%u", cid) >= sizeof(at_cmd)) {
return -E2BIG;
}
/* "+CGCONTRDP: 0,,"ims","","",
* "0000:0000:0000:0000:0000:0000:0000:0000",
* "0000:0000:0000:0000:0000:0000:0000:0000",,,,,1500"
int ret = 0;
struct at_parser parser;
size_t param_str_len;

char cgcontrdp_at_rsp_buf[512];

char *at_ptr;
char *tmp_ptr;
int lines = 0;
int iterator = 0;
char dns_addr_str[AT_CMD_PDP_CONTEXT_READ_IP_ADDR_STR_MAX_LEN];

char at_cmd_pdp_context_read_info_cmd_str[15];

int family;
struct in_addr *addr;
struct in6_addr *addr6;

if (!populated_info) {
goto clean_exit;
}

at_ptr = cgcontrdp_at_rsp_buf;
tmp_ptr = cgcontrdp_at_rsp_buf;

sprintf(at_cmd_pdp_context_read_info_cmd_str,
AT_CMD_PDP_CONTEXT_READ_INFO, populated_info->cid);
ret = nrf_modem_at_cmd(cgcontrdp_at_rsp_buf, sizeof(cgcontrdp_at_rsp_buf), "%s",
at_cmd_pdp_context_read_info_cmd_str);
if (ret) {
LOG_ERR(
"nrf_modem_at_cmd returned err: %d for %s",
ret,
at_cmd_pdp_context_read_info_cmd_str);
return ret;
}

/* Check how many rows of info do we have */
while (strncmp(tmp_ptr, "OK", 2) &&
(tmp_ptr = strstr(tmp_ptr, AT_CMD_PDP_CONTEXT_READ_RSP_DELIM)) != NULL) {
tmp_ptr += 2;
lines++;
}

/* Parse the response */
ret = at_parser_init(&parser, at_ptr);
if (ret) {
LOG_ERR("Could not init AT parser for %s, error: %d\n",
at_cmd_pdp_context_read_info_cmd_str, ret);
return ret;
}

parse:
/* Read primary DNS address */
param_str_len = sizeof(dns_addr_str);
ret = at_parser_string_get(
&parser,
AT_CMD_PDP_CONTEXT_READ_INFO_DNS_ADDR_PRIMARY_INDEX,
dns_addr_str, &param_str_len);
if (ret) {
LOG_ERR(
"Could not parse dns str for cid %d, err: %d",
populated_info->cid, ret);
goto clean_exit;
}
dns_addr_str[param_str_len] = '\0';

family = pdn_sa_family_from_ip_string(dns_addr_str);

if (family == AF_INET) {
addr = &(populated_info->dns_addr4_primary);
(void)inet_pton(AF_INET, dns_addr_str, addr);
} else if (family == AF_INET6) {
addr6 = &(populated_info->dns_addr6_primary);
(void)inet_pton(AF_INET6, dns_addr_str, addr6);
}

/* Read secondary DNS address */
param_str_len = sizeof(dns_addr_str);

ret = at_parser_string_get(
&parser,
AT_CMD_PDP_CONTEXT_READ_INFO_DNS_ADDR_SECONDARY_INDEX,
dns_addr_str, &param_str_len);
if (ret) {
LOG_ERR("Could not parse dns str, err: %d", ret);
goto clean_exit;
}
dns_addr_str[param_str_len] = '\0';

family = pdn_sa_family_from_ip_string(dns_addr_str);

if (family == AF_INET) {
addr = &(populated_info->dns_addr4_secondary);
(void)inet_pton(AF_INET, dns_addr_str, addr);
} else if (family == AF_INET6) {
addr6 = &(populated_info->dns_addr6_secondary);
(void)inet_pton(AF_INET6, dns_addr_str, addr6);
}

/* Read link MTU if exists:
* AT command spec:
* Note: If the PDN connection has dual stack capabilities, at least one pair of
* lines with information is returned per <cid>: First one line with the IPv4
* parameters followed by one line with the IPv6 parameters.
*/
fmt = "+CGCONTRDP: %*u,,\"%*[^\"]\",\"\",\"\","
"\"%45[0-9A-Fa-f:]\",\"%45[0-9A-Fa-f:]\",,,,,%u";

/* If IPv6 is enabled, it will be the first response line. */
matched = nrf_modem_at_scanf(at_cmd, fmt, &dns6_pri_str, &dns6_sec_str, &mtu);

if (matched < 1) {
return -EBADMSG;
}

if (dns6_pri) {
if (zsock_inet_pton(AF_INET6, dns6_pri_str, dns6_pri) != 1) {
return -EADDRNOTAVAIL;
if (iterator == 1) {
ret = at_parser_num_get(&parser, AT_CMD_PDP_CONTEXT_READ_INFO_MTU_INDEX,
&(populated_info->ipv6_mtu));
if (ret) {
/* Don't care if it fails */
ret = 0;
populated_info->ipv6_mtu = 0;
}
}
if (dns6_sec) {
if (matched >= 2) {
if (zsock_inet_pton(AF_INET6, dns6_sec_str, dns6_sec) != 1) {
return -EADDRNOTAVAIL;
}
} else {
ret = at_parser_num_get(&parser, AT_CMD_PDP_CONTEXT_READ_INFO_MTU_INDEX,
&(populated_info->ipv4_mtu));
if (ret) {
/* Don't care if it fails */
ret = 0;
populated_info->ipv4_mtu = 0;
}
}
if (ipv6_mtu) {
/* If we matched the MTU, copy it here, otherwise report zero */
if (matched == 3) {
*ipv6_mtu = mtu;
} else {
*ipv6_mtu = 0;

if (at_parser_cmd_next(&parser) == 0) {
iterator++;
if (iterator < lines) {
goto parse;
}
}

return 0;
clean_exit:
return ret;
}

int pdn_default_apn_get(char *buf, size_t len)
Expand Down
Loading

0 comments on commit 73ee8bd

Please sign in to comment.