Skip to content

Commit

Permalink
pdn: make pdp_context_dynamic_params_get common
Browse files Browse the repository at this point in the history
- We shouldn't expect 2 DNS records from ISP.
Because it sends sometimes 1 and even 0.
It must try to continue like in MOSH.
- 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 <[email protected]>
Co-authored-by: Eivind Jølsgard <[email protected]>
Co-authored-by: Pekka Niskanen <[email protected]>
Co-authored-by: Tommi Kangas <[email protected]>
Co-authored-by: Tommi Rantanen <[email protected]>
  • Loading branch information
5 people committed Jan 9, 2025
1 parent 852ae66 commit 5af606c
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 205 deletions.
55 changes: 33 additions & 22 deletions applications/serial_lte_modem/src/slm_ppp.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,37 +200,48 @@ static int ppp_start_failure(int ret)
return ret;
}

static unsigned int ppp_retrieve_mtu(void)
{
struct pdn_dynamic_info populated_info = { 0 };

if (!pdn_dynamic_info_get(PDP_CID, &populated_info)) {
if (populated_info.ipv6_mtu) {
/* Set the PPP MTU to that of the LTE link. */
/* IPv6's MTU has more priority on dual-stack.
* Because, it must be at least 1280 for IPv6,
* while MTU of IPv4 may be less.
*/
return MIN(populated_info.ipv6_mtu, sizeof(ppp_data_buf));
}
if (populated_info.ipv4_mtu) {
/* Set the PPP MTU to that of the LTE link. */
return MIN(populated_info.ipv4_mtu, sizeof(ppp_data_buf));
}
}

LOG_DBG("Could not retrieve MTU, using fallback value.");
BUILD_ASSERT(sizeof(ppp_data_buf) >= CONFIG_SLM_PPP_FALLBACK_MTU);
return CONFIG_SLM_PPP_FALLBACK_MTU;
}

static void ppp_set_mtu(void)
{
const unsigned int mtu = ppp_retrieve_mtu();

net_if_set_mtu(ppp_iface, mtu);
LOG_DBG("MTU set to %u.", mtu);
}

static int ppp_start_internal(void)
{
int ret;
unsigned int mtu;
struct ppp_context *const ctx = net_if_l2_data(ppp_iface);

if (!configure_ppp_link_ip_addresses(ctx)) {
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) {
return ret;
}
}

if (mtu) {
/* Set the PPP MTU to that of the LTE link. */
mtu = MIN(mtu, sizeof(ppp_data_buf));
} else {
LOG_DBG("Could not retrieve MTU, using fallback value.");
mtu = CONFIG_SLM_PPP_FALLBACK_MTU;
BUILD_ASSERT(sizeof(ppp_data_buf) >= CONFIG_SLM_PPP_FALLBACK_MTU);
}

net_if_set_mtu(ppp_iface, mtu);
LOG_DBG("MTU set to %u.", mtu);
ppp_set_mtu();

ret = net_if_up(ppp_iface);
if (ret) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,8 @@ Modem libraries

* :ref:`pdn_readme` library:

* Added the :c:func:`pdn_dynamic_params_get_v6` function to get PDN parameters for IPv6-only.
* Deprecated the :c:func:`pdn_dynamic_params_get` function.
Use the new function :c:func:`pdn_dynamic_info_get` instead.

* :ref:`lte_lc_readme` library:

Expand Down
47 changes: 39 additions & 8 deletions include/modem/pdn.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,38 @@ struct pdn_pdp_opt {
uint8_t secure_pco;
};

/**
* @brief PDN context dynamic information structure.
*
* This structure holds dynamic information about the PDN context.
*/
struct pdn_dynamic_info {
/**
* @brief IPv4 Maximum Transmission Unit.
*/
uint32_t ipv4_mtu;
/**
* @brief IPv6 Maximum Transmission Unit.
*/
uint32_t ipv6_mtu;
/**
* @brief Primary IPv4 DNS address.
*/
struct in_addr dns_addr4_primary;
/**
* @brief Secondary IPv4 DNS address.
*/
struct in_addr dns_addr4_secondary;
/**
* @brief Primary IPv6 DNS address.
*/
struct in6_addr dns_addr6_primary;
/**
* @brief Secondary IPv6 DNS address.
*/
struct in6_addr dns_addr6_secondary;
};

