RTC auf true

Revision:
0:38ceb79fef03
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/features/lwipstack/ppp_lwip.cpp	Wed Nov 28 15:10:15 2018 +0000
@@ -0,0 +1,465 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2016 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 <errno.h>
+#include "platform/FileHandle.h"
+#include "platform/mbed_poll.h"
+#include "events/EventQueue.h"
+#include "mbed_trace.h"
+#define TRACE_GROUP "LPPP"
+#include "rtos/Thread.h"
+#include "lwip/tcpip.h"
+#include "lwip/tcp.h"
+#include "lwip/ip.h"
+#include "lwip/dns.h"
+#include "lwip/pbuf.h"
+extern "C" { // "pppos.h" is missing extern C
+#include "netif/ppp/pppapi.h"
+}
+
+#include "nsapi_ppp.h"
+#include "ppp_lwip.h"
+#include "LWIPStack.h"
+
+namespace mbed {
+
+using rtos::Thread;
+using events::EventQueue;
+
+#if LWIP_PPP_API
+
+static EventQueue *event_queue;
+static Thread *event_thread;
+static volatile bool event_queued;
+static nsapi_error_t connect_error_code;
+
+// Just one interface for now
+static FileHandle *my_stream;
+static LWIP::Interface *my_interface;
+static ppp_pcb *my_ppp_pcb;
+static bool ppp_active = false;
+static bool blocking_connect = true;
+static const char *login;
+static const char *pwd;
+static sys_sem_t ppp_close_sem;
+static Callback<void(nsapi_event_t, intptr_t)> connection_status_cb;
+
+static EventQueue *prepare_event_queue()
+{
+    if (event_queue) {
+        return event_queue;
+    }
+
+    // Should be trying to get a global shared event queue here!
+    // Shouldn't have to be making a private thread!
+
+    // Only need to queue 2 events. new blows on failure.
+    event_queue = new EventQueue(2 * EVENTS_EVENT_SIZE, NULL);
+    event_thread = new Thread(osPriorityNormal, PPP_THREAD_STACK_SIZE);
+
+    if (event_thread->start(callback(event_queue, &EventQueue::dispatch_forever)) != osOK) {
+        delete event_thread;
+        delete event_queue;
+        return NULL;
+    }
+
+    return event_queue;
+}
+
+static u32_t ppp_output(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx)
+{
+    FileHandle *stream = my_stream;
+    if (!stream) {
+        return 0;
+    }
+
+    pollfh fhs;
+    fhs.fh = stream;
+    fhs.events = POLLOUT;
+
+    // LWIP expects us to block on write
+    // File handle will be in non-blocking mode, because of read events.
+    // Therefore must use poll to achieve the necessary block for writing.
+
+    uint32_t written = 0;
+    while (len != 0) {
+        // Block forever until we're selected - don't care about reason we wake;
+        // return from write should tell us what's up.
+        poll(&fhs, 1, -1);
+        // This write will be non-blocking, but blocking would be fine.
+        ssize_t ret = stream->write(data, len);
+        if (ret == -EAGAIN) {
+            continue;
+        } else if (ret < 0) {
+            break;
+        }
+        written += ret;
+        data += ret;
+        len -= ret;
+    }
+
+//    /tr_debug("> %ld bytes of data written\n", (long) written);
+
+    return written;
+}
+
+static void ppp_link_status(ppp_pcb *pcb, int err_code, void *ctx)
+{
+    nsapi_error_t mapped_err_code = NSAPI_ERROR_NO_CONNECTION;
+
+    switch(err_code) {
+        case PPPERR_NONE:
+            mapped_err_code = NSAPI_ERROR_OK;
+            tr_info("status_cb: Connected");
+#if PPP_IPV4_SUPPORT
+            tr_debug("   our_ipaddr  = %s", ipaddr_ntoa(&ppp_netif(pcb)->ip_addr));
+            tr_debug("   his_ipaddr  = %s", ipaddr_ntoa(&ppp_netif(pcb)->gw));
+            tr_debug("   netmask     = %s", ipaddr_ntoa(&ppp_netif(pcb)->netmask));
+#if LWIP_DNS
+            const ip_addr_t *ns;
+            ns = dns_getserver(0);
+            if (ns) {
+                tr_debug("   dns1        = %s", ipaddr_ntoa(ns));
+            }
+            ns = dns_getserver(1);
+            if (ns) {
+                tr_debug("   dns2        = %s", ipaddr_ntoa(ns));
+            }
+#endif /* LWIP_DNS */
+#endif /* PPP_IPV4_SUPPORT */
+#if PPP_IPV6_SUPPORT
+            tr_debug("   our6_ipaddr = %s", ip6addr_ntoa(netif_ip6_addr(ppp_netif(pcb), 0)));
+#endif /* PPP_IPV6_SUPPORT */
+            break;
+
+        case PPPERR_PARAM:
+            tr_info("status_cb: Invalid parameter");
+            break;
+
+        case PPPERR_OPEN:
+            tr_info("status_cb: Unable to open PPP session");
+            break;
+
+        case PPPERR_DEVICE:
+            tr_info("status_cb: Invalid I/O device for PPP");
+            break;
+
+        case PPPERR_ALLOC:
+            tr_info("status_cb: Unable to allocate resources");
+            break;
+
+        case PPPERR_USER:
+            tr_info("status_cb: User interrupt");
+            break;
+
+        case PPPERR_CONNECT:
+            tr_info("status_cb: Connection lost");
+            mapped_err_code = NSAPI_ERROR_CONNECTION_LOST;
+            break;
+
+        case PPPERR_AUTHFAIL:
+            tr_info("status_cb: Failed authentication challenge");
+            mapped_err_code = NSAPI_ERROR_AUTH_FAILURE;
+            break;
+
+        case PPPERR_PROTOCOL:
+            tr_info("status_cb: Failed to meet protocol");
+            break;
+
+        case PPPERR_PEERDEAD:
+            tr_info("status_cb: Connection timeout");
+            mapped_err_code = NSAPI_ERROR_CONNECTION_TIMEOUT;
+            break;
+
+        case PPPERR_IDLETIMEOUT:
+            tr_info("status_cb: Idle Timeout");
+            break;
+
+        case PPPERR_CONNECTTIME:
+            tr_info("status_cb: Max connect time reached");
+            break;
+
+        case PPPERR_LOOPBACK:
+            tr_info("status_cb: Loopback detected");
+            break;
+
+        default:
+            tr_info("status_cb: Unknown error code %d", err_code);
+            break;
+
+    }
+
+    if (err_code == PPPERR_NONE) {
+        /* status changes have to be reported */
+        if (connection_status_cb) {
+            connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_GLOBAL_UP);
+        }
+        return;
+    }
+
+    /* If some error happened, we need to properly shutdown the PPP interface  */
+    if (ppp_active) {
+        ppp_active = false;
+        connect_error_code = mapped_err_code;
+        sys_sem_signal(&ppp_close_sem);
+    }
+
+    /* Alright, PPP interface is down, we need to notify upper layer */
+    if (connection_status_cb) {
+        connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED);
+    }
+}
+
+static void handle_modem_hangup()
+{
+    if (my_ppp_pcb->phase != PPP_PHASE_DEAD) {
+        ppp_close(my_ppp_pcb, 1);
+    }
+}
+
+#if !PPP_INPROC_IRQ_SAFE
+#error "PPP_INPROC_IRQ_SAFE must be enabled"
+#endif
+static void ppp_input()
+{
+    // Allow new events from now, avoiding potential races around the read
+    event_queued = false;
+
+    if (!my_stream) {
+        return;
+    }
+
+    // Non-blocking error check handler
+    pollfh fhs;
+    fhs.fh = my_stream;
+    fhs.events = POLLIN;
+    poll(&fhs, 1, 0);
+    if (fhs.revents & (POLLHUP|POLLERR|POLLNVAL)) {
+        handle_modem_hangup();
+        return;
+    }
+
+    // Infinite loop, but we assume that we can read faster than the
+    // serial, so we will fairly rapidly hit -EAGAIN.
+    for (;;) {
+        u8_t buffer[16];
+        ssize_t len = my_stream->read(buffer, sizeof buffer);
+        if (len == -EAGAIN) {
+            break;
+        } else if (len <= 0) {
+            handle_modem_hangup();
+            return;
+        }
+        pppos_input(my_ppp_pcb, buffer, len);
+    }
+    return;
+}
+
+static void stream_cb() {
+    if (my_stream && !event_queued) {
+        event_queued = true;
+        if (event_queue->call(callback(ppp_input)) == 0) {
+            event_queued = false;
+        }
+    }
+}
+
+extern "C" err_t ppp_lwip_connect(void *pcb)
+{
+#if PPP_AUTH_SUPPORT
+   ppp_set_auth(my_ppp_pcb, PPPAUTHTYPE_ANY, login, pwd);
+#endif //PPP_AUTH_SUPPORT
+   ppp_active = true;
+   err_t ret = ppp_connect(my_ppp_pcb, 0);
+   // lwIP's ppp.txt says input must not be called until after connect
+   if (ret == ERR_OK) {
+       my_stream->sigio(callback(stream_cb));
+   } else {
+       ppp_active = false;
+   }
+   return ret;
+}
+
+extern "C" err_t ppp_lwip_disconnect(void *pcb)
+{
+    err_t ret = ERR_OK;
+    if (ppp_active) {
+        ret = ppp_close(my_ppp_pcb, 0);
+        if (ret == ERR_OK) {
+            /* close call made, now let's catch the response in the status callback */
+            sys_arch_sem_wait(&ppp_close_sem, 0);
+        }
+        ppp_active = false;
+    }
+    return ret;
+}
+
+extern "C" nsapi_error_t ppp_lwip_if_init(void *pcb, struct netif *netif, const nsapi_ip_stack_t stack)
+{
+    if (!prepare_event_queue()) {
+        return NSAPI_ERROR_NO_MEMORY;
+    }
+
+    if (!my_ppp_pcb) {
+        my_ppp_pcb = pppos_create(netif,
+                               ppp_output, ppp_link_status, NULL);
+        if (!my_ppp_pcb) {
+            return NSAPI_ERROR_DEVICE_ERROR;
+        }
+
+        sys_sem_new(&ppp_close_sem, 0);
+    }
+
+#if LWIP_IPV4
+    if (stack != IPV6_STACK) {
+        ppp_set_usepeerdns(my_ppp_pcb, true);
+    }
+#endif
+
+#if LWIP_IPV4 && LWIP_IPV6
+    if (stack == IPV4_STACK) {
+        my_ppp_pcb->ipv6cp_disabled = true;
+    } else if (stack == IPV6_STACK) {
+        my_ppp_pcb->ipcp_disabled = true;
+    }
+#endif
+
+    return NSAPI_ERROR_OK;
+}
+
+nsapi_error_t nsapi_ppp_error_code()
+{
+    return connect_error_code;
+}
+
+nsapi_error_t nsapi_ppp_set_blocking(bool blocking)
+{
+    blocking_connect = blocking;
+    return NSAPI_ERROR_OK;
+}
+
+nsapi_error_t nsapi_ppp_connect(FileHandle *stream, Callback<void(nsapi_event_t, intptr_t)> cb, const char *uname, const char *password, const nsapi_ip_stack_t stack)
+{
+    if (my_stream) {
+        return NSAPI_ERROR_PARAMETER;
+    }
+    my_stream = stream;
+    stream->set_blocking(false);
+    connection_status_cb = cb;
+    login = uname;
+    pwd = password;
+
+    nsapi_error_t retcode;
+
+    if (!my_interface) {
+        LWIP &lwip = LWIP::get_instance();
+        retcode = lwip._add_ppp_interface(stream, true, stack, &my_interface);
+        if (retcode != NSAPI_ERROR_OK) {
+            my_interface = NULL;
+            my_stream->set_blocking(true);
+            my_stream = NULL;
+            connection_status_cb = NULL;
+            return retcode;
+        }
+    }
+
+    // mustn't start calling input until after connect -
+    // attach deferred until ppp_lwip_connect, called from mbed_lwip_bringup
+    retcode = my_interface->bringup(false, NULL, NULL, NULL, stack, blocking_connect);
+
+    if (retcode != NSAPI_ERROR_OK) {
+        connection_status_cb = NULL;
+        my_stream->sigio(NULL);
+        my_stream->set_blocking(true);
+        my_stream = NULL;
+    }
+
+    if (retcode != NSAPI_ERROR_OK && connect_error_code != NSAPI_ERROR_OK) {
+        return connect_error_code;
+    } else {
+        return retcode;
+    }
+}
+
+nsapi_error_t nsapi_ppp_disconnect(FileHandle *stream)
+{
+    if (my_stream != stream) {
+        return NSAPI_ERROR_NO_CONNECTION;
+    }
+
+    nsapi_error_t retcode = my_interface->bringdown();
+
+    connection_status_cb = NULL;
+    /* Detach callbacks, and put handle back to default blocking mode */
+    my_stream->sigio(NULL);
+    my_stream->set_blocking(true);
+    my_stream = NULL;
+
+    return retcode;
+}
+
+NetworkStack *nsapi_ppp_get_stack()
+{
+    return &LWIP::get_instance();
+}
+
+const char *nsapi_ppp_get_ip_addr(FileHandle *stream)
+{
+    static char ip_addr[IPADDR_STRLEN_MAX];
+
+    if (stream == my_stream) {
+
+        if (my_interface->get_ip_address(ip_addr, IPADDR_STRLEN_MAX)) {
+            return ip_addr;
+        }
+    }
+
+    return NULL;
+}
+const char *nsapi_ppp_get_netmask(FileHandle *stream)
+{
+#if !LWIP_IPV4
+    return NULL;
+#endif
+
+    static char netmask[IPADDR_STRLEN_MAX];
+    if (stream == my_stream) {
+        if (my_interface->get_netmask(netmask, IPADDR_STRLEN_MAX)) {
+            return netmask;
+        }
+    }
+
+    return NULL;
+}
+const char *nsapi_ppp_get_gw_addr(FileHandle *stream)
+{
+#if !LWIP_IPV4
+    return NULL;
+#endif
+
+    static char gwaddr[IPADDR_STRLEN_MAX];
+    if (stream == my_stream) {
+        if (my_interface->get_gateway(gwaddr, IPADDR_STRLEN_MAX)) {
+            return gwaddr;
+        }
+    }
+
+    return NULL;
+}
+
+#endif /* LWIP_PPP_API */
+
+} // namespace mbed