diff --git a/applications/serial_lte_modem/src/slm_ppp.c b/applications/serial_lte_modem/src/slm_ppp.c index 8baf6ec950af..0b93df11f12a 100644 --- a/applications/serial_lte_modem/src/slm_ppp.c +++ b/applications/serial_lte_modem/src/slm_ppp.c @@ -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) { diff --git a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst index 828c7d16935c..3f89f4940827 100644 --- a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst +++ b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst @@ -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: diff --git a/include/modem/pdn.h b/include/modem/pdn.h index c3749d95f504..58a382dd4740 100644 --- a/include/modem/pdn.h +++ b/include/modem/pdn.h @@ -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 */ @@ -183,6 +215,8 @@ 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. @@ -190,21 +224,18 @@ int pdn_id_get(uint8_t cid); * * @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). diff --git a/lib/pdn/pdn.c b/lib/pdn/pdn.c index da58c6650150..1311da49df2d 100644 --- a/lib/pdn/pdn.c +++ b/lib/pdn/pdn.c @@ -15,9 +15,11 @@ #include #include #include +#include #include #include #include +#include #include LOG_MODULE_REGISTER(pdn, CONFIG_PDN_LOG_LEVEL); @@ -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); @@ -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, ¶m_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, ¶m_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 : 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) diff --git a/samples/cellular/modem_shell/src/link/link_api.c b/samples/cellular/modem_shell/src/link/link_api.c index 1e26abdc98e6..ac14e8338b19 100644 --- a/samples/cellular/modem_shell/src/link/link_api.c +++ b/samples/cellular/modem_shell/src/link/link_api.c @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -40,14 +41,6 @@ extern struct k_mutex mosh_at_resp_buf_mutex; #define AT_CMD_PDP_CONTEXTS_READ_APN_INDEX 3 #define AT_CMD_PDP_CONTEXTS_READ_PDP_ADDR_INDEX 4 -#define AT_CMD_PDP_CONTEXT_READ_INFO \ - "AT+CGCONTRDP=%d" /* Use sprintf to add CID into command */ -#define AT_CMD_PDP_CONTEXT_READ_INFO_PARAM_COUNT 20 -#define AT_CMD_PDP_CONTEXT_READ_INFO_CID_INDEX 1 -#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" /* ****************************************************************************/ @@ -348,137 +341,15 @@ static void link_api_modem_operator_info_read_for_shell(void) static int link_api_pdp_context_dynamic_params_get(struct pdp_context_info *populated_info) { - int ret = 0; - struct at_parser parser; - size_t param_str_len; - - /* Cannot use global mosh_at_resp_buf because this used from link_api_pdp_contexts_read() - * where global mosh_at_resp_buf is already used - */ - 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; - - 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) { - mosh_error( - "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) { - mosh_error("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, ¶m_str_len); - if (ret) { - mosh_error( - "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 = net_utils_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, ¶m_str_len); - if (ret) { - mosh_error("Could not parse dns str, err: %d", ret); - goto clean_exit; - } - dns_addr_str[param_str_len] = '\0'; - - family = net_utils_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 : 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_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; - } - } 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 (at_parser_cmd_next(&parser) == 0) { - iterator++; - if (iterator < lines) { - goto parse; - } - } - -clean_exit: + struct pdn_dynamic_info pdn_dynamic_info; + const int ret = pdn_dynamic_info_get(populated_info->cid, &pdn_dynamic_info); + + populated_info->ipv4_mtu = pdn_dynamic_info.ipv4_mtu; + populated_info->ipv6_mtu = pdn_dynamic_info.ipv6_mtu; + populated_info->dns_addr4_primary = pdn_dynamic_info.dns_addr4_primary; + populated_info->dns_addr4_secondary = pdn_dynamic_info.dns_addr4_secondary; + populated_info->dns_addr6_primary = pdn_dynamic_info.dns_addr6_primary; + populated_info->dns_addr6_secondary = pdn_dynamic_info.dns_addr6_secondary; return ret; }