/** @brief PDN library event */
enum pdn_event {
/** +CNEC ESM error code */
Expand Down Expand Up @@ -183,28 +215,27 @@ int pdn_id_get(uint8_t cid);
/**
* @brief Retrieve dynamic parameters of a given PDP context.
*
* @deprecated Use pdn_dynamic_info_get instead.
*
* @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.
*
* @return Zero on success or an error code on failure.
*/
int pdn_dynamic_params_get(uint8_t cid, struct in_addr *dns4_pri,
__deprecated 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.
* @brief Retrieve dynamic parameters of a given PDN 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.
* @param[in] cid The PDN context ID.
* @param[out] pdn_info PDN dynamic info.
*
* @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_dynamic_info_get(uint32_t cid, struct pdn_dynamic_info *pdn_info);

/**
* @brief Retrieve the default Access Point Name (APN).
Expand Down
178 changes: 143 additions & 35 deletions lib/pdn/pdn.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
#include <zephyr/net/socket.h>
#include <zephyr/sys/slist.h>
#include <zephyr/logging/log.h>
#include <zephyr/posix/arpa/inet.h>
#include <nrf_modem_at.h>
#include <modem/pdn.h>
#include <modem/at_monitor.h>
#include <modem/at_parser.h>
#include <modem/nrf_modem_lib.h>

LOG_MODULE_REGISTER(pdn, CONFIG_PDN_LOG_LEVEL);
Expand All @@ -34,6 +36,15 @@ LOG_MODULE_REGISTER(pdn, CONFIG_PDN_LOG_LEVEL);
#define MODEM_CFUN_NORMAL 1
#define MODEM_CFUN_ACTIVATE_LTE 21

#define AT_CMD_PDN_CONTEXT_READ_IP_ADDR_STR_MAX_LEN (255)

#define AT_CMD_PDN_CONTEXT_READ_INFO "AT+CGCONTRDP=%d"
#define AT_CMD_PDN_CONTEXT_READ_INFO_DNS_ADDR_PRIMARY_INDEX 6
#define AT_CMD_PDN_CONTEXT_READ_INFO_DNS_ADDR_SECONDARY_INDEX 7
#define AT_CMD_PDN_CONTEXT_READ_INFO_MTU_INDEX 12

#define AT_CMD_PDN_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 @@ -659,53 +670,150 @@ int pdn_dynamic_params_get(uint8_t cid, struct in_addr *dns4_pri,
return 0;
}

int pdn_dynamic_params_get_v6(uint8_t cid, struct in6_addr *dns6_pri,
struct in6_addr *dns6_sec, unsigned int *ipv6_mtu)
static int pdn_sa_family_from_ip_string(const char *src)
{
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")];
char buf[INET6_ADDRSTRLEN];

if (snprintf(at_cmd, sizeof(at_cmd), "AT+CGCONTRDP=%u", cid) >= sizeof(at_cmd)) {
return -E2BIG;
if (inet_pton(AF_INET, src, buf)) {
return AF_INET;
} else if (inet_pton(AF_INET6, src, buf)) {
return AF_INET6;
}
/* "+CGCONTRDP: 0,,"ims","","",
* "0000:0000:0000:0000:0000:0000:0000:0000",
* "0000:0000:0000:0000:0000:0000:0000:0000",,,,,1500"
*/
fmt = "+CGCONTRDP: %*u,,\"%*[^\"]\",\"\",\"\","
"\"%45[0-9A-Fa-f:]\",\"%45[0-9A-Fa-f:]\",,,,,%u";
return -1;
}

/* 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);
/* Need to match at least the two IP addresses, or there is an error */
if (matched < 2) {
return -EBADMSG;
int pdn_dynamic_info_get(uint32_t cid, struct pdn_dynamic_info *pdn_info)
{
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_PDN_CONTEXT_READ_IP_ADDR_STR_MAX_LEN];

char at_cmd_pdn_context_read_info_cmd_str[15];

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

if (!pdn_info) {
return -EINVAL;
}

if (dns6_pri) {
if (zsock_inet_pton(AF_INET6, dns6_pri_str, dns6_pri) != 1) {
return -EADDRNOTAVAIL;
}
at_ptr = cgcontrdp_at_rsp_buf;
tmp_ptr = cgcontrdp_at_rsp_buf;

sprintf(at_cmd_pdn_context_read_info_cmd_str, AT_CMD_PDN_CONTEXT_READ_INFO, cid);
ret = nrf_modem_at_cmd(cgcontrdp_at_rsp_buf, sizeof(cgcontrdp_at_rsp_buf), "%s",
at_cmd_pdn_context_read_info_cmd_str);
if (ret) {
LOG_ERR(
"nrf_modem_at_cmd returned err: %d for %s",
ret,
at_cmd_pdn_context_read_info_cmd_str);
return ret;
}
if (dns6_sec) {
if (zsock_inet_pton(AF_INET6, dns6_sec_str, dns6_sec) != 1) {
return -EADDRNOTAVAIL;

/* Check how many rows of info do we have */
while (strncmp(tmp_ptr, "OK", 2) &&
(tmp_ptr = strstr(tmp_ptr, AT_CMD_PDN_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_pdn_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_PDN_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", 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 = &(pdn_info->dns_addr4_primary);
(void)inet_pton(AF_INET, dns_addr_str, addr);
} else if (family == AF_INET6) {
addr6 = &(pdn_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_PDN_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 = &(pdn_info->dns_addr4_secondary);
(void)inet_pton(AF_INET, dns_addr_str, addr);
} else if (family == AF_INET6) {
addr6 = &(pdn_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.
*/
if (iterator == 1) {
ret = at_parser_num_get(&parser, AT_CMD_PDN_CONTEXT_READ_INFO_MTU_INDEX,
&(pdn_info->ipv6_mtu));
if (ret) {
/* Don't care if it fails */
ret = 0;
pdn_info->ipv6_mtu = 0;
}
} else {
ret = at_parser_num_get(&parser, AT_CMD_PDN_CONTEXT_READ_INFO_MTU_INDEX,
&(pdn_info->ipv4_mtu));
if (ret) {
/* Don't care if it fails */
ret = 0;
pdn_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 5af606c

Please sign in to comment.