From ea1b2b80452326436e78be5e782b7c792fa6561e Mon Sep 17 00:00:00 2001 From: Mirela Chirica Date: Thu, 12 Sep 2019 12:55:33 +0300 Subject: [PATCH 1/4] Cellular: Stack type based on assigned IP addresses versions --- UNITTESTS/stubs/CellularUtil_stub.cpp | 4 +-- .../framework/AT/AT_CellularStack.cpp | 32 ++++++++++++++----- .../cellular/framework/AT/AT_CellularStack.h | 2 +- .../framework/common/CellularUtil.cpp | 14 ++++++-- .../cellular/framework/common/CellularUtil.h | 3 +- 5 files changed, 40 insertions(+), 15 deletions(-) diff --git a/UNITTESTS/stubs/CellularUtil_stub.cpp b/UNITTESTS/stubs/CellularUtil_stub.cpp index 1ed70b7cfd..757fd2bbb8 100644 --- a/UNITTESTS/stubs/CellularUtil_stub.cpp +++ b/UNITTESTS/stubs/CellularUtil_stub.cpp @@ -51,9 +51,9 @@ uint16_t char_str_to_hex(const char *str, uint16_t len, char *buf, bool omit_lea return CellularUtil_stub::uint16_value; } -void convert_ipv6(char *ip) +nsapi_version_t convert_ipv6(char *ip) { - + return NSAPI_UNSPEC; } char *find_dot_number(char *str, int dot_number) diff --git a/features/cellular/framework/AT/AT_CellularStack.cpp b/features/cellular/framework/AT/AT_CellularStack.cpp index a8aba5b578..dc0f5732c2 100644 --- a/features/cellular/framework/AT/AT_CellularStack.cpp +++ b/features/cellular/framework/AT/AT_CellularStack.cpp @@ -59,27 +59,43 @@ const char *AT_CellularStack::get_ip_address() { _at.lock(); + bool ipv4 = false, ipv6 = false; + _at.cmd_start_stop("+CGPADDR", "=", "%d", _cid); _at.resp_start("+CGPADDR:"); - int len = -1; if (_at.info_resp()) { _at.skip_param(); - len = _at.read_string(_ip, PDP_IPV6_SIZE); + if (_at.read_string(_ip, PDP_IPV6_SIZE) != -1) { + convert_ipv6(_ip); + SocketAddress address; + address.set_ip_address(_ip); - if (len != -1 && _stack_type != IPV4_STACK) { - // in case stack type is not IPV4 only, try to look also for IPV6 address - (void)_at.read_string(_ip, PDP_IPV6_SIZE); + ipv4 = (address.get_ip_version() == NSAPI_IPv4); + ipv6 = (address.get_ip_version() == NSAPI_IPv6); + + // Try to look for second address ONLY if modem has support for dual stack(can handle both IPv4 and IPv6 simultaneously). + // Otherwise assumption is that second address is not reliable, even if network provides one. + if ((get_property(PROPERTY_IPV4V6_PDP_TYPE) && (_at.read_string(_ip, PDP_IPV6_SIZE) != -1))) { + convert_ipv6(_ip); + address.set_ip_address(_ip); + ipv6 = (address.get_ip_version() == NSAPI_IPv6); + } } } _at.resp_stop(); _at.unlock(); - // we have at least IPV4 address - convert_ipv6(_ip); + if (ipv4 && ipv6) { + _stack_type = IPV4V6_STACK; + } else if (ipv4) { + _stack_type = IPV4_STACK; + } else if (ipv6) { + _stack_type = IPV6_STACK; + } - return len != -1 ? _ip : NULL; + return (ipv4 || ipv6) ? _ip : NULL; } nsapi_error_t AT_CellularStack::socket_stack_init() diff --git a/features/cellular/framework/AT/AT_CellularStack.h b/features/cellular/framework/AT/AT_CellularStack.h index fd9adf28ac..a61515672f 100644 --- a/features/cellular/framework/AT/AT_CellularStack.h +++ b/features/cellular/framework/AT/AT_CellularStack.h @@ -203,7 +203,7 @@ protected: // PDP context id int _cid; - // stack type from PDP context + // stack type - initialised as PDP type and set accordingly after CGPADDR checked nsapi_ip_stack_t _stack_type; private: diff --git a/features/cellular/framework/common/CellularUtil.cpp b/features/cellular/framework/common/CellularUtil.cpp index 8c7bf7a9d3..33c5956899 100644 --- a/features/cellular/framework/common/CellularUtil.cpp +++ b/features/cellular/framework/common/CellularUtil.cpp @@ -28,10 +28,10 @@ using namespace mbed; namespace mbed_cellular_util { -void convert_ipv6(char *ip) +nsapi_version_t convert_ipv6(char *ip) { if (!ip) { - return; + return NSAPI_UNSPEC; } int len = strlen(ip); @@ -49,7 +49,11 @@ void convert_ipv6(char *ip) // more that 3 periods mean that it was ipv6 but in format of a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11.a12.a13.a14.a15.a16 // we need to convert it to hexadecimal format separated with colons - if (pos > 3) { + if (pos == 3) { + + return NSAPI_IPv4; + + } else if (pos > 3) { pos = 0; int ip_pos = 0; char b; @@ -74,7 +78,11 @@ void convert_ipv6(char *ip) ip[pos] = '\0'; } } + + return NSAPI_IPv6; } + + return NSAPI_UNSPEC; } // For example "32.1.13.184.0.0.205.48.0.0.0.0.0.0.0.0" diff --git a/features/cellular/framework/common/CellularUtil.h b/features/cellular/framework/common/CellularUtil.h index cfd7b50e0d..cfe0c86cba 100644 --- a/features/cellular/framework/common/CellularUtil.h +++ b/features/cellular/framework/common/CellularUtil.h @@ -48,8 +48,9 @@ static const char hex_values[] = "0123456789ABCDEF"; * where ax are in decimal format. In this case, function converts decimals to hex with separated with colons. * * @param ip IP address that can be IPv4 or IPv6 in different formats from AT command +CGPADDR. Converted result uses same buffer. + * @return IP version of the address or NSAPI_UNSPEC if param ip empty or if IPv4 or IPv6 version could not be concluded. */ -void convert_ipv6(char *ip); +nsapi_version_t convert_ipv6(char *ip); /** Separates IP addresses from the given 'orig' string. 'orig' may contain zero, one or two IP addresses in various formats. * See AT command +CGPIAF from 3GPP TS 27.007 for details. Does also needed conversions for IPv6 addresses. From b44ba531a15a1340d06e8bc62660dca62e45699f Mon Sep 17 00:00:00 2001 From: Mirela Chirica Date: Thu, 5 Sep 2019 14:08:35 +0300 Subject: [PATCH 2/4] Cellular: Check IP version of send to address --- .../framework/AT/AT_CellularStack.cpp | 26 ++++++++++++++++--- .../cellular/framework/AT/AT_CellularStack.h | 8 ++++++ .../BG96/QUECTEL_BG96_CellularStack.cpp | 10 +++++-- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/features/cellular/framework/AT/AT_CellularStack.cpp b/features/cellular/framework/AT/AT_CellularStack.cpp index dc0f5732c2..621431eabe 100644 --- a/features/cellular/framework/AT/AT_CellularStack.cpp +++ b/features/cellular/framework/AT/AT_CellularStack.cpp @@ -23,7 +23,7 @@ using namespace mbed_cellular_util; using namespace mbed; -AT_CellularStack::AT_CellularStack(ATHandler &at, int cid, nsapi_ip_stack_t stack_type) : AT_CellularBase(at), _socket(NULL), _socket_count(0), _cid(cid), _stack_type(stack_type) +AT_CellularStack::AT_CellularStack(ATHandler &at, int cid, nsapi_ip_stack_t stack_type) : AT_CellularBase(at), _socket(NULL), _socket_count(0), _cid(cid), _stack_type(stack_type), _ip_ver_sendto(NSAPI_UNSPEC) { memset(_ip, 0, PDP_IPV6_SIZE); } @@ -272,6 +272,13 @@ nsapi_size_or_error_t AT_CellularStack::socket_sendto(nsapi_socket_t handle, con nsapi_size_or_error_t ret_val = NSAPI_ERROR_OK; if (socket->id == -1) { + + /* Check that stack type supports sendto address type*/ + if (!is_addr_stack_compatible(addr)) { + return NSAPI_ERROR_PARAMETER; + } + + _ip_ver_sendto = addr.get_ip_version(); _at.lock(); ret_val = create_socket_impl(socket); @@ -283,9 +290,9 @@ nsapi_size_or_error_t AT_CellularStack::socket_sendto(nsapi_socket_t handle, con } } - /* Check parameters */ - if (addr.get_ip_version() == NSAPI_UNSPEC) { - return NSAPI_ERROR_DEVICE_ERROR; + /* Check parameters - sendto address is valid and stack type supports sending to that address type*/ + if (!is_addr_stack_compatible(addr)) { + return NSAPI_ERROR_PARAMETER; } _at.lock(); @@ -393,3 +400,14 @@ AT_CellularStack::CellularSocket *AT_CellularStack::find_socket(int sock_id) } return sock; } + +bool AT_CellularStack::is_addr_stack_compatible(const SocketAddress &addr) +{ + if ((addr.get_ip_version() == NSAPI_UNSPEC) || + (addr.get_ip_version() == NSAPI_IPv4 && _stack_type == IPV6_STACK) || + (addr.get_ip_version() == NSAPI_IPv6 && _stack_type == IPV4_STACK)) { + return false; + } + return true; +} + diff --git a/features/cellular/framework/AT/AT_CellularStack.h b/features/cellular/framework/AT/AT_CellularStack.h index a61515672f..9bbedd4fe6 100644 --- a/features/cellular/framework/AT/AT_CellularStack.h +++ b/features/cellular/framework/AT/AT_CellularStack.h @@ -191,6 +191,11 @@ protected: */ int find_socket_index(nsapi_socket_t handle); + /** + * Checks if send to address is valid and if current stack type supports sending to that address type + */ + bool is_addr_stack_compatible(const SocketAddress &addr); + // socket container CellularSocket **_socket; @@ -206,6 +211,9 @@ protected: // stack type - initialised as PDP type and set accordingly after CGPADDR checked nsapi_ip_stack_t _stack_type; + // IP version of send to address + nsapi_version_t _ip_ver_sendto; + private: int get_socket_index_by_port(uint16_t port); diff --git a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.cpp b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.cpp index 2cfef67cd3..1c26340204 100644 --- a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.cpp +++ b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.cpp @@ -212,7 +212,7 @@ nsapi_error_t QUECTEL_BG96_CellularStack::create_socket_impl(CellularSocket *soc if (socket->proto == NSAPI_UDP && !socket->connected) { _at.at_cmd_discard("+QIOPEN", "=", "%d%d%s%s%d%d%d", _cid, request_connect_id, "UDP SERVICE", - (_stack_type == IPV4_STACK) ? "127.0.0.1" : "0:0:0:0:0:0:0:1", + (_ip_ver_sendto == NSAPI_IPv4) ? "127.0.0.1" : "0:0:0:0:0:0:0:1", remote_port, socket->localAddress.get_port(), 0); handle_open_socket_response(modem_connect_id, err); @@ -225,7 +225,7 @@ nsapi_error_t QUECTEL_BG96_CellularStack::create_socket_impl(CellularSocket *soc socket_close_impl(modem_connect_id); _at.at_cmd_discard("+QIOPEN", "=", "%d%d%s%s%d%d%d", _cid, request_connect_id, "UDP SERVICE", - (_stack_type == IPV4_STACK) ? "127.0.0.1" : "0:0:0:0:0:0:0:1", + (_ip_ver_sendto == NSAPI_IPv4) ? "127.0.0.1" : "0:0:0:0:0:0:0:1", remote_port, socket->localAddress.get_port(), 0); handle_open_socket_response(modem_connect_id, err); @@ -273,6 +273,12 @@ nsapi_size_or_error_t QUECTEL_BG96_CellularStack::socket_sendto_impl(CellularSoc return NSAPI_ERROR_PARAMETER; } + if (_ip_ver_sendto != address.get_ip_version()) { + _ip_ver_sendto = address.get_ip_version(); + socket_close_impl(socket->id); + create_socket_impl(socket); + } + int sent_len = 0; int sent_len_before = 0; int sent_len_after = 0; From 7aaaae121e24ef3d6dabc807f8f2eedfa3656687 Mon Sep 17 00:00:00 2001 From: Mirela Chirica Date: Thu, 5 Sep 2019 14:03:01 +0300 Subject: [PATCH 3/4] Cellular: IP stack property redefined --- features/cellular/framework/AT/AT_CellularBase.h | 2 +- features/cellular/framework/AT/AT_CellularContext.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/features/cellular/framework/AT/AT_CellularBase.h b/features/cellular/framework/AT/AT_CellularBase.h index e50008a75d..c4448142a7 100644 --- a/features/cellular/framework/AT/AT_CellularBase.h +++ b/features/cellular/framework/AT/AT_CellularBase.h @@ -60,7 +60,7 @@ public: PROPERTY_AT_CSDH, // 0 = not supported, 1 = supported. Show text mode AT command PROPERTY_IPV4_PDP_TYPE, // 0 = not supported, 1 = supported. Does modem support IPV4? PROPERTY_IPV6_PDP_TYPE, // 0 = not supported, 1 = supported. Does modem support IPV6? - PROPERTY_IPV4V6_PDP_TYPE, // 0 = not supported, 1 = supported. Does modem support dual stack IPV4V6? + PROPERTY_IPV4V6_PDP_TYPE, // 0 = not supported, 1 = supported. Does modem support IPV4 and IPV6 simultaneously? PROPERTY_NON_IP_PDP_TYPE, // 0 = not supported, 1 = supported. Does modem support Non-IP? PROPERTY_AT_CGEREP, // 0 = not supported, 1 = supported. Does modem support AT command AT+CGEREP. diff --git a/features/cellular/framework/AT/AT_CellularContext.cpp b/features/cellular/framework/AT/AT_CellularContext.cpp index c1fbbc3b8d..cc0807dfb0 100644 --- a/features/cellular/framework/AT/AT_CellularContext.cpp +++ b/features/cellular/framework/AT/AT_CellularContext.cpp @@ -369,8 +369,9 @@ bool AT_CellularContext::get_context() // APN matched -> Check PDP type pdp_type_t pdp_type = string_to_pdp_type(pdp_type_from_context); - // Accept exact matching PDP context type - if (get_property(pdp_type_t_to_cellular_property(pdp_type))) { + // Accept exact matching PDP context type or dual PDP context for modems that support both IPv4 and IPv6 stacks + if (get_property(pdp_type_t_to_cellular_property(pdp_type)) || + ((pdp_type == IPV4V6_PDP_TYPE && (get_property(PROPERTY_IPV4_PDP_TYPE) && get_property(PROPERTY_IPV6_PDP_TYPE))) && !_nonip_req)) { _pdp_type = pdp_type; _cid = cid; } @@ -403,7 +404,7 @@ bool AT_CellularContext::set_new_context(int cid) if (_nonip_req && _cp_in_use && get_property(PROPERTY_NON_IP_PDP_TYPE)) { strncpy(pdp_type_str, "Non-IP", sizeof(pdp_type_str)); pdp_type = NON_IP_PDP_TYPE; - } else if (get_property(PROPERTY_IPV4V6_PDP_TYPE)) { + } else if (get_property(PROPERTY_IPV4V6_PDP_TYPE) || (get_property(PROPERTY_IPV4_PDP_TYPE) && get_property(PROPERTY_IPV6_PDP_TYPE))) { strncpy(pdp_type_str, "IPV4V6", sizeof(pdp_type_str)); pdp_type = IPV4V6_PDP_TYPE; } else if (get_property(PROPERTY_IPV6_PDP_TYPE)) { From 78f4e8b12f17320c34a63fa2814f874cf9b7ddab Mon Sep 17 00:00:00 2001 From: Mirela Chirica Date: Thu, 5 Sep 2019 10:34:46 +0300 Subject: [PATCH 4/4] Cellular: Enable IPv6 stack property for BG96 --- .../cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96.cpp b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96.cpp index 837f36c209..a0ee4a2c9f 100644 --- a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96.cpp +++ b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96.cpp @@ -57,7 +57,7 @@ static const intptr_t cellular_properties[AT_CellularBase::PROPERTY_MAX] = { 1, // AT_CMGF 1, // AT_CSDH 1, // PROPERTY_IPV4_STACK - 0, // PROPERTY_IPV6_STACK + 1, // PROPERTY_IPV6_STACK 0, // PROPERTY_IPV4V6_STACK 1, // PROPERTY_NON_IP_PDP_TYPE 1, // PROPERTY_AT_CGEREP