Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LwIP: add ICMPv4 Socket support #10978

Merged
merged 12 commits into from
Oct 31, 2019
1 change: 1 addition & 0 deletions UNITTESTS/features/netsocket/DTLSSocket/unittest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set(unittest-sources
../features/netsocket/SocketAddress.cpp
../features/netsocket/NetworkStack.cpp
../features/netsocket/InternetSocket.cpp
../features/netsocket/InternetDatagramSocket.cpp
../features/netsocket/UDPSocket.cpp
../features/netsocket/DTLSSocket.cpp
../features/netsocket/DTLSSocketWrapper.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set(unittest-sources
../features/netsocket/SocketAddress.cpp
../features/netsocket/NetworkStack.cpp
../features/netsocket/InternetSocket.cpp
../features/netsocket/InternetDatagramSocket.cpp
../features/netsocket/UDPSocket.cpp
../features/netsocket/DTLSSocketWrapper.cpp
../features/netsocket/TLSSocketWrapper.cpp
Expand Down
1 change: 1 addition & 0 deletions UNITTESTS/features/netsocket/UDPSocket/unittest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set(unittest-sources
../features/netsocket/SocketAddress.cpp
../features/netsocket/NetworkStack.cpp
../features/netsocket/InternetSocket.cpp
../features/netsocket/InternetDatagramSocket.cpp
../features/netsocket/UDPSocket.cpp
../features/frameworks/nanostack-libservice/source/libip4string/ip4tos.c
../features/frameworks/nanostack-libservice/source/libip6string/ip6tos.c
Expand Down
20 changes: 17 additions & 3 deletions features/lwipstack/LWIPStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,14 +230,28 @@ nsapi_error_t LWIP::socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto)
return NSAPI_ERROR_NO_SOCKET;
}

enum netconn_type lwip_proto = proto == NSAPI_TCP ? NETCONN_TCP : NETCONN_UDP;
enum netconn_type netconntype;
if (proto == NSAPI_TCP) {
netconntype = NETCONN_TCP;
} else if (proto == NSAPI_UDP) {
netconntype = NETCONN_UDP;
} else if (proto == NSAPI_ICMP) {
netconntype = NETCONN_RAW;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For future-proofing, can you make this error for unknown proto? I know it didn't before, but it should have,

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you mean the known proto be NASPI_ERROR_PROTO_UNKNOWN and return from function as below.
...
} else if (proto == NSAPI_UDP) {
netconntype = NETCONN_UDP;
} else if { proto == NSAPI_ICMP) {
netconntype = NETCONN_RAW;
} else {
return NSAPI_ERROR_PROTO_UNKNOWN;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed NSAPI_ERROR_PROTO_UNKNOWN

} else {
return NSAPI_ERROR_UNSUPPORTED;
}

#if LWIP_IPV6
// Enable IPv6 (or dual-stack)
lwip_proto = (enum netconn_type)(lwip_proto | NETCONN_TYPE_IPV6);
netconntype = (enum netconn_type)(netconntype | NETCONN_TYPE_IPV6);
#endif

s->conn = netconn_new_with_callback(lwip_proto, &LWIP::socket_callback);
if (proto == NSAPI_ICMP) {
s->conn = netconn_new_with_proto_and_callback(NETCONN_RAW,
(u8_t)IP_PROTO_ICMP, &LWIP::socket_callback);
kjbracey marked this conversation as resolved.
Show resolved Hide resolved
} else {
s->conn = netconn_new_with_callback(netconntype, &LWIP::socket_callback);
}

if (!s->conn) {
arena_dealloc(s);
Expand Down
4 changes: 1 addition & 3 deletions features/lwipstack/lwipopts.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,7 @@

#define SYS_LIGHTWEIGHT_PROT 1

#ifndef LWIP_RAW
#define LWIP_RAW 0
#endif
#define LWIP_RAW MBED_CONF_LWIP_RAW_SOCKET_ENABLED

#define MEMP_NUM_TCPIP_MSG_INPKT MBED_CONF_LWIP_MEMP_NUM_TCPIP_MSG_INPKT
#define TCPIP_MBOX_SIZE MBED_CONF_LWIP_TCPIP_MBOX_SIZE
Expand Down
4 changes: 4 additions & 0 deletions features/lwipstack/mbed_lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@
"num-netbuf": {
"help": "Number of netbufs, each netbuf requires 64 bytes of RAM, see LWIP's opt.h for more information. Current default is 8.",
"value": 8
},
"raw-socket-enabled": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kjbracey-arm Fixed now?

"help": "Enable lwip raw sockets, required for Mbed OS ICMPSocket",
"value": false
}
},
"target_overrides": {
Expand Down
29 changes: 29 additions & 0 deletions features/netsocket/ICMPSocket.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* Socket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "ICMPSocket.h"
#include "Timer.h"
#include "mbed_assert.h"

ICMPSocket::ICMPSocket()
{
_socket_stats.stats_update_proto(this, NSAPI_ICMP);
}

nsapi_protocol_t ICMPSocket::get_proto()
{
return NSAPI_ICMP;
}
50 changes: 50 additions & 0 deletions features/netsocket/ICMPSocket.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/** \addtogroup netsocket */
/** @{*/
/* ICMPSocket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef ICMPSOCKET_H
#define ICMPSOCKET_H

#include "netsocket/InternetSocket.h"
#include "netsocket/InternetDatagramSocket.h"
#include "netsocket/NetworkStack.h"
#include "netsocket/NetworkInterface.h"
#include "rtos/EventFlags.h"


/** ICMP socket implementation.
*/
class ICMPSocket : public InternetDatagramSocket {
public:
/** Create an uninitialized socket.
*
* @note Must call open to initialize the socket on a network stack.
*/
ICMPSocket();

#if !defined(DOXYGEN_ONLY)

protected:
virtual nsapi_protocol_t get_proto();

#endif //!defined(DOXYGEN_ONLY)
};


#endif

/** @}*/
182 changes: 182 additions & 0 deletions features/netsocket/InternetDatagramSocket.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/* Socket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "InternetDatagramSocket.h"
#include "Timer.h"
#include "mbed_assert.h"

nsapi_error_t InternetDatagramSocket::connect(const SocketAddress &address)
{
_remote_peer = address;
_socket_stats.stats_update_peer(this, _remote_peer);
_socket_stats.stats_update_socket_state(this, SOCK_CONNECTED);
return NSAPI_ERROR_OK;
}

nsapi_size_or_error_t InternetDatagramSocket::sendto(const char *host, uint16_t port, const void *data, nsapi_size_t size)
{
SocketAddress address;
nsapi_size_or_error_t err;

if (!strcmp(_interface_name, "")) {
err = _stack->gethostbyname(host, &address);
} else {
err = _stack->gethostbyname(host, &address, NSAPI_UNSPEC, _interface_name);
}

if (err) {
return NSAPI_ERROR_DNS_FAILURE;
}

address.set_port(port);

// sendto is thread safe
return sendto(address, data, size);
}

nsapi_size_or_error_t InternetDatagramSocket::sendto(const SocketAddress &address, const void *data, nsapi_size_t size)
{
_lock.lock();
nsapi_size_or_error_t ret;

_writers++;
if (_socket) {
_socket_stats.stats_update_socket_state(this, SOCK_OPEN);
_socket_stats.stats_update_peer(this, address);
}
while (true) {
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
break;
}

core_util_atomic_flag_clear(&_pending);
nsapi_size_or_error_t sent = _stack->socket_sendto(_socket, address, data, size);
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != sent)) {
_socket_stats.stats_update_sent_bytes(this, sent);
ret = sent;
break;
} else {
uint32_t flag;

// Release lock before blocking so other threads
// accessing this object aren't blocked
_lock.unlock();
flag = _event_flag.wait_any(WRITE_FLAG, _timeout);
_lock.lock();

if (flag & osFlagsError) {
// Timeout break
ret = NSAPI_ERROR_WOULD_BLOCK;
break;
}
}
}

_writers--;
if (!_socket || !_writers) {
_event_flag.set(FINISHED_FLAG);
}
_lock.unlock();
return ret;
}

nsapi_size_or_error_t InternetDatagramSocket::send(const void *data, nsapi_size_t size)
{
if (!_remote_peer) {
return NSAPI_ERROR_NO_ADDRESS;
}
return sendto(_remote_peer, data, size);
}

nsapi_size_or_error_t InternetDatagramSocket::recvfrom(SocketAddress *address, void *buffer, nsapi_size_t size)
{
_lock.lock();
nsapi_size_or_error_t ret;
SocketAddress ignored;

if (!address) {
address = &ignored;
}

_readers++;

if (_socket) {
_socket_stats.stats_update_socket_state(this, SOCK_OPEN);
}
while (true) {
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
break;
}

core_util_atomic_flag_clear(&_pending);
nsapi_size_or_error_t recv = _stack->socket_recvfrom(_socket, address, buffer, size);

// Filter incomming packets using connected peer address
if (recv >= 0 && _remote_peer && _remote_peer != *address) {
continue;
}

_socket_stats.stats_update_peer(this, _remote_peer);
// Non-blocking sockets always return. Blocking only returns when success or errors other than WOULD_BLOCK
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != recv)) {
ret = recv;
_socket_stats.stats_update_recv_bytes(this, recv);
break;
} else {
uint32_t flag;

// Release lock before blocking so other threads
// accessing this object aren't blocked
_lock.unlock();
flag = _event_flag.wait_any(READ_FLAG, _timeout);
_lock.lock();

if (flag & osFlagsError) {
// Timeout break
ret = NSAPI_ERROR_WOULD_BLOCK;
break;
}
}
}

_readers--;
if (!_socket || !_readers) {
_event_flag.set(FINISHED_FLAG);
}

_lock.unlock();
return ret;
}

nsapi_size_or_error_t InternetDatagramSocket::recv(void *buffer, nsapi_size_t size)
{
return recvfrom(NULL, buffer, size);
}

Socket *InternetDatagramSocket::accept(nsapi_error_t *error)
{
if (error) {
*error = NSAPI_ERROR_UNSUPPORTED;
}
return NULL;
}

nsapi_error_t InternetDatagramSocket::listen(int)
{
return NSAPI_ERROR_UNSUPPORTED;
}
Loading