summaryrefslogtreecommitdiff
path: root/components/net/sal/impl/af_inet_lwip.c
diff options
context:
space:
mode:
Diffstat (limited to 'components/net/sal/impl/af_inet_lwip.c')
-rw-r--r--components/net/sal/impl/af_inet_lwip.c337
1 files changed, 337 insertions, 0 deletions
diff --git a/components/net/sal/impl/af_inet_lwip.c b/components/net/sal/impl/af_inet_lwip.c
new file mode 100644
index 0000000000..2cf0958ee4
--- /dev/null
+++ b/components/net/sal/impl/af_inet_lwip.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018-05-17 ChenYong First version
+ */
+
+#include <rtthread.h>
+
+#include <lwip/sockets.h>
+#include <lwip/netdb.h>
+#include <lwip/api.h>
+#include <lwip/init.h>
+#include <lwip/netif.h>
+
+#ifdef SAL_USING_POSIX
+#include <poll.h>
+#endif
+
+#include <sal.h>
+#include <af_inet.h>
+
+#include <netdev.h>
+
+#if (LWIP_VERSION < 0x2000000) && NETDEV_IPV6
+#error "The lwIP version is not support IPV6, please disable netdev IPV6 configuration "
+#elif (LWIP_VERSION > 0x2000000) && (NETDEV_IPV6 != LWIP_IPV6)
+#error "IPV6 configuration error, Please check and synchronize netdev and lwip IPV6 configuration."
+#endif
+
+#if LWIP_VERSION < 0x2000000
+#define SELWAIT_T int
+#else
+#ifndef SELWAIT_T
+#define SELWAIT_T u8_t
+#endif
+#endif
+
+#ifdef SAL_USING_LWIP
+
+#ifdef SAL_USING_POSIX
+
+#if LWIP_VERSION >= 0x20100ff
+#include <lwip/priv/sockets_priv.h>
+#else /* LWIP_VERSION < 0x20100ff */
+/*
+ * Re-define lwip socket
+ *
+ * NOTE: please make sure the definitions same in lwip::net_socket.c
+ */
+struct lwip_sock {
+ /** sockets currently are built on netconns, each socket has one netconn */
+ struct netconn *conn;
+ /** data that was left from the previous read */
+ void *lastdata;
+ /** offset in the data that was left from the previous read */
+ u16_t lastoffset;
+ /** number of times data was received, set by event_callback(),
+ tested by the receive and select functions */
+ s16_t rcvevent;
+ /** number of times data was ACKed (free send buffer), set by event_callback(),
+ tested by select */
+ u16_t sendevent;
+ /** error happened for this socket, set by event_callback(), tested by select */
+ u16_t errevent;
+ /** last error that occurred on this socket */
+#if LWIP_VERSION < 0x2000000
+ int err;
+#else
+ u8_t err;
+#endif
+ /** counter of how many threads are waiting for this socket using select */
+ SELWAIT_T select_waiting;
+
+ rt_wqueue_t wait_head;
+};
+#endif /* LWIP_VERSION >= 0x20100ff */
+
+extern struct lwip_sock *lwip_tryget_socket(int s);
+
+static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
+{
+ int s;
+ struct lwip_sock *sock;
+ uint32_t event = 0;
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ LWIP_UNUSED_ARG(len);
+
+ /* Get socket */
+ if (conn)
+ {
+ s = conn->socket;
+ if (s < 0)
+ {
+ /* Data comes in right away after an accept, even though
+ * the server task might not have created a new socket yet.
+ * Just count down (or up) if that's the case and we
+ * will use the data later. Note that only receive events
+ * can happen before the new socket is set up. */
+ SYS_ARCH_PROTECT(lev);
+ if (conn->socket < 0)
+ {
+ if (evt == NETCONN_EVT_RCVPLUS)
+ {
+ conn->socket--;
+ }
+ SYS_ARCH_UNPROTECT(lev);
+ return;
+ }
+ s = conn->socket;
+ SYS_ARCH_UNPROTECT(lev);
+ }
+
+ sock = lwip_tryget_socket(s);
+ if (!sock)
+ {
+ return;
+ }
+ }
+ else
+ {
+ return;
+ }
+
+ SYS_ARCH_PROTECT(lev);
+ /* Set event as required */
+ switch (evt)
+ {
+ case NETCONN_EVT_RCVPLUS:
+ sock->rcvevent++;
+ break;
+ case NETCONN_EVT_RCVMINUS:
+ sock->rcvevent--;
+ break;
+ case NETCONN_EVT_SENDPLUS:
+ sock->sendevent = 1;
+ break;
+ case NETCONN_EVT_SENDMINUS:
+ sock->sendevent = 0;
+ break;
+ case NETCONN_EVT_ERROR:
+ sock->errevent = 1;
+ break;
+ default:
+ LWIP_ASSERT("unknown event", 0);
+ break;
+ }
+
+#if LWIP_VERSION >= 0x20100ff
+ if ((void*)(sock->lastdata.pbuf) || (sock->rcvevent > 0))
+#else
+ if ((void*)(sock->lastdata) || (sock->rcvevent > 0))
+#endif
+ event |= POLLIN;
+ if (sock->sendevent)
+ event |= POLLOUT;
+ if (sock->errevent)
+ event |= POLLERR;
+
+ SYS_ARCH_UNPROTECT(lev);
+
+ if (event)
+ {
+ rt_wqueue_wakeup(&sock->wait_head, (void*) event);
+ }
+}
+#endif /* SAL_USING_POSIX */
+
+static int inet_socket(int domain, int type, int protocol)
+{
+#ifdef SAL_USING_POSIX
+ int socket;
+
+ socket = lwip_socket(domain, type, protocol);
+ if (socket >= 0)
+ {
+ struct lwip_sock *lwsock;
+
+ lwsock = lwip_tryget_socket(socket);
+ lwsock->conn->callback = event_callback;
+
+ rt_wqueue_init(&lwsock->wait_head);
+ }
+
+ return socket;
+#else
+ return lwip_socket(domain, type, protocol);
+#endif /* SAL_USING_POSIX */
+}
+
+static int inet_accept(int socket, struct sockaddr *addr, socklen_t *addrlen)
+{
+#ifdef SAL_USING_POSIX
+ int new_socket;
+
+ new_socket = lwip_accept(socket, addr, addrlen);
+ if (new_socket >= 0)
+ {
+ struct lwip_sock *lwsock;
+
+ lwsock = lwip_tryget_socket(new_socket);
+
+ rt_wqueue_init(&lwsock->wait_head);
+ }
+
+ return new_socket;
+#else
+ return lwip_accept(socket, addr, addrlen);
+#endif /* SAL_USING_POSIX */
+}
+
+static int inet_getsockname(int socket, struct sockaddr *name, socklen_t *namelen)
+{
+#if LWIP_VERSION_MAJOR < 2U
+ rt_kprintf("ERROR: Your lwIP version is not supported. Please using lwIP 2.0.0+.\n");
+ RT_ASSERT(LWIP_VERSION_MAJOR >= 2U);
+#endif
+
+ return lwip_getsockname(socket, name, namelen);
+}
+
+int inet_ioctlsocket(int socket, long cmd, void *arg)
+{
+ switch (cmd)
+ {
+ case F_GETFL:
+ case F_SETFL:
+ return lwip_fcntl(socket, cmd, (int) arg);
+
+ default:
+ return lwip_ioctl(socket, cmd, arg);
+ }
+}
+
+#ifdef SAL_USING_POSIX
+static int inet_poll(struct dfs_fd *file, struct rt_pollreq *req)
+{
+ int mask = 0;
+ struct lwip_sock *sock;
+ struct sal_socket *sal_sock;
+
+ sal_sock = sal_get_socket((int) file->data);
+ if(!sal_sock)
+ {
+ return -1;
+ }
+
+ sock = lwip_tryget_socket((int)sal_sock->user_data);
+ if (sock != NULL)
+ {
+ rt_base_t level;
+
+ rt_poll_add(&sock->wait_head, req);
+
+ level = rt_hw_interrupt_disable();
+
+#if LWIP_VERSION >= 0x20100ff
+ if ((void*)(sock->lastdata.pbuf) || sock->rcvevent)
+#else
+ if ((void*)(sock->lastdata) || sock->rcvevent)
+#endif
+ {
+ mask |= POLLIN;
+ }
+ if (sock->sendevent)
+ {
+ mask |= POLLOUT;
+ }
+ if (sock->errevent)
+ {
+ mask |= POLLERR;
+ /* clean error event */
+ sock->errevent = 0;
+ }
+ rt_hw_interrupt_enable(level);
+ }
+
+ return mask;
+}
+#endif
+
+static const struct sal_socket_ops lwip_socket_ops =
+{
+ inet_socket,
+ lwip_close,
+ lwip_bind,
+ lwip_listen,
+ lwip_connect,
+ inet_accept,
+ (int (*)(int, const void *, size_t, int, const struct sockaddr *, socklen_t))lwip_sendto,
+ (int (*)(int, void *, size_t, int, struct sockaddr *, socklen_t *))lwip_recvfrom,
+ lwip_getsockopt,
+ //TODO fix on 1.4.1
+ lwip_setsockopt,
+ lwip_shutdown,
+ lwip_getpeername,
+ inet_getsockname,
+ inet_ioctlsocket,
+#ifdef SAL_USING_POSIX
+ inet_poll,
+#endif
+};
+
+static const struct sal_netdb_ops lwip_netdb_ops =
+{
+ lwip_gethostbyname,
+ lwip_gethostbyname_r,
+ lwip_getaddrinfo,
+ lwip_freeaddrinfo,
+};
+
+static const struct sal_proto_family lwip_inet_family =
+{
+ AF_INET,
+#if LWIP_VERSION > 0x2000000
+ AF_INET6,
+#else
+ AF_INET,
+#endif
+ &lwip_socket_ops,
+ &lwip_netdb_ops,
+};
+
+/* Set lwIP network interface device protocol family information */
+int sal_lwip_netdev_set_pf_info(struct netdev *netdev)
+{
+ RT_ASSERT(netdev);
+
+ netdev->sal_user_data = (void *) &lwip_inet_family;
+ return 0;
+}
+
+#endif /* SAL_USING_LWIP */