diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/FILES b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/FILES
new file mode 100644
index 0000000..10115a7
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/FILES
@@ -0,0 +1,13 @@
+api/      - The code for the high-level wrapper API. Not needed if

+            you use the lowel-level call-back/raw API.

+

+core/     - The core of the TPC/IP stack; protocol implementations,

+            memory and buffer management, and the low-level raw API.

+

+include/  - lwIP include files.

+

+netif/    - Generic network interface device drivers are kept here,

+            as well as the ARP module.

+

+For more information on the various subdirectories, check the FILES

+file in each directory.

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/api_lib.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/api_lib.c
new file mode 100644
index 0000000..36d52f9
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/api_lib.c
@@ -0,0 +1,570 @@
+/**

+ * @file

+ * Sequential API External module

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+/* This is the part of the API that is linked with

+   the application */

+

+#include "lwip/opt.h"

+

+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/api.h"

+#include "lwip/tcpip.h"

+#include "lwip/memp.h"

+

+#include "lwip/ip.h"

+#include "lwip/raw.h"

+#include "lwip/udp.h"

+#include "lwip/tcp.h"

+

+#include <string.h>

+

+/**

+ * Create a new netconn (of a specific type) that has a callback function.

+ * The corresponding pcb is also created.

+ *

+ * @param t the type of 'connection' to create (@see enum netconn_type)

+ * @param proto the IP protocol for RAW IP pcbs

+ * @param callback a function to call on status changes (RX available, TX'ed)

+ * @return a newly allocated struct netconn or

+ *         NULL on memory error

+ */

+struct netconn*

+netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)

+{

+  struct netconn *conn;

+  struct api_msg msg;

+

+  conn = netconn_alloc(t, callback);

+  if (conn != NULL ) {

+    msg.function = do_newconn;

+    msg.msg.msg.n.proto = proto;

+    msg.msg.conn = conn;

+    TCPIP_APIMSG(&msg);

+

+    if (conn->err != ERR_OK) {

+      LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);

+      LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL);

+      LWIP_ASSERT("conn has no recvmbox", conn->recvmbox != SYS_MBOX_NULL);

+      LWIP_ASSERT("conn->acceptmbox shouldn't exist", conn->acceptmbox == SYS_MBOX_NULL);

+      sys_sem_free(conn->op_completed);

+      sys_mbox_free(conn->recvmbox);

+      memp_free(MEMP_NETCONN, conn);

+      return NULL;

+    }

+  }

+  return conn;

+}

+

+/**

+ * Close a netconn 'connection' and free its resources.

+ * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate

+ * after this returns.

+ *

+ * @param conn the netconn to delete

+ * @return ERR_OK if the connection was deleted

+ */

+err_t

+netconn_delete(struct netconn *conn)

+{

+  struct api_msg msg;

+

+  /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */

+  if (conn == NULL) {

+    return ERR_OK;

+  }

+

+  msg.function = do_delconn;

+  msg.msg.conn = conn;

+  tcpip_apimsg(&msg);

+

+  conn->pcb.tcp = NULL;

+  netconn_free(conn);

+

+  return ERR_OK;

+}

+

+/**

+ * Get the type of a netconn (as enum netconn_type).

+ *

+ * @param conn the netconn of which to get the type

+ * @return the netconn_type of conn

+ */

+enum netconn_type

+netconn_type(struct netconn *conn)

+{

+  LWIP_ERROR("netconn_type: invalid conn", (conn != NULL), return NETCONN_INVALID;);

+  return conn->type;

+}

+

+/**

+ * Get the local or remote IP address and port of a netconn.

+ * For RAW netconns, this returns the protocol instead of a port!

+ *

+ * @param conn the netconn to query

+ * @param addr a pointer to which to save the IP address

+ * @param port a pointer to which to save the port (or protocol for RAW)

+ * @param local 1 to get the local IP address, 0 to get the remote one

+ * @return ERR_CONN for invalid connections

+ *         ERR_OK if the information was retrieved

+ */

+err_t

+netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t local)

+{

+  struct api_msg msg;

+

+  LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);

+  LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);

+  LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);

+

+  msg.function = do_getaddr;

+  msg.msg.conn = conn;

+  msg.msg.msg.ad.ipaddr = addr;

+  msg.msg.msg.ad.port = port;

+  msg.msg.msg.ad.local = local;

+  TCPIP_APIMSG(&msg);

+

+  return conn->err;

+}

+

+/**

+ * Bind a netconn to a specific local IP address and port.

+ * Binding one netconn twice might not always be checked correctly!

+ *

+ * @param conn the netconn to bind

+ * @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY

+ *             to bind to all addresses)

+ * @param port the local port to bind the netconn to (not used for RAW)

+ * @return ERR_OK if bound, any other err_t on failure

+ */

+err_t

+netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port)

+{

+  struct api_msg msg;

+

+  LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);

+

+  msg.function = do_bind;

+  msg.msg.conn = conn;

+  msg.msg.msg.bc.ipaddr = addr;

+  msg.msg.msg.bc.port = port;

+  TCPIP_APIMSG(&msg);

+  return conn->err;

+}

+

+/**

+ * Connect a netconn to a specific remote IP address and port.

+ *

+ * @param conn the netconn to connect

+ * @param addr the remote IP address to connect to

+ * @param port the remote port to connect to (no used for RAW)

+ * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise

+ */

+err_t

+netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port)

+{

+  struct api_msg msg;

+

+  LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);

+

+  msg.function = do_connect;

+  msg.msg.conn = conn;

+  msg.msg.msg.bc.ipaddr = addr;

+  msg.msg.msg.bc.port = port;

+  /* This is the only function which need to not block tcpip_thread */

+  tcpip_apimsg(&msg);

+  return conn->err;

+}

+

+/**

+ * Disconnect a netconn from its current peer (only valid for UDP netconns).

+ *

+ * @param conn the netconn to disconnect

+ * @return TODO: return value is not set here...

+ */

+err_t

+netconn_disconnect(struct netconn *conn)

+{

+  struct api_msg msg;

+

+  LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);

+

+  msg.function = do_disconnect;

+  msg.msg.conn = conn;

+  TCPIP_APIMSG(&msg);

+  return conn->err;

+}

+

+/**

+ * Set a TCP netconn into listen mode

+ *

+ * @param conn the tcp netconn to set to listen mode

+ * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1

+ * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns

+ *         don't return any error (yet?))

+ */

+err_t

+netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)

+{

+  struct api_msg msg;

+

+  /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */

+  LWIP_UNUSED_ARG(backlog);

+

+  LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);

+

+  msg.function = do_listen;

+  msg.msg.conn = conn;

+#if TCP_LISTEN_BACKLOG

+  msg.msg.msg.lb.backlog = backlog;

+#endif /* TCP_LISTEN_BACKLOG */

+  TCPIP_APIMSG(&msg);

+  return conn->err;

+}

+

+/**

+ * Accept a new connection on a TCP listening netconn.

+ *

+ * @param conn the TCP listen netconn

+ * @return the newly accepted netconn or NULL on timeout

+ */

+struct netconn *

+netconn_accept(struct netconn *conn)

+{

+  struct netconn *newconn;

+

+  LWIP_ERROR("netconn_accept: invalid conn",       (conn != NULL),                      return NULL;);

+  LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return NULL;);

+

+#if LWIP_SO_RCVTIMEO

+  if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {

+    newconn = NULL;

+  } else

+#else

+  sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0);

+#endif /* LWIP_SO_RCVTIMEO*/

+  {

+    /* Register event with callback */

+    API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);

+

+#if TCP_LISTEN_BACKLOG

+    if (newconn != NULL) {

+      /* Let the stack know that we have accepted the connection. */

+      struct api_msg msg;

+      msg.function = do_recv;

+      msg.msg.conn = conn;

+      TCPIP_APIMSG(&msg);

+    }

+#endif /* TCP_LISTEN_BACKLOG */

+  }

+

+  return newconn;

+}

+

+/**

+ * Receive data (in form of a netbuf containing a packet buffer) from a netconn

+ *

+ * @param conn the netconn from which to receive data

+ * @return a new netbuf containing received data or NULL on memory error or timeout

+ */

+struct netbuf *

+netconn_recv(struct netconn *conn)

+{

+  struct api_msg msg;

+  struct netbuf *buf = NULL;

+  struct pbuf *p;

+  u16_t len;

+

+  LWIP_ERROR("netconn_recv: invalid conn",  (conn != NULL), return NULL;);

+

+  if (conn->recvmbox == SYS_MBOX_NULL) {

+    /* @todo: should calling netconn_recv on a TCP listen conn be fatal (ERR_CONN)?? */

+    /* TCP listen conns don't have a recvmbox! */

+    conn->err = ERR_CONN;

+    return NULL;

+  }

+

+  if (ERR_IS_FATAL(conn->err)) {

+    return NULL;

+  }

+

+  if (conn->type == NETCONN_TCP) {

+#if LWIP_TCP

+    if (conn->state == NETCONN_LISTEN) {

+      /* @todo: should calling netconn_recv on a TCP listen conn be fatal?? */

+      conn->err = ERR_CONN;

+      return NULL;

+    }

+

+    buf = memp_malloc(MEMP_NETBUF);

+

+    if (buf == NULL) {

+      conn->err = ERR_MEM;

+      return NULL;

+    }

+

+#if LWIP_SO_RCVTIMEO

+    if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {

+      conn->err = ERR_TIMEOUT;

+      p = NULL;

+    }

+#else

+    sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0);

+#endif /* LWIP_SO_RCVTIMEO*/

+

+    if (p != NULL) {

+      len = p->tot_len;

+      SYS_ARCH_DEC(conn->recv_avail, len);

+    } else {

+      len = 0;

+    }

+

+    /* Register event with callback */

+    API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);

+

+    /* If we are closed, we indicate that we no longer wish to use the socket */

+    if (p == NULL) {

+      memp_free(MEMP_NETBUF, buf);

+      /* Avoid to lose any previous error code */

+      if (conn->err == ERR_OK) {

+        conn->err = ERR_CLSD;

+      }

+      return NULL;

+    }

+

+    buf->p = p;

+    buf->ptr = p;

+    buf->port = 0;

+    buf->addr = NULL;

+

+    /* Let the stack know that we have taken the data. */

+    msg.function = do_recv;

+    msg.msg.conn = conn;

+    if (buf != NULL) {

+      msg.msg.msg.r.len = buf->p->tot_len;

+    } else {

+      msg.msg.msg.r.len = 1;

+    }

+    TCPIP_APIMSG(&msg);

+#endif /* LWIP_TCP */

+  } else {

+#if (LWIP_UDP || LWIP_RAW)

+#if LWIP_SO_RCVTIMEO

+    if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {

+      buf = NULL;

+    }

+#else

+    sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, 0);

+#endif /* LWIP_SO_RCVTIMEO*/

+    if (buf!=NULL) {

+      SYS_ARCH_DEC(conn->recv_avail, buf->p->tot_len);

+      /* Register event with callback */

+      API_EVENT(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);

+    }

+#endif /* (LWIP_UDP || LWIP_RAW) */

+  }

+

+  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));

+

+  return buf;

+}

+

+/**

+ * Send data (in form of a netbuf) to a specific remote IP address and port.

+ * Only to be used for UDP and RAW netconns (not TCP).

+ *

+ * @param conn the netconn over which to send data

+ * @param buf a netbuf containing the data to send

+ * @param addr the remote IP address to which to send the data

+ * @param port the remote port to which to send the data

+ * @return ERR_OK if data was sent, any other err_t on error

+ */

+err_t

+netconn_sendto(struct netconn *conn, struct netbuf *buf, struct ip_addr *addr, u16_t port)

+{

+  if (buf != NULL) {

+    buf->addr = addr;

+    buf->port = port;

+    return netconn_send(conn, buf);

+  }

+  return ERR_VAL;

+}

+

+/**

+ * Send data over a UDP or RAW netconn (that is already connected).

+ *

+ * @param conn the UDP or RAW netconn over which to send data

+ * @param buf a netbuf containing the data to send

+ * @return ERR_OK if data was sent, any other err_t on error

+ */

+err_t

+netconn_send(struct netconn *conn, struct netbuf *buf)

+{

+  struct api_msg msg;

+

+  LWIP_ERROR("netconn_send: invalid conn",  (conn != NULL), return ERR_ARG;);

+

+  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len));

+  msg.function = do_send;

+  msg.msg.conn = conn;

+  msg.msg.msg.b = buf;

+  TCPIP_APIMSG(&msg);

+  return conn->err;

+}

+

+/**

+ * Send data over a TCP netconn.

+ *

+ * @param conn the TCP netconn over which to send data

+ * @param dataptr pointer to the application buffer that contains the data to send

+ * @param size size of the application data to send

+ * @param apiflags combination of following flags :

+ * - NETCONN_COPY (0x01) data will be copied into memory belonging to the stack

+ * - NETCONN_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent

+ * @return ERR_OK if data was sent, any other err_t on error

+ */

+err_t

+netconn_write(struct netconn *conn, const void *dataptr, int size, u8_t apiflags)

+{

+  struct api_msg msg;

+

+  LWIP_ERROR("netconn_write: invalid conn",  (conn != NULL), return ERR_ARG;);

+  LWIP_ERROR("netconn_write: invalid conn->type",  (conn->type == NETCONN_TCP), return ERR_VAL;);

+

+  msg.function = do_write;

+  msg.msg.conn = conn;

+  msg.msg.msg.w.dataptr = dataptr;

+  msg.msg.msg.w.apiflags = apiflags;

+  msg.msg.msg.w.len = size;

+  /* For locking the core: this _can_ be delayed on low memory/low send buffer,

+     but if it is, this is done inside api_msg.c:do_write(), so we can use the

+     non-blocking version here. */

+  TCPIP_APIMSG(&msg);

+  return conn->err;

+}

+

+/**

+ * Close a TCP netconn (doesn't delete it).

+ *

+ * @param conn the TCP netconn to close

+ * @return ERR_OK if the netconn was closed, any other err_t on error

+ */

+err_t

+netconn_close(struct netconn *conn)

+{

+  struct api_msg msg;

+

+  LWIP_ERROR("netconn_close: invalid conn",  (conn != NULL), return ERR_ARG;);

+

+  msg.function = do_close;

+  msg.msg.conn = conn;

+  tcpip_apimsg(&msg);

+  return conn->err;

+}

+

+#if LWIP_IGMP

+/**

+ * Join multicast groups for UDP netconns.

+ *

+ * @param conn the UDP netconn for which to change multicast addresses

+ * @param multiaddr IP address of the multicast group to join or leave

+ * @param interface the IP address of the network interface on which to send

+ *                  the igmp message

+ * @param join_or_leave flag whether to send a join- or leave-message

+ * @return ERR_OK if the action was taken, any err_t on error

+ */

+err_t

+netconn_join_leave_group(struct netconn *conn,

+                         struct ip_addr *multiaddr,

+                         struct ip_addr *interface,

+                         enum netconn_igmp join_or_leave)

+{

+  struct api_msg msg;

+

+  LWIP_ERROR("netconn_join_leave_group: invalid conn",  (conn != NULL), return ERR_ARG;);

+

+  msg.function = do_join_leave_group;

+  msg.msg.conn = conn;

+  msg.msg.msg.jl.multiaddr = multiaddr;

+  msg.msg.msg.jl.interface = interface;

+  msg.msg.msg.jl.join_or_leave = join_or_leave;

+  TCPIP_APIMSG(&msg);

+  return conn->err;

+}

+#endif /* LWIP_IGMP */

+

+#if LWIP_DNS

+/**

+ * Execute a DNS query, only one IP address is returned

+ *

+ * @param name a string representation of the DNS host name to query

+ * @param addr a preallocated struct ip_addr where to store the resolved IP address

+ * @return ERR_OK: resolving succeeded

+ *         ERR_MEM: memory error, try again later

+ *         ERR_ARG: dns client not initialized or invalid hostname

+ *         ERR_VAL: dns server response was invalid

+ */

+err_t

+netconn_gethostbyname(const char *name, struct ip_addr *addr)

+{

+  struct dns_api_msg msg;

+  err_t err;

+  sys_sem_t sem;

+

+  LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);

+  LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);

+

+  sem = sys_sem_new(0);

+  if (sem == SYS_SEM_NULL) {

+    return ERR_MEM;

+  }

+

+  msg.name = name;

+  msg.addr = addr;

+  msg.err = &err;

+  msg.sem = sem;

+

+  tcpip_callback(do_gethostbyname, &msg);

+  sys_sem_wait(sem);

+  sys_sem_free(sem);

+

+  return err;

+}

+#endif /* LWIP_DNS*/

+

+#endif /* LWIP_NETCONN */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/api_msg.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/api_msg.c
new file mode 100644
index 0000000..f08177c
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/api_msg.c
@@ -0,0 +1,1202 @@
+/**

+ * @file

+ * Sequential API Internal module

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/api_msg.h"

+

+#include "lwip/ip.h"

+#include "lwip/udp.h"

+#include "lwip/tcp.h"

+#include "lwip/raw.h"

+

+#include "lwip/memp.h"

+#include "lwip/tcpip.h"

+#include "lwip/igmp.h"

+#include "lwip/dns.h"

+

+/* forward declarations */

+#if LWIP_TCP

+static err_t do_writemore(struct netconn *conn);

+static void do_close_internal(struct netconn *conn);

+#endif

+

+#if LWIP_RAW

+/**

+ * Receive callback function for RAW netconns.

+ * Doesn't 'eat' the packet, only references it and sends it to

+ * conn->recvmbox

+ *

+ * @see raw.h (struct raw_pcb.recv) for parameters and return value

+ */

+static u8_t

+recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,

+    struct ip_addr *addr)

+{

+  struct pbuf *q;

+  struct netbuf *buf;

+  struct netconn *conn;

+#if LWIP_SO_RCVBUF

+  int recv_avail;

+#endif /* LWIP_SO_RCVBUF */

+

+  LWIP_UNUSED_ARG(addr);

+  conn = arg;

+

+#if LWIP_SO_RCVBUF

+  SYS_ARCH_GET(conn->recv_avail, recv_avail);

+  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) &&

+      ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) {

+#else  /* LWIP_SO_RCVBUF */

+  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) {

+#endif /* LWIP_SO_RCVBUF */

+    /* copy the whole packet into new pbufs */

+    q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);

+    if(q != NULL) {

+      if (pbuf_copy(q, p) != ERR_OK) {

+        pbuf_free(q);

+        q = NULL;

+      }

+    }

+

+    if(q != NULL) {

+      buf = memp_malloc(MEMP_NETBUF);

+      if (buf == NULL) {

+        pbuf_free(q);

+        return 0;

+      }

+

+      buf->p = q;

+      buf->ptr = q;

+      buf->addr = &(((struct ip_hdr*)(q->payload))->src);

+      buf->port = pcb->protocol;

+

+      SYS_ARCH_INC(conn->recv_avail, q->tot_len);

+      /* Register event with callback */

+      API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len);

+      if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {

+        netbuf_delete(buf);

+      }

+    }

+  }

+

+  return 0; /* do not eat the packet */

+}

+#endif /* LWIP_RAW*/

+

+#if LWIP_UDP

+/**

+ * Receive callback function for UDP netconns.

+ * Posts the packet to conn->recvmbox or deletes it on memory error.

+ *

+ * @see udp.h (struct udp_pcb.recv) for parameters

+ */

+static void

+recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,

+   struct ip_addr *addr, u16_t port)

+{

+  struct netbuf *buf;

+  struct netconn *conn;

+#if LWIP_SO_RCVBUF

+  int recv_avail;

+#endif /* LWIP_SO_RCVBUF */

+

+  LWIP_UNUSED_ARG(pcb); /* only used for asserts... */

+  LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);

+  LWIP_ASSERT("recv_udp must have an argument", arg != NULL);

+  conn = arg;

+  LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);

+

+#if LWIP_SO_RCVBUF

+  SYS_ARCH_GET(conn->recv_avail, recv_avail);

+  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) ||

+      ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {

+#else  /* LWIP_SO_RCVBUF */

+  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {

+#endif /* LWIP_SO_RCVBUF */

+    pbuf_free(p);

+    return;

+  }

+

+  buf = memp_malloc(MEMP_NETBUF);

+  if (buf == NULL) {

+    pbuf_free(p);

+    return;

+  } else {

+    buf->p = p;

+    buf->ptr = p;

+    buf->addr = addr;

+    buf->port = port;

+  }

+

+  SYS_ARCH_INC(conn->recv_avail, p->tot_len);

+  /* Register event with callback */

+  API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len);

+  if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {

+    netbuf_delete(buf);

+    return;

+  }

+}

+#endif /* LWIP_UDP */

+

+#if LWIP_TCP

+/**

+ * Receive callback function for TCP netconns.

+ * Posts the packet to conn->recvmbox, but doesn't delete it on errors.

+ *

+ * @see tcp.h (struct tcp_pcb.recv) for parameters and return value

+ */

+static err_t

+recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)

+{

+  struct netconn *conn;

+  u16_t len;

+

+  LWIP_UNUSED_ARG(pcb);

+  LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);

+  LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);

+  conn = arg;

+  LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);

+

+  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {

+    return ERR_VAL;

+  }

+

+  conn->err = err;

+  if (p != NULL) {

+    len = p->tot_len;

+    SYS_ARCH_INC(conn->recv_avail, len);

+  } else {

+    len = 0;

+  }

+  /* Register event with callback */

+  API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);

+  if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {

+    return ERR_MEM;

+  }

+

+  return ERR_OK;

+}

+

+/**

+ * Poll callback function for TCP netconns.

+ * Wakes up an application thread that waits for a connection to close

+ * or data to be sent. The application thread then takes the

+ * appropriate action to go on.

+ *

+ * Signals the conn->sem.

+ * netconn_close waits for conn->sem if closing failed.

+ *

+ * @see tcp.h (struct tcp_pcb.poll) for parameters and return value

+ */

+static err_t

+poll_tcp(void *arg, struct tcp_pcb *pcb)

+{

+  struct netconn *conn = arg;

+

+  LWIP_UNUSED_ARG(pcb);

+  LWIP_ASSERT("conn != NULL", (conn != NULL));

+

+  if (conn->state == NETCONN_WRITE) {

+    do_writemore(conn);

+  } else if (conn->state == NETCONN_CLOSE) {

+    do_close_internal(conn);

+  }

+

+  return ERR_OK;

+}

+

+/**

+ * Sent callback function for TCP netconns.

+ * Signals the conn->sem and calls API_EVENT.

+ * netconn_write waits for conn->sem if send buffer is low.

+ *

+ * @see tcp.h (struct tcp_pcb.sent) for parameters and return value

+ */

+static err_t

+sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)

+{

+  struct netconn *conn = arg;

+

+  LWIP_UNUSED_ARG(pcb);

+  LWIP_ASSERT("conn != NULL", (conn != NULL));

+

+  if (conn->state == NETCONN_WRITE) {

+    LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);

+    do_writemore(conn);

+  } else if (conn->state == NETCONN_CLOSE) {

+    do_close_internal(conn);

+  }

+

+  if (conn) {

+    if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) {

+      API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);

+    }

+  }

+

+  return ERR_OK;

+}

+

+/**

+ * Error callback function for TCP netconns.

+ * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.

+ * The application thread has then to decide what to do.

+ *

+ * @see tcp.h (struct tcp_pcb.err) for parameters

+ */

+static void

+err_tcp(void *arg, err_t err)

+{

+  struct netconn *conn;

+

+  conn = arg;

+  LWIP_ASSERT("conn != NULL", (conn != NULL));

+

+  conn->pcb.tcp = NULL;

+

+  conn->err = err;

+  if (conn->recvmbox != SYS_MBOX_NULL) {

+    /* Register event with callback */

+    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);

+    sys_mbox_post(conn->recvmbox, NULL);

+  }

+  if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) {

+    conn->state = NETCONN_NONE;

+    sys_sem_signal(conn->op_completed);

+  }

+  if (conn->acceptmbox != SYS_MBOX_NULL) {

+    /* Register event with callback */

+    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);

+    sys_mbox_post(conn->acceptmbox, NULL);

+  }

+  if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {

+    /* calling do_writemore/do_close_internal is not necessary

+       since the pcb has already been deleted! */

+    conn->state = NETCONN_NONE;

+    /* wake up the waiting task */

+    sys_sem_signal(conn->op_completed);

+  }

+}

+

+/**

+ * Setup a tcp_pcb with the correct callback function pointers

+ * and their arguments.

+ *

+ * @param conn the TCP netconn to setup

+ */

+static void

+setup_tcp(struct netconn *conn)

+{

+  struct tcp_pcb *pcb;

+

+  pcb = conn->pcb.tcp;

+  tcp_arg(pcb, conn);

+  tcp_recv(pcb, recv_tcp);

+  tcp_sent(pcb, sent_tcp);

+  tcp_poll(pcb, poll_tcp, 4);

+  tcp_err(pcb, err_tcp);

+}

+

+/**

+ * Accept callback function for TCP netconns.

+ * Allocates a new netconn and posts that to conn->acceptmbox.

+ *

+ * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value

+ */

+static err_t

+accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)

+{

+  struct netconn *newconn;

+  struct netconn *conn;

+

+#if API_MSG_DEBUG

+#if TCP_DEBUG

+  tcp_debug_print_state(newpcb->state);

+#endif /* TCP_DEBUG */

+#endif /* API_MSG_DEBUG */

+  conn = (struct netconn *)arg;

+

+  LWIP_ERROR("accept_function: invalid conn->acceptmbox",

+             conn->acceptmbox != SYS_MBOX_NULL, return ERR_VAL;);

+

+  /* We have to set the callback here even though

+   * the new socket is unknown. conn->socket is marked as -1. */

+  newconn = netconn_alloc(conn->type, conn->callback);

+  if (newconn == NULL) {

+    return ERR_MEM;

+  }

+  newconn->pcb.tcp = newpcb;

+  setup_tcp(newconn);

+  newconn->err = err;

+  /* Register event with callback */

+  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);

+

+  if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {

+    /* When returning != ERR_OK, the connection is aborted in tcp_process(),

+       so do nothing here! */

+    newconn->pcb.tcp = NULL;

+    netconn_free(newconn);

+    return ERR_MEM;

+  }

+  return ERR_OK;

+}

+#endif /* LWIP_TCP */

+

+/**

+ * Create a new pcb of a specific type.

+ * Called from do_newconn().

+ *

+ * @param msg the api_msg_msg describing the connection type

+ * @return msg->conn->err, but the return value is currently ignored

+ */

+static err_t

+pcb_new(struct api_msg_msg *msg)

+{

+   msg->conn->err = ERR_OK;

+

+   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);

+

+   /* Allocate a PCB for this connection */

+   switch(NETCONNTYPE_GROUP(msg->conn->type)) {

+#if LWIP_RAW

+   case NETCONN_RAW:

+     msg->conn->pcb.raw = raw_new(msg->msg.n.proto);

+     if(msg->conn->pcb.raw == NULL) {

+       msg->conn->err = ERR_MEM;

+       break;

+     }

+     raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);

+     break;

+#endif /* LWIP_RAW */

+#if LWIP_UDP

+   case NETCONN_UDP:

+     msg->conn->pcb.udp = udp_new();

+     if(msg->conn->pcb.udp == NULL) {

+       msg->conn->err = ERR_MEM;

+       break;

+     }

+#if LWIP_UDPLITE

+     if (msg->conn->type==NETCONN_UDPLITE) {

+       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);

+     }

+#endif /* LWIP_UDPLITE */

+     if (msg->conn->type==NETCONN_UDPNOCHKSUM) {

+       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);

+     }

+     udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);

+     break;

+#endif /* LWIP_UDP */

+#if LWIP_TCP

+   case NETCONN_TCP:

+     msg->conn->pcb.tcp = tcp_new();

+     if(msg->conn->pcb.tcp == NULL) {

+       msg->conn->err = ERR_MEM;

+       break;

+     }

+     setup_tcp(msg->conn);

+     break;

+#endif /* LWIP_TCP */

+   default:

+     /* Unsupported netconn type, e.g. protocol disabled */

+     msg->conn->err = ERR_VAL;

+     break;

+   }

+

+  return msg->conn->err;

+}

+

+/**

+ * Create a new pcb of a specific type inside a netconn.

+ * Called from netconn_new_with_proto_and_callback.

+ *

+ * @param msg the api_msg_msg describing the connection type

+ */

+void

+do_newconn(struct api_msg_msg *msg)

+{

+   if(msg->conn->pcb.tcp == NULL) {

+     pcb_new(msg);

+   }

+   /* Else? This "new" connection already has a PCB allocated. */

+   /* Is this an error condition? Should it be deleted? */

+   /* We currently just are happy and return. */

+

+   TCPIP_APIMSG_ACK(msg);

+}

+

+/**

+ * Create a new netconn (of a specific type) that has a callback function.

+ * The corresponding pcb is NOT created!

+ *

+ * @param t the type of 'connection' to create (@see enum netconn_type)

+ * @param proto the IP protocol for RAW IP pcbs

+ * @param callback a function to call on status changes (RX available, TX'ed)

+ * @return a newly allocated struct netconn or

+ *         NULL on memory error

+ */

+struct netconn*

+netconn_alloc(enum netconn_type t, netconn_callback callback)

+{

+  struct netconn *conn;

+  int size;

+

+  conn = memp_malloc(MEMP_NETCONN);

+  if (conn == NULL) {

+    return NULL;

+  }

+

+  conn->err = ERR_OK;

+  conn->type = t;

+  conn->pcb.tcp = NULL;

+

+#if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \

+    (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE)

+  size = DEFAULT_RAW_RECVMBOX_SIZE;

+#else

+  switch(NETCONNTYPE_GROUP(t)) {

+#if LWIP_RAW

+  case NETCONN_RAW:

+    size = DEFAULT_RAW_RECVMBOX_SIZE;

+    break;

+#endif /* LWIP_RAW */

+#if LWIP_UDP

+  case NETCONN_UDP:

+    size = DEFAULT_UDP_RECVMBOX_SIZE;

+    break;

+#endif /* LWIP_UDP */

+#if LWIP_TCP

+  case NETCONN_TCP:

+    size = DEFAULT_TCP_RECVMBOX_SIZE;

+    break;

+#endif /* LWIP_TCP */

+  default:

+    LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);

+    break;

+  }

+#endif

+

+  if ((conn->op_completed = sys_sem_new(0)) == SYS_SEM_NULL) {

+    memp_free(MEMP_NETCONN, conn);

+    return NULL;

+  }

+  if ((conn->recvmbox = sys_mbox_new(size)) == SYS_MBOX_NULL) {

+    sys_sem_free(conn->op_completed);

+    memp_free(MEMP_NETCONN, conn);

+    return NULL;

+  }

+

+  conn->acceptmbox   = SYS_MBOX_NULL;

+  conn->state        = NETCONN_NONE;

+  /* initialize socket to -1 since 0 is a valid socket */

+  conn->socket       = -1;

+  conn->callback     = callback;

+  conn->recv_avail   = 0;

+#if LWIP_SO_RCVTIMEO

+  conn->recv_timeout = 0;

+#endif /* LWIP_SO_RCVTIMEO */

+#if LWIP_SO_RCVBUF

+  conn->recv_bufsize = INT_MAX;

+#endif /* LWIP_SO_RCVBUF */

+  return conn;

+}

+

+/**

+ * Delete a netconn and all its resources.

+ * The pcb is NOT freed (since we might not be in the right thread context do this).

+ *

+ * @param conn the netconn to free

+ */

+void

+netconn_free(struct netconn *conn)

+{

+  void *mem;

+  LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);

+

+  /* Drain the recvmbox. */

+  if (conn->recvmbox != SYS_MBOX_NULL) {

+    while (sys_mbox_tryfetch(conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {

+      if (conn->type == NETCONN_TCP) {

+        if(mem != NULL) {

+          pbuf_free((struct pbuf *)mem);

+        }

+      } else {

+        netbuf_delete((struct netbuf *)mem);

+      }

+    }

+    sys_mbox_free(conn->recvmbox);

+    conn->recvmbox = SYS_MBOX_NULL;

+  }

+

+  /* Drain the acceptmbox. */

+  if (conn->acceptmbox != SYS_MBOX_NULL) {

+    while (sys_mbox_tryfetch(conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {

+      netconn_delete((struct netconn *)mem);

+    }

+    sys_mbox_free(conn->acceptmbox);

+    conn->acceptmbox = SYS_MBOX_NULL;

+  }

+

+  sys_sem_free(conn->op_completed);

+  conn->op_completed = SYS_SEM_NULL;

+

+  memp_free(MEMP_NETCONN, conn);

+}

+

+#if LWIP_TCP

+/**

+ * Internal helper function to close a TCP netconn: since this sometimes

+ * doesn't work at the first attempt, this function is called from multiple

+ * places.

+ *

+ * @param conn the TCP netconn to close

+ */

+static void

+do_close_internal(struct netconn *conn)

+{

+  err_t err;

+

+  LWIP_ASSERT("invalid conn", (conn != NULL));

+  LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));

+  LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));

+  LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));

+

+  /* Set back some callback pointers */

+  if (conn->pcb.tcp->state == LISTEN) {

+    tcp_arg(conn->pcb.tcp, NULL);

+    tcp_accept(conn->pcb.tcp, NULL);

+  } else {

+    tcp_recv(conn->pcb.tcp, NULL);

+  }

+  /* Try to close the connection */

+  err = tcp_close(conn->pcb.tcp);

+  if (err == ERR_OK) {

+    /* Closing succeeded */

+    conn->state = NETCONN_NONE;

+    /* Set back some callback pointers as conn is going away */

+    tcp_err(conn->pcb.tcp, NULL);

+    tcp_poll(conn->pcb.tcp, NULL, 4);

+    tcp_sent(conn->pcb.tcp, NULL);

+    tcp_recv(conn->pcb.tcp, NULL);

+    tcp_arg(conn->pcb.tcp, NULL);

+    conn->pcb.tcp = NULL;

+    conn->err = ERR_OK;

+    /* Trigger select() in socket layer. This send should something else so the

+       errorfd is set, not the read and write fd! */

+    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);

+    API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);

+    /* wake up the application task */

+    sys_sem_signal(conn->op_completed);

+  }

+  /* If closing didn't succeed, we get called again either

+     from poll_tcp or from sent_tcp */

+}

+#endif /* LWIP_TCP */

+

+/**

+ * Delete the pcb inside a netconn.

+ * Called from netconn_delete.

+ *

+ * @param msg the api_msg_msg pointing to the connection

+ */

+void

+do_delconn(struct api_msg_msg *msg)

+{

+  if (msg->conn->pcb.tcp != NULL) {

+    switch (NETCONNTYPE_GROUP(msg->conn->type)) {

+#if LWIP_RAW

+    case NETCONN_RAW:

+      raw_remove(msg->conn->pcb.raw);

+      break;

+#endif /* LWIP_RAW */

+#if LWIP_UDP

+    case NETCONN_UDP:

+      msg->conn->pcb.udp->recv_arg = NULL;

+      udp_remove(msg->conn->pcb.udp);

+      break;

+#endif /* LWIP_UDP */

+#if LWIP_TCP

+    case NETCONN_TCP:

+      msg->conn->state = NETCONN_CLOSE;

+      do_close_internal(msg->conn);

+      /* API_EVENT is called inside do_close_internal, before releasing

+         the application thread, so we can return at this point! */

+      return;

+#endif /* LWIP_TCP */

+    default:

+      break;

+    }

+  }

+  /* tcp netconns don't come here! */

+

+  /* Trigger select() in socket layer. This send should something else so the

+     errorfd is set, not the read and write fd! */

+  API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);

+  API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);

+

+  if (msg->conn->op_completed != SYS_SEM_NULL) {

+    sys_sem_signal(msg->conn->op_completed);

+  }

+}

+

+/**

+ * Bind a pcb contained in a netconn

+ * Called from netconn_bind.

+ *

+ * @param msg the api_msg_msg pointing to the connection and containing

+ *            the IP address and port to bind to

+ */

+void

+do_bind(struct api_msg_msg *msg)

+{

+  if (!ERR_IS_FATAL(msg->conn->err)) {

+    if (msg->conn->pcb.tcp != NULL) {

+      switch (NETCONNTYPE_GROUP(msg->conn->type)) {

+#if LWIP_RAW

+      case NETCONN_RAW:

+        msg->conn->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);

+        break;

+#endif /* LWIP_RAW */

+#if LWIP_UDP

+      case NETCONN_UDP:

+        msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);

+        break;

+#endif /* LWIP_UDP */

+#if LWIP_TCP

+      case NETCONN_TCP:

+        msg->conn->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);

+        break;

+#endif /* LWIP_TCP */

+      default:

+        break;

+      }

+    } else {

+      /* msg->conn->pcb is NULL */

+      msg->conn->err = ERR_VAL;

+    }

+  }

+  TCPIP_APIMSG_ACK(msg);

+}

+

+#if LWIP_TCP

+/**

+ * TCP callback function if a connection (opened by tcp_connect/do_connect) has

+ * been established (or reset by the remote host).

+ *

+ * @see tcp.h (struct tcp_pcb.connected) for parameters and return values

+ */

+static err_t

+do_connected(void *arg, struct tcp_pcb *pcb, err_t err)

+{

+  struct netconn *conn;

+

+  LWIP_UNUSED_ARG(pcb);

+

+  conn = arg;

+

+  if (conn == NULL) {

+    return ERR_VAL;

+  }

+

+  conn->err = err;

+  if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {

+    setup_tcp(conn);

+  }

+  conn->state = NETCONN_NONE;

+  sys_sem_signal(conn->op_completed);

+  return ERR_OK;

+}

+#endif /* LWIP_TCP */

+

+/**

+ * Connect a pcb contained inside a netconn

+ * Called from netconn_connect.

+ *

+ * @param msg the api_msg_msg pointing to the connection and containing

+ *            the IP address and port to connect to

+ */

+void

+do_connect(struct api_msg_msg *msg)

+{

+  if (msg->conn->pcb.tcp == NULL) {

+    sys_sem_signal(msg->conn->op_completed);

+    return;

+  }

+

+  switch (NETCONNTYPE_GROUP(msg->conn->type)) {

+#if LWIP_RAW

+  case NETCONN_RAW:

+    msg->conn->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);

+    sys_sem_signal(msg->conn->op_completed);

+    break;

+#endif /* LWIP_RAW */

+#if LWIP_UDP

+  case NETCONN_UDP:

+    msg->conn->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);

+    sys_sem_signal(msg->conn->op_completed);

+    break;

+#endif /* LWIP_UDP */

+#if LWIP_TCP

+  case NETCONN_TCP:

+    msg->conn->state = NETCONN_CONNECT;

+    setup_tcp(msg->conn);

+    msg->conn->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,

+                                 do_connected);

+    /* sys_sem_signal() is called from do_connected (or err_tcp()),

+     * when the connection is established! */

+    break;

+#endif /* LWIP_TCP */

+  default:

+    break;

+  }

+}

+

+/**

+ * Connect a pcb contained inside a netconn

+ * Only used for UDP netconns.

+ * Called from netconn_disconnect.

+ *

+ * @param msg the api_msg_msg pointing to the connection to disconnect

+ */

+void

+do_disconnect(struct api_msg_msg *msg)

+{

+#if LWIP_UDP

+  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {

+    udp_disconnect(msg->conn->pcb.udp);

+  }

+#endif /* LWIP_UDP */

+  TCPIP_APIMSG_ACK(msg);

+}

+

+/**

+ * Set a TCP pcb contained in a netconn into listen mode

+ * Called from netconn_listen.

+ *

+ * @param msg the api_msg_msg pointing to the connection

+ */

+void

+do_listen(struct api_msg_msg *msg)

+{

+#if LWIP_TCP

+  if (!ERR_IS_FATAL(msg->conn->err)) {

+    if (msg->conn->pcb.tcp != NULL) {

+      if (msg->conn->type == NETCONN_TCP) {

+        if (msg->conn->pcb.tcp->state == CLOSED) {

+#if TCP_LISTEN_BACKLOG

+          struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);

+#else  /* TCP_LISTEN_BACKLOG */

+          struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);

+#endif /* TCP_LISTEN_BACKLOG */

+          if (lpcb == NULL) {

+            msg->conn->err = ERR_MEM;

+          } else {

+            /* delete the recvmbox and allocate the acceptmbox */

+            if (msg->conn->recvmbox != SYS_MBOX_NULL) {

+              /** @todo: should we drain the recvmbox here? */

+              sys_mbox_free(msg->conn->recvmbox);

+              msg->conn->recvmbox = SYS_MBOX_NULL;

+            }

+            if (msg->conn->acceptmbox == SYS_MBOX_NULL) {

+              if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) {

+                msg->conn->err = ERR_MEM;

+              }

+            }

+            if (msg->conn->err == ERR_OK) {

+              msg->conn->state = NETCONN_LISTEN;

+              msg->conn->pcb.tcp = lpcb;

+              tcp_arg(msg->conn->pcb.tcp, msg->conn);

+              tcp_accept(msg->conn->pcb.tcp, accept_function);

+            }

+          }

+        } else {

+          msg->conn->err = ERR_CONN;

+        }

+      }

+    }

+  }

+#endif /* LWIP_TCP */

+  TCPIP_APIMSG_ACK(msg);

+}

+

+/**

+ * Send some data on a RAW or UDP pcb contained in a netconn

+ * Called from netconn_send

+ *

+ * @param msg the api_msg_msg pointing to the connection

+ */

+void

+do_send(struct api_msg_msg *msg)

+{

+  if (!ERR_IS_FATAL(msg->conn->err)) {

+    if (msg->conn->pcb.tcp != NULL) {

+      switch (NETCONNTYPE_GROUP(msg->conn->type)) {

+#if LWIP_RAW

+      case NETCONN_RAW:

+        if (msg->msg.b->addr == NULL) {

+          msg->conn->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);

+        } else {

+          msg->conn->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr);

+        }

+        break;

+#endif

+#if LWIP_UDP

+      case NETCONN_UDP:

+        if (msg->msg.b->addr == NULL) {

+          msg->conn->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);

+        } else {

+          msg->conn->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port);

+        }

+        break;

+#endif /* LWIP_UDP */

+      default:

+        break;

+      }

+    }

+  }

+  TCPIP_APIMSG_ACK(msg);

+}

+

+/**

+ * Recv some data from a RAW or UDP pcb contained in a netconn

+ * Called from netconn_recv

+ *

+ * @param msg the api_msg_msg pointing to the connection

+ */

+void

+do_recv(struct api_msg_msg *msg)

+{

+#if LWIP_TCP

+  if (!ERR_IS_FATAL(msg->conn->err)) {

+    if (msg->conn->pcb.tcp != NULL) {

+      if (msg->conn->type == NETCONN_TCP) {

+#if TCP_LISTEN_BACKLOG

+        if (msg->conn->pcb.tcp->state == LISTEN) {

+          tcp_accepted(msg->conn->pcb.tcp);

+        } else

+#endif /* TCP_LISTEN_BACKLOG */

+        {

+          tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len);

+        }

+      }

+    }

+  }

+#endif /* LWIP_TCP */

+  TCPIP_APIMSG_ACK(msg);

+}

+

+#if LWIP_TCP

+/**

+ * See if more data needs to be written from a previous call to netconn_write.

+ * Called initially from do_write. If the first call can't send all data

+ * (because of low memory or empty send-buffer), this function is called again

+ * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the

+ * blocking application thread (waiting in netconn_write) is released.

+ *

+ * @param conn netconn (that is currently in state NETCONN_WRITE) to process

+ * @return ERR_OK

+ *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished

+ */

+static err_t

+do_writemore(struct netconn *conn)

+{

+  err_t err;

+  void *dataptr;

+  u16_t len, available;

+  u8_t write_finished = 0;

+

+  LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));

+

+  dataptr = (u8_t*)conn->write_msg->msg.w.dataptr + conn->write_offset;

+  if ((conn->write_msg->msg.w.len - conn->write_offset > 0xffff)) { /* max_u16_t */

+    len = 0xffff;

+#if LWIP_TCPIP_CORE_LOCKING

+    conn->write_delayed = 1;

+#endif

+  } else {

+    len = conn->write_msg->msg.w.len - conn->write_offset;

+  }

+  available = tcp_sndbuf(conn->pcb.tcp);

+  if (available < len) {

+    /* don't try to write more than sendbuf */

+    len = available;

+#if LWIP_TCPIP_CORE_LOCKING

+    conn->write_delayed = 1;

+#endif

+  }

+

+  err = tcp_write(conn->pcb.tcp, dataptr, len, conn->write_msg->msg.w.apiflags);

+  LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->write_msg->msg.w.len));

+  if (err == ERR_OK) {

+    conn->write_offset += len;

+    if (conn->write_offset == conn->write_msg->msg.w.len) {

+      /* everything was written */

+      write_finished = 1;

+      conn->write_msg = NULL;

+      conn->write_offset = 0;

+    }

+    err = tcp_output_nagle(conn->pcb.tcp);

+    conn->err = err;

+    if ((err == ERR_OK) && (tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT)) {

+      API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);

+    }

+  } else if (err == ERR_MEM) {

+    /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called

+       we do NOT return to the application thread, since ERR_MEM is

+       only a temporary error! */

+

+    /* tcp_enqueue returned ERR_MEM, try tcp_output anyway */

+    err = tcp_output(conn->pcb.tcp);

+

+#if LWIP_TCPIP_CORE_LOCKING

+    conn->write_delayed = 1;

+#endif

+  } else {

+    /* On errors != ERR_MEM, we don't try writing any more but return

+       the error to the application thread. */

+    conn->err = err;

+    write_finished = 1;

+  }

+

+  if (write_finished) {

+    /* everything was written: set back connection state

+       and back to application task */

+    conn->state = NETCONN_NONE;

+#if LWIP_TCPIP_CORE_LOCKING

+    if (conn->write_delayed != 0)

+#endif

+    {

+      sys_sem_signal(conn->op_completed);

+    }

+  }

+#if LWIP_TCPIP_CORE_LOCKING

+  else

+    return ERR_MEM;

+#endif

+  return ERR_OK;

+}

+#endif /* LWIP_TCP */

+

+/**

+ * Send some data on a TCP pcb contained in a netconn

+ * Called from netconn_write

+ *

+ * @param msg the api_msg_msg pointing to the connection

+ */

+void

+do_write(struct api_msg_msg *msg)

+{

+  if (!ERR_IS_FATAL(msg->conn->err)) {

+    if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {

+#if LWIP_TCP

+      msg->conn->state = NETCONN_WRITE;

+      /* set all the variables used by do_writemore */

+      msg->conn->write_msg = msg;

+      msg->conn->write_offset = 0;

+#if LWIP_TCPIP_CORE_LOCKING

+      msg->conn->write_delayed = 0;

+      if (do_writemore(msg->conn) != ERR_OK) {

+        LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);

+        UNLOCK_TCPIP_CORE();

+        sys_arch_sem_wait(msg->conn->op_completed, 0);

+        LOCK_TCPIP_CORE();

+        LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);

+      }

+#else

+      do_writemore(msg->conn);

+#endif

+      /* for both cases: if do_writemore was called, don't ACK the APIMSG! */

+      return;

+#endif /* LWIP_TCP */

+#if (LWIP_UDP || LWIP_RAW)

+    } else {

+      msg->conn->err = ERR_VAL;

+#endif /* (LWIP_UDP || LWIP_RAW) */

+    }

+  }

+  TCPIP_APIMSG_ACK(msg);

+}

+

+/**

+ * Return a connection's local or remote address

+ * Called from netconn_getaddr

+ *

+ * @param msg the api_msg_msg pointing to the connection

+ */

+void

+do_getaddr(struct api_msg_msg *msg)

+{

+  if (msg->conn->pcb.ip != NULL) {

+    *(msg->msg.ad.ipaddr) = (msg->msg.ad.local?msg->conn->pcb.ip->local_ip:msg->conn->pcb.ip->remote_ip);

+

+    switch (NETCONNTYPE_GROUP(msg->conn->type)) {

+#if LWIP_RAW

+    case NETCONN_RAW:

+      if (msg->msg.ad.local) {

+        *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;

+      } else {

+        /* return an error as connecting is only a helper for upper layers */

+        msg->conn->err = ERR_CONN;

+      }

+      break;

+#endif /* LWIP_RAW */

+#if LWIP_UDP

+    case NETCONN_UDP:

+      if (msg->msg.ad.local) {

+        *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;

+      } else {

+        if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {

+          msg->conn->err = ERR_CONN;

+        } else {

+          *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;

+        }

+      }

+      break;

+#endif /* LWIP_UDP */

+#if LWIP_TCP

+    case NETCONN_TCP:

+      *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port);

+      break;

+#endif /* LWIP_TCP */

+    }

+  } else {

+    msg->conn->err = ERR_CONN;

+  }

+  TCPIP_APIMSG_ACK(msg);

+}

+

+/**

+ * Close a TCP pcb contained in a netconn

+ * Called from netconn_close

+ *

+ * @param msg the api_msg_msg pointing to the connection

+ */

+void

+do_close(struct api_msg_msg *msg)

+{

+#if LWIP_TCP

+  if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {

+      msg->conn->state = NETCONN_CLOSE;

+      do_close_internal(msg->conn);

+      /* for tcp netconns, do_close_internal ACKs the message */

+  } else

+#endif /* LWIP_TCP */

+  {

+    msg->conn->err = ERR_VAL;

+    TCPIP_APIMSG_ACK(msg);

+  }

+}

+

+#if LWIP_IGMP

+/**

+ * Join multicast groups for UDP netconns.

+ * Called from netconn_join_leave_group

+ *

+ * @param msg the api_msg_msg pointing to the connection

+ */

+void

+do_join_leave_group(struct api_msg_msg *msg)

+{

+  if (!ERR_IS_FATAL(msg->conn->err)) {

+    if (msg->conn->pcb.tcp != NULL) {

+      if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {

+#if LWIP_UDP

+        if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {

+          msg->conn->err = igmp_joingroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);

+        } else {

+          msg->conn->err = igmp_leavegroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);

+        }

+#endif /* LWIP_UDP */

+#if (LWIP_TCP || LWIP_RAW)

+      } else {

+        msg->conn->err = ERR_VAL;

+#endif /* (LWIP_TCP || LWIP_RAW) */

+      }

+    }

+  }

+  TCPIP_APIMSG_ACK(msg);

+}

+#endif /* LWIP_IGMP */

+

+#if LWIP_DNS

+/**

+ * Callback function that is called when DNS name is resolved

+ * (or on timeout). A waiting application thread is waked up by

+ * signaling the semaphore.

+ */

+static void

+do_dns_found(const char *name, struct ip_addr *ipaddr, void *arg)

+{

+  struct dns_api_msg *msg = (struct dns_api_msg*)arg;

+

+  LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0);

+

+  if (ipaddr == NULL) {

+    /* timeout or memory error */

+    *msg->err = ERR_VAL;

+  } else {

+    /* address was resolved */

+    *msg->err = ERR_OK;

+    *msg->addr = *ipaddr;

+  }

+  /* wake up the application task waiting in netconn_gethostbyname */

+  sys_sem_signal(msg->sem);

+}

+

+/**

+ * Execute a DNS query

+ * Called from netconn_gethostbyname

+ *

+ * @param arg the dns_api_msg pointing to the query

+ */

+void

+do_gethostbyname(void *arg)

+{

+  struct dns_api_msg *msg = (struct dns_api_msg*)arg;

+

+  *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg);

+  if (*msg->err != ERR_INPROGRESS) {

+    /* on error or immediate success, wake up the application

+     * task waiting in netconn_gethostbyname */

+    sys_sem_signal(msg->sem);

+  }

+}

+#endif /* LWIP_DNS */

+

+#endif /* LWIP_NETCONN */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/err.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/err.c
new file mode 100644
index 0000000..19ad3e7
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/err.c
@@ -0,0 +1,74 @@
+/**

+ * @file

+ * Error Management module

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/err.h"

+

+#ifdef LWIP_DEBUG

+

+static const char *err_strerr[] = {

+           "Ok.",                    /* ERR_OK          0  */

+           "Out of memory error.",   /* ERR_MEM        -1  */

+           "Buffer error.",          /* ERR_BUF        -2  */

+           "Routing problem.",       /* ERR_RTE        -3  */

+           "Connection aborted.",    /* ERR_ABRT       -4  */

+           "Connection reset.",      /* ERR_RST        -5  */

+           "Connection closed.",     /* ERR_CLSD       -6  */

+           "Not connected.",         /* ERR_CONN       -7  */

+           "Illegal value.",         /* ERR_VAL        -8  */

+           "Illegal argument.",      /* ERR_ARG        -9  */

+           "Address in use.",        /* ERR_USE        -10 */

+           "Low-level netif error.", /* ERR_IF         -11 */

+           "Already connected.",     /* ERR_ISCONN     -12 */

+           "Timeout.",               /* ERR_TIMEOUT    -13 */

+           "Operation in progress."  /* ERR_INPROGRESS -14 */

+};

+

+/**

+ * Convert an lwip internal error to a string representation.

+ *

+ * @param err an lwip internal err_t

+ * @return a string representation for err

+ */

+const char *

+lwip_strerr(err_t err)

+{

+  return err_strerr[-err];

+

+}

+

+#endif /* LWIP_DEBUG */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/netbuf.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/netbuf.c
new file mode 100644
index 0000000..12f4881
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/netbuf.c
@@ -0,0 +1,235 @@
+/**

+ * @file

+ * Network buffer management

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/netbuf.h"

+#include "lwip/memp.h"

+

+#include <string.h>

+

+/**

+ * Create (allocate) and initialize a new netbuf.

+ * The netbuf doesn't yet contain a packet buffer!

+ *

+ * @return a pointer to a new netbuf

+ *         NULL on lack of memory

+ */

+struct

+netbuf *netbuf_new(void)

+{

+  struct netbuf *buf;

+

+  buf = memp_malloc(MEMP_NETBUF);

+  if (buf != NULL) {

+    buf->p = NULL;

+    buf->ptr = NULL;

+    buf->addr = NULL;

+    return buf;

+  } else {

+    return NULL;

+  }

+}

+

+/**

+ * Deallocate a netbuf allocated by netbuf_new().

+ *

+ * @param buf pointer to a netbuf allocated by netbuf_new()

+ */

+void

+netbuf_delete(struct netbuf *buf)

+{

+  if (buf != NULL) {

+    if (buf->p != NULL) {

+      pbuf_free(buf->p);

+      buf->p = buf->ptr = NULL;

+    }

+    memp_free(MEMP_NETBUF, buf);

+  }

+}

+

+/**

+ * Allocate memory for a packet buffer for a given netbuf.

+ *

+ * @param buf the netbuf for which to allocate a packet buffer

+ * @param size the size of the packet buffer to allocate

+ * @return pointer to the allocated memory

+ *         NULL if no memory could be allocated

+ */

+void *

+netbuf_alloc(struct netbuf *buf, u16_t size)

+{

+  LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;);

+

+  /* Deallocate any previously allocated memory. */

+  if (buf->p != NULL) {

+    pbuf_free(buf->p);

+  }

+  buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);

+  if (buf->p == NULL) {

+     return NULL;

+  }

+  LWIP_ASSERT("check that first pbuf can hold size",

+             (buf->p->len >= size));

+  buf->ptr = buf->p;

+  return buf->p->payload;

+}

+

+/**

+ * Free the packet buffer included in a netbuf

+ *

+ * @param buf pointer to the netbuf which contains the packet buffer to free

+ */

+void

+netbuf_free(struct netbuf *buf)

+{

+  LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);

+  if (buf->p != NULL) {

+    pbuf_free(buf->p);

+  }

+  buf->p = buf->ptr = NULL;

+}

+

+/**

+ * Let a netbuf reference existing (non-volatile) data.

+ *

+ * @param buf netbuf which should reference the data

+ * @param dataptr pointer to the data to reference

+ * @param size size of the data

+ * @return ERR_OK if data is referenced

+ *         ERR_MEM if data couldn't be referenced due to lack of memory

+ */

+err_t

+netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)

+{

+  LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;);

+  if (buf->p != NULL) {

+    pbuf_free(buf->p);

+  }

+  buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);

+  if (buf->p == NULL) {

+    buf->ptr = NULL;

+    return ERR_MEM;

+  }

+  buf->p->payload = (void*)dataptr;

+  buf->p->len = buf->p->tot_len = size;

+  buf->ptr = buf->p;

+  return ERR_OK;

+}

+

+/**

+ * Chain one netbuf to another (@see pbuf_chain)

+ *

+ * @param head the first netbuf

+ * @param tail netbuf to chain after head

+ */

+void

+netbuf_chain(struct netbuf *head, struct netbuf *tail)

+{

+  LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);

+  LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);

+  pbuf_chain(head->p, tail->p);

+  head->ptr = head->p;

+  memp_free(MEMP_NETBUF, tail);

+}

+

+/**

+ * Get the data pointer and length of the data inside a netbuf.

+ *

+ * @param buf netbuf to get the data from

+ * @param dataptr pointer to a void pointer where to store the data pointer

+ * @param len pointer to an u16_t where the length of the data is stored

+ * @return ERR_OK if the information was retreived,

+ *         ERR_BUF on error.

+ */

+err_t

+netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)

+{

+  LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;);

+  LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;);

+  LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;);

+

+  if (buf->ptr == NULL) {

+    return ERR_BUF;

+  }

+  *dataptr = buf->ptr->payload;

+  *len = buf->ptr->len;

+  return ERR_OK;

+}

+

+/**

+ * Move the current data pointer of a packet buffer contained in a netbuf

+ * to the next part.

+ * The packet buffer itself is not modified.

+ *

+ * @param buf the netbuf to modify

+ * @return -1 if there is no next part

+ *         1  if moved to the next part but now there is no next part

+ *         0  if moved to the next part and there are still more parts

+ */

+s8_t

+netbuf_next(struct netbuf *buf)

+{

+  LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;);

+  if (buf->ptr->next == NULL) {

+    return -1;

+  }

+  buf->ptr = buf->ptr->next;

+  if (buf->ptr->next == NULL) {

+    return 1;

+  }

+  return 0;

+}

+

+/**

+ * Move the current data pointer of a packet buffer contained in a netbuf

+ * to the beginning of the packet.

+ * The packet buffer itself is not modified.

+ *

+ * @param buf the netbuf to modify

+ */

+void

+netbuf_first(struct netbuf *buf)

+{

+  LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);

+  buf->ptr = buf->p;

+}

+

+#endif /* LWIP_NETCONN */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/netdb.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/netdb.c
new file mode 100644
index 0000000..d45f83f
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/netdb.c
@@ -0,0 +1,352 @@
+/**

+ * @file

+ * API functions for name resolving

+ *

+ */

+

+/*

+ * Redistribution and use in source and binary forms, with or without modification, 

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ * 

+ * Author: Simon Goldschmidt

+ *

+ */

+

+#include "lwip/netdb.h"

+

+#if LWIP_DNS && LWIP_SOCKET

+

+#include "lwip/err.h"

+#include "lwip/mem.h"

+#include "lwip/ip_addr.h"

+#include "lwip/api.h"

+

+/** helper struct for gethostbyname_r to access the char* buffer */

+struct gethostbyname_r_helper {

+  struct ip_addr *addrs;

+  struct ip_addr addr;

+  char *aliases;

+};

+

+/** h_errno is exported in netdb.h for access by applications. */

+#if LWIP_DNS_API_DECLARE_H_ERRNO

+int h_errno;

+#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */

+

+/** define "hostent" variables storage: 0 if we use a static (but unprotected)

+ * set of variables for lwip_gethostbyname, 1 if we use a local storage */

+#ifndef LWIP_DNS_API_HOSTENT_STORAGE

+#define LWIP_DNS_API_HOSTENT_STORAGE 0

+#endif

+

+/** define "hostent" variables storage */

+#if LWIP_DNS_API_HOSTENT_STORAGE

+#define HOSTENT_STORAGE

+#else

+#define HOSTENT_STORAGE static

+#endif /* LWIP_DNS_API_STATIC_HOSTENT */

+

+/**

+ * Returns an entry containing addresses of address family AF_INET

+ * for the host with name name.

+ * Due to dns_gethostbyname limitations, only one address is returned.

+ *

+ * @param name the hostname to resolve

+ * @return an entry containing addresses of address family AF_INET

+ *         for the host with name name

+ */

+struct hostent*

+lwip_gethostbyname(const char *name)

+{

+  err_t err;

+  struct ip_addr addr;

+

+  /* buffer variables for lwip_gethostbyname() */

+  HOSTENT_STORAGE struct hostent s_hostent;

+  HOSTENT_STORAGE char *s_aliases;

+  HOSTENT_STORAGE struct ip_addr s_hostent_addr;

+  HOSTENT_STORAGE struct ip_addr *s_phostent_addr;

+

+  /* query host IP address */

+  err = netconn_gethostbyname(name, &addr);

+  if (err != ERR_OK) {

+    LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));

+    h_errno = HOST_NOT_FOUND;

+    return NULL;

+  }

+

+  /* fill hostent */

+  s_hostent_addr = addr;

+  s_phostent_addr = &s_hostent_addr;

+  s_hostent.h_name = (char*)name;

+  s_hostent.h_aliases = &s_aliases;

+  s_hostent.h_addrtype = AF_INET;

+  s_hostent.h_length = sizeof(struct ip_addr);

+  s_hostent.h_addr_list = (char**)&s_phostent_addr;

+

+#if DNS_DEBUG

+  /* dump hostent */

+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name           == %s\n",      s_hostent.h_name));

+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases        == 0x%08lX\n",(u32_t)(s_hostent.h_aliases)));

+  if (s_hostent.h_aliases != NULL) {

+    u8_t idx;

+    for ( idx=0; s_hostent.h_aliases[idx]; idx++) {

+      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == 0x%08lX\n", idx, s_hostent.h_aliases[idx]));

+      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %s\n",      idx, s_hostent.h_aliases[idx]));

+    }

+  }

+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype       == %lu\n",    (u32_t)(s_hostent.h_addrtype)));

+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length         == %lu\n",    (u32_t)(s_hostent.h_length)));

+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list      == 0x%08lX\n", s_hostent.h_addr_list));

+  if (s_hostent.h_addr_list != NULL) {

+    u8_t idx;

+    for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {

+      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]   == 0x%08lX\n", idx, s_hostent.h_addr_list[idx]));

+      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n",      idx, inet_ntoa(*((struct in_addr*)(s_hostent.h_addr_list[idx])))));

+    }

+  }

+#endif /* DNS_DEBUG */

+

+#if LWIP_DNS_API_HOSTENT_STORAGE

+  /* this function should return the "per-thread" hostent after copy from s_hostent */

+  return sys_thread_hostent(&s_hostent);

+#else

+  return &s_hostent;

+#endif /* LWIP_DNS_API_HOSTENT_STORAGE */

+}

+

+/**

+ * Thread-safe variant of lwip_gethostbyname: instead of using a static

+ * buffer, this function takes buffer and errno pointers as arguments

+ * and uses these for the result.

+ *

+ * @param name the hostname to resolve

+ * @param ret pre-allocated struct where to store the result

+ * @param buf pre-allocated buffer where to store additional data

+ * @param buflen the size of buf

+ * @param result pointer to a hostent pointer that is set to ret on success

+ *               and set to zero on error

+ * @param h_errnop pointer to an int where to store errors (instead of modifying

+ *                 the global h_errno)

+ * @return 0 on success, non-zero on error, additional error information

+ *         is stored in *h_errnop instead of h_errno to be thread-safe

+ */

+int

+lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,

+                size_t buflen, struct hostent **result, int *h_errnop)

+{

+  err_t err;

+  struct gethostbyname_r_helper *h;

+  char *hostname;

+  size_t namelen;

+  int lh_errno;

+

+  if (h_errnop == NULL) {

+    /* ensure h_errnop is never NULL */

+    h_errnop = &lh_errno;

+  }

+

+  if (result == NULL) {

+    /* not all arguments given */

+    *h_errnop = EINVAL;

+    return -1;

+  }

+  /* first thing to do: set *result to nothing */

+  *result = NULL;

+  if ((name == NULL) || (ret == NULL) || (buf == 0)) {

+    /* not all arguments given */

+    *h_errnop = EINVAL;

+    return -1;

+  }

+

+  namelen = strlen(name);

+  if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) {

+    /* buf can't hold the data needed + a copy of name */

+    *h_errnop = ERANGE;

+    return -1;

+  }

+

+  h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf);

+  hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);

+

+  /* query host IP address */

+  err = netconn_gethostbyname(name, &(h->addr));

+  if (err != ERR_OK) {

+    LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));

+    *h_errnop = ENSRNOTFOUND;

+    return -1;

+  }

+

+  /* copy the hostname into buf */

+  MEMCPY(hostname, name, namelen);

+  hostname[namelen] = 0;

+

+  /* fill hostent */

+  h->addrs = &(h->addr);

+  h->aliases = NULL;

+  ret->h_name = (char*)hostname;

+  ret->h_aliases = &(h->aliases);

+  ret->h_addrtype = AF_INET;

+  ret->h_length = sizeof(struct ip_addr);

+  ret->h_addr_list = (char**)&(h->addrs);

+

+  /* set result != NULL */

+  *result = ret;

+

+  /* return success */

+  return 0;

+}

+

+/**

+ * Frees one or more addrinfo structures returned by getaddrinfo(), along with

+ * any additional storage associated with those structures. If the ai_next field

+ * of the structure is not null, the entire list of structures is freed.

+ *

+ * @param ai struct addrinfo to free

+ */

+void

+lwip_freeaddrinfo(struct addrinfo *ai)

+{

+  struct addrinfo *next;

+

+  while (ai != NULL) {

+    if (ai->ai_addr != NULL) {

+      mem_free(ai->ai_addr);

+    }

+    if (ai->ai_canonname != NULL) {

+      mem_free(ai->ai_canonname);

+    }

+    next = ai->ai_next;

+    mem_free(ai);

+    ai = next;

+  }

+}

+

+/**

+ * Translates the name of a service location (for example, a host name) and/or

+ * a service name and returns a set of socket addresses and associated

+ * information to be used in creating a socket with which to address the

+ * specified service.

+ * Memory for the result is allocated internally and must be freed by calling

+ * lwip_freeaddrinfo()!

+ *

+ * Due to a limitation in dns_gethostbyname, only the first address of a

+ * host is returned.

+ * Also, service names are not supported (only port numbers)!

+ *

+ * @param nodename descriptive name or address string of the host

+ *                 (may be NULL -> local address)

+ * @param servname port number as string of NULL 

+ * @param hints structure containing input values that set socktype and protocol

+ * @param res pointer to a pointer where to store the result (set to NULL on failure)

+ * @return 0 on success, non-zero on failure

+ */

+int

+lwip_getaddrinfo(const char *nodename, const char *servname,

+       const struct addrinfo *hints, struct addrinfo **res)

+{

+  err_t err;

+  struct ip_addr addr;

+  struct addrinfo *ai;

+  struct sockaddr_in *sa = NULL;

+  int port_nr = 0;

+

+  if (res == NULL) {

+    return EAI_FAIL;

+  }

+  *res = NULL;

+  if ((nodename == NULL) && (servname == NULL)) {

+    return EAI_NONAME;

+  }

+

+  if (servname != NULL) {

+    /* service name specified: convert to port number

+     * @todo?: currently, only ASCII integers (port numbers) are supported! */

+    port_nr = atoi(servname);

+    if ((port_nr <= 0) || (port_nr > 0xffff)) {

+      return EAI_SERVICE;

+    }

+  }

+

+  if (nodename != NULL) {

+    /* service location specified, try to resolve */

+    err = netconn_gethostbyname(nodename, &addr);

+    if (err != ERR_OK) {

+      return EAI_FAIL;

+    }

+  } else {

+    /* service location specified, use loopback address */

+    addr.addr = INADDR_LOOPBACK;

+  }

+

+  ai = mem_malloc(sizeof(struct addrinfo));

+  if (ai == NULL) {

+    goto memerr;

+  }

+  memset(ai, 0, sizeof(struct addrinfo));

+  sa = mem_malloc(sizeof(struct sockaddr_in));

+  if (sa == NULL) {

+    goto memerr;

+  }

+  memset(sa, 0, sizeof(struct sockaddr_in));

+  /* set up sockaddr */

+  sa->sin_addr.s_addr = addr.addr;

+  sa->sin_family = AF_INET;

+  sa->sin_len = sizeof(struct sockaddr_in);

+  sa->sin_port = htons(port_nr);

+

+  /* set up addrinfo */

+  ai->ai_family = AF_INET;

+  if (hints != NULL) {

+    /* copy socktype & protocol from hints if specified */

+    ai->ai_socktype = hints->ai_socktype;

+    ai->ai_protocol = hints->ai_protocol;

+  }

+  if (nodename != NULL) {

+    /* copy nodename to canonname if specified */

+    size_t namelen = strlen(nodename);

+    ai->ai_canonname = mem_malloc(namelen + 1);

+    if (ai->ai_canonname == NULL) {

+      goto memerr;

+    }

+    MEMCPY(ai->ai_canonname, nodename, namelen);

+    ai->ai_canonname[namelen] = 0;

+  }

+  ai->ai_addrlen = sizeof(struct sockaddr_in);

+  ai->ai_addr = (struct sockaddr*)sa;

+

+  *res = ai;

+

+  return 0;

+memerr:

+  if (ai != NULL) {

+    mem_free(ai);

+  }

+  if (sa != NULL) {

+    mem_free(sa);

+  }

+  return EAI_MEMORY;

+}

+

+#endif /* LWIP_DNS && LWIP_SOCKET */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/netifapi.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/netifapi.c
new file mode 100644
index 0000000..49b6ef0
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/netifapi.c
@@ -0,0 +1,126 @@
+/**

+ * @file

+ * Network Interface Sequential API module

+ *

+ */

+

+/*

+ * Redistribution and use in source and binary forms, with or without modification, 

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ * 

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/netifapi.h"

+#include "lwip/tcpip.h"

+

+/**

+ * Call netif_add() inside the tcpip_thread context.

+ */

+void

+do_netifapi_netif_add( struct netifapi_msg_msg *msg)

+{

+  if (!netif_add( msg->netif,

+                  msg->msg.add.ipaddr,

+                  msg->msg.add.netmask,

+                  msg->msg.add.gw,

+                  msg->msg.add.state,

+                  msg->msg.add.init,

+                  msg->msg.add.input)) {

+    msg->err = ERR_IF;

+  } else {

+    msg->err = ERR_OK;

+  }

+  TCPIP_NETIFAPI_ACK(msg);

+}

+

+/**

+ * Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the

+ * tcpip_thread context.

+ */

+void

+do_netifapi_netif_common( struct netifapi_msg_msg *msg)

+{

+  if (msg->msg.common.errtfunc!=NULL) {

+    msg->err =

+    msg->msg.common.errtfunc(msg->netif);

+  } else {

+    msg->err = ERR_OK;

+    msg->msg.common.voidfunc(msg->netif);

+  }

+  TCPIP_NETIFAPI_ACK(msg);

+}

+

+/**

+ * Call netif_add() in a thread-safe way by running that function inside the

+ * tcpip_thread context.

+ *

+ * @note for params @see netif_add()

+ */

+err_t

+netifapi_netif_add(struct netif *netif,

+                   struct ip_addr *ipaddr,

+                   struct ip_addr *netmask,

+                   struct ip_addr *gw,

+                   void *state,

+                   err_t (* init)(struct netif *netif),

+                   err_t (* input)(struct pbuf *p, struct netif *netif))

+{

+  struct netifapi_msg msg;

+  msg.function = do_netifapi_netif_add;

+  msg.msg.netif = netif;

+  msg.msg.msg.add.ipaddr  = ipaddr;

+  msg.msg.msg.add.netmask = netmask;

+  msg.msg.msg.add.gw      = gw;

+  msg.msg.msg.add.state   = state;

+  msg.msg.msg.add.init    = init;

+  msg.msg.msg.add.input   = input;

+  TCPIP_NETIFAPI(&msg);

+  return msg.msg.err;

+}

+

+/**

+ * call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe

+ * way by running that function inside the tcpip_thread context.

+ *

+ * @note use only for functions where there is only "netif" parameter.

+ */

+err_t

+netifapi_netif_common( struct netif *netif,

+                       void  (* voidfunc)(struct netif *netif),

+                       err_t (* errtfunc)(struct netif *netif) )

+{

+  struct netifapi_msg msg;

+  msg.function = do_netifapi_netif_common;

+  msg.msg.netif = netif;

+  msg.msg.msg.common.voidfunc = voidfunc;

+  msg.msg.msg.common.errtfunc = errtfunc;

+  TCPIP_NETIFAPI(&msg);

+  return msg.msg.err;

+}

+

+#endif /* LWIP_NETIF_API */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/sockets.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/sockets.c
new file mode 100644
index 0000000..18663c9
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/sockets.c
@@ -0,0 +1,1924 @@
+/**

+ * @file

+ * Sockets BSD-Like API module

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/sockets.h"

+#include "lwip/api.h"

+#include "lwip/sys.h"

+#include "lwip/igmp.h"

+#include "lwip/inet.h"

+#include "lwip/tcp.h"

+#include "lwip/raw.h"

+#include "lwip/udp.h"

+#include "lwip/tcpip.h"

+

+#include <string.h>

+

+#define NUM_SOCKETS MEMP_NUM_NETCONN

+

+/** Contains all internal pointers and states used for a socket */

+struct lwip_socket {

+  /** sockets currently are built on netconns, each socket has one netconn */

+  struct netconn *conn;

+  /** data that was left from the previous read */

+  struct netbuf *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 */

+  u16_t rcvevent;

+  /** number of times data was received, set by event_callback(),

+      tested by select */

+  u16_t sendevent;

+  /** socket flags (currently, only used for O_NONBLOCK) */

+  u16_t flags;

+  /** last error that occurred on this socket */

+  int err;

+};

+

+/** Description for a task waiting in select */

+struct lwip_select_cb {

+  /** Pointer to the next waiting task */

+  struct lwip_select_cb *next;

+  /** readset passed to select */

+  fd_set *readset;

+  /** writeset passed to select */

+  fd_set *writeset;

+  /** unimplemented: exceptset passed to select */

+  fd_set *exceptset;

+  /** don't signal the same semaphore twice: set to 1 when signalled */

+  int sem_signalled;

+  /** semaphore to wake up a task waiting for select */

+  sys_sem_t sem;

+};

+

+/** This struct is used to pass data to the set/getsockopt_internal

+ * functions running in tcpip_thread context (only a void* is allowed) */

+struct lwip_setgetsockopt_data {

+  /** socket struct for which to change options */

+  struct lwip_socket *sock;

+  /** socket index for which to change options */

+  int s;

+  /** level of the option to process */

+  int level;

+  /** name of the option to process */

+  int optname;

+  /** set: value to set the option to

+    * get: value of the option is stored here */

+  void *optval;

+  /** size of *optval */

+  socklen_t *optlen;

+  /** if an error occures, it is temporarily stored here */

+  err_t err;

+};

+

+/** The global array of available sockets */

+static struct lwip_socket sockets[NUM_SOCKETS];

+/** The global list of tasks waiting for select */

+static struct lwip_select_cb *select_cb_list;

+

+/** Semaphore protecting the sockets array */

+static sys_sem_t socksem;

+/** Semaphore protecting select_cb_list */

+static sys_sem_t selectsem;

+

+/** Table to quickly map an lwIP error (err_t) to a socket error

+  * by using -err as an index */

+static const int err_to_errno_table[] = {

+  0,             /* ERR_OK          0      No error, everything OK. */

+  ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */

+  ENOBUFS,       /* ERR_BUF        -2      Buffer error.            */

+  EHOSTUNREACH,  /* ERR_RTE        -3      Routing problem.         */

+  ECONNABORTED,  /* ERR_ABRT       -4      Connection aborted.      */

+  ECONNRESET,    /* ERR_RST        -5      Connection reset.        */

+  ESHUTDOWN,     /* ERR_CLSD       -6      Connection closed.       */

+  ENOTCONN,      /* ERR_CONN       -7      Not connected.           */

+  EINVAL,        /* ERR_VAL        -8      Illegal value.           */

+  EIO,           /* ERR_ARG        -9      Illegal argument.        */

+  EADDRINUSE,    /* ERR_USE        -10     Address in use.          */

+  -1,            /* ERR_IF         -11     Low-level netif error    */

+  -1,            /* ERR_ISCONN     -12     Already connected.       */

+  ETIMEDOUT,     /* ERR_TIMEOUT    -13     Timeout                  */

+  EINPROGRESS    /* ERR_INPROGRESS -14     Operation in progress    */

+};

+

+#define ERR_TO_ERRNO_TABLE_SIZE \

+  (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))

+

+#define err_to_errno(err) \

+  ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \

+    err_to_errno_table[-(err)] : EIO)

+

+#ifdef ERRNO

+#define set_errno(err) errno = (err)

+#else

+#define set_errno(err)

+#endif

+

+#define sock_set_errno(sk, e) do { \

+  sk->err = (e); \

+  set_errno(sk->err); \

+} while (0)

+

+/* Forward delcaration of some functions */

+static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);

+static void lwip_getsockopt_internal(void *arg);

+static void lwip_setsockopt_internal(void *arg);

+

+/**

+ * Initialize this module. This function has to be called before any other

+ * functions in this module!

+ */

+void

+lwip_socket_init(void)

+{

+  socksem   = sys_sem_new(1);

+  selectsem = sys_sem_new(1);

+}

+

+/**

+ * Map a externally used socket index to the internal socket representation.

+ *

+ * @param s externally used socket index

+ * @return struct lwip_socket for the socket or NULL if not found

+ */

+static struct lwip_socket *

+get_socket(int s)

+{

+  struct lwip_socket *sock;

+

+  if ((s < 0) || (s >= NUM_SOCKETS)) {

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));

+    set_errno(EBADF);

+    return NULL;

+  }

+

+  sock = &sockets[s];

+

+  if (!sock->conn) {

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));

+    set_errno(EBADF);

+    return NULL;

+  }

+

+  return sock;

+}

+

+/**

+ * Allocate a new socket for a given netconn.

+ *

+ * @param newconn the netconn for which to allocate a socket

+ * @return the index of the new socket; -1 on error

+ */

+static int

+alloc_socket(struct netconn *newconn)

+{

+  int i;

+

+  /* Protect socket array */

+  sys_sem_wait(socksem);

+

+  /* allocate a new socket identifier */

+  for (i = 0; i < NUM_SOCKETS; ++i) {

+    if (!sockets[i].conn) {

+      sockets[i].conn       = newconn;

+      sockets[i].lastdata   = NULL;

+      sockets[i].lastoffset = 0;

+      sockets[i].rcvevent   = 0;

+      sockets[i].sendevent  = 1; /* TCP send buf is empty */

+      sockets[i].flags      = 0;

+      sockets[i].err        = 0;

+      sys_sem_signal(socksem);

+      return i;

+    }

+  }

+  sys_sem_signal(socksem);

+  return -1;

+}

+

+/* Below this, the well-known socket functions are implemented.

+ * Use google.com or opengroup.org to get a good description :-)

+ *

+ * Exceptions are documented!

+ */

+

+int

+lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)

+{

+  struct lwip_socket *sock, *nsock;

+  struct netconn *newconn;

+  struct ip_addr naddr;

+  u16_t port;

+  int newsock;

+  struct sockaddr_in sin;

+  err_t err;

+

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));

+  sock = get_socket(s);

+  if (!sock)

+    return -1;

+

+  newconn = netconn_accept(sock->conn);

+  if (!newconn) {

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) failed, err=%d\n", s, sock->conn->err));

+    sock_set_errno(sock, err_to_errno(sock->conn->err));

+    return -1;

+  }

+

+  /* get the IP address and port of the remote host */

+  err = netconn_peer(newconn, &naddr, &port);

+  if (err != ERR_OK) {

+    netconn_delete(newconn);

+    sock_set_errno(sock, err_to_errno(err));

+    return -1;

+  }

+

+  memset(&sin, 0, sizeof(sin));

+  sin.sin_len = sizeof(sin);

+  sin.sin_family = AF_INET;

+  sin.sin_port = htons(port);

+  sin.sin_addr.s_addr = naddr.addr;

+

+  if (*addrlen > sizeof(sin))

+    *addrlen = sizeof(sin);

+

+  SMEMCPY(addr, &sin, *addrlen);

+

+  newsock = alloc_socket(newconn);

+  if (newsock == -1) {

+    netconn_delete(newconn);

+    sock_set_errno(sock, ENFILE);

+    return -1;

+  }

+  LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));

+  newconn->callback = event_callback;

+  nsock = &sockets[newsock];

+  LWIP_ASSERT("invalid socket pointer", nsock != NULL);

+

+  sys_sem_wait(socksem);

+  /* See event_callback: If data comes in right away after an accept, even

+   * though the server task might not have created a new socket yet.

+   * In that case, newconn->socket is counted down (newconn->socket--),

+   * so nsock->rcvevent is >= 1 here!

+   */

+  nsock->rcvevent += -1 - newconn->socket;

+  newconn->socket = newsock;

+  sys_sem_signal(socksem);

+

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));

+  ip_addr_debug_print(SOCKETS_DEBUG, &naddr);

+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", port));

+

+  sock_set_errno(sock, 0);

+  return newsock;

+}

+

+int

+lwip_bind(int s, struct sockaddr *name, socklen_t namelen)

+{

+  struct lwip_socket *sock;

+  struct ip_addr local_addr;

+  u16_t local_port;

+  err_t err;

+

+  sock = get_socket(s);

+  if (!sock)

+    return -1;

+

+  LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&

+             ((((struct sockaddr_in *)name)->sin_family) == AF_INET)),

+             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);

+

+  local_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;

+  local_port = ((struct sockaddr_in *)name)->sin_port;

+

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));

+  ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);

+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(local_port)));

+

+  err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));

+

+  if (err != ERR_OK) {

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));

+    sock_set_errno(sock, err_to_errno(err));

+    return -1;

+  }

+

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));

+  sock_set_errno(sock, 0);

+  return 0;

+}

+

+int

+lwip_close(int s)

+{

+  struct lwip_socket *sock;

+

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));

+

+  sock = get_socket(s);

+  if (!sock) {

+    return -1;

+  }

+

+  netconn_delete(sock->conn);

+

+  sys_sem_wait(socksem);

+  if (sock->lastdata) {

+    netbuf_delete(sock->lastdata);

+  }

+  sock->lastdata   = NULL;

+  sock->lastoffset = 0;

+  sock->conn       = NULL;

+  sock_set_errno(sock, 0);

+  sys_sem_signal(socksem);

+  return 0;

+}

+

+int

+lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)

+{

+  struct lwip_socket *sock;

+  err_t err;

+

+  sock = get_socket(s);

+  if (!sock)

+    return -1;

+

+  LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&

+             ((((struct sockaddr_in *)name)->sin_family) == AF_INET)),

+             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);

+

+  if (((struct sockaddr_in *)name)->sin_family == AF_UNSPEC) {

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));

+    err = netconn_disconnect(sock->conn);

+  } else {

+    struct ip_addr remote_addr;

+    u16_t remote_port;

+

+    remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;

+    remote_port = ((struct sockaddr_in *)name)->sin_port;

+

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));

+    ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);

+    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port)));

+

+    err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));

+  }

+

+  if (err != ERR_OK) {

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));

+    sock_set_errno(sock, err_to_errno(err));

+    return -1;

+  }

+

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));

+  sock_set_errno(sock, 0);

+  return 0;

+}

+

+/**

+ * Set a socket into listen mode.

+ * The socket may not have been used for another connection previously.

+ *

+ * @param s the socket to set to listening mode

+ * @param backlog (ATTENTION: need TCP_LISTEN_BACKLOG=1)

+ * @return 0 on success, non-zero on failure

+ */

+int

+lwip_listen(int s, int backlog)

+{

+  struct lwip_socket *sock;

+  err_t err;

+

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));

+

+  sock = get_socket(s);

+  if (!sock)

+    return -1;

+

+  /* limit the "backlog" parameter to fit in an u8_t */

+  if (backlog < 0) {

+    backlog = 0;

+  }

+  if (backlog > 0xff) {

+    backlog = 0xff;

+  }

+

+  err = netconn_listen_with_backlog(sock->conn, backlog);

+

+  if (err != ERR_OK) {

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));

+    sock_set_errno(sock, err_to_errno(err));

+    return -1;

+  }

+

+  sock_set_errno(sock, 0);

+  return 0;

+}

+

+int

+lwip_recvfrom(int s, void *mem, int len, unsigned int flags,

+        struct sockaddr *from, socklen_t *fromlen)

+{

+  struct lwip_socket *sock;

+  struct netbuf      *buf;

+  u16_t               buflen, copylen, off = 0;

+  struct ip_addr     *addr;

+  u16_t               port;

+  u8_t                done = 0;

+

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags));

+  sock = get_socket(s);

+  if (!sock)

+    return -1;

+

+  do {

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", (void*)sock->lastdata));

+    /* Check if there is data left from the last recv operation. */

+    if (sock->lastdata) {

+      buf = sock->lastdata;

+    } else {

+      /* If this is non-blocking call, then check first */

+      if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && !sock->rcvevent) {

+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));

+        sock_set_errno(sock, EWOULDBLOCK);

+        return -1;

+      }

+

+      /* No data was left from the previous operation, so we try to get

+      some from the network. */

+      sock->lastdata = buf = netconn_recv(sock->conn);

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv netbuf=%p\n", (void*)buf));

+

+      if (!buf) {

+        /* We should really do some error checking here. */

+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s));

+        sock_set_errno(sock, (((sock->conn->pcb.ip!=NULL) && (sock->conn->err==ERR_OK))?ETIMEDOUT:err_to_errno(sock->conn->err)));

+        return 0;

+      }

+    }

+

+    buflen = netbuf_len(buf);

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%d len=%d off=%d sock->lastoffset=%d\n", buflen, len, off, sock->lastoffset));

+

+    buflen -= sock->lastoffset;

+

+    if (len > buflen) {

+      copylen = buflen;

+    } else {

+      copylen = len;

+    }

+

+    /* copy the contents of the received buffer into

+    the supplied memory pointer mem */

+    netbuf_copy_partial(buf, (u8_t*)mem + off, copylen, sock->lastoffset);

+

+    off += copylen;

+

+    if (netconn_type(sock->conn) == NETCONN_TCP) {

+      len -= copylen;

+      if ( (len <= 0) || (buf->p->flags & PBUF_FLAG_PUSH) || !sock->rcvevent) {

+        done = 1;

+      }

+    } else {

+      done = 1;

+    }

+

+    /* If we don't peek the incoming message... */

+    if ((flags & MSG_PEEK)==0) {

+      /* If this is a TCP socket, check if there is data left in the

+         buffer. If so, it should be saved in the sock structure for next

+         time around. */

+      if ((sock->conn->type == NETCONN_TCP) && (buflen - copylen > 0)) {

+        sock->lastdata = buf;

+        sock->lastoffset += copylen;

+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", (void*)buf));

+      } else {

+        sock->lastdata = NULL;

+        sock->lastoffset = 0;

+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", (void*)buf));

+        netbuf_delete(buf);

+      }

+    } else {

+      done = 1;

+    }

+  } while (!done);

+

+  /* Check to see from where the data was.*/

+  if (from && fromlen) {

+    struct sockaddr_in sin;

+

+    if (netconn_type(sock->conn) == NETCONN_TCP) {

+      addr = (struct ip_addr*)&(sin.sin_addr.s_addr);

+      netconn_getaddr(sock->conn, addr, &port, 0);

+    } else {

+      addr = netbuf_fromaddr(buf);

+      port = netbuf_fromport(buf);

+    }

+

+    memset(&sin, 0, sizeof(sin));

+    sin.sin_len = sizeof(sin);

+    sin.sin_family = AF_INET;

+    sin.sin_port = htons(port);

+    sin.sin_addr.s_addr = addr->addr;

+

+    if (*fromlen > sizeof(sin))

+      *fromlen = sizeof(sin);

+

+    SMEMCPY(from, &sin, *fromlen);

+

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));

+    ip_addr_debug_print(SOCKETS_DEBUG, addr);

+    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, off));

+  } else {

+#if SOCKETS_DEBUG

+    struct sockaddr_in sin;

+

+    if (netconn_type(sock->conn) == NETCONN_TCP) {

+      addr = (struct ip_addr*)&(sin.sin_addr.s_addr);

+      netconn_getaddr(sock->conn, addr, &port, 0);

+    } else {

+      addr = netbuf_fromaddr(buf);

+      port = netbuf_fromport(buf);

+    }

+

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));

+    ip_addr_debug_print(SOCKETS_DEBUG, addr);

+    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, off));

+#endif /*  SOCKETS_DEBUG */

+  }

+

+  sock_set_errno(sock, 0);

+  return off;

+}

+

+int

+lwip_read(int s, void *mem, int len)

+{

+  return lwip_recvfrom(s, mem, len, 0, NULL, NULL);

+}

+

+int

+lwip_recv(int s, void *mem, int len, unsigned int flags)

+{

+  return lwip_recvfrom(s, mem, len, flags, NULL, NULL);

+}

+

+int

+lwip_send(int s, const void *data, int size, unsigned int flags)

+{

+  struct lwip_socket *sock;

+  err_t err;

+

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%d, flags=0x%x)\n",

+                              s, data, size, flags));

+

+  sock = get_socket(s);

+  if (!sock)

+    return -1;

+

+  if (sock->conn->type!=NETCONN_TCP) {

+#if (LWIP_UDP || LWIP_RAW)

+    return lwip_sendto(s, data, size, flags, NULL, 0);

+#else

+    sock_set_errno(sock, err_to_errno(ERR_ARG));

+    return -1;

+#endif /* (LWIP_UDP || LWIP_RAW) */

+  }

+

+  err = netconn_write(sock->conn, data, size, NETCONN_COPY | ((flags & MSG_MORE)?NETCONN_MORE:0));

+

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%d\n", s, err, size));

+  sock_set_errno(sock, err_to_errno(err));

+  return (err==ERR_OK?size:-1);

+}

+

+int

+lwip_sendto(int s, const void *data, int size, unsigned int flags,

+       struct sockaddr *to, socklen_t tolen)

+{

+  struct lwip_socket *sock;

+  struct ip_addr remote_addr;

+  int err;

+#if !LWIP_TCPIP_CORE_LOCKING

+  struct netbuf buf;

+  u16_t remote_port;

+#endif

+

+  sock = get_socket(s);

+  if (!sock)

+    return -1;

+

+  if (sock->conn->type==NETCONN_TCP) {

+#if LWIP_TCP

+    return lwip_send(s, data, size, flags);

+#else

+    sock_set_errno(sock, err_to_errno(ERR_ARG));

+    return -1;

+#endif /* LWIP_TCP */

+  }

+

+  LWIP_ASSERT("lwip_sendto: size must fit in u16_t",

+              ((size >= 0) && (size <= 0xffff)));

+  LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||

+             ((tolen == sizeof(struct sockaddr_in)) &&

+             ((((struct sockaddr_in *)to)->sin_family) == AF_INET))),

+             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);

+

+#if LWIP_TCPIP_CORE_LOCKING

+  /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */

+  { struct pbuf* p;

+

+    p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);

+    if (p == NULL) {

+      err = ERR_MEM;

+    } else {

+      p->payload = (void*)data;

+      p->len = p->tot_len = size;

+

+      remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;

+

+      LOCK_TCPIP_CORE();

+      if (sock->conn->type==NETCONN_RAW) {

+        err = sock->conn->err = raw_sendto(sock->conn->pcb.raw, p, &remote_addr);

+      } else {

+        err = sock->conn->err = udp_sendto(sock->conn->pcb.udp, p, &remote_addr, ntohs(((struct sockaddr_in *)to)->sin_port));

+      }

+      UNLOCK_TCPIP_CORE();

+

+      pbuf_free(p);

+    }

+  }

+#else

+  /* initialize a buffer */

+  buf.p = buf.ptr = NULL;

+  if (to) {

+    remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;

+    remote_port      = ntohs(((struct sockaddr_in *)to)->sin_port);

+    buf.addr         = &remote_addr;

+    buf.port         = remote_port;

+  } else {

+    remote_addr.addr = 0;

+    remote_port      = 0;

+    buf.addr         = NULL;

+    buf.port         = 0;

+  }

+

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=",

+              s, data, size, flags));

+  ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);

+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", remote_port));

+

+  /* make the buffer point to the data that should be sent */

+  if ((err = netbuf_ref(&buf, data, size)) == ERR_OK) {

+    /* send the data */

+    err = netconn_send(sock->conn, &buf);

+  }

+

+  /* deallocated the buffer */

+  if (buf.p != NULL) {

+    pbuf_free(buf.p);

+  }

+#endif /* LWIP_TCPIP_CORE_LOCKING */

+  sock_set_errno(sock, err_to_errno(err));

+  return (err==ERR_OK?size:-1);

+}

+

+int

+lwip_socket(int domain, int type, int protocol)

+{

+  struct netconn *conn;

+  int i;

+

+  LWIP_UNUSED_ARG(domain);

+

+  /* create a netconn */

+  switch (type) {

+  case SOCK_RAW:

+    conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",

+                                 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));

+    break;

+  case SOCK_DGRAM:

+    conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?

+                 NETCONN_UDPLITE : NETCONN_UDP, event_callback);

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",

+                                 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));

+    break;

+  case SOCK_STREAM:

+    conn = netconn_new_with_callback(NETCONN_TCP, event_callback);

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",

+                                 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));

+    break;

+  default:

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",

+                                 domain, type, protocol));

+    set_errno(EINVAL);

+    return -1;

+  }

+

+  if (!conn) {

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));

+    set_errno(ENOBUFS);

+    return -1;

+  }

+

+  i = alloc_socket(conn);

+

+  if (i == -1) {

+    netconn_delete(conn);

+    set_errno(ENFILE);

+    return -1;

+  }

+  conn->socket = i;

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));

+  set_errno(0);

+  return i;

+}

+

+int

+lwip_write(int s, const void *data, int size)

+{

+  return lwip_send(s, data, size, 0);

+}

+

+/**

+ * Go through the readset and writeset lists and see which socket of the sockets

+ * set in the sets has events. On return, readset, writeset and exceptset have

+ * the sockets enabled that had events.

+ *

+ * exceptset is not used for now!!!

+ *

+ * @param maxfdp1 the highest socket index in the sets

+ * @param readset in: set of sockets to check for read events;

+ *                out: set of sockets that had read events

+ * @param writeset in: set of sockets to check for write events;

+ *                 out: set of sockets that had write events

+ * @param exceptset not yet implemented

+ * @return number of sockets that had events (read+write)

+ */

+static int

+lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset)

+{

+  int i, nready = 0;

+  fd_set lreadset, lwriteset, lexceptset;

+  struct lwip_socket *p_sock;

+

+  FD_ZERO(&lreadset);

+  FD_ZERO(&lwriteset);

+  FD_ZERO(&lexceptset);

+

+  /* Go through each socket in each list to count number of sockets which

+  currently match */

+  for(i = 0; i < maxfdp1; i++) {

+    if (FD_ISSET(i, readset)) {

+      /* See if netconn of this socket is ready for read */

+      p_sock = get_socket(i);

+      if (p_sock && (p_sock->lastdata || p_sock->rcvevent)) {

+        FD_SET(i, &lreadset);

+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));

+        nready++;

+      }

+    }

+    if (FD_ISSET(i, writeset)) {

+      /* See if netconn of this socket is ready for write */

+      p_sock = get_socket(i);

+      if (p_sock && p_sock->sendevent) {

+        FD_SET(i, &lwriteset);

+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));

+        nready++;

+      }

+    }

+  }

+  *readset = lreadset;

+  *writeset = lwriteset;

+  FD_ZERO(exceptset);

+

+  return nready;

+}

+

+

+/**

+ * Processing exceptset is not yet implemented.

+ */

+int

+lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,

+               struct timeval *timeout)

+{

+  int i;

+  int nready;

+  fd_set lreadset, lwriteset, lexceptset;

+  u32_t msectimeout;

+  struct lwip_select_cb select_cb;

+  struct lwip_select_cb *p_selcb;

+

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n",

+                  maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,

+                  timeout ? timeout->tv_sec : -1L, timeout ? timeout->tv_usec : -1L));

+

+  select_cb.next = 0;

+  select_cb.readset = readset;

+  select_cb.writeset = writeset;

+  select_cb.exceptset = exceptset;

+  select_cb.sem_signalled = 0;

+

+  /* Protect ourselves searching through the list */

+  sys_sem_wait(selectsem);

+

+  if (readset)

+    lreadset = *readset;

+  else

+    FD_ZERO(&lreadset);

+  if (writeset)

+    lwriteset = *writeset;

+  else

+    FD_ZERO(&lwriteset);

+  if (exceptset)

+    lexceptset = *exceptset;

+  else

+    FD_ZERO(&lexceptset);

+

+  /* Go through each socket in each list to count number of sockets which

+     currently match */

+  nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);

+

+  /* If we don't have any current events, then suspend if we are supposed to */

+  if (!nready) {

+    if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {

+      sys_sem_signal(selectsem);

+      if (readset)

+        FD_ZERO(readset);

+      if (writeset)

+        FD_ZERO(writeset);

+      if (exceptset)

+        FD_ZERO(exceptset);

+

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));

+      set_errno(0);

+

+      return 0;

+    }

+

+    /* add our semaphore to list */

+    /* We don't actually need any dynamic memory. Our entry on the

+     * list is only valid while we are in this function, so it's ok

+     * to use local variables */

+

+    select_cb.sem = sys_sem_new(0);

+    /* Note that we are still protected */

+    /* Put this select_cb on top of list */

+    select_cb.next = select_cb_list;

+    select_cb_list = &select_cb;

+

+    /* Now we can safely unprotect */

+    sys_sem_signal(selectsem);

+

+    /* Now just wait to be woken */

+    if (timeout == 0)

+      /* Wait forever */

+      msectimeout = 0;

+    else {

+      msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));

+      if(msectimeout == 0)

+        msectimeout = 1;

+    }

+

+    i = sys_sem_wait_timeout(select_cb.sem, msectimeout);

+

+    /* Take us off the list */

+    sys_sem_wait(selectsem);

+    if (select_cb_list == &select_cb)

+      select_cb_list = select_cb.next;

+    else

+      for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next) {

+        if (p_selcb->next == &select_cb) {

+          p_selcb->next = select_cb.next;

+          break;

+        }

+      }

+

+    sys_sem_signal(selectsem);

+

+    sys_sem_free(select_cb.sem);

+    if (i == 0)  {

+      /* Timeout */

+      if (readset)

+        FD_ZERO(readset);

+      if (writeset)

+        FD_ZERO(writeset);

+      if (exceptset)

+        FD_ZERO(exceptset);

+

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));

+      set_errno(0);

+

+      return 0;

+    }

+

+    if (readset)

+      lreadset = *readset;

+    else

+      FD_ZERO(&lreadset);

+    if (writeset)

+      lwriteset = *writeset;

+    else

+      FD_ZERO(&lwriteset);

+    if (exceptset)

+      lexceptset = *exceptset;

+    else

+      FD_ZERO(&lexceptset);

+

+    /* See what's set */

+    nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);

+  } else

+    sys_sem_signal(selectsem);

+

+  if (readset)

+    *readset = lreadset;

+  if (writeset)

+    *writeset = lwriteset;

+  if (exceptset)

+    *exceptset = lexceptset;

+

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));

+  set_errno(0);

+

+  return nready;

+}

+

+/**

+ * Callback registered in the netconn layer for each socket-netconn.

+ * Processes recvevent (data available) and wakes up tasks waiting for select.

+ */

+static void

+event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)

+{

+  int s;

+  struct lwip_socket *sock;

+  struct lwip_select_cb *scb;

+

+  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_sem_wait(socksem);

+      if (conn->socket < 0) {

+        if (evt == NETCONN_EVT_RCVPLUS) {

+          conn->socket--;

+        }

+        sys_sem_signal(socksem);

+        return;

+      }

+      sys_sem_signal(socksem);

+    }

+

+    sock = get_socket(s);

+    if (!sock) {

+      return;

+    }

+  } else {

+    return;

+  }

+

+  sys_sem_wait(selectsem);

+  /* 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;

+    default:

+      LWIP_ASSERT("unknown event", 0);

+      break;

+  }

+  sys_sem_signal(selectsem);

+

+  /* Now decide if anyone is waiting for this socket */

+  /* NOTE: This code is written this way to protect the select link list

+     but to avoid a deadlock situation by releasing socksem before

+     signalling for the select. This means we need to go through the list

+     multiple times ONLY IF a select was actually waiting. We go through

+     the list the number of waiting select calls + 1. This list is

+     expected to be small. */

+  while (1) {

+    sys_sem_wait(selectsem);

+    for (scb = select_cb_list; scb; scb = scb->next) {

+      if (scb->sem_signalled == 0) {

+        /* Test this select call for our socket */

+        if (scb->readset && FD_ISSET(s, scb->readset))

+          if (sock->rcvevent)

+            break;

+        if (scb->writeset && FD_ISSET(s, scb->writeset))

+          if (sock->sendevent)

+            break;

+      }

+    }

+    if (scb) {

+      scb->sem_signalled = 1;

+      sys_sem_signal(selectsem);

+      sys_sem_signal(scb->sem);

+    } else {

+      sys_sem_signal(selectsem);

+      break;

+    }

+  }

+}

+

+/**

+ * Unimplemented: Close one end of a full-duplex connection.

+ * Currently, the full connection is closed.

+ */

+int

+lwip_shutdown(int s, int how)

+{

+  LWIP_UNUSED_ARG(how);

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));

+  return lwip_close(s); /* XXX temporary hack until proper implementation */

+}

+

+static int

+lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)

+{

+  struct lwip_socket *sock;

+  struct sockaddr_in sin;

+  struct ip_addr naddr;

+

+  sock = get_socket(s);

+  if (!sock)

+    return -1;

+

+  memset(&sin, 0, sizeof(sin));

+  sin.sin_len = sizeof(sin);

+  sin.sin_family = AF_INET;

+

+  /* get the IP address and port */

+  netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);

+

+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));

+  ip_addr_debug_print(SOCKETS_DEBUG, &naddr);

+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));

+

+  sin.sin_port = htons(sin.sin_port);

+  sin.sin_addr.s_addr = naddr.addr;

+

+  if (*namelen > sizeof(sin))

+    *namelen = sizeof(sin);

+

+  SMEMCPY(name, &sin, *namelen);

+  sock_set_errno(sock, 0);

+  return 0;

+}

+

+int

+lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)

+{

+  return lwip_getaddrname(s, name, namelen, 0);

+}

+

+int

+lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)

+{

+  return lwip_getaddrname(s, name, namelen, 1);

+}

+

+int

+lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)

+{

+  err_t err = ERR_OK;

+  struct lwip_socket *sock = get_socket(s);

+  struct lwip_setgetsockopt_data data;

+

+  if (!sock)

+    return -1;

+

+  if ((NULL == optval) || (NULL == optlen)) {

+    sock_set_errno(sock, EFAULT);

+    return -1;

+  }

+

+  /* Do length and type checks for the various options first, to keep it readable. */

+  switch (level) {

+

+/* Level: SOL_SOCKET */

+  case SOL_SOCKET:

+    switch (optname) {

+

+    case SO_ACCEPTCONN:

+    case SO_BROADCAST:

+    /* UNIMPL case SO_DEBUG: */

+    /* UNIMPL case SO_DONTROUTE: */

+    case SO_ERROR:

+    case SO_KEEPALIVE:

+    /* UNIMPL case SO_CONTIMEO: */

+    /* UNIMPL case SO_SNDTIMEO: */

+#if LWIP_SO_RCVTIMEO

+    case SO_RCVTIMEO:

+#endif /* LWIP_SO_RCVTIMEO */

+#if LWIP_SO_RCVBUF

+    case SO_RCVBUF:

+#endif /* LWIP_SO_RCVBUF */

+    /* UNIMPL case SO_OOBINLINE: */

+    /* UNIMPL case SO_SNDBUF: */

+    /* UNIMPL case SO_RCVLOWAT: */

+    /* UNIMPL case SO_SNDLOWAT: */

+#if SO_REUSE

+    case SO_REUSEADDR:

+    case SO_REUSEPORT:

+#endif /* SO_REUSE */

+    case SO_TYPE:

+    /* UNIMPL case SO_USELOOPBACK: */

+      if (*optlen < sizeof(int)) {

+        err = EINVAL;

+      }

+      break;

+

+    case SO_NO_CHECK:

+      if (*optlen < sizeof(int)) {

+        err = EINVAL;

+      }

+#if LWIP_UDP

+      if ((sock->conn->type != NETCONN_UDP) ||

+          ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {

+        /* this flag is only available for UDP, not for UDP lite */

+        err = EAFNOSUPPORT;

+      }

+#endif /* LWIP_UDP */

+      break;

+

+    default:

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",

+                                  s, optname));

+      err = ENOPROTOOPT;

+    }  /* switch (optname) */

+    break;

+

+/* Level: IPPROTO_IP */

+  case IPPROTO_IP:

+    switch (optname) {

+    /* UNIMPL case IP_HDRINCL: */

+    /* UNIMPL case IP_RCVDSTADDR: */

+    /* UNIMPL case IP_RCVIF: */

+    case IP_TTL:

+    case IP_TOS:

+      if (*optlen < sizeof(int)) {

+        err = EINVAL;

+      }

+      break;

+#if LWIP_IGMP

+    case IP_MULTICAST_TTL:

+      if (*optlen < sizeof(u8_t)) {

+        err = EINVAL;

+      }

+      break;

+    case IP_MULTICAST_IF:

+      if (*optlen < sizeof(struct in_addr)) {

+        err = EINVAL;

+      }

+      break;

+#endif /* LWIP_IGMP */

+

+    default:

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",

+                                  s, optname));

+      err = ENOPROTOOPT;

+    }  /* switch (optname) */

+    break;

+

+#if LWIP_TCP

+/* Level: IPPROTO_TCP */

+  case IPPROTO_TCP:

+    if (*optlen < sizeof(int)) {

+      err = EINVAL;

+      break;

+    }

+

+    /* If this is no TCP socket, ignore any options. */

+    if (sock->conn->type != NETCONN_TCP)

+      return 0;

+

+    switch (optname) {

+    case TCP_NODELAY:

+    case TCP_KEEPALIVE:

+#if LWIP_TCP_KEEPALIVE

+    case TCP_KEEPIDLE:

+    case TCP_KEEPINTVL:

+    case TCP_KEEPCNT:

+#endif /* LWIP_TCP_KEEPALIVE */

+      break;

+

+    default:

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",

+                                  s, optname));

+      err = ENOPROTOOPT;

+    }  /* switch (optname) */

+    break;

+#endif /* LWIP_TCP */

+#if LWIP_UDP && LWIP_UDPLITE

+/* Level: IPPROTO_UDPLITE */

+  case IPPROTO_UDPLITE:

+    if (*optlen < sizeof(int)) {

+      err = EINVAL;

+      break;

+    }

+

+    /* If this is no UDP lite socket, ignore any options. */

+    if (sock->conn->type != NETCONN_UDPLITE)

+      return 0;

+

+    switch (optname) {

+    case UDPLITE_SEND_CSCOV:

+    case UDPLITE_RECV_CSCOV:

+      break;

+

+    default:

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",

+                                  s, optname));

+      err = ENOPROTOOPT;

+    }  /* switch (optname) */

+    break;

+#endif /* LWIP_UDP && LWIP_UDPLITE*/

+/* UNDEFINED LEVEL */

+  default:

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",

+                                  s, level, optname));

+      err = ENOPROTOOPT;

+  }  /* switch */

+

+

+  if (err != ERR_OK) {

+    sock_set_errno(sock, err);

+    return -1;

+  }

+

+  /* Now do the actual option processing */

+  data.sock = sock;

+  data.level = level;

+  data.optname = optname;

+  data.optval = optval;

+  data.optlen = optlen;

+  data.err = err;

+  tcpip_callback(lwip_getsockopt_internal, &data);

+  sys_arch_sem_wait(sock->conn->op_completed, 0);

+  /* maybe lwip_getsockopt_internal has changed err */

+  err = data.err;

+

+  sock_set_errno(sock, err);

+  return err ? -1 : 0;

+}

+

+static void

+lwip_getsockopt_internal(void *arg)

+{

+  struct lwip_socket *sock;

+#ifdef LWIP_DEBUG

+  int s;

+#endif /* LWIP_DEBUG */

+  int level, optname;

+  void *optval;

+  struct lwip_setgetsockopt_data *data;

+

+  LWIP_ASSERT("arg != NULL", arg != NULL);

+

+  data = (struct lwip_setgetsockopt_data*)arg;

+  sock = data->sock;

+#ifdef LWIP_DEBUG

+  s = data->s;

+#endif /* LWIP_DEBUG */

+  level = data->level;

+  optname = data->optname;

+  optval = data->optval;

+

+  switch (level) {

+

+/* Level: SOL_SOCKET */

+  case SOL_SOCKET:

+    switch (optname) {

+

+    /* The option flags */

+    case SO_ACCEPTCONN:

+    case SO_BROADCAST:

+    /* UNIMPL case SO_DEBUG: */

+    /* UNIMPL case SO_DONTROUTE: */

+    case SO_KEEPALIVE:

+    /* UNIMPL case SO_OOBINCLUDE: */

+#if SO_REUSE

+    case SO_REUSEADDR:

+    case SO_REUSEPORT:

+#endif /* SO_REUSE */

+    /*case SO_USELOOPBACK: UNIMPL */

+      *(int*)optval = sock->conn->pcb.ip->so_options & optname;

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",

+                                  s, optname, (*(int*)optval?"on":"off")));

+      break;

+

+    case SO_TYPE:

+      switch (NETCONNTYPE_GROUP(sock->conn->type)) {

+      case NETCONN_RAW:

+        *(int*)optval = SOCK_RAW;

+        break;

+      case NETCONN_TCP:

+        *(int*)optval = SOCK_STREAM;

+        break;

+      case NETCONN_UDP:

+        *(int*)optval = SOCK_DGRAM;

+        break;

+      default: /* unrecognized socket type */

+        *(int*)optval = sock->conn->type;

+        LWIP_DEBUGF(SOCKETS_DEBUG,

+                    ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",

+                    s, *(int *)optval));

+      }  /* switch (sock->conn->type) */

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",

+                  s, *(int *)optval));

+      break;

+

+    case SO_ERROR:

+      if (sock->err == 0) {

+        sock_set_errno(sock, err_to_errno(sock->conn->err));

+      }

+      *(int *)optval = sock->err;

+      sock->err = 0;

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",

+                  s, *(int *)optval));

+      break;

+

+#if LWIP_SO_RCVTIMEO

+    case SO_RCVTIMEO:

+      *(int *)optval = sock->conn->recv_timeout;

+      break;

+#endif /* LWIP_SO_RCVTIMEO */

+#if LWIP_SO_RCVBUF

+    case SO_RCVBUF:

+      *(int *)optval = sock->conn->recv_bufsize;

+      break;

+#endif /* LWIP_SO_RCVBUF */

+#if LWIP_UDP

+    case SO_NO_CHECK:

+      *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;

+      break;

+#endif /* LWIP_UDP*/

+    }  /* switch (optname) */

+    break;

+

+/* Level: IPPROTO_IP */

+  case IPPROTO_IP:

+    switch (optname) {

+    case IP_TTL:

+      *(int*)optval = sock->conn->pcb.ip->ttl;

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",

+                  s, *(int *)optval));

+      break;

+    case IP_TOS:

+      *(int*)optval = sock->conn->pcb.ip->tos;

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",

+                  s, *(int *)optval));

+      break;

+#if LWIP_IGMP

+    case IP_MULTICAST_TTL:

+      *(u8_t*)optval = sock->conn->pcb.ip->ttl;

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",

+                  s, *(int *)optval));

+      break;

+    case IP_MULTICAST_IF:

+      ((struct in_addr*) optval)->s_addr = sock->conn->pcb.udp->multicast_ip.addr;

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%x\n",

+                  s, *(u32_t *)optval));

+      break;

+#endif /* LWIP_IGMP */

+    }  /* switch (optname) */

+    break;

+

+#if LWIP_TCP

+/* Level: IPPROTO_TCP */

+  case IPPROTO_TCP:

+    switch (optname) {

+    case TCP_NODELAY:

+      *(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY);

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",

+                  s, (*(int*)optval)?"on":"off") );

+      break;

+    case TCP_KEEPALIVE:

+      *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",

+                  s, *(int *)optval));

+      break;

+

+#if LWIP_TCP_KEEPALIVE

+    case TCP_KEEPIDLE:

+      *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",

+                  s, *(int *)optval));

+      break;

+    case TCP_KEEPINTVL:

+      *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",

+                  s, *(int *)optval));

+      break;

+    case TCP_KEEPCNT:

+      *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",

+                  s, *(int *)optval));

+      break;

+#endif /* LWIP_TCP_KEEPALIVE */

+

+    }  /* switch (optname) */

+    break;

+#endif /* LWIP_TCP */

+#if LWIP_UDP && LWIP_UDPLITE

+  /* Level: IPPROTO_UDPLITE */

+  case IPPROTO_UDPLITE:

+    switch (optname) {

+    case UDPLITE_SEND_CSCOV:

+      *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",

+                  s, (*(int*)optval)) );

+      break;

+    case UDPLITE_RECV_CSCOV:

+      *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",

+                  s, (*(int*)optval)) );

+      break;

+    }  /* switch (optname) */

+    break;

+#endif /* LWIP_UDP */

+  } /* switch (level) */

+  sys_sem_signal(sock->conn->op_completed);

+}

+

+int

+lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)

+{

+  struct lwip_socket *sock = get_socket(s);

+  int err = ERR_OK;

+  struct lwip_setgetsockopt_data data;

+

+  if (!sock)

+    return -1;

+

+  if (NULL == optval) {

+    sock_set_errno(sock, EFAULT);

+    return -1;

+  }

+

+  /* Do length and type checks for the various options first, to keep it readable. */

+  switch (level) {

+

+/* Level: SOL_SOCKET */

+  case SOL_SOCKET:

+    switch (optname) {

+

+    case SO_BROADCAST:

+    /* UNIMPL case SO_DEBUG: */

+    /* UNIMPL case SO_DONTROUTE: */

+    case SO_KEEPALIVE:

+    /* UNIMPL case case SO_CONTIMEO: */

+    /* UNIMPL case case SO_SNDTIMEO: */

+#if LWIP_SO_RCVTIMEO

+    case SO_RCVTIMEO:

+#endif /* LWIP_SO_RCVTIMEO */

+#if LWIP_SO_RCVBUF

+    case SO_RCVBUF:

+#endif /* LWIP_SO_RCVBUF */

+    /* UNIMPL case SO_OOBINLINE: */

+    /* UNIMPL case SO_SNDBUF: */

+    /* UNIMPL case SO_RCVLOWAT: */

+    /* UNIMPL case SO_SNDLOWAT: */

+#if SO_REUSE

+    case SO_REUSEADDR:

+    case SO_REUSEPORT:

+#endif /* SO_REUSE */

+    /* UNIMPL case SO_USELOOPBACK: */

+      if (optlen < sizeof(int)) {

+        err = EINVAL;

+      }

+      break;

+    case SO_NO_CHECK:

+      if (optlen < sizeof(int)) {

+        err = EINVAL;

+      }

+#if LWIP_UDP

+      if ((sock->conn->type != NETCONN_UDP) ||

+          ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {

+        /* this flag is only available for UDP, not for UDP lite */

+        err = EAFNOSUPPORT;

+      }

+#endif /* LWIP_UDP */

+      break;

+    default:

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",

+                  s, optname));

+      err = ENOPROTOOPT;

+    }  /* switch (optname) */

+    break;

+

+/* Level: IPPROTO_IP */

+  case IPPROTO_IP:

+    switch (optname) {

+    /* UNIMPL case IP_HDRINCL: */

+    /* UNIMPL case IP_RCVDSTADDR: */

+    /* UNIMPL case IP_RCVIF: */

+    case IP_TTL:

+    case IP_TOS:

+      if (optlen < sizeof(int)) {

+        err = EINVAL;

+      }

+      break;

+#if LWIP_IGMP

+    case IP_MULTICAST_TTL:

+      if (optlen < sizeof(u8_t)) {

+        err = EINVAL;

+      }

+      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {

+        err = EAFNOSUPPORT;

+      }

+      break;

+    case IP_MULTICAST_IF:

+      if (optlen < sizeof(struct in_addr)) {

+        err = EINVAL;

+      }

+      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {

+        err = EAFNOSUPPORT;

+      }

+      break;

+    case IP_ADD_MEMBERSHIP:

+    case IP_DROP_MEMBERSHIP:

+      if (optlen < sizeof(struct ip_mreq)) {

+        err = EINVAL;

+      }

+      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {

+        err = EAFNOSUPPORT;

+      }

+      break;

+#endif /* LWIP_IGMP */

+      default:

+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",

+                    s, optname));

+        err = ENOPROTOOPT;

+    }  /* switch (optname) */

+    break;

+

+#if LWIP_TCP

+/* Level: IPPROTO_TCP */

+  case IPPROTO_TCP:

+    if (optlen < sizeof(int)) {

+      err = EINVAL;

+      break;

+    }

+

+    /* If this is no TCP socket, ignore any options. */

+    if (sock->conn->type != NETCONN_TCP)

+      return 0;

+

+    switch (optname) {

+    case TCP_NODELAY:

+    case TCP_KEEPALIVE:

+#if LWIP_TCP_KEEPALIVE

+    case TCP_KEEPIDLE:

+    case TCP_KEEPINTVL:

+    case TCP_KEEPCNT:

+#endif /* LWIP_TCP_KEEPALIVE */

+      break;

+

+    default:

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",

+                  s, optname));

+      err = ENOPROTOOPT;

+    }  /* switch (optname) */

+    break;

+#endif /* LWIP_TCP */

+#if LWIP_UDP && LWIP_UDPLITE

+/* Level: IPPROTO_UDPLITE */

+  case IPPROTO_UDPLITE:

+    if (optlen < sizeof(int)) {

+      err = EINVAL;

+      break;

+    }

+

+    /* If this is no UDP lite socket, ignore any options. */

+    if (sock->conn->type != NETCONN_UDPLITE)

+      return 0;

+

+    switch (optname) {

+    case UDPLITE_SEND_CSCOV:

+    case UDPLITE_RECV_CSCOV:

+      break;

+

+    default:

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",

+                  s, optname));

+      err = ENOPROTOOPT;

+    }  /* switch (optname) */

+    break;

+#endif /* LWIP_UDP && LWIP_UDPLITE */

+/* UNDEFINED LEVEL */

+  default:

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",

+                s, level, optname));

+    err = ENOPROTOOPT;

+  }  /* switch (level) */

+

+

+  if (err != ERR_OK) {

+    sock_set_errno(sock, err);

+    return -1;

+  }

+

+

+  /* Now do the actual option processing */

+  data.sock = sock;

+  data.level = level;

+  data.optname = optname;

+  data.optval = (void*)optval;

+  data.optlen = &optlen;

+  data.err = err;

+  tcpip_callback(lwip_setsockopt_internal, &data);

+  sys_arch_sem_wait(sock->conn->op_completed, 0);

+  /* maybe lwip_setsockopt_internal has changed err */

+  err = data.err;

+

+  sock_set_errno(sock, err);

+  return err ? -1 : 0;

+}

+

+static void

+lwip_setsockopt_internal(void *arg)

+{

+  struct lwip_socket *sock;

+#ifdef LWIP_DEBUG

+  int s;

+#endif /* LWIP_DEBUG */

+  int level, optname;

+  const void *optval;

+  struct lwip_setgetsockopt_data *data;

+

+  LWIP_ASSERT("arg != NULL", arg != NULL);

+

+  data = (struct lwip_setgetsockopt_data*)arg;

+  sock = data->sock;

+#ifdef LWIP_DEBUG

+  s = data->s;

+#endif /* LWIP_DEBUG */

+  level = data->level;

+  optname = data->optname;

+  optval = data->optval;

+

+  switch (level) {

+

+/* Level: SOL_SOCKET */

+  case SOL_SOCKET:

+    switch (optname) {

+

+    /* The option flags */

+    case SO_BROADCAST:

+    /* UNIMPL case SO_DEBUG: */

+    /* UNIMPL case SO_DONTROUTE: */

+    case SO_KEEPALIVE:

+    /* UNIMPL case SO_OOBINCLUDE: */

+#if SO_REUSE

+    case SO_REUSEADDR:

+    case SO_REUSEPORT:

+#endif /* SO_REUSE */

+    /* UNIMPL case SO_USELOOPBACK: */

+      if (*(int*)optval) {

+        sock->conn->pcb.ip->so_options |= optname;

+      } else {

+        sock->conn->pcb.ip->so_options &= ~optname;

+      }

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",

+                  s, optname, (*(int*)optval?"on":"off")));

+      break;

+#if LWIP_SO_RCVTIMEO

+    case SO_RCVTIMEO:

+      sock->conn->recv_timeout = ( *(int*)optval );

+      break;

+#endif /* LWIP_SO_RCVTIMEO */

+#if LWIP_SO_RCVBUF

+    case SO_RCVBUF:

+      sock->conn->recv_bufsize = ( *(int*)optval );

+      break;

+#endif /* LWIP_SO_RCVBUF */

+#if LWIP_UDP

+    case SO_NO_CHECK:

+      if (*(int*)optval) {

+        udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);

+      } else {

+        udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);

+      }

+      break;

+#endif /* LWIP_UDP */

+    }  /* switch (optname) */

+    break;

+

+/* Level: IPPROTO_IP */

+  case IPPROTO_IP:

+    switch (optname) {

+    case IP_TTL:

+      sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %u\n",

+                  s, sock->conn->pcb.ip->ttl));

+      break;

+    case IP_TOS:

+      sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n",

+                  s, sock->conn->pcb.ip->tos));

+      break;

+#if LWIP_IGMP

+    case IP_MULTICAST_TTL:

+      sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);

+      break;

+    case IP_MULTICAST_IF:

+      sock->conn->pcb.udp->multicast_ip.addr = ((struct in_addr*) optval)->s_addr;

+      break;

+    case IP_ADD_MEMBERSHIP:

+    case IP_DROP_MEMBERSHIP:

+      {

+        /* If this is a TCP or a RAW socket, ignore these options. */

+        struct ip_mreq *imr = (struct ip_mreq *)optval;

+        if(optname == IP_ADD_MEMBERSHIP){

+          data->err = igmp_joingroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr));

+        } else {

+          data->err = igmp_leavegroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr));

+        }

+        if(data->err != ERR_OK) {

+          data->err = EADDRNOTAVAIL;

+        }

+      }

+      break;

+#endif /* LWIP_IGMP */

+    }  /* switch (optname) */

+    break;

+

+#if LWIP_TCP

+/* Level: IPPROTO_TCP */

+  case IPPROTO_TCP:

+    switch (optname) {

+    case TCP_NODELAY:

+      if (*(int*)optval) {

+        sock->conn->pcb.tcp->flags |= TF_NODELAY;

+      } else {

+        sock->conn->pcb.tcp->flags &= ~TF_NODELAY;

+      }

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",

+                  s, (*(int *)optval)?"on":"off") );

+      break;

+    case TCP_KEEPALIVE:

+      sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %lu\n",

+                  s, sock->conn->pcb.tcp->keep_idle));

+      break;

+

+#if LWIP_TCP_KEEPALIVE

+    case TCP_KEEPIDLE:

+      sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %lu\n",

+                  s, sock->conn->pcb.tcp->keep_idle));

+      break;

+    case TCP_KEEPINTVL:

+      sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %lu\n",

+                  s, sock->conn->pcb.tcp->keep_intvl));

+      break;

+    case TCP_KEEPCNT:

+      sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %lu\n",

+                  s, sock->conn->pcb.tcp->keep_cnt));

+      break;

+#endif /* LWIP_TCP_KEEPALIVE */

+

+    }  /* switch (optname) */

+    break;

+#endif /* LWIP_TCP*/

+#if LWIP_UDP && LWIP_UDPLITE

+  /* Level: IPPROTO_UDPLITE */

+  case IPPROTO_UDPLITE:

+    switch (optname) {

+    case UDPLITE_SEND_CSCOV:

+      if ((*(int*)optval != 0) && (*(int*)optval < 8)) {

+        /* don't allow illegal values! */

+        sock->conn->pcb.udp->chksum_len_tx = 8;

+      } else {

+        sock->conn->pcb.udp->chksum_len_tx = *(int*)optval;

+      }

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",

+                  s, (*(int*)optval)) );

+      break;

+    case UDPLITE_RECV_CSCOV:

+      if ((*(int*)optval != 0) && (*(int*)optval < 8)) {

+        /* don't allow illegal values! */

+        sock->conn->pcb.udp->chksum_len_rx = 8;

+      } else {

+        sock->conn->pcb.udp->chksum_len_rx = *(int*)optval;

+      }

+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",

+                  s, (*(int*)optval)) );

+      break;

+    }  /* switch (optname) */

+    break;

+#endif /* LWIP_UDP */

+  }  /* switch (level) */

+  sys_sem_signal(sock->conn->op_completed);

+}

+

+int

+lwip_ioctl(int s, long cmd, void *argp)

+{

+  struct lwip_socket *sock = get_socket(s);

+  u16_t buflen = 0;

+

+  if (!sock)

+    return -1;

+

+  switch (cmd) {

+  case FIONREAD:

+    if (!argp) {

+      sock_set_errno(sock, EINVAL);

+      return -1;

+    }

+

+    SYS_ARCH_GET(sock->conn->recv_avail, *((u16_t*)argp));

+

+    /* Check if there is data left from the last recv operation. /maq 041215 */

+    if (sock->lastdata) {

+      buflen = netbuf_len(sock->lastdata);

+      buflen -= sock->lastoffset;

+

+      *((u16_t*)argp) += buflen;

+    }

+

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16_t*)argp)));

+    sock_set_errno(sock, 0);

+    return 0;

+

+  case FIONBIO:

+    if (argp && *(u32_t*)argp)

+      sock->flags |= O_NONBLOCK;

+    else

+      sock->flags &= ~O_NONBLOCK;

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK)));

+    sock_set_errno(sock, 0);

+    return 0;

+

+  default:

+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));

+    sock_set_errno(sock, ENOSYS); /* not yet implemented */

+    return -1;

+  } /* switch (cmd) */

+}

+

+#endif /* LWIP_SOCKET */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/tcpip.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/tcpip.c
new file mode 100644
index 0000000..b22894e
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/api/tcpip.c
@@ -0,0 +1,521 @@
+/**

+ * @file

+ * Sequential API Main thread module

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if !NO_SYS /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/sys.h"

+#include "lwip/memp.h"

+#include "lwip/pbuf.h"

+#include "lwip/ip_frag.h"

+#include "lwip/tcp.h"

+#include "lwip/autoip.h"

+#include "lwip/dhcp.h"

+#include "lwip/igmp.h"

+#include "lwip/dns.h"

+#include "lwip/tcpip.h"

+#include "lwip/init.h"

+#include "netif/etharp.h"

+#include "netif/ppp_oe.h"

+

+/* global variables */

+static void (* tcpip_init_done)(void *arg);

+static void *tcpip_init_done_arg;

+static sys_mbox_t mbox = SYS_MBOX_NULL;

+

+#if LWIP_TCPIP_CORE_LOCKING

+/** The global semaphore to lock the stack. */

+sys_sem_t lock_tcpip_core;

+#endif /* LWIP_TCPIP_CORE_LOCKING */

+

+#if LWIP_TCP

+/* global variable that shows if the tcp timer is currently scheduled or not */

+static int tcpip_tcp_timer_active;

+

+/**

+ * Timer callback function that calls tcp_tmr() and reschedules itself.

+ *

+ * @param arg unused argument

+ */

+static void

+tcpip_tcp_timer(void *arg)

+{

+  LWIP_UNUSED_ARG(arg);

+

+  /* call TCP timer handler */

+  tcp_tmr();

+  /* timer still needed? */

+  if (tcp_active_pcbs || tcp_tw_pcbs) {

+    /* restart timer */

+    sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);

+  } else {

+    /* disable timer */

+    tcpip_tcp_timer_active = 0;

+  }

+}

+

+#if !NO_SYS

+/**

+ * Called from TCP_REG when registering a new PCB:

+ * the reason is to have the TCP timer only running when

+ * there are active (or time-wait) PCBs.

+ */

+void

+tcp_timer_needed(void)

+{

+  /* timer is off but needed again? */

+  if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {

+    /* enable and start timer */

+    tcpip_tcp_timer_active = 1;

+    sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);

+  }

+}

+#endif /* !NO_SYS */

+#endif /* LWIP_TCP */

+

+#if IP_REASSEMBLY

+/**

+ * Timer callback function that calls ip_reass_tmr() and reschedules itself.

+ *

+ * @param arg unused argument

+ */

+static void

+ip_reass_timer(void *arg)

+{

+  LWIP_UNUSED_ARG(arg);

+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n"));

+  ip_reass_tmr();

+  sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);

+}

+#endif /* IP_REASSEMBLY */

+

+#if LWIP_ARP

+/**

+ * Timer callback function that calls etharp_tmr() and reschedules itself.

+ *

+ * @param arg unused argument

+ */

+static void

+arp_timer(void *arg)

+{

+  LWIP_UNUSED_ARG(arg);

+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: etharp_tmr()\n"));

+  etharp_tmr();

+  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);

+}

+#endif /* LWIP_ARP */

+

+#if LWIP_DHCP

+/**

+ * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.

+ *

+ * @param arg unused argument

+ */

+static void

+dhcp_timer_coarse(void *arg)

+{

+  LWIP_UNUSED_ARG(arg);

+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));

+  dhcp_coarse_tmr();

+  sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);

+}

+

+/**

+ * Timer callback function that calls dhcp_fine_tmr() and reschedules itself.

+ *

+ * @param arg unused argument

+ */

+static void

+dhcp_timer_fine(void *arg)

+{

+  LWIP_UNUSED_ARG(arg);

+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));

+  dhcp_fine_tmr();

+  sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);

+}

+#endif /* LWIP_DHCP */

+

+#if LWIP_AUTOIP

+/**

+ * Timer callback function that calls autoip_tmr() and reschedules itself.

+ *

+ * @param arg unused argument

+ */

+static void

+autoip_timer(void *arg)

+{

+  LWIP_UNUSED_ARG(arg);

+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: autoip_tmr()\n"));

+  autoip_tmr();

+  sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);

+}

+#endif /* LWIP_AUTOIP */

+

+#if LWIP_IGMP

+/**

+ * Timer callback function that calls igmp_tmr() and reschedules itself.

+ *

+ * @param arg unused argument

+ */

+static void

+igmp_timer(void *arg)

+{

+  LWIP_UNUSED_ARG(arg);

+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: igmp_tmr()\n"));

+  igmp_tmr();

+  sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);

+}

+#endif /* LWIP_IGMP */

+

+#if LWIP_DNS

+/**

+ * Timer callback function that calls dns_tmr() and reschedules itself.

+ *

+ * @param arg unused argument

+ */

+static void

+dns_timer(void *arg)

+{

+  LWIP_UNUSED_ARG(arg);

+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dns_tmr()\n"));

+  dns_tmr();

+  sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);

+}

+#endif /* LWIP_DNS */

+

+/**

+ * The main lwIP thread. This thread has exclusive access to lwIP core functions

+ * (unless access to them is not locked). Other threads communicate with this

+ * thread using message boxes.

+ *

+ * It also starts all the timers to make sure they are running in the right

+ * thread context.

+ *

+ * @param arg unused argument

+ */

+static void

+tcpip_thread(void *arg)

+{

+  struct tcpip_msg *msg;

+  LWIP_UNUSED_ARG(arg);

+

+#if IP_REASSEMBLY

+  sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);

+#endif /* IP_REASSEMBLY */

+#if LWIP_ARP

+  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);

+#endif /* LWIP_ARP */

+#if LWIP_DHCP

+  sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);

+  sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);

+#endif /* LWIP_DHCP */

+#if LWIP_AUTOIP

+  sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);

+#endif /* LWIP_AUTOIP */

+#if LWIP_IGMP

+  sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);

+#endif /* LWIP_IGMP */

+#if LWIP_DNS

+  sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);

+#endif /* LWIP_DNS */

+

+  if (tcpip_init_done != NULL) {

+    tcpip_init_done(tcpip_init_done_arg);

+  }

+

+  LOCK_TCPIP_CORE();

+  while (1) {                          /* MAIN Loop */

+    sys_mbox_fetch(mbox, (void *)&msg);

+    switch (msg->type) {

+#if LWIP_NETCONN

+    case TCPIP_MSG_API:

+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));

+      msg->msg.apimsg->function(&(msg->msg.apimsg->msg));

+      break;

+#endif /* LWIP_NETCONN */

+

+    case TCPIP_MSG_INPKT:

+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));

+#if LWIP_ARP

+      if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP) {

+        ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);

+      } else

+#endif /* LWIP_ARP */

+      { ip_input(msg->msg.inp.p, msg->msg.inp.netif);

+      }

+      memp_free(MEMP_TCPIP_MSG_INPKT, msg);

+      break;

+

+#if LWIP_NETIF_API

+    case TCPIP_MSG_NETIFAPI:

+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));

+      msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));

+      break;

+#endif /* LWIP_NETIF_API */

+

+    case TCPIP_MSG_CALLBACK:

+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));

+      msg->msg.cb.f(msg->msg.cb.ctx);

+      memp_free(MEMP_TCPIP_MSG_API, msg);

+      break;

+

+    case TCPIP_MSG_TIMEOUT:

+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));

+

+      if(msg->msg.tmo.msecs != 0xffffffff)

+        sys_timeout (msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);

+      else

+        sys_untimeout (msg->msg.tmo.h, msg->msg.tmo.arg);

+      memp_free(MEMP_TCPIP_MSG_API, msg);

+      break;

+

+    default:

+      break;

+    }

+  }

+}

+

+/**

+ * Pass a received packet to tcpip_thread for input processing

+ *

+ * @param p the received packet, p->payload pointing to the Ethernet header or

+ *          to an IP header (if netif doesn't got NETIF_FLAG_ETHARP flag)

+ * @param inp the network interface on which the packet was received

+ */

+err_t

+tcpip_input(struct pbuf *p, struct netif *inp)

+{

+  struct tcpip_msg *msg;

+

+  if (mbox != SYS_MBOX_NULL) {

+    msg = memp_malloc(MEMP_TCPIP_MSG_INPKT);

+    if (msg == NULL) {

+      return ERR_MEM;

+    }

+

+    msg->type = TCPIP_MSG_INPKT;

+    msg->msg.inp.p = p;

+    msg->msg.inp.netif = inp;

+    if (sys_mbox_trypost(mbox, msg) != ERR_OK) {

+      memp_free(MEMP_TCPIP_MSG_INPKT, msg);

+      return ERR_MEM;

+    }

+    return ERR_OK;

+  }

+  return ERR_VAL;

+}

+

+/**

+ * Call a specific function in the thread context of

+ * tcpip_thread for easy access synchronization.

+ * A function called in that way may access lwIP core code

+ * without fearing concurrent access.

+ *

+ * @param f the function to call

+ * @param ctx parameter passed to f

+ * @param block 1 to block until the request is posted, 0 to non-blocking mode

+ * @return ERR_OK if the function was called, another err_t if not

+ */

+err_t

+tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block)

+{

+  struct tcpip_msg *msg;

+

+  if (mbox != SYS_MBOX_NULL) {

+    msg = memp_malloc(MEMP_TCPIP_MSG_API);

+    if (msg == NULL) {

+      return ERR_MEM;

+    }

+

+    msg->type = TCPIP_MSG_CALLBACK;

+    msg->msg.cb.f = f;

+    msg->msg.cb.ctx = ctx;

+    if (block) {

+      sys_mbox_post(mbox, msg);

+    } else {

+      if (sys_mbox_trypost(mbox, msg) != ERR_OK) {

+        memp_free(MEMP_TCPIP_MSG_API, msg);

+        return ERR_MEM;

+      }

+    }

+    return ERR_OK;

+  }

+  return ERR_VAL;

+}

+

+err_t

+tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)

+{

+  struct tcpip_msg *msg;

+

+  if (mbox != SYS_MBOX_NULL) {

+    msg = memp_malloc(MEMP_TCPIP_MSG_API);

+    if (msg == NULL) {

+      return ERR_MEM;

+    }

+

+    msg->type = TCPIP_MSG_TIMEOUT;

+    msg->msg.tmo.msecs = msecs;

+    msg->msg.tmo.h = h;

+    msg->msg.tmo.arg = arg;

+    sys_mbox_post(mbox, msg);

+    return ERR_OK;

+  }

+  return ERR_VAL;

+}

+

+#if LWIP_NETCONN

+/**

+ * Call the lower part of a netconn_* function

+ * This function is then running in the thread context

+ * of tcpip_thread and has exclusive access to lwIP core code.

+ *

+ * @param apimsg a struct containing the function to call and its parameters

+ * @return ERR_OK if the function was called, another err_t if not

+ */

+err_t

+tcpip_apimsg(struct api_msg *apimsg)

+{

+  struct tcpip_msg msg;

+

+  if (mbox != SYS_MBOX_NULL) {

+    msg.type = TCPIP_MSG_API;

+    msg.msg.apimsg = apimsg;

+    sys_mbox_post(mbox, &msg);

+    sys_arch_sem_wait(apimsg->msg.conn->op_completed, 0);

+    return ERR_OK;

+  }

+  return ERR_VAL;

+}

+

+#if LWIP_TCPIP_CORE_LOCKING

+/**

+ * Call the lower part of a netconn_* function

+ * This function has exclusive access to lwIP core code by locking it

+ * before the function is called.

+ *

+ * @param apimsg a struct containing the function to call and its parameters

+ * @return ERR_OK (only for compatibility fo tcpip_apimsg())

+ */

+err_t

+tcpip_apimsg_lock(struct api_msg *apimsg)

+{

+  LOCK_TCPIP_CORE();

+  apimsg->function(&(apimsg->msg));

+  UNLOCK_TCPIP_CORE();

+  return ERR_OK;

+

+}

+#endif /* LWIP_TCPIP_CORE_LOCKING */

+#endif /* LWIP_NETCONN */

+

+#if LWIP_NETIF_API

+#if !LWIP_TCPIP_CORE_LOCKING

+/**

+ * Much like tcpip_apimsg, but calls the lower part of a netifapi_*

+ * function.

+ *

+ * @param netifapimsg a struct containing the function to call and its parameters

+ * @return error code given back by the function that was called

+ */

+err_t

+tcpip_netifapi(struct netifapi_msg* netifapimsg)

+{

+  struct tcpip_msg msg;

+

+  if (mbox != SYS_MBOX_NULL) {

+    netifapimsg->msg.sem = sys_sem_new(0);

+    if (netifapimsg->msg.sem == SYS_SEM_NULL) {

+      netifapimsg->msg.err = ERR_MEM;

+      return netifapimsg->msg.err;

+    }

+

+    msg.type = TCPIP_MSG_NETIFAPI;

+    msg.msg.netifapimsg = netifapimsg;

+    sys_mbox_post(mbox, &msg);

+    sys_sem_wait(netifapimsg->msg.sem);

+    sys_sem_free(netifapimsg->msg.sem);

+    return netifapimsg->msg.err;

+  }

+  return ERR_VAL;

+}

+#else /* !LWIP_TCPIP_CORE_LOCKING */

+/**

+ * Call the lower part of a netifapi_* function

+ * This function has exclusive access to lwIP core code by locking it

+ * before the function is called.

+ *

+ * @param netifapimsg a struct containing the function to call and its parameters

+ * @return ERR_OK (only for compatibility fo tcpip_netifapi())

+ */

+err_t

+tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)

+{

+  LOCK_TCPIP_CORE();

+  netifapimsg->function(&(netifapimsg->msg));

+  UNLOCK_TCPIP_CORE();

+  return netifapimsg->msg.err;

+}

+#endif /* !LWIP_TCPIP_CORE_LOCKING */

+#endif /* LWIP_NETIF_API */

+

+/**

+ * Initialize this module:

+ * - initialize all sub modules

+ * - start the tcpip_thread

+ *

+ * @param initfunc a function to call when tcpip_thread is running and finished initializing

+ * @param arg argument to pass to initfunc

+ */

+void

+tcpip_init(void (* initfunc)(void *), void *arg)

+{

+  lwip_init();

+

+  tcpip_init_done = initfunc;

+  tcpip_init_done_arg = arg;

+  mbox = sys_mbox_new(TCPIP_MBOX_SIZE);

+#if LWIP_TCPIP_CORE_LOCKING

+  lock_tcpip_core = sys_sem_new(1);

+#endif /* LWIP_TCPIP_CORE_LOCKING */

+

+  sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);

+}

+

+#endif /* !NO_SYS */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/dhcp.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/dhcp.c
new file mode 100644
index 0000000..f0c41c6
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/dhcp.c
@@ -0,0 +1,1548 @@
+/**

+ * @file

+ * Dynamic Host Configuration Protocol client

+ *

+ */

+

+/*

+ *

+ * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net>

+ * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is a contribution to the lwIP TCP/IP stack.

+ * The Swedish Institute of Computer Science and Adam Dunkels

+ * are specifically granted permission to redistribute this

+ * source code.

+ *

+ * Author: Leon Woestenberg <leon.woestenberg@gmx.net>

+ *

+ * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform

+ * with RFC 2131 and RFC 2132.

+ *

+ * TODO:

+ * - Proper parsing of DHCP messages exploiting file/sname field overloading.

+ * - Add JavaDoc style documentation (API, internals).

+ * - Support for interfaces other than Ethernet (SLIP, PPP, ...)

+ *

+ * Please coordinate changes and requests with Leon Woestenberg

+ * <leon.woestenberg@gmx.net>

+ *

+ * Integration with your code:

+ *

+ * In lwip/dhcp.h

+ * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)

+ * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)

+ *

+ * Then have your application call dhcp_coarse_tmr() and

+ * dhcp_fine_tmr() on the defined intervals.

+ *

+ * dhcp_start(struct netif *netif);

+ * starts a DHCP client instance which configures the interface by

+ * obtaining an IP address lease and maintaining it.

+ *

+ * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)

+ * to remove the DHCP client.

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/stats.h"

+#include "lwip/mem.h"

+#include "lwip/udp.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/inet.h"

+#include "lwip/sys.h"

+#include "lwip/dhcp.h"

+#include "lwip/autoip.h"

+#include "lwip/dns.h"

+#include "netif/etharp.h"

+

+#include <string.h>

+

+/** global transaction identifier, must be

+ *  unique for each DHCP request. We simply increment, starting

+ *  with this value (easy to match with a packet analyzer) */

+static u32_t xid = 0xABCD0000;

+

+/* DHCP client state machine functions */

+static void dhcp_handle_ack(struct netif *netif);

+static void dhcp_handle_nak(struct netif *netif);

+static void dhcp_handle_offer(struct netif *netif);

+

+static err_t dhcp_discover(struct netif *netif);

+static err_t dhcp_select(struct netif *netif);

+static void dhcp_check(struct netif *netif);

+static void dhcp_bind(struct netif *netif);

+#if DHCP_DOES_ARP_CHECK

+static err_t dhcp_decline(struct netif *netif);

+#endif /* DHCP_DOES_ARP_CHECK */

+static err_t dhcp_rebind(struct netif *netif);

+static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state);

+

+/* receive, unfold, parse and free incoming messages */

+static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);

+static err_t dhcp_unfold_reply(struct dhcp *dhcp);

+static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type);

+static u8_t dhcp_get_option_byte(u8_t *ptr);

+#if 0

+static u16_t dhcp_get_option_short(u8_t *ptr);

+#endif

+static u32_t dhcp_get_option_long(u8_t *ptr);

+static void dhcp_free_reply(struct dhcp *dhcp);

+

+/* set the DHCP timers */

+static void dhcp_timeout(struct netif *netif);

+static void dhcp_t1_timeout(struct netif *netif);

+static void dhcp_t2_timeout(struct netif *netif);

+

+/* build outgoing messages */

+/* create a DHCP request, fill in common headers */

+static err_t dhcp_create_request(struct netif *netif);

+/* free a DHCP request */

+static void dhcp_delete_request(struct netif *netif);

+/* add a DHCP option (type, then length in bytes) */

+static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);

+/* add option values */

+static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);

+static void dhcp_option_short(struct dhcp *dhcp, u16_t value);

+static void dhcp_option_long(struct dhcp *dhcp, u32_t value);

+/* always add the DHCP options trailer to end and pad */

+static void dhcp_option_trailer(struct dhcp *dhcp);

+

+/**

+ * Back-off the DHCP client (because of a received NAK response).

+ *

+ * Back-off the DHCP client because of a received NAK. Receiving a

+ * NAK means the client asked for something non-sensible, for

+ * example when it tries to renew a lease obtained on another network.

+ *

+ * We clear any existing set IP address and restart DHCP negotiation

+ * afresh (as per RFC2131 3.2.3).

+ *

+ * @param netif the netif under DHCP control

+ */

+static void

+dhcp_handle_nak(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n",

+    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));

+  /* Set the interface down since the address must no longer be used, as per RFC2131 */

+  netif_set_down(netif);

+  /* remove IP address from interface */

+  netif_set_ipaddr(netif, IP_ADDR_ANY);

+  netif_set_gw(netif, IP_ADDR_ANY);

+  netif_set_netmask(netif, IP_ADDR_ANY);

+  /* Change to a defined state */

+  dhcp_set_state(dhcp, DHCP_BACKING_OFF);

+  /* We can immediately restart discovery */

+  dhcp_discover(netif);

+}

+

+/**

+ * Checks if the offered IP address is already in use.

+ *

+ * It does so by sending an ARP request for the offered address and

+ * entering CHECKING state. If no ARP reply is received within a small

+ * interval, the address is assumed to be free for use by us.

+ *

+ * @param netif the netif under DHCP control

+ */

+static void

+dhcp_check(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result;

+  u16_t msecs;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],

+    (s16_t)netif->name[1]));

+  /* create an ARP query for the offered IP address, expecting that no host

+     responds, as the IP address should not be in use. */

+  result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);

+  if (result != ERR_OK) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_check: could not perform ARP query\n"));

+  }

+  dhcp->tries++;

+  msecs = 500;

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs));

+  dhcp_set_state(dhcp, DHCP_CHECKING);

+}

+

+/**

+ * Remember the configuration offered by a DHCP server.

+ *

+ * @param netif the netif under DHCP control

+ */

+static void

+dhcp_handle_offer(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  /* obtain the server address */

+  u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID);

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",

+    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));

+  if (option_ptr != NULL) {

+    dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", dhcp->server_ip_addr.addr));

+    /* remember offered address */

+    ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr);

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));

+

+    dhcp_select(netif);

+  }

+}

+

+/**

+ * Select a DHCP server offer out of all offers.

+ *

+ * Simply select the first offer received.

+ *

+ * @param netif the netif under DHCP control

+ * @return lwIP specific error (see error.h)

+ */

+static err_t

+dhcp_select(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result;

+  u16_t msecs;

+#if LWIP_NETIF_HOSTNAME

+  const char *p;

+#endif /* LWIP_NETIF_HOSTNAME */

+

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));

+

+  /* create and initialize the DHCP message header */

+  result = dhcp_create_request(netif);

+  if (result == ERR_OK) {

+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);

+    dhcp_option_byte(dhcp, DHCP_REQUEST);

+

+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);

+    dhcp_option_short(dhcp, 576);

+

+    /* MUST request the offered IP address */

+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);

+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));

+

+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);

+    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));

+

+    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);

+    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);

+    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);

+    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);

+    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);

+

+#if LWIP_NETIF_HOSTNAME

+    p = (const char*)netif->hostname;

+    if (p!=NULL) {

+      dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p));

+      while (*p) {

+        dhcp_option_byte(dhcp, *p++);

+      }

+    }

+#endif /* LWIP_NETIF_HOSTNAME */

+

+    dhcp_option_trailer(dhcp);

+    /* shrink the pbuf to the actual content length */

+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

+

+    /* TODO: we really should bind to a specific local interface here

+       but we cannot specify an unconfigured netif as it is addressless */

+    /* send broadcast to any DHCP server */

+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);

+    /* reconnect to any (or to server here?!) */

+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);

+    dhcp_delete_request(netif);

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));

+    dhcp_set_state(dhcp, DHCP_REQUESTING);

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));

+  }

+  dhcp->tries++;

+  msecs = dhcp->tries < 4 ? dhcp->tries * 1000 : 4 * 1000;

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs));

+  return result;

+}

+

+/**

+ * The DHCP timer that checks for lease renewal/rebind timeouts.

+ *

+ */

+void

+dhcp_coarse_tmr()

+{

+  struct netif *netif = netif_list;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n"));

+  /* iterate through all network interfaces */

+  while (netif != NULL) {

+    /* only act on DHCP configured interfaces */

+    if (netif->dhcp != NULL) {

+      /* timer is active (non zero), and triggers (zeroes) now? */

+      if (netif->dhcp->t2_timeout-- == 1) {

+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));

+        /* this clients' rebind timeout triggered */

+        dhcp_t2_timeout(netif);

+      /* timer is active (non zero), and triggers (zeroes) now */

+      } else if (netif->dhcp->t1_timeout-- == 1) {

+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));

+        /* this clients' renewal timeout triggered */

+        dhcp_t1_timeout(netif);

+      }

+    }

+    /* proceed to next netif */

+    netif = netif->next;

+  }

+}

+

+/**

+ * DHCP transaction timeout handling

+ *

+ * A DHCP server is expected to respond within a short period of time.

+ * This timer checks whether an outstanding DHCP request is timed out.

+ *

+ */

+void

+dhcp_fine_tmr()

+{

+  struct netif *netif = netif_list;

+  /* loop through netif's */

+  while (netif != NULL) {

+    /* only act on DHCP configured interfaces */

+    if (netif->dhcp != NULL) {

+      /* timer is active (non zero), and is about to trigger now */

+      if (netif->dhcp->request_timeout > 1) {

+        netif->dhcp->request_timeout--;

+      }

+      else if (netif->dhcp->request_timeout == 1) {

+        netif->dhcp->request_timeout--;

+        /* { netif->dhcp->request_timeout == 0 } */

+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));

+        /* this clients' request timeout triggered */

+        dhcp_timeout(netif);

+      }

+    }

+    /* proceed to next network interface */

+    netif = netif->next;

+  }

+}

+

+/**

+ * A DHCP negotiation transaction, or ARP request, has timed out.

+ *

+ * The timer that was started with the DHCP or ARP request has

+ * timed out, indicating no response was received in time.

+ *

+ * @param netif the netif under DHCP control

+ */

+static void

+dhcp_timeout(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_timeout()\n"));

+  /* back-off period has passed, or server selection timed out */

+  if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));

+    dhcp_discover(netif);

+  /* receiving the requested lease timed out */

+  } else if (dhcp->state == DHCP_REQUESTING) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));

+    if (dhcp->tries <= 5) {

+      dhcp_select(netif);

+    } else {

+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));

+      dhcp_release(netif);

+      dhcp_discover(netif);

+    }

+  /* received no ARP reply for the offered address (which is good) */

+  } else if (dhcp->state == DHCP_CHECKING) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));

+    if (dhcp->tries <= 1) {

+      dhcp_check(netif);

+    /* no ARP replies on the offered address,

+       looks like the IP address is indeed free */

+    } else {

+      /* bind the interface to the offered address */

+      dhcp_bind(netif);

+    }

+  }

+  /* did not get response to renew request? */

+  else if (dhcp->state == DHCP_RENEWING) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n"));

+    /* just retry renewal */

+    /* note that the rebind timer will eventually time-out if renew does not work */

+    dhcp_renew(netif);

+  /* did not get response to rebind request? */

+  } else if (dhcp->state == DHCP_REBINDING) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n"));

+    if (dhcp->tries <= 8) {

+      dhcp_rebind(netif);

+    } else {

+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n"));

+      dhcp_release(netif);

+      dhcp_discover(netif);

+    }

+  }

+}

+

+/**

+ * The renewal period has timed out.

+ *

+ * @param netif the netif under DHCP control

+ */

+static void

+dhcp_t1_timeout(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n"));

+  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {

+    /* just retry to renew - note that the rebind timer (t2) will

+     * eventually time-out if renew tries fail. */

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t1_timeout(): must renew\n"));

+    dhcp_renew(netif);

+  }

+}

+

+/**

+ * The rebind period has timed out.

+ *

+ * @param netif the netif under DHCP control

+ */

+static void

+dhcp_t2_timeout(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n"));

+  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {

+    /* just retry to rebind */

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout(): must rebind\n"));

+    dhcp_rebind(netif);

+  }

+}

+

+/**

+ * Handle a DHCP ACK packet

+ *

+ * @param netif the netif under DHCP control

+ */

+static void

+dhcp_handle_ack(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  u8_t *option_ptr;

+  /* clear options we might not get from the ACK */

+  dhcp->offered_sn_mask.addr = 0;

+  dhcp->offered_gw_addr.addr = 0;

+  dhcp->offered_bc_addr.addr = 0;

+

+  /* lease time given? */

+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME);

+  if (option_ptr != NULL) {

+    /* remember offered lease time */

+    dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2);

+  }

+  /* renewal period given? */

+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1);

+  if (option_ptr != NULL) {

+    /* remember given renewal period */

+    dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2);

+  } else {

+    /* calculate safe periods for renewal */

+    dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;

+  }

+

+  /* renewal period given? */

+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2);

+  if (option_ptr != NULL) {

+    /* remember given rebind period */

+    dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2);

+  } else {

+    /* calculate safe periods for rebinding */

+    dhcp->offered_t2_rebind = dhcp->offered_t0_lease;

+  }

+

+  /* (y)our internet address */

+  ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr);

+

+/**

+ * Patch #1308

+ * TODO: we must check if the file field is not overloaded by DHCP options!

+ */

+#if 0

+  /* boot server address */

+  ip_addr_set(&dhcp->offered_si_addr, &dhcp->msg_in->siaddr);

+  /* boot file name */

+  if (dhcp->msg_in->file[0]) {

+    dhcp->boot_file_name = mem_malloc(strlen(dhcp->msg_in->file) + 1);

+    strcpy(dhcp->boot_file_name, dhcp->msg_in->file);

+  }

+#endif

+

+  /* subnet mask */

+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK);

+  /* subnet mask given? */

+  if (option_ptr != NULL) {

+    dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2]));

+  }

+

+  /* gateway router */

+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER);

+  if (option_ptr != NULL) {

+    dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));

+  }

+

+  /* broadcast address */

+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST);

+  if (option_ptr != NULL) {

+    dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));

+  }

+

+  /* DNS servers */

+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER);

+  if (option_ptr != NULL) {

+    u8_t n;

+    dhcp->dns_count = dhcp_get_option_byte(&option_ptr[1]) / (u32_t)sizeof(struct ip_addr);

+    /* limit to at most DHCP_MAX_DNS DNS servers */

+    if (dhcp->dns_count > DHCP_MAX_DNS)

+      dhcp->dns_count = DHCP_MAX_DNS;

+    for (n = 0; n < dhcp->dns_count; n++) {

+      dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2 + n * 4]));

+#if LWIP_DNS

+      dns_setserver( n, (struct ip_addr *)(&(dhcp->offered_dns_addr[n].addr)));

+#endif /* LWIP_DNS */

+    }

+#if LWIP_DNS

+    dns_setserver( n, (struct ip_addr *)(&ip_addr_any));

+#endif /* LWIP_DNS */

+  }

+}

+

+/**

+ * Start DHCP negotiation for a network interface.

+ *

+ * If no DHCP client instance was attached to this interface,

+ * a new client is created first. If a DHCP client instance

+ * was already present, it restarts negotiation.

+ *

+ * @param netif The lwIP network interface

+ * @return lwIP error code

+ * - ERR_OK - No error

+ * - ERR_MEM - Out of memory

+ */

+err_t

+dhcp_start(struct netif *netif)

+{

+  struct dhcp *dhcp;

+  err_t result = ERR_OK;

+

+  LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);

+  dhcp = netif->dhcp;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));

+  netif->flags &= ~NETIF_FLAG_DHCP;

+

+  /* no DHCP client attached yet? */

+  if (dhcp == NULL) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));

+    dhcp = mem_malloc(sizeof(struct dhcp));

+    if (dhcp == NULL) {

+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));

+      return ERR_MEM;

+    }

+    /* store this dhcp client in the netif */

+    netif->dhcp = dhcp;

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));

+  /* already has DHCP client attached */

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));

+  }

+

+  /* clear data structure */

+  memset(dhcp, 0, sizeof(struct dhcp));

+  /* allocate UDP PCB */

+  dhcp->pcb = udp_new();

+  if (dhcp->pcb == NULL) {

+    LWIP_DEBUGF(DHCP_DEBUG  | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));

+    mem_free((void *)dhcp);

+    netif->dhcp = dhcp = NULL;

+    return ERR_MEM;

+  }

+  /* set up local and remote port for the pcb */

+  udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);

+  udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);

+  /* set up the recv callback and argument */

+  udp_recv(dhcp->pcb, dhcp_recv, netif);

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));

+  /* (re)start the DHCP negotiation */

+  result = dhcp_discover(netif);

+  if (result != ERR_OK) {

+    /* free resources allocated above */

+    dhcp_stop(netif);

+    return ERR_MEM;

+  }

+  netif->flags |= NETIF_FLAG_DHCP;

+  return result;

+}

+

+/**

+ * Inform a DHCP server of our manual configuration.

+ *

+ * This informs DHCP servers of our fixed IP address configuration

+ * by sending an INFORM message. It does not involve DHCP address

+ * configuration, it is just here to be nice to the network.

+ *

+ * @param netif The lwIP network interface

+ */

+void

+dhcp_inform(struct netif *netif)

+{

+  struct dhcp *dhcp, *old_dhcp = netif->dhcp;

+  err_t result = ERR_OK;

+  dhcp = mem_malloc(sizeof(struct dhcp));

+  if (dhcp == NULL) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n"));

+    return;

+  }

+  netif->dhcp = dhcp;

+  memset(dhcp, 0, sizeof(struct dhcp));

+

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): allocated dhcp\n"));

+  dhcp->pcb = udp_new();

+  if (dhcp->pcb == NULL) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb"));

+    mem_free((void *)dhcp);

+    return;

+  }

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));

+  /* create and initialize the DHCP message header */

+  result = dhcp_create_request(netif);

+  if (result == ERR_OK) {

+

+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);

+    dhcp_option_byte(dhcp, DHCP_INFORM);

+

+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);

+    /* TODO: use netif->mtu ?! */

+    dhcp_option_short(dhcp, 576);

+

+    dhcp_option_trailer(dhcp);

+

+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

+

+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);

+    udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n"));

+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);

+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);

+    dhcp_delete_request(netif);

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n"));

+  }

+

+  if (dhcp != NULL) {

+    if (dhcp->pcb != NULL) {

+      udp_remove(dhcp->pcb);

+    }

+    dhcp->pcb = NULL;

+    mem_free((void *)dhcp);

+    netif->dhcp = old_dhcp;

+  }

+}

+

+#if DHCP_DOES_ARP_CHECK

+/**

+ * Match an ARP reply with the offered IP address.

+ *

+ * @param netif the network interface on which the reply was received

+ * @param addr The IP address we received a reply from

+ */

+void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)

+{

+  LWIP_ERROR("netif != NULL", (netif != NULL), return;);

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_arp_reply()\n"));

+  /* is a DHCP client doing an ARP check? */

+  if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", addr->addr));

+    /* did a host respond with the address we

+       were offered by the DHCP server? */

+    if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {

+      /* we will not accept the offered address */

+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));

+      dhcp_decline(netif);

+    }

+  }

+}

+

+/**

+ * Decline an offered lease.

+ *

+ * Tell the DHCP server we do not accept the offered address.

+ * One reason to decline the lease is when we find out the address

+ * is already in use by another host (through ARP).

+ *

+ * @param netif the netif under DHCP control

+ */

+static err_t

+dhcp_decline(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result = ERR_OK;

+  u16_t msecs;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_decline()\n"));

+  dhcp_set_state(dhcp, DHCP_BACKING_OFF);

+  /* create and initialize the DHCP message header */

+  result = dhcp_create_request(netif);

+  if (result == ERR_OK) {

+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);

+    dhcp_option_byte(dhcp, DHCP_DECLINE);

+

+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);

+    dhcp_option_short(dhcp, 576);

+

+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);

+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));

+

+    dhcp_option_trailer(dhcp);

+    /* resize pbuf to reflect true size of options */

+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

+

+    /* @todo: should we really connect here? we are performing sendto() */

+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);

+    /* per section 4.4.4, broadcast DECLINE messages */

+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);

+    dhcp_delete_request(netif);

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n"));

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n"));

+  }

+  dhcp->tries++;

+  msecs = 10*1000;

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs));

+  return result;

+}

+#endif

+

+

+/**

+ * Start the DHCP process, discover a DHCP server.

+ *

+ * @param netif the netif under DHCP control

+ */

+static err_t

+dhcp_discover(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result = ERR_OK;

+  u16_t msecs;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_discover()\n"));

+  ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY);

+  /* create and initialize the DHCP message header */

+  result = dhcp_create_request(netif);

+  if (result == ERR_OK) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n"));

+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);

+    dhcp_option_byte(dhcp, DHCP_DISCOVER);

+

+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);

+    dhcp_option_short(dhcp, 576);

+

+    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);

+    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);

+    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);

+    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);

+    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);

+

+    dhcp_option_trailer(dhcp);

+

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n"));

+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

+

+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));

+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n"));

+    dhcp_delete_request(netif);

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n"));

+    dhcp_set_state(dhcp, DHCP_SELECTING);

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));

+  }

+  dhcp->tries++;

+#if LWIP_DHCP_AUTOIP_COOP

+  /* that means we waited 57 seconds */

+  if(dhcp->tries >= 9 && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) {

+    dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON;

+    autoip_start(netif);

+  }

+#endif /* LWIP_DHCP_AUTOIP_COOP */

+  msecs = dhcp->tries < 4 ? (dhcp->tries + 1) * 1000 : 10 * 1000;

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs));

+  return result;

+}

+

+

+/**

+ * Bind the interface to the offered IP address.

+ *

+ * @param netif network interface to bind to the offered address

+ */

+static void

+dhcp_bind(struct netif *netif)

+{

+  u32_t timeout;

+  struct dhcp *dhcp;

+  struct ip_addr sn_mask, gw_addr;

+  LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;);

+  dhcp = netif->dhcp;

+  LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;);

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));

+

+  /* temporary DHCP lease? */

+  if (dhcp->offered_t1_renew != 0xffffffffUL) {

+    /* set renewal period timer */

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew));

+    timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;

+    if(timeout > 0xffff) {

+      timeout = 0xffff;

+    }

+    dhcp->t1_timeout = (u16_t)timeout;

+    if (dhcp->t1_timeout == 0) {

+      dhcp->t1_timeout = 1;

+    }

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000));

+  }

+  /* set renewal period timer */

+  if (dhcp->offered_t2_rebind != 0xffffffffUL) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind));

+    timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;

+    if(timeout > 0xffff) {

+      timeout = 0xffff;

+    }

+    dhcp->t2_timeout = (u16_t)timeout;

+    if (dhcp->t2_timeout == 0) {

+      dhcp->t2_timeout = 1;

+    }

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000));

+  }

+  /* copy offered network mask */

+  ip_addr_set(&sn_mask, &dhcp->offered_sn_mask);

+

+  /* subnet mask not given? */

+  /* TODO: this is not a valid check. what if the network mask is 0? */

+  if (sn_mask.addr == 0) {

+    /* choose a safe subnet mask given the network class */

+    u8_t first_octet = ip4_addr1(&sn_mask);

+    if (first_octet <= 127) {

+      sn_mask.addr = htonl(0xff000000);

+    } else if (first_octet >= 192) {

+      sn_mask.addr = htonl(0xffffff00);

+    } else {

+      sn_mask.addr = htonl(0xffff0000);

+    }

+  }

+

+  ip_addr_set(&gw_addr, &dhcp->offered_gw_addr);

+  /* gateway address not given? */

+  if (gw_addr.addr == 0) {

+    /* copy network address */

+    gw_addr.addr = (dhcp->offered_ip_addr.addr & sn_mask.addr);

+    /* use first host address on network as gateway */

+    gw_addr.addr |= htonl(0x00000001);

+  }

+

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));

+  netif_set_ipaddr(netif, &dhcp->offered_ip_addr);

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr));

+  netif_set_netmask(netif, &sn_mask);

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", gw_addr.addr));

+  netif_set_gw(netif, &gw_addr);

+  /* bring the interface up */

+  netif_set_up(netif);

+  /* netif is now bound to DHCP leased address */

+  dhcp_set_state(dhcp, DHCP_BOUND);

+}

+

+/**

+ * Renew an existing DHCP lease at the involved DHCP server.

+ *

+ * @param netif network interface which must renew its lease

+ */

+err_t

+dhcp_renew(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result;

+  u16_t msecs;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_renew()\n"));

+  dhcp_set_state(dhcp, DHCP_RENEWING);

+

+  /* create and initialize the DHCP message header */

+  result = dhcp_create_request(netif);

+  if (result == ERR_OK) {

+

+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);

+    dhcp_option_byte(dhcp, DHCP_REQUEST);

+

+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);

+    /* TODO: use netif->mtu in some way */

+    dhcp_option_short(dhcp, 576);

+

+#if 0

+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);

+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));

+#endif

+

+#if 0

+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);

+    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));

+#endif

+    /* append DHCP message trailer */

+    dhcp_option_trailer(dhcp);

+

+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

+

+    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);

+    udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);

+    dhcp_delete_request(netif);

+

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n"));

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n"));

+  }

+  dhcp->tries++;

+  /* back-off on retries, but to a maximum of 20 seconds */

+  msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000;

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs));

+  return result;

+}

+

+/**

+ * Rebind with a DHCP server for an existing DHCP lease.

+ *

+ * @param netif network interface which must rebind with a DHCP server

+ */

+static err_t

+dhcp_rebind(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result;

+  u16_t msecs;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n"));

+  dhcp_set_state(dhcp, DHCP_REBINDING);

+

+  /* create and initialize the DHCP message header */

+  result = dhcp_create_request(netif);

+  if (result == ERR_OK) {

+

+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);

+    dhcp_option_byte(dhcp, DHCP_REQUEST);

+

+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);

+    dhcp_option_short(dhcp, 576);

+

+#if 0

+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);

+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));

+

+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);

+    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));

+#endif

+

+    dhcp_option_trailer(dhcp);

+

+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

+

+    /* broadcast to server */

+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);

+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);

+    dhcp_delete_request(netif);

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n"));

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n"));

+  }

+  dhcp->tries++;

+  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs));

+  return result;

+}

+

+/**

+ * Release a DHCP lease.

+ *

+ * @param netif network interface which must release its lease

+ */

+err_t

+dhcp_release(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  err_t result;

+  u16_t msecs;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_release()\n"));

+

+  /* idle DHCP client */

+  dhcp_set_state(dhcp, DHCP_OFF);

+  /* clean old DHCP offer */

+  dhcp->server_ip_addr.addr = 0;

+  dhcp->offered_ip_addr.addr = dhcp->offered_sn_mask.addr = 0;

+  dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0;

+  dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;

+  dhcp->dns_count = 0;

+

+  /* create and initialize the DHCP message header */

+  result = dhcp_create_request(netif);

+  if (result == ERR_OK) {

+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);

+    dhcp_option_byte(dhcp, DHCP_RELEASE);

+

+    dhcp_option_trailer(dhcp);

+

+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

+

+    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);

+    udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);

+    dhcp_delete_request(netif);

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));

+  } else {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n"));

+  }

+  dhcp->tries++;

+  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;

+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs));

+  /* bring the interface down */

+  netif_set_down(netif);

+  /* remove IP address from interface */

+  netif_set_ipaddr(netif, IP_ADDR_ANY);

+  netif_set_gw(netif, IP_ADDR_ANY);

+  netif_set_netmask(netif, IP_ADDR_ANY);

+

+  /* TODO: netif_down(netif); */

+  return result;

+}

+

+/**

+ * Remove the DHCP client from the interface.

+ *

+ * @param netif The network interface to stop DHCP on

+ */

+void

+dhcp_stop(struct netif *netif)

+{

+  struct dhcp *dhcp = netif->dhcp;

+  LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;);

+

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_stop()\n"));

+  /* netif is DHCP configured? */

+  if (dhcp != NULL) {

+    if (dhcp->pcb != NULL) {

+      udp_remove(dhcp->pcb);

+      dhcp->pcb = NULL;

+    }

+    if (dhcp->p != NULL) {

+      pbuf_free(dhcp->p);

+      dhcp->p = NULL;

+    }

+    /* free unfolded reply */

+    dhcp_free_reply(dhcp);

+    mem_free((void *)dhcp);

+    netif->dhcp = NULL;

+  }

+}

+

+/*

+ * Set the DHCP state of a DHCP client.

+ *

+ * If the state changed, reset the number of tries.

+ *

+ * TODO: we might also want to reset the timeout here?

+ */

+static void

+dhcp_set_state(struct dhcp *dhcp, u8_t new_state)

+{

+  if (new_state != dhcp->state) {

+    dhcp->state = new_state;

+    dhcp->tries = 0;

+  }

+}

+

+/*

+ * Concatenate an option type and length field to the outgoing

+ * DHCP message.

+ *

+ */

+static void

+dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)

+{

+  LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN);

+  dhcp->msg_out->options[dhcp->options_out_len++] = option_type;

+  dhcp->msg_out->options[dhcp->options_out_len++] = option_len;

+}

+/*

+ * Concatenate a single byte to the outgoing DHCP message.

+ *

+ */

+static void

+dhcp_option_byte(struct dhcp *dhcp, u8_t value)

+{

+  LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN);

+  dhcp->msg_out->options[dhcp->options_out_len++] = value;

+}

+

+static void

+dhcp_option_short(struct dhcp *dhcp, u16_t value)

+{

+  LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN);

+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8);

+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU);

+}

+

+static void

+dhcp_option_long(struct dhcp *dhcp, u32_t value)

+{

+  LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN);

+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24);

+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16);

+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8);

+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL));

+}

+

+/**

+ * Extract the DHCP message and the DHCP options.

+ *

+ * Extract the DHCP message and the DHCP options, each into a contiguous

+ * piece of memory. As a DHCP message is variable sized by its options,

+ * and also allows overriding some fields for options, the easy approach

+ * is to first unfold the options into a conitguous piece of memory, and

+ * use that further on.

+ *

+ */

+static err_t

+dhcp_unfold_reply(struct dhcp *dhcp)

+{

+  u16_t ret;

+  LWIP_ERROR("dhcp != NULL", (dhcp != NULL), return ERR_ARG;);

+  LWIP_ERROR("dhcp->p != NULL", (dhcp->p != NULL), return ERR_VAL;);

+  /* free any left-overs from previous unfolds */

+  dhcp_free_reply(dhcp);

+  /* options present? */

+  if (dhcp->p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN)) {

+    dhcp->options_in_len = dhcp->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);

+    dhcp->options_in = mem_malloc(dhcp->options_in_len);

+    if (dhcp->options_in == NULL) {

+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n"));

+      return ERR_MEM;

+    }

+  }

+  dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);

+  if (dhcp->msg_in == NULL) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n"));

+    mem_free((void *)dhcp->options_in);

+    dhcp->options_in = NULL;

+    return ERR_MEM;

+  }

+

+  /** copy the DHCP message without options */

+  ret = pbuf_copy_partial(dhcp->p, dhcp->msg_in, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN, 0);

+  LWIP_ASSERT("ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN", ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n",

+     sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN));

+

+  if (dhcp->options_in != NULL) {

+    /** copy the DHCP options */

+    ret = pbuf_copy_partial(dhcp->p, dhcp->options_in, dhcp->options_in_len, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);

+    LWIP_ASSERT("ret == dhcp->options_in_len", ret == dhcp->options_in_len);

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n",

+      dhcp->options_in_len));

+  }

+  LWIP_UNUSED_ARG(ret);

+  return ERR_OK;

+}

+

+/**

+ * Free the incoming DHCP message including contiguous copy of

+ * its DHCP options.

+ *

+ */

+static void dhcp_free_reply(struct dhcp *dhcp)

+{

+  if (dhcp->msg_in != NULL) {

+    mem_free((void *)dhcp->msg_in);

+    dhcp->msg_in = NULL;

+  }

+  if (dhcp->options_in) {

+    mem_free((void *)dhcp->options_in);

+    dhcp->options_in = NULL;

+    dhcp->options_in_len = 0;

+  }

+  LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n"));

+}

+

+

+/**

+ * If an incoming DHCP message is in response to us, then trigger the state machine

+ */

+static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)

+{

+  struct netif *netif = (struct netif *)arg;

+  struct dhcp *dhcp = netif->dhcp;

+  struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;

+  u8_t *options_ptr;

+  u8_t msg_type;

+  u8_t i;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,

+    (u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff),

+    (u16_t)(ntohl(addr->addr) >>  8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), port));

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));

+  /* prevent warnings about unused arguments */

+  LWIP_UNUSED_ARG(pcb);

+  LWIP_UNUSED_ARG(addr);

+  LWIP_UNUSED_ARG(port);

+  dhcp->p = p;

+  /* TODO: check packet length before reading them */

+  if (reply_msg->op != DHCP_BOOTREPLY) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));

+    goto free_pbuf_and_return;

+  }

+  /* iterate through hardware address and match against DHCP message */

+  for (i = 0; i < netif->hwaddr_len; i++) {

+    if (netif->hwaddr[i] != reply_msg->chaddr[i]) {

+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",

+        (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));

+      goto free_pbuf_and_return;

+    }

+  }

+  /* match transaction ID against what we expected */

+  if (ntohl(reply_msg->xid) != dhcp->xid) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid));

+    goto free_pbuf_and_return;

+  }

+  /* option fields could be unfold? */

+  if (dhcp_unfold_reply(dhcp) != ERR_OK) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n"));

+    goto free_pbuf_and_return;

+  }

+

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));

+  /* obtain pointer to DHCP message type */

+  options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE);

+  if (options_ptr == NULL) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));

+    goto free_pbuf_and_return;

+  }

+

+  /* read DHCP message type */

+  msg_type = dhcp_get_option_byte(options_ptr + 2);

+  /* message type is DHCP ACK? */

+  if (msg_type == DHCP_ACK) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_ACK received\n"));

+    /* in requesting state? */

+    if (dhcp->state == DHCP_REQUESTING) {

+      dhcp_handle_ack(netif);

+      dhcp->request_timeout = 0;

+#if DHCP_DOES_ARP_CHECK

+      /* check if the acknowledged lease address is already in use */

+      dhcp_check(netif);

+#else

+      /* bind interface to the acknowledged lease address */

+      dhcp_bind(netif);

+#endif

+    }

+    /* already bound to the given lease address? */

+    else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {

+      dhcp->request_timeout = 0;

+      dhcp_bind(netif);

+    }

+  }

+  /* received a DHCP_NAK in appropriate state? */

+  else if ((msg_type == DHCP_NAK) &&

+    ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||

+     (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING  ))) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_NAK received\n"));

+    dhcp->request_timeout = 0;

+    dhcp_handle_nak(netif);

+  }

+  /* received a DHCP_OFFER in DHCP_SELECTING state? */

+  else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n"));

+    dhcp->request_timeout = 0;

+    /* remember offered lease */

+    dhcp_handle_offer(netif);

+  }

+free_pbuf_and_return:

+  pbuf_free(p);

+  dhcp->p = NULL;

+}

+

+/**

+ * Create a DHCP request, fill in common headers

+ *

+ * @param netif the netif under DHCP control

+ */

+static err_t

+dhcp_create_request(struct netif *netif)

+{

+  struct dhcp *dhcp;

+  u16_t i;

+  LWIP_ERROR("dhcp_create_request: netif != NULL", (netif != NULL), return ERR_ARG;);

+  dhcp = netif->dhcp;

+  LWIP_ERROR("dhcp_create_request: dhcp != NULL", (dhcp != NULL), return ERR_VAL;);

+  LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL);

+  LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL);

+  dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);

+  if (dhcp->p_out == NULL) {

+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n"));

+    return ERR_MEM;

+  }

+  LWIP_ASSERT("dhcp_create_request: check that first pbuf can hold struct dhcp_msg",

+           (dhcp->p_out->len >= sizeof(struct dhcp_msg)));

+

+  /* give unique transaction identifier to this request */

+  dhcp->xid = xid++;

+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("transaction id xid++(%"X32_F") dhcp->xid(%"U32_F")\n",xid,dhcp->xid));

+

+  dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;

+

+  dhcp->msg_out->op = DHCP_BOOTREQUEST;

+  /* TODO: make link layer independent */

+  dhcp->msg_out->htype = DHCP_HTYPE_ETH;

+  /* TODO: make link layer independent */

+  dhcp->msg_out->hlen = DHCP_HLEN_ETH;

+  dhcp->msg_out->hops = 0;

+  dhcp->msg_out->xid = htonl(dhcp->xid);

+  dhcp->msg_out->secs = 0;

+  dhcp->msg_out->flags = 0;

+  dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr;

+  dhcp->msg_out->yiaddr.addr = 0;

+  dhcp->msg_out->siaddr.addr = 0;

+  dhcp->msg_out->giaddr.addr = 0;

+  for (i = 0; i < DHCP_CHADDR_LEN; i++) {

+    /* copy netif hardware address, pad with zeroes */

+    dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;

+  }

+  for (i = 0; i < DHCP_SNAME_LEN; i++) {

+    dhcp->msg_out->sname[i] = 0;

+  }

+  for (i = 0; i < DHCP_FILE_LEN; i++) {

+    dhcp->msg_out->file[i] = 0;

+  }

+  dhcp->msg_out->cookie = htonl(0x63825363UL);

+  dhcp->options_out_len = 0;

+  /* fill options field with an incrementing array (for debugging purposes) */

+  for (i = 0; i < DHCP_OPTIONS_LEN; i++) {

+    dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */

+  }

+  return ERR_OK;

+}

+

+/**

+ * Free previously allocated memory used to send a DHCP request.

+ *

+ * @param netif the netif under DHCP control

+ */

+static void

+dhcp_delete_request(struct netif *netif)

+{

+  struct dhcp *dhcp;

+  LWIP_ERROR("dhcp_delete_request: netif != NULL", (netif != NULL), return;);

+  dhcp = netif->dhcp;

+  LWIP_ERROR("dhcp_delete_request: dhcp != NULL", (dhcp != NULL), return;);

+  LWIP_ASSERT("dhcp_delete_request: dhcp->p_out != NULL", dhcp->p_out != NULL);

+  LWIP_ASSERT("dhcp_delete_request: dhcp->msg_out != NULL", dhcp->msg_out != NULL);

+  if (dhcp->p_out != NULL) {

+    pbuf_free(dhcp->p_out);

+  }

+  dhcp->p_out = NULL;

+  dhcp->msg_out = NULL;

+}

+

+/**

+ * Add a DHCP message trailer

+ *

+ * Adds the END option to the DHCP message, and if

+ * necessary, up to three padding bytes.

+ *

+ * @param dhcp DHCP state structure

+ */

+static void

+dhcp_option_trailer(struct dhcp *dhcp)

+{

+  LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;);

+  LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL);

+  LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);

+  dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;

+  /* packet is too small, or not 4 byte aligned? */

+  while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {

+    /* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */

+    LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);

+    /* add a fill/padding byte */

+    dhcp->msg_out->options[dhcp->options_out_len++] = 0;

+  }

+}

+

+/**

+ * Find the offset of a DHCP option inside the DHCP message.

+ *

+ * @param dhcp DHCP client

+ * @param option_type

+ *

+ * @return a byte offset into the UDP message where the option was found, or

+ * zero if the given option was not found.

+ */

+static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)

+{

+  u8_t overload = DHCP_OVERLOAD_NONE;

+

+  /* options available? */

+  if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) {

+    /* start with options field */

+    u8_t *options = (u8_t *)dhcp->options_in;

+    u16_t offset = 0;

+    /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */

+    while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) {

+      /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */

+      /* are the sname and/or file field overloaded with options? */

+      if (options[offset] == DHCP_OPTION_OVERLOAD) {

+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("overloaded message detected\n"));

+        /* skip option type and length */

+        offset += 2;

+        overload = options[offset++];

+      }

+      /* requested option found */

+      else if (options[offset] == option_type) {

+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("option found at offset %"U16_F" in options\n", offset));

+        return &options[offset];

+      /* skip option */

+      } else {

+         LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", options[offset]));

+        /* skip option type */

+        offset++;

+        /* skip option length, and then length bytes */

+        offset += 1 + options[offset];

+      }

+    }

+    /* is this an overloaded message? */

+    if (overload != DHCP_OVERLOAD_NONE) {

+      u16_t field_len;

+      if (overload == DHCP_OVERLOAD_FILE) {

+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded file field\n"));

+        options = (u8_t *)&dhcp->msg_in->file;

+        field_len = DHCP_FILE_LEN;

+      } else if (overload == DHCP_OVERLOAD_SNAME) {

+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded sname field\n"));

+        options = (u8_t *)&dhcp->msg_in->sname;

+        field_len = DHCP_SNAME_LEN;

+      /* TODO: check if else if () is necessary */

+      } else {

+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded sname and file field\n"));

+        options = (u8_t *)&dhcp->msg_in->sname;

+        field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN;

+      }

+      offset = 0;

+

+      /* at least 1 byte to read and no end marker */

+      while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) {

+        if (options[offset] == option_type) {

+           LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("option found at offset=%"U16_F"\n", offset));

+          return &options[offset];

+        /* skip option */

+        } else {

+          LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("skipping option %"U16_F"\n", options[offset]));

+          /* skip option type */

+          offset++;

+          offset += 1 + options[offset];

+        }

+      }

+    }

+  }

+  return NULL;

+}

+

+/**

+ * Return the byte of DHCP option data.

+ *

+ * @param client DHCP client.

+ * @param ptr pointer obtained by dhcp_get_option_ptr().

+ *

+ * @return byte value at the given address.

+ */

+static u8_t

+dhcp_get_option_byte(u8_t *ptr)

+{

+  LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%"U16_F"\n", (u16_t)(*ptr)));

+  return *ptr;

+}

+

+#if 0 /* currently unused */

+/**

+ * Return the 16-bit value of DHCP option data.

+ *

+ * @param client DHCP client.

+ * @param ptr pointer obtained by dhcp_get_option_ptr().

+ *

+ * @return byte value at the given address.

+ */

+static u16_t

+dhcp_get_option_short(u8_t *ptr)

+{

+  u16_t value;

+  value = *ptr++ << 8;

+  value |= *ptr;

+  LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%"U16_F"\n", value));

+  return value;

+}

+#endif

+

+/**

+ * Return the 32-bit value of DHCP option data.

+ *

+ * @param client DHCP client.

+ * @param ptr pointer obtained by dhcp_get_option_ptr().

+ *

+ * @return byte value at the given address.

+ */

+static u32_t dhcp_get_option_long(u8_t *ptr)

+{

+  u32_t value;

+  value = (u32_t)(*ptr++) << 24;

+  value |= (u32_t)(*ptr++) << 16;

+  value |= (u32_t)(*ptr++) << 8;

+  value |= (u32_t)(*ptr++);

+  LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%"U32_F"\n", value));

+  return value;

+}

+

+#endif /* LWIP_DHCP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/dns.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/dns.c
new file mode 100644
index 0000000..defd7e4
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/dns.c
@@ -0,0 +1,823 @@
+/**

+ * @file

+ * DNS - host name to IP address resolver.

+ *

+ */

+

+/**

+

+ * This file implements a DNS host name to IP address resolver.

+

+ * Port to lwIP from uIP

+ * by Jim Pettinato April 2007

+

+ * uIP version Copyright (c) 2002-2003, Adam Dunkels.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ * 1. Redistributions of source code must retain the above copyright

+ *    notice, this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright

+ *    notice, this list of conditions and the following disclaimer in the

+ *    documentation and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote

+ *    products derived from this software without specific prior

+ *    written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS

+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY

+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL

+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE

+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,

+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING

+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ *

+ *

+ * DNS.C

+ *

+ * The lwIP DNS resolver functions are used to lookup a host name and

+ * map it to a numerical IP address. It maintains a list of resolved

+ * hostnames that can be queried with the dns_lookup() function.

+ * New hostnames can be resolved using the dns_query() function.

+ *

+ * The lwIP version of the resolver also adds a non-blocking version of

+ * gethostbyname() that will work with a raw API application. This function

+ * checks for an IP address string first and converts it if it is valid.

+ * gethostbyname() then does a dns_lookup() to see if the name is 

+ * already in the table. If so, the IP is returned. If not, a query is 

+ * issued and the function returns with a ERR_INPROGRESS status. The app

+ * using the dns client must then go into a waiting state.

+ *

+ * Once a hostname has been resolved (or found to be non-existent),

+ * the resolver code calls a specified callback function (which 

+ * must be implemented by the module that uses the resolver).

+ */

+

+/*-----------------------------------------------------------------------------

+ * RFC 1035 - Domain names - implementation and specification

+ * RFC 2181 - Clarifications to the DNS Specification

+ *----------------------------------------------------------------------------*/

+

+/** @todo: define good default values (rfc compliance) */

+/** @todo: improve answer parsing, more checkings... */

+/** @todo: check RFC1035 - 7.3. Processing responses */

+

+/*-----------------------------------------------------------------------------

+ * Includes

+ *----------------------------------------------------------------------------*/

+

+#include "lwip/opt.h"

+

+#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/udp.h"

+#include "lwip/mem.h"

+#include "lwip/dns.h"

+

+#include <string.h>

+

+/** DNS server IP address */

+#ifndef DNS_SERVER_ADDRESS

+#define DNS_SERVER_ADDRESS        inet_addr("208.67.222.222") /* resolver1.opendns.com */

+#endif

+

+/** DNS server port address */

+#ifndef DNS_SERVER_PORT

+#define DNS_SERVER_PORT           53

+#endif

+

+/** DNS maximum number of retries when asking for a name, before "timeout". */

+#ifndef DNS_MAX_RETRIES

+#define DNS_MAX_RETRIES           4

+#endif

+

+/** DNS resource record max. TTL (one week as default) */

+#ifndef DNS_MAX_TTL

+#define DNS_MAX_TTL               604800

+#endif

+

+/* DNS protocol flags */

+#define DNS_FLAG1_RESPONSE        0x80

+#define DNS_FLAG1_OPCODE_STATUS   0x10

+#define DNS_FLAG1_OPCODE_INVERSE  0x08

+#define DNS_FLAG1_OPCODE_STANDARD 0x00

+#define DNS_FLAG1_AUTHORATIVE     0x04

+#define DNS_FLAG1_TRUNC           0x02

+#define DNS_FLAG1_RD              0x01

+#define DNS_FLAG2_RA              0x80

+#define DNS_FLAG2_ERR_MASK        0x0f

+#define DNS_FLAG2_ERR_NONE        0x00

+#define DNS_FLAG2_ERR_NAME        0x03

+

+/* DNS protocol states */

+#define DNS_STATE_UNUSED          0

+#define DNS_STATE_NEW             1

+#define DNS_STATE_ASKING          2

+#define DNS_STATE_DONE            3

+

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+/** DNS message header */

+struct dns_hdr {

+  u16_t id;

+  u8_t flags1;

+  u8_t flags2;

+  u16_t numquestions;

+  u16_t numanswers;

+  u16_t numauthrr;

+  u16_t numextrarr;

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+/** DNS query message structure */

+struct dns_query {

+  /* DNS query record starts with either a domain name or a pointer

+     to a name already present somewhere in the packet. */

+  u16_t type;

+  u16_t class;

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+/** DNS answer message structure */

+struct dns_answer {

+  /* DNS answer record starts with either a domain name or a pointer

+     to a name already present somewhere in the packet. */

+  u16_t type;

+  u16_t class;

+  u32_t ttl;

+  u16_t len;

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+/** DNS table entry */

+struct dns_table_entry {

+  u8_t  state;

+  u8_t  numdns;

+  u8_t  tmr;

+  u8_t  retries;

+  u8_t  seqno;

+  u8_t  err;

+  u32_t ttl;

+  char name[DNS_MAX_NAME_LENGTH];

+  struct ip_addr ipaddr;

+  /* pointer to callback on DNS query done */

+  dns_found_callback found;

+  void *arg;

+};

+

+

+/* forward declarations */

+static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);

+static void dns_check_entries(void);

+

+/*-----------------------------------------------------------------------------

+ * Globales

+ *----------------------------------------------------------------------------*/

+

+/* DNS variables */

+static struct udp_pcb        *dns_pcb;

+static u8_t                   dns_seqno;

+static struct dns_table_entry dns_table[DNS_TABLE_SIZE];

+static struct ip_addr         dns_servers[DNS_MAX_SERVERS];

+

+#if (DNS_USES_STATIC_BUF == 1)

+static u8_t                   dns_payload[DNS_MSG_SIZE];

+#endif /* (DNS_USES_STATIC_BUF == 1) */

+

+/**

+ * Initialize the resolver: set up the UDP pcb and configure the default server

+ * (DNS_SERVER_ADDRESS).

+ */

+void

+dns_init()

+{

+  struct ip_addr dnsserver;

+  

+  /* initialize default DNS server address */

+  dnsserver.addr = DNS_SERVER_ADDRESS;

+

+  LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));

+

+  /* if dns client not yet initialized... */

+  if (dns_pcb == NULL) {

+    dns_pcb = udp_new();

+

+    if (dns_pcb != NULL) {

+      /* initialize DNS table not needed (initialized to zero since it is a

+       * global variable) */

+      LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",

+        DNS_STATE_UNUSED == 0);

+

+      /* initialize DNS client */

+      udp_bind(dns_pcb, IP_ADDR_ANY, 0);

+      udp_recv(dns_pcb, dns_recv, NULL);

+

+      /* initialize default DNS primary server */

+      dns_setserver(0, &dnsserver);

+    }

+  }

+}

+

+/**

+ * Initialize one of the DNS servers.

+ *

+ * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS

+ * @param dnsserver IP address of the DNS server to set

+ */

+void

+dns_setserver(u8_t numdns, struct ip_addr *dnsserver)

+{

+  if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&

+      (dnsserver != NULL) && (dnsserver->addr !=0 )) {

+    dns_servers[numdns] = (*dnsserver);

+  }

+}

+

+/**

+ * Obtain one of the currently configured DNS server.

+ *

+ * @param numdns the index of the DNS server

+ * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS

+ *         server has not been configured.

+ */

+struct ip_addr

+dns_getserver(u8_t numdns)

+{

+  if (numdns < DNS_MAX_SERVERS) {

+    return dns_servers[numdns];

+  } else {

+    return *IP_ADDR_ANY;

+  }

+}

+

+/**

+ * The DNS resolver client timer - handle retries and timeouts and should

+ * be called every DNS_TMR_INTERVAL milliseconds (every second by default).

+ */

+void

+dns_tmr(void)

+{

+  if (dns_pcb != NULL) {

+    LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));

+    dns_check_entries();

+  }

+}

+

+/**

+ * Look up a hostname in the array of known hostnames.

+ *

+ * @note This function only looks in the internal array of known

+ * hostnames, it does not send out a query for the hostname if none

+ * was found. The function dns_enqueue() can be used to send a query

+ * for a hostname.

+ *

+ * @param name the hostname to look up

+ * @return the hostname's IP address, as u32_t (instead of struct ip_addr to

+ *         better check for failure: != 0) or 0 if the hostname was not found

+ *         in the cached dns_table.

+ */

+static u32_t

+dns_lookup(const char *name)

+{

+  u8_t i;

+

+  /* Walk through name list, return entry if found. If not, return NULL. */

+  for (i = 0; i < DNS_TABLE_SIZE; ++i) {

+    if ((dns_table[i].state == DNS_STATE_DONE) &&

+        (strcmp(name, dns_table[i].name) == 0)) {

+      LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));

+      ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));

+      LWIP_DEBUGF(DNS_DEBUG, ("\n"));

+      return dns_table[i].ipaddr.addr;

+    }

+  }

+

+  return 0;

+}

+

+#if DNS_DOES_NAME_CHECK

+/**

+ * Compare the "dotted" name "query" with the encoded name "response"

+ * to make sure an answer from the DNS server matches the current dns_table

+ * entry (otherwise, answers might arrive late for hostname not on the list

+ * any more).

+ *

+ * @param query hostname (not encoded) from the dns_table

+ * @param response encoded hostname in the DNS response

+ * @return 0: names equal; 1: names differ

+ */

+static u8_t

+dns_compare_name(unsigned char *query, unsigned char *response)

+{

+  unsigned char n;

+

+  do {

+    n = *response++;

+    /** @see RFC 1035 - 4.1.4. Message compression */

+    if ((n & 0xc0) == 0xc0) {

+      /* Compressed name */

+      break;

+    } else {

+      /* Not compressed name */

+      while (n > 0) {

+        if ((*query) != (*response)) {

+          return 1;

+        }

+        ++response;

+        ++query;

+        --n;

+      };

+      ++query;

+    }

+  } while (*response != 0);

+

+  return 0;

+}

+#endif /* DNS_DOES_NAME_CHECK */

+

+/**

+ * Walk through a compact encoded DNS name and return the end of the name.

+ *

+ * @param query encoded DNS name in the DNS server response

+ * @return end of the name

+ */

+static unsigned char *

+dns_parse_name(unsigned char *query)

+{

+  unsigned char n;

+

+  do {

+    n = *query++;

+    /** @see RFC 1035 - 4.1.4. Message compression */

+    if ((n & 0xc0) == 0xc0) {

+      /* Compressed name */

+      break;

+    } else {

+      /* Not compressed name */

+      while (n > 0) {

+        ++query;

+        --n;

+      };

+    }

+  } while (*query != 0);

+

+  return query + 1;

+}

+

+/**

+ * Send a DNS query packet.

+ *

+ * @param numdns index of the DNS server in the dns_servers table

+ * @param name hostname to query

+ * @param id index of the hostname in dns_table, used as transaction ID in the

+ *        DNS query packet

+ * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise

+ */

+static err_t

+dns_send(u8_t numdns, const char* name, u8_t id)

+{

+  err_t err;

+  struct dns_hdr *hdr;

+  struct dns_query qry;

+  struct pbuf *p;

+  char *query, *nptr;

+  const char *pHostname;

+  u8_t n;

+

+  LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",

+              (u16_t)(numdns), name));

+  LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);

+  LWIP_ASSERT("dns server has no IP address set", dns_servers[numdns].addr != 0);

+

+  /* if here, we have either a new query or a retry on a previous query to process */

+  p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dns_hdr) + DNS_MAX_NAME_LENGTH +

+                 sizeof(struct dns_query), PBUF_RAM);

+  if (p != NULL) {

+    LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);

+    /* fill dns header */

+    hdr = (struct dns_hdr*)p->payload;

+    memset(hdr, 0, sizeof(struct dns_hdr));

+    hdr->id = htons(id);

+    hdr->flags1 = DNS_FLAG1_RD;

+    hdr->numquestions = htons(1);

+    query = (char*)hdr + sizeof(struct dns_hdr);

+    pHostname = name;

+    --pHostname;

+

+    /* convert hostname into suitable query format. */

+    do {

+      ++pHostname;

+      nptr = query;

+      ++query;

+      for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {

+        *query = *pHostname;

+        ++query;

+        ++n;

+      }

+      *nptr = n;

+    } while(*pHostname != 0);

+    *query++='\0';

+

+    /* fill dns query */

+    qry.type  = htons(DNS_RRTYPE_A);

+    qry.class = htons(DNS_RRCLASS_IN);

+    MEMCPY( query, &qry, sizeof(struct dns_query));

+

+    /* resize pbuf to the exact dns query */

+    pbuf_realloc(p, (query + sizeof(struct dns_query)) - ((char*)(p->payload)));

+

+    /* connect to the server for faster receiving */

+    udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);

+    /* send dns packet */

+    err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);

+

+    /* free pbuf */

+    pbuf_free(p);

+  } else {

+    err = ERR_MEM;

+  }

+

+  return err;

+}

+

+/**

+ * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query.

+ * Check an entry in the dns_table:

+ * - send out query for new entries

+ * - retry old pending entries on timeout (also with different servers)

+ * - remove completed entries from the table if their TTL has expired

+ *

+ * @param i index of the dns_table entry to check

+ */

+static void

+dns_check_entry(u8_t i)

+{

+  struct dns_table_entry *pEntry = &dns_table[i];

+

+  LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);

+

+  switch(pEntry->state) {

+

+    case DNS_STATE_NEW: {

+      /* initialize new entry */

+      pEntry->state   = DNS_STATE_ASKING;

+      pEntry->numdns  = 0;

+      pEntry->tmr     = 1;

+      pEntry->retries = 0;

+      

+      /* send DNS packet for this entry */

+      dns_send(pEntry->numdns, pEntry->name, i);

+      break;

+    }

+

+    case DNS_STATE_ASKING: {

+      if (--pEntry->tmr == 0) {

+        if (++pEntry->retries == DNS_MAX_RETRIES) {

+          if ((pEntry->numdns+1<DNS_MAX_SERVERS) && (dns_servers[pEntry->numdns+1].addr!=0)) {

+            /* change of server */

+            pEntry->numdns++;

+            pEntry->tmr     = 1;

+            pEntry->retries = 0;

+            break;

+          } else {

+            LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));

+            /* call specified callback function if provided */

+            if (pEntry->found)

+              (*pEntry->found)(pEntry->name, NULL, pEntry->arg);

+            /* flush this entry */

+            pEntry->state   = DNS_STATE_UNUSED;

+            pEntry->found   = NULL;

+            break;

+          }

+        }

+

+        /* wait longer for the next retry */

+        pEntry->tmr = pEntry->retries;

+

+        /* send DNS packet for this entry */

+        dns_send(pEntry->numdns, pEntry->name, i);

+      }

+      break;

+    }

+

+    case DNS_STATE_DONE: {

+      /* if the time to live is nul */

+      if (--pEntry->ttl == 0) {

+        LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));

+        /* flush this entry */

+        pEntry->state = DNS_STATE_UNUSED;

+        pEntry->found = NULL;

+      }

+      break;

+    }

+    case DNS_STATE_UNUSED:

+      /* nothing to do */

+      break;

+    default:

+      LWIP_ASSERT("unknown dns_table entry state:", 0);

+      break;

+  }

+}

+

+/**

+ * Call dns_check_entry for each entry in dns_table - check all entries.

+ */

+static void

+dns_check_entries(void)

+{

+  u8_t i;

+

+  for (i = 0; i < DNS_TABLE_SIZE; ++i) {

+    dns_check_entry(i);

+  }

+}

+

+/**

+ * Receive input function for DNS response packets arriving for the dns UDP pcb.

+ *

+ * @params see udp.h

+ */

+static void

+dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)

+{

+  u8_t i;

+  char *pHostname;

+  struct dns_hdr *hdr;

+  struct dns_answer ans;

+  struct dns_table_entry *pEntry;

+  u8_t nquestions, nanswers;

+#if (DNS_USES_STATIC_BUF == 0)

+  u8_t dns_payload[DNS_MSG_SIZE];

+#endif /* (DNS_USES_STATIC_BUF == 0) */

+#if (DNS_USES_STATIC_BUF == 2)

+  u8_t* dns_payload;

+#endif /* (DNS_USES_STATIC_BUF == 2) */

+

+  LWIP_UNUSED_ARG(arg);

+  LWIP_UNUSED_ARG(pcb);

+  LWIP_UNUSED_ARG(addr);

+  LWIP_UNUSED_ARG(port);

+

+  /* is the dns message too big ? */

+  if (p->tot_len > DNS_MSG_SIZE) {

+    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));

+    /* free pbuf and return */

+    goto memerr1;

+  }

+

+  /* is the dns message big enough ? */

+  if (p->tot_len < (sizeof(struct dns_hdr) + sizeof(struct dns_query) + sizeof(struct dns_answer))) {

+    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));

+    /* free pbuf and return */

+    goto memerr1;

+  }

+

+#if (DNS_USES_STATIC_BUF == 2)

+  dns_payload = mem_malloc(p->tot_len);

+  if (dns_payload == NULL) {

+    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: mem_malloc error\n"));

+    /* free pbuf and return */

+    goto memerr1;

+  }

+#endif /* (DNS_USES_STATIC_BUF == 2) */

+

+  /* copy dns payload inside static buffer for processing */ 

+  if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {

+    /* The ID in the DNS header should be our entry into the name table. */

+    hdr = (struct dns_hdr*)dns_payload;

+    i = htons(hdr->id);

+    if (i < DNS_TABLE_SIZE) {

+      pEntry = &dns_table[i];

+      if(pEntry->state == DNS_STATE_ASKING) {

+        /* This entry is now completed. */

+        pEntry->state = DNS_STATE_DONE;

+        pEntry->err   = hdr->flags2 & DNS_FLAG2_ERR_MASK;

+

+        /* We only care about the question(s) and the answers. The authrr

+           and the extrarr are simply discarded. */

+        nquestions = htons(hdr->numquestions);

+        nanswers   = htons(hdr->numanswers);

+

+        /* Check for error. If so, call callback to inform. */

+        if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {

+          LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));

+          /* call callback to indicate error, clean up memory and return */

+          goto responseerr;

+        }

+

+#if DNS_DOES_NAME_CHECK

+        /* Check if the name in the "question" part match with the name in the entry. */

+        if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + sizeof(struct dns_hdr)) != 0) {

+          LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));

+          /* call callback to indicate error, clean up memory and return */

+          goto responseerr;

+        }

+#endif /* DNS_DOES_NAME_CHECK */

+

+        /* Skip the name in the "question" part */

+        pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + sizeof(struct dns_hdr)) + sizeof(struct dns_query);

+

+        while(nanswers > 0) {

+          /* skip answer resource record's host name */

+          pHostname = (char *) dns_parse_name((unsigned char *)pHostname);

+

+          /* Check for IP address type and Internet class. Others are discarded. */

+          MEMCPY(&ans, pHostname, sizeof(struct dns_answer));

+          if((ntohs(ans.type) == DNS_RRTYPE_A) && (ntohs(ans.class) == DNS_RRCLASS_IN) && (ntohs(ans.len) == sizeof(struct ip_addr)) ) {

+            /* read the answer resource record's TTL, and maximize it if needed */

+            pEntry->ttl = ntohl(ans.ttl);

+            if (pEntry->ttl > DNS_MAX_TTL) {

+              pEntry->ttl = DNS_MAX_TTL;

+            }

+            /* read the IP address after answer resource record's header */

+            MEMCPY( &(pEntry->ipaddr), (pHostname+sizeof(struct dns_answer)), sizeof(struct ip_addr));

+            LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));

+            ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));

+            LWIP_DEBUGF(DNS_DEBUG, ("\n"));

+            /* call specified callback function if provided */

+            if (pEntry->found) {

+              (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);

+            }

+            /* deallocate memory and return */

+            goto memerr2;

+          } else {

+            pHostname = pHostname + sizeof(struct dns_answer) + htons(ans.len);

+          }

+          --nanswers;

+        }

+        LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));

+        /* call callback to indicate error, clean up memory and return */

+        goto responseerr;

+      }

+    }

+  }

+

+  /* deallocate memory and return */

+  goto memerr2;

+

+responseerr:

+  /* ERROR: call specified callback function with NULL as name to indicate an error */

+  if (pEntry->found) {

+    (*pEntry->found)(pEntry->name, NULL, pEntry->arg);

+  }

+  /* flush this entry */

+  pEntry->state = DNS_STATE_UNUSED;

+  pEntry->found = NULL;

+

+memerr2:

+#if (DNS_USES_STATIC_BUF == 2)

+  /* free dns buffer */

+  mem_free(dns_payload);

+#endif /* (DNS_USES_STATIC_BUF == 2) */

+

+memerr1:

+  /* free pbuf */

+  pbuf_free(p);

+  return;

+}

+

+/**

+ * Queues a new hostname to resolve and sends out a DNS query for that hostname

+ *

+ * @param name the hostname that is to be queried

+ * @param found a callback founction to be called on success, failure or timeout

+ * @param callback_arg argument to pass to the callback function

+ * @return @return a err_t return code.

+ */

+static err_t

+dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)

+{

+  u8_t i;

+  u8_t lseq, lseqi;

+  struct dns_table_entry *pEntry = NULL;

+

+  /* search an unused entry, or the oldest one */

+  lseq = lseqi = 0;

+  for (i = 0; i < DNS_TABLE_SIZE; ++i) {

+    pEntry = &dns_table[i];

+    /* is it an unused entry ? */

+    if (pEntry->state == DNS_STATE_UNUSED)

+      break;

+

+    /* check if this is the oldest completed entry */

+    if (pEntry->state == DNS_STATE_DONE) {

+      if ((dns_seqno - pEntry->seqno) > lseq) {

+        lseq = dns_seqno - pEntry->seqno;

+        lseqi = i;

+      }

+    }

+  }

+

+  /* if we don't have found an unused entry, use the oldest completed one */

+  if (i == DNS_TABLE_SIZE) {

+    if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {

+      /* no entry can't be used now, table is full */

+      LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));

+      return ERR_MEM;

+    } else {

+      /* use the oldest completed one */

+      i = lseqi;

+      pEntry = &dns_table[i];

+    }

+  }

+

+  /* use this entry */

+  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));

+

+  /* fill the entry */

+  pEntry->state = DNS_STATE_NEW;

+  pEntry->seqno = dns_seqno++;

+  pEntry->found = found;

+  pEntry->arg   = callback_arg;

+  strcpy(pEntry->name, name);

+

+  /* force to send query without waiting timer */

+  dns_check_entry(i);

+

+  /* dns query is enqueued */

+  return ERR_INPROGRESS;

+}

+

+/**

+ * Resolve a hostname (string) into an IP address.

+ * NON-BLOCKING callback version for use with raw API!!!

+ *

+ * Returns immediately with one of err_t return codes:

+ * - ERR_OK if hostname is a valid IP address string or the host

+ *   name is already in the local names table.

+ * - ERR_INPROGRESS enqueue a request to be sent to the DNS server

+ *   for resolution if no errors are present.

+ *

+ * @param hostname the hostname that is to be queried

+ * @param addr pointer to a struct ip_addr where to store the address if it is already

+ *             cached in the dns_table (only valid if ERR_OK is returned!)

+ * @param found a callback function to be called on success, failure or timeout (only if

+ *              ERR_INPROGRESS is returned!)

+ * @param callback_arg argument to pass to the callback function

+ * @return a err_t return code.

+ */

+err_t

+dns_gethostbyname(const char *hostname, struct ip_addr *addr, dns_found_callback found,

+                  void *callback_arg)

+{

+  /* not initialized or no valid server yet, or invalid addr pointer

+   * or invalid hostname or invalid hostname length */

+  if ((dns_pcb == NULL) || (addr == NULL) ||

+      (!hostname) || (!hostname[0]) ||

+      (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {

+    return ERR_VAL;

+  }

+

+#if LWIP_HAVE_LOOPIF

+  if (strcmp(hostname,"localhost")==0) {

+    addr->addr = INADDR_LOOPBACK;

+    return ERR_OK;

+  }

+#endif /* LWIP_HAVE_LOOPIF */

+

+  /* host name already in octet notation? set ip addr and return ERR_OK

+   * already have this address cached? */

+  if (((addr->addr = inet_addr(hostname)) != INADDR_NONE) ||

+      ((addr->addr = dns_lookup(hostname)) != 0)) {

+    return ERR_OK;

+  }

+

+  /* queue query with specified callback */

+  return dns_enqueue(hostname, found, callback_arg);

+}

+

+#endif /* LWIP_DNS */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/init.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/init.c
new file mode 100644
index 0000000..1faacb8
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/init.c
@@ -0,0 +1,253 @@
+/**

+ * @file

+ * Modules initialization

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#include "lwip/init.h"

+#include "lwip/stats.h"

+#include "lwip/sys.h"

+#include "lwip/mem.h"

+#include "lwip/memp.h"

+#include "lwip/pbuf.h"

+#include "lwip/netif.h"

+#include "lwip/sockets.h"

+#include "lwip/ip.h"

+#include "lwip/raw.h"

+#include "lwip/udp.h"

+#include "lwip/tcp.h"

+#include "lwip/autoip.h"

+#include "lwip/igmp.h"

+#include "lwip/dns.h"

+#include "netif/etharp.h"

+

+/* Compile-time sanity checks for configuration errors.

+ * These can be done independently of LWIP_DEBUG, without penalty.

+ */

+#ifndef BYTE_ORDER

+  #error "BYTE_ORDER is not defined, you have to define it in your cc.h"

+#endif

+#if (!LWIP_ARP && ARP_QUEUEING)

+  #error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h"

+#endif

+#if (!LWIP_UDP && LWIP_UDPLITE)

+  #error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h"

+#endif

+#if (!LWIP_UDP && LWIP_SNMP)

+  #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"

+#endif

+#if (!LWIP_UDP && LWIP_DHCP)

+  #error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h"

+#endif

+#if (!LWIP_UDP && LWIP_IGMP)

+  #error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h"

+#endif

+#if (!LWIP_UDP && LWIP_DNS)

+  #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h"

+#endif

+#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))

+  #error "If you want to use ARP, ARP_TABLE_SIZE must fit in an s8_t, so, you have to reduce it in your lwipopts.h"

+#endif

+#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0))

+  #error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h"

+#endif

+#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0))

+  #error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h"

+#endif

+#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0))

+  #error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h"

+#endif

+#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0))

+  #error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h"

+#endif

+#if (LWIP_TCP && (TCP_WND > 0xffff))

+  #error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h"

+#endif

+#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff))

+  #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h"

+#endif

+#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12)))

+  #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h"

+#endif

+#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))

+  #error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t"

+#endif

+#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))

+  #error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"

+#endif

+#if (PPP_SUPPORT && (NO_SYS==1))

+  #error "If you want to use PPP, you have to define NO_SYS=0 in your lwipopts.h"

+#endif

+#if (LWIP_NETIF_API && (NO_SYS==1))

+  #error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h"

+#endif

+#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))

+  #error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"

+#endif

+#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))

+  #error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"

+#endif

+#if (!LWIP_NETCONN && LWIP_SOCKET)

+  #error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h"

+#endif

+#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP)

+  #error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h"

+#endif

+#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK)

+  #error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h"

+#endif

+#if (!LWIP_ARP && LWIP_AUTOIP)

+  #error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h"

+#endif

+#if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0))

+  #error "If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h"

+#endif

+#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0))

+  #error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h"

+#endif

+#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API)))

+  #error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h"

+#endif

+/* There must be sufficient timeouts, taking into account requirements of the subsystems. */

+#if ((NO_SYS==0) && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT)))

+  #error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"

+#endif

+#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))

+  #error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"

+#endif

+#if (MEM_LIBC_MALLOC && MEM_USE_POOLS)

+  #error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h"

+#endif

+#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS)

+  #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h"

+#endif

+

+

+/* Compile-time checks for deprecated options.

+ */

+#ifdef MEMP_NUM_TCPIP_MSG

+  #error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h."

+#endif

+#ifdef MEMP_NUM_API_MSG

+  #error "MEMP_NUM_API_MSG option is deprecated. Remove it from your lwipopts.h."

+#endif

+#ifdef TCP_REXMIT_DEBUG

+  #error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h."

+#endif

+#ifdef RAW_STATS

+  #error "RAW_STATS option is deprecated. Remove it from your lwipopts.h."

+#endif

+#ifdef ETHARP_QUEUE_FIRST

+  #error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h."

+#endif

+#ifdef ETHARP_ALWAYS_INSERT

+  #error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h."

+#endif

+#if SO_REUSE

+/* I removed the lot since this was an ugly hack. It broke the raw-API.

+   It also came with many ugly goto's, Christiaan Simons. */

+  #error "SO_REUSE currently unavailable, this was a hack"

+#endif

+

+#ifdef LWIP_DEBUG

+static void

+lwip_sanity_check(void)

+{

+  /* Warnings */

+#if LWIP_NETCONN

+  if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB))

+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN\n"));

+#endif /* LWIP_NETCONN */

+#if LWIP_TCP

+  if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)

+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n"));

+  if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS)))

+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n"));

+  if (TCP_SNDLOWAT > TCP_SND_BUF)

+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than or equal to TCP_SND_BUF.\n"));

+  if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE))

+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n"));

+  if (TCP_WND < TCP_MSS)

+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n"));

+#endif /* LWIP_TCP */

+}

+#else  /* LWIP_DEBUG */

+#define lwip_sanity_check()

+#endif /* LWIP_DEBUG */

+

+/**

+ * Perform Sanity check of user-configurable values, and initialize all modules.

+ */

+void

+lwip_init(void)

+{

+  /* Sanity check user-configurable values */

+  lwip_sanity_check();

+

+  /* Modules initialization */

+  stats_init();

+  sys_init();

+  mem_init();

+  memp_init();

+  pbuf_init();

+  netif_init();

+#if LWIP_SOCKET

+  lwip_socket_init();

+#endif /* LWIP_SOCKET */

+  ip_init();

+#if LWIP_ARP

+  etharp_init();

+#endif /* LWIP_ARP */

+#if LWIP_RAW

+  raw_init();

+#endif /* LWIP_RAW */

+#if LWIP_UDP

+  udp_init();

+#endif /* LWIP_UDP */

+#if LWIP_TCP

+  tcp_init();

+#endif /* LWIP_TCP */

+#if LWIP_AUTOIP

+  autoip_init();

+#endif /* LWIP_AUTOIP */

+#if LWIP_IGMP

+  igmp_init();

+#endif /* LWIP_IGMP */

+#if LWIP_DNS

+  dns_init();

+#endif /* LWIP_DNS */

+}

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/autoip.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/autoip.c
new file mode 100644
index 0000000..e7fd48e
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/autoip.c
@@ -0,0 +1,432 @@
+/**

+ * @file

+ * AutoIP Automatic LinkLocal IP Configuration

+ *

+ */

+

+/*

+ *

+ * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * Author: Dominik Spies <kontakt@dspies.de>

+ *

+ * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform

+ * with RFC 3927.

+ *

+ *

+ * Please coordinate changes and requests with Dominik Spies

+ * <kontakt@dspies.de>

+ */

+

+/*******************************************************************************

+ * USAGE:

+ * 

+ * define LWIP_AUTOIP 1  in your lwipopts.h

+ * 

+ * If you don't use tcpip.c (so, don't call, you don't call tcpip_init):

+ * - First, call autoip_init().

+ * - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces,

+ *   that should be defined in autoip.h.

+ *   I recommend a value of 100. The value must divide 1000 with a remainder almost 0.

+ *   Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....

+ *

+ * Without DHCP:

+ * - Call autoip_start() after netif_add().

+ * 

+ * With DHCP:

+ * - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.

+ * - Configure your DHCP Client.

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/mem.h"

+#include "lwip/udp.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/autoip.h"

+#include "netif/etharp.h"

+

+#include <stdlib.h>

+#include <string.h>

+

+/* Pseudo random macro based on netif informations.

+ * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */

+#ifndef LWIP_AUTOIP_RAND

+#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \

+                                   ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \

+                                   ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \

+                                   ((u32_t)((netif->hwaddr[4]) & 0xff))) + \

+                                   (netif->autoip?netif->autoip->tried_llipaddr:0))

+#endif /* LWIP_AUTOIP_RAND */

+

+/* static functions */

+static void autoip_handle_arp_conflict(struct netif *netif);

+

+/* creates random LL IP-Address for a network interface */

+static void autoip_create_rand_addr(struct netif *netif, struct ip_addr *RandomIPAddr);

+

+/* sends an ARP announce */

+static err_t autoip_arp_announce(struct netif *netif);

+

+/* configure interface for use with current LL IP-Address */

+static err_t autoip_bind(struct netif *netif);

+

+/**

+ * Initialize this module

+ */

+void

+autoip_init(void)

+{

+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_init()\n"));

+}

+

+/**

+ * Handle a IP address conflict after an ARP conflict detection

+ */

+static void

+autoip_handle_arp_conflict(struct netif *netif)

+{

+  /* Somehow detect if we are defending or retreating */

+  unsigned char defend = 1; /* tbd */

+

+  if(defend) {

+    if(netif->autoip->lastconflict > 0) {

+      /* retreat, there was a conflicting ARP in the last

+       * DEFEND_INTERVAL seconds

+       */

+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,

+        ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));

+

+      /* TODO: close all TCP sessions */

+      autoip_start(netif);

+    } else {

+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,

+        ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));

+      autoip_arp_announce(netif);

+      netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;

+    }

+  } else {

+    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,

+      ("autoip_handle_arp_conflict(): we do not defend, retreating\n"));

+    /* TODO: close all TCP sessions */

+    autoip_start(netif);

+  }

+}

+

+/**

+ * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255

+ *

+ * @param netif network interface on which create the IP-Address

+ * @param RandomIPAddr ip address to initialize

+ */

+static void

+autoip_create_rand_addr(struct netif *netif, struct ip_addr *RandomIPAddr)

+{

+  /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255

+   * compliant to RFC 3927 Section 2.1

+   * We have 254 * 256 possibilities

+   */

+  

+  RandomIPAddr->addr = (0xA9FE0100 + ((u32_t)(((u8_t)(netif->hwaddr[4])) |

+    ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)) + netif->autoip->tried_llipaddr);

+

+  if (RandomIPAddr->addr>0xA9FEFEFF) {

+    RandomIPAddr->addr = (0xA9FE0100 + (RandomIPAddr->addr-0xA9FEFEFF));

+  }

+  if (RandomIPAddr->addr<0xA9FE0100) {

+    RandomIPAddr->addr = (0xA9FEFEFF - (0xA9FE0100-RandomIPAddr->addr));

+  }

+  RandomIPAddr->addr = htonl(RandomIPAddr->addr);

+  

+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,

+    ("autoip_create_rand_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n",

+    (u16_t)(netif->autoip->tried_llipaddr), (u32_t)(RandomIPAddr->addr)));

+}

+

+/**

+ * Sends an ARP announce from a network interface

+ *

+ * @param netif network interface used to send the announce

+ */

+static err_t

+autoip_arp_announce(struct netif *netif)

+{

+  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,

+    (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, &ethzero,

+    &netif->autoip->llipaddr, ARP_REQUEST);

+}

+

+/**

+ * Configure interface for use with current LL IP-Address

+ *

+ * @param netif network interface to configure with current LL IP-Address

+ */

+static err_t

+autoip_bind(struct netif *netif)

+{

+  struct autoip *autoip = netif->autoip;

+  struct ip_addr sn_mask, gw_addr;

+

+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,

+    ("autoip_bind(netif=%p) %c%c%"U16_F" 0x%08"X32_F"\n",

+    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, autoip->llipaddr.addr));

+

+  IP4_ADDR(&sn_mask, 255, 255, 0, 0);

+  IP4_ADDR(&gw_addr, 0, 0, 0, 0);

+

+  netif_set_ipaddr(netif, &autoip->llipaddr);

+  netif_set_netmask(netif, &sn_mask);

+  netif_set_gw(netif, &gw_addr);  

+

+  /* bring the interface up */

+  netif_set_up(netif);

+

+  return ERR_OK;

+}

+

+/**

+ * Start AutoIP client

+ *

+ * @param netif network interface on which start the AutoIP client

+ */

+err_t

+autoip_start(struct netif *netif)

+{

+  struct autoip *autoip = netif->autoip;

+  err_t result = ERR_OK;

+

+  if(netif_is_up(netif)) {

+    netif_set_down(netif);

+  }

+

+  /* Set IP-Address, Netmask and Gateway to 0 to make sure that

+   * ARP Packets are formed correctly

+   */

+  netif->ip_addr.addr = 0;

+  netif->netmask.addr = 0;

+  netif->gw.addr      = 0;

+

+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,

+    ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0],

+    netif->name[1], (u16_t)netif->num));

+  if(autoip == NULL) {

+    /* no AutoIP client attached yet? */

+    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,

+      ("autoip_start(): starting new AUTOIP client\n"));

+    autoip = mem_malloc(sizeof(struct autoip));

+    if(autoip == NULL) {

+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,

+        ("autoip_start(): could not allocate autoip\n"));

+      return ERR_MEM;

+    }

+    memset( autoip, 0, sizeof(struct autoip));

+    /* store this AutoIP client in the netif */

+    netif->autoip = autoip;

+    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));

+  } else {

+    autoip->state = AUTOIP_STATE_OFF;

+    autoip->ttw = 0;

+    autoip->sent_num = 0;

+    memset(&autoip->llipaddr, 0, sizeof(struct ip_addr));

+    autoip->lastconflict = 0;

+  }

+

+  autoip_create_rand_addr(netif, &(autoip->llipaddr));

+  autoip->tried_llipaddr++;

+  autoip->state = AUTOIP_STATE_PROBING;

+  autoip->sent_num = 0;

+

+  /* time to wait to first probe, this is randomly

+   * choosen out of 0 to PROBE_WAIT seconds.

+   * compliant to RFC 3927 Section 2.2.1

+   */

+  autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND));

+

+  /*

+   * if we tried more then MAX_CONFLICTS we must limit our rate for

+   * accquiring and probing address

+   * compliant to RFC 3927 Section 2.2.1

+   */

+

+  if(autoip->tried_llipaddr > MAX_CONFLICTS) {

+    autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;

+  }

+

+  return result;

+}

+

+/**

+ * Stop AutoIP client

+ *

+ * @param netif network interface on which stop the AutoIP client

+ */

+err_t

+autoip_stop(struct netif *netif)

+{

+  netif->autoip->state = AUTOIP_STATE_OFF;

+  netif_set_down(netif);

+  return ERR_OK;

+}

+

+/**

+ * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds

+ */

+void

+autoip_tmr()

+{

+  struct netif *netif = netif_list;

+  /* loop through netif's */

+  while (netif != NULL) {

+    /* only act on AutoIP configured interfaces */

+    if (netif->autoip != NULL) {

+      if(netif->autoip->lastconflict > 0) {

+        netif->autoip->lastconflict--;

+      }

+

+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,

+        ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n",

+        (u16_t)(netif->autoip->state), netif->autoip->ttw));

+

+      switch(netif->autoip->state) {

+        case AUTOIP_STATE_PROBING:

+          if(netif->autoip->ttw > 0) {

+            netif->autoip->ttw--;

+          } else {

+            if(netif->autoip->sent_num == PROBE_NUM) {

+              netif->autoip->state = AUTOIP_STATE_ANNOUNCING;

+              netif->autoip->sent_num = 0;

+              netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;

+            } else {

+              etharp_request(netif, &(netif->autoip->llipaddr));

+              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,

+                ("autoip_tmr() PROBING Sent Probe\n"));

+              netif->autoip->sent_num++;

+              /* calculate time to wait to next probe */

+              netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %

+                ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +

+                PROBE_MIN * AUTOIP_TICKS_PER_SECOND);

+            }

+          }

+          break;

+

+        case AUTOIP_STATE_ANNOUNCING:

+          if(netif->autoip->ttw > 0) {

+            netif->autoip->ttw--;

+          } else {

+            if(netif->autoip->sent_num == 0) {

+             /* We are here the first time, so we waited ANNOUNCE_WAIT seconds

+              * Now we can bind to an IP address and use it

+              */

+              autoip_bind(netif);

+            }

+

+            if(netif->autoip->sent_num == ANNOUNCE_NUM) {

+              netif->autoip->state = AUTOIP_STATE_BOUND;

+              netif->autoip->sent_num = 0;

+              netif->autoip->ttw = 0;

+            } else {

+              autoip_arp_announce(netif);

+              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,

+                ("autoip_tmr() ANNOUNCING Sent Announce\n"));

+              netif->autoip->sent_num++;

+              netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;

+            }

+          }

+          break;

+      }

+    }

+    /* proceed to next network interface */

+    netif = netif->next;

+  }

+}

+

+/**

+ * Handles every incoming ARP Packet, called by etharp_arp_input.

+ *

+ * @param netif network interface to use for autoip processing

+ * @param hdr Incoming ARP packet

+ */

+void

+autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)

+{

+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_arp_reply()\n"));

+  if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) {

+   /* when ip.src == llipaddr && hw.src != netif->hwaddr

+    *

+    * when probing  ip.dst == llipaddr && hw.src != netif->hwaddr

+    * we have a conflict and must solve it

+    */

+    struct ip_addr sipaddr, dipaddr;

+    struct eth_addr netifaddr;

+    netifaddr.addr[0] = netif->hwaddr[0];

+    netifaddr.addr[1] = netif->hwaddr[1];

+    netifaddr.addr[2] = netif->hwaddr[2];

+    netifaddr.addr[3] = netif->hwaddr[3];

+    netifaddr.addr[4] = netif->hwaddr[4];

+    netifaddr.addr[5] = netif->hwaddr[5];

+

+    /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without

+     * structure packing (not using structure copy which breaks strict-aliasing rules).

+     */

+    MEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));

+    MEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));

+      

+    if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||

+        ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&

+         (netif->autoip->sent_num == 0))) {

+     /* RFC 3927 Section 2.2.1:

+      * from beginning to after ANNOUNCE_WAIT

+      * seconds we have a conflict if

+      * ip.src == llipaddr OR

+      * ip.dst == llipaddr && hw.src != own hwaddr

+      */

+      if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||

+          (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&

+           !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {

+        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,

+          ("autoip_arp_reply(): Probe Conflict detected\n"));

+        autoip_start(netif);

+      }

+    } else {

+     /* RFC 3927 Section 2.5:

+      * in any state we have a conflict if

+      * ip.src == llipaddr && hw.src != own hwaddr

+      */

+      if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&

+          !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {

+        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,

+          ("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));

+        autoip_handle_arp_conflict(netif);

+      }

+    }

+  }

+}

+

+#endif /* LWIP_AUTOIP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/icmp.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/icmp.c
new file mode 100644
index 0000000..aca1e5e
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/icmp.c
@@ -0,0 +1,317 @@
+/**

+ * @file

+ * ICMP - Internet Control Message Protocol

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+/* Some ICMP messages should be passed to the transport protocols. This

+   is not implemented. */

+

+#include "lwip/opt.h"

+

+#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/icmp.h"

+#include "lwip/inet.h"

+#include "lwip/inet_chksum.h"

+#include "lwip/ip.h"

+#include "lwip/def.h"

+#include "lwip/stats.h"

+#include "lwip/snmp.h"

+

+#include <string.h>

+

+/* The amount of data from the original packet to return in a dest-unreachable */

+#define ICMP_DEST_UNREACH_DATASIZE 8

+

+/**

+ * Processes ICMP input packets, called from ip_input().

+ *

+ * Currently only processes icmp echo requests and sends

+ * out the echo response.

+ *

+ * @param p the icmp echo request packet, p->payload pointing to the ip header

+ * @param inp the netif on which this packet was received

+ */

+void

+icmp_input(struct pbuf *p, struct netif *inp)

+{

+  u8_t type;

+#ifdef LWIP_DEBUG

+  u8_t code;

+#endif /* LWIP_DEBUG */

+  struct icmp_echo_hdr *iecho;

+  struct ip_hdr *iphdr;

+  struct ip_addr tmpaddr;

+  s16_t hlen;

+

+  ICMP_STATS_INC(icmp.recv);

+  snmp_inc_icmpinmsgs();

+

+

+  iphdr = p->payload;

+  hlen = IPH_HL(iphdr) * 4;

+  if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {

+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));

+    goto lenerr;

+  }

+

+  type = *((u8_t *)p->payload);

+#ifdef LWIP_DEBUG

+  code = *(((u8_t *)p->payload)+1);

+#endif /* LWIP_DEBUG */

+  switch (type) {

+  case ICMP_ECHO:

+    /* broadcast or multicast destination address? */

+    if (ip_addr_isbroadcast(&iphdr->dest, inp) || ip_addr_ismulticast(&iphdr->dest)) {

+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));

+      ICMP_STATS_INC(icmp.err);

+      pbuf_free(p);

+      return;

+    }

+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));

+    if (p->tot_len < sizeof(struct icmp_echo_hdr)) {

+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));

+      goto lenerr;

+    }

+    if (inet_chksum_pbuf(p) != 0) {

+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));

+      pbuf_free(p);

+      ICMP_STATS_INC(icmp.chkerr);

+      snmp_inc_icmpinerrors();

+      return;

+    }

+    if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {

+      /* p is not big enough to contain link headers

+       * allocate a new one and copy p into it

+       */

+      struct pbuf *r;

+      /* switch p->payload to ip header */

+      if (pbuf_header(p, hlen)) {

+        LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);

+        goto memerr;

+      }

+      /* allocate new packet buffer with space for link headers */

+      r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);

+      if (r == NULL) {

+        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));

+        goto memerr;

+      }

+      LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",

+                  (r->len >= hlen + sizeof(struct icmp_echo_hdr)));

+      /* copy the whole packet including ip header */

+      if (pbuf_copy(r, p) != ERR_OK) {

+        LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);

+        goto memerr;

+      }

+      iphdr = r->payload;

+      /* switch r->payload back to icmp header */

+      if (pbuf_header(r, -hlen)) {

+        LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);

+        goto memerr;

+      }

+      /* free the original p */

+      pbuf_free(p);

+      /* we now have an identical copy of p that has room for link headers */

+      p = r;

+    } else {

+      /* restore p->payload to point to icmp header */

+      if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {

+        LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);

+        goto memerr;

+      }

+    }

+    /* At this point, all checks are OK. */

+    /* We generate an answer by switching the dest and src ip addresses,

+     * setting the icmp type to ECHO_RESPONSE and updating the checksum. */

+    iecho = p->payload;

+    tmpaddr.addr = iphdr->src.addr;

+    iphdr->src.addr = iphdr->dest.addr;

+    iphdr->dest.addr = tmpaddr.addr;

+    ICMPH_TYPE_SET(iecho, ICMP_ER);

+    /* adjust the checksum */

+    if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) {

+      iecho->chksum += htons(ICMP_ECHO << 8) + 1;

+    } else {

+      iecho->chksum += htons(ICMP_ECHO << 8);

+    }

+

+    /* Set the correct TTL and recalculate the header checksum. */

+    IPH_TTL_SET(iphdr, ICMP_TTL);

+    IPH_CHKSUM_SET(iphdr, 0);

+#if CHECKSUM_GEN_IP

+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));

+#endif /* CHECKSUM_GEN_IP */

+

+    ICMP_STATS_INC(icmp.xmit);

+    /* increase number of messages attempted to send */

+    snmp_inc_icmpoutmsgs();

+    /* increase number of echo replies attempted to send */

+    snmp_inc_icmpoutechoreps();

+

+    if(pbuf_header(p, hlen)) {

+      LWIP_ASSERT("Can't move over header in packet", 0);

+    } else {

+      err_t ret;

+      ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL,

+                   ICMP_TTL, 0, IP_PROTO_ICMP, inp);

+      if (ret != ERR_OK) {

+        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));

+      }

+    }

+    break;

+  default:

+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",

+                (s16_t)type, (s16_t)code));

+    ICMP_STATS_INC(icmp.proterr);

+    ICMP_STATS_INC(icmp.drop);

+  }

+  pbuf_free(p);

+  return;

+lenerr:

+  pbuf_free(p);

+  ICMP_STATS_INC(icmp.lenerr);

+  snmp_inc_icmpinerrors();

+  return;

+memerr:

+  pbuf_free(p);

+  ICMP_STATS_INC(icmp.err);

+  snmp_inc_icmpinerrors();

+  return;

+}

+

+/**

+ * Send an icmp 'destination unreachable' packet, called from ip_input() if

+ * the transport layer protocol is unknown and from udp_input() if the local

+ * port is not bound.

+ *

+ * @param p the input packet for which the 'unreachable' should be sent,

+ *          p->payload pointing to the IP header

+ * @param t type of the 'unreachable' packet

+ */

+void

+icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)

+{

+  struct pbuf *q;

+  struct ip_hdr *iphdr;

+  struct icmp_dur_hdr *idur;

+

+  /* ICMP header + IP header + 8 bytes of data */

+  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,

+                 PBUF_RAM);

+  if (q == NULL) {

+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));

+    return;

+  }

+  LWIP_ASSERT("check that first pbuf can hold icmp message",

+             (q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));

+

+  iphdr = p->payload;

+

+  idur = q->payload;

+  ICMPH_TYPE_SET(idur, ICMP_DUR);

+  ICMPH_CODE_SET(idur, t);

+

+  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), p->payload,

+          IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);

+

+  /* calculate checksum */

+  idur->chksum = 0;

+  idur->chksum = inet_chksum(idur, q->len);

+  ICMP_STATS_INC(icmp.xmit);

+  /* increase number of messages attempted to send */

+  snmp_inc_icmpoutmsgs();

+  /* increase number of destination unreachable messages attempted to send */

+  snmp_inc_icmpoutdestunreachs();

+

+  ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);

+  pbuf_free(q);

+}

+

+#if IP_FORWARD || IP_REASSEMBLY

+/**

+ * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0.

+ *

+ * @param p the input packet for which the 'time exceeded' should be sent,

+ *          p->payload pointing to the IP header

+ * @param t type of the 'time exceeded' packet

+ */

+void

+icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)

+{

+  struct pbuf *q;

+  struct ip_hdr *iphdr;

+  struct icmp_te_hdr *tehdr;

+

+  /* ICMP header + IP header + 8 bytes of data */

+  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,

+                 PBUF_RAM);

+  if (q == NULL) {

+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));

+    return;

+  }

+  LWIP_ASSERT("check that first pbuf can hold icmp message",

+             (q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));

+

+  iphdr = p->payload;

+  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));

+  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));

+  LWIP_DEBUGF(ICMP_DEBUG, (" to "));

+  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));

+  LWIP_DEBUGF(ICMP_DEBUG, ("\n"));

+

+  tehdr = q->payload;

+  ICMPH_TYPE_SET(tehdr, ICMP_TE);

+  ICMPH_CODE_SET(tehdr, t);

+

+  /* copy fields from original packet */

+  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), (u8_t *)p->payload,

+          IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);

+

+  /* calculate checksum */

+  tehdr->chksum = 0;

+  tehdr->chksum = inet_chksum(tehdr, q->len);

+  ICMP_STATS_INC(icmp.xmit);

+  /* increase number of messages attempted to send */

+  snmp_inc_icmpoutmsgs();

+  /* increase number of destination unreachable messages attempted to send */

+  snmp_inc_icmpouttimeexcds();

+  ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);

+  pbuf_free(q);

+}

+

+#endif /* IP_FORWARD */

+

+#endif /* LWIP_ICMP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/igmp.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/igmp.c
new file mode 100644
index 0000000..13144b6
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/igmp.c
@@ -0,0 +1,808 @@
+/**

+ * @file

+ * IGMP - Internet Group Management Protocol

+ *

+ */

+

+/*

+ * Copyright (c) 2002 CITEL Technologies Ltd.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without 

+ * modification, are permitted provided that the following conditions 

+ * are met: 

+ * 1. Redistributions of source code must retain the above copyright 

+ *    notice, this list of conditions and the following disclaimer. 

+ * 2. Redistributions in binary form must reproduce the above copyright 

+ *    notice, this list of conditions and the following disclaimer in the 

+ *    documentation and/or other materials provided with the distribution. 

+ * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors 

+ *    may be used to endorse or promote products derived from this software 

+ *    without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''

+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 

+ * ARE DISCLAIMED.  IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE 

+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 

+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 

+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 

+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 

+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 

+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 

+ * SUCH DAMAGE. 

+ *

+ * This file is a contribution to the lwIP TCP/IP stack.

+ * The Swedish Institute of Computer Science and Adam Dunkels

+ * are specifically granted permission to redistribute this

+ * source code.

+*/

+

+/*-------------------------------------------------------------

+Note 1)

+Although the rfc requires V1 AND V2 capability

+we will only support v2 since now V1 is very old (August 1989)

+V1 can be added if required

+

+a debug print and statistic have been implemented to

+show this up.

+-------------------------------------------------------------

+-------------------------------------------------------------

+Note 2)

+A query for a specific group address (as opposed to ALLHOSTS)

+has now been implemented as I am unsure if it is required

+

+a debug print and statistic have been implemented to

+show this up.

+-------------------------------------------------------------

+-------------------------------------------------------------

+Note 3)

+The router alert rfc 2113 is implemented in outgoing packets

+but not checked rigorously incoming

+-------------------------------------------------------------

+Steve Reynolds

+------------------------------------------------------------*/

+

+/*-----------------------------------------------------------------------------

+ * RFC 988  - Host extensions for IP multicasting                         - V0

+ * RFC 1054 - Host extensions for IP multicasting                         -

+ * RFC 1112 - Host extensions for IP multicasting                         - V1

+ * RFC 2236 - Internet Group Management Protocol, Version 2               - V2  <- this code is based on this RFC (it's the "de facto" standard)

+ * RFC 3376 - Internet Group Management Protocol, Version 3               - V3

+ * RFC 4604 - Using Internet Group Management Protocol Version 3...       - V3+

+ * RFC 2113 - IP Router Alert Option                                      - 

+ *----------------------------------------------------------------------------*/

+

+/*-----------------------------------------------------------------------------

+ * Includes

+ *----------------------------------------------------------------------------*/

+

+#include "lwip/opt.h"

+

+#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/igmp.h"

+#include "lwip/debug.h"

+#include "lwip/def.h"

+#include "lwip/mem.h"

+#include "lwip/ip.h"

+#include "lwip/inet.h"

+#include "lwip/inet_chksum.h"

+#include "lwip/netif.h"

+#include "lwip/icmp.h"

+#include "lwip/udp.h"

+#include "lwip/tcp.h"

+#include "lwip/stats.h"

+

+#include "string.h"

+

+/*-----------------------------------------------------------------------------

+ * Globales

+ *----------------------------------------------------------------------------*/

+

+static struct igmp_group* igmp_group_list;

+static struct ip_addr     allsystems;

+static struct ip_addr     allrouters;

+

+/**

+ * Initialize the IGMP module

+ */

+void

+igmp_init(void)

+{

+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));

+

+  IP4_ADDR(&allsystems, 224, 0, 0, 1);

+  IP4_ADDR(&allrouters, 224, 0, 0, 2);

+}

+

+#ifdef LWIP_DEBUG

+/**

+ * Dump global IGMP groups list

+ */

+void

+igmp_dump_group_list()

+{ 

+  struct igmp_group *group = igmp_group_list;

+

+  while (group != NULL) {

+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));

+    ip_addr_debug_print(IGMP_DEBUG, &group->group_address);

+    LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) group->interface));

+    group = group->next;

+  }

+  LWIP_DEBUGF(IGMP_DEBUG, ("\n"));

+}

+#else

+#define igmp_dump_group_list()

+#endif /* LWIP_DEBUG */

+

+/**

+ * Start IGMP processing on interface

+ *

+ * @param netif network interface on which start IGMP processing

+ */

+err_t

+igmp_start(struct netif *netif)

+{

+  struct igmp_group* group;

+

+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %x\n", (int) netif));

+

+  group = igmp_lookup_group(netif, &allsystems);

+

+  if (group != NULL) {

+    group->group_state = IGMP_GROUP_IDLE_MEMBER;

+    group->use++;

+

+    /* Allow the igmp messages at the MAC level */

+    if (netif->igmp_mac_filter != NULL) {

+      LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));

+      ip_addr_debug_print(IGMP_DEBUG, &allsystems);

+      LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));

+      netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER);

+    }

+

+    return ERR_OK;

+  }

+

+  return ERR_MEM;

+}

+

+/**

+ * Stop IGMP processing on interface

+ *

+ * @param netif network interface on which stop IGMP processing

+ */

+err_t

+igmp_stop(struct netif *netif)

+{

+  struct igmp_group *group = igmp_group_list;

+  struct igmp_group *prev  = NULL;

+  struct igmp_group *next;

+

+  /* look for groups joined on this interface further down the list */

+  while (group != NULL) {

+    next = group->next;

+    /* is it a group joined on this interface? */

+    if (group->interface == netif) {

+      /* is it the first group of the list? */

+      if (group == igmp_group_list) {

+        igmp_group_list = next;

+      }

+      /* is there a "previous" group defined? */

+      if (prev != NULL) {

+        prev->next = next;

+      }

+      /* disable the group at the MAC level */

+      if (netif->igmp_mac_filter != NULL) {

+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));

+        ip_addr_debug_print(IGMP_DEBUG, &group->group_address);

+        LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));

+        netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);

+      }

+      /* free group */

+      memp_free(MEMP_IGMP_GROUP, group);

+    } else {

+      /* change the "previous" */

+      prev = group;

+    }

+    /* move to "next" */

+    group = next;

+  }

+  return ERR_OK;

+}

+

+/**

+ * Report IGMP memberships for this interface

+ *

+ * @param netif network interface on which report IGMP memberships

+ */

+void

+igmp_report_groups( struct netif *netif)

+{

+  struct igmp_group *group = igmp_group_list;

+

+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %x\n", (int) netif));

+

+  while (group != NULL) {

+    if (group->interface == netif) {

+      igmp_delaying_member( group, IGMP_JOIN_DELAYING_MEMBER_TMR);

+    }

+    group = group->next;

+  }

+}

+

+/**

+ * Search for a group in the global igmp_group_list

+ *

+ * @param ifp the network interface for which to look

+ * @param addr the group ip address to search for

+ * @return a struct igmp_group* if the group has been found,

+ *         NULL if the group wasn't found.

+ */

+struct igmp_group *

+igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr)

+{

+  struct igmp_group *group = igmp_group_list;

+

+  while (group != NULL) {

+    if ((group->interface == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {

+      return group;

+    }

+    group = group->next;

+  }

+

+  /* to be clearer, we return NULL here instead of

+   * 'group' (which is also NULL at this point).

+   */

+  return NULL;

+}

+

+/**

+ * Search for a specific igmp group and create a new one if not found-

+ *

+ * @param ifp the network interface for which to look

+ * @param addr the group ip address to search

+ * @return a struct igmp_group*,

+ *         NULL on memory error.

+ */

+struct igmp_group *

+igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)

+{

+  struct igmp_group *group = igmp_group_list;

+  

+  /* Search if the group already exists */

+  group = igmp_lookfor_group(ifp, addr);

+  if (group != NULL) {

+    /* Group already exists. */

+    return group;

+  }

+

+  /* Group doesn't exist yet, create a new one */

+  group = memp_malloc(MEMP_IGMP_GROUP);

+  if (group != NULL) {

+    group->interface          = ifp;

+    ip_addr_set(&(group->group_address), addr);

+    group->timer              = 0; /* Not running */

+    group->group_state        = IGMP_GROUP_NON_MEMBER;

+    group->last_reporter_flag = 0;

+    group->use                = 0;

+    group->next               = igmp_group_list;

+    

+    igmp_group_list = group;

+  }

+

+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));

+  ip_addr_debug_print(IGMP_DEBUG, addr);

+  LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) ifp));

+

+  return group;

+}

+

+/**

+ * Remove a group in the global igmp_group_list

+ *

+ * @param group the group to remove from the global igmp_group_list

+ * @return ERR_OK if group was removed from the list, an err_t otherwise

+ */

+err_t

+igmp_remove_group(struct igmp_group *group)

+{

+  err_t err = ERR_OK;

+

+  /* Is it the first group? */

+  if (igmp_group_list == group) {

+    igmp_group_list = group->next;

+  } else {

+    /* look for group further down the list */

+    struct igmp_group *tmpGroup;

+    for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {

+      if (tmpGroup->next == group) {

+        tmpGroup->next = group->next;

+        break;

+      }

+    }

+    /* Group not found in the global igmp_group_list */

+    if (tmpGroup == NULL)

+      err = ERR_ARG;

+  }

+  /* free group */

+  memp_free(MEMP_IGMP_GROUP, group);

+

+  return err;

+}

+

+/**

+ * Called from ip_input() if a new IGMP packet is received.

+ *

+ * @param p received igmp packet, p->payload pointing to the ip header

+ * @param inp network interface on which the packet was received

+ * @param dest destination ip address of the igmp packet

+ */

+void

+igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)

+{

+  struct ip_hdr *    iphdr;

+  struct igmp_msg*   igmp;

+  struct igmp_group* group;

+  struct igmp_group* groupref;

+

+  /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */    

+  iphdr = p->payload;

+  if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {

+    pbuf_free(p);

+    IGMP_STATS_INC(igmp.lenerr);

+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));

+    return;

+  }

+

+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));

+  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));

+  LWIP_DEBUGF(IGMP_DEBUG, (" to address "));

+  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));

+  LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) inp));

+

+  /* Now calculate and check the checksum */

+  igmp = (struct igmp_msg *)p->payload;

+  if (inet_chksum(igmp, p->len)) {

+    pbuf_free(p);

+    IGMP_STATS_INC(igmp.chkerr);

+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));

+    return;

+  }

+

+  /* Packet is ok so find an existing group */

+  group = igmp_lookfor_group(inp, dest); /* use the incoming IP address! */

+  

+  /* If group can be found or create... */

+  if (!group) {

+    pbuf_free(p);

+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));

+    return;

+  }

+

+  /* NOW ACT ON THE INCOMING MESSAGE TYPE... */

+  switch (igmp->igmp_msgtype) {

+   case IGMP_MEMB_QUERY: {

+     /* IGMP_MEMB_QUERY to the "all systems" address ? */

+     if ((ip_addr_cmp(dest, &allsystems)) && (igmp->igmp_group_address.addr == 0)) {

+       /* THIS IS THE GENERAL QUERY */

+       LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));

+

+       if (igmp->igmp_maxresp == 0) {

+         IGMP_STATS_INC(igmp.v1_rxed);

+         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));

+         igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;

+       }

+

+       IGMP_STATS_INC(igmp.group_query_rxed);

+       groupref = igmp_group_list;

+       while (groupref) {

+         /* Do not send messages on the all systems group address! */

+         if ((groupref->interface == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {

+           igmp_delaying_member( groupref, igmp->igmp_maxresp);

+         }

+         groupref = groupref->next;

+       }

+     } else {

+       /* IGMP_MEMB_QUERY to a specific group ? */

+       if (group->group_address.addr != 0) {

+         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));

+         ip_addr_debug_print(IGMP_DEBUG, &group->group_address);

+         if (ip_addr_cmp (dest, &allsystems)) {

+           LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));

+           /* we first need to re-lookfor the group since we used dest last time */

+           group = igmp_lookfor_group(inp, &igmp->igmp_group_address);

+         } else {

+           LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));

+         }

+

+         if (group != NULL) {

+           IGMP_STATS_INC(igmp.unicast_query);

+           igmp_delaying_member( group, igmp->igmp_maxresp);

+         }

+       }

+     }

+     break;

+   }

+   case IGMP_V2_MEMB_REPORT: {

+     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));

+

+     IGMP_STATS_INC(igmp.report_rxed);

+     if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {

+       /* This is on a specific group we have already looked up */

+       group->timer = 0; /* stopped */

+       group->group_state = IGMP_GROUP_IDLE_MEMBER;

+       group->last_reporter_flag = 0;

+     }

+     break;

+   }

+   default: {

+     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %x in state %x on group %x on if %x\n", (int) igmp->igmp_msgtype, (int) group->group_state, (int) &group, (int) group->interface));

+     break;

+   }

+  }

+

+  pbuf_free(p);

+  return;

+}

+

+/**

+ * Join a group on one network interface.

+ *

+ * @param ifaddr ip address of the network interface which should join a new group

+ * @param groupaddr the ip address of the group which to join

+ * @return ERR_OK if group was joined on the netif(s), an err_t otherwise

+ */

+err_t

+igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)

+{

+  err_t              err = ERR_VAL; /* no matching interface */

+  struct igmp_group *group;

+  struct netif      *netif;

+

+  /* make sure it is multicast address */

+  LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);

+  LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);

+

+  /* loop through netif's */

+  netif = netif_list;

+  while (netif != NULL) {

+    /* Should we join this interface ? */

+    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {

+      /* find group or create a new one if not found */

+      group = igmp_lookup_group(netif, groupaddr);

+

+      if (group != NULL) {

+        /* This should create a new group, check the state to make sure */

+        if (group->group_state != IGMP_GROUP_NON_MEMBER) {

+          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));

+        } else {

+          /* OK - it was new group */

+          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));

+          ip_addr_debug_print(IGMP_DEBUG, groupaddr);

+          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));

+

+          /* If first use of the group, allow the group at the MAC level */

+          if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {

+            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));

+            ip_addr_debug_print(IGMP_DEBUG, groupaddr);

+            LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));

+            netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);

+          }

+

+          IGMP_STATS_INC(igmp.join_sent);

+          igmp_send(group, IGMP_V2_MEMB_REPORT);

+

+          igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);

+

+          /* Need to work out where this timer comes from */

+          group->group_state = IGMP_GROUP_DELAYING_MEMBER;

+        }

+        /* Increment group use */

+        group->use++;

+        /* Join on this interface */

+        err = ERR_OK;

+      } else {

+        /* Return an error even if some network interfaces are joined */

+        /** @todo undo any other netif already joined */

+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));

+        return ERR_MEM;

+      }

+    }

+    /* proceed to next network interface */

+    netif = netif->next;

+  }

+

+  return err;

+}

+

+/**

+ * Leave a group on one network interface.

+ *

+ * @param ifaddr ip address of the network interface which should leave a group

+ * @param groupaddr the ip address of the group which to leave

+ * @return ERR_OK if group was left on the netif(s), an err_t otherwise

+ */

+err_t

+igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)

+{

+  err_t              err = ERR_VAL; /* no matching interface */

+  struct igmp_group *group;

+  struct netif      *netif;

+

+  /* make sure it is multicast address */

+  LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);

+  LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);

+

+  /* loop through netif's */

+  netif = netif_list;

+  while (netif != NULL) {

+    /* Should we leave this interface ? */

+    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {

+      /* find group */

+      group = igmp_lookfor_group(netif, groupaddr);

+

+      if (group != NULL) {

+        /* Only send a leave if the flag is set according to the state diagram */

+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));

+        ip_addr_debug_print(IGMP_DEBUG, groupaddr);

+        LWIP_DEBUGF(IGMP_DEBUG, ("\n"));

+

+        /* If there is no other use of the group */

+        if (group->use <= 1) {

+          /* If we are the last reporter for this group */

+          if (group->last_reporter_flag) {

+            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));

+            IGMP_STATS_INC(igmp.leave_sent);

+            igmp_send(group, IGMP_LEAVE_GROUP);

+          }

+          

+          /* Disable the group at the MAC level */

+          if (netif->igmp_mac_filter != NULL) {

+            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));

+            ip_addr_debug_print(IGMP_DEBUG, groupaddr);

+            LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));

+            netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);

+          }

+          

+          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));

+          ip_addr_debug_print(IGMP_DEBUG, groupaddr);

+          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));          

+          

+          /* Free the group */

+          igmp_remove_group(group);

+        } else {

+          /* Decrement group use */

+          group->use--;

+        }

+        /* Leave on this interface */

+        err = ERR_OK;

+      } else {

+        /* It's not a fatal error on "leavegroup" */

+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));

+      }

+    }

+    /* proceed to next network interface */

+    netif = netif->next;

+  }

+

+  return err;

+}

+

+/**

+ * The igmp timer function (both for NO_SYS=1 and =0)

+ * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default).

+ */

+void

+igmp_tmr(void)

+{

+  struct igmp_group *group = igmp_group_list;

+

+  while (group != NULL) {

+    if (group->timer != 0) {

+      group->timer -= 1;

+      if (group->timer == 0) {

+        igmp_timeout(group);

+      }

+    }

+    group = group->next;

+  }

+}

+

+/**

+ * Called if a timeout for one group is reached.

+ * Sends a report for this group.

+ *

+ * @param group an igmp_group for which a timeout is reached

+ */

+void

+igmp_timeout(struct igmp_group *group)

+{

+  /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */

+  if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {

+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));

+    ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));

+    LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) group->interface));

+

+    igmp_send(group, IGMP_V2_MEMB_REPORT);

+  }

+}

+

+/**

+ * Start a timer for an igmp group

+ *

+ * @param group the igmp_group for which to start a timer

+ * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with

+ *        every call to igmp_tmr())

+ */

+void

+igmp_start_timer(struct igmp_group *group, u8_t max_time)

+{

+  /**

+   * @todo Important !! this should be random 0 -> max_time. Find out how to do this

+   */

+  group->timer = max_time;

+}

+

+/**

+ * Stop a timer for an igmp_group

+ *

+ * @param group the igmp_group for which to stop the timer

+ */

+void

+igmp_stop_timer(struct igmp_group *group)

+{

+  group->timer = 0;

+}

+

+/**

+ * Delaying membership report for a group if necessary

+ *

+ * @param group the igmp_group for which "delaying" membership report

+ * @param maxresp query delay

+ */

+void

+igmp_delaying_member( struct igmp_group *group, u8_t maxresp)

+{

+  if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) {

+    igmp_start_timer(group, (maxresp)/2);

+    group->group_state = IGMP_GROUP_DELAYING_MEMBER;

+  }

+}

+

+

+/**

+ * Sends an IP packet on a network interface. This function constructs the IP header

+ * and calculates the IP header checksum. If the source IP address is NULL,

+ * the IP address of the outgoing network interface is filled in as source address.

+ *

+ * @param p the packet to send (p->payload points to the data, e.g. next

+            protocol header; if dest == IP_HDRINCL, p already includes an IP

+            header and p->payload points to that IP header)

+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the

+ *         IP  address of the netif used to send is used as source address)

+ * @param dest the destination IP address to send the packet to

+ * @param ttl the TTL value to be set in the IP header

+ * @param proto the PROTOCOL to be set in the IP header

+ * @param netif the netif on which to send this packet

+ * @return ERR_OK if the packet was sent OK

+ *         ERR_BUF if p doesn't have enough space for IP/LINK headers

+ *         returns errors returned by netif->output

+ */

+err_t

+igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,

+                  u8_t ttl, u8_t proto, struct netif *netif)

+{

+  static u16_t    ip_id = 0;

+  struct ip_hdr * iphdr = NULL;

+  u16_t *         ra    = NULL;

+

+  /* First write in the "router alert" */

+  if (pbuf_header(p, ROUTER_ALERTLEN)) {

+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n"));

+    return ERR_BUF;

+  }

+

+  /* This is the "router alert" option */

+  ra    = p->payload;

+  ra[0] = htons (ROUTER_ALERT);

+  ra[1] = 0x0000; /* Router shall examine packet */

+

+  /* now the normal ip header */

+  if (pbuf_header(p, IP_HLEN)) {

+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n"));

+    return ERR_BUF;

+  }

+

+  iphdr = p->payload;

+

+  /* Should the IP header be generated or is it already included in p? */

+  if (dest != IP_HDRINCL) {

+    /** @todo should be shared with ip.c - ip_output_if */

+    IPH_TTL_SET(iphdr, ttl);

+    IPH_PROTO_SET(iphdr, proto);

+

+    ip_addr_set(&(iphdr->dest), dest);

+

+    IPH_VHLTOS_SET(iphdr, 4, ((IP_HLEN + ROUTER_ALERTLEN) / 4), 0/*tos*/);

+    IPH_LEN_SET(iphdr, htons(p->tot_len));

+    IPH_OFFSET_SET(iphdr, 0);

+    IPH_ID_SET(iphdr, htons(ip_id));

+    ++ip_id;

+

+    if (ip_addr_isany(src)) {

+      ip_addr_set(&(iphdr->src), &(netif->ip_addr));

+    } else {

+      ip_addr_set(&(iphdr->src), src);

+    }

+

+    IPH_CHKSUM_SET(iphdr, 0);

+#if CHECKSUM_GEN_IP

+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, (IP_HLEN + ROUTER_ALERTLEN)));

+#endif

+  } else {

+    dest = &(iphdr->dest);

+  }

+

+#if IP_DEBUG

+  ip_debug_print(p);

+#endif

+

+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: sending to if %x\n", (int) netif));

+

+  return netif->output(netif, p, dest);

+}

+

+/**

+ * Send an igmp packet to a specific group.

+ *

+ * @param group the group to which to send the packet

+ * @param type the type of igmp packet to send

+ */

+void

+igmp_send(struct igmp_group *group, u8_t type)

+{

+  struct pbuf*     p    = NULL;

+  struct igmp_msg* igmp = NULL;

+  struct ip_addr   src  = {0};

+  struct ip_addr*  dest = NULL;

+

+  /* IP header + "router alert" option + IGMP header */

+  p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);

+  

+  if (p) {

+    igmp = p->payload;

+    LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",

+               (p->len >= sizeof(struct igmp_msg)));

+    ip_addr_set(&src, &((group->interface)->ip_addr));

+     

+    if (type == IGMP_V2_MEMB_REPORT) {

+      dest = &(group->group_address);

+      IGMP_STATS_INC(igmp.report_sent);

+      ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));

+      group->last_reporter_flag = 1; /* Remember we were the last to report */

+    } else {

+      if (type == IGMP_LEAVE_GROUP) {

+        dest = &allrouters;

+        ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));

+      }

+    }

+

+    if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {

+      igmp->igmp_msgtype  = type;

+      igmp->igmp_maxresp  = 0;

+      igmp->igmp_checksum = 0;

+      igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN);

+

+      igmp_ip_output_if( p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface);

+    }

+

+    pbuf_free (p);

+  } else {

+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));

+  }

+}

+

+#endif /* LWIP_IGMP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/inet.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/inet.c
new file mode 100644
index 0000000..cded5ef
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/inet.c
@@ -0,0 +1,278 @@
+/**

+ * @file

+ * Functions common to all TCP/IPv4 modules, such as the byte order functions.

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#include "lwip/inet.h"

+

+/* Here for now until needed in other places in lwIP */

+#ifndef isprint

+#define in_range(c, lo, up)  ((u8_t)c >= lo && (u8_t)c <= up)

+#define isprint(c)           in_range(c, 0x20, 0x7f)

+#define isdigit(c)           in_range(c, '0', '9')

+#define isxdigit(c)          (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))

+#define islower(c)           in_range(c, 'a', 'z')

+#define isspace(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')

+#endif

+

+/**

+ * Ascii internet address interpretation routine.

+ * The value returned is in network order.

+ *

+ * @param cp IP address in ascii represenation (e.g. "127.0.0.1")

+ * @return ip address in network order

+ */

+u32_t

+inet_addr(const char *cp)

+{

+  struct in_addr val;

+

+  if (inet_aton(cp, &val)) {

+    return (val.s_addr);

+  }

+  return (INADDR_NONE);

+}

+

+/**

+ * Check whether "cp" is a valid ascii representation

+ * of an Internet address and convert to a binary address.

+ * Returns 1 if the address is valid, 0 if not.

+ * This replaces inet_addr, the return value from which

+ * cannot distinguish between failure and a local broadcast address.

+ *

+ * @param cp IP address in ascii represenation (e.g. "127.0.0.1")

+ * @param addr pointer to which to save the ip address in network order

+ * @return 1 if cp could be converted to addr, 0 on failure

+ */

+int

+inet_aton(const char *cp, struct in_addr *addr)

+{

+  u32_t val;

+  int base, n, c;

+  u32_t parts[4];

+  u32_t *pp = parts;

+

+  c = *cp;

+  for (;;) {

+    /*

+     * Collect number up to ``.''.

+     * Values are specified as for C:

+     * 0x=hex, 0=octal, 1-9=decimal.

+     */

+    if (!isdigit(c))

+      return (0);

+    val = 0;

+    base = 10;

+    if (c == '0') {

+      c = *++cp;

+      if (c == 'x' || c == 'X') {

+        base = 16;

+        c = *++cp;

+      } else

+        base = 8;

+    }

+    for (;;) {

+      if (isdigit(c)) {

+        val = (val * base) + (int)(c - '0');

+        c = *++cp;

+      } else if (base == 16 && isxdigit(c)) {

+        val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));

+        c = *++cp;

+      } else

+        break;

+    }

+    if (c == '.') {

+      /*

+       * Internet format:

+       *  a.b.c.d

+       *  a.b.c   (with c treated as 16 bits)

+       *  a.b (with b treated as 24 bits)

+       */

+      if (pp >= parts + 3)

+        return (0);

+      *pp++ = val;

+      c = *++cp;

+    } else

+      break;

+  }

+  /*

+   * Check for trailing characters.

+   */

+  if (c != '\0' && (!isprint(c) || !isspace(c)))

+    return (0);

+  /*

+   * Concoct the address according to

+   * the number of parts specified.

+   */

+  n = pp - parts + 1;

+  switch (n) {

+

+  case 0:

+    return (0);       /* initial nondigit */

+

+  case 1:             /* a -- 32 bits */

+    break;

+

+  case 2:             /* a.b -- 8.24 bits */

+    if (val > 0xffffffUL)

+      return (0);

+    val |= parts[0] << 24;

+    break;

+

+  case 3:             /* a.b.c -- 8.8.16 bits */

+    if (val > 0xffff)

+      return (0);

+    val |= (parts[0] << 24) | (parts[1] << 16);

+    break;

+

+  case 4:             /* a.b.c.d -- 8.8.8.8 bits */

+    if (val > 0xff)

+      return (0);

+    val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);

+    break;

+  }

+  if (addr)

+    addr->s_addr = htonl(val);

+  return (1);

+}

+

+/**

+ * Convert numeric IP address into decimal dotted ASCII representation.

+ * returns ptr to static buffer; not reentrant!

+ *

+ * @param addr ip address in network order to convert

+ * @return pointer to a global static (!) buffer that holds the ASCII

+ *         represenation of addr

+ */

+char *

+inet_ntoa(struct in_addr addr)

+{

+  static char str[16];

+  u32_t s_addr = addr.s_addr;

+  char inv[3];

+  char *rp;

+  u8_t *ap;

+  u8_t rem;

+  u8_t n;

+  u8_t i;

+

+  rp = str;

+  ap = (u8_t *)&s_addr;

+  for(n = 0; n < 4; n++) {

+    i = 0;

+    do {

+      rem = *ap % (u8_t)10;

+      *ap /= (u8_t)10;

+      inv[i++] = '0' + rem;

+    } while(*ap);

+    while(i--)

+      *rp++ = inv[i];

+    *rp++ = '.';

+    ap++;

+  }

+  *--rp = 0;

+  return str;

+}

+

+/**

+ * These are reference implementations of the byte swapping functions.

+ * Again with the aim of being simple, correct and fully portable.

+ * Byte swapping is the second thing you would want to optimize. You will

+ * need to port it to your architecture and in your cc.h:

+ *

+ * #define LWIP_PLATFORM_BYTESWAP 1

+ * #define LWIP_PLATFORM_HTONS(x) <your_htons>

+ * #define LWIP_PLATFORM_HTONL(x) <your_htonl>

+ *

+ * Note ntohs() and ntohl() are merely references to the htonx counterparts.

+ */

+

+#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)

+

+/**

+ * Convert an u16_t from host- to network byte order.

+ *

+ * @param n u16_t in host byte order

+ * @return n in network byte order

+ */

+u16_t

+htons(u16_t n)

+{

+  return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);

+}

+

+/**

+ * Convert an u16_t from network- to host byte order.

+ *

+ * @param n u16_t in network byte order

+ * @return n in host byte order

+ */

+u16_t

+ntohs(u16_t n)

+{

+  return htons(n);

+}

+

+/**

+ * Convert an u32_t from host- to network byte order.

+ *

+ * @param n u32_t in host byte order

+ * @return n in network byte order

+ */

+u32_t

+htonl(u32_t n)

+{

+  return ((n & 0xff) << 24) |

+    ((n & 0xff00) << 8) |

+    ((n & 0xff0000UL) >> 8) |

+    ((n & 0xff000000UL) >> 24);

+}

+

+/**

+ * Convert an u32_t from network- to host byte order.

+ *

+ * @param n u32_t in network byte order

+ * @return n in host byte order

+ */

+u32_t

+ntohl(u32_t n)

+{

+  return htonl(n);

+}

+

+#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/inet_chksum.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/inet_chksum.c
new file mode 100644
index 0000000..095bef6
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/inet_chksum.c
@@ -0,0 +1,423 @@
+/**

+ * @file

+ * Incluse internet checksum functions.

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#include "lwip/inet_chksum.h"

+#include "lwip/inet.h"

+

+#include <string.h>

+

+/* These are some reference implementations of the checksum algorithm, with the

+ * aim of being simple, correct and fully portable. Checksumming is the

+ * first thing you would want to optimize for your platform. If you create

+ * your own version, link it in and in your cc.h put:

+ *

+ * #define LWIP_CHKSUM <your_checksum_routine>

+ *

+ * Or you can select from the implementations below by defining

+ * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.

+ */

+

+#ifndef LWIP_CHKSUM

+# define LWIP_CHKSUM lwip_standard_chksum

+# ifndef LWIP_CHKSUM_ALGORITHM

+#  define LWIP_CHKSUM_ALGORITHM 1

+# endif

+#endif

+/* If none set: */

+#ifndef LWIP_CHKSUM_ALGORITHM

+# define LWIP_CHKSUM_ALGORITHM 0

+#endif

+

+#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */

+/**

+ * lwip checksum

+ *

+ * @param dataptr points to start of data to be summed at any boundary

+ * @param len length of data to be summed

+ * @return host order (!) lwip checksum (non-inverted Internet sum)

+ *

+ * @note accumulator size limits summable length to 64k

+ * @note host endianess is irrelevant (p3 RFC1071)

+ */

+static u16_t

+lwip_standard_chksum(void *dataptr, u16_t len)

+{

+  u32_t acc;

+  u16_t src;

+  u8_t *octetptr;

+

+  acc = 0;

+  /* dataptr may be at odd or even addresses */

+  octetptr = (u8_t*)dataptr;

+  while (len > 1)

+  {

+    /* declare first octet as most significant

+       thus assume network order, ignoring host order */

+    src = (*octetptr) << 8;

+    octetptr++;

+    /* declare second octet as least significant */

+    src |= (*octetptr);

+    octetptr++;

+    acc += src;

+    len -= 2;

+  }

+  if (len > 0)

+  {

+    /* accumulate remaining octet */

+    src = (*octetptr) << 8;

+    acc += src;

+  }

+  /* add deferred carry bits */

+  acc = (acc >> 16) + (acc & 0x0000ffffUL);

+  if ((acc & 0xffff0000) != 0) {

+    acc = (acc >> 16) + (acc & 0x0000ffffUL);

+  }

+  /* This maybe a little confusing: reorder sum using htons()

+     instead of ntohs() since it has a little less call overhead.

+     The caller must invert bits for Internet sum ! */

+  return htons((u16_t)acc);

+}

+#endif

+

+#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */

+/*

+ * Curt McDowell

+ * Broadcom Corp.

+ * csm@broadcom.com

+ *

+ * IP checksum two bytes at a time with support for

+ * unaligned buffer.

+ * Works for len up to and including 0x20000.

+ * by Curt McDowell, Broadcom Corp. 12/08/2005

+ *

+ * @param dataptr points to start of data to be summed at any boundary

+ * @param len length of data to be summed

+ * @return host order (!) lwip checksum (non-inverted Internet sum)

+ */

+

+static u16_t

+lwip_standard_chksum(void *dataptr, int len)

+{

+  u8_t *pb = dataptr;

+  u16_t *ps, t = 0;

+  u32_t sum = 0;

+  int odd = ((u32_t)pb & 1);

+

+  /* Get aligned to u16_t */

+  if (odd && len > 0) {

+    ((u8_t *)&t)[1] = *pb++;

+    len--;

+  }

+

+  /* Add the bulk of the data */

+  ps = (u16_t *)pb;

+  while (len > 1) {

+    sum += *ps++;

+    len -= 2;

+  }

+

+  /* Consume left-over byte, if any */

+  if (len > 0)

+    ((u8_t *)&t)[0] = *(u8_t *)ps;;

+

+  /* Add end bytes */

+  sum += t;

+

+  /*  Fold 32-bit sum to 16 bits */

+  while ((sum >> 16) != 0)

+    sum = (sum & 0xffff) + (sum >> 16);

+

+  /* Swap if alignment was odd */

+  if (odd)

+    sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);

+

+  return sum;

+}

+#endif

+

+#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */

+/**

+ * An optimized checksum routine. Basically, it uses loop-unrolling on

+ * the checksum loop, treating the head and tail bytes specially, whereas

+ * the inner loop acts on 8 bytes at a time.

+ *

+ * @arg start of buffer to be checksummed. May be an odd byte address.

+ * @len number of bytes in the buffer to be checksummed.

+ * @return host order (!) lwip checksum (non-inverted Internet sum)

+ *

+ * by Curt McDowell, Broadcom Corp. December 8th, 2005

+ */

+

+static u16_t

+lwip_standard_chksum(void *dataptr, int len)

+{

+  u8_t *pb = dataptr;

+  u16_t *ps, t = 0;

+  u32_t *pl;

+  u32_t sum = 0, tmp;

+  /* starts at odd byte address? */

+  int odd = ((u32_t)pb & 1);

+

+  if (odd && len > 0) {

+    ((u8_t *)&t)[1] = *pb++;

+    len--;

+  }

+

+  ps = (u16_t *)pb;

+

+  if (((u32_t)ps & 3) && len > 1) {

+    sum += *ps++;

+    len -= 2;

+  }

+

+  pl = (u32_t *)ps;

+

+  while (len > 7)  {

+    tmp = sum + *pl++;          /* ping */

+    if (tmp < sum)

+      tmp++;                    /* add back carry */

+

+    sum = tmp + *pl++;          /* pong */

+    if (sum < tmp)

+      sum++;                    /* add back carry */

+

+    len -= 8;

+  }

+

+  /* make room in upper bits */

+  sum = (sum >> 16) + (sum & 0xffff);

+

+  ps = (u16_t *)pl;

+

+  /* 16-bit aligned word remaining? */

+  while (len > 1) {

+    sum += *ps++;

+    len -= 2;

+  }

+

+  /* dangling tail byte remaining? */

+  if (len > 0)                  /* include odd byte */

+    ((u8_t *)&t)[0] = *(u8_t *)ps;

+

+  sum += t;                     /* add end bytes */

+

+  while ((sum >> 16) != 0)      /* combine halves */

+    sum = (sum >> 16) + (sum & 0xffff);

+

+  if (odd)

+    sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);

+

+  return sum;

+}

+#endif

+

+/* inet_chksum_pseudo:

+ *

+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.

+ * IP addresses are expected to be in network byte order.

+ *

+ * @param p chain of pbufs over that a checksum should be calculated (ip data part)

+ * @param src source ip address (used for checksum of pseudo header)

+ * @param dst destination ip address (used for checksum of pseudo header)

+ * @param proto ip protocol (used for checksum of pseudo header)

+ * @param proto_len length of the ip data part (used for checksum of pseudo header)

+ * @return checksum (as u16_t) to be saved directly in the protocol header

+ */

+u16_t

+inet_chksum_pseudo(struct pbuf *p,

+       struct ip_addr *src, struct ip_addr *dest,

+       u8_t proto, u16_t proto_len)

+{

+  u32_t acc;

+  struct pbuf *q;

+  u8_t swapped;

+

+  acc = 0;

+  swapped = 0;

+  /* iterate through all pbuf in chain */

+  for(q = p; q != NULL; q = q->next) {

+    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",

+      (void *)q, (void *)q->next));

+    acc += LWIP_CHKSUM(q->payload, q->len);

+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/

+    while ((acc >> 16) != 0) {

+      acc = (acc & 0xffffUL) + (acc >> 16);

+    }

+    if (q->len % 2 != 0) {

+      swapped = 1 - swapped;

+      acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);

+    }

+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/

+  }

+

+  if (swapped) {

+    acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);

+  }

+  acc += (src->addr & 0xffffUL);

+  acc += ((src->addr >> 16) & 0xffffUL);

+  acc += (dest->addr & 0xffffUL);

+  acc += ((dest->addr >> 16) & 0xffffUL);

+  acc += (u32_t)htons((u16_t)proto);

+  acc += (u32_t)htons(proto_len);

+

+  while ((acc >> 16) != 0) {

+    acc = (acc & 0xffffUL) + (acc >> 16);

+  }

+  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));

+  return (u16_t)~(acc & 0xffffUL);

+}

+

+/* inet_chksum_pseudo:

+ *

+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.

+ * IP addresses are expected to be in network byte order.

+ *

+ * @param p chain of pbufs over that a checksum should be calculated (ip data part)

+ * @param src source ip address (used for checksum of pseudo header)

+ * @param dst destination ip address (used for checksum of pseudo header)

+ * @param proto ip protocol (used for checksum of pseudo header)

+ * @param proto_len length of the ip data part (used for checksum of pseudo header)

+ * @return checksum (as u16_t) to be saved directly in the protocol header

+ */

+u16_t

+inet_chksum_pseudo_partial(struct pbuf *p,

+       struct ip_addr *src, struct ip_addr *dest,

+       u8_t proto, u16_t proto_len, u16_t chksum_len)

+{

+  u32_t acc;

+  struct pbuf *q;

+  u8_t swapped;

+  u16_t chklen;

+

+  acc = 0;

+  swapped = 0;

+  /* iterate through all pbuf in chain */

+  for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {

+    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",

+      (void *)q, (void *)q->next));

+    chklen = q->len;

+    if (chklen > chksum_len) {

+      chklen = chksum_len;

+    }

+    acc += LWIP_CHKSUM(q->payload, chklen);

+    chksum_len -= chklen;

+    LWIP_ASSERT("delete me", chksum_len < 0x7fff);

+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/

+    while ((acc >> 16) != 0) {

+      acc = (acc & 0xffffUL) + (acc >> 16);

+    }

+    if (q->len % 2 != 0) {

+      swapped = 1 - swapped;

+      acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);

+    }

+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/

+  }

+

+  if (swapped) {

+    acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);

+  }

+  acc += (src->addr & 0xffffUL);

+  acc += ((src->addr >> 16) & 0xffffUL);

+  acc += (dest->addr & 0xffffUL);

+  acc += ((dest->addr >> 16) & 0xffffUL);

+  acc += (u32_t)htons((u16_t)proto);

+  acc += (u32_t)htons(proto_len);

+

+  while ((acc >> 16) != 0) {

+    acc = (acc & 0xffffUL) + (acc >> 16);

+  }

+  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));

+  return (u16_t)~(acc & 0xffffUL);

+}

+

+/* inet_chksum:

+ *

+ * Calculates the Internet checksum over a portion of memory. Used primarily for IP

+ * and ICMP.

+ *

+ * @param dataptr start of the buffer to calculate the checksum (no alignment needed)

+ * @param len length of the buffer to calculate the checksum

+ * @return checksum (as u16_t) to be saved directly in the protocol header

+ */

+

+u16_t

+inet_chksum(void *dataptr, u16_t len)

+{

+  u32_t acc;

+

+  acc = LWIP_CHKSUM(dataptr, len);

+  while ((acc >> 16) != 0) {

+    acc = (acc & 0xffff) + (acc >> 16);

+  }

+  return (u16_t)~(acc & 0xffff);

+}

+

+/**

+ * Calculate a checksum over a chain of pbufs (without pseudo-header, much like

+ * inet_chksum only pbufs are used).

+ *

+ * @param p pbuf chain over that the checksum should be calculated

+ * @return checksum (as u16_t) to be saved directly in the protocol header

+ */

+u16_t

+inet_chksum_pbuf(struct pbuf *p)

+{

+  u32_t acc;

+  struct pbuf *q;

+  u8_t swapped;

+

+  acc = 0;

+  swapped = 0;

+  for(q = p; q != NULL; q = q->next) {

+    acc += LWIP_CHKSUM(q->payload, q->len);

+    while ((acc >> 16) != 0) {

+      acc = (acc & 0xffffUL) + (acc >> 16);

+    }

+    if (q->len % 2 != 0) {

+      swapped = 1 - swapped;

+      acc = (acc & 0x00ffUL << 8) | (acc & 0xff00UL >> 8);

+    }

+  }

+

+  if (swapped) {

+    acc = ((acc & 0x00ffUL) << 8) | ((acc & 0xff00UL) >> 8);

+  }

+  return (u16_t)~(acc & 0xffffUL);

+}

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip.c
new file mode 100644
index 0000000..11da757
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip.c
@@ -0,0 +1,614 @@
+/**

+ * @file

+ * This is the IPv4 layer implementation for incoming and outgoing IP traffic.

+ *

+ * @see ip_frag.c

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+#include "lwip/ip.h"

+#include "lwip/def.h"

+#include "lwip/mem.h"

+#include "lwip/ip_frag.h"

+#include "lwip/inet.h"

+#include "lwip/inet_chksum.h"

+#include "lwip/netif.h"

+#include "lwip/icmp.h"

+#include "lwip/igmp.h"

+#include "lwip/raw.h"

+#include "lwip/udp.h"

+#include "lwip/tcp.h"

+#include "lwip/snmp.h"

+#include "lwip/dhcp.h"

+#include "lwip/stats.h"

+#include "arch/perf.h"

+

+/**

+ * Finds the appropriate network interface for a given IP address. It

+ * searches the list of network interfaces linearly. A match is found

+ * if the masked IP address of the network interface equals the masked

+ * IP address given to the function.

+ *

+ * @param dest the destination IP address for which to find the route

+ * @return the netif on which to send to reach dest

+ */

+struct netif *

+ip_route(struct ip_addr *dest)

+{

+  struct netif *netif;

+

+  /* iterate through netifs */

+  for(netif = netif_list; netif != NULL; netif = netif->next) {

+    /* network mask matches? */

+    if (netif_is_up(netif)) {

+      if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {

+        /* return netif on which to forward IP packet */

+        return netif;

+      }

+    }

+  }

+  if ((netif_default == NULL) || (!netif_is_up(netif_default))) {

+    LWIP_DEBUGF(IP_DEBUG | 2, ("ip_route: No route to 0x%"X32_F"\n", dest->addr));

+    IP_STATS_INC(ip.rterr);

+    snmp_inc_ipoutnoroutes();

+    return NULL;

+  }

+  /* no matching netif found, use default netif */

+  return netif_default;

+}

+

+#if IP_FORWARD

+/**

+ * Forwards an IP packet. It finds an appropriate route for the

+ * packet, decrements the TTL value of the packet, adjusts the

+ * checksum and outputs the packet on the appropriate interface.

+ *

+ * @param p the packet to forward (p->payload points to IP header)

+ * @param iphdr the IP header of the input packet

+ * @param inp the netif on which this packet was received

+ * @return the netif on which the packet was sent (NULL if it wasn't sent)

+ */

+static struct netif *

+ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)

+{

+  struct netif *netif;

+

+  PERF_START;

+  /* Find network interface where to forward this IP packet to. */

+  netif = ip_route((struct ip_addr *)&(iphdr->dest));

+  if (netif == NULL) {

+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n",

+                      iphdr->dest.addr));

+    snmp_inc_ipoutnoroutes();

+    return (struct netif *)NULL;

+  }

+  /* Do not forward packets onto the same network interface on which

+   * they arrived. */

+  if (netif == inp) {

+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));

+    snmp_inc_ipoutnoroutes();

+    return (struct netif *)NULL;

+  }

+

+  /* decrement TTL */

+  IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);

+  /* send ICMP if TTL == 0 */

+  if (IPH_TTL(iphdr) == 0) {

+    snmp_inc_ipinhdrerrors();

+#if LWIP_ICMP

+    /* Don't send ICMP messages in response to ICMP messages */

+    if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {

+      icmp_time_exceeded(p, ICMP_TE_TTL);

+    }

+#endif /* LWIP_ICMP */

+    return (struct netif *)NULL;

+  }

+

+  /* Incrementally update the IP checksum. */

+  if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) {

+    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1);

+  } else {

+    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100));

+  }

+

+  LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n",

+                    iphdr->dest.addr));

+

+  IP_STATS_INC(ip.fw);

+  IP_STATS_INC(ip.xmit);

+  snmp_inc_ipforwdatagrams();

+

+  PERF_STOP("ip_forward");

+  /* transmit pbuf on chosen interface */

+  netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));

+  return netif;

+}

+#endif /* IP_FORWARD */

+

+/**

+ * This function is called by the network interface device driver when

+ * an IP packet is received. The function does the basic checks of the

+ * IP header such as packet size being at least larger than the header

+ * size etc. If the packet was not destined for us, the packet is

+ * forwarded (using ip_forward). The IP checksum is always checked.

+ *

+ * Finally, the packet is sent to the upper layer protocol input function.

+ *

+ * @param p the received IP packet (p->payload points to IP header)

+ * @param inp the netif on which this packet was received

+ * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't

+ *         processed, but currently always returns ERR_OK)

+ */

+err_t

+ip_input(struct pbuf *p, struct netif *inp)

+{

+  struct ip_hdr *iphdr;

+  struct netif *netif;

+  u16_t iphdr_hlen;

+  u16_t iphdr_len;

+#if LWIP_DHCP

+  int check_ip_src=1;

+#endif /* LWIP_DHCP */

+

+  IP_STATS_INC(ip.recv);

+  snmp_inc_ipinreceives();

+

+  /* identify the IP header */

+  iphdr = p->payload;

+  if (IPH_V(iphdr) != 4) {

+    LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));

+    ip_debug_print(p);

+    pbuf_free(p);

+    IP_STATS_INC(ip.err);

+    IP_STATS_INC(ip.drop);

+    snmp_inc_ipinhdrerrors();

+    return ERR_OK;

+  }

+

+  /* obtain IP header length in number of 32-bit words */

+  iphdr_hlen = IPH_HL(iphdr);

+  /* calculate IP header length in bytes */

+  iphdr_hlen *= 4;

+  /* obtain ip length in bytes */

+  iphdr_len = ntohs(IPH_LEN(iphdr));

+

+  /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */

+  if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {

+    if (iphdr_hlen > p->len)

+    LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",

+                               iphdr_hlen, p->len));

+    if (iphdr_len > p->tot_len)

+    LWIP_DEBUGF(IP_DEBUG | 2, ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), "

+                               "IP packet dropped.\n",

+                               iphdr_len, p->tot_len));

+    /* free (drop) packet pbufs */

+    pbuf_free(p);

+    IP_STATS_INC(ip.lenerr);

+    IP_STATS_INC(ip.drop);

+    snmp_inc_ipindiscards();

+    return ERR_OK;

+  }

+

+  /* verify checksum */

+#if CHECKSUM_CHECK_IP

+  if (inet_chksum(iphdr, iphdr_hlen) != 0) {

+

+    LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));

+    ip_debug_print(p);

+    pbuf_free(p);

+    IP_STATS_INC(ip.chkerr);

+    IP_STATS_INC(ip.drop);

+    snmp_inc_ipinhdrerrors();

+    return ERR_OK;

+  }

+#endif

+

+  /* Trim pbuf. This should have been done at the netif layer,

+   * but we'll do it anyway just to be sure that its done. */

+  pbuf_realloc(p, iphdr_len);

+

+  /* match packet against an interface, i.e. is this packet for us? */

+#if LWIP_IGMP

+  if (ip_addr_ismulticast(&(iphdr->dest))) {

+    if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) {

+      netif = inp;

+    } else {

+      netif = NULL;

+    }

+  } else

+#endif /* LWIP_IGMP */

+  {

+    /* start trying with inp. if that's not acceptable, start walking the

+       list of configured netifs.

+       'first' is used as a boolean to mark whether we started walking the list */

+    int first = 1;

+    netif = inp;

+    do {

+      LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",

+          iphdr->dest.addr, netif->ip_addr.addr,

+          iphdr->dest.addr & netif->netmask.addr,

+          netif->ip_addr.addr & netif->netmask.addr,

+          iphdr->dest.addr & ~(netif->netmask.addr)));

+

+      /* interface is up and configured? */

+      if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {

+        /* unicast to this interface address? */

+        if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||

+            /* or broadcast on this interface network address? */

+            ip_addr_isbroadcast(&(iphdr->dest), netif)) {

+          LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",

+              netif->name[0], netif->name[1]));

+          /* break out of for loop */

+          break;

+        }

+      }

+      if (first) {

+        first = 0;

+        netif = netif_list;

+      } else {

+        netif = netif->next;

+      }

+      if (netif == inp) {

+        netif = netif->next;

+      }

+    } while(netif != NULL);

+  }

+

+#if LWIP_DHCP

+  /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed

+   * using link layer addressing (such as Ethernet MAC) so we must not filter on IP.

+   * According to RFC 1542 section 3.1.1, referred by RFC 2131).

+   */

+  if (netif == NULL) {

+    /* remote port is DHCP server? */

+    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {

+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",

+        ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest)));

+      if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) {

+        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));

+        netif = inp;

+        check_ip_src = 0;

+      }

+    }

+  }

+#endif /* LWIP_DHCP */

+

+  /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */

+#if LWIP_DHCP

+  if (check_ip_src)

+#endif /* LWIP_DHCP */

+  {  if ((ip_addr_isbroadcast(&(iphdr->src), inp)) ||

+         (ip_addr_ismulticast(&(iphdr->src)))) {

+      /* packet source is not valid */

+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet source is not valid.\n"));

+      /* free (drop) packet pbufs */

+      pbuf_free(p);

+      IP_STATS_INC(ip.drop);

+      snmp_inc_ipinaddrerrors();

+      snmp_inc_ipindiscards();

+      return ERR_OK;

+    }

+  }

+

+  /* packet not for us? */

+  if (netif == NULL) {

+    /* packet not for us, route or discard */

+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet not for us.\n"));

+#if IP_FORWARD

+    /* non-broadcast packet? */

+    if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {

+      /* try to forward IP packet on (other) interfaces */

+      ip_forward(p, iphdr, inp);

+    } else

+#endif /* IP_FORWARD */

+    {

+      snmp_inc_ipinaddrerrors();

+      snmp_inc_ipindiscards();

+    }

+    pbuf_free(p);

+    return ERR_OK;

+  }

+  /* packet consists of multiple fragments? */

+  if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {

+#if IP_REASSEMBLY /* packet fragment reassembly code present? */

+    LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",

+      ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));

+    /* reassemble the packet*/

+    p = ip_reass(p);

+    /* packet not fully reassembled yet? */

+    if (p == NULL) {

+      return ERR_OK;

+    }

+    iphdr = p->payload;

+#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */

+    pbuf_free(p);

+    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",

+      ntohs(IPH_OFFSET(iphdr))));

+    IP_STATS_INC(ip.opterr);

+    IP_STATS_INC(ip.drop);

+    /* unsupported protocol feature */

+    snmp_inc_ipinunknownprotos();

+    return ERR_OK;

+#endif /* IP_REASSEMBLY */

+  }

+

+#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */

+

+#if LWIP_IGMP

+  /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */

+  if((iphdr_hlen > IP_HLEN &&  (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {

+#else

+  if (iphdr_hlen > IP_HLEN) {

+#endif /* LWIP_IGMP */

+    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));

+    pbuf_free(p);

+    IP_STATS_INC(ip.opterr);

+    IP_STATS_INC(ip.drop);

+    /* unsupported protocol feature */

+    snmp_inc_ipinunknownprotos();

+    return ERR_OK;

+  }

+#endif /* IP_OPTIONS_ALLOWED == 0 */

+

+  /* send to upper layers */

+  LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));

+  ip_debug_print(p);

+  LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));

+

+#if LWIP_RAW

+  /* raw input did not eat the packet? */

+  if (raw_input(p, inp) == 0)

+#endif /* LWIP_RAW */

+  {

+

+    switch (IPH_PROTO(iphdr)) {

+#if LWIP_UDP

+    case IP_PROTO_UDP:

+#if LWIP_UDPLITE

+    case IP_PROTO_UDPLITE:

+#endif /* LWIP_UDPLITE */

+      snmp_inc_ipindelivers();

+      udp_input(p, inp);

+      break;

+#endif /* LWIP_UDP */

+#if LWIP_TCP

+    case IP_PROTO_TCP:

+      snmp_inc_ipindelivers();

+      tcp_input(p, inp);

+      break;

+#endif /* LWIP_TCP */

+#if LWIP_ICMP

+    case IP_PROTO_ICMP:

+      snmp_inc_ipindelivers();

+      icmp_input(p, inp);

+      break;

+#endif /* LWIP_ICMP */

+#if LWIP_IGMP

+    case IP_PROTO_IGMP:

+      igmp_input(p,inp,&(iphdr->dest));

+      break;

+#endif /* LWIP_IGMP */

+    default:

+#if LWIP_ICMP

+      /* send ICMP destination protocol unreachable unless is was a broadcast */

+      if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&

+          !ip_addr_ismulticast(&(iphdr->dest))) {

+        p->payload = iphdr;

+        icmp_dest_unreach(p, ICMP_DUR_PROTO);

+      }

+#endif /* LWIP_ICMP */

+      pbuf_free(p);

+

+      LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));

+

+      IP_STATS_INC(ip.proterr);

+      IP_STATS_INC(ip.drop);

+      snmp_inc_ipinunknownprotos();

+    }

+  }

+

+  return ERR_OK;

+}

+

+/**

+ * Sends an IP packet on a network interface. This function constructs

+ * the IP header and calculates the IP header checksum. If the source

+ * IP address is NULL, the IP address of the outgoing network

+ * interface is filled in as source address.

+ * If the destination IP address is IP_HDRINCL, p is assumed to already

+ * include an IP header and p->payload points to it instead of the data.

+ *

+ * @param p the packet to send (p->payload points to the data, e.g. next

+            protocol header; if dest == IP_HDRINCL, p already includes an IP

+            header and p->payload points to that IP header)

+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the

+ *         IP  address of the netif used to send is used as source address)

+ * @param dest the destination IP address to send the packet to

+ * @param ttl the TTL value to be set in the IP header

+ * @param tos the TOS value to be set in the IP header

+ * @param proto the PROTOCOL to be set in the IP header

+ * @param netif the netif on which to send this packet

+ * @return ERR_OK if the packet was sent OK

+ *         ERR_BUF if p doesn't have enough space for IP/LINK headers

+ *         returns errors returned by netif->output

+ *

+ * @note ip_id: RFC791 "some host may be able to simply use

+ *  unique identifiers independent of destination"

+ */

+err_t

+ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,

+             u8_t ttl, u8_t tos,

+             u8_t proto, struct netif *netif)

+{

+  struct ip_hdr *iphdr;

+  static u16_t ip_id = 0;

+

+  snmp_inc_ipoutrequests();

+

+  /* Should the IP header be generated or is it already included in p? */

+  if (dest != IP_HDRINCL) {

+    /* generate IP header */

+    if (pbuf_header(p, IP_HLEN)) {

+      LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));

+

+      IP_STATS_INC(ip.err);

+      snmp_inc_ipoutdiscards();

+      return ERR_BUF;

+    }

+

+    iphdr = p->payload;

+    LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",

+               (p->len >= sizeof(struct ip_hdr)));

+

+    IPH_TTL_SET(iphdr, ttl);

+    IPH_PROTO_SET(iphdr, proto);

+

+    ip_addr_set(&(iphdr->dest), dest);

+

+    IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos);

+    IPH_LEN_SET(iphdr, htons(p->tot_len));

+    IPH_OFFSET_SET(iphdr, 0);

+    IPH_ID_SET(iphdr, htons(ip_id));

+    ++ip_id;

+

+    if (ip_addr_isany(src)) {

+      ip_addr_set(&(iphdr->src), &(netif->ip_addr));

+    } else {

+      ip_addr_set(&(iphdr->src), src);

+    }

+

+    IPH_CHKSUM_SET(iphdr, 0);

+#if CHECKSUM_GEN_IP

+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));

+#endif

+  } else {

+    /* IP header already included in p */

+    iphdr = p->payload;

+    dest = &(iphdr->dest);

+  }

+

+#if IP_FRAG

+  /* don't fragment if interface has mtu set to 0 [loopif] */

+  if (netif->mtu && (p->tot_len > netif->mtu))

+    return ip_frag(p,netif,dest);

+#endif

+

+  IP_STATS_INC(ip.xmit);

+

+  LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));

+  ip_debug_print(p);

+

+  LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));

+

+  return netif->output(netif, p, dest);

+}

+

+/**

+ * Simple interface to ip_output_if. It finds the outgoing network

+ * interface and calls upon ip_output_if to do the actual work.

+ *

+ * @param p the packet to send (p->payload points to the data, e.g. next

+            protocol header; if dest == IP_HDRINCL, p already includes an IP

+            header and p->payload points to that IP header)

+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the

+ *         IP  address of the netif used to send is used as source address)

+ * @param dest the destination IP address to send the packet to

+ * @param ttl the TTL value to be set in the IP header

+ * @param tos the TOS value to be set in the IP header

+ * @param proto the PROTOCOL to be set in the IP header

+ *

+ * @return ERR_RTE if no route is found

+ *         see ip_output_if() for more return values

+ */

+err_t

+ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,

+          u8_t ttl, u8_t tos, u8_t proto)

+{

+  struct netif *netif;

+

+  if ((netif = ip_route(dest)) == NULL) {

+    return ERR_RTE;

+  }

+

+  return ip_output_if(p, src, dest, ttl, tos, proto, netif);

+}

+

+#if IP_DEBUG

+/* Print an IP header by using LWIP_DEBUGF

+ * @param p an IP packet, p->payload pointing to the IP header

+ */

+void

+ip_debug_print(struct pbuf *p)

+{

+  struct ip_hdr *iphdr = p->payload;

+  u8_t *payload;

+

+  payload = (u8_t *)iphdr + IP_HLEN;

+

+  LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));

+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" |  0x%02"X16_F" |     %5"U16_F"     | (v, hl, tos, len)\n",

+                    IPH_V(iphdr),

+                    IPH_HL(iphdr),

+                    IPH_TOS(iphdr),

+                    ntohs(IPH_LEN(iphdr))));

+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      |%"U16_F"%"U16_F"%"U16_F"|    %4"U16_F"   | (id, flags, offset)\n",

+                    ntohs(IPH_ID(iphdr)),

+                    ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,

+                    ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,

+                    ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,

+                    ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));

+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |    0x%04"X16_F"     | (ttl, proto, chksum)\n",

+                    IPH_TTL(iphdr),

+                    IPH_PROTO(iphdr),

+                    ntohs(IPH_CHKSUM(iphdr))));

+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (src)\n",

+                    ip4_addr1(&iphdr->src),

+                    ip4_addr2(&iphdr->src),

+                    ip4_addr3(&iphdr->src),

+                    ip4_addr4(&iphdr->src)));

+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (dest)\n",

+                    ip4_addr1(&iphdr->dest),

+                    ip4_addr2(&iphdr->dest),

+                    ip4_addr3(&iphdr->dest),

+                    ip4_addr4(&iphdr->dest)));

+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));

+}

+#endif /* IP_DEBUG */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip_addr.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip_addr.c
new file mode 100644
index 0000000..7a96c2f
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip_addr.c
@@ -0,0 +1,84 @@
+/**

+ * @file

+ * This is the IPv4 address tools implementation.

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+#include "lwip/ip_addr.h"

+#include "lwip/inet.h"

+#include "lwip/netif.h"

+

+#define IP_ADDR_ANY_VALUE 0x00000000UL

+#define IP_ADDR_BROADCAST_VALUE 0xffffffffUL

+

+/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */

+const struct ip_addr ip_addr_any = { IP_ADDR_ANY_VALUE };

+const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE };

+

+/**

+ * Determine if an address is a broadcast address on a network interface

+ *

+ * @param addr address to be checked

+ * @param netif the network interface against which the address is checked

+ * @return returns non-zero if the address is a broadcast address

+ */

+u8_t ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif)

+{

+  u32_t addr2test;

+

+  addr2test = addr->addr;

+  /* all ones (broadcast) or all zeroes (old skool broadcast) */

+  if ((~addr2test == IP_ADDR_ANY_VALUE) ||

+      (addr2test == IP_ADDR_ANY_VALUE))

+    return 1;

+  /* no broadcast support on this network interface? */

+  else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0)

+    /* the given address cannot be a broadcast address

+     * nor can we check against any broadcast addresses */

+    return 0;

+  /* address matches network interface address exactly? => no broadcast */

+  else if (addr2test == netif->ip_addr.addr)

+    return 0;

+  /*  on the same (sub) network... */

+  else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask))

+         /* ...and host identifier bits are all ones? =>... */

+          && ((addr2test & ~netif->netmask.addr) ==

+           (IP_ADDR_BROADCAST_VALUE & ~netif->netmask.addr)))

+    /* => network broadcast address */

+    return 1;

+  else

+    return 0;

+}

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip_frag.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip_frag.c
new file mode 100644
index 0000000..5cca281
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip_frag.c
@@ -0,0 +1,783 @@
+/**

+ * @file

+ * This is the IPv4 packet segmentation and reassembly implementation.

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Jani Monoses <jani@iv.ro>

+ *         Simon Goldschmidt

+ * original reassembly code by Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+#include "lwip/ip_frag.h"

+#include "lwip/ip.h"

+#include "lwip/inet.h"

+#include "lwip/inet_chksum.h"

+#include "lwip/netif.h"

+#include "lwip/snmp.h"

+#include "lwip/stats.h"

+#include "lwip/icmp.h"

+

+#include <string.h>

+

+#if IP_REASSEMBLY

+/**

+ * The IP reassembly code currently has the following limitations:

+ * - IP header options are not supported

+ * - fragments must not overlap (e.g. due to different routes),

+ *   currently, overlapping or duplicate fragments are thrown away

+ *   if IP_REASS_CHECK_OVERLAP=1 (the default)!

+ *

+ * @todo: work with IP header options

+ */

+

+/** Setting this to 0, you can turn off checking the fragments for overlapping

+ * regions. The code gets a little smaller. Only use this if you know that

+ * overlapping won't occur on your network! */

+#ifndef IP_REASS_CHECK_OVERLAP

+#define IP_REASS_CHECK_OVERLAP 1

+#endif /* IP_REASS_CHECK_OVERLAP */

+

+/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is

+ * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.

+ * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA

+ * is set to 1, so one datagram can be reassembled at a time, only. */

+#ifndef IP_REASS_FREE_OLDEST

+#define IP_REASS_FREE_OLDEST 1

+#endif /* IP_REASS_FREE_OLDEST */

+

+#define IP_REASS_FLAG_LASTFRAG 0x01

+

+/** This is a helper struct which holds the starting

+ * offset and the ending offset of this fragment to

+ * easily chain the fragments.

+ */

+struct ip_reass_helper {

+  struct pbuf *next_pbuf;

+  u16_t start;

+  u16_t end;

+};

+

+#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB)  \

+  (ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \

+   ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \

+   IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0

+

+/* global variables */

+static struct ip_reassdata *reassdatagrams;

+static u16_t ip_reass_pbufcount;

+

+/* function prototypes */

+static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);

+static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);

+

+/**

+ * Reassembly timer base function

+ * for both NO_SYS == 0 and 1 (!).

+ *

+ * Should be called every 1000 msec (defined by IP_TMR_INTERVAL).

+ */

+void

+ip_reass_tmr(void)

+{

+  struct ip_reassdata *r, *prev = NULL;

+

+  r = reassdatagrams;

+  while (r != NULL) {

+    /* Decrement the timer. Once it reaches 0,

+     * clean up the incomplete fragment assembly */

+    if (r->timer > 0) {

+      r->timer--;

+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer));

+      prev = r;

+      r = r->next;

+    } else {

+      /* reassembly timed out */

+      struct ip_reassdata *tmp;

+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n"));

+      tmp = r;

+      /* get the next pointer before freeing */

+      r = r->next;

+      /* free the helper struct and all enqueued pbufs */

+      ip_reass_free_complete_datagram(tmp, prev);

+     }

+   }

+}

+

+/**

+ * Free a datagram (struct ip_reassdata) and all its pbufs.

+ * Updates the total count of enqueued pbufs (ip_reass_pbufcount),

+ * SNMP counters and sends an ICMP time exceeded packet.

+ *

+ * @param ipr datagram to free

+ * @param prev the previous datagram in the linked list

+ * @return the number of pbufs freed

+ */

+static int

+ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)

+{

+  int pbufs_freed = 0;

+  struct pbuf *p;

+  struct ip_reass_helper *iprh;

+

+  LWIP_ASSERT("prev != ipr", prev != ipr);

+  if (prev != NULL) {

+    LWIP_ASSERT("prev->next == ipr", prev->next == ipr);

+  }

+

+  snmp_inc_ipreasmfails();

+#if LWIP_ICMP

+  iprh = (struct ip_reass_helper *)ipr->p->payload;

+  if (iprh->start == 0) {

+    /* The first fragment was received, send ICMP time exceeded. */

+    /* First, de-queue the first pbuf from r->p. */

+    p = ipr->p;

+    ipr->p = iprh->next_pbuf;

+    /* Then, copy the original header into it. */

+    SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);

+    icmp_time_exceeded(p, ICMP_TE_FRAG);

+    pbufs_freed += pbuf_clen(p);

+    pbuf_free(p);

+  }

+#endif /* LWIP_ICMP */

+

+  /* First, free all received pbufs.  The individual pbufs need to be released

+     separately as they have not yet been chained */

+  p = ipr->p;

+  while (p != NULL) {

+    struct pbuf *pcur;

+    iprh = (struct ip_reass_helper *)p->payload;

+    pcur = p;

+    /* get the next pointer before freeing */

+    p = iprh->next_pbuf;

+    pbufs_freed += pbuf_clen(pcur);

+    pbuf_free(pcur);

+  }

+  /* Then, unchain the struct ip_reassdata from the list and free it. */

+  ip_reass_dequeue_datagram(ipr, prev);

+  LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed);

+  ip_reass_pbufcount -= pbufs_freed;

+

+  return pbufs_freed;

+}

+

+#if IP_REASS_FREE_OLDEST

+/**

+ * Free the oldest datagram to make room for enqueueing new fragments.

+ * The datagram 'fraghdr' belongs to is not freed!

+ *

+ * @param fraghdr IP header of the current fragment

+ * @param pbufs_needed number of pbufs needed to enqueue

+ *        (used for freeing other datagrams if not enough space)

+ * @return the number of pbufs freed

+ */

+static int

+ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)

+{

+  /* @todo Can't we simply remove the last datagram in the

+   *       linked list behind reassdatagrams?

+   */

+  struct ip_reassdata *r, *oldest, *prev;

+  int pbufs_freed = 0, pbufs_freed_current;

+  int other_datagrams;

+

+  /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,

+   * but don't free the datagram that 'fraghdr' belongs to! */

+  do {

+    oldest = NULL;

+    prev = NULL;

+    other_datagrams = 0;

+    r = reassdatagrams;

+    while (r != NULL) {

+      if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) {

+        /* Not the same datagram as fraghdr */

+        other_datagrams++;

+        if (oldest == NULL) {

+          oldest = r;

+        } else if (r->timer <= oldest->timer) {

+          /* older than the previous oldest */

+          oldest = r;

+        }

+      }

+      if (r->next != NULL) {

+        prev = r;

+      }

+      r = r->next;

+    }

+    if (oldest != NULL) {

+      pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev);

+      pbufs_freed += pbufs_freed_current;

+    }

+  } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));

+  return pbufs_freed;

+}

+#endif /* IP_REASS_FREE_OLDEST */

+

+/**

+ * Enqueues a new fragment into the fragment queue

+ * @param fraghdr points to the new fragments IP hdr

+ * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space)

+ * @return A pointer to the queue location into which the fragment was enqueued

+ */

+static struct ip_reassdata*

+ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)

+{

+  struct ip_reassdata* ipr;

+  /* No matching previous fragment found, allocate a new reassdata struct */

+  ipr = memp_malloc(MEMP_REASSDATA);

+  if (ipr == NULL) {

+#if IP_REASS_FREE_OLDEST

+    if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {

+      ipr = memp_malloc(MEMP_REASSDATA);

+    }

+    if (ipr == NULL)

+#endif /* IP_REASS_FREE_OLDEST */

+    {

+      IPFRAG_STATS_INC(ip_frag.memerr);

+      LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n"));

+      return NULL;

+    }

+  }

+  memset(ipr, 0, sizeof(struct ip_reassdata));

+  ipr->timer = IP_REASS_MAXAGE;

+

+  /* enqueue the new structure to the front of the list */

+  ipr->next = reassdatagrams;

+  reassdatagrams = ipr;

+  /* copy the ip header for later tests and input */

+  /* @todo: no ip options supported? */

+  SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN);

+  return ipr;

+}

+

+/**

+ * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs.

+ * @param ipr points to the queue entry to dequeue

+ */

+static void

+ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)

+{

+

+  /* dequeue the reass struct  */

+  if (reassdatagrams == ipr) {

+    /* it was the first in the list */

+    reassdatagrams = ipr->next;

+  } else {

+    /* it wasn't the first, so it must have a valid 'prev' */

+    LWIP_ASSERT("sanity check linked list", prev != NULL);

+    prev->next = ipr->next;

+  }

+

+  /* now we can free the ip_reass struct */

+  memp_free(MEMP_REASSDATA, ipr);

+}

+

+/**

+ * Chain a new pbuf into the pbuf list that composes the datagram.  The pbuf list

+ * will grow over time as  new pbufs are rx.

+ * Also checks that the datagram passes basic continuity checks (if the last

+ * fragment was received at least once).

+ * @param root_p points to the 'root' pbuf for the current datagram being assembled.

+ * @param new_p points to the pbuf for the current fragment

+ * @return 0 if invalid, >0 otherwise

+ */

+static int

+ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p)

+{

+  struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;

+  struct pbuf *q;

+  u16_t offset,len;

+  struct ip_hdr *fraghdr;

+  int valid = 1;

+

+  /* Extract length and fragment offset from current fragment */

+  fraghdr = (struct ip_hdr*)new_p->payload;

+  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;

+  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;

+

+  /* overwrite the fragment's ip header from the pbuf with our helper struct,

+   * and setup the embedded helper structure. */

+  /* make sure the struct ip_reass_helper fits into the IP header */

+  LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN",

+              sizeof(struct ip_reass_helper) <= IP_HLEN);

+  iprh = (struct ip_reass_helper*)new_p->payload;

+  iprh->next_pbuf = NULL;

+  iprh->start = offset;

+  iprh->end = offset + len;

+

+  /* Iterate through until we either get to the end of the list (append),

+   * or we find on with a larger offset (insert). */

+  for (q = ipr->p; q != NULL;) {

+    iprh_tmp = (struct ip_reass_helper*)q->payload;

+    if (iprh->start < iprh_tmp->start) {

+      /* the new pbuf should be inserted before this */

+      iprh->next_pbuf = q;

+      if (iprh_prev != NULL) {

+        /* not the fragment with the lowest offset */

+#if IP_REASS_CHECK_OVERLAP

+        if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {

+          /* fragment overlaps with previous or following, throw away */

+          goto freepbuf;

+        }

+#endif /* IP_REASS_CHECK_OVERLAP */

+        iprh_prev->next_pbuf = new_p;

+      } else {

+        /* fragment with the lowest offset */

+        ipr->p = new_p;

+      }

+      break;

+    } else if(iprh->start == iprh_tmp->start) {

+      /* received the same datagram twice: no need to keep the datagram */

+      goto freepbuf;

+#if IP_REASS_CHECK_OVERLAP

+    } else if(iprh->start < iprh_tmp->end) {

+      /* overlap: no need to keep the new datagram */

+      goto freepbuf;

+#endif /* IP_REASS_CHECK_OVERLAP */

+    } else {

+      /* Check if the fragments received so far have no wholes. */

+      if (iprh_prev != NULL) {

+        if (iprh_prev->end != iprh_tmp->start) {

+          /* There is a fragment missing between the current

+           * and the previous fragment */

+          valid = 0;

+        }

+      }

+    }

+    q = iprh_tmp->next_pbuf;

+    iprh_prev = iprh_tmp;

+  }

+

+  /* If q is NULL, then we made it to the end of the list. Determine what to do now */

+  if (q == NULL) {

+    if (iprh_prev != NULL) {

+      /* this is (for now), the fragment with the highest offset:

+       * chain it to the last fragment */

+#if IP_REASS_CHECK_OVERLAP

+      LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);

+#endif /* IP_REASS_CHECK_OVERLAP */

+      iprh_prev->next_pbuf = new_p;

+      if (iprh_prev->end != iprh->start) {

+        valid = 0;

+      }

+    } else {

+#if IP_REASS_CHECK_OVERLAP

+      LWIP_ASSERT("no previous fragment, this must be the first fragment!",

+        ipr->p == NULL);

+#endif /* IP_REASS_CHECK_OVERLAP */

+      /* this is the first fragment we ever received for this ip datagram */

+      ipr->p = new_p;

+    }

+  }

+

+  /* At this point, the validation part begins: */

+  /* If we already received the last fragment */

+  if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {

+    /* and had no wholes so far */

+    if (valid) {

+      /* then check if the rest of the fragments is here */

+      /* Check if the queue starts with the first datagram */

+      if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) {

+        valid = 0;

+      } else {

+        /* and check that there are no wholes after this datagram */

+        iprh_prev = iprh;

+        q = iprh->next_pbuf;

+        while (q != NULL) {

+          iprh = (struct ip_reass_helper*)q->payload;

+          if (iprh_prev->end != iprh->start) {

+            valid = 0;

+            break;

+          }

+          iprh_prev = iprh;

+          q = iprh->next_pbuf;

+        }

+        /* if still valid, all fragments are received

+         * (because to the MF==0 already arrived */

+        if (valid) {

+          LWIP_ASSERT("sanity check", ipr->p != NULL);

+          LWIP_ASSERT("sanity check",

+            ((struct ip_reass_helper*)ipr->p->payload) != iprh);

+          LWIP_ASSERT("validate_datagram:next_pbuf!=NULL",

+            iprh->next_pbuf == NULL);

+          LWIP_ASSERT("validate_datagram:datagram end!=datagram len",

+            iprh->end == ipr->datagram_len);

+        }

+      }

+    }

+    /* If valid is 0 here, there are some fragments missing in the middle

+     * (since MF == 0 has already arrived). Such datagrams simply time out if

+     * no more fragments are received... */

+    return valid;

+  }

+  /* If we come here, not all fragments were received, yet! */

+  return 0; /* not yet valid! */

+#if IP_REASS_CHECK_OVERLAP

+freepbuf:

+  ip_reass_pbufcount -= pbuf_clen(new_p);

+  pbuf_free(new_p);

+  return 0;

+#endif /* IP_REASS_CHECK_OVERLAP */

+}

+

+/**

+ * Reassembles incoming IP fragments into an IP datagram.

+ *

+ * @param p points to a pbuf chain of the fragment

+ * @return NULL if reassembly is incomplete, ? otherwise

+ */

+struct pbuf *

+ip_reass(struct pbuf *p)

+{

+  struct pbuf *r;

+  struct ip_hdr *fraghdr;

+  struct ip_reassdata *ipr;

+  struct ip_reass_helper *iprh;

+  u16_t offset, len;

+  u8_t clen;

+  struct ip_reassdata *ipr_prev = NULL;

+

+  IPFRAG_STATS_INC(ip_frag.recv);

+  snmp_inc_ipreasmreqds();

+

+  fraghdr = (struct ip_hdr*)p->payload;

+

+  if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {

+    LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n"));

+    IPFRAG_STATS_INC(ip_frag.err);

+    goto nullreturn;

+  }

+

+  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;

+  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;

+

+  /* Check if we are allowed to enqueue more datagrams. */

+  clen = pbuf_clen(p);

+  if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {

+#if IP_REASS_FREE_OLDEST

+    if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||

+        ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))

+#endif /* IP_REASS_FREE_OLDEST */

+    {

+      /* No datagram could be freed and still too many pbufs enqueued */

+      LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",

+        ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));

+      IPFRAG_STATS_INC(ip_frag.memerr);

+      /* @todo: send ICMP time exceeded here? */

+      /* drop this pbuf */

+      goto nullreturn;

+    }

+  }

+

+  /* Look for the datagram the fragment belongs to in the current datagram queue,

+   * remembering the previous in the queue for later dequeueing. */

+  for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {

+    /* Check if the incoming fragment matches the one currently present

+       in the reassembly buffer. If so, we proceed with copying the

+       fragment into the buffer. */

+    if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {

+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",

+        ntohs(IPH_ID(fraghdr))));

+      IPFRAG_STATS_INC(ip_frag.cachehit);

+      break;

+    }

+    ipr_prev = ipr;

+  }

+

+  if (ipr == NULL) {

+  /* Enqueue a new datagram into the datagram queue */

+    ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);

+    /* Bail if unable to enqueue */

+    if(ipr == NULL) {

+      goto nullreturn;

+    }

+  } else {

+    if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&

+      ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {

+      /* ipr->iphdr is not the header from the first fragment, but fraghdr is

+       * -> copy fraghdr into ipr->iphdr since we want to have the header

+       * of the first fragment (for ICMP time exceeded and later, for copying

+       * all options, if supported)*/

+      SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);

+    }

+  }

+  /* Track the current number of pbufs current 'in-flight', in order to limit

+  the number of fragments that may be enqueued at any one time */

+  ip_reass_pbufcount += clen;

+

+  /* At this point, we have either created a new entry or pointing

+   * to an existing one */

+

+  /* check for 'no more fragments', and update queue entry*/

+  if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {

+    ipr->flags |= IP_REASS_FLAG_LASTFRAG;

+    ipr->datagram_len = offset + len;

+    LWIP_DEBUGF(IP_REASS_DEBUG,

+     ("ip_reass: last fragment seen, total len %"S16_F"\n",

+      ipr->datagram_len));

+  }

+  /* find the right place to insert this pbuf */

+  /* @todo: trim pbufs if fragments are overlapping */

+  if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {

+    /* the totally last fragment (flag more fragments = 0) was received at least

+     * once AND all fragments are received */

+    ipr->datagram_len += IP_HLEN;

+

+    /* save the second pbuf before copying the header over the pointer */

+    r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;

+

+    /* copy the original ip header back to the first pbuf */

+    fraghdr = (struct ip_hdr*)(ipr->p->payload);

+    SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);

+    IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));

+    IPH_OFFSET_SET(fraghdr, 0);

+    IPH_CHKSUM_SET(fraghdr, 0);

+    /* @todo: do we need to set calculate the correct checksum? */

+    IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));

+

+    p = ipr->p;

+

+    /* chain together the pbufs contained within the reass_data list. */

+    while(r != NULL) {

+      iprh = (struct ip_reass_helper*)r->payload;

+

+      /* hide the ip header for every succeding fragment */

+      pbuf_header(r, -IP_HLEN);

+      pbuf_cat(p, r);

+      r = iprh->next_pbuf;

+    }

+    /* release the sources allocate for the fragment queue entry */

+    ip_reass_dequeue_datagram(ipr, ipr_prev);

+

+    /* and adjust the number of pbufs currently queued for reassembly. */

+    ip_reass_pbufcount -= pbuf_clen(p);

+

+    /* Return the pbuf chain */

+    return p;

+  }

+  /* the datagram is not (yet?) reassembled completely */

+  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount));

+  return NULL;

+

+nullreturn:

+  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n"));

+  IPFRAG_STATS_INC(ip_frag.drop);

+  pbuf_free(p);

+  return NULL;

+}

+#endif /* IP_REASSEMBLY */

+

+#if IP_FRAG

+#if IP_FRAG_USES_STATIC_BUF

+static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU)];

+#endif /* IP_FRAG_USES_STATIC_BUF */

+

+/**

+ * Fragment an IP datagram if too large for the netif.

+ *

+ * Chop the datagram in MTU sized chunks and send them in order

+ * by using a fixed size static memory buffer (PBUF_REF) or

+ * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).

+ *

+ * @param p ip packet to send

+ * @param netif the netif on which to send

+ * @param dest destination ip address to which to send

+ *

+ * @return ERR_OK if sent successfully, err_t otherwise

+ */

+err_t

+ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)

+{

+  struct pbuf *rambuf;

+#if IP_FRAG_USES_STATIC_BUF

+  struct pbuf *header;

+#else

+  struct pbuf *newpbuf;

+  struct ip_hdr *original_iphdr;

+#endif

+  struct ip_hdr *iphdr;

+  u16_t nfb;

+  u16_t left, cop;

+  u16_t mtu = netif->mtu;

+  u16_t ofo, omf;

+  u16_t last;

+  u16_t poff = IP_HLEN;

+  u16_t tmp;

+#if !IP_FRAG_USES_STATIC_BUF

+  u16_t newpbuflen = 0;

+  u16_t left_to_copy;

+#endif

+

+  /* Get a RAM based MTU sized pbuf */

+#if IP_FRAG_USES_STATIC_BUF

+  /* When using a static buffer, we use a PBUF_REF, which we will

+   * use to reference the packet (without link header).

+   * Layer and length is irrelevant.

+   */

+  rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);

+  if (rambuf == NULL) {

+    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));

+    return ERR_MEM;

+  }

+  rambuf->tot_len = rambuf->len = mtu;

+  rambuf->payload = LWIP_MEM_ALIGN((void *)buf);

+

+  /* Copy the IP header in it */

+  iphdr = rambuf->payload;

+  SMEMCPY(iphdr, p->payload, IP_HLEN);

+#else /* IP_FRAG_USES_STATIC_BUF */

+  original_iphdr = p->payload;

+  iphdr = original_iphdr;

+#endif /* IP_FRAG_USES_STATIC_BUF */

+

+  /* Save original offset */

+  tmp = ntohs(IPH_OFFSET(iphdr));

+  ofo = tmp & IP_OFFMASK;

+  omf = tmp & IP_MF;

+

+  left = p->tot_len - IP_HLEN;

+

+  nfb = (mtu - IP_HLEN) / 8;

+

+  while (left) {

+    last = (left <= mtu - IP_HLEN);

+

+    /* Set new offset and MF flag */

+    tmp = omf | (IP_OFFMASK & (ofo));

+    if (!last)

+      tmp = tmp | IP_MF;

+

+    /* Fill this fragment */

+    cop = last ? left : nfb * 8;

+

+#if IP_FRAG_USES_STATIC_BUF

+    poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);

+#else /* IP_FRAG_USES_STATIC_BUF */

+    /* When not using a static buffer, create a chain of pbufs.

+     * The first will be a PBUF_RAM holding the link and IP header.

+     * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,

+     * but limited to the size of an mtu.

+     */

+    rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);

+    if (rambuf == NULL) {

+      return ERR_MEM;

+    }

+    LWIP_ASSERT("this needs a pbuf in one piece!",

+                (p->len >= (IP_HLEN)));

+    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);

+    iphdr = rambuf->payload;

+

+    /* Can just adjust p directly for needed offset. */

+    p->payload = (u8_t *)p->payload + poff;

+    p->len -= poff;

+

+    left_to_copy = cop;

+    while (left_to_copy) {

+      newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;

+      /* Is this pbuf already empty? */

+      if (!newpbuflen) {

+        p = p->next;

+        continue;

+      }

+      newpbuf = pbuf_alloc(PBUF_RAW, 0, PBUF_REF);

+      if (newpbuf == NULL) {

+        pbuf_free(rambuf);

+        return ERR_MEM;

+      }

+      /* Mirror this pbuf, although we might not need all of it. */

+      newpbuf->payload = p->payload;

+      newpbuf->len = newpbuf->tot_len = newpbuflen;

+      /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain

+       * so that it is removed when pbuf_dechain is later called on rambuf.

+       */

+      pbuf_cat(rambuf, newpbuf);

+      left_to_copy -= newpbuflen;

+      if (left_to_copy)

+        p = p->next;

+    }

+    poff = newpbuflen;

+#endif /* IP_FRAG_USES_STATIC_BUF */

+

+    /* Correct header */

+    IPH_OFFSET_SET(iphdr, htons(tmp));

+    IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));

+    IPH_CHKSUM_SET(iphdr, 0);

+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));

+

+#if IP_FRAG_USES_STATIC_BUF

+    if (last)

+      pbuf_realloc(rambuf, left + IP_HLEN);

+

+    /* This part is ugly: we alloc a RAM based pbuf for

+     * the link level header for each chunk and then

+     * free it.A PBUF_ROM style pbuf for which pbuf_header

+     * worked would make things simpler.

+     */

+    header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);

+    if (header != NULL) {

+      pbuf_chain(header, rambuf);

+      netif->output(netif, header, dest);

+      IPFRAG_STATS_INC(ip_frag.xmit);

+      snmp_inc_ipfragcreates();

+      pbuf_free(header);

+    } else {

+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));

+      pbuf_free(rambuf);

+      return ERR_MEM;

+    }

+#else /* IP_FRAG_USES_STATIC_BUF */

+    /* No need for separate header pbuf - we allowed room for it in rambuf

+     * when allocated.

+     */

+    netif->output(netif, rambuf, dest);

+    IPFRAG_STATS_INC(ip_frag.xmit);

+

+    /* Unfortunately we can't reuse rambuf - the hardware may still be

+     * using the buffer. Instead we free it (and the ensuing chain) and

+     * recreate it next time round the loop. If we're lucky the hardware

+     * will have already sent the packet, the free will really free, and

+     * there will be zero memory penalty.

+     */

+

+    pbuf_free(rambuf);

+#endif /* IP_FRAG_USES_STATIC_BUF */

+    left -= cop;

+    ofo += nfb;

+  }

+#if IP_FRAG_USES_STATIC_BUF

+  pbuf_free(rambuf);

+#endif /* IP_FRAG_USES_STATIC_BUF */

+  snmp_inc_ipfragoks();

+  return ERR_OK;

+}

+#endif /* IP_FRAG */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/README b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/README
new file mode 100644
index 0000000..a59caef
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/README
@@ -0,0 +1 @@
+IPv6 support in lwIP is very experimental.

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/icmp6.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/icmp6.c
new file mode 100644
index 0000000..1661ace
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/icmp6.c
@@ -0,0 +1,179 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+/* Some ICMP messages should be passed to the transport protocols. This

+   is not implemented. */

+

+#include "lwip/opt.h"

+

+#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/icmp.h"

+#include "lwip/inet.h"

+#include "lwip/ip.h"

+#include "lwip/def.h"

+#include "lwip/stats.h"

+

+void

+icmp_input(struct pbuf *p, struct netif *inp)

+{

+  u8_t type;

+  struct icmp_echo_hdr *iecho;

+  struct ip_hdr *iphdr;

+  struct ip_addr tmpaddr;

+

+  ICMP_STATS_INC(icmp.recv);

+

+  /* TODO: check length before accessing payload! */

+

+  type = ((u8_t *)p->payload)[0];

+

+  switch (type) {

+  case ICMP6_ECHO:

+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));

+

+    if (p->tot_len < sizeof(struct icmp_echo_hdr)) {

+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));

+

+      pbuf_free(p);

+      ICMP_STATS_INC(icmp.lenerr);

+      return;

+    }

+    iecho = p->payload;

+    iphdr = (struct ip_hdr *)((u8_t *)p->payload - IP_HLEN);

+    if (inet_chksum_pbuf(p) != 0) {

+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));

+      ICMP_STATS_INC(icmp.chkerr);

+    /*      return;*/

+    }

+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp: p->len %"S16_F" p->tot_len %"S16_F"\n", p->len, p->tot_len));

+    ip_addr_set(&tmpaddr, &(iphdr->src));

+    ip_addr_set(&(iphdr->src), &(iphdr->dest));

+    ip_addr_set(&(iphdr->dest), &tmpaddr);

+    iecho->type = ICMP6_ER;

+    /* adjust the checksum */

+    if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) {

+      iecho->chksum += htons(ICMP6_ECHO << 8) + 1;

+    } else {

+      iecho->chksum += htons(ICMP6_ECHO << 8);

+    }

+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));

+    ICMP_STATS_INC(icmp.xmit);

+

+    /*    LWIP_DEBUGF("icmp: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/

+    ip_output_if (p, &(iphdr->src), IP_HDRINCL,

+     iphdr->hoplim, IP_PROTO_ICMP, inp);

+    break;

+  default:

+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" not supported.\n", (s16_t)type));

+    ICMP_STATS_INC(icmp.proterr);

+    ICMP_STATS_INC(icmp.drop);

+  }

+

+  pbuf_free(p);

+}

+

+void

+icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)

+{

+  struct pbuf *q;

+  struct ip_hdr *iphdr;

+  struct icmp_dur_hdr *idur;

+

+  /* @todo: can this be PBUF_LINK instead of PBUF_IP? */

+  q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);

+  /* ICMP header + IP header + 8 bytes of data */

+  if (q == NULL) {

+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));

+    pbuf_free(p);

+    return;

+  }

+  LWIP_ASSERT("check that first pbuf can hold icmp message",

+             (q->len >= (8 + IP_HLEN + 8)));

+

+  iphdr = p->payload;

+

+  idur = q->payload;

+  idur->type = (u8_t)ICMP6_DUR;

+  idur->icode = (u8_t)t;

+

+  SMEMCPY((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8);

+

+  /* calculate checksum */

+  idur->chksum = 0;

+  idur->chksum = inet_chksum(idur, q->len);

+  ICMP_STATS_INC(icmp.xmit);

+

+  ip_output(q, NULL,

+      (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);

+  pbuf_free(q);

+}

+

+void

+icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)

+{

+  struct pbuf *q;

+  struct ip_hdr *iphdr;

+  struct icmp_te_hdr *tehdr;

+

+  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n"));

+

+  /* @todo: can this be PBUF_LINK instead of PBUF_IP? */

+  q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);

+  /* ICMP header + IP header + 8 bytes of data */

+  if (q == NULL) {

+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));

+    pbuf_free(p);

+    return;

+  }

+  LWIP_ASSERT("check that first pbuf can hold icmp message",

+             (q->len >= (8 + IP_HLEN + 8)));

+

+  iphdr = p->payload;

+

+  tehdr = q->payload;

+  tehdr->type = (u8_t)ICMP6_TE;

+  tehdr->icode = (u8_t)t;

+

+  /* copy fields from original packet */

+  SMEMCPY((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8);

+

+  /* calculate checksum */

+  tehdr->chksum = 0;

+  tehdr->chksum = inet_chksum(tehdr, q->len);

+  ICMP_STATS_INC(icmp.xmit);

+  ip_output(q, NULL,

+      (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);

+  pbuf_free(q);

+}

+

+#endif /* LWIP_ICMP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/inet6.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/inet6.c
new file mode 100644
index 0000000..8214f05
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/inet6.c
@@ -0,0 +1,163 @@
+/**

+ * @file

+ * Functions common to all TCP/IPv6 modules, such as the Internet checksum and the

+ * byte order functions.

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved. 

+ * 

+ * Redistribution and use in source and binary forms, with or without modification, 

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ * 

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#include "lwip/def.h"

+#include "lwip/inet.h"

+

+/* chksum:

+ *

+ * Sums up all 16 bit words in a memory portion. Also includes any odd byte.

+ * This function is used by the other checksum functions.

+ *

+ * For now, this is not optimized. Must be optimized for the particular processor

+ * arcitecture on which it is to run. Preferebly coded in assembler.

+ */

+

+static u32_t

+chksum(void *dataptr, u16_t len)

+{

+  u16_t *sdataptr = dataptr;

+  u32_t acc;

+  

+  

+  for(acc = 0; len > 1; len -= 2) {

+    acc += *sdataptr++;

+  }

+

+  /* add up any odd byte */

+  if (len == 1) {

+    acc += htons((u16_t)(*(u8_t *)dataptr) << 8);

+  }

+

+  return acc;

+

+}

+

+/* inet_chksum_pseudo:

+ *

+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.

+ */

+

+u16_t

+inet_chksum_pseudo(struct pbuf *p,

+       struct ip_addr *src, struct ip_addr *dest,

+       u8_t proto, u32_t proto_len)

+{

+  u32_t acc;

+  struct pbuf *q;

+  u8_t swapped, i;

+

+  acc = 0;

+  swapped = 0;

+  for(q = p; q != NULL; q = q->next) {    

+    acc += chksum(q->payload, q->len);

+    while (acc >> 16) {

+      acc = (acc & 0xffff) + (acc >> 16);

+    }

+    if (q->len % 2 != 0) {

+      swapped = 1 - swapped;

+      acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);

+    }

+  }

+

+  if (swapped) {

+    acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);

+  }

+  

+  for(i = 0; i < 8; i++) {

+    acc += ((u16_t *)src->addr)[i] & 0xffff;

+    acc += ((u16_t *)dest->addr)[i] & 0xffff;

+    while (acc >> 16) {

+      acc = (acc & 0xffff) + (acc >> 16);

+    }

+  }

+  acc += (u16_t)htons((u16_t)proto);

+  acc += ((u16_t *)&proto_len)[0] & 0xffff;

+  acc += ((u16_t *)&proto_len)[1] & 0xffff;

+

+  while (acc >> 16) {

+    acc = (acc & 0xffff) + (acc >> 16);

+  }

+  return ~(acc & 0xffff);

+}

+

+/* inet_chksum:

+ *

+ * Calculates the Internet checksum over a portion of memory. Used primarely for IP

+ * and ICMP.

+ */

+

+u16_t

+inet_chksum(void *dataptr, u16_t len)

+{

+  u32_t acc, sum;

+

+  acc = chksum(dataptr, len);

+  sum = (acc & 0xffff) + (acc >> 16);

+  sum += (sum >> 16);

+  return ~(sum & 0xffff);

+}

+

+u16_t

+inet_chksum_pbuf(struct pbuf *p)

+{

+  u32_t acc;

+  struct pbuf *q;

+  u8_t swapped;

+  

+  acc = 0;

+  swapped = 0;

+  for(q = p; q != NULL; q = q->next) {

+    acc += chksum(q->payload, q->len);

+    while (acc >> 16) {

+      acc = (acc & 0xffff) + (acc >> 16);

+    }    

+    if (q->len % 2 != 0) {

+      swapped = 1 - swapped;

+      acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8);

+    }

+  }

+ 

+  if (swapped) {

+    acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);

+  }

+  return ~(acc & 0xffff);

+}

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/ip6.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/ip6.c
new file mode 100644
index 0000000..46bc3ad
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/ip6.c
@@ -0,0 +1,375 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+

+

+/* ip.c

+ *

+ * This is the code for the IP layer for IPv6.

+ *

+ */

+

+

+#include "lwip/opt.h"

+

+#include "lwip/def.h"

+#include "lwip/mem.h"

+#include "lwip/ip.h"

+#include "lwip/inet.h"

+#include "lwip/netif.h"

+#include "lwip/icmp.h"

+#include "lwip/udp.h"

+#include "lwip/tcp.h"

+

+#include "lwip/stats.h"

+

+#include "arch/perf.h"

+

+/* ip_init:

+ *

+ * Initializes the IP layer.

+ */

+

+void

+ip_init(void)

+{

+}

+

+/* ip_route:

+ *

+ * Finds the appropriate network interface for a given IP address. It searches the

+ * list of network interfaces linearly. A match is found if the masked IP address of

+ * the network interface equals the masked IP address given to the function.

+ */

+

+struct netif *

+ip_route(struct ip_addr *dest)

+{

+  struct netif *netif;

+

+  for(netif = netif_list; netif != NULL; netif = netif->next) {

+    if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {

+      return netif;

+    }

+  }

+

+  return netif_default;

+}

+

+/* ip_forward:

+ *

+ * Forwards an IP packet. It finds an appropriate route for the packet, decrements

+ * the TTL value of the packet, adjusts the checksum and outputs the packet on the

+ * appropriate interface.

+ */

+

+static void

+ip_forward(struct pbuf *p, struct ip_hdr *iphdr)

+{

+  struct netif *netif;

+

+  PERF_START;

+

+  if ((netif = ip_route((struct ip_addr *)&(iphdr->dest))) == NULL) {

+

+    LWIP_DEBUGF(IP_DEBUG, ("ip_input: no forwarding route found for "));

+#if IP_DEBUG

+    ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));

+#endif /* IP_DEBUG */

+    LWIP_DEBUGF(IP_DEBUG, ("\n"));

+    pbuf_free(p);

+    return;

+  }

+  /* Decrement TTL and send ICMP if ttl == 0. */

+  if (--iphdr->hoplim == 0) {

+#if LWIP_ICMP

+    /* Don't send ICMP messages in response to ICMP messages */

+    if (iphdr->nexthdr != IP_PROTO_ICMP) {

+      icmp_time_exceeded(p, ICMP_TE_TTL);

+    }

+#endif /* LWIP_ICMP */

+    pbuf_free(p);

+    return;

+  }

+

+  /* Incremental update of the IP checksum. */

+  /*  if (iphdr->chksum >= htons(0xffff - 0x100)) {

+    iphdr->chksum += htons(0x100) + 1;

+  } else {

+    iphdr->chksum += htons(0x100);

+    }*/

+

+

+  LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to "));

+#if IP_DEBUG

+  ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));

+#endif /* IP_DEBUG */

+  LWIP_DEBUGF(IP_DEBUG, ("\n"));

+

+  IP_STATS_INC(ip.fw);

+  IP_STATS_INC(ip.xmit);

+

+  PERF_STOP("ip_forward");

+

+  netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));

+}

+

+/* ip_input:

+ *

+ * This function is called by the network interface device driver when an IP packet is

+ * received. The function does the basic checks of the IP header such as packet size

+ * being at least larger than the header size etc. If the packet was not destined for

+ * us, the packet is forwarded (using ip_forward). The IP checksum is always checked.

+ *

+ * Finally, the packet is sent to the upper layer protocol input function.

+ */

+

+void

+ip_input(struct pbuf *p, struct netif *inp) {

+  struct ip_hdr *iphdr;

+  struct netif *netif;

+

+

+  PERF_START;

+

+#if IP_DEBUG

+  ip_debug_print(p);

+#endif /* IP_DEBUG */

+

+

+  IP_STATS_INC(ip.recv);

+

+  /* identify the IP header */

+  iphdr = p->payload;

+

+

+  if (iphdr->v != 6) {

+    LWIP_DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number\n"));

+#if IP_DEBUG

+    ip_debug_print(p);

+#endif /* IP_DEBUG */

+    pbuf_free(p);

+    IP_STATS_INC(ip.err);

+    IP_STATS_INC(ip.drop);

+    return;

+  }

+

+  /* is this packet for us? */

+  for(netif = netif_list; netif != NULL; netif = netif->next) {

+#if IP_DEBUG

+    LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest "));

+    ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));

+    LWIP_DEBUGF(IP_DEBUG, ("netif->ip_addr "));

+    ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));

+    LWIP_DEBUGF(IP_DEBUG, ("\n"));

+#endif /* IP_DEBUG */

+    if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr))) {

+      break;

+    }

+  }

+

+

+  if (netif == NULL) {

+    /* packet not for us, route or discard */

+#if IP_FORWARD

+    ip_forward(p, iphdr);

+#endif

+    pbuf_free(p);

+    return;

+  }

+

+  pbuf_realloc(p, IP_HLEN + ntohs(iphdr->len));

+

+  /* send to upper layers */

+#if IP_DEBUG

+  /*  LWIP_DEBUGF("ip_input: \n");

+  ip_debug_print(p);

+  LWIP_DEBUGF("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/

+#endif /* IP_DEBUG */

+

+  if(pbuf_header(p, -IP_HLEN)) {

+    LWIP_ASSERT("Can't move over header in packet", 0);

+    return;

+  }

+

+  switch (iphdr->nexthdr) {

+  case IP_PROTO_UDP:

+    udp_input(p, inp);

+    break;

+  case IP_PROTO_TCP:

+    tcp_input(p, inp);

+    break;

+#if LWIP_ICMP

+  case IP_PROTO_ICMP:

+    icmp_input(p, inp);

+    break;

+#endif /* LWIP_ICMP */

+  default:

+#if LWIP_ICMP

+    /* send ICMP destination protocol unreachable */

+    icmp_dest_unreach(p, ICMP_DUR_PROTO);

+#endif /* LWIP_ICMP */

+    pbuf_free(p);

+    LWIP_DEBUGF(IP_DEBUG, ("Unsupported transport protocol %"U16_F"\n",

+          iphdr->nexthdr));

+

+    IP_STATS_INC(ip.proterr);

+    IP_STATS_INC(ip.drop);

+  }

+  PERF_STOP("ip_input");

+}

+

+

+/* ip_output_if:

+ *

+ * Sends an IP packet on a network interface. This function constructs the IP header

+ * and calculates the IP header checksum. If the source IP address is NULL,

+ * the IP address of the outgoing network interface is filled in as source address.

+ */

+

+err_t

+ip_output_if (struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,

+       u8_t ttl,

+       u8_t proto, struct netif *netif)

+{

+  struct ip_hdr *iphdr;

+

+  PERF_START;

+

+  LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len));

+  if (pbuf_header(p, IP_HLEN)) {

+    LWIP_DEBUGF(IP_DEBUG, ("ip_output: not enough room for IP header in pbuf\n"));

+    IP_STATS_INC(ip.err);

+

+    return ERR_BUF;

+  }

+  LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len));

+

+  iphdr = p->payload;

+

+

+  if (dest != IP_HDRINCL) {

+    LWIP_DEBUGF(IP_DEBUG, ("!IP_HDRLINCL\n"));

+    iphdr->hoplim = ttl;

+    iphdr->nexthdr = proto;

+    iphdr->len = htons(p->tot_len - IP_HLEN);

+    ip_addr_set(&(iphdr->dest), dest);

+

+    iphdr->v = 6;

+

+    if (ip_addr_isany(src)) {

+      ip_addr_set(&(iphdr->src), &(netif->ip_addr));

+    } else {

+      ip_addr_set(&(iphdr->src), src);

+    }

+

+  } else {

+    dest = &(iphdr->dest);

+  }

+

+  IP_STATS_INC(ip.xmit);

+

+  LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c (len %"U16_F")\n", netif->name[0], netif->name[1], p->tot_len));

+#if IP_DEBUG

+  ip_debug_print(p);

+#endif /* IP_DEBUG */

+

+  PERF_STOP("ip_output_if");

+  return netif->output(netif, p, dest);

+}

+

+/* ip_output:

+ *

+ * Simple interface to ip_output_if. It finds the outgoing network interface and

+ * calls upon ip_output_if to do the actual work.

+ */

+

+err_t

+ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,

+    u8_t ttl, u8_t proto)

+{

+  struct netif *netif;

+  if ((netif = ip_route(dest)) == NULL) {

+    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));

+    IP_STATS_INC(ip.rterr);

+    return ERR_RTE;

+  }

+

+  return ip_output_if (p, src, dest, ttl, proto, netif);

+}

+

+#if IP_DEBUG

+void

+ip_debug_print(struct pbuf *p)

+{

+  struct ip_hdr *iphdr = p->payload;

+

+  LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));

+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |  %"X16_F"%"X16_F"  |      %"X16_F"%"X16_F"           | (v, traffic class, flow label)\n",

+        iphdr->v,

+        iphdr->tclass1, iphdr->tclass2,

+        iphdr->flow1, iphdr->flow2));

+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      | %2"U16_F"  |  %2"U16_F"   | (len, nexthdr, hoplim)\n",

+        ntohs(iphdr->len),

+        iphdr->nexthdr,

+        iphdr->hoplim));

+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n",

+        (ntohl(iphdr->src.addr[0]) >> 16) & 0xffff,

+        ntohl(iphdr->src.addr[0]) & 0xffff));

+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n",

+        (ntohl(iphdr->src.addr[1]) >> 16) & 0xffff,

+        ntohl(iphdr->src.addr[1]) & 0xffff));

+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n",

+        (ntohl(iphdr->src.addr[2]) >> 16) & 0xffff,

+        ntohl(iphdr->src.addr[2]) & 0xffff));

+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n",

+        (ntohl(iphdr->src.addr[3]) >> 16) & 0xffff,

+        ntohl(iphdr->src.addr[3]) & 0xffff));

+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n",

+        (ntohl(iphdr->dest.addr[0]) >> 16) & 0xffff,

+        ntohl(iphdr->dest.addr[0]) & 0xffff));

+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n",

+        (ntohl(iphdr->dest.addr[1]) >> 16) & 0xffff,

+        ntohl(iphdr->dest.addr[1]) & 0xffff));

+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n",

+        (ntohl(iphdr->dest.addr[2]) >> 16) & 0xffff,

+        ntohl(iphdr->dest.addr[2]) & 0xffff));

+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n",

+        (ntohl(iphdr->dest.addr[3]) >> 16) & 0xffff,

+        ntohl(iphdr->dest.addr[3]) & 0xffff));

+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));

+}

+#endif /* IP_DEBUG */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/ip6_addr.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/ip6_addr.c
new file mode 100644
index 0000000..d898526
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/ipv6/ip6_addr.c
@@ -0,0 +1,72 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved. 

+ * 

+ * Redistribution and use in source and binary forms, with or without modification, 

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ * 

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+#include "lwip/ip_addr.h"

+#include "lwip/inet.h"

+

+u8_t

+ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,

+                struct ip_addr *mask)

+{

+  return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) &&

+         (addr1->addr[1] & mask->addr[1]) == (addr2->addr[1] & mask->addr[1]) &&

+         (addr1->addr[2] & mask->addr[2]) == (addr2->addr[2] & mask->addr[2]) &&

+         (addr1->addr[3] & mask->addr[3]) == (addr2->addr[3] & mask->addr[3]));

+        

+}

+

+u8_t

+ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2)

+{

+  return(addr1->addr[0] == addr2->addr[0] &&

+         addr1->addr[1] == addr2->addr[1] &&

+         addr1->addr[2] == addr2->addr[2] &&

+         addr1->addr[3] == addr2->addr[3]);

+}

+

+void

+ip_addr_set(struct ip_addr *dest, struct ip_addr *src)

+{

+  SMEMCPY(dest, src, sizeof(struct ip_addr));

+  /*  dest->addr[0] = src->addr[0];

+  dest->addr[1] = src->addr[1];

+  dest->addr[2] = src->addr[2];

+  dest->addr[3] = src->addr[3];*/

+}

+

+u8_t

+ip_addr_isany(struct ip_addr *addr)

+{

+  if (addr == NULL) return 1;

+  return((addr->addr[0] | addr->addr[1] | addr->addr[2] | addr->addr[3]) == 0);

+}

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/mem.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/mem.c
new file mode 100644
index 0000000..fbe3fa2
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/mem.c
@@ -0,0 +1,577 @@
+/**

+ * @file

+ * Dynamic memory manager

+ *

+ * This is a lightweight replacement for the standard C library malloc().

+ *

+ * If you want to use the standard C library malloc() instead, define

+ * MEM_LIBC_MALLOC to 1 in your lwipopts.h

+ *

+ * To let mem_malloc() use pools (prevents fragmentation and is much faster than

+ * a heap but might waste some memory), define MEM_USE_POOLS to 1, define

+ * MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list

+ * of pools like this (more pools can be added between _START and _END):

+ *

+ * Define three pools with sizes 256, 512, and 1512 bytes

+ * LWIP_MALLOC_MEMPOOL_START

+ * LWIP_MALLOC_MEMPOOL(20, 256)

+ * LWIP_MALLOC_MEMPOOL(10, 512)

+ * LWIP_MALLOC_MEMPOOL(5, 1512)

+ * LWIP_MALLOC_MEMPOOL_END

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *         Simon Goldschmidt

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/def.h"

+#include "lwip/mem.h"

+#include "lwip/sys.h"

+#include "lwip/stats.h"

+

+#include <string.h>

+

+#if MEM_USE_POOLS

+/* lwIP head implemented with different sized pools */

+

+/**

+ * This structure is used to save the pool one element came from.

+ */

+struct mem_helper

+{

+   memp_t poolnr;

+};

+

+/**

+ * Allocate memory: determine the smallest pool that is big enough

+ * to contain an element of 'size' and get an element from that pool.

+ *

+ * @param size the size in bytes of the memory needed

+ * @return a pointer to the allocated memory or NULL if the pool is empty

+ */

+void *

+mem_malloc(mem_size_t size)

+{

+  struct mem_helper *element;

+  memp_t poolnr;

+

+  for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr++) {

+    /* is this pool big enough to hold an element of the required size

+       plus a struct mem_helper that saves the pool this element came from? */

+    if ((size + sizeof(struct mem_helper)) <= memp_sizes[poolnr]) {

+      break;

+    }

+  }

+  if (poolnr > MEMP_POOL_LAST) {

+    LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);

+    return NULL;

+  }

+  element = (struct mem_helper*)memp_malloc(poolnr);

+  if (element == NULL) {

+    /* No need to DEBUGF or ASSERT: This error is already

+       taken care of in memp.c */

+    /** @todo: we could try a bigger pool if this one is empty! */

+    return NULL;

+  }

+

+  /* save the pool number this element came from */

+  element->poolnr = poolnr;

+  /* and return a pointer to the memory directly after the struct mem_helper */

+  element++;

+

+  return element;

+}

+

+/**

+ * Free memory previously allocated by mem_malloc. Loads the pool number

+ * and calls memp_free with that pool number to put the element back into

+ * its pool

+ *

+ * @param rmem the memory element to free

+ */

+void

+mem_free(void *rmem)

+{

+  struct mem_helper *hmem = (struct mem_helper*)rmem;

+

+  LWIP_ASSERT("rmem != NULL", (rmem != NULL));

+  LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));

+

+  /* get the original struct mem_helper */

+  hmem--;

+

+  LWIP_ASSERT("hmem != NULL", (hmem != NULL));

+  LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));

+  LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX));

+

+  /* and put it in the pool we saved earlier */

+  memp_free(hmem->poolnr, hmem);

+}

+

+#else /* MEM_USE_POOLS */

+/* lwIP replacement for your libc malloc() */

+

+/**

+ * The heap is made up as a list of structs of this type.

+ * This does not have to be aligned since for getting its size,

+ * we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes.

+ */

+struct mem {

+  /** index (-> ram[next]) of the next struct */

+  mem_size_t next;

+  /** index (-> ram[next]) of the next struct */

+  mem_size_t prev;

+  /** 1: this area is used; 0: this area is unused */

+  u8_t used;

+};

+

+/** All allocated blocks will be MIN_SIZE bytes big, at least!

+ * MIN_SIZE can be overridden to suit your needs. Smaller values save space,

+ * larger values could prevent too small blocks to fragment the RAM too much. */

+#ifndef MIN_SIZE

+#define MIN_SIZE             12

+#endif /* MIN_SIZE */

+/* some alignment macros: we define them here for better source code layout */

+#define MIN_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MIN_SIZE)

+#define SIZEOF_STRUCT_MEM    LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))

+#define MEM_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEM_SIZE)

+

+/** the heap. we need one struct mem at the end and some room for alignment */

+static u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];

+/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */

+static u8_t *ram;

+/** the last entry, always unused! */

+static struct mem *ram_end;

+/** pointer to the lowest free block, this is used for faster search */

+static struct mem *lfree;

+/** concurrent access protection */

+static sys_sem_t mem_sem;

+

+/**

+ * "Plug holes" by combining adjacent empty struct mems.

+ * After this function is through, there should not exist

+ * one empty struct mem pointing to another empty struct mem.

+ *

+ * @param mem this points to a struct mem which just has been freed

+ * @internal this function is only called by mem_free() and mem_realloc()

+ *

+ * This assumes access to the heap is protected by the calling function

+ * already.

+ */

+static void

+plug_holes(struct mem *mem)

+{

+  struct mem *nmem;

+  struct mem *pmem;

+

+  LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);

+  LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);

+  LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);

+

+  /* plug hole forward */

+  LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);

+

+  nmem = (struct mem *)&ram[mem->next];

+  if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {

+    /* if mem->next is unused and not end of ram, combine mem and mem->next */

+    if (lfree == nmem) {

+      lfree = mem;

+    }

+    mem->next = nmem->next;

+    ((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;

+  }

+

+  /* plug hole backward */

+  pmem = (struct mem *)&ram[mem->prev];

+  if (pmem != mem && pmem->used == 0) {

+    /* if mem->prev is unused, combine mem and mem->prev */

+    if (lfree == mem) {

+      lfree = pmem;

+    }

+    pmem->next = mem->next;

+    ((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;

+  }

+}

+

+/**

+ * Zero the heap and initialize start, end and lowest-free

+ */

+void

+mem_init(void)

+{

+  struct mem *mem;

+

+  LWIP_ASSERT("Sanity check alignment",

+    (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0);

+

+  /* align the heap */

+  ram = LWIP_MEM_ALIGN(ram_heap);

+  /* initialize the start of the heap */

+  mem = (struct mem *)ram;

+  mem->next = MEM_SIZE_ALIGNED;

+  mem->prev = 0;

+  mem->used = 0;

+  /* initialize the end of the heap */

+  ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED];

+  ram_end->used = 1;

+  ram_end->next = MEM_SIZE_ALIGNED;

+  ram_end->prev = MEM_SIZE_ALIGNED;

+

+  mem_sem = sys_sem_new(1);

+

+  /* initialize the lowest-free pointer to the start of the heap */

+  lfree = (struct mem *)ram;

+

+#if MEM_STATS

+  lwip_stats.mem.avail = MEM_SIZE_ALIGNED;

+#endif /* MEM_STATS */

+}

+

+/**

+ * Put a struct mem back on the heap

+ *

+ * @param rmem is the data portion of a struct mem as returned by a previous

+ *             call to mem_malloc()

+ */

+void

+mem_free(void *rmem)

+{

+  struct mem *mem;

+

+  if (rmem == NULL) {

+    LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n"));

+    return;

+  }

+  LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);

+

+  /* protect the heap from concurrent access */

+  sys_arch_sem_wait(mem_sem, 0);

+

+  LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&

+    (u8_t *)rmem < (u8_t *)ram_end);

+

+  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {

+    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n"));

+#if MEM_STATS

+    ++lwip_stats.mem.err;

+#endif /* MEM_STATS */

+    sys_sem_signal(mem_sem);

+    return;

+  }

+  /* Get the corresponding struct mem ... */

+  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);

+  /* ... which has to be in a used state ... */

+  LWIP_ASSERT("mem_free: mem->used", mem->used);

+  /* ... and is now unused. */

+  mem->used = 0;

+

+  if (mem < lfree) {

+    /* the newly freed struct is now the lowest */

+    lfree = mem;

+  }

+

+#if MEM_STATS

+  lwip_stats.mem.used -= mem->next - ((u8_t *)mem - ram);

+#endif /* MEM_STATS */

+

+  /* finally, see if prev or next are free also */

+  plug_holes(mem);

+  sys_sem_signal(mem_sem);

+}

+

+/**

+ * In contrast to its name, mem_realloc can only shrink memory, not expand it.

+ * Since the only use (for now) is in pbuf_realloc (which also can only shrink),

+ * this shouldn't be a problem!

+ *

+ * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked

+ * @param newsize required size after shrinking (needs to be smaller than or

+ *                equal to the previous size)

+ * @return for compatibility reasons: is always == rmem, at the moment

+ */

+void *

+mem_realloc(void *rmem, mem_size_t newsize)

+{

+  mem_size_t size;

+  mem_size_t ptr, ptr2;

+  struct mem *mem, *mem2;

+

+  /* Expand the size of the allocated memory region so that we can

+     adjust for alignment. */

+  newsize = LWIP_MEM_ALIGN_SIZE(newsize);

+

+  if(newsize < MIN_SIZE_ALIGNED) {

+    /* every data block must be at least MIN_SIZE_ALIGNED long */

+    newsize = MIN_SIZE_ALIGNED;

+  }

+

+  if (newsize > MEM_SIZE_ALIGNED) {

+    return NULL;

+  }

+

+  LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram &&

+   (u8_t *)rmem < (u8_t *)ram_end);

+

+  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {

+    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n"));

+    return rmem;

+  }

+  /* Get the corresponding struct mem ... */

+  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);

+  /* ... and its offset pointer */

+  ptr = (u8_t *)mem - ram;

+

+  size = mem->next - ptr - SIZEOF_STRUCT_MEM;

+  LWIP_ASSERT("mem_realloc can only shrink memory", newsize <= size);

+  if (newsize > size) {

+    /* not supported */

+    return NULL;

+  }

+  if (newsize == size) {

+    /* No change in size, simply return */

+    return rmem;

+  }

+

+  /* protect the heap from concurrent access */

+  sys_arch_sem_wait(mem_sem, 0);

+

+#if MEM_STATS

+  lwip_stats.mem.used -= (size - newsize);

+#endif /* MEM_STATS */

+

+  mem2 = (struct mem *)&ram[mem->next];

+  if(mem2->used == 0) {

+    /* The next struct is unused, we can simply move it at little */

+    mem_size_t next;

+    /* remember the old next pointer */

+    next = mem2->next;

+    /* create new struct mem which is moved directly after the shrinked mem */

+    ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;

+    if (lfree == mem2) {

+      lfree = (struct mem *)&ram[ptr2];

+    }

+    mem2 = (struct mem *)&ram[ptr2];

+    mem2->used = 0;

+    /* restore the next pointer */

+    mem2->next = next;

+    /* link it back to mem */

+    mem2->prev = ptr;

+    /* link mem to it */

+    mem->next = ptr2;

+    /* last thing to restore linked list: as we have moved mem2,

+     * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not

+     * the end of the heap */

+    if (mem2->next != MEM_SIZE_ALIGNED) {

+      ((struct mem *)&ram[mem2->next])->prev = ptr2;

+    }

+    /* no need to plug holes, we've already done that */

+  } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {

+    /* Next struct is used but there's room for another struct mem with

+     * at least MIN_SIZE_ALIGNED of data.

+     * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem

+     * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED').

+     * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty

+     *       region that couldn't hold data, but when mem->next gets freed,

+     *       the 2 regions would be combined, resulting in more free memory */

+    ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;

+    mem2 = (struct mem *)&ram[ptr2];

+    if (mem2 < lfree) {

+      lfree = mem2;

+    }

+    mem2->used = 0;

+    mem2->next = mem->next;

+    mem2->prev = ptr;

+    mem->next = ptr2;

+    if (mem2->next != MEM_SIZE_ALIGNED) {

+      ((struct mem *)&ram[mem2->next])->prev = ptr2;

+    }

+    /* the original mem->next is used, so no need to plug holes! */

+  }

+  /* else {

+    next struct mem is used but size between mem and mem2 is not big enough

+    to create another struct mem

+    -> don't do anyhting.

+    -> the remaining space stays unused since it is too small

+  } */

+  sys_sem_signal(mem_sem);

+  return rmem;

+}

+

+/**

+ * Adam's mem_malloc() plus solution for bug #17922

+ * Allocate a block of memory with a minimum of 'size' bytes.

+ *

+ * @param size is the minimum size of the requested block in bytes.

+ * @return pointer to allocated memory or NULL if no free memory was found.

+ *

+ * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT).

+ */

+void *

+mem_malloc(mem_size_t size)

+{

+  mem_size_t ptr, ptr2;

+  struct mem *mem, *mem2;

+

+  if (size == 0) {

+    return NULL;

+  }

+

+  /* Expand the size of the allocated memory region so that we can

+     adjust for alignment. */

+  size = LWIP_MEM_ALIGN_SIZE(size);

+

+  if(size < MIN_SIZE_ALIGNED) {

+    /* every data block must be at least MIN_SIZE_ALIGNED long */

+    size = MIN_SIZE_ALIGNED;

+  }

+

+  if (size > MEM_SIZE_ALIGNED) {

+    return NULL;

+  }

+

+  /* protect the heap from concurrent access */

+  sys_arch_sem_wait(mem_sem, 0);

+

+  /* Scan through the heap searching for a free block that is big enough,

+   * beginning with the lowest free block.

+   */

+  for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;

+       ptr = ((struct mem *)&ram[ptr])->next) {

+    mem = (struct mem *)&ram[ptr];

+

+    if ((!mem->used) &&

+        (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {

+      /* mem is not used and at least perfect fit is possible:

+       * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */

+

+      if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {

+        /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing

+         * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')

+         * -> split large block, create empty remainder,

+         * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if

+         * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,

+         * struct mem would fit in but no data between mem2 and mem2->next

+         * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty

+         *       region that couldn't hold data, but when mem->next gets freed,

+         *       the 2 regions would be combined, resulting in more free memory

+         */

+        ptr2 = ptr + SIZEOF_STRUCT_MEM + size;

+        /* create mem2 struct */

+        mem2 = (struct mem *)&ram[ptr2];

+        mem2->used = 0;

+        mem2->next = mem->next;

+        mem2->prev = ptr;

+        /* and insert it between mem and mem->next */

+        mem->next = ptr2;

+        mem->used = 1;

+

+        if (mem2->next != MEM_SIZE_ALIGNED) {

+          ((struct mem *)&ram[mem2->next])->prev = ptr2;

+        }

+#if MEM_STATS

+        lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM);

+        if (lwip_stats.mem.max < lwip_stats.mem.used) {

+          lwip_stats.mem.max = lwip_stats.mem.used;

+        }

+#endif /* MEM_STATS */

+      } else {

+        /* (a mem2 struct does no fit into the user data space of mem and mem->next will always

+         * be used at this point: if not we have 2 unused structs in a row, plug_holes should have

+         * take care of this).

+         * -> near fit or excact fit: do not split, no mem2 creation

+         * also can't move mem->next directly behind mem, since mem->next

+         * will always be used at this point!

+         */

+        mem->used = 1;

+#if MEM_STATS

+        lwip_stats.mem.used += mem->next - ((u8_t *)mem - ram);

+        if (lwip_stats.mem.max < lwip_stats.mem.used) {

+          lwip_stats.mem.max = lwip_stats.mem.used;

+        }

+#endif /* MEM_STATS */

+      }

+

+      if (mem == lfree) {

+        /* Find next free block after mem and update lowest free pointer */

+        while (lfree->used && lfree != ram_end) {

+          lfree = (struct mem *)&ram[lfree->next];

+        }

+        LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));

+      }

+      sys_sem_signal(mem_sem);

+      LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",

+       (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);

+      LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",

+       (unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);

+      LWIP_ASSERT("mem_malloc: sanity check alignment",

+        (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);

+

+      return (u8_t *)mem + SIZEOF_STRUCT_MEM;

+    }

+  }

+  LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));

+#if MEM_STATS

+  ++lwip_stats.mem.err;

+#endif /* MEM_STATS */

+  sys_sem_signal(mem_sem);

+  return NULL;

+}

+

+#endif /* MEM_USE_POOLS */

+/**

+ * Contiguously allocates enough space for count objects that are size bytes

+ * of memory each and returns a pointer to the allocated memory.

+ *

+ * The allocated memory is filled with bytes of value zero.

+ *

+ * @param count number of objects to allocate

+ * @param size size of the objects to allocate

+ * @return pointer to allocated memory / NULL pointer if there is an error

+ */

+void *mem_calloc(mem_size_t count, mem_size_t size)

+{

+  void *p;

+

+  /* allocate 'count' objects of size 'size' */

+  p = mem_malloc(count * size);

+  if (p) {

+    /* zero the memory */

+    memset(p, 0, count * size);

+  }

+  return p;

+}

+

+#endif /* !MEM_LIBC_MALLOC */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/memp.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/memp.c
new file mode 100644
index 0000000..d43e479
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/memp.c
@@ -0,0 +1,380 @@
+/**

+ * @file

+ * Dynamic pool memory manager

+ *

+ * lwIP has dedicated pools for many structures (netconn, protocol control blocks,

+ * packet buffers, ...). All these pools are managed here.

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#include "lwip/memp.h"

+#include "lwip/pbuf.h"

+#include "lwip/udp.h"

+#include "lwip/raw.h"

+#include "lwip/tcp.h"

+#include "lwip/igmp.h"

+#include "lwip/api.h"

+#include "lwip/api_msg.h"

+#include "lwip/tcpip.h"

+#include "lwip/sys.h"

+#include "lwip/stats.h"

+#include "netif/etharp.h"

+#include "lwip/ip_frag.h"

+

+#include <string.h>

+

+struct memp {

+  struct memp *next;

+#if MEMP_OVERFLOW_CHECK

+  const char *file;

+  int line;

+#endif /* MEMP_OVERFLOW_CHECK */

+};

+

+#if MEMP_OVERFLOW_CHECK

+/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning

+ * and at the end of each element, initialize them as 0xcd and check

+ * them later. */

+/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,

+ * every single element in each pool is checked!

+ * This is VERY SLOW but also very helpful. */

+/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in

+ * lwipopts.h to change the amount reserved for checking. */

+#ifndef MEMP_SANITY_REGION_BEFORE

+#define MEMP_SANITY_REGION_BEFORE  16

+#endif /* MEMP_SANITY_REGION_BEFORE*/

+#if MEMP_SANITY_REGION_BEFORE > 0

+#define MEMP_SANITY_REGION_BEFORE_ALIGNED    LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)

+#else

+#define MEMP_SANITY_REGION_BEFORE_ALIGNED    0

+#endif /* MEMP_SANITY_REGION_BEFORE*/

+#ifndef MEMP_SANITY_REGION_AFTER

+#define MEMP_SANITY_REGION_AFTER   16

+#endif /* MEMP_SANITY_REGION_AFTER*/

+#if MEMP_SANITY_REGION_AFTER > 0

+#define MEMP_SANITY_REGION_AFTER_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)

+#else

+#define MEMP_SANITY_REGION_AFTER_ALIGNED     0

+#endif /* MEMP_SANITY_REGION_AFTER*/

+

+/* MEMP_SIZE: save space for struct memp and for sanity check */

+#define MEMP_SIZE          (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)

+#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)

+

+#else /* MEMP_OVERFLOW_CHECK */

+

+/* No sanity checks

+ * We don't need to preserve the struct memp while not allocated, so we

+ * can save a little space and set MEMP_SIZE to 0.

+ */

+#define MEMP_SIZE           0

+#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))

+

+#endif /* MEMP_OVERFLOW_CHECK */

+

+/** This array holds the first free element of each pool.

+ *  Elements form a linked list. */

+static struct memp *memp_tab[MEMP_MAX];

+

+/** This array holds the element sizes of each pool. */

+#if !MEM_USE_POOLS

+static

+#endif

+const u16_t memp_sizes[MEMP_MAX] = {

+#define LWIP_MEMPOOL(name,num,size,desc)  MEMP_ALIGN_SIZE(size),

+#include "lwip/memp_std.h"

+};

+

+/** This array holds the number of elements in each pool. */

+static const u16_t memp_num[MEMP_MAX] = {

+#define LWIP_MEMPOOL(name,num,size,desc)  (num),

+#include "lwip/memp_std.h"

+};

+

+/** This array holds a textual description of each pool. */

+#ifdef LWIP_DEBUG

+static const char *memp_desc[MEMP_MAX] = {

+#define LWIP_MEMPOOL(name,num,size,desc)  (desc),

+#include "lwip/memp_std.h"

+};

+#endif /* LWIP_DEBUG */

+

+/** This is the actual memory used by the pools. */

+static u8_t memp_memory[MEM_ALIGNMENT - 1

+#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )

+#include "lwip/memp_std.h"

+];

+

+#if MEMP_SANITY_CHECK

+/**

+ * Check that memp-lists don't form a circle

+ */

+static int

+memp_sanity(void)

+{

+  s16_t i, c;

+  struct memp *m, *n;

+

+  for (i = 0; i < MEMP_MAX; i++) {

+    for (m = memp_tab[i]; m != NULL; m = m->next) {

+      c = 1;

+      for (n = memp_tab[i]; n != NULL; n = n->next) {

+        if (n == m && --c < 0) {

+          return 0;

+        }

+      }

+    }

+  }

+  return 1;

+}

+#endif /* MEMP_SANITY_CHECK*/

+#if MEMP_OVERFLOW_CHECK

+/**

+ * Check if a memp element was victim of an overflow

+ * (e.g. the restricted area after it has been altered)

+ *

+ * @param p the memp element to check

+ * @param memp_size the element size of the pool p comes from

+ */

+static void

+memp_overflow_check_element(struct memp *p, u16_t memp_size)

+{

+  u16_t k;

+  u8_t *m;

+#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0

+  m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;

+  for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {

+    if (m[k] != 0xcd) {

+      LWIP_ASSERT("detected memp underflow!", 0);

+    }

+  }

+#endif

+#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0

+  m = (u8_t*)p + MEMP_SIZE + memp_size - MEMP_SANITY_REGION_AFTER_ALIGNED;

+  for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {

+    if (m[k] != 0xcd) {

+      LWIP_ASSERT("detected memp overflow!", 0);

+    }

+  }

+#endif

+}

+

+/**

+ * Do an overflow check for all elements in every pool.

+ *

+ * @see memp_overflow_check_element for a description of the check

+ */

+static void

+memp_overflow_check_all(void)

+{

+  u16_t i, j;

+  struct memp *p;

+

+  p = LWIP_MEM_ALIGN(memp_memory);

+  for (i = 0; i < MEMP_MAX; ++i) {

+    p = p;

+    for (j = 0; j < memp_num[i]; ++j) {

+      memp_overflow_check_element(p, memp_sizes[i]);

+      p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i]);

+    }

+  }

+}

+

+/**

+ * Initialize the restricted areas of all memp elements in every pool.

+ */

+static void

+memp_overflow_init(void)

+{

+  u16_t i, j;

+  struct memp *p;

+  u8_t *m;

+

+  p = LWIP_MEM_ALIGN(memp_memory);

+  for (i = 0; i < MEMP_MAX; ++i) {

+    p = p;

+    for (j = 0; j < memp_num[i]; ++j) {

+#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0

+      m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;

+      memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);

+#endif

+#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0

+      m = (u8_t*)p + MEMP_SIZE + memp_sizes[i] - MEMP_SANITY_REGION_AFTER_ALIGNED;

+      memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);

+#endif

+      p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i]);

+    }

+  }

+}

+#endif /* MEMP_OVERFLOW_CHECK */

+

+/**

+ * Initialize this module.

+ *

+ * Carves out memp_memory into linked lists for each pool-type.

+ */

+void

+memp_init(void)

+{

+  struct memp *memp;

+  u16_t i, j;

+

+#if MEMP_STATS

+  for (i = 0; i < MEMP_MAX; ++i) {

+    lwip_stats.memp[i].used = lwip_stats.memp[i].max =

+      lwip_stats.memp[i].err = 0;

+    lwip_stats.memp[i].avail = memp_num[i];

+  }

+#endif /* MEMP_STATS */

+

+  memp = LWIP_MEM_ALIGN(memp_memory);

+  /* for every pool: */

+  for (i = 0; i < MEMP_MAX; ++i) {

+    memp_tab[i] = NULL;

+    /* create a linked list of memp elements */

+    for (j = 0; j < memp_num[i]; ++j) {

+      memp->next = memp_tab[i];

+      memp_tab[i] = memp;

+      memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]);

+    }

+  }

+#if MEMP_OVERFLOW_CHECK

+  memp_overflow_init();

+  /* check everything a first time to see if it worked */

+  memp_overflow_check_all();

+#endif /* MEMP_OVERFLOW_CHECK */

+}

+

+/**

+ * Get an element from a specific pool.

+ *

+ * @param type the pool to get an element from

+ *

+ * the debug version has two more parameters:

+ * @param file file name calling this function

+ * @param line number of line where this function is called

+ *

+ * @return a pointer to the allocated memory or a NULL pointer on error

+ */

+void *

+#if !MEMP_OVERFLOW_CHECK

+memp_malloc(memp_t type)

+#else

+memp_malloc_fn(memp_t type, const char* file, const int line)

+#endif

+{

+  struct memp *memp;

+  SYS_ARCH_DECL_PROTECT(old_level);

+

+  LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);

+

+  SYS_ARCH_PROTECT(old_level);

+#if MEMP_OVERFLOW_CHECK >= 2

+  memp_overflow_check_all();

+#endif /* MEMP_OVERFLOW_CHECK >= 2 */

+

+  memp = memp_tab[type];

+

+  if (memp != NULL) {

+    memp_tab[type] = memp->next;

+#if MEMP_OVERFLOW_CHECK

+    memp->next = NULL;

+    memp->file = file;

+    memp->line = line;

+#endif /* MEMP_OVERFLOW_CHECK */

+#if MEMP_STATS

+    ++lwip_stats.memp[type].used;

+    if (lwip_stats.memp[type].used > lwip_stats.memp[type].max) {

+      lwip_stats.memp[type].max = lwip_stats.memp[type].used;

+    }

+#endif /* MEMP_STATS */

+    LWIP_ASSERT("memp_malloc: memp properly aligned",

+                ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);

+    memp = (struct memp*)((u8_t*)memp + MEMP_SIZE);

+  } else {

+    LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));

+#if MEMP_STATS

+    ++lwip_stats.memp[type].err;

+#endif /* MEMP_STATS */

+  }

+

+  SYS_ARCH_UNPROTECT(old_level);

+

+  return memp;

+}

+

+/**

+ * Put an element back into its pool.

+ *

+ * @param type the pool where to put mem

+ * @param mem the memp element to free

+ */

+void

+memp_free(memp_t type, void *mem)

+{

+  struct memp *memp;

+  SYS_ARCH_DECL_PROTECT(old_level);

+

+  if (mem == NULL) {

+    return;

+  }

+  LWIP_ASSERT("memp_free: mem properly aligned",

+                ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);

+

+  memp = (struct memp *)((u8_t*)mem - MEMP_SIZE);

+

+  SYS_ARCH_PROTECT(old_level);

+#if MEMP_OVERFLOW_CHECK

+#if MEMP_OVERFLOW_CHECK >= 2

+  memp_overflow_check_all();

+#else

+  memp_overflow_check_element(memp, memp_sizes[type]);

+#endif /* MEMP_OVERFLOW_CHECK >= 2 */

+#endif /* MEMP_OVERFLOW_CHECK */

+

+#if MEMP_STATS

+  lwip_stats.memp[type].used--;

+#endif /* MEMP_STATS */

+

+  memp->next = memp_tab[type];

+  memp_tab[type] = memp;

+

+#if MEMP_SANITY_CHECK

+  LWIP_ASSERT("memp sanity", memp_sanity());

+#endif /* MEMP_SANITY_CHECK */

+

+  SYS_ARCH_UNPROTECT(old_level);

+}

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/netif.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/netif.c
new file mode 100644
index 0000000..362c6ae
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/netif.c
@@ -0,0 +1,499 @@
+/**

+ * @file

+ * lwIP network interface abstraction

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#include "lwip/def.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/tcp.h"

+#include "lwip/snmp.h"

+#include "lwip/igmp.h"

+#include "netif/etharp.h"

+

+#if LWIP_NETIF_STATUS_CALLBACK

+#define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); }

+#else

+#define NETIF_STATUS_CALLBACK(n) { /* NOP */ }

+#endif /* LWIP_NETIF_STATUS_CALLBACK */

+

+#if LWIP_NETIF_LINK_CALLBACK

+#define NETIF_LINK_CALLBACK(n) { if (n->link_callback) (n->link_callback)(n); }

+#else

+#define NETIF_LINK_CALLBACK(n) { /* NOP */ }

+#endif /* LWIP_NETIF_LINK_CALLBACK */

+

+struct netif *netif_list;

+struct netif *netif_default;

+

+/**

+ * Add a network interface to the list of lwIP netifs.

+ *

+ * @param netif a pre-allocated netif structure

+ * @param ipaddr IP address for the new netif

+ * @param netmask network mask for the new netif

+ * @param gw default gateway IP address for the new netif

+ * @param state opaque data passed to the new netif

+ * @param init callback function that initializes the interface

+ * @param input callback function that is called to pass

+ * ingress packets up in the protocol layer stack.

+ *

+ * @return netif, or NULL if failed.

+ */

+struct netif *

+netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,

+  struct ip_addr *gw,

+  void *state,

+  err_t (* init)(struct netif *netif),

+  err_t (* input)(struct pbuf *p, struct netif *netif))

+{

+  static u8_t netifnum = 0;

+

+  /* reset new interface configuration state */

+  netif->ip_addr.addr = 0;

+  netif->netmask.addr = 0;

+  netif->gw.addr = 0;

+  netif->flags = 0;

+#if LWIP_DHCP

+  /* netif not under DHCP control by default */

+  netif->dhcp = NULL;

+#endif /* LWIP_DHCP */

+#if LWIP_AUTOIP

+  /* netif not under AutoIP control by default */

+  netif->autoip = NULL;

+#endif /* LWIP_AUTOIP */

+#if LWIP_NETIF_STATUS_CALLBACK

+  netif->status_callback = NULL;

+#endif /* LWIP_NETIF_STATUS_CALLBACK */

+#if LWIP_NETIF_LINK_CALLBACK

+  netif->link_callback = NULL;

+#endif /* LWIP_NETIF_LINK_CALLBACK */

+#if LWIP_IGMP

+  netif->igmp_mac_filter = NULL;

+#endif /* LWIP_IGMP */

+

+  /* remember netif specific state information data */

+  netif->state = state;

+  netif->num = netifnum++;

+  netif->input = input;

+#if LWIP_NETIF_HWADDRHINT

+  netif->addr_hint = NULL;

+#endif /* LWIP_NETIF_HWADDRHINT*/

+

+  netif_set_addr(netif, ipaddr, netmask, gw);

+

+  /* call user specified initialization function for netif */

+  if (init(netif) != ERR_OK) {

+    return NULL;

+  }

+

+  /* add this netif to the list */

+  netif->next = netif_list;

+  netif_list = netif;

+  snmp_inc_iflist();

+

+#if LWIP_IGMP

+  /* start IGMP processing */

+  if (netif->flags & NETIF_FLAG_IGMP) {

+    igmp_start( netif);

+  }

+#endif /* LWIP_IGMP */

+

+  LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ",

+    netif->name[0], netif->name[1]));

+  ip_addr_debug_print(NETIF_DEBUG, ipaddr);

+  LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));

+  ip_addr_debug_print(NETIF_DEBUG, netmask);

+  LWIP_DEBUGF(NETIF_DEBUG, (" gw "));

+  ip_addr_debug_print(NETIF_DEBUG, gw);

+  LWIP_DEBUGF(NETIF_DEBUG, ("\n"));

+  return netif;

+}

+

+/**

+ * Change IP address configuration for a network interface (including netmask

+ * and default gateway).

+ *

+ * @param netif the network interface to change

+ * @param ipaddr the new IP address

+ * @param netmask the new netmask

+ * @param gw the new default gateway

+ */

+void

+netif_set_addr(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,

+    struct ip_addr *gw)

+{

+  netif_set_ipaddr(netif, ipaddr);

+  netif_set_netmask(netif, netmask);

+  netif_set_gw(netif, gw);

+}

+

+/**

+ * Remove a network interface from the list of lwIP netifs.

+ *

+ * @param netif the network interface to remove

+ */

+void netif_remove(struct netif * netif)

+{

+  if ( netif == NULL ) return;

+

+#if LWIP_IGMP

+  /* stop IGMP processing */

+  if (netif->flags & NETIF_FLAG_IGMP) {

+    igmp_stop( netif);

+  }

+#endif /* LWIP_IGMP */

+

+  snmp_delete_ipaddridx_tree(netif);

+

+  /*  is it the first netif? */

+  if (netif_list == netif) {

+    netif_list = netif->next;

+    snmp_dec_iflist();

+  }

+  else {

+    /*  look for netif further down the list */

+    struct netif * tmpNetif;

+    for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {

+      if (tmpNetif->next == netif) {

+        tmpNetif->next = netif->next;

+        snmp_dec_iflist();

+        break;

+      }

+    }

+    if (tmpNetif == NULL)

+      return; /*  we didn't find any netif today */

+  }

+  /* this netif is default? */

+  if (netif_default == netif)

+    /* reset default netif */

+    netif_set_default(NULL);

+  LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );

+}

+

+/**

+ * Find a network interface by searching for its name

+ *

+ * @param name the name of the netif (like netif->name) plus concatenated number

+ * in ascii representation (e.g. 'en0')

+ */

+struct netif *

+netif_find(char *name)

+{

+  struct netif *netif;

+  u8_t num;

+

+  if (name == NULL) {

+    return NULL;

+  }

+

+  num = name[2] - '0';

+

+  for(netif = netif_list; netif != NULL; netif = netif->next) {

+    if (num == netif->num &&

+       name[0] == netif->name[0] &&

+       name[1] == netif->name[1]) {

+      LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1]));

+      return netif;

+    }

+  }

+  LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1]));

+  return NULL;

+}

+

+/**

+ * Change the IP address of a network interface

+ *

+ * @param netif the network interface to change

+ * @param ipaddr the new IP address

+ *

+ * @note call netif_set_addr() if you also want to change netmask and

+ * default gateway

+ */

+void

+netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)

+{

+  /* TODO: Handling of obsolete pcbs */

+  /* See:  http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */

+#if LWIP_TCP

+  struct tcp_pcb *pcb;

+  struct tcp_pcb_listen *lpcb;

+

+  /* address is actually being changed? */

+  if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0)

+  {

+    /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */

+    LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: netif address being changed\n"));

+    pcb = tcp_active_pcbs;

+    while (pcb != NULL) {

+      /* PCB bound to current local interface address? */

+      if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {

+        /* this connection must be aborted */

+        struct tcp_pcb *next = pcb->next;

+        LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));

+        tcp_abort(pcb);

+        pcb = next;

+      } else {

+        pcb = pcb->next;

+      }

+    }

+    for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {

+      /* PCB bound to current local interface address? */

+      if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&

+          (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {

+        /* The PCB is listening to the old ipaddr and

+         * is set to listen to the new one instead */

+        ip_addr_set(&(lpcb->local_ip), ipaddr);

+      }

+    }

+  }

+#endif

+  snmp_delete_ipaddridx_tree(netif);

+  snmp_delete_iprteidx_tree(0,netif);

+  /* set new IP address to netif */

+  ip_addr_set(&(netif->ip_addr), ipaddr);

+  snmp_insert_ipaddridx_tree(netif);

+  snmp_insert_iprteidx_tree(0,netif);

+

+  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",

+    netif->name[0], netif->name[1],

+    ip4_addr1(&netif->ip_addr),

+    ip4_addr2(&netif->ip_addr),

+    ip4_addr3(&netif->ip_addr),

+    ip4_addr4(&netif->ip_addr)));

+}

+

+/**

+ * Change the default gateway for a network interface

+ *

+ * @param netif the network interface to change

+ * @param gw the new default gateway

+ *

+ * @note call netif_set_addr() if you also want to change ip address and netmask

+ */

+void

+netif_set_gw(struct netif *netif, struct ip_addr *gw)

+{

+  ip_addr_set(&(netif->gw), gw);

+  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",

+    netif->name[0], netif->name[1],

+    ip4_addr1(&netif->gw),

+    ip4_addr2(&netif->gw),

+    ip4_addr3(&netif->gw),

+    ip4_addr4(&netif->gw)));

+}

+

+/**

+ * Change the netmask of a network interface

+ *

+ * @param netif the network interface to change

+ * @param netmask the new netmask

+ *

+ * @note call netif_set_addr() if you also want to change ip address and

+ * default gateway

+ */

+void

+netif_set_netmask(struct netif *netif, struct ip_addr *netmask)

+{

+  snmp_delete_iprteidx_tree(0, netif);

+  /* set new netmask to netif */

+  ip_addr_set(&(netif->netmask), netmask);

+  snmp_insert_iprteidx_tree(0, netif);

+  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",

+    netif->name[0], netif->name[1],

+    ip4_addr1(&netif->netmask),

+    ip4_addr2(&netif->netmask),

+    ip4_addr3(&netif->netmask),

+    ip4_addr4(&netif->netmask)));

+}

+

+/**

+ * Set a network interface as the default network interface

+ * (used to output all packets for which no specific route is found)

+ *

+ * @param netif the default network interface

+ */

+void

+netif_set_default(struct netif *netif)

+{

+  if (netif == NULL)

+  {

+    /* remove default route */

+    snmp_delete_iprteidx_tree(1, netif);

+  }

+  else

+  {

+    /* install default route */

+    snmp_insert_iprteidx_tree(1, netif);

+  }

+  netif_default = netif;

+  LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",

+           netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));

+}

+

+/**

+ * Bring an interface up, available for processing

+ * traffic.

+ *

+ * @note: Enabling DHCP on a down interface will make it come

+ * up once configured.

+ *

+ * @see dhcp_start()

+ */

+void netif_set_up(struct netif *netif)

+{

+  if ( !(netif->flags & NETIF_FLAG_UP )) {

+    netif->flags |= NETIF_FLAG_UP;

+

+#if LWIP_SNMP

+    snmp_get_sysuptime(&netif->ts);

+#endif /* LWIP_SNMP */

+

+    NETIF_LINK_CALLBACK(netif);

+    NETIF_STATUS_CALLBACK(netif);

+

+#if LWIP_ARP

+    /** For Ethernet network interfaces, we would like to send a

+     *  "gratuitous ARP"; this is an ARP packet sent by a node in order

+     *  to spontaneously cause other nodes to update an entry in their

+     *  ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.

+     */

+    if (netif->flags & NETIF_FLAG_ETHARP) {

+      etharp_query(netif, &(netif->ip_addr), NULL);

+    }

+#endif /* LWIP_ARP */

+

+  }

+}

+

+/**

+ * Bring an interface down, disabling any traffic processing.

+ *

+ * @note: Enabling DHCP on a down interface will make it come

+ * up once configured.

+ *

+ * @see dhcp_start()

+ */

+void netif_set_down(struct netif *netif)

+{

+  if ( netif->flags & NETIF_FLAG_UP )

+    {

+      netif->flags &= ~NETIF_FLAG_UP;

+#if LWIP_SNMP

+      snmp_get_sysuptime(&netif->ts);

+#endif

+

+      NETIF_LINK_CALLBACK(netif);

+      NETIF_STATUS_CALLBACK(netif);

+    }

+}

+

+/**

+ * Ask if an interface is up

+ */

+u8_t netif_is_up(struct netif *netif)

+{

+  return (netif->flags & NETIF_FLAG_UP)?1:0;

+}

+

+#if LWIP_NETIF_STATUS_CALLBACK

+/**

+ * Set callback to be called when interface is brought up/down

+ */

+void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif ))

+{

+    if ( netif )

+        netif->status_callback = status_callback;

+}

+#endif /* LWIP_NETIF_STATUS_CALLBACK */

+

+#if LWIP_NETIF_LINK_CALLBACK

+/**

+ * Called by a driver when its link goes up

+ */

+void netif_set_link_up(struct netif *netif )

+{

+  netif->flags |= NETIF_FLAG_LINK_UP;

+

+#if LWIP_ARP

+  /** For Ethernet network interfaces, we would like to send a

+   *  "gratuitous ARP"; this is an ARP packet sent by a node in order

+   *  to spontaneously cause other nodes to update an entry in their

+   *  ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.

+   */

+  if (netif->flags & NETIF_FLAG_ETHARP) {

+    etharp_query(netif, &(netif->ip_addr), NULL);

+  }

+#endif /* LWIP_ARP */

+

+#if LWIP_IGMP

+  /* resend IGMP memberships */

+  if (netif->flags & NETIF_FLAG_IGMP) {

+    igmp_report_groups( netif);

+  }

+#endif /* LWIP_IGMP */

+

+  NETIF_LINK_CALLBACK(netif);

+}

+

+/**

+ * Called by a driver when its link goes down

+ */

+void netif_set_link_down(struct netif *netif )

+{

+  netif->flags &= ~NETIF_FLAG_LINK_UP;

+  NETIF_LINK_CALLBACK(netif);

+}

+

+/**

+ * Ask if a link is up

+ */

+u8_t netif_is_link_up(struct netif *netif)

+{

+  return (netif->flags & NETIF_FLAG_LINK_UP) ? 1 : 0;

+}

+

+/**

+ * Set callback to be called when link is brought up/down

+ */

+void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif ))

+{

+    if ( netif )

+        netif->link_callback = link_callback;

+}

+#endif /* LWIP_NETIF_LINK_CALLBACK */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/pbuf.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/pbuf.c
new file mode 100644
index 0000000..ecd5e16
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/pbuf.c
@@ -0,0 +1,777 @@
+/**

+ * @file

+ * Packet buffer management

+ *

+ * Packets are built from the pbuf data structure. It supports dynamic

+ * memory allocation for packet contents or can reference externally

+ * managed packet contents both in RAM and ROM. Quick allocation for

+ * incoming packets is provided through pools with fixed sized pbufs.

+ *

+ * A packet may span over multiple pbufs, chained as a singly linked

+ * list. This is called a "pbuf chain".

+ *

+ * Multiple packets may be queued, also using this singly linked list.

+ * This is called a "packet queue".

+ *

+ * So, a packet queue consists of one or more pbuf chains, each of

+ * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE

+ * NOT SUPPORTED!!! Use helper structs to queue multiple packets.

+ *

+ * The differences between a pbuf chain and a packet queue are very

+ * precise but subtle.

+ *

+ * The last pbuf of a packet has a ->tot_len field that equals the

+ * ->len field. It can be found by traversing the list. If the last

+ * pbuf of a packet has a ->next field other than NULL, more packets

+ * are on the queue.

+ *

+ * Therefore, looping through a pbuf of a single packet, has an

+ * loop end condition (tot_len == p->len), NOT (next == NULL).

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#include "lwip/stats.h"

+#include "lwip/def.h"

+#include "lwip/mem.h"

+#include "lwip/memp.h"

+#include "lwip/pbuf.h"

+#include "lwip/sys.h"

+#include "arch/perf.h"

+

+#include <string.h>

+

+#define SIZEOF_STRUCT_PBUF        LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))

+/* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically

+   aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */

+#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)

+

+/**

+ * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).

+ *

+ * The actual memory allocated for the pbuf is determined by the

+ * layer at which the pbuf is allocated and the requested size

+ * (from the size parameter).

+ *

+ * @param layer flag to define header size

+ * @param length size of the pbuf's payload

+ * @param type this parameter decides how and where the pbuf

+ * should be allocated as follows:

+ *

+ * - PBUF_RAM: buffer memory for pbuf is allocated as one large

+ *             chunk. This includes protocol headers as well.

+ * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for

+ *             protocol headers. Additional headers must be prepended

+ *             by allocating another pbuf and chain in to the front of

+ *             the ROM pbuf. It is assumed that the memory used is really

+ *             similar to ROM in that it is immutable and will not be

+ *             changed. Memory which is dynamic should generally not

+ *             be attached to PBUF_ROM pbufs. Use PBUF_REF instead.

+ * - PBUF_REF: no buffer memory is allocated for the pbuf, even for

+ *             protocol headers. It is assumed that the pbuf is only

+ *             being used in a single thread. If the pbuf gets queued,

+ *             then pbuf_take should be called to copy the buffer.

+ * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from

+ *              the pbuf pool that is allocated during pbuf_init().

+ *

+ * @return the allocated pbuf. If multiple pbufs where allocated, this

+ * is the first pbuf of a pbuf chain.

+ */

+struct pbuf *

+pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)

+{

+  struct pbuf *p, *q, *r;

+  u16_t offset;

+  s32_t rem_len; /* remaining length */

+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F")\n", length));

+

+  /* determine header offset */

+  offset = 0;

+  switch (layer) {

+  case PBUF_TRANSPORT:

+    /* add room for transport (often TCP) layer header */

+    offset += PBUF_TRANSPORT_HLEN;

+    /* FALLTHROUGH */

+  case PBUF_IP:

+    /* add room for IP layer header */

+    offset += PBUF_IP_HLEN;

+    /* FALLTHROUGH */

+  case PBUF_LINK:

+    /* add room for link layer header */

+    offset += PBUF_LINK_HLEN;

+    break;

+  case PBUF_RAW:

+    break;

+  default:

+    LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);

+    return NULL;

+  }

+

+  switch (type) {

+  case PBUF_POOL:

+    /* allocate head of pbuf chain into p */

+      p = memp_malloc(MEMP_PBUF_POOL);

+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));

+    if (p == NULL) {

+      return NULL;

+    }

+    p->type = type;

+    p->next = NULL;

+

+    /* make the payload pointer point 'offset' bytes into pbuf data memory */

+    p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));

+    LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",

+            ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);

+    /* the total length of the pbuf chain is the requested size */

+    p->tot_len = length;

+    /* set the length of the first pbuf in the chain */

+    p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));

+    LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",

+                ((u8_t*)p->payload + p->len <=

+                 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));

+    /* set reference count (needed here in case we fail) */

+    p->ref = 1;

+

+    /* now allocate the tail of the pbuf chain */

+

+    /* remember first pbuf for linkage in next iteration */

+    r = p;

+    /* remaining length to be allocated */

+    rem_len = length - p->len;

+    /* any remaining pbufs to be allocated? */

+    while (rem_len > 0) {

+      q = memp_malloc(MEMP_PBUF_POOL);

+      if (q == NULL) {

+        /* free chain so far allocated */

+        pbuf_free(p);

+        /* bail out unsuccesfully */

+        return NULL;

+      }

+      q->type = type;

+      q->flags = 0;

+      q->next = NULL;

+      /* make previous pbuf point to this pbuf */

+      r->next = q;

+      /* set total length of this pbuf and next in chain */

+      LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff);

+      q->tot_len = (u16_t)rem_len;

+      /* this pbuf length is pool size, unless smaller sized tail */

+      q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);

+      q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);

+      LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",

+              ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);

+      LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",

+                  ((u8_t*)p->payload + p->len <=

+                   (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));

+      q->ref = 1;

+      /* calculate remaining length to be allocated */

+      rem_len -= q->len;

+      /* remember this pbuf for linkage in next iteration */

+      r = q;

+    }

+    /* end of chain */

+    /*r->next = NULL;*/

+

+    break;

+  case PBUF_RAM:

+    /* If pbuf is to be allocated in RAM, allocate memory for it. */

+    p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));

+    if (p == NULL) {

+      return NULL;

+    }

+    /* Set up internal structure of the pbuf. */

+    p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));

+    p->len = p->tot_len = length;

+    p->next = NULL;

+    p->type = type;

+

+    LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",

+           ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);

+    break;

+  /* pbuf references existing (non-volatile static constant) ROM payload? */

+  case PBUF_ROM:

+  /* pbuf references existing (externally allocated) RAM payload? */

+  case PBUF_REF:

+    /* only allocate memory for the pbuf structure */

+    p = memp_malloc(MEMP_PBUF);

+    if (p == NULL) {

+      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",

+                  (type == PBUF_ROM) ? "ROM" : "REF"));

+      return NULL;

+    }

+    /* caller must set this field properly, afterwards */

+    p->payload = NULL;

+    p->len = p->tot_len = length;

+    p->next = NULL;

+    p->type = type;

+    break;

+  default:

+    LWIP_ASSERT("pbuf_alloc: erroneous type", 0);

+    return NULL;

+  }

+  /* set reference count */

+  p->ref = 1;

+  /* set flags */

+  p->flags = 0;

+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));

+  return p;

+}

+

+

+/**

+ * Shrink a pbuf chain to a desired length.

+ *

+ * @param p pbuf to shrink.

+ * @param new_len desired new length of pbuf chain

+ *

+ * Depending on the desired length, the first few pbufs in a chain might

+ * be skipped and left unchanged. The new last pbuf in the chain will be

+ * resized, and any remaining pbufs will be freed.

+ *

+ * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.

+ * @note May not be called on a packet queue.

+ *

+ * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain).

+ */

+void

+pbuf_realloc(struct pbuf *p, u16_t new_len)

+{

+  struct pbuf *q;

+  u16_t rem_len; /* remaining length */

+  s32_t grow;

+

+  LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||

+              p->type == PBUF_ROM ||

+              p->type == PBUF_RAM ||

+              p->type == PBUF_REF);

+

+  /* desired length larger than current length? */

+  if (new_len >= p->tot_len) {

+    /* enlarging not yet supported */

+    return;

+  }

+

+  /* the pbuf chain grows by (new_len - p->tot_len) bytes

+   * (which may be negative in case of shrinking) */

+  grow = new_len - p->tot_len;

+

+  /* first, step over any pbufs that should remain in the chain */

+  rem_len = new_len;

+  q = p;

+  /* should this pbuf be kept? */

+  while (rem_len > q->len) {

+    /* decrease remaining length by pbuf length */

+    rem_len -= q->len;

+    /* decrease total length indicator */

+    LWIP_ASSERT("grow < max_u16_t", grow < 0xffff);

+    q->tot_len += (u16_t)grow;

+    /* proceed to next pbuf in chain */

+    q = q->next;

+  }

+  /* we have now reached the new last pbuf (in q) */

+  /* rem_len == desired length for pbuf q */

+

+  /* shrink allocated memory for PBUF_RAM */

+  /* (other types merely adjust their length fields */

+  if ((q->type == PBUF_RAM) && (rem_len != q->len)) {

+    /* reallocate and adjust the length of the pbuf that will be split */

+    q = mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);

+    LWIP_ASSERT("mem_realloc give q == NULL", q != NULL);

+  }

+  /* adjust length fields for new last pbuf */

+  q->len = rem_len;

+  q->tot_len = q->len;

+

+  /* any remaining pbufs in chain? */

+  if (q->next != NULL) {

+    /* free remaining pbufs in chain */

+    pbuf_free(q->next);

+  }

+  /* q is last packet in chain */

+  q->next = NULL;

+

+}

+

+/**

+ * Adjusts the payload pointer to hide or reveal headers in the payload.

+ *

+ * Adjusts the ->payload pointer so that space for a header

+ * (dis)appears in the pbuf payload.

+ *

+ * The ->payload, ->tot_len and ->len fields are adjusted.

+ *

+ * @param p pbuf to change the header size.

+ * @param header_size_increment Number of bytes to increment header size which

+ * increases the size of the pbuf. New space is on the front.

+ * (Using a negative value decreases the header size.)

+ * If hdr_size_inc is 0, this function does nothing and returns succesful.

+ *

+ * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so

+ * the call will fail. A check is made that the increase in header size does

+ * not move the payload pointer in front of the start of the buffer.

+ * @return non-zero on failure, zero on success.

+ *

+ */

+u8_t

+pbuf_header(struct pbuf *p, s16_t header_size_increment)

+{

+  u16_t type;

+  void *payload;

+  u16_t increment_magnitude;

+

+  LWIP_ASSERT("p != NULL", p != NULL);

+  if ((header_size_increment == 0) || (p == NULL))

+    return 0;

+

+  if (header_size_increment < 0){

+    increment_magnitude = -header_size_increment;

+    /* Check that we aren't going to move off the end of the pbuf */

+    LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);

+  } else {

+    increment_magnitude = header_size_increment;

+#if 0

+    /* Can't assert these as some callers speculatively call

+         pbuf_header() to see if it's OK.  Will return 1 below instead. */

+    /* Check that we've got the correct type of pbuf to work with */

+    LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL",

+                p->type == PBUF_RAM || p->type == PBUF_POOL);

+    /* Check that we aren't going to move off the beginning of the pbuf */

+    LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF",

+                (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF);

+#endif

+  }

+

+  type = p->type;

+  /* remember current payload pointer */

+  payload = p->payload;

+

+  /* pbuf types containing payloads? */

+  if (type == PBUF_RAM || type == PBUF_POOL) {

+    /* set new payload pointer */

+    p->payload = (u8_t *)p->payload - header_size_increment;

+    /* boundary check fails? */

+    if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {

+      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",

+        (void *)p->payload,

+        (void *)(p + 1)));\

+      /* restore old payload pointer */

+      p->payload = payload;

+      /* bail out unsuccesfully */

+      return 1;

+    }

+  /* pbuf types refering to external payloads? */

+  } else if (type == PBUF_REF || type == PBUF_ROM) {

+    /* hide a header in the payload? */

+    if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {

+      /* increase payload pointer */

+      p->payload = (u8_t *)p->payload - header_size_increment;

+    } else {

+      /* cannot expand payload to front (yet!)

+       * bail out unsuccesfully */

+      return 1;

+    }

+  }

+  else {

+    /* Unknown type */

+    LWIP_ASSERT("bad pbuf type", 0);

+    return 1;

+  }

+  /* modify pbuf length fields */

+  p->len += header_size_increment;

+  p->tot_len += header_size_increment;

+

+  LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n",

+    (void *)payload, (void *)p->payload, header_size_increment));

+

+  return 0;

+}

+

+/**

+ * Dereference a pbuf chain or queue and deallocate any no-longer-used

+ * pbufs at the head of this chain or queue.

+ *

+ * Decrements the pbuf reference count. If it reaches zero, the pbuf is

+ * deallocated.

+ *

+ * For a pbuf chain, this is repeated for each pbuf in the chain,

+ * up to the first pbuf which has a non-zero reference count after

+ * decrementing. So, when all reference counts are one, the whole

+ * chain is free'd.

+ *

+ * @param p The pbuf (chain) to be dereferenced.

+ *

+ * @return the number of pbufs that were de-allocated

+ * from the head of the chain.

+ *

+ * @note MUST NOT be called on a packet queue (Not verified to work yet).

+ * @note the reference counter of a pbuf equals the number of pointers

+ * that refer to the pbuf (or into the pbuf).

+ *

+ * @internal examples:

+ *

+ * Assuming existing chains a->b->c with the following reference

+ * counts, calling pbuf_free(a) results in:

+ *

+ * 1->2->3 becomes ...1->3

+ * 3->3->3 becomes 2->3->3

+ * 1->1->2 becomes ......1

+ * 2->1->1 becomes 1->1->1

+ * 1->1->1 becomes .......

+ *

+ */

+u8_t

+pbuf_free(struct pbuf *p)

+{

+  u16_t type;

+  struct pbuf *q;

+  u8_t count;

+

+  if (p == NULL) {

+    LWIP_ASSERT("p != NULL", p != NULL);

+    /* if assertions are disabled, proceed with debug output */

+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));

+    return 0;

+  }

+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p));

+

+  PERF_START;

+

+  LWIP_ASSERT("pbuf_free: sane type",

+    p->type == PBUF_RAM || p->type == PBUF_ROM ||

+    p->type == PBUF_REF || p->type == PBUF_POOL);

+

+  count = 0;

+  /* de-allocate all consecutive pbufs from the head of the chain that

+   * obtain a zero reference count after decrementing*/

+  while (p != NULL) {

+    u16_t ref;

+    SYS_ARCH_DECL_PROTECT(old_level);

+    /* Since decrementing ref cannot be guaranteed to be a single machine operation

+     * we must protect it. We put the new ref into a local variable to prevent

+     * further protection. */

+    SYS_ARCH_PROTECT(old_level);

+    /* all pbufs in a chain are referenced at least once */

+    LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);

+    /* decrease reference count (number of pointers to pbuf) */

+    ref = --(p->ref);

+    SYS_ARCH_UNPROTECT(old_level);

+    /* this pbuf is no longer referenced to? */

+    if (ref == 0) {

+      /* remember next pbuf in chain for next iteration */

+      q = p->next;

+      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p));

+      type = p->type;

+      /* is this a pbuf from the pool? */

+      if (type == PBUF_POOL) {

+        memp_free(MEMP_PBUF_POOL, p);

+      /* is this a ROM or RAM referencing pbuf? */

+      } else if (type == PBUF_ROM || type == PBUF_REF) {

+        memp_free(MEMP_PBUF, p);

+      /* type == PBUF_RAM */

+      } else {

+        mem_free(p);

+      }

+      count++;

+      /* proceed to next pbuf */

+      p = q;

+    /* p->ref > 0, this pbuf is still referenced to */

+    /* (and so the remaining pbufs in chain as well) */

+    } else {

+      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));

+      /* stop walking through the chain */

+      p = NULL;

+    }

+  }

+  PERF_STOP("pbuf_free");

+  /* return number of de-allocated pbufs */

+  return count;

+}

+

+/**

+ * Count number of pbufs in a chain

+ *

+ * @param p first pbuf of chain

+ * @return the number of pbufs in a chain

+ */

+

+u8_t

+pbuf_clen(struct pbuf *p)

+{

+  u8_t len;

+

+  len = 0;

+  while (p != NULL) {

+    ++len;

+    p = p->next;

+  }

+  return len;

+}

+

+/**

+ * Increment the reference count of the pbuf.

+ *

+ * @param p pbuf to increase reference counter of

+ *

+ */

+void

+pbuf_ref(struct pbuf *p)

+{

+  SYS_ARCH_DECL_PROTECT(old_level);

+  /* pbuf given? */

+  if (p != NULL) {

+    SYS_ARCH_PROTECT(old_level);

+    ++(p->ref);

+    SYS_ARCH_UNPROTECT(old_level);

+  }

+}

+

+/**

+ * Concatenate two pbufs (each may be a pbuf chain) and take over

+ * the caller's reference of the tail pbuf.

+ *

+ * @note The caller MAY NOT reference the tail pbuf afterwards.

+ * Use pbuf_chain() for that purpose.

+ *

+ * @see pbuf_chain()

+ */

+

+void

+pbuf_cat(struct pbuf *h, struct pbuf *t)

+{

+  struct pbuf *p;

+

+  LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",

+             ((h != NULL) && (t != NULL)), return;);

+

+  /* proceed to last pbuf of chain */

+  for (p = h; p->next != NULL; p = p->next) {

+    /* add total length of second chain to all totals of first chain */

+    p->tot_len += t->tot_len;

+  }

+  /* { p is last pbuf of first h chain, p->next == NULL } */

+  LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);

+  LWIP_ASSERT("p->next == NULL", p->next == NULL);

+  /* add total length of second chain to last pbuf total of first chain */

+  p->tot_len += t->tot_len;

+  /* chain last pbuf of head (p) with first of tail (t) */

+  p->next = t;

+  /* p->next now references t, but the caller will drop its reference to t,

+   * so netto there is no change to the reference count of t.

+   */

+}

+

+/**

+ * Chain two pbufs (or pbuf chains) together.

+ *

+ * The caller MUST call pbuf_free(t) once it has stopped

+ * using it. Use pbuf_cat() instead if you no longer use t.

+ *

+ * @param h head pbuf (chain)

+ * @param t tail pbuf (chain)

+ * @note The pbufs MUST belong to the same packet.

+ * @note MAY NOT be called on a packet queue.

+ *

+ * The ->tot_len fields of all pbufs of the head chain are adjusted.

+ * The ->next field of the last pbuf of the head chain is adjusted.

+ * The ->ref field of the first pbuf of the tail chain is adjusted.

+ *

+ */

+void

+pbuf_chain(struct pbuf *h, struct pbuf *t)

+{

+  pbuf_cat(h, t);

+  /* t is now referenced by h */

+  pbuf_ref(t);

+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));

+}

+

+/**

+ * Dechains the first pbuf from its succeeding pbufs in the chain.

+ *

+ * Makes p->tot_len field equal to p->len.

+ * @param p pbuf to dechain

+ * @return remainder of the pbuf chain, or NULL if it was de-allocated.

+ * @note May not be called on a packet queue.

+ */

+struct pbuf *

+pbuf_dechain(struct pbuf *p)

+{

+  struct pbuf *q;

+  u8_t tail_gone = 1;

+  /* tail */

+  q = p->next;

+  /* pbuf has successor in chain? */

+  if (q != NULL) {

+    /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */

+    LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);

+    /* enforce invariant if assertion is disabled */

+    q->tot_len = p->tot_len - p->len;

+    /* decouple pbuf from remainder */

+    p->next = NULL;

+    /* total length of pbuf p is its own length only */

+    p->tot_len = p->len;

+    /* q is no longer referenced by p, free it */

+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));

+    tail_gone = pbuf_free(q);

+    if (tail_gone > 0) {

+      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE,

+                  ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));

+    }

+    /* return remaining tail or NULL if deallocated */

+  }

+  /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */

+  LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);

+  return ((tail_gone > 0) ? NULL : q);

+}

+

+/**

+ *

+ * Create PBUF_RAM copies of pbufs.

+ *

+ * Used to queue packets on behalf of the lwIP stack, such as

+ * ARP based queueing.

+ *

+ * @note You MUST explicitly use p = pbuf_take(p);

+ *

+ * @note Only one packet is copied, no packet queue!

+ *

+ * @param p_to pbuf source of the copy

+ * @param p_from pbuf destination of the copy

+ *

+ * @return ERR_OK if pbuf was copied

+ *         ERR_ARG if one of the pbufs is NULL or p_to is not big

+ *                 enough to hold p_from

+ */

+err_t

+pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)

+{

+  u16_t offset_to=0, offset_from=0, len;

+

+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_copy(%p, %p)\n",

+    (void*)p_to, (void*)p_from));

+

+  /* is the target big enough to hold the source? */

+  LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&

+             (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);

+

+  /* iterate through pbuf chain */

+  do

+  {

+    LWIP_ASSERT("p_to != NULL", p_to != NULL);

+    /* copy one part of the original chain */

+    if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {

+      /* complete current p_from fits into current p_to */

+      len = p_from->len - offset_from;

+    } else {

+      /* current p_from does not fit into current p_to */

+      len = p_to->len - offset_to;

+    }

+    MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len);

+    offset_to += len;

+    offset_from += len;

+    LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);

+    if (offset_to == p_to->len) {

+      /* on to next p_to (if any) */

+      offset_to = 0;

+      p_to = p_to->next;

+    }

+    LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);

+    if (offset_from >= p_from->len) {

+      /* on to next p_from (if any) */

+      offset_from = 0;

+      p_from = p_from->next;

+    }

+

+    if((p_from != NULL) && (p_from->len == p_from->tot_len)) {

+      /* don't copy more than one packet! */

+      LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",

+                 (p_from->next == NULL), return ERR_VAL;);

+    }

+    if((p_to != NULL) && (p_to->len == p_to->tot_len)) {

+      /* don't copy more than one packet! */

+      LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",

+                  (p_to->next == NULL), return ERR_VAL;);

+    }

+  } while (p_from);

+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 1, ("pbuf_copy: end of chain reached.\n"));

+  return ERR_OK;

+}

+

+/**

+ * Copy (part of) the contents of a packet buffer

+ * to an application supplied buffer.

+ *

+ * @param buf the pbuf from which to copy data

+ * @param dataptr the application supplied buffer

+ * @param len length of data to copy (dataptr must be big enough)

+ * @param offset offset into the packet buffer from where to begin copying len bytes

+ */

+u16_t

+pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)

+{

+  struct pbuf *p;

+  u16_t left;

+  u16_t buf_copy_len;

+  u16_t copied_total = 0;

+

+  LWIP_ERROR("netbuf_copy_partial: invalid buf", (buf != NULL), return 0;);

+  LWIP_ERROR("netbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);

+

+  left = 0;

+

+  if((buf == NULL) || (dataptr == NULL)) {

+    return 0;

+  }

+

+  /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */

+  for(p = buf; len != 0 && p != NULL; p = p->next) {

+    if ((offset != 0) && (offset >= p->len)) {

+      /* don't copy from this buffer -> on to the next */

+      offset -= p->len;

+    } else {

+      /* copy from this buffer. maybe only partially. */

+      buf_copy_len = p->len - offset;

+      if (buf_copy_len > len)

+          buf_copy_len = len;

+      /* copy the necessary parts of the buffer */

+      MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);

+      copied_total += buf_copy_len;

+      left += buf_copy_len;

+      len -= buf_copy_len;

+      offset = 0;

+    }

+  }

+  return copied_total;

+}

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/raw.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/raw.c
new file mode 100644
index 0000000..2ba693b
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/raw.c
@@ -0,0 +1,336 @@
+/**

+ * @file

+ * Implementation of raw protocol PCBs for low-level handling of

+ * different types of protocols besides (or overriding) those

+ * already available in lwIP.

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/def.h"

+#include "lwip/memp.h"

+#include "lwip/inet.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/raw.h"

+#include "lwip/stats.h"

+#include "lwip/snmp.h"

+#include "arch/perf.h"

+

+#include <string.h>

+

+/** The list of RAW PCBs */

+static struct raw_pcb *raw_pcbs;

+

+/**

+ * Determine if in incoming IP packet is covered by a RAW PCB

+ * and if so, pass it to a user-provided receive callback function.

+ *

+ * Given an incoming IP datagram (as a chain of pbufs) this function

+ * finds a corresponding RAW PCB and calls the corresponding receive

+ * callback function.

+ *

+ * @param p pbuf to be demultiplexed to a RAW PCB.

+ * @param inp network interface on which the datagram was received.

+ * @return - 1 if the packet has been eaten by a RAW PCB receive

+ *           callback function. The caller MAY NOT not reference the

+ *           packet any longer, and MAY NOT call pbuf_free().

+ * @return - 0 if packet is not eaten (pbuf is still referenced by the

+ *           caller).

+ *

+ */

+u8_t

+raw_input(struct pbuf *p, struct netif *inp)

+{

+  struct raw_pcb *pcb, *prev;

+  struct ip_hdr *iphdr;

+  s16_t proto;

+  u8_t eaten = 0;

+

+  LWIP_UNUSED_ARG(inp);

+

+  iphdr = p->payload;

+  proto = IPH_PROTO(iphdr);

+

+  prev = NULL;

+  pcb = raw_pcbs;

+  /* loop through all raw pcbs until the packet is eaten by one */

+  /* this allows multiple pcbs to match against the packet by design */

+  while ((eaten == 0) && (pcb != NULL)) {

+    if (pcb->protocol == proto) {

+      /* receive callback function available? */

+      if (pcb->recv != NULL) {

+        /* the receive callback function did not eat the packet? */

+        if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0)

+        {

+          /* receive function ate the packet */

+          p = NULL;

+          eaten = 1;

+          if (prev != NULL) {

+          /* move the pcb to the front of raw_pcbs so that is

+             found faster next time */

+            prev->next = pcb->next;

+            pcb->next = raw_pcbs;

+            raw_pcbs = pcb;

+          }

+        }

+      }

+      /* no receive callback function was set for this raw PCB */

+      /* drop the packet */

+    }

+    prev = pcb;

+    pcb = pcb->next;

+  }

+  return eaten;

+}

+

+/**

+ * Bind a RAW PCB.

+ *

+ * @param pcb RAW PCB to be bound with a local address ipaddr.

+ * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to

+ * bind to all local interfaces.

+ *

+ * @return lwIP error code.

+ * - ERR_OK. Successful. No error occured.

+ * - ERR_USE. The specified IP address is already bound to by

+ * another RAW PCB.

+ *

+ * @see raw_disconnect()

+ */

+err_t

+raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr)

+{

+  ip_addr_set(&pcb->local_ip, ipaddr);

+  return ERR_OK;

+}

+

+/**

+ * Connect an RAW PCB. This function is required by upper layers

+ * of lwip. Using the raw api you could use raw_sendto() instead

+ *

+ * This will associate the RAW PCB with the remote address.

+ *

+ * @param pcb RAW PCB to be connected with remote address ipaddr and port.

+ * @param ipaddr remote IP address to connect with.

+ *

+ * @return lwIP error code

+ *

+ * @see raw_disconnect() and raw_sendto()

+ */

+err_t

+raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr)

+{

+  ip_addr_set(&pcb->remote_ip, ipaddr);

+  return ERR_OK;

+}

+

+

+/**

+ * Set the callback function for received packets that match the

+ * raw PCB's protocol and binding.

+ *

+ * The callback function MUST either

+ * - eat the packet by calling pbuf_free() and returning non-zero. The

+ *   packet will not be passed to other raw PCBs or other protocol layers.

+ * - not free the packet, and return zero. The packet will be matched

+ *   against further PCBs and/or forwarded to another protocol layers.

+ *

+ * @return non-zero if the packet was free()d, zero if the packet remains

+ * available for others.

+ */

+void

+raw_recv(struct raw_pcb *pcb,

+         u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p,

+                      struct ip_addr *addr),

+         void *recv_arg)

+{

+  /* remember recv() callback and user data */

+  pcb->recv = recv;

+  pcb->recv_arg = recv_arg;

+}

+

+/**

+ * Send the raw IP packet to the given address. Note that actually you cannot

+ * modify the IP headers (this is inconsistent with the receive callback where

+ * you actually get the IP headers), you can only specify the IP payload here.

+ * It requires some more changes in lwIP. (there will be a raw_send() function

+ * then.)

+ *

+ * @param pcb the raw pcb which to send

+ * @param p the IP payload to send

+ * @param ipaddr the destination address of the IP packet

+ *

+ */

+err_t

+raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)

+{

+  err_t err;

+  struct netif *netif;

+  struct ip_addr *src_ip;

+  struct pbuf *q; /* q will be sent down the stack */

+

+  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_sendto\n"));

+

+  /* not enough space to add an IP header to first pbuf in given p chain? */

+  if (pbuf_header(p, IP_HLEN)) {

+    /* allocate header in new pbuf */

+    q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);

+    /* new header pbuf could not be allocated? */

+    if (q == NULL) {

+      LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 2, ("raw_sendto: could not allocate header\n"));

+      return ERR_MEM;

+    }

+    /* chain header q in front of given pbuf p */

+    pbuf_chain(q, p);

+    /* { first pbuf q points to header pbuf } */

+    LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));

+  }  else {

+    /* first pbuf q equals given pbuf */

+    q = p;

+    if(pbuf_header(q, -IP_HLEN)) {

+      LWIP_ASSERT("Can't restore header we just removed!", 0);

+      return ERR_MEM;

+    }

+  }

+

+  if ((netif = ip_route(ipaddr)) == NULL) {

+    LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr));

+    /* free any temporary header pbuf allocated by pbuf_header() */

+    if (q != p) {

+      pbuf_free(q);

+    }

+    return ERR_RTE;

+  }

+

+  if (ip_addr_isany(&pcb->local_ip)) {

+    /* use outgoing network interface IP address as source address */

+    src_ip = &(netif->ip_addr);

+  } else {

+    /* use RAW PCB local IP address as source address */

+    src_ip = &(pcb->local_ip);

+  }

+

+#if LWIP_NETIF_HWADDRHINT

+  netif->addr_hint = &(pcb->addr_hint);

+#endif /* LWIP_NETIF_HWADDRHINT*/

+  err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);

+#if LWIP_NETIF_HWADDRHINT

+  netif->addr_hint = NULL;

+#endif /* LWIP_NETIF_HWADDRHINT*/

+

+  /* did we chain a header earlier? */

+  if (q != p) {

+    /* free the header */

+    pbuf_free(q);

+  }

+  return err;

+}

+

+/**

+ * Send the raw IP packet to the address given by raw_connect()

+ *

+ * @param pcb the raw pcb which to send

+ * @param p the IP payload to send

+ *

+ */

+err_t

+raw_send(struct raw_pcb *pcb, struct pbuf *p)

+{

+  return raw_sendto(pcb, p, &pcb->remote_ip);

+}

+

+/**

+ * Remove an RAW PCB.

+ *

+ * @param pcb RAW PCB to be removed. The PCB is removed from the list of

+ * RAW PCB's and the data structure is freed from memory.

+ *

+ * @see raw_new()

+ */

+void

+raw_remove(struct raw_pcb *pcb)

+{

+  struct raw_pcb *pcb2;

+  /* pcb to be removed is first in list? */

+  if (raw_pcbs == pcb) {

+    /* make list start at 2nd pcb */

+    raw_pcbs = raw_pcbs->next;

+    /* pcb not 1st in list */

+  } else {

+    for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {

+      /* find pcb in raw_pcbs list */

+      if (pcb2->next != NULL && pcb2->next == pcb) {

+        /* remove pcb from list */

+        pcb2->next = pcb->next;

+      }

+    }

+  }

+  memp_free(MEMP_RAW_PCB, pcb);

+}

+

+/**

+ * Create a RAW PCB.

+ *

+ * @return The RAW PCB which was created. NULL if the PCB data structure

+ * could not be allocated.

+ *

+ * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)

+ *

+ * @see raw_remove()

+ */

+struct raw_pcb *

+raw_new(u8_t proto) {

+  struct raw_pcb *pcb;

+

+  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_new\n"));

+

+  pcb = memp_malloc(MEMP_RAW_PCB);

+  /* could allocate RAW PCB? */

+  if (pcb != NULL) {

+    /* initialize PCB to all zeroes */

+    memset(pcb, 0, sizeof(struct raw_pcb));

+    pcb->protocol = proto;

+    pcb->ttl = RAW_TTL;

+    pcb->next = raw_pcbs;

+    raw_pcbs = pcb;

+  }

+  return pcb;

+}

+

+#endif /* LWIP_RAW */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/asn1_dec.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/asn1_dec.c
new file mode 100644
index 0000000..87288ac
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/asn1_dec.c
@@ -0,0 +1,657 @@
+/**

+ * @file

+ * Abstract Syntax Notation One (ISO 8824, 8825) decoding

+ *

+ * @todo not optimised (yet), favor correctness over speed, favor speed over size

+ */

+

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * Author: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/snmp_asn1.h"

+

+/**

+ * Retrieves type field from incoming pbuf chain.

+ *

+ * @param p points to a pbuf holding an ASN1 coded type field

+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field

+ * @param type return ASN1 type

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode

+ */

+err_t

+snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+      *type = *msg_ptr;

+      return ERR_OK;

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Decodes length field from incoming pbuf chain into host length.

+ *

+ * @param p points to a pbuf holding an ASN1 coded length

+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded length

+ * @param octets_used returns number of octets used by the length code

+ * @param length return host order length, upto 64k

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode

+ */

+err_t

+snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+

+      if (*msg_ptr < 0x80)

+      {

+        /* primitive definite length format */

+        *octets_used = 1;

+        *length = *msg_ptr;

+        return ERR_OK;

+      }

+      else if (*msg_ptr == 0x80)

+      {

+        /* constructed indefinite length format, termination with two zero octets */

+        u8_t zeros;

+        u8_t i;

+

+        *length = 0;

+        zeros = 0;

+        while (zeros != 2)

+        {

+          i = 2;

+          while (i > 0)

+          {

+            i--;

+            (*length) += 1;

+            ofs += 1;

+            if (ofs >= plen)

+            {

+              /* next octet in next pbuf */

+              p = p->next;

+              if (p == NULL) { return ERR_ARG; }

+              msg_ptr = p->payload;

+              plen += p->len;

+            }

+            else

+            {

+              /* next octet in same pbuf */

+              msg_ptr++;

+            }

+            if (*msg_ptr == 0)

+            {

+              zeros++;

+              if (zeros == 2)

+              {

+                /* stop while (i > 0) */

+                i = 0;

+              }

+            }

+            else

+            {

+              zeros = 0;

+            }

+          }

+        }

+        *octets_used = 1;

+        return ERR_OK;

+      }

+      else if (*msg_ptr == 0x81)

+      {

+        /* constructed definite length format, one octet */

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+        *length = *msg_ptr;

+        *octets_used = 2;

+        return ERR_OK;

+      }

+      else if (*msg_ptr == 0x82)

+      {

+        u8_t i;

+

+        /* constructed definite length format, two octets */

+        i = 2;

+        while (i > 0)

+        {

+          i--;

+          ofs += 1;

+          if (ofs >= plen)

+          {

+            /* next octet in next pbuf */

+            p = p->next;

+            if (p == NULL) { return ERR_ARG; }

+            msg_ptr = p->payload;

+            plen += p->len;

+          }

+          else

+          {

+            /* next octet in same pbuf */

+            msg_ptr++;

+          }

+          if (i == 0)

+          {

+            /* least significant length octet */

+            *length |= *msg_ptr;

+          }

+          else

+          {

+            /* most significant length octet */

+            *length = (*msg_ptr) << 8;

+          }

+        }

+        *octets_used = 3;

+        return ERR_OK;

+      }

+      else

+      {

+        /* constructed definite length format 3..127 octets, this is too big (>64k) */

+        /**  @todo: do we need to accept inefficient codings with many leading zero's? */

+        *octets_used = 1 + ((*msg_ptr) & 0x7f);

+        return ERR_ARG;

+      }

+    }

+    p = p->next;

+  }

+

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Decodes positive integer (counter, gauge, timeticks) into u32_t.

+ *

+ * @param p points to a pbuf holding an ASN1 coded integer

+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer

+ * @param len length of the coded integer field

+ * @param value return host order integer

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode

+ *

+ * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded

+ * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value

+ * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!

+ */

+err_t

+snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+      if ((len > 0) && (len < 6))

+      {

+        /* start from zero */

+        *value = 0;

+        if (*msg_ptr & 0x80)

+        {

+          /* negative, expecting zero sign bit! */

+          return ERR_ARG;

+        }

+        else

+        {

+          /* positive */

+          if ((len > 1) && (*msg_ptr == 0))

+          {

+            /* skip leading "sign byte" octet 0x00 */

+            len--;

+            ofs += 1;

+            if (ofs >= plen)

+            {

+              /* next octet in next pbuf */

+              p = p->next;

+              if (p == NULL) { return ERR_ARG; }

+              msg_ptr = p->payload;

+              plen += p->len;

+            }

+            else

+            {

+              /* next octet in same pbuf */

+              msg_ptr++;

+            }

+          }

+        }

+        /* OR octets with value */

+        while (len > 1)

+        {

+          len--;

+          *value |= *msg_ptr;

+          *value <<= 8;

+          ofs += 1;

+          if (ofs >= plen)

+          {

+            /* next octet in next pbuf */

+            p = p->next;

+            if (p == NULL) { return ERR_ARG; }

+            msg_ptr = p->payload;

+            plen += p->len;

+          }

+          else

+          {

+            /* next octet in same pbuf */

+            msg_ptr++;

+          }

+        }

+        *value |= *msg_ptr;

+        return ERR_OK;

+      }

+      else

+      {

+        return ERR_ARG;

+      }

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Decodes integer into s32_t.

+ *

+ * @param p points to a pbuf holding an ASN1 coded integer

+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer

+ * @param len length of the coded integer field

+ * @param value return host order integer

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode

+ *

+ * @note ASN coded integers are _always_ signed!

+ */

+err_t

+snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+#if BYTE_ORDER == LITTLE_ENDIAN

+  u8_t *lsb_ptr = (u8_t*)value;

+#endif

+#if BYTE_ORDER == BIG_ENDIAN

+  u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;

+#endif

+  u8_t sign;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+      if ((len > 0) && (len < 5))

+      {

+        if (*msg_ptr & 0x80)

+        {

+          /* negative, start from -1 */

+          *value = -1;

+          sign = 1;

+        }

+        else

+        {

+          /* positive, start from 0 */

+          *value = 0;

+          sign = 0;

+        }

+        /* OR/AND octets with value */

+        while (len > 1)

+        {

+          len--;

+          if (sign)

+          {

+            *lsb_ptr &= *msg_ptr;

+            *value <<= 8;

+            *lsb_ptr |= 255;

+          }

+          else

+          {

+            *lsb_ptr |= *msg_ptr;

+            *value <<= 8;

+          }

+          ofs += 1;

+          if (ofs >= plen)

+          {

+            /* next octet in next pbuf */

+            p = p->next;

+            if (p == NULL) { return ERR_ARG; }

+            msg_ptr = p->payload;

+            plen += p->len;

+          }

+          else

+          {

+            /* next octet in same pbuf */

+            msg_ptr++;

+          }

+        }

+        if (sign)

+        {

+          *lsb_ptr &= *msg_ptr;

+        }

+        else

+        {

+          *lsb_ptr |= *msg_ptr;

+        }

+        return ERR_OK;

+      }

+      else

+      {

+        return ERR_ARG;

+      }

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Decodes object identifier from incoming message into array of s32_t.

+ *

+ * @param p points to a pbuf holding an ASN1 coded object identifier

+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier

+ * @param len length of the coded object identifier

+ * @param oid return object identifier struct

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode

+ */

+err_t

+snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+  s32_t *oid_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+

+      oid->len = 0;

+      oid_ptr = &oid->id[0];

+      if (len > 0)

+      {

+        /* first compressed octet */

+        if (*msg_ptr == 0x2B)

+        {

+          /* (most) common case 1.3 (iso.org) */

+          *oid_ptr = 1;

+          oid_ptr++;

+          *oid_ptr = 3;

+          oid_ptr++;

+        }

+        else if (*msg_ptr < 40)

+        {

+          *oid_ptr = 0;

+          oid_ptr++;

+          *oid_ptr = *msg_ptr;

+          oid_ptr++;

+        }

+        else if (*msg_ptr < 80)

+        {

+          *oid_ptr = 1;

+          oid_ptr++;

+          *oid_ptr = (*msg_ptr) - 40;

+          oid_ptr++;

+        }

+        else

+        {

+          *oid_ptr = 2;

+          oid_ptr++;

+          *oid_ptr = (*msg_ptr) - 80;

+          oid_ptr++;

+        }

+        oid->len = 2;

+      }

+      else

+      {

+        /* accepting zero length identifiers e.g. for

+           getnext operation. uncommon but valid */

+        return ERR_OK;

+      }

+      len--;

+      if (len > 0)

+      {

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+          plen += p->len;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+      }

+      while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN))

+      {

+        /* sub-identifier uses multiple octets */

+        if (*msg_ptr & 0x80)

+        {

+          s32_t sub_id = 0;

+

+          while ((*msg_ptr & 0x80) && (len > 1))

+          {

+            len--;

+            sub_id = (sub_id << 7) + (*msg_ptr & ~0x80);

+            ofs += 1;

+            if (ofs >= plen)

+            {

+              /* next octet in next pbuf */

+              p = p->next;

+              if (p == NULL) { return ERR_ARG; }

+              msg_ptr = p->payload;

+              plen += p->len;

+            }

+            else

+            {

+              /* next octet in same pbuf */

+              msg_ptr++;

+            }

+          }

+          if (!(*msg_ptr & 0x80) && (len > 0))

+          {

+            /* last octet sub-identifier */

+            len--;

+            sub_id = (sub_id << 7) + *msg_ptr;

+            *oid_ptr = sub_id;

+          }

+        }

+        else

+        {

+          /* !(*msg_ptr & 0x80) sub-identifier uses single octet */

+          len--;

+          *oid_ptr = *msg_ptr;

+        }

+        if (len > 0)

+        {

+          /* remaining oid bytes available ... */

+          ofs += 1;

+          if (ofs >= plen)

+          {

+            /* next octet in next pbuf */

+            p = p->next;

+            if (p == NULL) { return ERR_ARG; }

+            msg_ptr = p->payload;

+            plen += p->len;

+          }

+          else

+          {

+            /* next octet in same pbuf */

+            msg_ptr++;

+          }

+        }

+        oid_ptr++;

+        oid->len++;

+      }

+      if (len == 0)

+      {

+        /* len == 0, end of oid */

+        return ERR_OK;

+      }

+      else

+      {

+        /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */

+        return ERR_ARG;

+      }

+

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)

+ * from incoming message into array.

+ *

+ * @param p points to a pbuf holding an ASN1 coded raw data

+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data

+ * @param len length of the coded raw data (zero is valid, e.g. empty string!)

+ * @param raw_len length of the raw return value

+ * @param raw return raw bytes

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode

+ */

+err_t

+snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  if (len > 0)

+  {

+    plen = 0;

+    while (p != NULL)

+    {

+      base = plen;

+      plen += p->len;

+      if (ofs < plen)

+      {

+        msg_ptr = p->payload;

+        msg_ptr += ofs - base;

+        if (raw_len >= len)

+        {

+          while (len > 1)

+          {

+            /* copy len - 1 octets */

+            len--;

+            *raw = *msg_ptr;

+            raw++;

+            ofs += 1;

+            if (ofs >= plen)

+            {

+              /* next octet in next pbuf */

+              p = p->next;

+              if (p == NULL) { return ERR_ARG; }

+              msg_ptr = p->payload;

+              plen += p->len;

+            }

+            else

+            {

+              /* next octet in same pbuf */

+              msg_ptr++;

+            }

+          }

+          /* copy last octet */

+          *raw = *msg_ptr;

+          return ERR_OK;

+        }

+        else

+        {

+          /* raw_len < len, not enough dst space */

+          return ERR_ARG;

+        }

+      }

+      p = p->next;

+    }

+    /* p == NULL, ofs >= plen */

+    return ERR_ARG;

+  }

+  else

+  {

+    /* len == 0, empty string */

+    return ERR_OK;

+  }

+}

+

+#endif /* LWIP_SNMP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/asn1_enc.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/asn1_enc.c
new file mode 100644
index 0000000..ac29636
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/asn1_enc.c
@@ -0,0 +1,611 @@
+/**

+ * @file

+ * Abstract Syntax Notation One (ISO 8824, 8825) encoding

+ *

+ * @todo not optimised (yet), favor correctness over speed, favor speed over size

+ */

+

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * Author: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/snmp_asn1.h"

+

+/**

+ * Returns octet count for length.

+ *

+ * @param length

+ * @param octets_needed points to the return value

+ */

+void

+snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)

+{

+  if (length < 0x80U)

+  {

+    *octets_needed = 1;

+  }

+  else if (length < 0x100U)

+  {

+    *octets_needed = 2;

+  }

+  else

+  {

+    *octets_needed = 3;

+  }

+}

+

+/**

+ * Returns octet count for an u32_t.

+ *

+ * @param value

+ * @param octets_needed points to the return value

+ *

+ * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded

+ * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value

+ * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!

+ */

+void

+snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)

+{

+  if (value < 0x80UL)

+  {

+    *octets_needed = 1;

+  }

+  else if (value < 0x8000UL)

+  {

+    *octets_needed = 2;

+  }

+  else if (value < 0x800000UL)

+  {

+    *octets_needed = 3;

+  }

+  else if (value < 0x80000000UL)

+  {

+    *octets_needed = 4;

+  }

+  else

+  {

+    *octets_needed = 5;

+  }

+}

+

+/**

+ * Returns octet count for an s32_t.

+ *

+ * @param value

+ * @param octets_needed points to the return value

+ *

+ * @note ASN coded integers are _always_ signed.

+ */

+void

+snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)

+{

+  if (value < 0)

+  {

+    value = ~value;

+  }

+  if (value < 0x80L)

+  {

+    *octets_needed = 1;

+  }

+  else if (value < 0x8000L)

+  {

+    *octets_needed = 2;

+  }

+  else if (value < 0x800000L)

+  {

+    *octets_needed = 3;

+  }

+  else

+  {

+    *octets_needed = 4;

+  }

+}

+

+/**

+ * Returns octet count for an object identifier.

+ *

+ * @param ident_len object identifier array length

+ * @param ident points to object identifier array

+ * @param octets_needed points to the return value

+ */

+void

+snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed)

+{

+  s32_t sub_id;

+  u8_t cnt;

+

+  cnt = 0;

+  if (ident_len > 1)

+  {

+    /* compressed prefix in one octet */

+    cnt++;

+    ident_len -= 2;

+    ident += 2;

+  }

+  while(ident_len > 0)

+  {

+    ident_len--;

+    sub_id = *ident;

+

+    sub_id >>= 7;

+    cnt++;

+    while(sub_id > 0)

+    {

+      sub_id >>= 7;

+      cnt++;

+    }

+    ident++;

+  }

+  *octets_needed = cnt;

+}

+

+/**

+ * Encodes ASN type field into a pbuf chained ASN1 msg.

+ *

+ * @param p points to output pbuf to encode value into

+ * @param ofs points to the offset within the pbuf chain

+ * @param type input ASN1 type

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode

+ */

+err_t

+snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+      *msg_ptr = type;

+      return ERR_OK;

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Encodes host order length field into a pbuf chained ASN1 msg.

+ *

+ * @param p points to output pbuf to encode length into

+ * @param ofs points to the offset within the pbuf chain

+ * @param length is the host order length to be encoded

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode

+ */

+err_t

+snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+

+      if (length < 0x80)

+      {

+        *msg_ptr = length;

+        return ERR_OK;

+      }

+      else if (length < 0x100)

+      {

+        *msg_ptr = 0x81;

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+        *msg_ptr = length;

+        return ERR_OK;

+      }

+      else

+      {

+        u8_t i;

+

+        /* length >= 0x100 && length <= 0xFFFF */

+        *msg_ptr = 0x82;

+        i = 2;

+        while (i > 0)

+        {

+          i--;

+          ofs += 1;

+          if (ofs >= plen)

+          {

+            /* next octet in next pbuf */

+            p = p->next;

+            if (p == NULL) { return ERR_ARG; }

+            msg_ptr = p->payload;

+            plen += p->len;

+          }

+          else

+          {

+            /* next octet in same pbuf */

+            msg_ptr++;

+          }

+          if (i == 0)

+          {

+            /* least significant length octet */

+            *msg_ptr = length;

+          }

+          else

+          {

+            /* most significant length octet */

+            *msg_ptr = length >> 8;

+          }

+        }

+        return ERR_OK;

+      }

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.

+ *

+ * @param p points to output pbuf to encode value into

+ * @param ofs points to the offset within the pbuf chain

+ * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())

+ * @param value is the host order u32_t value to be encoded

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode

+ *

+ * @see snmp_asn1_enc_u32t_cnt()

+ */

+err_t

+snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+

+      if (octets_needed == 5)

+      {

+        /* not enough bits in 'value' add leading 0x00 */

+        octets_needed--;

+        *msg_ptr = 0x00;

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+          plen += p->len;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+      }

+      while (octets_needed > 1)

+      {

+        octets_needed--;

+        *msg_ptr = value >> (octets_needed << 3);

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+          plen += p->len;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+      }

+      /* (only) one least significant octet */

+      *msg_ptr = value;

+      return ERR_OK;

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Encodes s32_t integer into a pbuf chained ASN1 msg.

+ *

+ * @param p points to output pbuf to encode value into

+ * @param ofs points to the offset within the pbuf chain

+ * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())

+ * @param value is the host order s32_t value to be encoded

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode

+ *

+ * @see snmp_asn1_enc_s32t_cnt()

+ */

+err_t

+snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+

+      while (octets_needed > 1)

+      {

+        octets_needed--;

+        *msg_ptr = value >> (octets_needed << 3);

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+          plen += p->len;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+      }

+      /* (only) one least significant octet */

+      *msg_ptr = value;

+      return ERR_OK;

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Encodes object identifier into a pbuf chained ASN1 msg.

+ *

+ * @param p points to output pbuf to encode oid into

+ * @param ofs points to the offset within the pbuf chain

+ * @param ident_len object identifier array length

+ * @param ident points to object identifier array

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode

+ */

+err_t

+snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+

+      if (ident_len > 1)

+      {

+        if ((ident[0] == 1) && (ident[1] == 3))

+        {

+          /* compressed (most common) prefix .iso.org */

+          *msg_ptr = 0x2b;

+        }

+        else

+        {

+          /* calculate prefix */

+          *msg_ptr = (ident[0] * 40) + ident[1];

+        }

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+          plen += p->len;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+        ident_len -= 2;

+        ident += 2;

+      }

+      else

+      {

+/* @bug:  allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression??  */

+        /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */

+        return ERR_ARG;

+      }

+      while (ident_len > 0)

+      {

+        s32_t sub_id;

+        u8_t shift, tail;

+

+        ident_len--;

+        sub_id = *ident;

+        tail = 0;

+        shift = 28;

+        while(shift > 0)

+        {

+          u8_t code;

+

+          code = sub_id >> shift;

+          if ((code != 0) || (tail != 0))

+          {

+            tail = 1;

+            *msg_ptr = code | 0x80;

+            ofs += 1;

+            if (ofs >= plen)

+            {

+              /* next octet in next pbuf */

+              p = p->next;

+              if (p == NULL) { return ERR_ARG; }

+              msg_ptr = p->payload;

+              plen += p->len;

+            }

+            else

+            {

+              /* next octet in same pbuf */

+              msg_ptr++;

+            }

+          }

+          shift -= 7;

+        }

+        *msg_ptr = (u8_t)sub_id & 0x7F;

+        if (ident_len > 0)

+        {

+          ofs += 1;

+          if (ofs >= plen)

+          {

+            /* next octet in next pbuf */

+            p = p->next;

+            if (p == NULL) { return ERR_ARG; }

+            msg_ptr = p->payload;

+            plen += p->len;

+          }

+          else

+          {

+            /* next octet in same pbuf */

+            msg_ptr++;

+          }

+        }

+        /* proceed to next sub-identifier */

+        ident++;

+      }

+      return ERR_OK;

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+/**

+ * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.

+ *

+ * @param p points to output pbuf to encode raw data into

+ * @param ofs points to the offset within the pbuf chain

+ * @param raw_len raw data length

+ * @param raw points raw data

+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode

+ */

+err_t

+snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw)

+{

+  u16_t plen, base;

+  u8_t *msg_ptr;

+

+  plen = 0;

+  while (p != NULL)

+  {

+    base = plen;

+    plen += p->len;

+    if (ofs < plen)

+    {

+      msg_ptr = p->payload;

+      msg_ptr += ofs - base;

+

+      while (raw_len > 1)

+      {

+        /* copy raw_len - 1 octets */

+        raw_len--;

+        *msg_ptr = *raw;

+        raw++;

+        ofs += 1;

+        if (ofs >= plen)

+        {

+          /* next octet in next pbuf */

+          p = p->next;

+          if (p == NULL) { return ERR_ARG; }

+          msg_ptr = p->payload;

+          plen += p->len;

+        }

+        else

+        {

+          /* next octet in same pbuf */

+          msg_ptr++;

+        }

+      }

+      if (raw_len > 0)

+      {

+        /* copy last or single octet */

+        *msg_ptr = *raw;

+      }

+      return ERR_OK;

+    }

+    p = p->next;

+  }

+  /* p == NULL, ofs >= plen */

+  return ERR_ARG;

+}

+

+#endif /* LWIP_SNMP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/mib2.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/mib2.c
new file mode 100644
index 0000000..0e582c1
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/mib2.c
@@ -0,0 +1,4126 @@
+/**

+ * @file

+ * Management Information Base II (RFC1213) objects and functions.

+ *

+ * @note the object identifiers for this MIB-2 and private MIB tree

+ * must be kept in sorted ascending order. This to ensure correct getnext operation.

+ */

+

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * Author: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/snmp.h"

+#include "lwip/netif.h"

+#include "lwip/ip.h"

+#include "lwip/ip_frag.h"

+#include "lwip/tcp.h"

+#include "lwip/udp.h"

+#include "lwip/snmp_asn1.h"

+#include "lwip/snmp_structs.h"

+#include "netif/etharp.h"

+

+/**

+ * IANA assigned enterprise ID for lwIP is 26381

+ * @see http://www.iana.org/assignments/enterprise-numbers

+ *

+ * @note this enterprise ID is assigned to the lwIP project,

+ * all object identifiers living under this ID are assigned

+ * by the lwIP maintainers (contact Christiaan Simons)!

+ * @note don't change this define, use snmp_set_sysobjid()

+ *

+ * If you need to create your own private MIB you'll need

+ * to apply for your own enterprise ID with IANA:

+ * http://www.iana.org/numbers.html

+ */

+#define SNMP_ENTERPRISE_ID 26381

+#define SNMP_SYSOBJID_LEN 7

+#define SNMP_SYSOBJID {1, 3, 6, 1, 4, 1, SNMP_ENTERPRISE_ID}

+

+#ifndef SNMP_SYSSERVICES

+#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2))

+#endif

+

+#ifndef SNMP_GET_SYSUPTIME

+#define SNMP_GET_SYSUPTIME(sysuptime)

+#endif

+

+static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void system_get_value(struct obj_def *od, u16_t len, void *value);

+static u8_t system_set_test(struct obj_def *od, u16_t len, void *value);

+static void system_set_value(struct obj_def *od, u16_t len, void *value);

+static void interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void interfaces_get_value(struct obj_def *od, u16_t len, void *value);

+static void ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void ifentry_get_value(struct obj_def *od, u16_t len, void *value);

+#if !SNMP_SAFE_REQUESTS

+static u8_t ifentry_set_test (struct obj_def *od, u16_t len, void *value);

+static void ifentry_set_value (struct obj_def *od, u16_t len, void *value);

+#endif /* SNMP_SAFE_REQUESTS */

+static void atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void atentry_get_value(struct obj_def *od, u16_t len, void *value);

+static void ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void ip_get_value(struct obj_def *od, u16_t len, void *value);

+static u8_t ip_set_test(struct obj_def *od, u16_t len, void *value);

+static void ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value);

+static void ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value);

+static void ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value);

+static void icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void icmp_get_value(struct obj_def *od, u16_t len, void *value);

+#if LWIP_TCP

+static void tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void tcp_get_value(struct obj_def *od, u16_t len, void *value);

+#ifdef THIS_SEEMS_UNUSED

+static void tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value);

+#endif

+#endif

+static void udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void udp_get_value(struct obj_def *od, u16_t len, void *value);

+static void udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void udpentry_get_value(struct obj_def *od, u16_t len, void *value);

+static void snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+static void snmp_get_value(struct obj_def *od, u16_t len, void *value);

+static u8_t snmp_set_test(struct obj_def *od, u16_t len, void *value);

+static void snmp_set_value(struct obj_def *od, u16_t len, void *value);

+

+

+/* snmp .1.3.6.1.2.1.11 */

+const mib_scalar_node snmp_scalar = {

+  &snmp_get_object_def,

+  &snmp_get_value,

+  &snmp_set_test,

+  &snmp_set_value,

+  MIB_NODE_SC,

+  0

+};

+const s32_t snmp_ids[28] = {

+  1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16,

+  17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30

+};

+struct mib_node* const snmp_nodes[28] = {

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,

+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar

+};

+const struct mib_array_node snmp = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  28,

+  snmp_ids,

+  snmp_nodes

+};

+

+/* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */

+/* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */

+/* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */

+

+/* udp .1.3.6.1.2.1.7 */

+/** index root node for udpTable */

+struct mib_list_rootnode udp_root = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_LR,

+  0,

+  NULL,

+  NULL,

+  0

+};

+const s32_t udpentry_ids[2] = { 1, 2 };

+struct mib_node* const udpentry_nodes[2] = {

+  (struct mib_node* const)&udp_root, (struct mib_node* const)&udp_root,

+};

+const struct mib_array_node udpentry = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  2,

+  udpentry_ids,

+  udpentry_nodes

+};

+

+s32_t udptable_id = 1;

+struct mib_node* udptable_node = (struct mib_node* const)&udpentry;

+struct mib_ram_array_node udptable = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_RA,

+  0,

+  &udptable_id,

+  &udptable_node

+};

+

+const mib_scalar_node udp_scalar = {

+  &udp_get_object_def,

+  &udp_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_SC,

+  0

+};

+const s32_t udp_ids[5] = { 1, 2, 3, 4, 5 };

+struct mib_node* const udp_nodes[5] = {

+  (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar,

+  (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar,

+  (struct mib_node* const)&udptable

+};

+const struct mib_array_node udp = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  5,

+  udp_ids,

+  udp_nodes

+};

+

+/* tcp .1.3.6.1.2.1.6 */

+#if LWIP_TCP

+/* only if the TCP protocol is available may implement this group */

+/** index root node for tcpConnTable */

+struct mib_list_rootnode tcpconntree_root = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_LR,

+  0,

+  NULL,

+  NULL,

+  0

+};

+const s32_t tcpconnentry_ids[5] = { 1, 2, 3, 4, 5 };

+struct mib_node* const tcpconnentry_nodes[5] = {

+  (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root,

+  (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root,

+  (struct mib_node* const)&tcpconntree_root

+};

+const struct mib_array_node tcpconnentry = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  5,

+  tcpconnentry_ids,

+  tcpconnentry_nodes

+};

+

+s32_t tcpconntable_id = 1;

+struct mib_node* tcpconntable_node = (struct mib_node* const)&tcpconnentry;

+struct mib_ram_array_node tcpconntable = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_RA,

+/** @todo update maxlength when inserting / deleting from table

+   0 when table is empty, 1 when more than one entry */

+  0,

+  &tcpconntable_id,

+  &tcpconntable_node

+};

+

+const mib_scalar_node tcp_scalar = {

+  &tcp_get_object_def,

+  &tcp_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_SC,

+  0

+};

+const s32_t tcp_ids[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };

+struct mib_node* const tcp_nodes[15] = {

+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,

+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,

+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,

+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,

+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,

+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,

+  (struct mib_node* const)&tcpconntable, (struct mib_node* const)&tcp_scalar,

+  (struct mib_node* const)&tcp_scalar

+};

+const struct mib_array_node tcp = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  15,

+  tcp_ids,

+  tcp_nodes

+};

+#endif

+

+/* icmp .1.3.6.1.2.1.5 */

+const mib_scalar_node icmp_scalar = {

+  &icmp_get_object_def,

+  &icmp_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_SC,

+  0

+};

+const s32_t icmp_ids[26] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };

+struct mib_node* const icmp_nodes[26] = {

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,

+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar

+};

+const struct mib_array_node icmp = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  26,

+  icmp_ids,

+  icmp_nodes

+};

+

+/** index root node for ipNetToMediaTable */

+struct mib_list_rootnode ipntomtree_root = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_LR,

+  0,

+  NULL,

+  NULL,

+  0

+};

+const s32_t ipntomentry_ids[4] = { 1, 2, 3, 4 };

+struct mib_node* const ipntomentry_nodes[4] = {

+  (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root,

+  (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root

+};

+const struct mib_array_node ipntomentry = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  4,

+  ipntomentry_ids,

+  ipntomentry_nodes

+};

+

+s32_t ipntomtable_id = 1;

+struct mib_node* ipntomtable_node = (struct mib_node* const)&ipntomentry;

+struct mib_ram_array_node ipntomtable = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_RA,

+  0,

+  &ipntomtable_id,

+  &ipntomtable_node

+};

+

+/** index root node for ipRouteTable */

+struct mib_list_rootnode iprtetree_root = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_LR,

+  0,

+  NULL,

+  NULL,

+  0

+};

+const s32_t iprteentry_ids[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };

+struct mib_node* const iprteentry_nodes[13] = {

+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,

+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,

+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,

+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,

+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,

+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,

+  (struct mib_node* const)&iprtetree_root

+};

+const struct mib_array_node iprteentry = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  13,

+  iprteentry_ids,

+  iprteentry_nodes

+};

+

+s32_t iprtetable_id = 1;

+struct mib_node* iprtetable_node = (struct mib_node* const)&iprteentry;

+struct mib_ram_array_node iprtetable = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_RA,

+  0,

+  &iprtetable_id,

+  &iprtetable_node

+};

+

+/** index root node for ipAddrTable */

+struct mib_list_rootnode ipaddrtree_root = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_LR,

+  0,

+  NULL,

+  NULL,

+  0

+};

+const s32_t ipaddrentry_ids[5] = { 1, 2, 3, 4, 5 };

+struct mib_node* const ipaddrentry_nodes[5] = {

+  (struct mib_node* const)&ipaddrtree_root,

+  (struct mib_node* const)&ipaddrtree_root,

+  (struct mib_node* const)&ipaddrtree_root,

+  (struct mib_node* const)&ipaddrtree_root,

+  (struct mib_node* const)&ipaddrtree_root

+};

+const struct mib_array_node ipaddrentry = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  5,

+  ipaddrentry_ids,

+  ipaddrentry_nodes

+};

+

+s32_t ipaddrtable_id = 1;

+struct mib_node* ipaddrtable_node = (struct mib_node* const)&ipaddrentry;

+struct mib_ram_array_node ipaddrtable = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_RA,

+  0,

+  &ipaddrtable_id,

+  &ipaddrtable_node

+};

+

+/* ip .1.3.6.1.2.1.4 */

+const mib_scalar_node ip_scalar = {

+  &ip_get_object_def,

+  &ip_get_value,

+  &ip_set_test,

+  &noleafs_set_value,

+  MIB_NODE_SC,

+  0

+};

+const s32_t ip_ids[23] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };

+struct mib_node* const ip_nodes[23] = {

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,

+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ipaddrtable,

+  (struct mib_node* const)&iprtetable, (struct mib_node* const)&ipntomtable,

+  (struct mib_node* const)&ip_scalar

+};

+const struct mib_array_node mib2_ip = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  23,

+  ip_ids,

+  ip_nodes

+};

+

+/** index root node for atTable */

+struct mib_list_rootnode arptree_root = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_LR,

+  0,

+  NULL,

+  NULL,

+  0

+};

+const s32_t atentry_ids[3] = { 1, 2, 3 };

+struct mib_node* const atentry_nodes[3] = {

+  (struct mib_node* const)&arptree_root,

+  (struct mib_node* const)&arptree_root,

+  (struct mib_node* const)&arptree_root

+};

+const struct mib_array_node atentry = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  3,

+  atentry_ids,

+  atentry_nodes

+};

+

+const s32_t attable_id = 1;

+struct mib_node* const attable_node = (struct mib_node* const)&atentry;

+const struct mib_array_node attable = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  1,

+  &attable_id,

+  &attable_node

+};

+

+/* at .1.3.6.1.2.1.3 */

+s32_t at_id = 1;

+struct mib_node* mib2_at_node = (struct mib_node* const)&attable;

+struct mib_ram_array_node at = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_RA,

+  0,

+  &at_id,

+  &mib2_at_node

+};

+

+/** index root node for ifTable */

+struct mib_list_rootnode iflist_root = {

+  &ifentry_get_object_def,

+  &ifentry_get_value,

+#if SNMP_SAFE_REQUESTS

+  &noleafs_set_test,

+  &noleafs_set_value,

+#else /* SNMP_SAFE_REQUESTS */

+  &ifentry_set_test,

+  &ifentry_set_value,

+#endif /* SNMP_SAFE_REQUESTS */

+  MIB_NODE_LR,

+  0,

+  NULL,

+  NULL,

+  0

+};

+const s32_t ifentry_ids[22] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 };

+struct mib_node* const ifentry_nodes[22] = {

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,

+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root

+};

+const struct mib_array_node ifentry = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  22,

+  ifentry_ids,

+  ifentry_nodes

+};

+

+s32_t iftable_id = 1;

+struct mib_node* iftable_node = (struct mib_node* const)&ifentry;

+struct mib_ram_array_node iftable = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_RA,

+  0,

+  &iftable_id,

+  &iftable_node

+};

+

+/* interfaces .1.3.6.1.2.1.2 */

+const mib_scalar_node interfaces_scalar = {

+  &interfaces_get_object_def,

+  &interfaces_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_SC,

+  0

+};

+const s32_t interfaces_ids[2] = { 1, 2 };

+struct mib_node* const interfaces_nodes[2] = {

+  (struct mib_node* const)&interfaces_scalar, (struct mib_node* const)&iftable

+};

+const struct mib_array_node interfaces = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  2,

+  interfaces_ids,

+  interfaces_nodes

+};

+

+

+/*             0 1 2 3 4 5 6 */

+/* system .1.3.6.1.2.1.1 */

+const mib_scalar_node sys_tem_scalar = {

+  &system_get_object_def,

+  &system_get_value,

+  &system_set_test,

+  &system_set_value,

+  MIB_NODE_SC,

+  0

+};

+const s32_t sys_tem_ids[7] = { 1, 2, 3, 4, 5, 6, 7 };

+struct mib_node* const sys_tem_nodes[7] = {

+  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,

+  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,

+  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,

+  (struct mib_node* const)&sys_tem_scalar

+};

+/* work around name issue with 'sys_tem', some compiler(s?) seem to reserve 'system' */

+const struct mib_array_node sys_tem = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  7,

+  sys_tem_ids,

+  sys_tem_nodes

+};

+

+/* mib-2 .1.3.6.1.2.1 */

+#if LWIP_TCP

+#define MIB2_GROUPS 8

+#else

+#define MIB2_GROUPS 7

+#endif

+const s32_t mib2_ids[MIB2_GROUPS] =

+{

+  1,

+  2,

+  3,

+  4,

+  5,

+#if LWIP_TCP

+  6,

+#endif

+  7,

+  11

+};

+struct mib_node* const mib2_nodes[MIB2_GROUPS] = {

+  (struct mib_node* const)&sys_tem,

+  (struct mib_node* const)&interfaces,

+  (struct mib_node* const)&at,

+  (struct mib_node* const)&mib2_ip,

+  (struct mib_node* const)&icmp,

+#if LWIP_TCP

+  (struct mib_node* const)&tcp,

+#endif

+  (struct mib_node* const)&udp,

+  (struct mib_node* const)&snmp

+};

+

+const struct mib_array_node mib2 = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  MIB2_GROUPS,

+  mib2_ids,

+  mib2_nodes

+};

+

+/* mgmt .1.3.6.1.2 */

+const s32_t mgmt_ids[1] = { 1 };

+struct mib_node* const mgmt_nodes[1] = { (struct mib_node* const)&mib2 };

+const struct mib_array_node mgmt = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  1,

+  mgmt_ids,

+  mgmt_nodes

+};

+

+/* internet .1.3.6.1 */

+#if SNMP_PRIVATE_MIB

+s32_t internet_ids[2] = { 2, 4 };

+struct mib_node* const internet_nodes[2] = { (struct mib_node* const)&mgmt, (struct mib_node* const)&private };

+const struct mib_array_node internet = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  2,

+  internet_ids,

+  internet_nodes

+};

+#else

+const s32_t internet_ids[1] = { 2 };

+struct mib_node* const internet_nodes[1] = { (struct mib_node* const)&mgmt };

+const struct mib_array_node internet = {

+  &noleafs_get_object_def,

+  &noleafs_get_value,

+  &noleafs_set_test,

+  &noleafs_set_value,

+  MIB_NODE_AR,

+  1,

+  internet_ids,

+  internet_nodes

+};

+#endif

+

+/** mib-2.system.sysObjectID  */

+static struct snmp_obj_id sysobjid = {SNMP_SYSOBJID_LEN, SNMP_SYSOBJID};

+/** enterprise ID for generic TRAPs, .iso.org.dod.internet.mgmt.mib-2.snmp */

+static struct snmp_obj_id snmpgrp_id = {7,{1,3,6,1,2,1,11}};

+/** mib-2.system.sysServices */

+static const s32_t sysservices = SNMP_SYSSERVICES;

+

+/** mib-2.system.sysDescr */

+static const u8_t sysdescr_len_default = 4;

+static const u8_t sysdescr_default[] = "lwIP";

+static u8_t* sysdescr_len_ptr = (u8_t*)&sysdescr_len_default;

+static u8_t* sysdescr_ptr = (u8_t*)&sysdescr_default[0];

+/** mib-2.system.sysContact */

+static const u8_t syscontact_len_default = 0;

+static const u8_t syscontact_default[] = "";

+static u8_t* syscontact_len_ptr = (u8_t*)&syscontact_len_default;

+static u8_t* syscontact_ptr = (u8_t*)&syscontact_default[0];

+/** mib-2.system.sysName */

+static const u8_t sysname_len_default = 8;

+static const u8_t sysname_default[] = "FQDN-unk";

+static u8_t* sysname_len_ptr = (u8_t*)&sysname_len_default;

+static u8_t* sysname_ptr = (u8_t*)&sysname_default[0];

+/** mib-2.system.sysLocation */

+static const u8_t syslocation_len_default = 0;

+static const u8_t syslocation_default[] = "";

+static u8_t* syslocation_len_ptr = (u8_t*)&syslocation_len_default;

+static u8_t* syslocation_ptr = (u8_t*)&syslocation_default[0];

+/** mib-2.snmp.snmpEnableAuthenTraps */

+static const u8_t snmpenableauthentraps_default = 2; /* disabled */

+static u8_t* snmpenableauthentraps_ptr = (u8_t*)&snmpenableauthentraps_default;

+

+/** mib-2.interfaces.ifTable.ifEntry.ifSpecific (zeroDotZero) */

+static const struct snmp_obj_id ifspecific = {2, {0, 0}};

+/** mib-2.ip.ipRouteTable.ipRouteEntry.ipRouteInfo (zeroDotZero) */

+static const struct snmp_obj_id iprouteinfo = {2, {0, 0}};

+

+

+

+/* mib-2.system counter(s) */

+static u32_t sysuptime = 0;

+

+/* mib-2.ip counter(s) */

+static u32_t ipinreceives = 0,

+             ipinhdrerrors = 0,

+             ipinaddrerrors = 0,

+             ipforwdatagrams = 0,

+             ipinunknownprotos = 0,

+             ipindiscards = 0,

+             ipindelivers = 0,

+             ipoutrequests = 0,

+             ipoutdiscards = 0,

+             ipoutnoroutes = 0,

+             ipreasmreqds = 0,

+             ipreasmoks = 0,

+             ipreasmfails = 0,

+             ipfragoks = 0,

+             ipfragfails = 0,

+             ipfragcreates = 0,

+             iproutingdiscards = 0;

+/* mib-2.icmp counter(s) */

+static u32_t icmpinmsgs = 0,

+             icmpinerrors = 0,

+             icmpindestunreachs = 0,

+             icmpintimeexcds = 0,

+             icmpinparmprobs = 0,

+             icmpinsrcquenchs = 0,

+             icmpinredirects = 0,

+             icmpinechos = 0,

+             icmpinechoreps = 0,

+             icmpintimestamps = 0,

+             icmpintimestampreps = 0,

+             icmpinaddrmasks = 0,

+             icmpinaddrmaskreps = 0,

+             icmpoutmsgs = 0,

+             icmpouterrors = 0,

+             icmpoutdestunreachs = 0,

+             icmpouttimeexcds = 0,

+             icmpoutparmprobs = 0,

+             icmpoutsrcquenchs = 0,

+             icmpoutredirects = 0,

+             icmpoutechos = 0,

+             icmpoutechoreps = 0,

+             icmpouttimestamps = 0,

+             icmpouttimestampreps = 0,

+             icmpoutaddrmasks = 0,

+             icmpoutaddrmaskreps = 0;

+/* mib-2.tcp counter(s) */

+static u32_t tcpactiveopens = 0,

+             tcppassiveopens = 0,

+             tcpattemptfails = 0,

+             tcpestabresets = 0,

+             tcpinsegs = 0,

+             tcpoutsegs = 0,

+             tcpretranssegs = 0,

+             tcpinerrs = 0,

+             tcpoutrsts = 0;

+/* mib-2.udp counter(s) */

+static u32_t udpindatagrams = 0,

+             udpnoports = 0,

+             udpinerrors = 0,

+             udpoutdatagrams = 0;

+/* mib-2.snmp counter(s) */

+static u32_t snmpinpkts = 0,

+             snmpoutpkts = 0,

+             snmpinbadversions = 0,

+             snmpinbadcommunitynames = 0,

+             snmpinbadcommunityuses = 0,

+             snmpinasnparseerrs = 0,

+             snmpintoobigs = 0,

+             snmpinnosuchnames = 0,

+             snmpinbadvalues = 0,

+             snmpinreadonlys = 0,

+             snmpingenerrs = 0,

+             snmpintotalreqvars = 0,

+             snmpintotalsetvars = 0,

+             snmpingetrequests = 0,

+             snmpingetnexts = 0,

+             snmpinsetrequests = 0,

+             snmpingetresponses = 0,

+             snmpintraps = 0,

+             snmpouttoobigs = 0,

+             snmpoutnosuchnames = 0,

+             snmpoutbadvalues = 0,

+             snmpoutgenerrs = 0,

+             snmpoutgetrequests = 0,

+             snmpoutgetnexts = 0,

+             snmpoutsetrequests = 0,

+             snmpoutgetresponses = 0,

+             snmpouttraps = 0;

+

+

+

+/* prototypes of the following functions are in lwip/src/include/lwip/snmp.h */

+/**

+ * Copy octet string.

+ *

+ * @param dst points to destination

+ * @param src points to source

+ * @param n number of octets to copy.

+ */

+void ocstrncpy(u8_t *dst, u8_t *src, u8_t n)

+{

+  while (n > 0)

+  {

+    n--;

+    *dst++ = *src++;

+  }

+}

+

+/**

+ * Copy object identifier (s32_t) array.

+ *

+ * @param dst points to destination

+ * @param src points to source

+ * @param n number of sub identifiers to copy.

+ */

+void objectidncpy(s32_t *dst, s32_t *src, u8_t n)

+{

+  while(n > 0)

+  {

+    n--;

+    *dst++ = *src++;

+  }

+}

+

+/**

+ * Initializes sysDescr pointers.

+ *

+ * @param str if non-NULL then copy str pointer

+ * @param len points to string length, excluding zero terminator

+ */

+void snmp_set_sysdesr(u8_t *str, u8_t *len)

+{

+  if (str != NULL)

+  {

+    sysdescr_ptr = str;

+    sysdescr_len_ptr = len;

+  }

+}

+

+void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid)

+{

+  *oid = &sysobjid;

+}

+

+/**

+ * Initializes sysObjectID value.

+ *

+ * @param oid points to stuct snmp_obj_id to copy

+ */

+void snmp_set_sysobjid(struct snmp_obj_id *oid)

+{

+  sysobjid = *oid;

+}

+

+/**

+ * Must be called at regular 10 msec interval from a timer interrupt

+ * or signal handler depending on your runtime environment.

+ */

+void snmp_inc_sysuptime(void)

+{

+  sysuptime++;

+}

+

+void snmp_add_sysuptime(u32_t value)

+{

+  sysuptime+=value;

+}

+

+void snmp_get_sysuptime(u32_t *value)

+{

+  SNMP_GET_SYSUPTIME(sysuptime);

+  *value = sysuptime;

+}

+

+/**

+ * Initializes sysContact pointers,

+ * e.g. ptrs to non-volatile memory external to lwIP.

+ *

+ * @param ocstr if non-NULL then copy str pointer

+ * @param ocstrlen points to string length, excluding zero terminator

+ */

+void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen)

+{

+  if (ocstr != NULL)

+  {

+    syscontact_ptr = ocstr;

+    syscontact_len_ptr = ocstrlen;

+  }

+}

+

+/**

+ * Initializes sysName pointers,

+ * e.g. ptrs to non-volatile memory external to lwIP.

+ *

+ * @param ocstr if non-NULL then copy str pointer

+ * @param ocstrlen points to string length, excluding zero terminator

+ */

+void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen)

+{

+  if (ocstr != NULL)

+  {

+    sysname_ptr = ocstr;

+    sysname_len_ptr = ocstrlen;

+  }

+}

+

+/**

+ * Initializes sysLocation pointers,

+ * e.g. ptrs to non-volatile memory external to lwIP.

+ *

+ * @param ocstr if non-NULL then copy str pointer

+ * @param ocstrlen points to string length, excluding zero terminator

+ */

+void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen)

+{

+  if (ocstr != NULL)

+  {

+    syslocation_ptr = ocstr;

+    syslocation_len_ptr = ocstrlen;

+  }

+}

+

+

+void snmp_add_ifinoctets(struct netif *ni, u32_t value)

+{

+  ni->ifinoctets += value;

+}

+

+void snmp_inc_ifinucastpkts(struct netif *ni)

+{

+  (ni->ifinucastpkts)++;

+}

+

+void snmp_inc_ifinnucastpkts(struct netif *ni)

+{

+  (ni->ifinnucastpkts)++;

+}

+

+void snmp_inc_ifindiscards(struct netif *ni)

+{

+  (ni->ifindiscards)++;

+}

+

+void snmp_add_ifoutoctets(struct netif *ni, u32_t value)

+{

+  ni->ifoutoctets += value;

+}

+

+void snmp_inc_ifoutucastpkts(struct netif *ni)

+{

+  (ni->ifoutucastpkts)++;

+}

+

+void snmp_inc_ifoutnucastpkts(struct netif *ni)

+{

+  (ni->ifoutnucastpkts)++;

+}

+

+void snmp_inc_ifoutdiscards(struct netif *ni)

+{

+  (ni->ifoutdiscards)++;

+}

+

+void snmp_inc_iflist(void)

+{

+  struct mib_list_node *if_node = NULL;

+

+  snmp_mib_node_insert(&iflist_root, iflist_root.count + 1, &if_node);

+  /* enable getnext traversal on filled table */

+  iftable.maxlength = 1;

+}

+

+void snmp_dec_iflist(void)

+{

+  snmp_mib_node_delete(&iflist_root, iflist_root.tail);

+  /* disable getnext traversal on empty table */

+  if(iflist_root.count == 0) iftable.maxlength = 0;

+}

+

+/**

+ * Inserts ARP table indexes (.xIfIndex.xNetAddress)

+ * into arp table index trees (both atTable and ipNetToMediaTable).

+ */

+void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip)

+{

+  struct mib_list_rootnode *at_rn;

+  struct mib_list_node *at_node;

+  struct ip_addr hip;

+  s32_t arpidx[5];

+  u8_t level, tree;

+

+  LWIP_ASSERT("ni != NULL", ni != NULL);

+  snmp_netiftoifindex(ni, &arpidx[0]);

+  hip.addr = ntohl(ip->addr);

+  snmp_iptooid(&hip, &arpidx[1]);

+

+  for (tree = 0; tree < 2; tree++)

+  {

+    if (tree == 0)

+    {

+      at_rn = &arptree_root;

+    }

+    else

+    {

+      at_rn = &ipntomtree_root;

+    }

+    for (level = 0; level < 5; level++)

+    {

+      at_node = NULL;

+      snmp_mib_node_insert(at_rn, arpidx[level], &at_node);

+      if ((level != 4) && (at_node != NULL))

+      {

+        if (at_node->nptr == NULL)

+        {

+          at_rn = snmp_mib_lrn_alloc();

+          at_node->nptr = (struct mib_node*)at_rn;

+          if (at_rn != NULL)

+          {

+            if (level == 3)

+            {

+              if (tree == 0)

+              {

+                at_rn->get_object_def = atentry_get_object_def;

+                at_rn->get_value = atentry_get_value;

+              }

+              else

+              {

+                at_rn->get_object_def = ip_ntomentry_get_object_def;

+                at_rn->get_value = ip_ntomentry_get_value;

+              }

+              at_rn->set_test = noleafs_set_test;

+              at_rn->set_value = noleafs_set_value;

+            }

+          }

+          else

+          {

+            /* at_rn == NULL, malloc failure */

+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_arpidx_tree() insert failed, mem full"));

+            break;

+          }

+        }

+        else

+        {

+          at_rn = (struct mib_list_rootnode*)at_node->nptr;

+        }

+      }

+    }

+  }

+  /* enable getnext traversal on filled tables */

+  at.maxlength = 1;

+  ipntomtable.maxlength = 1;

+}

+

+/**

+ * Removes ARP table indexes (.xIfIndex.xNetAddress)

+ * from arp table index trees.

+ */

+void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip)

+{

+  struct mib_list_rootnode *at_rn, *next, *del_rn[5];

+  struct mib_list_node *at_n, *del_n[5];

+  struct ip_addr hip;

+  s32_t arpidx[5];

+  u8_t fc, tree, level, del_cnt;

+

+  snmp_netiftoifindex(ni, &arpidx[0]);

+  hip.addr = ntohl(ip->addr);

+  snmp_iptooid(&hip, &arpidx[1]);

+

+  for (tree = 0; tree < 2; tree++)

+  {

+    /* mark nodes for deletion */

+    if (tree == 0)

+    {

+      at_rn = &arptree_root;

+    }

+    else

+    {

+      at_rn = &ipntomtree_root;

+    }

+    level = 0;

+    del_cnt = 0;

+    while ((level < 5) && (at_rn != NULL))

+    {

+      fc = snmp_mib_node_find(at_rn, arpidx[level], &at_n);

+      if (fc == 0)

+      {

+        /* arpidx[level] does not exist */

+        del_cnt = 0;

+        at_rn = NULL;

+      }

+      else if (fc == 1)

+      {

+        del_rn[del_cnt] = at_rn;

+        del_n[del_cnt] = at_n;

+        del_cnt++;

+        at_rn = (struct mib_list_rootnode*)(at_n->nptr);

+      }

+      else if (fc == 2)

+      {

+        /* reset delete (2 or more childs) */

+        del_cnt = 0;

+        at_rn = (struct mib_list_rootnode*)(at_n->nptr);

+      }

+      level++;

+    }

+    /* delete marked index nodes */

+    while (del_cnt > 0)

+    {

+      del_cnt--;

+

+      at_rn = del_rn[del_cnt];

+      at_n = del_n[del_cnt];

+

+      next = snmp_mib_node_delete(at_rn, at_n);

+      if (next != NULL)

+      {

+        LWIP_ASSERT("next_count == 0",next->count == 0);

+        snmp_mib_lrn_free(next);

+      }

+    }

+  }

+  /* disable getnext traversal on empty tables */

+  if(arptree_root.count == 0) at.maxlength = 0;

+  if(ipntomtree_root.count == 0) ipntomtable.maxlength = 0;

+}

+

+void snmp_inc_ipinreceives(void)

+{

+  ipinreceives++;

+}

+

+void snmp_inc_ipinhdrerrors(void)

+{

+  ipinhdrerrors++;

+}

+

+void snmp_inc_ipinaddrerrors(void)

+{

+  ipinaddrerrors++;

+}

+

+void snmp_inc_ipforwdatagrams(void)

+{

+  ipforwdatagrams++;

+}

+

+void snmp_inc_ipinunknownprotos(void)

+{

+  ipinunknownprotos++;

+}

+

+void snmp_inc_ipindiscards(void)

+{

+  ipindiscards++;

+}

+

+void snmp_inc_ipindelivers(void)

+{

+  ipindelivers++;

+}

+

+void snmp_inc_ipoutrequests(void)

+{

+  ipoutrequests++;

+}

+

+void snmp_inc_ipoutdiscards(void)

+{

+  ipoutdiscards++;

+}

+

+void snmp_inc_ipoutnoroutes(void)

+{

+  ipoutnoroutes++;

+}

+

+void snmp_inc_ipreasmreqds(void)

+{

+  ipreasmreqds++;

+}

+

+void snmp_inc_ipreasmoks(void)

+{

+  ipreasmoks++;

+}

+

+void snmp_inc_ipreasmfails(void)

+{

+  ipreasmfails++;

+}

+

+void snmp_inc_ipfragoks(void)

+{

+  ipfragoks++;

+}

+

+void snmp_inc_ipfragfails(void)

+{

+  ipfragfails++;

+}

+

+void snmp_inc_ipfragcreates(void)

+{

+  ipfragcreates++;

+}

+

+void snmp_inc_iproutingdiscards(void)

+{

+  iproutingdiscards++;

+}

+

+/**

+ * Inserts ipAddrTable indexes (.ipAdEntAddr)

+ * into index tree.

+ */

+void snmp_insert_ipaddridx_tree(struct netif *ni)

+{

+  struct mib_list_rootnode *ipa_rn;

+  struct mib_list_node *ipa_node;

+  struct ip_addr ip;

+  s32_t ipaddridx[4];

+  u8_t level;

+

+  LWIP_ASSERT("ni != NULL", ni != NULL);

+  ip.addr = ntohl(ni->ip_addr.addr);

+  snmp_iptooid(&ip, &ipaddridx[0]);

+

+  level = 0;

+  ipa_rn = &ipaddrtree_root;

+  while (level < 4)

+  {

+    ipa_node = NULL;

+    snmp_mib_node_insert(ipa_rn, ipaddridx[level], &ipa_node);

+    if ((level != 3) && (ipa_node != NULL))

+    {

+      if (ipa_node->nptr == NULL)

+      {

+        ipa_rn = snmp_mib_lrn_alloc();

+        ipa_node->nptr = (struct mib_node*)ipa_rn;

+        if (ipa_rn != NULL)

+        {

+          if (level == 2)

+          {

+            ipa_rn->get_object_def = ip_addrentry_get_object_def;

+            ipa_rn->get_value = ip_addrentry_get_value;

+            ipa_rn->set_test = noleafs_set_test;

+            ipa_rn->set_value = noleafs_set_value;

+          }

+        }

+        else

+        {

+          /* ipa_rn == NULL, malloc failure */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_ipaddridx_tree() insert failed, mem full"));

+          break;

+        }

+      }

+      else

+      {

+        ipa_rn = (struct mib_list_rootnode*)ipa_node->nptr;

+      }

+    }

+    level++;

+  }

+  /* enable getnext traversal on filled table */

+  ipaddrtable.maxlength = 1;

+}

+

+/**

+ * Removes ipAddrTable indexes (.ipAdEntAddr)

+ * from index tree.

+ */

+void snmp_delete_ipaddridx_tree(struct netif *ni)

+{

+  struct mib_list_rootnode *ipa_rn, *next, *del_rn[4];

+  struct mib_list_node *ipa_n, *del_n[4];

+  struct ip_addr ip;

+  s32_t ipaddridx[4];

+  u8_t fc, level, del_cnt;

+

+  LWIP_ASSERT("ni != NULL", ni != NULL);

+  ip.addr = ntohl(ni->ip_addr.addr);

+  snmp_iptooid(&ip, &ipaddridx[0]);

+

+  /* mark nodes for deletion */

+  level = 0;

+  del_cnt = 0;

+  ipa_rn = &ipaddrtree_root;

+  while ((level < 4) && (ipa_rn != NULL))

+  {

+    fc = snmp_mib_node_find(ipa_rn, ipaddridx[level], &ipa_n);

+    if (fc == 0)

+    {

+      /* ipaddridx[level] does not exist */

+      del_cnt = 0;

+      ipa_rn = NULL;

+    }

+    else if (fc == 1)

+    {

+      del_rn[del_cnt] = ipa_rn;

+      del_n[del_cnt] = ipa_n;

+      del_cnt++;

+      ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr);

+    }

+    else if (fc == 2)

+    {

+      /* reset delete (2 or more childs) */

+      del_cnt = 0;

+      ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr);

+    }

+    level++;

+  }

+  /* delete marked index nodes */

+  while (del_cnt > 0)

+  {

+    del_cnt--;

+

+    ipa_rn = del_rn[del_cnt];

+    ipa_n = del_n[del_cnt];

+

+    next = snmp_mib_node_delete(ipa_rn, ipa_n);

+    if (next != NULL)

+    {

+      LWIP_ASSERT("next_count == 0",next->count == 0);

+      snmp_mib_lrn_free(next);

+    }

+  }

+  /* disable getnext traversal on empty table */

+  if (ipaddrtree_root.count == 0) ipaddrtable.maxlength = 0;

+}

+

+/**

+ * Inserts ipRouteTable indexes (.ipRouteDest)

+ * into index tree.

+ *

+ * @param dflt non-zero for the default rte, zero for network rte

+ * @param ni points to network interface for this rte

+ *

+ * @todo record sysuptime for _this_ route when it is installed

+ *   (needed for ipRouteAge) in the netif.

+ */

+void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni)

+{

+  u8_t insert = 0;

+  struct ip_addr dst;

+

+  if (dflt != 0)

+  {

+    /* the default route 0.0.0.0 */

+    dst.addr = 0;

+    insert = 1;

+  }

+  else

+  {

+    /* route to the network address */

+    dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr);

+    /* exclude 0.0.0.0 network (reserved for default rte) */

+    if (dst.addr != 0) insert = 1;

+  }

+  if (insert)

+  {

+    struct mib_list_rootnode *iprte_rn;

+    struct mib_list_node *iprte_node;

+    s32_t iprteidx[4];

+    u8_t level;

+

+    snmp_iptooid(&dst, &iprteidx[0]);

+    level = 0;

+    iprte_rn = &iprtetree_root;

+    while (level < 4)

+    {

+      iprte_node = NULL;

+      snmp_mib_node_insert(iprte_rn, iprteidx[level], &iprte_node);

+      if ((level != 3) && (iprte_node != NULL))

+      {

+        if (iprte_node->nptr == NULL)

+        {

+          iprte_rn = snmp_mib_lrn_alloc();

+          iprte_node->nptr = (struct mib_node*)iprte_rn;

+          if (iprte_rn != NULL)

+          {

+            if (level == 2)

+            {

+              iprte_rn->get_object_def = ip_rteentry_get_object_def;

+              iprte_rn->get_value = ip_rteentry_get_value;

+              iprte_rn->set_test = noleafs_set_test;

+              iprte_rn->set_value = noleafs_set_value;

+            }

+          }

+          else

+          {

+            /* iprte_rn == NULL, malloc failure */

+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_iprteidx_tree() insert failed, mem full"));

+            break;

+          }

+        }

+        else

+        {

+          iprte_rn = (struct mib_list_rootnode*)iprte_node->nptr;

+        }

+      }

+      level++;

+    }

+  }

+  /* enable getnext traversal on filled table */

+  iprtetable.maxlength = 1;

+}

+

+/**

+ * Removes ipRouteTable indexes (.ipRouteDest)

+ * from index tree.

+ *

+ * @param dflt non-zero for the default rte, zero for network rte

+ * @param ni points to network interface for this rte or NULL

+ *   for default route to be removed.

+ */

+void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni)

+{

+  u8_t delete = 0;

+  struct ip_addr dst;

+

+  if (dflt != 0)

+  {

+    /* the default route 0.0.0.0 */

+    dst.addr = 0;

+    delete = 1;

+  }

+  else

+  {

+    /* route to the network address */

+    dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr);

+    /* exclude 0.0.0.0 network (reserved for default rte) */

+    if (dst.addr != 0) delete = 1;

+  }

+  if (delete)

+  {

+    struct mib_list_rootnode *iprte_rn, *next, *del_rn[4];

+    struct mib_list_node *iprte_n, *del_n[4];

+    s32_t iprteidx[4];

+    u8_t fc, level, del_cnt;

+

+    snmp_iptooid(&dst, &iprteidx[0]);

+    /* mark nodes for deletion */

+    level = 0;

+    del_cnt = 0;

+    iprte_rn = &iprtetree_root;

+    while ((level < 4) && (iprte_rn != NULL))

+    {

+      fc = snmp_mib_node_find(iprte_rn, iprteidx[level], &iprte_n);

+      if (fc == 0)

+      {

+        /* iprteidx[level] does not exist */

+        del_cnt = 0;

+        iprte_rn = NULL;

+      }

+      else if (fc == 1)

+      {

+        del_rn[del_cnt] = iprte_rn;

+        del_n[del_cnt] = iprte_n;

+        del_cnt++;

+        iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr);

+      }

+      else if (fc == 2)

+      {

+        /* reset delete (2 or more childs) */

+        del_cnt = 0;

+        iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr);

+      }

+      level++;

+    }

+    /* delete marked index nodes */

+    while (del_cnt > 0)

+    {

+      del_cnt--;

+

+      iprte_rn = del_rn[del_cnt];

+      iprte_n = del_n[del_cnt];

+

+      next = snmp_mib_node_delete(iprte_rn, iprte_n);

+      if (next != NULL)

+      {

+        LWIP_ASSERT("next_count == 0",next->count == 0);

+        snmp_mib_lrn_free(next);

+      }

+    }

+  }

+  /* disable getnext traversal on empty table */

+  if (iprtetree_root.count == 0) iprtetable.maxlength = 0;

+}

+

+

+void snmp_inc_icmpinmsgs(void)

+{

+  icmpinmsgs++;

+}

+

+void snmp_inc_icmpinerrors(void)

+{

+  icmpinerrors++;

+}

+

+void snmp_inc_icmpindestunreachs(void)

+{

+  icmpindestunreachs++;

+}

+

+void snmp_inc_icmpintimeexcds(void)

+{

+  icmpintimeexcds++;

+}

+

+void snmp_inc_icmpinparmprobs(void)

+{

+  icmpinparmprobs++;

+}

+

+void snmp_inc_icmpinsrcquenchs(void)

+{

+  icmpinsrcquenchs++;

+}

+

+void snmp_inc_icmpinredirects(void)

+{

+  icmpinredirects++;

+}

+

+void snmp_inc_icmpinechos(void)

+{

+  icmpinechos++;

+}

+

+void snmp_inc_icmpinechoreps(void)

+{

+  icmpinechoreps++;

+}

+

+void snmp_inc_icmpintimestamps(void)

+{

+  icmpintimestamps++;

+}

+

+void snmp_inc_icmpintimestampreps(void)

+{

+  icmpintimestampreps++;

+}

+

+void snmp_inc_icmpinaddrmasks(void)

+{

+  icmpinaddrmasks++;

+}

+

+void snmp_inc_icmpinaddrmaskreps(void)

+{

+  icmpinaddrmaskreps++;

+}

+

+void snmp_inc_icmpoutmsgs(void)

+{

+  icmpoutmsgs++;

+}

+

+void snmp_inc_icmpouterrors(void)

+{

+  icmpouterrors++;

+}

+

+void snmp_inc_icmpoutdestunreachs(void)

+{

+  icmpoutdestunreachs++;

+}

+

+void snmp_inc_icmpouttimeexcds(void)

+{

+  icmpouttimeexcds++;

+}

+

+void snmp_inc_icmpoutparmprobs(void)

+{

+  icmpoutparmprobs++;

+}

+

+void snmp_inc_icmpoutsrcquenchs(void)

+{

+  icmpoutsrcquenchs++;

+}

+

+void snmp_inc_icmpoutredirects(void)

+{

+  icmpoutredirects++;

+}

+

+void snmp_inc_icmpoutechos(void)

+{

+  icmpoutechos++;

+}

+

+void snmp_inc_icmpoutechoreps(void)

+{

+  icmpoutechoreps++;

+}

+

+void snmp_inc_icmpouttimestamps(void)

+{

+  icmpouttimestamps++;

+}

+

+void snmp_inc_icmpouttimestampreps(void)

+{

+  icmpouttimestampreps++;

+}

+

+void snmp_inc_icmpoutaddrmasks(void)

+{

+  icmpoutaddrmasks++;

+}

+

+void snmp_inc_icmpoutaddrmaskreps(void)

+{

+  icmpoutaddrmaskreps++;

+}

+

+void snmp_inc_tcpactiveopens(void)

+{

+  tcpactiveopens++;

+}

+

+void snmp_inc_tcppassiveopens(void)

+{

+  tcppassiveopens++;

+}

+

+void snmp_inc_tcpattemptfails(void)

+{

+  tcpattemptfails++;

+}

+

+void snmp_inc_tcpestabresets(void)

+{

+  tcpestabresets++;

+}

+

+void snmp_inc_tcpinsegs(void)

+{

+  tcpinsegs++;

+}

+

+void snmp_inc_tcpoutsegs(void)

+{

+  tcpoutsegs++;

+}

+

+void snmp_inc_tcpretranssegs(void)

+{

+  tcpretranssegs++;

+}

+

+void snmp_inc_tcpinerrs(void)

+{

+  tcpinerrs++;

+}

+

+void snmp_inc_tcpoutrsts(void)

+{

+  tcpoutrsts++;

+}

+

+void snmp_inc_udpindatagrams(void)

+{

+  udpindatagrams++;

+}

+

+void snmp_inc_udpnoports(void)

+{

+  udpnoports++;

+}

+

+void snmp_inc_udpinerrors(void)

+{

+  udpinerrors++;

+}

+

+void snmp_inc_udpoutdatagrams(void)

+{

+  udpoutdatagrams++;

+}

+

+/**

+ * Inserts udpTable indexes (.udpLocalAddress.udpLocalPort)

+ * into index tree.

+ */

+void snmp_insert_udpidx_tree(struct udp_pcb *pcb)

+{

+  struct mib_list_rootnode *udp_rn;

+  struct mib_list_node *udp_node;

+  struct ip_addr ip;

+  s32_t udpidx[5];

+  u8_t level;

+

+  LWIP_ASSERT("pcb != NULL", pcb != NULL);

+  ip.addr = ntohl(pcb->local_ip.addr);

+  snmp_iptooid(&ip, &udpidx[0]);

+  udpidx[4] = pcb->local_port;

+

+  udp_rn = &udp_root;

+  for (level = 0; level < 5; level++)

+  {

+    udp_node = NULL;

+    snmp_mib_node_insert(udp_rn, udpidx[level], &udp_node);

+    if ((level != 4) && (udp_node != NULL))

+    {

+      if (udp_node->nptr == NULL)

+      {

+        udp_rn = snmp_mib_lrn_alloc();

+        udp_node->nptr = (struct mib_node*)udp_rn;

+        if (udp_rn != NULL)

+        {

+          if (level == 3)

+          {

+            udp_rn->get_object_def = udpentry_get_object_def;

+            udp_rn->get_value = udpentry_get_value;

+            udp_rn->set_test = noleafs_set_test;

+            udp_rn->set_value = noleafs_set_value;

+          }

+        }

+        else

+        {

+          /* udp_rn == NULL, malloc failure */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_udpidx_tree() insert failed, mem full"));

+          break;

+        }

+      }

+      else

+      {

+        udp_rn = (struct mib_list_rootnode*)udp_node->nptr;

+      }

+    }

+  }

+  udptable.maxlength = 1;

+}

+

+/**

+ * Removes udpTable indexes (.udpLocalAddress.udpLocalPort)

+ * from index tree.

+ */

+void snmp_delete_udpidx_tree(struct udp_pcb *pcb)

+{

+  struct mib_list_rootnode *udp_rn, *next, *del_rn[5];

+  struct mib_list_node *udp_n, *del_n[5];

+  struct ip_addr ip;

+  s32_t udpidx[5];

+  u8_t bindings, fc, level, del_cnt;

+

+  LWIP_ASSERT("pcb != NULL", pcb != NULL);

+  ip.addr = ntohl(pcb->local_ip.addr);

+  snmp_iptooid(&ip, &udpidx[0]);

+  udpidx[4] = pcb->local_port;

+

+  /* count PCBs for a given binding

+     (e.g. when reusing ports or for temp output PCBs) */

+  bindings = 0;

+  pcb = udp_pcbs;

+  while ((pcb != NULL))

+  {

+    if ((pcb->local_ip.addr == ip.addr) &&

+        (pcb->local_port == udpidx[4]))

+    {

+      bindings++;

+    }

+    pcb = pcb->next;

+  }

+  if (bindings == 1)

+  {

+    /* selectively remove */

+    /* mark nodes for deletion */

+    level = 0;

+    del_cnt = 0;

+    udp_rn = &udp_root;

+    while ((level < 5) && (udp_rn != NULL))

+    {

+      fc = snmp_mib_node_find(udp_rn, udpidx[level], &udp_n);

+      if (fc == 0)

+      {

+        /* udpidx[level] does not exist */

+        del_cnt = 0;

+        udp_rn = NULL;

+      }

+      else if (fc == 1)

+      {

+        del_rn[del_cnt] = udp_rn;

+        del_n[del_cnt] = udp_n;

+        del_cnt++;

+        udp_rn = (struct mib_list_rootnode*)(udp_n->nptr);

+      }

+      else if (fc == 2)

+      {

+        /* reset delete (2 or more childs) */

+        del_cnt = 0;

+        udp_rn = (struct mib_list_rootnode*)(udp_n->nptr);

+      }

+      level++;

+    }

+    /* delete marked index nodes */

+    while (del_cnt > 0)

+    {

+      del_cnt--;

+

+      udp_rn = del_rn[del_cnt];

+      udp_n = del_n[del_cnt];

+

+      next = snmp_mib_node_delete(udp_rn, udp_n);

+      if (next != NULL)

+      {

+        LWIP_ASSERT("next_count == 0",next->count == 0);

+        snmp_mib_lrn_free(next);

+      }

+    }

+  }

+  /* disable getnext traversal on empty table */

+  if (udp_root.count == 0) udptable.maxlength = 0;

+}

+

+

+void snmp_inc_snmpinpkts(void)

+{

+  snmpinpkts++;

+}

+

+void snmp_inc_snmpoutpkts(void)

+{

+  snmpoutpkts++;

+}

+

+void snmp_inc_snmpinbadversions(void)

+{

+  snmpinbadversions++;

+}

+

+void snmp_inc_snmpinbadcommunitynames(void)

+{

+  snmpinbadcommunitynames++;

+}

+

+void snmp_inc_snmpinbadcommunityuses(void)

+{

+  snmpinbadcommunityuses++;

+}

+

+void snmp_inc_snmpinasnparseerrs(void)

+{

+  snmpinasnparseerrs++;

+}

+

+void snmp_inc_snmpintoobigs(void)

+{

+  snmpintoobigs++;

+}

+

+void snmp_inc_snmpinnosuchnames(void)

+{

+  snmpinnosuchnames++;

+}

+

+void snmp_inc_snmpinbadvalues(void)

+{

+  snmpinbadvalues++;

+}

+

+void snmp_inc_snmpinreadonlys(void)

+{

+  snmpinreadonlys++;

+}

+

+void snmp_inc_snmpingenerrs(void)

+{

+  snmpingenerrs++;

+}

+

+void snmp_add_snmpintotalreqvars(u8_t value)

+{

+  snmpintotalreqvars += value;

+}

+

+void snmp_add_snmpintotalsetvars(u8_t value)

+{

+  snmpintotalsetvars += value;

+}

+

+void snmp_inc_snmpingetrequests(void)

+{

+  snmpingetrequests++;

+}

+

+void snmp_inc_snmpingetnexts(void)

+{

+  snmpingetnexts++;

+}

+

+void snmp_inc_snmpinsetrequests(void)

+{

+  snmpinsetrequests++;

+}

+

+void snmp_inc_snmpingetresponses(void)

+{

+  snmpingetresponses++;

+}

+

+void snmp_inc_snmpintraps(void)

+{

+  snmpintraps++;

+}

+

+void snmp_inc_snmpouttoobigs(void)

+{

+  snmpouttoobigs++;

+}

+

+void snmp_inc_snmpoutnosuchnames(void)

+{

+  snmpoutnosuchnames++;

+}

+

+void snmp_inc_snmpoutbadvalues(void)

+{

+  snmpoutbadvalues++;

+}

+

+void snmp_inc_snmpoutgenerrs(void)

+{

+  snmpoutgenerrs++;

+}

+

+void snmp_inc_snmpoutgetrequests(void)

+{

+  snmpoutgetrequests++;

+}

+

+void snmp_inc_snmpoutgetnexts(void)

+{

+  snmpoutgetnexts++;

+}

+

+void snmp_inc_snmpoutsetrequests(void)

+{

+  snmpoutsetrequests++;

+}

+

+void snmp_inc_snmpoutgetresponses(void)

+{

+  snmpoutgetresponses++;

+}

+

+void snmp_inc_snmpouttraps(void)

+{

+  snmpouttraps++;

+}

+

+void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid)

+{

+  *oid = &snmpgrp_id;

+}

+

+void snmp_set_snmpenableauthentraps(u8_t *value)

+{

+  if (value != NULL)

+  {

+    snmpenableauthentraps_ptr = value;

+  }

+}

+

+void snmp_get_snmpenableauthentraps(u8_t *value)

+{

+  *value = *snmpenableauthentraps_ptr;

+}

+

+void

+noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  if (ident_len){}

+  if (ident){}

+  od->instance = MIB_OBJECT_NONE;

+}

+

+void

+noleafs_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  if (od){}

+  if (len){}

+  if (value){}

+}

+

+u8_t

+noleafs_set_test(struct obj_def *od, u16_t len, void *value)

+{

+  if (od){}

+  if (len){}

+  if (value){}

+  /* can't set */

+  return 0;

+}

+

+void

+noleafs_set_value(struct obj_def *od, u16_t len, void *value)

+{

+  if (od){}

+  if (len){}

+  if (value){}

+}

+

+

+/**

+ * Returns systems object definitions.

+ *

+ * @param ident_len the address length (2)

+ * @param ident points to objectname.0 (object id trailer)

+ * @param od points to object definition.

+ */

+static void

+system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  u8_t id;

+

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if (ident_len == 2)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def system.%"U16_F".0\n",(u16_t)id));

+    switch (id)

+    {

+      case 1: /* sysDescr */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+        od->v_len = *sysdescr_len_ptr;

+        break;

+      case 2: /* sysObjectID */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);

+        od->v_len = sysobjid.len * sizeof(s32_t);

+        break;

+      case 3: /* sysUpTime */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS);

+        od->v_len = sizeof(u32_t);

+        break;

+      case 4: /* sysContact */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+        od->v_len = *syscontact_len_ptr;

+        break;

+      case 5: /* sysName */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+        od->v_len = *sysname_len_ptr;

+        break;

+      case 6: /* sysLocation */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+        od->v_len = *syslocation_len_ptr;

+        break;

+      case 7: /* sysServices */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    };

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+/**

+ * Returns system object value.

+ *

+ * @param ident_len the address length (2)

+ * @param ident points to objectname.0 (object id trailer)

+ * @param len return value space (in bytes)

+ * @param value points to (varbind) space to copy value into.

+ */

+static void

+system_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id;

+

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 1: /* sysDescr */

+      ocstrncpy(value,sysdescr_ptr,len);

+      break;

+    case 2: /* sysObjectID */

+      objectidncpy((s32_t*)value,(s32_t*)sysobjid.id,len / sizeof(s32_t));

+      break;

+    case 3: /* sysUpTime */

+      {

+        snmp_get_sysuptime(value);

+      }

+      break;

+    case 4: /* sysContact */

+      ocstrncpy(value,syscontact_ptr,len);

+      break;

+    case 5: /* sysName */

+      ocstrncpy(value,sysname_ptr,len);

+      break;

+    case 6: /* sysLocation */

+      ocstrncpy(value,syslocation_ptr,len);

+      break;

+    case 7: /* sysServices */

+      {

+        s32_t *sint_ptr = value;

+        *sint_ptr = sysservices;

+      }

+      break;

+  };

+}

+

+static u8_t

+system_set_test(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id, set_ok;

+

+  if (value) {}

+  set_ok = 0;

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 4: /* sysContact */

+      if ((syscontact_ptr != syscontact_default) &&

+          (len <= 255))

+      {

+        set_ok = 1;

+      }

+      break;

+    case 5: /* sysName */

+      if ((sysname_ptr != sysname_default) &&

+          (len <= 255))

+      {

+        set_ok = 1;

+      }

+      break;

+    case 6: /* sysLocation */

+      if ((syslocation_ptr != syslocation_default) &&

+          (len <= 255))

+      {

+        set_ok = 1;

+      }

+      break;

+  };

+  return set_ok;

+}

+

+static void

+system_set_value(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id;

+

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 4: /* sysContact */

+      ocstrncpy(syscontact_ptr,value,len);

+      *syscontact_len_ptr = len;

+      break;

+    case 5: /* sysName */

+      ocstrncpy(sysname_ptr,value,len);

+      *sysname_len_ptr = len;

+      break;

+    case 6: /* sysLocation */

+      ocstrncpy(syslocation_ptr,value,len);

+      *syslocation_len_ptr = len;

+      break;

+  };

+}

+

+/**

+ * Returns interfaces.ifnumber object definition.

+ *

+ * @param ident_len the address length (2)

+ * @param ident points to objectname.index

+ * @param od points to object definition.

+ */

+static void

+interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if (ident_len == 2)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    od->instance = MIB_OBJECT_SCALAR;

+    od->access = MIB_OBJECT_READ_ONLY;

+    od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+    od->v_len = sizeof(s32_t);

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("interfaces_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+/**

+ * Returns interfaces.ifnumber object value.

+ *

+ * @param ident_len the address length (2)

+ * @param ident points to objectname.0 (object id trailer)

+ * @param len return value space (in bytes)

+ * @param value points to (varbind) space to copy value into.

+ */

+static void

+interfaces_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  if (len){}

+  if (od->id_inst_ptr[0] == 1)

+  {

+    s32_t *sint_ptr = value;

+    *sint_ptr = iflist_root.count;

+  }

+}

+

+/**

+ * Returns ifentry object definitions.

+ *

+ * @param ident_len the address length (2)

+ * @param ident points to objectname.index

+ * @param od points to object definition.

+ */

+static void

+ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  u8_t id;

+

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if (ident_len == 2)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ifentry.%"U16_F"\n",(u16_t)id));

+    switch (id)

+    {

+      case 1: /* ifIndex */

+      case 3: /* ifType */

+      case 4: /* ifMtu */

+      case 8: /* ifOperStatus */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 2: /* ifDescr */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+        /** @todo this should be some sort of sizeof(struct netif.name) */

+        od->v_len = 2;

+        break;

+      case 5: /* ifSpeed */

+      case 21: /* ifOutQLen */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);

+        od->v_len = sizeof(u32_t);

+        break;

+      case 6: /* ifPhysAddress */

+        {

+          struct netif *netif;

+

+          snmp_ifindextonetif(ident[1], &netif);

+          od->instance = MIB_OBJECT_TAB;

+          od->access = MIB_OBJECT_READ_ONLY;

+          od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+          od->v_len = netif->hwaddr_len;

+        }

+        break;

+      case 7: /* ifAdminStatus */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 9: /* ifLastChange */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS);

+        od->v_len = sizeof(u32_t);

+        break;

+      case 10: /* ifInOctets */

+      case 11: /* ifInUcastPkts */

+      case 12: /* ifInNUcastPkts */

+      case 13: /* ifInDiscarts */

+      case 14: /* ifInErrors */

+      case 15: /* ifInUnkownProtos */

+      case 16: /* ifOutOctets */

+      case 17: /* ifOutUcastPkts */

+      case 18: /* ifOutNUcastPkts */

+      case 19: /* ifOutDiscarts */

+      case 20: /* ifOutErrors */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);

+        od->v_len = sizeof(u32_t);

+        break;

+      case 22: /* ifSpecific */

+        /** @note returning zeroDotZero (0.0) no media specific MIB support */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);

+        od->v_len = ifspecific.len * sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    };

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+/**

+ * Returns ifentry object value.

+ *

+ * @param ident_len the address length (2)

+ * @param ident points to objectname.0 (object id trailer)

+ * @param len return value space (in bytes)

+ * @param value points to (varbind) space to copy value into.

+ */

+static void

+ifentry_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  struct netif *netif;

+  u8_t id;

+

+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 1: /* ifIndex */

+      {

+        s32_t *sint_ptr = value;

+        *sint_ptr = od->id_inst_ptr[1];

+      }

+      break;

+    case 2: /* ifDescr */

+      ocstrncpy(value,(u8_t*)netif->name,len);

+      break;

+    case 3: /* ifType */

+      {

+        s32_t *sint_ptr = value;

+        *sint_ptr = netif->link_type;

+      }

+      break;

+    case 4: /* ifMtu */

+      {

+        s32_t *sint_ptr = value;

+        *sint_ptr = netif->mtu;

+      }

+      break;

+    case 5: /* ifSpeed */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->link_speed;

+      }

+      break;

+    case 6: /* ifPhysAddress */

+      ocstrncpy(value,netif->hwaddr,len);

+      break;

+    case 7: /* ifAdminStatus */

+#if LWIP_NETIF_LINK_CALLBACK

+      {

+        s32_t *sint_ptr = value;

+        if (netif_is_up(netif))

+        {

+          if (netif_is_link_up(netif))

+          {

+            *sint_ptr = 1; /* up */

+          }

+          else

+          {

+            *sint_ptr = 7; /* lowerLayerDown */

+          }

+        }

+        else

+        {

+          *sint_ptr = 2; /* down */

+        }

+      }

+      break;

+#endif

+    case 8: /* ifOperStatus */

+      {

+        s32_t *sint_ptr = value;

+        if (netif_is_up(netif))

+        {

+          *sint_ptr = 1;

+        }

+        else

+        {

+          *sint_ptr = 2;

+        }

+      }

+      break;

+    case 9: /* ifLastChange */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ts;

+      }

+      break;

+    case 10: /* ifInOctets */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifinoctets;

+      }

+      break;

+    case 11: /* ifInUcastPkts */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifinucastpkts;

+      }

+      break;

+    case 12: /* ifInNUcastPkts */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifinnucastpkts;

+      }

+      break;

+    case 13: /* ifInDiscarts */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifindiscards;

+      }

+      break;

+    case 14: /* ifInErrors */

+    case 15: /* ifInUnkownProtos */

+      /** @todo add these counters! */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = 0;

+      }

+      break;

+    case 16: /* ifOutOctets */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifoutoctets;

+      }

+      break;

+    case 17: /* ifOutUcastPkts */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifoutucastpkts;

+      }

+      break;

+    case 18: /* ifOutNUcastPkts */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifoutnucastpkts;

+      }

+      break;

+    case 19: /* ifOutDiscarts */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = netif->ifoutdiscards;

+      }

+      break;

+    case 20: /* ifOutErrors */

+       /** @todo add this counter! */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = 0;

+      }

+      break;

+    case 21: /* ifOutQLen */

+      /** @todo figure out if this must be 0 (no queue) or 1? */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = 0;

+      }

+      break;

+    case 22: /* ifSpecific */

+      objectidncpy((s32_t*)value,(s32_t*)ifspecific.id,len / sizeof(s32_t));

+      break;

+  };

+}

+

+#if !SNMP_SAFE_REQUESTS

+static u8_t

+ifentry_set_test (struct obj_def *od, u16_t len, void *value)

+{

+  struct netif *netif;

+  u8_t id, set_ok;

+

+  set_ok = 0;

+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 7: /* ifAdminStatus */

+      {

+        s32_t *sint_ptr = value;

+        if (*sint_ptr == 1 || *sint_ptr == 2)

+          set_ok = 1;

+      }

+      break;

+  }

+  return set_ok;

+}

+

+static void

+ifentry_set_value (struct obj_def *od, u16_t len, void *value)

+{

+  struct netif *netif;

+  u8_t id;

+

+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 7: /* ifAdminStatus */

+      {

+        s32_t *sint_ptr = value;

+        if (*sint_ptr == 1)

+        {

+          netif_set_up(netif);

+        }

+        else if (*sint_ptr == 2)

+        {

+          netif_set_down(netif);

+         }

+      }

+      break;

+  }

+}

+#endif /* SNMP_SAFE_REQUESTS */

+

+/**

+ * Returns atentry object definitions.

+ *

+ * @param ident_len the address length (6)

+ * @param ident points to objectname.atifindex.atnetaddress

+ * @param od points to object definition.

+ */

+static void

+atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (5) */

+  ident_len += 5;

+  ident -= 5;

+

+  if (ident_len == 6)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    switch (ident[0])

+    {

+      case 1: /* atIfIndex */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 2: /* atPhysAddress */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+        od->v_len = 6; /** @todo try to use netif::hwaddr_len */

+        break;

+      case 3: /* atNetAddress */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);

+        od->v_len = 4;

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    }

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+atentry_get_value(struct obj_def *od, u16_t len, void *value)

+{

+#if LWIP_ARP

+  u8_t id;

+  struct eth_addr* ethaddr_ret;

+  struct ip_addr* ipaddr_ret;

+#endif /* LWIP_ARP */

+  struct ip_addr ip;

+  struct netif *netif;

+

+  if (len) {}

+

+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);

+  snmp_oidtoip(&od->id_inst_ptr[2], &ip);

+  ip.addr = htonl(ip.addr);

+

+#if LWIP_ARP /** @todo implement a netif_find_addr */

+  if (etharp_find_addr(netif, &ip, &ethaddr_ret, &ipaddr_ret) > -1)

+  {

+    id = od->id_inst_ptr[0];

+    switch (id)

+    {

+      case 1: /* atIfIndex */

+        {

+          s32_t *sint_ptr = value;

+          *sint_ptr = od->id_inst_ptr[1];

+        }

+        break;

+      case 2: /* atPhysAddress */

+        {

+          struct eth_addr *dst = value;

+

+          *dst = *ethaddr_ret;

+        }

+        break;

+      case 3: /* atNetAddress */

+        {

+          struct ip_addr *dst = value;

+

+          *dst = *ipaddr_ret;

+        }

+        break;

+    }

+  }

+#endif /* LWIP_ARP */

+}

+

+static void

+ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  u8_t id;

+

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if (ident_len == 2)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ip.%"U16_F".0\n",(u16_t)id));

+    switch (id)

+    {

+      case 1: /* ipForwarding */

+      case 2: /* ipDefaultTTL */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 3: /* ipInReceives */

+      case 4: /* ipInHdrErrors */

+      case 5: /* ipInAddrErrors */

+      case 6: /* ipForwDatagrams */

+      case 7: /* ipInUnknownProtos */

+      case 8: /* ipInDiscards */

+      case 9: /* ipInDelivers */

+      case 10: /* ipOutRequests */

+      case 11: /* ipOutDiscards */

+      case 12: /* ipOutNoRoutes */

+      case 14: /* ipReasmReqds */

+      case 15: /* ipReasmOKs */

+      case 16: /* ipReasmFails */

+      case 17: /* ipFragOKs */

+      case 18: /* ipFragFails */

+      case 19: /* ipFragCreates */

+      case 23: /* ipRoutingDiscards */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);

+        od->v_len = sizeof(u32_t);

+        break;

+      case 13: /* ipReasmTimeout */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    };

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+ip_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id;

+

+  if (len) {}

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 1: /* ipForwarding */

+      {

+        s32_t *sint_ptr = value;

+#if IP_FORWARD

+        /* forwarding */

+        *sint_ptr = 1;

+#else

+        /* not-forwarding */

+        *sint_ptr = 2;

+#endif

+      }

+      break;

+    case 2: /* ipDefaultTTL */

+      {

+        s32_t *sint_ptr = value;

+        *sint_ptr = IP_DEFAULT_TTL;

+      }

+      break;

+    case 3: /* ipInReceives */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipinreceives;

+      }

+      break;

+    case 4: /* ipInHdrErrors */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipinhdrerrors;

+      }

+      break;

+    case 5: /* ipInAddrErrors */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipinaddrerrors;

+      }

+      break;

+    case 6: /* ipForwDatagrams */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipforwdatagrams;

+      }

+      break;

+    case 7: /* ipInUnknownProtos */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipinunknownprotos;

+      }

+      break;

+    case 8: /* ipInDiscards */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipindiscards;

+      }

+      break;

+    case 9: /* ipInDelivers */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipindelivers;

+      }

+      break;

+    case 10: /* ipOutRequests */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipoutrequests;

+      }

+      break;

+    case 11: /* ipOutDiscards */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipoutdiscards;

+      }

+      break;

+    case 12: /* ipOutNoRoutes */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipoutnoroutes;

+      }

+      break;

+    case 13: /* ipReasmTimeout */

+      {

+        s32_t *sint_ptr = value;

+#if IP_REASSEMBLY

+        *sint_ptr = IP_REASS_MAXAGE;

+#else

+        *sint_ptr = 0;

+#endif

+      }

+      break;

+    case 14: /* ipReasmReqds */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipreasmreqds;

+      }

+      break;

+    case 15: /* ipReasmOKs */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipreasmoks;

+      }

+      break;

+    case 16: /* ipReasmFails */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipreasmfails;

+      }

+      break;

+    case 17: /* ipFragOKs */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipfragoks;

+      }

+      break;

+    case 18: /* ipFragFails */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipfragfails;

+      }

+      break;

+    case 19: /* ipFragCreates */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = ipfragcreates;

+      }

+      break;

+    case 23: /* ipRoutingDiscards */

+      /** @todo can lwIP discard routes at all?? hardwire this to 0?? */

+      {

+        u32_t *uint_ptr = value;

+        *uint_ptr = iproutingdiscards;

+      }

+      break;

+  };

+}

+

+/**

+ * Test ip object value before setting.

+ *

+ * @param od is the object definition

+ * @param len return value space (in bytes)

+ * @param value points to (varbind) space to copy value from.

+ *

+ * @note we allow set if the value matches the hardwired value,

+ *   otherwise return badvalue.

+ */

+static u8_t

+ip_set_test(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id, set_ok;

+  s32_t *sint_ptr = value;

+

+  if (len) {}

+  set_ok = 0;

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 1: /* ipForwarding */

+#if IP_FORWARD

+      /* forwarding */

+      if (*sint_ptr == 1)

+#else

+      /* not-forwarding */

+      if (*sint_ptr == 2)

+#endif

+      {

+        set_ok = 1;

+      }

+      break;

+    case 2: /* ipDefaultTTL */

+      if (*sint_ptr == IP_DEFAULT_TTL)

+      {

+        set_ok = 1;

+      }

+      break;

+  };

+  return set_ok;

+}

+

+static void

+ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (4) */

+  ident_len += 4;

+  ident -= 4;

+

+  if (ident_len == 5)

+  {

+    u8_t id;

+

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    switch (id)

+    {

+      case 1: /* ipAdEntAddr */

+      case 3: /* ipAdEntNetMask */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);

+        od->v_len = 4;

+        break;

+      case 2: /* ipAdEntIfIndex */

+      case 4: /* ipAdEntBcastAddr */

+      case 5: /* ipAdEntReasmMaxSize */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    }

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id;

+  u16_t ifidx;

+  struct ip_addr ip;

+  struct netif *netif = netif_list;

+

+  if (len) {}

+  snmp_oidtoip(&od->id_inst_ptr[1], &ip);

+  ip.addr = htonl(ip.addr);

+  ifidx = 0;

+  while ((netif != NULL) && !ip_addr_cmp(&ip, &netif->ip_addr))

+  {

+    netif = netif->next;

+    ifidx++;

+  }

+

+  if (netif != NULL)

+  {

+    id = od->id_inst_ptr[0];

+    switch (id)

+    {

+      case 1: /* ipAdEntAddr */

+        {

+          struct ip_addr *dst = value;

+          *dst = netif->ip_addr;

+        }

+        break;

+      case 2: /* ipAdEntIfIndex */

+        {

+          s32_t *sint_ptr = value;

+          *sint_ptr = ifidx + 1;

+        }

+        break;

+      case 3: /* ipAdEntNetMask */

+        {

+          struct ip_addr *dst = value;

+          *dst = netif->netmask;

+        }

+        break;

+      case 4: /* ipAdEntBcastAddr */

+        {

+          s32_t *sint_ptr = value;

+

+          /* lwIP oddity, there's no broadcast

+            address in the netif we can rely on */

+          *sint_ptr = ip_addr_broadcast.addr & 1;

+        }

+        break;

+      case 5: /* ipAdEntReasmMaxSize */

+        {

+          s32_t *sint_ptr = value;

+#if IP_REASSEMBLY

+          /* @todo The theoretical maximum is IP_REASS_MAX_PBUFS * size of the pbufs,

+           * but only if receiving one fragmented packet at a time.

+           * The current solution is to calculate for 2 simultaneous packets...

+           */

+          *sint_ptr = (IP_HLEN + ((IP_REASS_MAX_PBUFS/2) *

+            (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - IP_HLEN)));

+#else

+          /** @todo returning MTU would be a bad thing and

+             returning a wild guess like '576' isn't good either */

+          *sint_ptr = 0;

+#endif

+        }

+        break;

+    }

+  }

+}

+

+/**

+ * @note

+ * lwIP IP routing is currently using the network addresses in netif_list.

+ * if no suitable network IP is found in netif_list, the default_netif is used.

+ */

+static void

+ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  u8_t id;

+

+  /* return to object name, adding index depth (4) */

+  ident_len += 4;

+  ident -= 4;

+

+  if (ident_len == 5)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    switch (id)

+    {

+      case 1: /* ipRouteDest */

+      case 7: /* ipRouteNextHop */

+      case 11: /* ipRouteMask */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);

+        od->v_len = 4;

+        break;

+      case 2: /* ipRouteIfIndex */

+      case 3: /* ipRouteMetric1 */

+      case 4: /* ipRouteMetric2 */

+      case 5: /* ipRouteMetric3 */

+      case 6: /* ipRouteMetric4 */

+      case 8: /* ipRouteType */

+      case 10: /* ipRouteAge */

+      case 12: /* ipRouteMetric5 */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 9: /* ipRouteProto */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 13: /* ipRouteInfo */

+        /** @note returning zeroDotZero (0.0) no routing protocol specific MIB */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);

+        od->v_len = iprouteinfo.len * sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    }

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  struct netif *netif;

+  struct ip_addr dest;

+  s32_t *ident;

+  u8_t id;

+

+  ident = od->id_inst_ptr;

+  snmp_oidtoip(&ident[1], &dest);

+  dest.addr = htonl(dest.addr);

+

+  if (dest.addr == 0)

+  {

+    /* ip_route() uses default netif for default route */

+    netif = netif_default;

+  }

+  else

+  {

+    /* not using ip_route(), need exact match! */

+    netif = netif_list;

+    while ((netif != NULL) &&

+            !ip_addr_netcmp(&dest, &(netif->ip_addr), &(netif->netmask)) )

+    {

+      netif = netif->next;

+    }

+  }

+  if (netif != NULL)

+  {

+    id = ident[0];

+    switch (id)

+    {

+      case 1: /* ipRouteDest */

+        {

+          struct ip_addr *dst = value;

+

+          if (dest.addr == 0)

+          {

+            /* default rte has 0.0.0.0 dest */

+            dst->addr = 0;

+          }

+          else

+          {

+            /* netifs have netaddress dest */

+            dst->addr = netif->ip_addr.addr & netif->netmask.addr;

+          }

+        }

+        break;

+      case 2: /* ipRouteIfIndex */

+        {

+          s32_t *sint_ptr = value;

+

+          snmp_netiftoifindex(netif, sint_ptr);

+        }

+        break;

+      case 3: /* ipRouteMetric1 */

+        {

+          s32_t *sint_ptr = value;

+

+          if (dest.addr == 0)

+          {

+            /* default rte has metric 1 */

+            *sint_ptr = 1;

+          }

+          else

+          {

+            /* other rtes have metric 0 */

+            *sint_ptr = 0;

+          }

+        }

+        break;

+      case 4: /* ipRouteMetric2 */

+      case 5: /* ipRouteMetric3 */

+      case 6: /* ipRouteMetric4 */

+      case 12: /* ipRouteMetric5 */

+        {

+          s32_t *sint_ptr = value;

+          /* not used */

+          *sint_ptr = -1;

+        }

+        break;

+      case 7: /* ipRouteNextHop */

+        {

+          struct ip_addr *dst = value;

+

+          if (dest.addr == 0)

+          {

+            /* default rte: gateway */

+            *dst = netif->gw;

+          }

+          else

+          {

+            /* other rtes: netif ip_addr  */

+            *dst = netif->ip_addr;

+          }

+        }

+        break;

+      case 8: /* ipRouteType */

+        {

+          s32_t *sint_ptr = value;

+

+          if (dest.addr == 0)

+          {

+            /* default rte is indirect */

+            *sint_ptr = 4;

+          }

+          else

+          {

+            /* other rtes are direct */

+            *sint_ptr = 3;

+          }

+        }

+        break;

+      case 9: /* ipRouteProto */

+        {

+          s32_t *sint_ptr = value;

+          /* locally defined routes */

+          *sint_ptr = 2;

+        }

+        break;

+      case 10: /* ipRouteAge */

+        {

+          s32_t *sint_ptr = value;

+          /** @todo (sysuptime - timestamp last change) / 100

+              @see snmp_insert_iprteidx_tree() */

+          *sint_ptr = 0;

+        }

+        break;

+      case 11: /* ipRouteMask */

+        {

+          struct ip_addr *dst = value;

+

+          if (dest.addr == 0)

+          {

+            /* default rte use 0.0.0.0 mask */

+            dst->addr = 0;

+          }

+          else

+          {

+            /* other rtes use netmask */

+            *dst = netif->netmask;

+          }

+        }

+        break;

+      case 13: /* ipRouteInfo */

+        objectidncpy((s32_t*)value,(s32_t*)iprouteinfo.id,len / sizeof(s32_t));

+        break;

+    }

+  }

+}

+

+static void

+ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (5) */

+  ident_len += 5;

+  ident -= 5;

+

+  if (ident_len == 6)

+  {

+    u8_t id;

+

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    switch (id)

+    {

+      case 1: /* ipNetToMediaIfIndex */

+      case 4: /* ipNetToMediaType */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 2: /* ipNetToMediaPhysAddress */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);

+        od->v_len = 6; /** @todo try to use netif::hwaddr_len */

+        break;

+      case 3: /* ipNetToMediaNetAddress */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);

+        od->v_len = 4;

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    }

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value)

+{

+#if LWIP_ARP

+  u8_t id;

+  struct eth_addr* ethaddr_ret;

+  struct ip_addr* ipaddr_ret;

+#endif /* LWIP_ARP */

+  struct ip_addr ip;

+  struct netif *netif;

+

+  if (len) {}

+

+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);

+  snmp_oidtoip(&od->id_inst_ptr[2], &ip);

+  ip.addr = htonl(ip.addr);

+

+#if LWIP_ARP /** @todo implement a netif_find_addr */

+  if (etharp_find_addr(netif, &ip, &ethaddr_ret, &ipaddr_ret) > -1)

+  {

+    id = od->id_inst_ptr[0];

+    switch (id)

+    {

+      case 1: /* ipNetToMediaIfIndex */

+        {

+          s32_t *sint_ptr = value;

+          *sint_ptr = od->id_inst_ptr[1];

+        }

+        break;

+      case 2: /* ipNetToMediaPhysAddress */

+        {

+          struct eth_addr *dst = value;

+

+          *dst = *ethaddr_ret;

+        }

+        break;

+      case 3: /* ipNetToMediaNetAddress */

+        {

+          struct ip_addr *dst = value;

+

+          *dst = *ipaddr_ret;

+        }

+        break;

+      case 4: /* ipNetToMediaType */

+        {

+          s32_t *sint_ptr = value;

+          /* dynamic (?) */

+          *sint_ptr = 3;

+        }

+        break;

+    }

+  }

+#endif /* LWIP_ARP */

+}

+

+static void

+icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if ((ident_len == 2) &&

+      (ident[0] > 0) && (ident[0] < 27))

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    od->instance = MIB_OBJECT_SCALAR;

+    od->access = MIB_OBJECT_READ_ONLY;

+    od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);

+    od->v_len = sizeof(u32_t);

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+icmp_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u32_t *uint_ptr = value;

+  u8_t id;

+

+  if (len){}

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 1: /* icmpInMsgs */

+      *uint_ptr = icmpinmsgs;

+      break;

+    case 2: /* icmpInErrors */

+      *uint_ptr = icmpinerrors;

+      break;

+    case 3: /* icmpInDestUnreachs */

+      *uint_ptr = icmpindestunreachs;

+      break;

+    case 4: /* icmpInTimeExcds */

+      *uint_ptr = icmpintimeexcds;

+      break;

+    case 5: /* icmpInParmProbs */

+      *uint_ptr = icmpinparmprobs;

+      break;

+    case 6: /* icmpInSrcQuenchs */

+      *uint_ptr = icmpinsrcquenchs;

+      break;

+    case 7: /* icmpInRedirects */

+      *uint_ptr = icmpinredirects;

+      break;

+    case 8: /* icmpInEchos */

+      *uint_ptr = icmpinechos;

+      break;

+    case 9: /* icmpInEchoReps */

+      *uint_ptr = icmpinechoreps;

+      break;

+    case 10: /* icmpInTimestamps */

+      *uint_ptr = icmpintimestamps;

+      break;

+    case 11: /* icmpInTimestampReps */

+      *uint_ptr = icmpintimestampreps;

+      break;

+    case 12: /* icmpInAddrMasks */

+      *uint_ptr = icmpinaddrmasks;

+      break;

+    case 13: /* icmpInAddrMaskReps */

+      *uint_ptr = icmpinaddrmaskreps;

+      break;

+    case 14: /* icmpOutMsgs */

+      *uint_ptr = icmpoutmsgs;

+      break;

+    case 15: /* icmpOutErrors */

+      *uint_ptr = icmpouterrors;

+      break;

+    case 16: /* icmpOutDestUnreachs */

+      *uint_ptr = icmpoutdestunreachs;

+      break;

+    case 17: /* icmpOutTimeExcds */

+      *uint_ptr = icmpouttimeexcds;

+      break;

+    case 18: /* icmpOutParmProbs */

+      *uint_ptr = icmpoutparmprobs;

+      break;

+    case 19: /* icmpOutSrcQuenchs */

+      *uint_ptr = icmpoutsrcquenchs;

+      break;

+    case 20: /* icmpOutRedirects */

+      *uint_ptr = icmpoutredirects;

+      break;

+    case 21: /* icmpOutEchos */

+      *uint_ptr = icmpoutechos;

+      break;

+    case 22: /* icmpOutEchoReps */

+      *uint_ptr = icmpoutechoreps;

+      break;

+    case 23: /* icmpOutTimestamps */

+      *uint_ptr = icmpouttimestamps;

+      break;

+    case 24: /* icmpOutTimestampReps */

+      *uint_ptr = icmpouttimestampreps;

+      break;

+    case 25: /* icmpOutAddrMasks */

+      *uint_ptr = icmpoutaddrmasks;

+      break;

+    case 26: /* icmpOutAddrMaskReps */

+      *uint_ptr = icmpoutaddrmaskreps;

+      break;

+  }

+}

+

+#if LWIP_TCP

+/** @todo tcp grp */

+static void

+tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  u8_t id;

+

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if (ident_len == 2)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id));

+

+    switch (id)

+    {

+      case 1: /* tcpRtoAlgorithm */

+      case 2: /* tcpRtoMin */

+      case 3: /* tcpRtoMax */

+      case 4: /* tcpMaxConn */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 5: /* tcpActiveOpens */

+      case 6: /* tcpPassiveOpens */

+      case 7: /* tcpAttemptFails */

+      case 8: /* tcpEstabResets */

+      case 10: /* tcpInSegs */

+      case 11: /* tcpOutSegs */

+      case 12: /* tcpRetransSegs */

+      case 14: /* tcpInErrs */

+      case 15: /* tcpOutRsts */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);

+        od->v_len = sizeof(u32_t);

+        break;

+      case 9: /* tcpCurrEstab */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);

+        od->v_len = sizeof(u32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    };

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+tcp_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u32_t *uint_ptr = value;

+  s32_t *sint_ptr = value;

+  u8_t id;

+

+  if (len){}

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 1: /* tcpRtoAlgorithm, vanj(4) */

+      *sint_ptr = 4;

+      break;

+    case 2: /* tcpRtoMin */

+      /* @todo not the actual value, a guess,

+          needs to be calculated */

+      *sint_ptr = 1000;

+      break;

+    case 3: /* tcpRtoMax */

+      /* @todo not the actual value, a guess,

+         needs to be calculated */

+      *sint_ptr = 60000;

+      break;

+    case 4: /* tcpMaxConn */

+      *sint_ptr = MEMP_NUM_TCP_PCB;

+      break;

+    case 5: /* tcpActiveOpens */

+      *uint_ptr = tcpactiveopens;

+      break;

+    case 6: /* tcpPassiveOpens */

+      *uint_ptr = tcppassiveopens;

+      break;

+    case 7: /* tcpAttemptFails */

+      *uint_ptr = tcpattemptfails;

+      break;

+    case 8: /* tcpEstabResets */

+      *uint_ptr = tcpestabresets;

+      break;

+    case 9: /* tcpCurrEstab */

+      {

+        u16_t tcpcurrestab = 0;

+        struct tcp_pcb *pcb = tcp_active_pcbs;

+        while (pcb != NULL)

+        {

+          if ((pcb->state == ESTABLISHED) ||

+              (pcb->state == CLOSE_WAIT))

+          {

+            tcpcurrestab++;

+          }

+          pcb = pcb->next;

+        }

+        *uint_ptr = tcpcurrestab;

+      }

+      break;

+    case 10: /* tcpInSegs */

+      *uint_ptr = tcpinsegs;

+      break;

+    case 11: /* tcpOutSegs */

+      *uint_ptr = tcpoutsegs;

+      break;

+    case 12: /* tcpRetransSegs */

+      *uint_ptr = tcpretranssegs;

+      break;

+    case 14: /* tcpInErrs */

+      *uint_ptr = tcpinerrs;

+      break;

+    case 15: /* tcpOutRsts */

+      *uint_ptr = tcpoutrsts;

+      break;

+  }

+}

+#ifdef THIS_SEEMS_UNUSED

+static void

+tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (10) */

+  ident_len += 10;

+  ident -= 10;

+

+  if (ident_len == 11)

+  {

+    u8_t id;

+

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id));

+

+    switch (id)

+    {

+      case 1: /* tcpConnState */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      case 2: /* tcpConnLocalAddress */

+      case 4: /* tcpConnRemAddress */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);

+        od->v_len = 4;

+        break;

+      case 3: /* tcpConnLocalPort */

+      case 5: /* tcpConnRemPort */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    };

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  struct ip_addr lip, rip;

+  u16_t lport, rport;

+  s32_t *ident;

+

+  ident = od->id_inst_ptr;

+  snmp_oidtoip(&ident[1], &lip);

+  lip.addr = htonl(lip.addr);

+  lport = ident[5];

+  snmp_oidtoip(&ident[6], &rip);

+  rip.addr = htonl(rip.addr);

+  rport = ident[10];

+

+  /** @todo find matching PCB */

+}

+#endif /* if 0 */

+#endif

+

+static void

+udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if ((ident_len == 2) &&

+      (ident[0] > 0) && (ident[0] < 6))

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    od->instance = MIB_OBJECT_SCALAR;

+    od->access = MIB_OBJECT_READ_ONLY;

+    od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);

+    od->v_len = sizeof(u32_t);

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+udp_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u32_t *uint_ptr = value;

+  u8_t id;

+

+  if (len){}

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+    case 1: /* udpInDatagrams */

+      *uint_ptr = udpindatagrams;

+      break;

+    case 2: /* udpNoPorts */

+      *uint_ptr = udpnoports;

+      break;

+    case 3: /* udpInErrors */

+      *uint_ptr = udpinerrors;

+      break;

+    case 4: /* udpOutDatagrams */

+      *uint_ptr = udpoutdatagrams;

+      break;

+  }

+}

+

+static void

+udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (5) */

+  ident_len += 5;

+  ident -= 5;

+

+  if (ident_len == 6)

+  {

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    switch (ident[0])

+    {

+      case 1: /* udpLocalAddress */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);

+        od->v_len = 4;

+        break;

+      case 2: /* udpLocalPort */

+        od->instance = MIB_OBJECT_TAB;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    }

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+udpentry_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id;

+  struct udp_pcb *pcb;

+  struct ip_addr ip;

+  u16_t port;

+

+  if (len){}

+  snmp_oidtoip(&od->id_inst_ptr[1], &ip);

+  ip.addr = htonl(ip.addr);

+  port = od->id_inst_ptr[5];

+

+  pcb = udp_pcbs;

+  while ((pcb != NULL) &&

+         !((pcb->local_ip.addr == ip.addr) &&

+           (pcb->local_port == port)))

+  {

+    pcb = pcb->next;

+  }

+

+  if (pcb != NULL)

+  {

+    id = od->id_inst_ptr[0];

+    switch (id)

+    {

+      case 1: /* udpLocalAddress */

+        {

+          struct ip_addr *dst = value;

+          *dst = pcb->local_ip;

+        }

+        break;

+      case 2: /* udpLocalPort */

+        {

+          s32_t *sint_ptr = value;

+          *sint_ptr = pcb->local_port;

+        }

+        break;

+    }

+  }

+}

+

+static void

+snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)

+{

+  /* return to object name, adding index depth (1) */

+  ident_len += 1;

+  ident -= 1;

+  if (ident_len == 2)

+  {

+    u8_t id;

+

+    od->id_inst_len = ident_len;

+    od->id_inst_ptr = ident;

+

+    id = ident[0];

+    switch (id)

+    {

+      case 1: /* snmpInPkts */

+      case 2: /* snmpOutPkts */

+      case 3: /* snmpInBadVersions */

+      case 4: /* snmpInBadCommunityNames */

+      case 5: /* snmpInBadCommunityUses */

+      case 6: /* snmpInASNParseErrs */

+      case 8: /* snmpInTooBigs */

+      case 9: /* snmpInNoSuchNames */

+      case 10: /* snmpInBadValues */

+      case 11: /* snmpInReadOnlys */

+      case 12: /* snmpInGenErrs */

+      case 13: /* snmpInTotalReqVars */

+      case 14: /* snmpInTotalSetVars */

+      case 15: /* snmpInGetRequests */

+      case 16: /* snmpInGetNexts */

+      case 17: /* snmpInSetRequests */

+      case 18: /* snmpInGetResponses */

+      case 19: /* snmpInTraps */

+      case 20: /* snmpOutTooBigs */

+      case 21: /* snmpOutNoSuchNames */

+      case 22: /* snmpOutBadValues */

+      case 24: /* snmpOutGenErrs */

+      case 25: /* snmpOutGetRequests */

+      case 26: /* snmpOutGetNexts */

+      case 27: /* snmpOutSetRequests */

+      case 28: /* snmpOutGetResponses */

+      case 29: /* snmpOutTraps */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_ONLY;

+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);

+        od->v_len = sizeof(u32_t);

+        break;

+      case 30: /* snmpEnableAuthenTraps */

+        od->instance = MIB_OBJECT_SCALAR;

+        od->access = MIB_OBJECT_READ_WRITE;

+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);

+        od->v_len = sizeof(s32_t);

+        break;

+      default:

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no such object\n"));

+        od->instance = MIB_OBJECT_NONE;

+        break;

+    };

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no scalar\n"));

+    od->instance = MIB_OBJECT_NONE;

+  }

+}

+

+static void

+snmp_get_value(struct obj_def *od, u16_t len, void *value)

+{

+  u32_t *uint_ptr = value;

+  u8_t id;

+

+  if (len){}

+  id = od->id_inst_ptr[0];

+  switch (id)

+  {

+      case 1: /* snmpInPkts */

+        *uint_ptr = snmpinpkts;

+        break;

+      case 2: /* snmpOutPkts */

+        *uint_ptr = snmpoutpkts;

+        break;

+      case 3: /* snmpInBadVersions */

+        *uint_ptr = snmpinbadversions;

+        break;

+      case 4: /* snmpInBadCommunityNames */

+        *uint_ptr = snmpinbadcommunitynames;

+        break;

+      case 5: /* snmpInBadCommunityUses */

+        *uint_ptr = snmpinbadcommunityuses;

+        break;

+      case 6: /* snmpInASNParseErrs */

+        *uint_ptr = snmpinasnparseerrs;

+        break;

+      case 8: /* snmpInTooBigs */

+        *uint_ptr = snmpintoobigs;

+        break;

+      case 9: /* snmpInNoSuchNames */

+        *uint_ptr = snmpinnosuchnames;

+        break;

+      case 10: /* snmpInBadValues */

+        *uint_ptr = snmpinbadvalues;

+        break;

+      case 11: /* snmpInReadOnlys */

+        *uint_ptr = snmpinreadonlys;

+        break;

+      case 12: /* snmpInGenErrs */

+        *uint_ptr = snmpingenerrs;

+        break;

+      case 13: /* snmpInTotalReqVars */

+        *uint_ptr = snmpintotalreqvars;

+        break;

+      case 14: /* snmpInTotalSetVars */

+        *uint_ptr = snmpintotalsetvars;

+        break;

+      case 15: /* snmpInGetRequests */

+        *uint_ptr = snmpingetrequests;

+        break;

+      case 16: /* snmpInGetNexts */

+        *uint_ptr = snmpingetnexts;

+        break;

+      case 17: /* snmpInSetRequests */

+        *uint_ptr = snmpinsetrequests;

+        break;

+      case 18: /* snmpInGetResponses */

+        *uint_ptr = snmpingetresponses;

+        break;

+      case 19: /* snmpInTraps */

+        *uint_ptr = snmpintraps;

+        break;

+      case 20: /* snmpOutTooBigs */

+        *uint_ptr = snmpouttoobigs;

+        break;

+      case 21: /* snmpOutNoSuchNames */

+        *uint_ptr = snmpoutnosuchnames;

+        break;

+      case 22: /* snmpOutBadValues */

+        *uint_ptr = snmpoutbadvalues;

+        break;

+      case 24: /* snmpOutGenErrs */

+        *uint_ptr = snmpoutgenerrs;

+        break;

+      case 25: /* snmpOutGetRequests */

+        *uint_ptr = snmpoutgetrequests;

+        break;

+      case 26: /* snmpOutGetNexts */

+        *uint_ptr = snmpoutgetnexts;

+        break;

+      case 27: /* snmpOutSetRequests */

+        *uint_ptr = snmpoutsetrequests;

+        break;

+      case 28: /* snmpOutGetResponses */

+        *uint_ptr = snmpoutgetresponses;

+        break;

+      case 29: /* snmpOutTraps */

+        *uint_ptr = snmpouttraps;

+        break;

+      case 30: /* snmpEnableAuthenTraps */

+        *uint_ptr = *snmpenableauthentraps_ptr;

+        break;

+  };

+}

+

+/**

+ * Test snmp object value before setting.

+ *

+ * @param od is the object definition

+ * @param len return value space (in bytes)

+ * @param value points to (varbind) space to copy value from.

+ */

+static u8_t

+snmp_set_test(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id, set_ok;

+

+  if (len) {}

+  set_ok = 0;

+  id = od->id_inst_ptr[0];

+  if (id == 30)

+  {

+    /* snmpEnableAuthenTraps */

+    s32_t *sint_ptr = value;

+

+    if (snmpenableauthentraps_ptr != &snmpenableauthentraps_default)

+    {

+      /* we should have writable non-volatile mem here */

+      if ((*sint_ptr == 1) || (*sint_ptr == 2))

+      {

+        set_ok = 1;

+      }

+    }

+    else

+    {

+      /* const or hardwired value */

+      if (*sint_ptr == snmpenableauthentraps_default)

+      {

+        set_ok = 1;

+      }

+    }

+  }

+  return set_ok;

+}

+

+static void

+snmp_set_value(struct obj_def *od, u16_t len, void *value)

+{

+  u8_t id;

+

+  if (len) {}

+  id = od->id_inst_ptr[0];

+  if (id == 30)

+  {

+    /* snmpEnableAuthenTraps */

+    s32_t *sint_ptr = value;

+    *snmpenableauthentraps_ptr = *sint_ptr;

+  }

+}

+

+#endif /* LWIP_SNMP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/mib_structs.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/mib_structs.c
new file mode 100644
index 0000000..cff50b5
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/mib_structs.c
@@ -0,0 +1,1183 @@
+/**

+ * @file

+ * MIB tree access/construction functions.

+ */

+

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * Author: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/snmp_structs.h"

+#include "lwip/mem.h"

+

+/** .iso.org.dod.internet address prefix, @see snmp_iso_*() */

+const s32_t prefix[4] = {1, 3, 6, 1};

+

+#define NODE_STACK_SIZE (LWIP_SNMP_OBJ_ID_LEN)

+/** node stack entry (old news?) */

+struct nse

+{

+  /** right child */

+  struct mib_node* r_ptr;

+  /** right child identifier */

+  s32_t r_id;

+  /** right child next level */

+  u8_t r_nl;

+};

+static u8_t node_stack_cnt;

+static struct nse node_stack[NODE_STACK_SIZE];

+

+/**

+ * Pushes nse struct onto stack.

+ */

+static void

+push_node(struct nse* node)

+{

+  LWIP_ASSERT("node_stack_cnt < NODE_STACK_SIZE",node_stack_cnt < NODE_STACK_SIZE);

+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("push_node() node=%p id=%"S32_F"\n",(void*)(node->r_ptr),node->r_id));

+  if (node_stack_cnt < NODE_STACK_SIZE)

+  {

+    node_stack[node_stack_cnt] = *node;

+    node_stack_cnt++;

+  }

+}

+

+/**

+ * Pops nse struct from stack.

+ */

+static void

+pop_node(struct nse* node)

+{

+  if (node_stack_cnt > 0)

+  {

+    node_stack_cnt--;

+    *node = node_stack[node_stack_cnt];

+  }

+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("pop_node() node=%p id=%"S32_F"\n",(void *)(node->r_ptr),node->r_id));

+}

+

+/**

+ * Conversion from ifIndex to lwIP netif

+ * @param ifindex is a s32_t object sub-identifier

+ * @param netif points to returned netif struct pointer

+ */

+void

+snmp_ifindextonetif(s32_t ifindex, struct netif **netif)

+{

+  struct netif *nif = netif_list;

+  u16_t i, ifidx;

+

+  ifidx = ifindex - 1;

+  i = 0;

+  while ((nif != NULL) && (i < ifidx))

+  {

+    nif = nif->next;

+    i++;

+  }

+  *netif = nif;

+}

+

+/**

+ * Conversion from lwIP netif to ifIndex

+ * @param netif points to a netif struct

+ * @param ifidx points to s32_t object sub-identifier

+ */

+void

+snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)

+{

+  struct netif *nif = netif_list;

+  u16_t i;

+

+  i = 0;

+  while (nif != netif)

+  {

+    nif = nif->next;

+    i++;

+  }

+  *ifidx = i+1;

+}

+

+/**

+ * Conversion from oid to lwIP ip_addr

+ * @param ident points to s32_t ident[4] input

+ * @param ip points to output struct

+ */

+void

+snmp_oidtoip(s32_t *ident, struct ip_addr *ip)

+{

+  u32_t ipa;

+

+  ipa = ident[0];

+  ipa <<= 8;

+  ipa |= ident[1];

+  ipa <<= 8;

+  ipa |= ident[2];

+  ipa <<= 8;

+  ipa |= ident[3];

+  ip->addr = ipa;

+}

+

+/**

+ * Conversion from lwIP ip_addr to oid

+ * @param ip points to input struct

+ * @param ident points to s32_t ident[4] output

+ */

+void

+snmp_iptooid(struct ip_addr *ip, s32_t *ident)

+{

+  u32_t ipa;

+

+  ipa = ip->addr;

+  ident[0] = (ipa >> 24) & 0xff;

+  ident[1] = (ipa >> 16) & 0xff;

+  ident[2] = (ipa >> 8) & 0xff;

+  ident[3] = ipa & 0xff;

+}

+

+struct mib_list_node *

+snmp_mib_ln_alloc(s32_t id)

+{

+  struct mib_list_node *ln;

+

+  ln = (struct mib_list_node *)mem_malloc(sizeof(struct mib_list_node));

+  if (ln != NULL)

+  {

+    ln->prev = NULL;

+    ln->next = NULL;

+    ln->objid = id;

+    ln->nptr = NULL;

+  }

+  return ln;

+}

+

+void

+snmp_mib_ln_free(struct mib_list_node *ln)

+{

+  mem_free(ln);

+}

+

+struct mib_list_rootnode *

+snmp_mib_lrn_alloc(void)

+{

+  struct mib_list_rootnode *lrn;

+

+  lrn = (struct mib_list_rootnode*)mem_malloc(sizeof(struct mib_list_rootnode));

+  if (lrn != NULL)

+  {

+    lrn->get_object_def = noleafs_get_object_def;

+    lrn->get_value = noleafs_get_value;

+    lrn->set_test = noleafs_set_test;

+    lrn->set_value = noleafs_set_value;

+    lrn->node_type = MIB_NODE_LR;

+    lrn->maxlength = 0;

+    lrn->head = NULL;

+    lrn->tail = NULL;

+    lrn->count = 0;

+  }

+  return lrn;

+}

+

+void

+snmp_mib_lrn_free(struct mib_list_rootnode *lrn)

+{

+  mem_free(lrn);

+}

+

+/**

+ * Inserts node in idx list in a sorted

+ * (ascending order) fashion and

+ * allocates the node if needed.

+ *

+ * @param rn points to the root node

+ * @param objid is the object sub identifier

+ * @param insn points to a pointer to the inserted node

+ *   used for constructing the tree.

+ * @return -1 if failed, 1 if inserted, 2 if present.

+ */

+s8_t

+snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn)

+{

+  struct mib_list_node *nn;

+  s8_t insert;

+

+  LWIP_ASSERT("rn != NULL",rn != NULL);

+

+  /* -1 = malloc failure, 0 = not inserted, 1 = inserted, 2 = was present */

+  insert = 0;

+  if (rn->head == NULL)

+  {

+    /* empty list, add first node */

+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc empty list objid==%"S32_F"\n",objid));

+    nn = snmp_mib_ln_alloc(objid);

+    if (nn != NULL)

+    {

+      rn->head = nn;

+      rn->tail = nn;

+      *insn = nn;

+      insert = 1;

+    }

+    else

+    {

+      insert = -1;

+    }

+  }

+  else

+  {

+    struct mib_list_node *n;

+    /* at least one node is present */

+    n = rn->head;

+    while ((n != NULL) && (insert == 0))

+    {

+      if (n->objid == objid)

+      {

+        /* node is already there */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("node already there objid==%"S32_F"\n",objid));

+        *insn = n;

+        insert = 2;

+      }

+      else if (n->objid < objid)

+      {

+        if (n->next == NULL)

+        {

+          /* alloc and insert at the tail */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins tail objid==%"S32_F"\n",objid));

+          nn = snmp_mib_ln_alloc(objid);

+          if (nn != NULL)

+          {

+            nn->next = NULL;

+            nn->prev = n;

+            n->next = nn;

+            rn->tail = nn;

+            *insn = nn;

+            insert = 1;

+          }

+          else

+          {

+            /* insertion failure */

+            insert = -1;

+          }

+        }

+        else

+        {

+          /* there's more to explore: traverse list */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("traverse list\n"));

+          n = n->next;

+        }

+      }

+      else

+      {

+        /* n->objid > objid */

+        /* alloc and insert between n->prev and n */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins n->prev, objid==%"S32_F", n\n",objid));

+        nn = snmp_mib_ln_alloc(objid);

+        if (nn != NULL)

+        {

+          if (n->prev == NULL)

+          {

+            /* insert at the head */

+            nn->next = n;

+            nn->prev = NULL;

+            rn->head = nn;

+            n->prev = nn;

+          }

+          else

+          {

+            /* insert in the middle */

+            nn->next = n;

+            nn->prev = n->prev;

+            n->prev->next = nn;

+            n->prev = nn;

+          }

+          *insn = nn;

+          insert = 1;

+        }

+        else

+        {

+          /* insertion failure */

+          insert = -1;

+        }

+      }

+    }

+  }

+  if (insert == 1)

+  {

+    rn->count += 1;

+  }

+  LWIP_ASSERT("insert != 0",insert != 0);

+  return insert;

+}

+

+/**

+ * Finds node in idx list and returns deletion mark.

+ *

+ * @param rn points to the root node

+ * @param objid  is the object sub identifier

+ * @param fn returns pointer to found node

+ * @return 0 if not found, 1 if deletable,

+ *   2 can't delete (2 or more children), 3 not a list_node

+ */

+s8_t

+snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn)

+{

+  s8_t fc;

+  struct mib_list_node *n;

+

+  LWIP_ASSERT("rn != NULL",rn != NULL);

+  n = rn->head;

+  while ((n != NULL) && (n->objid != objid))

+  {

+    n = n->next;

+  }

+  if (n == NULL)

+  {

+    fc = 0;

+  }

+  else if (n->nptr == NULL)

+  {

+    /* leaf, can delete node */

+    fc = 1;

+  }

+  else

+  {

+    struct mib_list_rootnode *r;

+

+    if (n->nptr->node_type == MIB_NODE_LR)

+    {

+      r = (struct mib_list_rootnode *)n->nptr;

+      if (r->count > 1)

+      {

+        /* can't delete node */

+        fc = 2;

+      }

+      else

+      {

+        /* count <= 1, can delete node */

+        fc = 1;

+      }

+    }

+    else

+    {

+      /* other node type */

+      fc = 3;

+    }

+  }

+  *fn = n;

+  return fc;

+}

+

+/**

+ * Removes node from idx list

+ * if it has a single child left.

+ *

+ * @param rn points to the root node

+ * @param n points to the node to delete

+ * @return the nptr to be freed by caller

+ */

+struct mib_list_rootnode *

+snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n)

+{

+  struct mib_list_rootnode *next;

+

+  LWIP_ASSERT("rn != NULL",rn != NULL);

+  LWIP_ASSERT("n != NULL",n != NULL);

+

+  /* caller must remove this sub-tree */

+  next = (struct mib_list_rootnode*)(n->nptr);

+  rn->count -= 1;

+

+  if (n == rn->head)

+  {

+    rn->head = n->next;

+    if (n->next != NULL)

+    {

+      /* not last node, new list begin */

+      n->next->prev = NULL;

+    }

+  }

+  else if (n == rn->tail)

+  {

+    rn->tail = n->prev;

+    if (n->prev != NULL)

+    {

+      /* not last node, new list end */

+      n->prev->next = NULL;

+    }

+  }

+  else

+  {

+    /* node must be in the middle */

+    n->prev->next = n->next;

+    n->next->prev = n->prev;

+  }

+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("free list objid==%"S32_F"\n",n->objid));

+  snmp_mib_ln_free(n);

+  if (rn->count == 0)

+  {

+    rn->head = NULL;

+    rn->tail = NULL;

+  }

+  return next;

+}

+

+

+

+/**

+ * Searches tree for the supplied (scalar?) object identifier.

+ *

+ * @param node points to the root of the tree ('.internet')

+ * @param ident_len the length of the supplied object identifier

+ * @param ident points to the array of sub identifiers

+ * @param np points to the found object instance (rerurn)

+ * @return pointer to the requested parent (!) node if success, NULL otherwise

+ */

+struct mib_node *

+snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np)

+{

+  u8_t node_type, ext_level;

+

+  ext_level = 0;

+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F"\n",(void*)node,*ident));

+  while (node != NULL)

+  {

+    node_type = node->node_type;

+    if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))

+    {

+      struct mib_array_node *an;

+      u16_t i;

+

+      if (ident_len > 0)

+      {

+        /* array node (internal ROM or RAM, fixed length) */

+        an = (struct mib_array_node *)node;

+        i = 0;

+        while ((i < an->maxlength) && (an->objid[i] != *ident))

+        {

+          i++;

+        }

+        if (i < an->maxlength)

+        {

+          /* found it, if available proceed to child, otherwise inspect leaf */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));

+          if (an->nptr[i] == NULL)

+          {

+            /* a scalar leaf OR table,

+               inspect remaining instance number / table index */

+            np->ident_len = ident_len;

+            np->ident = ident;

+            return (struct mib_node*)an;

+          }

+          else

+          {

+            /* follow next child pointer */

+            ident++;

+            ident_len--;

+            node = an->nptr[i];

+          }

+        }

+        else

+        {

+          /* search failed, identifier mismatch (nosuchname) */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed *ident==%"S32_F"\n",*ident));

+          return NULL;

+        }

+      }

+      else

+      {

+        /* search failed, short object identifier (nosuchname) */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed, short object identifier\n"));

+        return NULL;

+      }

+    }

+    else if(node_type == MIB_NODE_LR)

+    {

+      struct mib_list_rootnode *lrn;

+      struct mib_list_node *ln;

+

+      if (ident_len > 0)

+      {

+        /* list root node (internal 'RAM', variable length) */

+        lrn = (struct mib_list_rootnode *)node;

+        ln = lrn->head;

+        /* iterate over list, head to tail */

+        while ((ln != NULL) && (ln->objid != *ident))

+        {

+          ln = ln->next;

+        }

+        if (ln != NULL)

+        {

+          /* found it, proceed to child */;

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));

+          if (ln->nptr == NULL)

+          {

+            np->ident_len = ident_len;

+            np->ident = ident;

+            return (struct mib_node*)lrn;

+          }

+          else

+          {

+            /* follow next child pointer */

+            ident_len--;

+            ident++;

+            node = ln->nptr;

+          }

+        }

+        else

+        {

+          /* search failed */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed *ident==%"S32_F"\n",*ident));

+          return NULL;

+        }

+      }

+      else

+      {

+        /* search failed, short object identifier (nosuchname) */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed, short object identifier\n"));

+        return NULL;

+      }

+    }

+    else if(node_type == MIB_NODE_EX)

+    {

+      struct mib_external_node *en;

+      u16_t i, len;

+

+      if (ident_len > 0)

+      {

+        /* external node (addressing and access via functions) */

+        en = (struct mib_external_node *)node;

+

+        i = 0;

+        len = en->level_length(en->addr_inf,ext_level);

+        while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) != 0))

+        {

+          i++;

+        }

+        if (i < len)

+        {

+          s32_t debug_id;

+

+          en->get_objid(en->addr_inf,ext_level,i,&debug_id);

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid==%"S32_F" *ident==%"S32_F"\n",debug_id,*ident));

+          if ((ext_level + 1) == en->tree_levels)

+          {

+            np->ident_len = ident_len;

+            np->ident = ident;

+            return (struct mib_node*)en;

+          }

+          else

+          {

+            /* found it, proceed to child */

+            ident_len--;

+            ident++;

+            ext_level++;

+          }

+        }

+        else

+        {

+          /* search failed */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed *ident==%"S32_F"\n",*ident));

+          return NULL;

+        }

+      }

+      else

+      {

+        /* search failed, short object identifier (nosuchname) */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed, short object identifier\n"));

+        return NULL;

+      }

+    }

+    else if (node_type == MIB_NODE_SC)

+    {

+      mib_scalar_node *sn;

+

+      sn = (mib_scalar_node *)node;

+      if ((ident_len == 1) && (*ident == 0))

+      {

+        np->ident_len = ident_len;

+        np->ident = ident;

+        return (struct mib_node*)sn;

+      }

+      else

+      {

+        /* search failed, short object identifier (nosuchname) */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, invalid object identifier length\n"));

+        return NULL;

+      }

+    }

+    else

+    {

+      /* unknown node_type */

+      LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node_type %"U16_F" unkown\n",(u16_t)node_type));

+      return NULL;

+    }

+  }

+  /* done, found nothing */

+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p\n",(void*)node));

+  return NULL;

+}

+

+/**

+ * Test table for presence of at least one table entry.

+ */

+static u8_t

+empty_table(struct mib_node *node)

+{

+  u8_t node_type;

+  u8_t empty = 0;

+

+  if (node != NULL)

+  {

+    node_type = node->node_type;

+    if (node_type == MIB_NODE_LR)

+    {

+      struct mib_list_rootnode *lrn;

+      lrn = (struct mib_list_rootnode *)node;

+      if ((lrn->count == 0) || (lrn->head == NULL))

+      {

+        empty = 1;

+      }

+    }

+    else if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))

+    {

+      struct mib_array_node *an;

+      an = (struct mib_array_node *)node;

+      if ((an->maxlength == 0) || (an->nptr == NULL))

+      {

+        empty = 1;

+      }

+    }

+    else if (node_type == MIB_NODE_EX)

+    {

+      struct mib_external_node *en;

+      en = (struct mib_external_node *)node;

+      if (en->tree_levels == 0)

+      {

+        empty = 1;

+      }

+    }

+  }

+  return empty;

+}

+

+/**

+ * Tree expansion.

+ */

+struct mib_node *

+snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)

+{

+  u8_t node_type, ext_level, climb_tree;

+

+  ext_level = 0;

+  /* reset node stack */

+  node_stack_cnt = 0;

+  while (node != NULL)

+  {

+    climb_tree = 0;

+    node_type = node->node_type;

+    if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))

+    {

+      struct mib_array_node *an;

+      u16_t i;

+

+      /* array node (internal ROM or RAM, fixed length) */

+      an = (struct mib_array_node *)node;

+      if (ident_len > 0)

+      {

+        i = 0;

+        while ((i < an->maxlength) && (an->objid[i] < *ident))

+        {

+          i++;

+        }

+        if (i < an->maxlength)

+        {

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));

+          /* add identifier to oidret */

+          oidret->id[oidret->len] = an->objid[i];

+          (oidret->len)++;

+

+          if (an->nptr[i] == NULL)

+          {

+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));

+            /* leaf node (e.g. in a fixed size table) */

+            if (an->objid[i] > *ident)

+            {

+              return (struct mib_node*)an;

+            }

+            else if ((i + 1) < an->maxlength)

+            {

+              /* an->objid[i] == *ident */

+              (oidret->len)--;

+              oidret->id[oidret->len] = an->objid[i + 1];

+              (oidret->len)++;

+              return (struct mib_node*)an;

+            }

+            else

+            {

+              /* (i + 1) == an->maxlength */

+              (oidret->len)--;

+              climb_tree = 1;

+            }

+          }

+          else

+          {

+            u8_t j;

+            struct nse cur_node;

+

+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));

+            /* non-leaf, store right child ptr and id */

+            j = i + 1;

+            while ((j < an->maxlength) && (empty_table(an->nptr[j])))

+            {

+              j++;

+            }

+            if (j < an->maxlength)

+            {

+              cur_node.r_ptr = an->nptr[j];

+              cur_node.r_id = an->objid[j];

+              cur_node.r_nl = 0;

+            }

+            else

+            {

+              cur_node.r_ptr = NULL;

+            }

+            push_node(&cur_node);

+            if (an->objid[i] == *ident)

+            {

+              ident_len--;

+              ident++;

+            }

+            else

+            {

+              /* an->objid[i] < *ident */

+              ident_len = 0;

+            }

+            /* follow next child pointer */

+            node = an->nptr[i];

+          }

+        }

+        else

+        {

+          /* i == an->maxlength */

+          climb_tree = 1;

+        }

+      }

+      else

+      {

+        u8_t j;

+        /* ident_len == 0, complete with leftmost '.thing' */

+        j = 0;

+        while ((j < an->maxlength) && empty_table(an->nptr[j]))

+        {

+          j++;

+        }

+        if (j < an->maxlength)

+        {

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("left an->objid[j]==%"S32_F"\n",an->objid[j]));

+          oidret->id[oidret->len] = an->objid[j];

+          (oidret->len)++;

+          if (an->nptr[j] == NULL)

+          {

+            /* leaf node */

+            return (struct mib_node*)an;

+          }

+          else

+          {

+            /* no leaf, continue */

+            node = an->nptr[j];

+          }

+        }

+        else

+        {

+          /* j == an->maxlength */

+          climb_tree = 1;

+        }

+      }

+    }

+    else if(node_type == MIB_NODE_LR)

+    {

+      struct mib_list_rootnode *lrn;

+      struct mib_list_node *ln;

+

+      /* list root node (internal 'RAM', variable length) */

+      lrn = (struct mib_list_rootnode *)node;

+      if (ident_len > 0)

+      {

+        ln = lrn->head;

+        /* iterate over list, head to tail */

+        while ((ln != NULL) && (ln->objid < *ident))

+        {

+          ln = ln->next;

+        }

+        if (ln != NULL)

+        {

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));

+          oidret->id[oidret->len] = ln->objid;

+          (oidret->len)++;

+          if (ln->nptr == NULL)

+          {

+            /* leaf node */

+            if (ln->objid > *ident)

+            {

+              return (struct mib_node*)lrn;

+            }

+            else if (ln->next != NULL)

+            {

+              /* ln->objid == *ident */

+              (oidret->len)--;

+              oidret->id[oidret->len] = ln->next->objid;

+              (oidret->len)++;

+              return (struct mib_node*)lrn;

+            }

+            else

+            {

+              /* ln->next == NULL */

+              (oidret->len)--;

+              climb_tree = 1;

+            }

+          }

+          else

+          {

+            struct mib_list_node *jn;

+            struct nse cur_node;

+

+            /* non-leaf, store right child ptr and id */

+            jn = ln->next;

+            while ((jn != NULL) && empty_table(jn->nptr))

+            {

+              jn = jn->next;

+            }

+            if (jn != NULL)

+            {

+              cur_node.r_ptr = jn->nptr;

+              cur_node.r_id = jn->objid;

+              cur_node.r_nl = 0;

+            }

+            else

+            {

+              cur_node.r_ptr = NULL;

+            }

+            push_node(&cur_node);

+            if (ln->objid == *ident)

+            {

+              ident_len--;

+              ident++;

+            }

+            else

+            {

+              /* ln->objid < *ident */

+              ident_len = 0;

+            }

+            /* follow next child pointer */

+            node = ln->nptr;

+          }

+

+        }

+        else

+        {

+          /* ln == NULL */

+          climb_tree = 1;

+        }

+      }

+      else

+      {

+        struct mib_list_node *jn;

+        /* ident_len == 0, complete with leftmost '.thing' */

+        jn = lrn->head;

+        while ((jn != NULL) && empty_table(jn->nptr))

+        {

+          jn = jn->next;

+        }

+        if (jn != NULL)

+        {

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("left jn->objid==%"S32_F"\n",jn->objid));

+          oidret->id[oidret->len] = jn->objid;

+          (oidret->len)++;

+          if (jn->nptr == NULL)

+          {

+            /* leaf node */

+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("jn->nptr == NULL\n"));

+            return (struct mib_node*)lrn;

+          }

+          else

+          {

+            /* no leaf, continue */

+            node = jn->nptr;

+          }

+        }

+        else

+        {

+          /* jn == NULL */

+          climb_tree = 1;

+        }

+      }

+    }

+    else if(node_type == MIB_NODE_EX)

+    {

+      struct mib_external_node *en;

+      s32_t ex_id;

+

+      /* external node (addressing and access via functions) */

+      en = (struct mib_external_node *)node;

+      if (ident_len > 0)

+      {

+        u16_t i, len;

+

+        i = 0;

+        len = en->level_length(en->addr_inf,ext_level);

+        while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) < 0))

+        {

+          i++;

+        }

+        if (i < len)

+        {

+          /* add identifier to oidret */

+          en->get_objid(en->addr_inf,ext_level,i,&ex_id);

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,ex_id,*ident));

+          oidret->id[oidret->len] = ex_id;

+          (oidret->len)++;

+

+          if ((ext_level + 1) == en->tree_levels)

+          {

+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));

+            /* leaf node */

+            if (ex_id > *ident)

+            {

+              return (struct mib_node*)en;

+            }

+            else if ((i + 1) < len)

+            {

+              /* ex_id == *ident */

+              en->get_objid(en->addr_inf,ext_level,i + 1,&ex_id);

+              (oidret->len)--;

+              oidret->id[oidret->len] = ex_id;

+              (oidret->len)++;

+              return (struct mib_node*)en;

+            }

+            else

+            {

+              /* (i + 1) == len */

+              (oidret->len)--;

+              climb_tree = 1;

+            }

+          }

+          else

+          {

+            u8_t j;

+            struct nse cur_node;

+

+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));

+            /* non-leaf, store right child ptr and id */

+            j = i + 1;

+            if (j < len)

+            {

+              /* right node is the current external node */

+              cur_node.r_ptr = node;

+              en->get_objid(en->addr_inf,ext_level,j,&cur_node.r_id);

+              cur_node.r_nl = ext_level + 1;

+            }

+            else

+            {

+              cur_node.r_ptr = NULL;

+            }

+            push_node(&cur_node);

+            if (en->ident_cmp(en->addr_inf,ext_level,i,*ident) == 0)

+            {

+              ident_len--;

+              ident++;

+            }

+            else

+            {

+              /* external id < *ident */

+              ident_len = 0;

+            }

+            /* proceed to child */

+            ext_level++;

+          }

+        }

+        else

+        {

+          /* i == len (en->level_len()) */

+          climb_tree = 1;

+        }

+      }

+      else

+      {

+        /* ident_len == 0, complete with leftmost '.thing' */

+        en->get_objid(en->addr_inf,ext_level,0,&ex_id);

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("left en->objid==%"S32_F"\n",ex_id));

+        oidret->id[oidret->len] = ex_id;

+        (oidret->len)++;

+        if ((ext_level + 1) == en->tree_levels)

+        {

+          /* leaf node */

+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("(ext_level + 1) == en->tree_levels\n"));

+          return (struct mib_node*)en;

+        }

+        else

+        {

+          /* no leaf, proceed to child */

+          ext_level++;

+        }

+      }

+    }

+    else if(node_type == MIB_NODE_SC)

+    {

+      mib_scalar_node *sn;

+

+      /* scalar node  */

+      sn = (mib_scalar_node *)node;

+      if (ident_len > 0)

+      {

+        /* at .0 */

+        climb_tree = 1;

+      }

+      else

+      {

+        /* ident_len == 0, complete object identifier */

+        oidret->id[oidret->len] = 0;

+        (oidret->len)++;

+        /* leaf node */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("completed scalar leaf\n"));

+        return (struct mib_node*)sn;

+      }

+    }

+    else

+    {

+      /* unknown/unhandled node_type */

+      LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node_type %"U16_F" unkown\n",(u16_t)node_type));

+      return NULL;

+    }

+

+    if (climb_tree)

+    {

+      struct nse child;

+

+      /* find right child ptr */

+      child.r_ptr = NULL;

+      child.r_id = 0;

+      child.r_nl = 0;

+      while ((node_stack_cnt > 0) && (child.r_ptr == NULL))

+      {

+        pop_node(&child);

+        /* trim returned oid */

+        (oidret->len)--;

+      }

+      if (child.r_ptr != NULL)

+      {

+        /* incoming ident is useless beyond this point */

+        ident_len = 0;

+        oidret->id[oidret->len] = child.r_id;

+        oidret->len++;

+        node = child.r_ptr;

+        ext_level = child.r_nl;

+      }

+      else

+      {

+        /* tree ends here ... */

+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed, tree ends here\n"));

+        return NULL;

+      }

+    }

+  }

+  /* done, found nothing */

+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node==%p\n",(void*)node));

+  return NULL;

+}

+

+/**

+ * Test object identifier for the iso.org.dod.internet prefix.

+ *

+ * @param ident_len the length of the supplied object identifier

+ * @param ident points to the array of sub identifiers

+ * @return 1 if it matches, 0 otherwise

+ */

+u8_t

+snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident)

+{

+  if ((ident_len > 3) &&

+      (ident[0] == 1) && (ident[1] == 3) &&

+      (ident[2] == 6) && (ident[3] == 1))

+  {

+    return 1;

+  }

+  else

+  {

+    return 0;

+  }

+}

+

+/**

+ * Expands object identifier to the iso.org.dod.internet

+ * prefix for use in getnext operation.

+ *

+ * @param ident_len the length of the supplied object identifier

+ * @param ident points to the array of sub identifiers

+ * @param oidret points to returned expanded object identifier

+ * @return 1 if it matches, 0 otherwise

+ *

+ * @note ident_len 0 is allowed, expanding to the first known object id!!

+ */

+u8_t

+snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)

+{

+  const s32_t *prefix_ptr;

+  s32_t *ret_ptr;

+  u8_t i;

+

+  i = 0;

+  prefix_ptr = &prefix[0];

+  ret_ptr = &oidret->id[0];

+  ident_len = ((ident_len < 4)?ident_len:4);

+  while ((i < ident_len) && ((*ident) <= (*prefix_ptr)))

+  {

+    *ret_ptr++ = *prefix_ptr++;

+    ident++;

+    i++;

+  }

+  if (i == ident_len)

+  {

+    /* match, complete missing bits */

+    while (i < 4)

+    {

+      *ret_ptr++ = *prefix_ptr++;

+      i++;

+    }

+    oidret->len = i;

+    return 1;

+  }

+  else

+  {

+    /* i != ident_len */

+    return 0;

+  }

+}

+

+#endif /* LWIP_SNMP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/msg_in.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/msg_in.c
new file mode 100644
index 0000000..4f62bc9
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/msg_in.c
@@ -0,0 +1,1453 @@
+/**

+ * @file

+ * SNMP input message processing (RFC1157).

+ */

+

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * Author: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/ip_addr.h"

+#include "lwip/mem.h"

+#include "lwip/udp.h"

+#include "lwip/stats.h"

+#include "lwip/snmp.h"

+#include "lwip/snmp_asn1.h"

+#include "lwip/snmp_msg.h"

+#include "lwip/snmp_structs.h"

+

+#include <string.h>

+

+/* public (non-static) constants */

+/** SNMP v1 == 0 */

+const s32_t snmp_version = 0;

+/** default SNMP community string */

+const char snmp_publiccommunity[7] = "public";

+

+/* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */

+struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS];

+/* UDP Protocol Control Block */

+struct udp_pcb *snmp1_pcb;

+

+static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);

+static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);

+static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);

+

+

+/**

+ * Starts SNMP Agent.

+ * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.

+ */

+void

+snmp_init(void)

+{

+  struct snmp_msg_pstat *msg_ps;

+  u8_t i;

+

+  snmp1_pcb = udp_new();

+  if (snmp1_pcb != NULL)

+  {

+    udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT);

+    udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT);

+  }

+  msg_ps = &msg_input_list[0];

+  for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++)

+  {

+    msg_ps->state = SNMP_MSG_EMPTY;

+    msg_ps->error_index = 0;

+    msg_ps->error_status = SNMP_ES_NOERROR;

+    msg_ps++;

+  }

+  trap_msg.pcb = snmp1_pcb;

+  /* The coldstart trap will only be output

+     if our outgoing interface is up & configured  */

+  snmp_coldstart_trap();

+}

+

+static void

+snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error)

+{

+  snmp_varbind_list_free(&msg_ps->outvb);

+  msg_ps->outvb = msg_ps->invb;

+  msg_ps->invb.head = NULL;

+  msg_ps->invb.tail = NULL;

+  msg_ps->invb.count = 0;

+  msg_ps->error_status = error;

+  msg_ps->error_index = 1 + msg_ps->vb_idx;

+  snmp_send_response(msg_ps);

+  snmp_varbind_list_free(&msg_ps->outvb);

+  msg_ps->state = SNMP_MSG_EMPTY;

+}

+

+static void

+snmp_ok_response(struct snmp_msg_pstat *msg_ps)

+{

+  err_t err_ret;

+

+  err_ret = snmp_send_response(msg_ps);

+  if (err_ret == ERR_MEM)

+  {

+    /* serious memory problem, can't return tooBig */

+  }

+  else

+  {

+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status));

+  }

+  /* free varbinds (if available) */

+  snmp_varbind_list_free(&msg_ps->invb);

+  snmp_varbind_list_free(&msg_ps->outvb);

+  msg_ps->state = SNMP_MSG_EMPTY;

+}

+

+/**

+ * Service an internal or external event for SNMP GET.

+ *

+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)

+ * @param msg_ps points to the assosicated message process state

+ */

+static void

+snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)

+{

+  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));

+

+  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)

+  {

+    struct mib_external_node *en;

+    struct snmp_name_ptr np;

+

+    /* get_object_def() answer*/

+    en = msg_ps->ext_mib_node;

+    np = msg_ps->ext_name_ptr;

+

+    /* translate answer into a known lifeform */

+    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);

+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)

+    {

+      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;

+      en->get_value_q(request_id, &msg_ps->ext_object_def);

+    }

+    else

+    {

+      en->get_object_def_pc(request_id, np.ident_len, np.ident);

+      /* search failed, object id points to unknown object (nosuchname) */

+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+    }

+  }

+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)

+  {

+    struct mib_external_node *en;

+    struct snmp_varbind *vb;

+

+    /* get_value() answer */

+    en = msg_ps->ext_mib_node;

+

+    /* allocate output varbind */

+    vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));

+    LWIP_ASSERT("vb != NULL",vb != NULL);

+    if (vb != NULL)

+    {

+      vb->next = NULL;

+      vb->prev = NULL;

+

+      /* move name from invb to outvb */

+      vb->ident = msg_ps->vb_ptr->ident;

+      vb->ident_len = msg_ps->vb_ptr->ident_len;

+      /* ensure this memory is refereced once only */

+      msg_ps->vb_ptr->ident = NULL;

+      msg_ps->vb_ptr->ident_len = 0;

+

+      vb->value_type = msg_ps->ext_object_def.asn_type;

+      vb->value_len =  msg_ps->ext_object_def.v_len;

+      if (vb->value_len > 0)

+      {

+        vb->value = mem_malloc(vb->value_len);

+        LWIP_ASSERT("vb->value != NULL",vb->value != NULL);

+        if (vb->value != NULL)

+        {

+          en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);

+          snmp_varbind_tail_add(&msg_ps->outvb, vb);

+          /* search again (if vb_idx < msg_ps->invb.count) */

+          msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+          msg_ps->vb_idx += 1;

+        }

+        else

+        {

+          en->get_value_pc(request_id, &msg_ps->ext_object_def);

+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n"));

+          msg_ps->vb_ptr->ident = vb->ident;

+          msg_ps->vb_ptr->ident_len = vb->ident_len;

+          mem_free(vb);

+          snmp_error_response(msg_ps,SNMP_ES_TOOBIG);

+        }

+      }

+      else

+      {

+        /* vb->value_len == 0, empty value (e.g. empty string) */

+        en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);

+        vb->value = NULL;

+        snmp_varbind_tail_add(&msg_ps->outvb, vb);

+        /* search again (if vb_idx < msg_ps->invb.count) */

+        msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+        msg_ps->vb_idx += 1;

+      }

+    }

+    else

+    {

+      en->get_value_pc(request_id, &msg_ps->ext_object_def);

+      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n"));

+      snmp_error_response(msg_ps,SNMP_ES_TOOBIG);

+    }

+  }

+

+  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&

+         (msg_ps->vb_idx < msg_ps->invb.count))

+  {

+    struct mib_node *mn;

+    struct snmp_name_ptr np;

+

+    if (msg_ps->vb_idx == 0)

+    {

+      msg_ps->vb_ptr = msg_ps->invb.head;

+    }

+    else

+    {

+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;

+    }

+    /** test object identifier for .iso.org.dod.internet prefix */

+    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))

+    {

+      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,

+                             msg_ps->vb_ptr->ident + 4, &np);

+      if (mn != NULL)

+      {

+        if (mn->node_type == MIB_NODE_EX)

+        {

+          /* external object */

+          struct mib_external_node *en = (struct mib_external_node*)mn;

+

+          msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;

+          /* save en && args in msg_ps!! */

+          msg_ps->ext_mib_node = en;

+          msg_ps->ext_name_ptr = np;

+

+          en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);

+        }

+        else

+        {

+          /* internal object */

+          struct obj_def object_def;

+

+          msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;

+          mn->get_object_def(np.ident_len, np.ident, &object_def);

+          if (object_def.instance != MIB_OBJECT_NONE)

+          {

+            mn = mn;

+          }

+          else

+          {

+            /* search failed, object id points to unknown object (nosuchname) */

+            mn =  NULL;

+          }

+          if (mn != NULL)

+          {

+            struct snmp_varbind *vb;

+

+            msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;

+            /* allocate output varbind */

+            vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));

+            LWIP_ASSERT("vb != NULL",vb != NULL);

+            if (vb != NULL)

+            {

+              vb->next = NULL;

+              vb->prev = NULL;

+

+              /* move name from invb to outvb */

+              vb->ident = msg_ps->vb_ptr->ident;

+              vb->ident_len = msg_ps->vb_ptr->ident_len;

+              /* ensure this memory is refereced once only */

+              msg_ps->vb_ptr->ident = NULL;

+              msg_ps->vb_ptr->ident_len = 0;

+

+              vb->value_type = object_def.asn_type;

+              vb->value_len = object_def.v_len;

+              if (vb->value_len > 0)

+              {

+                vb->value = mem_malloc(vb->value_len);

+                LWIP_ASSERT("vb->value != NULL",vb->value != NULL);

+                if (vb->value != NULL)

+                {

+                  mn->get_value(&object_def, vb->value_len, vb->value);

+                  snmp_varbind_tail_add(&msg_ps->outvb, vb);

+                  msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+                  msg_ps->vb_idx += 1;

+                }

+                else

+                {

+                  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));

+                  msg_ps->vb_ptr->ident = vb->ident;

+                  msg_ps->vb_ptr->ident_len = vb->ident_len;

+                  mem_free(vb);

+                  snmp_error_response(msg_ps,SNMP_ES_TOOBIG);

+                }

+              }

+              else

+              {

+                /* vb->value_len == 0, empty value (e.g. empty string) */

+                vb->value = NULL;

+                snmp_varbind_tail_add(&msg_ps->outvb, vb);

+                msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+                msg_ps->vb_idx += 1;

+              }

+            }

+            else

+            {

+              LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n"));

+              snmp_error_response(msg_ps,SNMP_ES_TOOBIG);

+            }

+          }

+        }

+      }

+    }

+    else

+    {

+      mn = NULL;

+    }

+    if (mn == NULL)

+    {

+      /* mn == NULL, noSuchName */

+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+    }

+  }

+  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&

+      (msg_ps->vb_idx == msg_ps->invb.count))

+  {

+    snmp_ok_response(msg_ps);

+  }

+}

+

+/**

+ * Service an internal or external event for SNMP GETNEXT.

+ *

+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)

+ * @param msg_ps points to the assosicated message process state

+ */

+static void

+snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)

+{

+  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));

+

+  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)

+  {

+    struct mib_external_node *en;

+

+    /* get_object_def() answer*/

+    en = msg_ps->ext_mib_node;

+

+    /* translate answer into a known lifeform */

+    en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def);

+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)

+    {

+      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;

+      en->get_value_q(request_id, &msg_ps->ext_object_def);

+    }

+    else

+    {

+      en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]);

+      /* search failed, object id points to unknown object (nosuchname) */

+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+    }

+  }

+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)

+  {

+    struct mib_external_node *en;

+    struct snmp_varbind *vb;

+

+    /* get_value() answer */

+    en = msg_ps->ext_mib_node;

+

+    vb = snmp_varbind_alloc(&msg_ps->ext_oid,

+                            msg_ps->ext_object_def.asn_type,

+                            msg_ps->ext_object_def.v_len);

+    if (vb != NULL)

+    {

+      en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);

+      snmp_varbind_tail_add(&msg_ps->outvb, vb);

+      msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+      msg_ps->vb_idx += 1;

+    }

+    else

+    {

+      en->get_value_pc(request_id, &msg_ps->ext_object_def);

+      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n"));

+      snmp_error_response(msg_ps,SNMP_ES_TOOBIG);

+    }

+  }

+

+  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&

+         (msg_ps->vb_idx < msg_ps->invb.count))

+  {

+    struct mib_node *mn;

+    struct snmp_obj_id oid;

+

+    if (msg_ps->vb_idx == 0)

+    {

+      msg_ps->vb_ptr = msg_ps->invb.head;

+    }

+    else

+    {

+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;

+    }

+    if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid))

+    {

+      if (msg_ps->vb_ptr->ident_len > 3)

+      {

+        /* can offset ident_len and ident */

+        mn = snmp_expand_tree((struct mib_node*)&internet,

+                              msg_ps->vb_ptr->ident_len - 4,

+                              msg_ps->vb_ptr->ident + 4, &oid);

+      }

+      else

+      {

+        /* can't offset ident_len -4, ident + 4 */

+        mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid);

+      }

+    }

+    else

+    {

+      mn = NULL;

+    }

+    if (mn != NULL)

+    {

+      if (mn->node_type == MIB_NODE_EX)

+      {

+        /* external object */

+        struct mib_external_node *en = (struct mib_external_node*)mn;

+

+        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;

+        /* save en && args in msg_ps!! */

+        msg_ps->ext_mib_node = en;

+        msg_ps->ext_oid = oid;

+

+        en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]);

+      }

+      else

+      {

+        /* internal object */

+        struct obj_def object_def;

+        struct snmp_varbind *vb;

+

+        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;

+        mn->get_object_def(1, &oid.id[oid.len - 1], &object_def);

+

+        vb = snmp_varbind_alloc(&oid, object_def.asn_type, object_def.v_len);

+        if (vb != NULL)

+        {

+          msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;

+          mn->get_value(&object_def, object_def.v_len, vb->value);

+          snmp_varbind_tail_add(&msg_ps->outvb, vb);

+          msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+          msg_ps->vb_idx += 1;

+        }

+        else

+        {

+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n"));

+          snmp_error_response(msg_ps,SNMP_ES_TOOBIG);

+        }

+      }

+    }

+    if (mn == NULL)

+    {

+      /* mn == NULL, noSuchName */

+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+    }

+  }

+  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&

+      (msg_ps->vb_idx == msg_ps->invb.count))

+  {

+    snmp_ok_response(msg_ps);

+  }

+}

+

+/**

+ * Service an internal or external event for SNMP SET.

+ *

+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)

+ * @param msg_ps points to the assosicated message process state

+ */

+static void

+snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)

+{

+  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));

+

+  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)

+  {

+    struct mib_external_node *en;

+    struct snmp_name_ptr np;

+

+    /* get_object_def() answer*/

+    en = msg_ps->ext_mib_node;

+    np = msg_ps->ext_name_ptr;

+

+    /* translate answer into a known lifeform */

+    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);

+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)

+    {

+      msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST;

+      en->set_test_q(request_id, &msg_ps->ext_object_def);

+    }

+    else

+    {

+      en->get_object_def_pc(request_id, np.ident_len, np.ident);

+      /* search failed, object id points to unknown object (nosuchname) */

+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+    }

+  }

+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST)

+  {

+    struct mib_external_node *en;

+

+    /* set_test() answer*/

+    en = msg_ps->ext_mib_node;

+

+    if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE)

+    {

+       if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&

+           (en->set_test_a(request_id,&msg_ps->ext_object_def,

+                           msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))

+      {

+        msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+        msg_ps->vb_idx += 1;

+      }

+      else

+      {

+        en->set_test_pc(request_id,&msg_ps->ext_object_def);

+        /* bad value */

+        snmp_error_response(msg_ps,SNMP_ES_BADVALUE);

+      }

+    }

+    else

+    {

+      en->set_test_pc(request_id,&msg_ps->ext_object_def);

+      /* object not available for set */

+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+    }

+  }

+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)

+  {

+    struct mib_external_node *en;

+    struct snmp_name_ptr np;

+

+    /* get_object_def() answer*/

+    en = msg_ps->ext_mib_node;

+    np = msg_ps->ext_name_ptr;

+

+    /* translate answer into a known lifeform */

+    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);

+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)

+    {

+      msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE;

+      en->set_value_q(request_id, &msg_ps->ext_object_def,

+                      msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);

+    }

+    else

+    {

+      en->get_object_def_pc(request_id, np.ident_len, np.ident);

+      /* set_value failed, object has disappeared for some odd reason?? */

+      snmp_error_response(msg_ps,SNMP_ES_GENERROR);

+    }

+  }

+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE)

+  {

+    struct mib_external_node *en;

+

+    /** set_value_a() @todo: use reply value?? */

+    en = msg_ps->ext_mib_node;

+    en->set_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);

+

+    /** @todo use set_value_pc() if toobig */

+    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;

+    msg_ps->vb_idx += 1;

+  }

+

+  /* test all values before setting */

+  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&

+         (msg_ps->vb_idx < msg_ps->invb.count))

+  {

+    struct mib_node *mn;

+    struct snmp_name_ptr np;

+

+    if (msg_ps->vb_idx == 0)

+    {

+      msg_ps->vb_ptr = msg_ps->invb.head;

+    }

+    else

+    {

+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;

+    }

+    /** test object identifier for .iso.org.dod.internet prefix */

+    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))

+    {

+      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,

+                             msg_ps->vb_ptr->ident + 4, &np);

+      if (mn != NULL)

+      {

+        if (mn->node_type == MIB_NODE_EX)

+        {

+          /* external object */

+          struct mib_external_node *en = (struct mib_external_node*)mn;

+

+          msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;

+          /* save en && args in msg_ps!! */

+          msg_ps->ext_mib_node = en;

+          msg_ps->ext_name_ptr = np;

+

+          en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);

+        }

+        else

+        {

+          /* internal object */

+          struct obj_def object_def;

+

+          msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;

+          mn->get_object_def(np.ident_len, np.ident, &object_def);

+          if (object_def.instance != MIB_OBJECT_NONE)

+          {

+            mn = mn;

+          }

+          else

+          {

+            /* search failed, object id points to unknown object (nosuchname) */

+            mn = NULL;

+          }

+          if (mn != NULL)

+          {

+            msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;

+

+            if (object_def.access == MIB_OBJECT_READ_WRITE)

+            {

+              if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&

+                  (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))

+              {

+                msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+                msg_ps->vb_idx += 1;

+              }

+              else

+              {

+                /* bad value */

+                snmp_error_response(msg_ps,SNMP_ES_BADVALUE);

+              }

+            }

+            else

+            {

+              /* object not available for set */

+              snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+            }

+          }

+        }

+      }

+    }

+    else

+    {

+      mn = NULL;

+    }

+    if (mn == NULL)

+    {

+      /* mn == NULL, noSuchName */

+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);

+    }

+  }

+

+  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&

+      (msg_ps->vb_idx == msg_ps->invb.count))

+  {

+    msg_ps->vb_idx = 0;

+    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;

+  }

+

+  /* set all values "atomically" (be as "atomic" as possible) */

+  while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&

+         (msg_ps->vb_idx < msg_ps->invb.count))

+  {

+    struct mib_node *mn;

+    struct snmp_name_ptr np;

+

+    if (msg_ps->vb_idx == 0)

+    {

+      msg_ps->vb_ptr = msg_ps->invb.head;

+    }

+    else

+    {

+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;

+    }

+    /* skip iso prefix test, was done previously while settesting() */

+    mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,

+                           msg_ps->vb_ptr->ident + 4, &np);

+    /* check if object is still available

+       (e.g. external hot-plug thingy present?) */

+    if (mn != NULL)

+    {

+      if (mn->node_type == MIB_NODE_EX)

+      {

+        /* external object */

+        struct mib_external_node *en = (struct mib_external_node*)mn;

+

+        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S;

+        /* save en && args in msg_ps!! */

+        msg_ps->ext_mib_node = en;

+        msg_ps->ext_name_ptr = np;

+

+        en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);

+      }

+      else

+      {

+        /* internal object */

+        struct obj_def object_def;

+

+        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S;

+        mn->get_object_def(np.ident_len, np.ident, &object_def);

+        msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;

+        mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);

+        msg_ps->vb_idx += 1;

+      }

+    }

+  }

+  if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&

+      (msg_ps->vb_idx == msg_ps->invb.count))

+  {

+    /* simply echo the input if we can set it

+       @todo do we need to return the actual value?

+       e.g. if value is silently modified or behaves sticky? */

+    msg_ps->outvb = msg_ps->invb;

+    msg_ps->invb.head = NULL;

+    msg_ps->invb.tail = NULL;

+    msg_ps->invb.count = 0;

+    snmp_ok_response(msg_ps);

+  }

+}

+

+

+/**

+ * Handle one internal or external event.

+ * Called for one async event. (recv external/private answer)

+ *

+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)

+ */

+void

+snmp_msg_event(u8_t request_id)

+{

+  struct snmp_msg_pstat *msg_ps;

+

+  if (request_id < SNMP_CONCURRENT_REQUESTS)

+  {

+    msg_ps = &msg_input_list[request_id];

+    if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ)

+    {

+      snmp_msg_getnext_event(request_id, msg_ps);

+    }

+    else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)

+    {

+      snmp_msg_get_event(request_id, msg_ps);

+    }

+    else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)

+    {

+      snmp_msg_set_event(request_id, msg_ps);

+    }

+  }

+}

+

+

+/* lwIP UDP receive callback function */

+static void

+snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)

+{

+  struct udp_hdr *udphdr;

+

+  /* suppress unused argument warning */

+  LWIP_UNUSED_ARG(arg);

+  /* peek in the UDP header (goto IP payload) */

+  if(pbuf_header(p, UDP_HLEN)){

+    LWIP_ASSERT("Can't move to UDP header", 0);

+    pbuf_free(p);

+    return;

+  }

+  udphdr = p->payload;

+

+  /* check if datagram is really directed at us (including broadcast requests) */

+  if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == SNMP_IN_PORT))

+  {

+    struct snmp_msg_pstat *msg_ps;

+    u8_t req_idx;

+

+    /* traverse input message process list, look for SNMP_MSG_EMPTY */

+    msg_ps = &msg_input_list[0];

+    req_idx = 0;

+    while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))

+    {

+      req_idx++;

+      msg_ps++;

+    }

+    if (req_idx != SNMP_CONCURRENT_REQUESTS)

+    {

+      err_t err_ret;

+      u16_t payload_len;

+      u16_t payload_ofs;

+      u16_t varbind_ofs = 0;

+

+      /* accepting request */

+      snmp_inc_snmpinpkts();

+      /* record used 'protocol control block' */

+      msg_ps->pcb = pcb;

+      /* source address (network order) */

+      msg_ps->sip = *addr;

+      /* source port (host order (lwIP oddity)) */

+      msg_ps->sp = port;

+      /* read UDP payload length from UDP header */

+      payload_len = ntohs(udphdr->len) - UDP_HLEN;

+

+      /* adjust to UDP payload */

+      payload_ofs = UDP_HLEN;

+

+      /* check total length, version, community, pdu type */

+      err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);

+      if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||

+           (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||

+           (msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) &&

+          ((msg_ps->error_status == SNMP_ES_NOERROR) &&

+           (msg_ps->error_index == 0)) )

+      {

+        /* Only accept requests and requests without error (be robust) */

+        err_ret = err_ret;

+      }

+      else

+      {

+        /* Reject response and trap headers or error requests as input! */

+        err_ret = ERR_ARG;

+      }

+      if (err_ret == ERR_OK)

+      {

+        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));

+

+        /* Builds a list of variable bindings. Copy the varbinds from the pbuf

+          chain to glue them when these are divided over two or more pbuf's. */

+        err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);

+        if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0))

+        {

+          /* we've decoded the incoming message, release input msg now */

+          pbuf_free(p);

+

+          msg_ps->error_status = SNMP_ES_NOERROR;

+          msg_ps->error_index = 0;

+          /* find object for each variable binding */

+          msg_ps->state = SNMP_MSG_SEARCH_OBJ;

+          /* first variable binding from list to inspect */

+          msg_ps->vb_idx = 0;

+

+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));

+

+          /* handle input event and as much objects as possible in one go */

+          snmp_msg_event(req_idx);

+        }

+        else

+        {

+          /* varbind-list decode failed, or varbind list empty.

+             drop request silently, do not return error!

+             (errors are only returned for a specific varbind failure) */

+          pbuf_free(p);

+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));

+        }

+      }

+      else

+      {

+        /* header check failed

+           drop request silently, do not return error! */

+        pbuf_free(p);

+        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));

+      }

+    }

+    else

+    {

+      /* exceeding number of concurrent requests */

+      pbuf_free(p);

+    }

+  }

+  else

+  {

+    /* datagram not for us */

+    pbuf_free(p);

+  }

+}

+

+/**

+ * Checks and decodes incoming SNMP message header, logs header errors.

+ *

+ * @param p points to pbuf chain of SNMP message (UDP payload)

+ * @param ofs points to first octet of SNMP message

+ * @param pdu_len the length of the UDP payload

+ * @param ofs_ret returns the ofset of the variable bindings

+ * @param m_stat points to the current message request state return

+ * @return

+ * - ERR_OK SNMP header is sane and accepted

+ * - ERR_ARG SNMP header is either malformed or rejected

+ */

+static err_t

+snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)

+{

+  err_t derr;

+  u16_t len, ofs_base;

+  u8_t  len_octets;

+  u8_t  type;

+  s32_t version;

+

+  ofs_base = ofs;

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+  if ((derr != ERR_OK) ||

+      (pdu_len != (1 + len_octets + len)) ||

+      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))

+  {

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  ofs += (1 + len_octets);

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))

+  {

+    /* can't decode or no integer (version) */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);

+  if (derr != ERR_OK)

+  {

+    /* can't decode */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  if (version != 0)

+  {

+    /* not version 1 */

+    snmp_inc_snmpinbadversions();

+    return ERR_ARG;

+  }

+  ofs += (1 + len_octets + len);

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))

+  {

+    /* can't decode or no octet string (community) */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community);

+  if (derr != ERR_OK)

+  {

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  /* add zero terminator */

+  len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));

+  m_stat->community[len] = 0;

+  m_stat->com_strlen = len;

+  if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)

+  {

+    /** @todo: move this if we need to check more names */

+    snmp_inc_snmpinbadcommunitynames();

+    snmp_authfail_trap();

+    return ERR_ARG;

+  }

+  ofs += (1 + len_octets + len);

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+  if (derr != ERR_OK)

+  {

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  switch(type)

+  {

+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ):

+      /* GetRequest PDU */

+      snmp_inc_snmpingetrequests();

+      derr = ERR_OK;

+      break;

+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ):

+      /* GetNextRequest PDU */

+      snmp_inc_snmpingetnexts();

+      derr = ERR_OK;

+      break;

+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP):

+      /* GetResponse PDU */

+      snmp_inc_snmpingetresponses();

+      derr = ERR_ARG;

+      break;

+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ):

+      /* SetRequest PDU */

+      snmp_inc_snmpinsetrequests();

+      derr = ERR_OK;

+      break;

+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP):

+      /* Trap PDU */

+      snmp_inc_snmpintraps();

+      derr = ERR_ARG;

+      break;

+    default:

+      snmp_inc_snmpinasnparseerrs();

+      derr = ERR_ARG;

+      break;

+  }

+  if (derr != ERR_OK)

+  {

+    /* unsupported input PDU for this agent (no parse error) */

+    return ERR_ARG;

+  }

+  m_stat->rt = type & 0x1F;

+  ofs += (1 + len_octets);

+  if (len != (pdu_len - (ofs - ofs_base)))

+  {

+    /* decoded PDU length does not equal actual payload length */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))

+  {

+    /* can't decode or no integer (request ID) */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid);

+  if (derr != ERR_OK)

+  {

+    /* can't decode */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  ofs += (1 + len_octets + len);

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))

+  {

+    /* can't decode or no integer (error-status) */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  /* must be noError (0) for incoming requests.

+     log errors for mib-2 completeness and for debug purposes */

+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);

+  if (derr != ERR_OK)

+  {

+    /* can't decode */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  switch (m_stat->error_status)

+  {

+    case SNMP_ES_TOOBIG:

+      snmp_inc_snmpintoobigs();

+      break;

+    case SNMP_ES_NOSUCHNAME:

+      snmp_inc_snmpinnosuchnames();

+      break;

+    case SNMP_ES_BADVALUE:

+      snmp_inc_snmpinbadvalues();

+      break;

+    case SNMP_ES_READONLY:

+      snmp_inc_snmpinreadonlys();

+      break;

+    case SNMP_ES_GENERROR:

+      snmp_inc_snmpingenerrs();

+      break;

+  }

+  ofs += (1 + len_octets + len);

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))

+  {

+    /* can't decode or no integer (error-index) */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  /* must be 0 for incoming requests.

+     decode anyway to catch bad integers (and dirty tricks) */

+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index);

+  if (derr != ERR_OK)

+  {

+    /* can't decode */

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  ofs += (1 + len_octets + len);

+  *ofs_ret = ofs;

+  return ERR_OK;

+}

+

+static err_t

+snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)

+{

+  err_t derr;

+  u16_t len, vb_len;

+  u8_t  len_octets;

+  u8_t type;

+

+  /* variable binding list */

+  snmp_asn1_dec_type(p, ofs, &type);

+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len);

+  if ((derr != ERR_OK) ||

+      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))

+  {

+    snmp_inc_snmpinasnparseerrs();

+    return ERR_ARG;

+  }

+  ofs += (1 + len_octets);

+

+  /* start with empty list */

+  m_stat->invb.count = 0;

+  m_stat->invb.head = NULL;

+  m_stat->invb.tail = NULL;

+

+  while (vb_len > 0)

+  {

+    struct snmp_obj_id oid, oid_value;

+    struct snmp_varbind *vb;

+

+    snmp_asn1_dec_type(p, ofs, &type);

+    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+    if ((derr != ERR_OK) ||

+        (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||

+        (len <= 0) || (len > vb_len))

+    {

+      snmp_inc_snmpinasnparseerrs();

+      /* free varbinds (if available) */

+      snmp_varbind_list_free(&m_stat->invb);

+      return ERR_ARG;

+    }

+    ofs += (1 + len_octets);

+    vb_len -= (1 + len_octets);

+

+    snmp_asn1_dec_type(p, ofs, &type);

+    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+    if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)))

+    {

+      /* can't decode object name length */

+      snmp_inc_snmpinasnparseerrs();

+      /* free varbinds (if available) */

+      snmp_varbind_list_free(&m_stat->invb);

+      return ERR_ARG;

+    }

+    derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid);

+    if (derr != ERR_OK)

+    {

+      /* can't decode object name */

+      snmp_inc_snmpinasnparseerrs();

+      /* free varbinds (if available) */

+      snmp_varbind_list_free(&m_stat->invb);

+      return ERR_ARG;

+    }

+    ofs += (1 + len_octets + len);

+    vb_len -= (1 + len_octets + len);

+

+    snmp_asn1_dec_type(p, ofs, &type);

+    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);

+    if (derr != ERR_OK)

+    {

+      /* can't decode object value length */

+      snmp_inc_snmpinasnparseerrs();

+      /* free varbinds (if available) */

+      snmp_varbind_list_free(&m_stat->invb);

+      return ERR_ARG;

+    }

+

+    switch (type)

+    {

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):

+        vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));

+        if (vb != NULL)

+        {

+          s32_t *vptr = vb->value;

+

+          derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);

+          snmp_varbind_tail_add(&m_stat->invb, vb);

+        }

+        else

+        {

+          derr = ERR_ARG;

+        }

+        break;

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):

+        vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));

+        if (vb != NULL)

+        {

+          u32_t *vptr = vb->value;

+

+          derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);

+          snmp_varbind_tail_add(&m_stat->invb, vb);

+        }

+        else

+        {

+          derr = ERR_ARG;

+        }

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):

+        vb = snmp_varbind_alloc(&oid, type, len);

+        if (vb != NULL)

+        {

+          derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);

+          snmp_varbind_tail_add(&m_stat->invb, vb);

+        }

+        else

+        {

+          derr = ERR_ARG;

+        }

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):

+        vb = snmp_varbind_alloc(&oid, type, 0);

+        if (vb != NULL)

+        {

+          snmp_varbind_tail_add(&m_stat->invb, vb);

+          derr = ERR_OK;

+        }

+        else

+        {

+          derr = ERR_ARG;

+        }

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):

+        derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value);

+        if (derr == ERR_OK)

+        {

+          vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t));

+          if (vb != NULL)

+          {

+            u8_t i = oid_value.len;

+            s32_t *vptr = vb->value;

+

+            while(i > 0)

+            {

+              i--;

+              vptr[i] = oid_value.id[i];

+            }

+            snmp_varbind_tail_add(&m_stat->invb, vb);

+            derr = ERR_OK;

+          }

+          else

+          {

+            derr = ERR_ARG;

+          }

+        }

+        break;

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):

+        if (len == 4)

+        {

+          /* must be exactly 4 octets! */

+          vb = snmp_varbind_alloc(&oid, type, 4);

+          if (vb != NULL)

+          {

+            derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);

+            snmp_varbind_tail_add(&m_stat->invb, vb);

+          }

+          else

+          {

+            derr = ERR_ARG;

+          }

+        }

+        else

+        {

+          derr = ERR_ARG;

+        }

+        break;

+      default:

+        derr = ERR_ARG;

+        break;

+    }

+    if (derr != ERR_OK)

+    {

+      snmp_inc_snmpinasnparseerrs();

+      /* free varbinds (if available) */

+      snmp_varbind_list_free(&m_stat->invb);

+      return ERR_ARG;

+    }

+    ofs += (1 + len_octets + len);

+    vb_len -= (1 + len_octets + len);

+  }

+

+  if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ)

+  {

+    snmp_add_snmpintotalsetvars(m_stat->invb.count);

+  }

+  else

+  {

+    snmp_add_snmpintotalreqvars(m_stat->invb.count);

+  }

+

+  *ofs_ret = ofs;

+  return ERR_OK;

+}

+

+struct snmp_varbind*

+snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)

+{

+  struct snmp_varbind *vb;

+

+  vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));

+  LWIP_ASSERT("vb != NULL",vb != NULL);

+  if (vb != NULL)

+  {

+    u8_t i;

+

+    vb->next = NULL;

+    vb->prev = NULL;

+    i = oid->len;

+    vb->ident_len = i;

+    if (i > 0)

+    {

+      /* allocate array of s32_t for our object identifier */

+      vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i);

+      LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);

+      if (vb->ident == NULL)

+      {

+        mem_free(vb);

+        return NULL;

+      }

+      while(i > 0)

+      {

+        i--;

+        vb->ident[i] = oid->id[i];

+      }

+    }

+    else

+    {

+      /* i == 0, pass zero length object identifier */

+      vb->ident = NULL;

+    }

+    vb->value_type = type;

+    vb->value_len = len;

+    if (len > 0)

+    {

+      /* allocate raw bytes for our object value */

+      vb->value = mem_malloc(len);

+      LWIP_ASSERT("vb->value != NULL",vb->value != NULL);

+      if (vb->value == NULL)

+      {

+        if (vb->ident != NULL)

+        {

+          mem_free(vb->ident);

+        }

+        mem_free(vb);

+        return NULL;

+      }

+    }

+    else

+    {

+      /* ASN1_NUL type, or zero length ASN1_OC_STR */

+      vb->value = NULL;

+    }

+  }

+  return vb;

+}

+

+void

+snmp_varbind_free(struct snmp_varbind *vb)

+{

+  if (vb->value != NULL )

+  {

+    mem_free(vb->value);

+  }

+  if (vb->ident != NULL )

+  {

+    mem_free(vb->ident);

+  }

+  mem_free(vb);

+}

+

+void

+snmp_varbind_list_free(struct snmp_varbind_root *root)

+{

+  struct snmp_varbind *vb, *prev;

+

+  vb = root->tail;

+  while ( vb != NULL )

+  {

+    prev = vb->prev;

+    snmp_varbind_free(vb);

+    vb = prev;

+  }

+  root->count = 0;

+  root->head = NULL;

+  root->tail = NULL;

+}

+

+void

+snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb)

+{

+  if (root->count == 0)

+  {

+    /* add first varbind to list */

+    root->head = vb;

+    root->tail = vb;

+  }

+  else

+  {

+    /* add nth varbind to list tail */

+    root->tail->next = vb;

+    vb->prev = root->tail;

+    root->tail = vb;

+  }

+  root->count += 1;

+}

+

+struct snmp_varbind*

+snmp_varbind_tail_remove(struct snmp_varbind_root *root)

+{

+  struct snmp_varbind* vb;

+

+  if (root->count > 0)

+  {

+    /* remove tail varbind */

+    vb = root->tail;

+    root->tail = vb->prev;

+    vb->prev->next = NULL;

+    root->count -= 1;

+  }

+  else

+  {

+    /* nothing to remove */

+    vb = NULL;

+  }

+  return vb;

+}

+

+#endif /* LWIP_SNMP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/msg_out.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/msg_out.c
new file mode 100644
index 0000000..242d309
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/snmp/msg_out.c
@@ -0,0 +1,683 @@
+/**

+ * @file

+ * SNMP output message processing (RFC1157).

+ *

+ * Output responses and traps are build in two passes:

+ *

+ * Pass 0: iterate over the output message backwards to determine encoding lengths

+ * Pass 1: the actual forward encoding of internal form into ASN1

+ *

+ * The single-pass encoding method described by Comer & Stevens

+ * requires extra buffer space and copying for reversal of the packet.

+ * The buffer requirement can be prohibitively large for big payloads

+ * (>= 484) therefore we use the two encoding passes.

+ */

+

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * Author: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/udp.h"

+#include "lwip/netif.h"

+#include "lwip/snmp.h"

+#include "lwip/snmp_asn1.h"

+#include "lwip/snmp_msg.h"

+

+struct snmp_trap_dst

+{

+  /* destination IP address in network order */

+  struct ip_addr dip;

+  /* set to 0 when disabled, >0 when enabled */

+  u8_t enable;

+};

+struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];

+

+/** TRAP message structure */

+struct snmp_msg_trap trap_msg;

+

+static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len);

+static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len);

+static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root);

+

+static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p);

+static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p);

+static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs);

+

+/**

+ * Sets enable switch for this trap destination.

+ * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1

+ * @param enable switch if 0 destination is disabled >0 enabled.

+ */

+void

+snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)

+{

+  if (dst_idx < SNMP_TRAP_DESTINATIONS)

+  {

+    trap_dst[dst_idx].enable = enable;

+  }

+}

+

+/**

+ * Sets IPv4 address for this trap destination.

+ * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1

+ * @param dst IPv4 address in host order.

+ */

+void

+snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst)

+{

+  if (dst_idx < SNMP_TRAP_DESTINATIONS)

+  {

+    trap_dst[dst_idx].dip.addr = htonl(dst->addr);

+  }

+}

+

+/**

+ * Sends a 'getresponse' message to the request originator.

+ *

+ * @param m_stat points to the current message request state source

+ * @return ERR_OK when success, ERR_MEM if we're out of memory

+ *

+ * @note the caller is responsible for filling in outvb in the m_stat

+ * and provide error-status and index (except for tooBig errors) ...

+ */

+err_t

+snmp_send_response(struct snmp_msg_pstat *m_stat)

+{

+  struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0};

+  struct pbuf *p;

+  u16_t tot_len;

+  err_t err;

+

+  /* pass 0, calculate length fields */

+  tot_len = snmp_varbind_list_sum(&m_stat->outvb);

+  tot_len = snmp_resp_header_sum(m_stat, tot_len);

+

+  /* try allocating pbuf(s) for complete response */

+  p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);

+  if (p == NULL)

+  {

+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n"));

+

+    /* can't construct reply, return error-status tooBig */

+    m_stat->error_status = SNMP_ES_TOOBIG;

+    m_stat->error_index = 0;

+    /* pass 0, recalculate lengths, for empty varbind-list */

+    tot_len = snmp_varbind_list_sum(&emptyvb);

+    tot_len = snmp_resp_header_sum(m_stat, tot_len);

+    /* retry allocation once for header and empty varbind-list */

+    p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);

+  }

+  if (p != NULL)

+  {

+    /* first pbuf alloc try or retry alloc success */

+    u16_t ofs;

+

+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n"));

+

+    /* pass 1, size error, encode packet ino the pbuf(s) */

+    ofs = snmp_resp_header_enc(m_stat, p);

+    if (m_stat->error_status == SNMP_ES_TOOBIG)

+    {

+      snmp_varbind_list_enc(&emptyvb, p, ofs);

+    }

+    else

+    {

+      snmp_varbind_list_enc(&m_stat->outvb, p, ofs);

+    }

+

+    switch (m_stat->error_status)

+    {

+      case SNMP_ES_TOOBIG:

+        snmp_inc_snmpouttoobigs();

+        break;

+      case SNMP_ES_NOSUCHNAME:

+        snmp_inc_snmpoutnosuchnames();

+        break;

+      case SNMP_ES_BADVALUE:

+        snmp_inc_snmpoutbadvalues();

+        break;

+      case SNMP_ES_GENERROR:

+        snmp_inc_snmpoutgenerrs();

+        break;

+    }

+    snmp_inc_snmpoutgetresponses();

+    snmp_inc_snmpoutpkts();

+

+    /** @todo do we need separate rx and tx pcbs for threaded case? */

+    /** connect to the originating source */

+    udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp);

+    err = udp_send(m_stat->pcb, p);

+    if (err == ERR_MEM)

+    {

+      /** @todo release some memory, retry and return tooBig? tooMuchHassle? */

+      err = ERR_MEM;

+    }

+    else

+    {

+      err = ERR_OK;

+    }

+    /** disassociate remote address and port with this pcb */

+    udp_disconnect(m_stat->pcb);

+

+    pbuf_free(p);

+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n"));

+    return err;

+  }

+  else

+  {

+    /* first pbuf alloc try or retry alloc failed

+       very low on memory, couldn't return tooBig */

+    return ERR_MEM;

+  }

+}

+

+

+/**

+ * Sends an generic or enterprise specific trap message.

+ *

+ * @param generic_trap is the trap code

+ * @param eoid points to enterprise object identifier

+ * @param specific_trap used for enterprise traps when generic_trap == 6

+ * @return ERR_OK when success, ERR_MEM if we're out of memory

+ *

+ * @note the caller is responsible for filling in outvb in the trap_msg

+ * @note the use of the enterpise identifier field

+ * is per RFC1215.

+ * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps

+ * and .iso.org.dod.internet.private.enterprises.yourenterprise

+ * (sysObjectID) for specific traps.

+ */

+err_t

+snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)

+{

+  struct snmp_trap_dst *td;

+  struct netif *dst_if;

+  struct ip_addr dst_ip;

+  struct pbuf *p;

+  u16_t i,tot_len;

+

+  for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++)

+  {

+    if ((td->enable != 0) && (td->dip.addr != 0))

+    {

+      /* network order trap destination */

+      trap_msg.dip.addr = td->dip.addr;

+      /* lookup current source address for this dst */

+      dst_if = ip_route(&td->dip);

+      dst_ip.addr = ntohl(dst_if->ip_addr.addr);

+      trap_msg.sip_raw[0] = dst_ip.addr >> 24;

+      trap_msg.sip_raw[1] = dst_ip.addr >> 16;

+      trap_msg.sip_raw[2] = dst_ip.addr >> 8;

+      trap_msg.sip_raw[3] = dst_ip.addr;

+      trap_msg.gen_trap = generic_trap;

+      trap_msg.spc_trap = specific_trap;

+      if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC)

+      {

+        /* enterprise-Specific trap */

+        trap_msg.enterprise = eoid;

+      }

+      else

+      {

+        /* generic (MIB-II) trap */

+        snmp_get_snmpgrpid_ptr(&trap_msg.enterprise);

+      }

+      snmp_get_sysuptime(&trap_msg.ts);

+

+      /* pass 0, calculate length fields */

+      tot_len = snmp_varbind_list_sum(&trap_msg.outvb);

+      tot_len = snmp_trap_header_sum(&trap_msg, tot_len);

+

+      /* allocate pbuf(s) */

+      p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);

+      if (p != NULL)

+      {

+        u16_t ofs;

+

+        /* pass 1, encode packet ino the pbuf(s) */

+        ofs = snmp_trap_header_enc(&trap_msg, p);

+        snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);

+

+        snmp_inc_snmpouttraps();

+        snmp_inc_snmpoutpkts();

+

+        /** connect to the TRAP destination */

+        udp_connect(trap_msg.pcb, &trap_msg.dip, SNMP_TRAP_PORT);

+        udp_send(trap_msg.pcb, p);

+        /** disassociate remote address and port with this pcb */

+        udp_disconnect(trap_msg.pcb);

+

+        pbuf_free(p);

+      }

+      else

+      {

+        return ERR_MEM;

+      }

+    }

+  }

+  return ERR_OK;

+}

+

+void

+snmp_coldstart_trap(void)

+{

+  trap_msg.outvb.head = NULL;

+  trap_msg.outvb.tail = NULL;

+  trap_msg.outvb.count = 0;

+  snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0);

+}

+

+void

+snmp_authfail_trap(void)

+{

+  u8_t enable;

+  snmp_get_snmpenableauthentraps(&enable);

+  if (enable == 1)

+  {

+    trap_msg.outvb.head = NULL;

+    trap_msg.outvb.tail = NULL;

+    trap_msg.outvb.count = 0;

+    snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0);

+  }

+}

+

+/**

+ * Sums response header field lengths from tail to head and

+ * returns resp_header_lengths for second encoding pass.

+ *

+ * @param vb_len varbind-list length

+ * @param rhl points to returned header lengths

+ * @return the required lenght for encoding the response header

+ */

+static u16_t

+snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len)

+{

+  u16_t tot_len;

+  struct snmp_resp_header_lengths *rhl;

+

+  rhl = &m_stat->rhl;

+  tot_len = vb_len;

+  snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen);

+  snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen);

+  tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen;

+

+  snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen);

+  snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen);

+  tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen;

+

+  snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen);

+  snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen);

+  tot_len += 1 + rhl->ridlenlen + rhl->ridlen;

+

+  rhl->pdulen = tot_len;

+  snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen);

+  tot_len += 1 + rhl->pdulenlen;

+

+  rhl->comlen = m_stat->com_strlen;

+  snmp_asn1_enc_length_cnt(rhl->comlen, &rhl->comlenlen);

+  tot_len += 1 + rhl->comlenlen + rhl->comlen;

+

+  snmp_asn1_enc_s32t_cnt(snmp_version, &rhl->verlen);

+  snmp_asn1_enc_length_cnt(rhl->verlen, &rhl->verlenlen);

+  tot_len += 1 + rhl->verlen + rhl->verlenlen;

+

+  rhl->seqlen = tot_len;

+  snmp_asn1_enc_length_cnt(rhl->seqlen, &rhl->seqlenlen);

+  tot_len += 1 + rhl->seqlenlen;

+

+  return tot_len;

+}

+

+/**

+ * Sums trap header field lengths from tail to head and

+ * returns trap_header_lengths for second encoding pass.

+ *

+ * @param vb_len varbind-list length

+ * @param thl points to returned header lengths

+ * @return the required lenght for encoding the trap header

+ */

+static u16_t

+snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len)

+{

+  u16_t tot_len;

+  struct snmp_trap_header_lengths *thl;

+

+  thl = &m_trap->thl;

+  tot_len = vb_len;

+

+  snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen);

+  snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen);

+  tot_len += 1 + thl->tslen + thl->tslenlen;

+

+  snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen);

+  snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen);

+  tot_len += 1 + thl->strplen + thl->strplenlen;

+

+  snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen);

+  snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen);

+  tot_len += 1 + thl->gtrplen + thl->gtrplenlen;

+

+  thl->aaddrlen = 4;

+  snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen);

+  tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen;

+

+  snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen);

+  snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen);

+  tot_len += 1 + thl->eidlen + thl->eidlenlen;

+

+  thl->pdulen = tot_len;

+  snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen);

+  tot_len += 1 + thl->pdulenlen;

+

+  thl->comlen = sizeof(snmp_publiccommunity) - 1;

+  snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen);

+  tot_len += 1 + thl->comlenlen + thl->comlen;

+

+  snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen);

+  snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen);

+  tot_len += 1 + thl->verlen + thl->verlenlen;

+

+  thl->seqlen = tot_len;

+  snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen);

+  tot_len += 1 + thl->seqlenlen;

+

+  return tot_len;

+}

+

+/**

+ * Sums varbind lengths from tail to head and

+ * annotates lengths in varbind for second encoding pass.

+ *

+ * @param root points to the root of the variable binding list

+ * @return the required lenght for encoding the variable bindings

+ */

+static u16_t

+snmp_varbind_list_sum(struct snmp_varbind_root *root)

+{

+  struct snmp_varbind *vb;

+  u32_t *uint_ptr;

+  s32_t *sint_ptr;

+  u16_t tot_len;

+

+  tot_len = 0;

+  vb = root->tail;

+  while ( vb != NULL )

+  {

+    /* encoded value lenght depends on type */

+    switch (vb->value_type)

+    {

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):

+        sint_ptr = vb->value;

+        snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen);

+        break;

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):

+        uint_ptr = vb->value;

+        snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen);

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):

+        vb->vlen = vb->value_len;

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):

+        sint_ptr = vb->value;

+        snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen);

+        break;

+      default:

+        /* unsupported type */

+        vb->vlen = 0;

+        break;

+    };

+    /* encoding length of value length field */

+    snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen);

+    snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen);

+    snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen);

+

+    vb->seqlen = 1 + vb->vlenlen + vb->vlen;

+    vb->seqlen += 1 + vb->olenlen + vb->olen;

+    snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen);

+

+    /* varbind seq */

+    tot_len += 1 + vb->seqlenlen + vb->seqlen;

+

+    vb = vb->prev;

+  }

+

+  /* varbind-list seq */

+  root->seqlen = tot_len;

+  snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen);

+  tot_len += 1 + root->seqlenlen;

+

+  return tot_len;

+}

+

+/**

+ * Encodes response header from head to tail.

+ */

+static u16_t

+snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p)

+{

+  u16_t ofs;

+

+  ofs = 0;

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen);

+  ofs += m_stat->rhl.seqlenlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen);

+  ofs += m_stat->rhl.verlenlen;

+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_version);

+  ofs += m_stat->rhl.verlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen);

+  ofs += m_stat->rhl.comlenlen;

+  snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community);

+  ofs += m_stat->rhl.comlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen);

+  ofs += m_stat->rhl.pdulenlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen);

+  ofs += m_stat->rhl.ridlenlen;

+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid);

+  ofs += m_stat->rhl.ridlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen);

+  ofs += m_stat->rhl.errstatlenlen;

+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status);

+  ofs += m_stat->rhl.errstatlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen);

+  ofs += m_stat->rhl.erridxlenlen;

+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index);

+  ofs += m_stat->rhl.erridxlen;

+

+  return ofs;

+}

+

+/**

+ * Encodes trap header from head to tail.

+ */

+static u16_t

+snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p)

+{

+  u16_t ofs;

+

+  ofs = 0;

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen);

+  ofs += m_trap->thl.seqlenlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen);

+  ofs += m_trap->thl.verlenlen;

+  snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version);

+  ofs += m_trap->thl.verlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen);

+  ofs += m_trap->thl.comlenlen;

+  snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (u8_t *)&snmp_publiccommunity[0]);

+  ofs += m_trap->thl.comlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen);

+  ofs += m_trap->thl.pdulenlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen);

+  ofs += m_trap->thl.eidlenlen;

+  snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]);

+  ofs += m_trap->thl.eidlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen);

+  ofs += m_trap->thl.aaddrlenlen;

+  snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]);

+  ofs += m_trap->thl.aaddrlen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen);

+  ofs += m_trap->thl.gtrplenlen;

+  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap);

+  ofs += m_trap->thl.gtrplen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen);

+  ofs += m_trap->thl.strplenlen;

+  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap);

+  ofs += m_trap->thl.strplen;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen);

+  ofs += m_trap->thl.tslenlen;

+  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts);

+  ofs += m_trap->thl.tslen;

+

+  return ofs;

+}

+

+/**

+ * Encodes varbind list from head to tail.

+ */

+static u16_t

+snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs)

+{

+  struct snmp_varbind *vb;

+  s32_t *sint_ptr;

+  u32_t *uint_ptr;

+  u8_t *raw_ptr;

+

+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));

+  ofs += 1;

+  snmp_asn1_enc_length(p, ofs, root->seqlen);

+  ofs += root->seqlenlen;

+

+  vb = root->head;

+  while ( vb != NULL )

+  {

+    snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));

+    ofs += 1;

+    snmp_asn1_enc_length(p, ofs, vb->seqlen);

+    ofs += vb->seqlenlen;

+

+    snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));

+    ofs += 1;

+    snmp_asn1_enc_length(p, ofs, vb->olen);

+    ofs += vb->olenlen;

+    snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]);

+    ofs += vb->olen;

+

+    snmp_asn1_enc_type(p, ofs, vb->value_type);

+    ofs += 1;

+    snmp_asn1_enc_length(p, ofs, vb->vlen);

+    ofs += vb->vlenlen;

+

+    switch (vb->value_type)

+    {

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):

+        sint_ptr = vb->value;

+        snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr);

+        break;

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):

+        uint_ptr = vb->value;

+        snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr);

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):

+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):

+        raw_ptr = vb->value;

+        snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr);

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):

+        break;

+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):

+        sint_ptr = vb->value;

+        snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr);

+        break;

+      default:

+        /* unsupported type */

+        break;

+    };

+    ofs += vb->vlen;

+    vb = vb->next;

+  }

+  return ofs;

+}

+

+#endif /* LWIP_SNMP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/stats.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/stats.c
new file mode 100644
index 0000000..76c979f
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/stats.c
@@ -0,0 +1,142 @@
+/**

+ * @file

+ * Statistics module

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_STATS /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/def.h"

+#include "lwip/stats.h"

+#include "lwip/mem.h"

+

+#include <string.h>

+

+struct stats_ lwip_stats;

+

+#if LWIP_STATS_DISPLAY

+void

+stats_display_proto(struct stats_proto *proto, char *name)

+{

+  LWIP_PLATFORM_DIAG(("\n%s\n\t", name));

+  LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit));

+  LWIP_PLATFORM_DIAG(("rexmit: %"STAT_COUNTER_F"\n\t", proto->rexmit));

+  LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv));

+  LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw));

+  LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop));

+  LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", proto->chkerr));

+  LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", proto->lenerr));

+  LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", proto->memerr));

+  LWIP_PLATFORM_DIAG(("rterr: %"STAT_COUNTER_F"\n\t", proto->rterr));

+  LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", proto->proterr));

+  LWIP_PLATFORM_DIAG(("opterr: %"STAT_COUNTER_F"\n\t", proto->opterr));

+  LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n\t", proto->err));

+  LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit));

+}

+

+void

+stats_display_igmp(struct stats_igmp *igmp)

+{

+  LWIP_PLATFORM_DIAG(("\nIGMP\n\t"));

+  LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr));

+  LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr));

+  LWIP_PLATFORM_DIAG(("v1_rxed: %"STAT_COUNTER_F"\n\t", igmp->v1_rxed));

+  LWIP_PLATFORM_DIAG(("join_sent: %"STAT_COUNTER_F"\n\t", igmp->join_sent));

+  LWIP_PLATFORM_DIAG(("leave_sent: %"STAT_COUNTER_F"\n\t", igmp->leave_sent));

+  LWIP_PLATFORM_DIAG(("unicast_query: %"STAT_COUNTER_F"\n\t", igmp->unicast_query));

+  LWIP_PLATFORM_DIAG(("report_sent: %"STAT_COUNTER_F"\n\t", igmp->report_sent));

+  LWIP_PLATFORM_DIAG(("report_rxed: %"STAT_COUNTER_F"\n\t", igmp->report_rxed));

+  LWIP_PLATFORM_DIAG(("group_query_rxed: %"STAT_COUNTER_F"\n", igmp->group_query_rxed));

+}

+

+void

+stats_display_mem(struct stats_mem *mem, char *name)

+{

+  LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name));

+  LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail));

+  LWIP_PLATFORM_DIAG(("used: %"U32_F"\n\t", (u32_t)mem->used));

+  LWIP_PLATFORM_DIAG(("max: %"U32_F"\n\t", (u32_t)mem->max));

+  LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err));

+}

+

+void

+stats_display(void)

+{

+#if MEMP_STATS

+  s16_t i;

+  char * memp_names[] = {

+#define LWIP_MEMPOOL(name,num,size,desc) desc,

+#include "lwip/memp_std.h"

+  };

+#endif

+#if LINK_STATS

+  stats_display_proto(&lwip_stats.link, "LINK");

+#endif

+#if ETHARP_STATS

+  stats_display_proto(&lwip_stats.etharp, "ETHARP");

+#endif

+#if IPFRAG_STATS

+  stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG");

+#endif

+#if IP_STATS

+  stats_display_proto(&lwip_stats.ip, "IP");

+#endif

+#if ICMP_STATS

+  stats_display_proto(&lwip_stats.icmp, "ICMP");

+#endif

+#if IGMP_STATS

+  stats_display_igmp(&lwip_stats.igmp);

+#endif

+#if UDP_STATS

+  stats_display_proto(&lwip_stats.udp, "UDP");

+#endif

+#if TCP_STATS

+  stats_display_proto(&lwip_stats.tcp, "TCP");

+#endif

+#if MEM_STATS

+  stats_display_mem(&lwip_stats.mem, "HEAP");

+#endif

+#if MEMP_STATS

+  for (i = 0; i < MEMP_MAX; i++) {

+    stats_display_mem(&lwip_stats.memp[i], memp_names[i]);

+  }

+#endif

+}

+#endif /* LWIP_STATS_DISPLAY */

+

+#endif /* LWIP_STATS */

+

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/sys.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/sys.c
new file mode 100644
index 0000000..7f81e50
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/sys.c
@@ -0,0 +1,344 @@
+/**

+ * @file

+ * lwIP Operating System abstraction

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/sys.h"

+#include "lwip/def.h"

+#include "lwip/memp.h"

+#include "lwip/tcpip.h"

+

+/**

+ * Struct used for sys_sem_wait_timeout() to tell wether the time

+ * has run out or the semaphore has really become available.

+ */

+struct sswt_cb

+{

+  s16_t timeflag;

+  sys_sem_t *psem;

+};

+

+/**

+ * Wait (forever) for a message to arrive in an mbox.

+ * While waiting, timeouts (for this thread) are processed.

+ *

+ * @param mbox the mbox to fetch the message from

+ * @param msg the place to store the message

+ */

+void

+sys_mbox_fetch(sys_mbox_t mbox, void **msg)

+{

+  u32_t time;

+  struct sys_timeouts *timeouts;

+  struct sys_timeo *tmptimeout;

+  sys_timeout_handler h;

+  void *arg;

+

+ again:

+  timeouts = sys_arch_timeouts();

+

+  if (!timeouts || !timeouts->next) {

+    UNLOCK_TCPIP_CORE();

+    time = sys_arch_mbox_fetch(mbox, msg, 0);

+    LOCK_TCPIP_CORE();

+  } else {

+    if (timeouts->next->time > 0) {

+      UNLOCK_TCPIP_CORE();

+      time = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);

+      LOCK_TCPIP_CORE();

+    } else {

+      time = SYS_ARCH_TIMEOUT;

+    }

+

+    if (time == SYS_ARCH_TIMEOUT) {

+      /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message

+         could be fetched. We should now call the timeout handler and

+         deallocate the memory allocated for the timeout. */

+      tmptimeout = timeouts->next;

+      timeouts->next = tmptimeout->next;

+      h   = tmptimeout->h;

+      arg = tmptimeout->arg;

+      memp_free(MEMP_SYS_TIMEOUT, tmptimeout);

+      if (h != NULL) {

+        LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", (void*)&h, arg));

+        h(arg);

+      }

+

+      /* We try again to fetch a message from the mbox. */

+      goto again;

+    } else {

+      /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout

+         occured. The time variable is set to the number of

+         milliseconds we waited for the message. */

+      if (time < timeouts->next->time) {

+        timeouts->next->time -= time;

+      } else {

+        timeouts->next->time = 0;

+      }

+    }

+  }

+}

+

+/**

+ * Wait (forever) for a semaphore to become available.

+ * While waiting, timeouts (for this thread) are processed.

+ *

+ * @param sem semaphore to wait for

+ */

+void

+sys_sem_wait(sys_sem_t sem)

+{

+  u32_t time;

+  struct sys_timeouts *timeouts;

+  struct sys_timeo *tmptimeout;

+  sys_timeout_handler h;

+  void *arg;

+

+ again:

+

+  timeouts = sys_arch_timeouts();

+

+  if (!timeouts || !timeouts->next) {

+    sys_arch_sem_wait(sem, 0);

+  } else {

+    if (timeouts->next->time > 0) {

+      time = sys_arch_sem_wait(sem, timeouts->next->time);

+    } else {

+      time = SYS_ARCH_TIMEOUT;

+    }

+

+    if (time == SYS_ARCH_TIMEOUT) {

+      /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message

+        could be fetched. We should now call the timeout handler and

+        deallocate the memory allocated for the timeout. */

+      tmptimeout = timeouts->next;

+      timeouts->next = tmptimeout->next;

+      h = tmptimeout->h;

+      arg = tmptimeout->arg;

+      memp_free(MEMP_SYS_TIMEOUT, tmptimeout);

+      if (h != NULL) {

+        LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", (void*)&h, (void *)arg));

+        h(arg);

+      }

+

+      /* We try again to fetch a message from the mbox. */

+      goto again;

+    } else {

+      /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout

+         occured. The time variable is set to the number of

+         milliseconds we waited for the message. */

+      if (time < timeouts->next->time) {

+        timeouts->next->time -= time;

+      } else {

+        timeouts->next->time = 0;

+      }

+    }

+  }

+}

+

+/**

+ * Create a one-shot timer (aka timeout). Timeouts are processed in the

+ * following cases:

+ * - while waiting for a message using sys_mbox_fetch()

+ * - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout()

+ * - while sleeping using the inbuilt sys_msleep()

+ *

+ * @param msecs time in milliseconds after that the timer should expire

+ * @param h callback function to call when msecs have elapsed

+ * @param arg argument to pass to the callback function

+ */

+void

+sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)

+{

+  struct sys_timeouts *timeouts;

+  struct sys_timeo *timeout, *t;

+

+  timeout = memp_malloc(MEMP_SYS_TIMEOUT);

+  if (timeout == NULL) {

+    LWIP_ASSERT("sys_timeout: timeout != NULL", timeout != NULL);

+    return;

+  }

+  timeout->next = NULL;

+  timeout->h = h;

+  timeout->arg = arg;

+  timeout->time = msecs;

+

+  timeouts = sys_arch_timeouts();

+

+  LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",

+    (void *)timeout, msecs, (void*)&h, (void *)arg));

+

+  if (timeouts == NULL) {

+    LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);

+    return;

+  }

+

+  if (timeouts->next == NULL) {

+    timeouts->next = timeout;

+    return;

+  }

+

+  if (timeouts->next->time > msecs) {

+    timeouts->next->time -= msecs;

+    timeout->next = timeouts->next;

+    timeouts->next = timeout;

+  } else {

+    for(t = timeouts->next; t != NULL; t = t->next) {

+      timeout->time -= t->time;

+      if (t->next == NULL || t->next->time > timeout->time) {

+        if (t->next != NULL) {

+          t->next->time -= timeout->time;

+        }

+        timeout->next = t->next;

+        t->next = timeout;

+        break;

+      }

+    }

+  }

+}

+

+/**

+ * Go through timeout list (for this task only) and remove the first matching

+ * entry, even though the timeout has not triggered yet.

+ *

+ * @note This function only works as expected if there is only one timeout

+ * calling 'h' in the list of timeouts.

+ *

+ * @param h callback function that would be called by the timeout

+ * @param arg callback argument that would be passed to h

+*/

+void

+sys_untimeout(sys_timeout_handler h, void *arg)

+{

+  struct sys_timeouts *timeouts;

+  struct sys_timeo *prev_t, *t;

+

+  timeouts = sys_arch_timeouts();

+

+  if (timeouts == NULL) {

+    LWIP_ASSERT("sys_untimeout: timeouts != NULL", timeouts != NULL);

+    return;

+  }

+  if (timeouts->next == NULL) {

+    return;

+  }

+

+  for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {

+    if ((t->h == h) && (t->arg == arg)) {

+      /* We have a match */

+      /* Unlink from previous in list */

+      if (prev_t == NULL)

+        timeouts->next = t->next;

+      else

+        prev_t->next = t->next;

+      /* If not the last one, add time of this one back to next */

+      if (t->next != NULL)

+        t->next->time += t->time;

+      memp_free(MEMP_SYS_TIMEOUT, t);

+      return;

+    }

+  }

+  return;

+}

+

+/**

+ * Timeout handler function for sys_sem_wait_timeout()

+ *

+ * @param arg struct sswt_cb* used to signal a semaphore and end waiting.

+ */

+static void

+sswt_handler(void *arg)

+{

+  struct sswt_cb *sswt_cb = (struct sswt_cb *) arg;

+

+  /* Timeout. Set flag to TRUE and signal semaphore */

+  sswt_cb->timeflag = 1;

+  sys_sem_signal(*(sswt_cb->psem));

+}

+

+/**

+ * Wait for a semaphore with timeout (specified in ms)

+ *

+ * @param sem semaphore to wait

+ * @param timeout timeout in ms (0: wait forever)

+ * @return 0 on timeout, 1 otherwise

+ */

+int

+sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout)

+{

+  struct sswt_cb sswt_cb;

+

+  sswt_cb.psem = &sem;

+  sswt_cb.timeflag = 0;

+

+  /* If timeout is zero, then just wait forever */

+  if (timeout > 0) {

+    /* Create a timer and pass it the address of our flag */

+    sys_timeout(timeout, sswt_handler, &sswt_cb);

+  }

+  sys_sem_wait(sem);

+  /* Was it a timeout? */

+  if (sswt_cb.timeflag) {

+    /* timeout */

+    return 0;

+  } else {

+    /* Not a timeout. Remove timeout entry */

+    sys_untimeout(sswt_handler, &sswt_cb);

+    return 1;

+  }

+}

+

+/**

+ * Sleep for some ms. Timeouts are processed while sleeping.

+ *

+ * @param ms number of milliseconds to sleep

+ */

+void

+sys_msleep(u32_t ms)

+{

+  sys_sem_t delaysem = sys_sem_new(0);

+

+  sys_sem_wait_timeout(delaysem, ms);

+

+  sys_sem_free(delaysem);

+}

+

+

+#endif /* NO_SYS */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/tcp.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/tcp.c
new file mode 100644
index 0000000..aa2f3c8
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/tcp.c
@@ -0,0 +1,1418 @@
+/**

+ * @file

+ * Transmission Control Protocol for IP

+ *

+ * This file contains common functions for the TCP implementation, such as functinos

+ * for manipulating the data structures and the TCP timer functions. TCP functions

+ * related to input and output is found in tcp_in.c and tcp_out.c respectively.

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/def.h"

+#include "lwip/mem.h"

+#include "lwip/memp.h"

+#include "lwip/snmp.h"

+#include "lwip/tcp.h"

+

+#include <string.h>

+

+/* Incremented every coarse grained timer shot (typically every 500 ms). */

+u32_t tcp_ticks;

+const u8_t tcp_backoff[13] =

+    { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};

+ /* Times per slowtmr hits */

+const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 };

+

+/* The TCP PCB lists. */

+

+/** List of all TCP PCBs bound but not yet (connected || listening) */

+struct tcp_pcb *tcp_bound_pcbs;

+/** List of all TCP PCBs in LISTEN state */

+union tcp_listen_pcbs_t tcp_listen_pcbs;

+/** List of all TCP PCBs that are in a state in which

+ * they accept or send data. */

+struct tcp_pcb *tcp_active_pcbs;

+/** List of all TCP PCBs in TIME-WAIT state */

+struct tcp_pcb *tcp_tw_pcbs;

+

+struct tcp_pcb *tcp_tmp_pcb;

+

+static u8_t tcp_timer;

+static u16_t tcp_new_port(void);

+

+/**

+ * Called periodically to dispatch TCP timers.

+ *

+ */

+void

+tcp_tmr(void)

+{

+  /* Call tcp_fasttmr() every 250 ms */

+  tcp_fasttmr();

+

+  if (++tcp_timer & 1) {

+    /* Call tcp_tmr() every 500 ms, i.e., every other timer

+       tcp_tmr() is called. */

+    tcp_slowtmr();

+  }

+}

+

+/**

+ * Closes the connection held by the PCB.

+ *

+ * Listening pcbs are freed and may not be referenced any more.

+ * Connection pcbs are freed if not yet connected and may not be referenced

+ * any more. If a connection is established (at least SYN received or in

+ * a closing state), the connection is closed, and put in a closing state.

+ * The pcb is then automatically freed in tcp_slowtmr(). It is therefore

+ * unsafe to reference it.

+ *

+ * @param pcb the tcp_pcb to close

+ * @return ERR_OK if connection has been closed

+ *         another err_t if closing failed and pcb is not freed

+ */

+err_t

+tcp_close(struct tcp_pcb *pcb)

+{

+  err_t err;

+

+#if TCP_DEBUG

+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in "));

+  tcp_debug_print_state(pcb->state);

+#endif /* TCP_DEBUG */

+

+  switch (pcb->state) {

+  case CLOSED:

+    /* Closing a pcb in the CLOSED state might seem erroneous,

+     * however, it is in this state once allocated and as yet unused

+     * and the user needs some way to free it should the need arise.

+     * Calling tcp_close() with a pcb that has already been closed, (i.e. twice)

+     * or for a pcb that has been used and then entered the CLOSED state

+     * is erroneous, but this should never happen as the pcb has in those cases

+     * been freed, and so any remaining handles are bogus. */

+    err = ERR_OK;

+    TCP_RMV(&tcp_bound_pcbs, pcb);

+    memp_free(MEMP_TCP_PCB, pcb);

+    pcb = NULL;

+    break;

+  case LISTEN:

+    err = ERR_OK;

+    tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);

+    memp_free(MEMP_TCP_PCB_LISTEN, pcb);

+    pcb = NULL;

+    break;

+  case SYN_SENT:

+    err = ERR_OK;

+    tcp_pcb_remove(&tcp_active_pcbs, pcb);

+    memp_free(MEMP_TCP_PCB, pcb);

+    pcb = NULL;

+    snmp_inc_tcpattemptfails();

+    break;

+  case SYN_RCVD:

+    err = tcp_send_ctrl(pcb, TCP_FIN);

+    if (err == ERR_OK) {

+      snmp_inc_tcpattemptfails();

+      pcb->state = FIN_WAIT_1;

+    }

+    break;

+  case ESTABLISHED:

+    err = tcp_send_ctrl(pcb, TCP_FIN);

+    if (err == ERR_OK) {

+      snmp_inc_tcpestabresets();

+      pcb->state = FIN_WAIT_1;

+    }

+    break;

+  case CLOSE_WAIT:

+    err = tcp_send_ctrl(pcb, TCP_FIN);

+    if (err == ERR_OK) {

+      snmp_inc_tcpestabresets();

+      pcb->state = LAST_ACK;

+    }

+    break;

+  default:

+    /* Has already been closed, do nothing. */

+    err = ERR_OK;

+    pcb = NULL;

+    break;

+  }

+

+  if (pcb != NULL && err == ERR_OK) {

+    /* To ensure all data has been sent when tcp_close returns, we have

+       to make sure tcp_output doesn't fail.

+       Since we don't really have to ensure all data has been sent when tcp_close

+       returns (unsent data is sent from tcp timer functions, also), we don't care

+       for the return value of tcp_output for now. */

+    /* @todo: When implementing SO_LINGER, this must be changed somehow:

+       If SOF_LINGER is set, the data should be sent when tcp_close returns. */

+    tcp_output(pcb);

+  }

+  return err;

+}

+

+/**

+ * Aborts a connection by sending a RST to the remote host and deletes

+ * the local protocol control block. This is done when a connection is

+ * killed because of shortage of memory.

+ *

+ * @param pcb the tcp_pcb to abort

+ */

+void

+tcp_abort(struct tcp_pcb *pcb)

+{

+  u32_t seqno, ackno;

+  u16_t remote_port, local_port;

+  struct ip_addr remote_ip, local_ip;

+#if LWIP_CALLBACK_API

+  void (* errf)(void *arg, err_t err);

+#endif /* LWIP_CALLBACK_API */

+  void *errf_arg;

+

+

+  /* Figure out on which TCP PCB list we are, and remove us. If we

+     are in an active state, call the receive function associated with

+     the PCB with a NULL argument, and send an RST to the remote end. */

+  if (pcb->state == TIME_WAIT) {

+    tcp_pcb_remove(&tcp_tw_pcbs, pcb);

+    memp_free(MEMP_TCP_PCB, pcb);

+  } else {

+    seqno = pcb->snd_nxt;

+    ackno = pcb->rcv_nxt;

+    ip_addr_set(&local_ip, &(pcb->local_ip));

+    ip_addr_set(&remote_ip, &(pcb->remote_ip));

+    local_port = pcb->local_port;

+    remote_port = pcb->remote_port;

+#if LWIP_CALLBACK_API

+    errf = pcb->errf;

+#endif /* LWIP_CALLBACK_API */

+    errf_arg = pcb->callback_arg;

+    tcp_pcb_remove(&tcp_active_pcbs, pcb);

+    if (pcb->unacked != NULL) {

+      tcp_segs_free(pcb->unacked);

+    }

+    if (pcb->unsent != NULL) {

+      tcp_segs_free(pcb->unsent);

+    }

+#if TCP_QUEUE_OOSEQ

+    if (pcb->ooseq != NULL) {

+      tcp_segs_free(pcb->ooseq);

+    }

+#endif /* TCP_QUEUE_OOSEQ */

+    memp_free(MEMP_TCP_PCB, pcb);

+    TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);

+    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RST\n"));

+    tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);

+  }

+}

+

+/**

+ * Binds the connection to a local portnumber and IP address. If the

+ * IP address is not given (i.e., ipaddr == NULL), the IP address of

+ * the outgoing network interface is used instead.

+ *

+ * @param pcb the tcp_pcb to bind (no check is done whether this pcb is

+ *        already bound!)

+ * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind

+ *        to any local address

+ * @param port the local port to bind to

+ * @return ERR_USE if the port is already in use

+ *         ERR_OK if bound

+ */

+err_t

+tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)

+{

+  struct tcp_pcb *cpcb;

+

+  LWIP_ERROR("tcp_connect: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);

+

+  if (port == 0) {

+    port = tcp_new_port();

+  }

+  /* Check if the address already is in use. */

+  /* Check the listen pcbs. */

+  for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs;

+      cpcb != NULL; cpcb = cpcb->next) {

+    if (cpcb->local_port == port) {

+      if (ip_addr_isany(&(cpcb->local_ip)) ||

+          ip_addr_isany(ipaddr) ||

+          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {

+        return ERR_USE;

+      }

+    }

+  }

+  /* Check the connected pcbs. */

+  for(cpcb = tcp_active_pcbs;

+      cpcb != NULL; cpcb = cpcb->next) {

+    if (cpcb->local_port == port) {

+      if (ip_addr_isany(&(cpcb->local_ip)) ||

+          ip_addr_isany(ipaddr) ||

+          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {

+        return ERR_USE;

+      }

+    }

+  }

+  /* Check the bound, not yet connected pcbs. */

+  for(cpcb = tcp_bound_pcbs; cpcb != NULL; cpcb = cpcb->next) {

+    if (cpcb->local_port == port) {

+      if (ip_addr_isany(&(cpcb->local_ip)) ||

+          ip_addr_isany(ipaddr) ||

+          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {

+        return ERR_USE;

+      }

+    }

+  }

+  /* @todo: until SO_REUSEADDR is implemented (see task #6995 on savannah),

+   * we have to check the pcbs in TIME-WAIT state, also: */

+  for(cpcb = tcp_tw_pcbs; cpcb != NULL; cpcb = cpcb->next) {

+    if (cpcb->local_port == port) {

+      if (ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {

+        return ERR_USE;

+      }

+    }

+  }

+

+  if (!ip_addr_isany(ipaddr)) {

+    pcb->local_ip = *ipaddr;

+  }

+  pcb->local_port = port;

+  TCP_REG(&tcp_bound_pcbs, pcb);

+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port));

+  return ERR_OK;

+}

+#if LWIP_CALLBACK_API

+/**

+ * Default accept callback if no accept callback is specified by the user.

+ */

+static err_t

+tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)

+{

+  LWIP_UNUSED_ARG(arg);

+  LWIP_UNUSED_ARG(pcb);

+  LWIP_UNUSED_ARG(err);

+

+  return ERR_ABRT;

+}

+#endif /* LWIP_CALLBACK_API */

+

+/**

+ * Set the state of the connection to be LISTEN, which means that it

+ * is able to accept incoming connections. The protocol control block

+ * is reallocated in order to consume less memory. Setting the

+ * connection to LISTEN is an irreversible process.

+ *

+ * @param pcb the original tcp_pcb

+ * @param backlog the incoming connections queue limit

+ * @return tcp_pcb used for listening, consumes less memory.

+ *

+ * @note The original tcp_pcb is freed. This function therefore has to be

+ *       called like this:

+ *             tpcb = tcp_listen(tpcb);

+ */

+struct tcp_pcb *

+tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)

+{

+  struct tcp_pcb_listen *lpcb;

+

+  LWIP_UNUSED_ARG(backlog);

+  LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL);

+

+  /* already listening? */

+  if (pcb->state == LISTEN) {

+    return pcb;

+  }

+  lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN);

+  if (lpcb == NULL) {

+    return NULL;

+  }

+  lpcb->callback_arg = pcb->callback_arg;

+  lpcb->local_port = pcb->local_port;

+  lpcb->state = LISTEN;

+  lpcb->so_options = pcb->so_options;

+  lpcb->so_options |= SOF_ACCEPTCONN;

+  lpcb->ttl = pcb->ttl;

+  lpcb->tos = pcb->tos;

+  ip_addr_set(&lpcb->local_ip, &pcb->local_ip);

+  TCP_RMV(&tcp_bound_pcbs, pcb);

+  memp_free(MEMP_TCP_PCB, pcb);

+#if LWIP_CALLBACK_API

+  lpcb->accept = tcp_accept_null;

+#endif /* LWIP_CALLBACK_API */

+#if TCP_LISTEN_BACKLOG

+  lpcb->accepts_pending = 0;

+  lpcb->backlog = (backlog ? backlog : 1);

+#endif /* TCP_LISTEN_BACKLOG */

+  TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);

+  return (struct tcp_pcb *)lpcb;

+}

+

+/**

+ * This function should be called by the application when it has

+ * processed the data. The purpose is to advertise a larger window

+ * when the data has been processed.

+ *

+ * @param pcb the tcp_pcb for which data is read

+ * @param len the amount of bytes that have been read by the application

+ */

+void

+tcp_recved(struct tcp_pcb *pcb, u16_t len)

+{

+  if ((u32_t)pcb->rcv_wnd + len > TCP_WND) {

+    pcb->rcv_wnd = TCP_WND;

+    pcb->rcv_ann_wnd = TCP_WND;

+  } else {

+    pcb->rcv_wnd += len;

+    if (pcb->rcv_wnd >= pcb->mss) {

+      pcb->rcv_ann_wnd = pcb->rcv_wnd;

+    }

+  }

+

+  if (!(pcb->flags & TF_ACK_DELAY) &&

+     !(pcb->flags & TF_ACK_NOW)) {

+    /*

+     * We send an ACK here (if one is not already pending, hence

+     * the above tests) as tcp_recved() implies that the application

+     * has processed some data, and so we can open the receiver's

+     * window to allow more to be transmitted.  This could result in

+     * two ACKs being sent for each received packet in some limited cases

+     * (where the application is only receiving data, and is slow to

+     * process it) but it is necessary to guarantee that the sender can

+     * continue to transmit.

+     */

+    tcp_ack(pcb);

+  }

+  else if (pcb->flags & TF_ACK_DELAY && pcb->rcv_wnd >= TCP_WND/2) {

+    /* If we can send a window update such that there is a full

+     * segment available in the window, do so now.  This is sort of

+     * nagle-like in its goals, and tries to hit a compromise between

+     * sending acks each time the window is updated, and only sending

+     * window updates when a timer expires.  The "threshold" used

+     * above (currently TCP_WND/2) can be tuned to be more or less

+     * aggressive  */

+    tcp_ack_now(pcb);

+  }

+

+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",

+         len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));

+}

+

+/**

+ * A nastly hack featuring 'goto' statements that allocates a

+ * new TCP local port.

+ *

+ * @return a new (free) local TCP port number

+ */

+static u16_t

+tcp_new_port(void)

+{

+  struct tcp_pcb *pcb;

+#ifndef TCP_LOCAL_PORT_RANGE_START

+#define TCP_LOCAL_PORT_RANGE_START 4096

+#define TCP_LOCAL_PORT_RANGE_END   0x7fff

+#endif

+  static u16_t port = TCP_LOCAL_PORT_RANGE_START;

+

+ again:

+  if (++port > TCP_LOCAL_PORT_RANGE_END) {

+    port = TCP_LOCAL_PORT_RANGE_START;

+  }

+

+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {

+    if (pcb->local_port == port) {

+      goto again;

+    }

+  }

+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {

+    if (pcb->local_port == port) {

+      goto again;

+    }

+  }

+  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {

+    if (pcb->local_port == port) {

+      goto again;

+    }

+  }

+  return port;

+}

+

+/**

+ * Connects to another host. The function given as the "connected"

+ * argument will be called when the connection has been established.

+ *

+ * @param pcb the tcp_pcb used to establish the connection

+ * @param ipaddr the remote ip address to connect to

+ * @param port the remote tcp port to connect to

+ * @param connected callback function to call when connected (or on error)

+ * @return ERR_VAL if invalid arguments are given

+ *         ERR_OK if connect request has been sent

+ *         other err_t values if connect request couldn't be sent

+ */

+err_t

+tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,

+      err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))

+{

+  u32_t optdata;

+  err_t ret;

+  u32_t iss;

+

+  LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);

+

+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));

+  if (ipaddr != NULL) {

+    pcb->remote_ip = *ipaddr;

+  } else {

+    return ERR_VAL;

+  }

+  pcb->remote_port = port;

+  if (pcb->local_port == 0) {

+    pcb->local_port = tcp_new_port();

+  }

+  iss = tcp_next_iss();

+  pcb->rcv_nxt = 0;

+  pcb->snd_nxt = iss;

+  pcb->lastack = iss - 1;

+  pcb->snd_lbb = iss - 1;

+  pcb->rcv_wnd = TCP_WND;

+  pcb->rcv_ann_wnd = TCP_WND;

+  pcb->snd_wnd = TCP_WND;

+  /* The send MSS is updated when an MSS option is received. */

+  pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;

+#if TCP_CALCULATE_EFF_SEND_MSS

+  pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr);

+#endif /* TCP_CALCULATE_EFF_SEND_MSS */

+  pcb->cwnd = 1;

+  pcb->ssthresh = pcb->mss * 10;

+  pcb->state = SYN_SENT;

+#if LWIP_CALLBACK_API

+  pcb->connected = connected;

+#endif /* LWIP_CALLBACK_API */

+  TCP_RMV(&tcp_bound_pcbs, pcb);

+  TCP_REG(&tcp_active_pcbs, pcb);

+

+  snmp_inc_tcpactiveopens();

+

+  /* Build an MSS option */

+  optdata = TCP_BUILD_MSS_OPTION();

+

+  ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4);

+  if (ret == ERR_OK) {

+    tcp_output(pcb);

+  }

+  return ret;

+}

+

+/**

+ * Called every 500 ms and implements the retransmission timer and the timer that

+ * removes PCBs that have been in TIME-WAIT for enough time. It also increments

+ * various timers such as the inactivity timer in each PCB.

+ *

+ * Automatically called from tcp_tmr().

+ */

+void

+tcp_slowtmr(void)

+{

+  struct tcp_pcb *pcb, *pcb2, *prev;

+  u16_t eff_wnd;

+  u8_t pcb_remove;      /* flag if a PCB should be removed */

+  err_t err;

+

+  err = ERR_OK;

+

+  ++tcp_ticks;

+

+  /* Steps through all of the active PCBs. */

+  prev = NULL;

+  pcb = tcp_active_pcbs;

+  if (pcb == NULL) {

+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));

+  }

+  while (pcb != NULL) {

+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));

+    LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);

+    LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);

+    LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);

+

+    pcb_remove = 0;

+

+    if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {

+      ++pcb_remove;

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));

+    }

+    else if (pcb->nrtx == TCP_MAXRTX) {

+      ++pcb_remove;

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));

+    } else {

+      if (pcb->persist_backoff > 0) {

+        /* If snd_wnd is zero, use persist timer to send 1 byte probes

+         * instead of using the standard retransmission mechanism. */

+        pcb->persist_cnt++;

+        if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) {

+          pcb->persist_cnt = 0;

+          if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) {

+            pcb->persist_backoff++;

+          }

+          tcp_zero_window_probe(pcb);

+        }

+      } else {

+        /* Increase the retransmission timer if it is running */

+        if(pcb->rtime >= 0)

+          ++pcb->rtime;

+

+        if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {

+          /* Time for a retransmission. */

+          LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F

+                                      " pcb->rto %"S16_F"\n",

+                                      pcb->rtime, pcb->rto));

+

+          /* Double retransmission time-out unless we are trying to

+           * connect to somebody (i.e., we are in SYN_SENT). */

+          if (pcb->state != SYN_SENT) {

+            pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];

+          }

+

+          /* Reset the retransmission timer. */

+          pcb->rtime = 0;

+

+          /* Reduce congestion window and ssthresh. */

+          eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);

+          pcb->ssthresh = eff_wnd >> 1;

+          if (pcb->ssthresh < pcb->mss) {

+            pcb->ssthresh = pcb->mss * 2;

+          }

+          pcb->cwnd = pcb->mss;

+          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F

+                                       " ssthresh %"U16_F"\n",

+                                       pcb->cwnd, pcb->ssthresh));

+

+          /* The following needs to be called AFTER cwnd is set to one

+             mss - STJ */

+          tcp_rexmit_rto(pcb);

+        }

+      }

+    }

+    /* Check if this PCB has stayed too long in FIN-WAIT-2 */

+    if (pcb->state == FIN_WAIT_2) {

+      if ((u32_t)(tcp_ticks - pcb->tmr) >

+          TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {

+        ++pcb_remove;

+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));

+      }

+    }

+

+    /* Check if KEEPALIVE should be sent */

+    if((pcb->so_options & SOF_KEEPALIVE) &&

+       ((pcb->state == ESTABLISHED) ||

+        (pcb->state == CLOSE_WAIT))) {

+#if LWIP_TCP_KEEPALIVE

+      if((u32_t)(tcp_ticks - pcb->tmr) >

+         (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl))

+         / TCP_SLOW_INTERVAL)

+#else

+      if((u32_t)(tcp_ticks - pcb->tmr) >

+         (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)

+#endif /* LWIP_TCP_KEEPALIVE */

+      {

+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",

+                                ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),

+                                ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));

+

+        tcp_abort(pcb);

+      }

+#if LWIP_TCP_KEEPALIVE

+      else if((u32_t)(tcp_ticks - pcb->tmr) >

+              (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl)

+              / TCP_SLOW_INTERVAL)

+#else

+      else if((u32_t)(tcp_ticks - pcb->tmr) >

+              (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT)

+              / TCP_SLOW_INTERVAL)

+#endif /* LWIP_TCP_KEEPALIVE */

+      {

+        tcp_keepalive(pcb);

+        pcb->keep_cnt_sent++;

+      }

+    }

+

+    /* If this PCB has queued out of sequence data, but has been

+       inactive for too long, will drop the data (it will eventually

+       be retransmitted). */

+#if TCP_QUEUE_OOSEQ

+    if (pcb->ooseq != NULL &&

+        (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) {

+      tcp_segs_free(pcb->ooseq);

+      pcb->ooseq = NULL;

+      LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n"));

+    }

+#endif /* TCP_QUEUE_OOSEQ */

+

+    /* Check if this PCB has stayed too long in SYN-RCVD */

+    if (pcb->state == SYN_RCVD) {

+      if ((u32_t)(tcp_ticks - pcb->tmr) >

+          TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {

+        ++pcb_remove;

+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n"));

+      }

+    }

+

+    /* Check if this PCB has stayed too long in LAST-ACK */

+    if (pcb->state == LAST_ACK) {

+      if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {

+        ++pcb_remove;

+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n"));

+      }

+    }

+

+    /* If the PCB should be removed, do it. */

+    if (pcb_remove) {

+      tcp_pcb_purge(pcb);

+      /* Remove PCB from tcp_active_pcbs list. */

+      if (prev != NULL) {

+        LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);

+        prev->next = pcb->next;

+      } else {

+        /* This PCB was the first. */

+        LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);

+        tcp_active_pcbs = pcb->next;

+      }

+

+      TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);

+

+      pcb2 = pcb->next;

+      memp_free(MEMP_TCP_PCB, pcb);

+      pcb = pcb2;

+    } else {

+

+      /* We check if we should poll the connection. */

+      ++pcb->polltmr;

+      if (pcb->polltmr >= pcb->pollinterval) {

+        pcb->polltmr = 0;

+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));

+        TCP_EVENT_POLL(pcb, err);

+        if (err == ERR_OK) {

+          tcp_output(pcb);

+        }

+      }

+

+      prev = pcb;

+      pcb = pcb->next;

+    }

+  }

+

+

+  /* Steps through all of the TIME-WAIT PCBs. */

+  prev = NULL;

+  pcb = tcp_tw_pcbs;

+  while (pcb != NULL) {

+    LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);

+    pcb_remove = 0;

+

+    /* Check if this PCB has stayed long enough in TIME-WAIT */

+    if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {

+      ++pcb_remove;

+    }

+

+

+

+    /* If the PCB should be removed, do it. */

+    if (pcb_remove) {

+      tcp_pcb_purge(pcb);

+      /* Remove PCB from tcp_tw_pcbs list. */

+      if (prev != NULL) {

+        LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);

+        prev->next = pcb->next;

+      } else {

+        /* This PCB was the first. */

+        LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);

+        tcp_tw_pcbs = pcb->next;

+      }

+      pcb2 = pcb->next;

+      memp_free(MEMP_TCP_PCB, pcb);

+      pcb = pcb2;

+    } else {

+      prev = pcb;

+      pcb = pcb->next;

+    }

+  }

+}

+

+/**

+ * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously

+ * "refused" by upper layer (application) and sends delayed ACKs.

+ *

+ * Automatically called from tcp_tmr().

+ */

+void

+tcp_fasttmr(void)

+{

+  struct tcp_pcb *pcb;

+

+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {

+    /* If there is data which was previously "refused" by upper layer */

+    if (pcb->refused_data != NULL) {

+      /* Notify again application with data previously received. */

+      err_t err;

+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n"));

+      TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);

+      if (err == ERR_OK) {

+        pcb->refused_data = NULL;

+      }

+    }

+

+    /* send delayed ACKs */

+    if (pcb->flags & TF_ACK_DELAY) {

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));

+      tcp_ack_now(pcb);

+      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);

+    }

+  }

+}

+

+/**

+ * Deallocates a list of TCP segments (tcp_seg structures).

+ *

+ * @param seg tcp_seg list of TCP segments to free

+ * @return the number of pbufs that were deallocated

+ */

+u8_t

+tcp_segs_free(struct tcp_seg *seg)

+{

+  u8_t count = 0;

+  struct tcp_seg *next;

+  while (seg != NULL) {

+    next = seg->next;

+    count += tcp_seg_free(seg);

+    seg = next;

+  }

+  return count;

+}

+

+/**

+ * Frees a TCP segment (tcp_seg structure).

+ *

+ * @param seg single tcp_seg to free

+ * @return the number of pbufs that were deallocated

+ */

+u8_t

+tcp_seg_free(struct tcp_seg *seg)

+{

+  u8_t count = 0;

+

+  if (seg != NULL) {

+    if (seg->p != NULL) {

+      count = pbuf_free(seg->p);

+#if TCP_DEBUG

+      seg->p = NULL;

+#endif /* TCP_DEBUG */

+    }

+    memp_free(MEMP_TCP_SEG, seg);

+  }

+  return count;

+}

+

+/**

+ * Sets the priority of a connection.

+ *

+ * @param pcb the tcp_pcb to manipulate

+ * @param prio new priority

+ */

+void

+tcp_setprio(struct tcp_pcb *pcb, u8_t prio)

+{

+  pcb->prio = prio;

+}

+#if TCP_QUEUE_OOSEQ

+

+/**

+ * Returns a copy of the given TCP segment.

+ * The pbuf and data are not copied, only the pointers

+ *

+ * @param seg the old tcp_seg

+ * @return a copy of seg

+ */

+struct tcp_seg *

+tcp_seg_copy(struct tcp_seg *seg)

+{

+  struct tcp_seg *cseg;

+

+  cseg = memp_malloc(MEMP_TCP_SEG);

+  if (cseg == NULL) {

+    return NULL;

+  }

+  SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg));

+  pbuf_ref(cseg->p);

+  return cseg;

+}

+#endif

+

+#if LWIP_CALLBACK_API

+/**

+ * Default receive callback that is called if the user didn't register

+ * a recv callback for the pcb.

+ */

+static err_t

+tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)

+{

+  arg = arg;

+  if (p != NULL) {

+    pbuf_free(p);

+  } else if (err == ERR_OK) {

+    return tcp_close(pcb);

+  }

+  return ERR_OK;

+}

+#endif /* LWIP_CALLBACK_API */

+

+/**

+ * Kills the oldest active connection that has lower priority than prio.

+ *

+ * @param prio minimum priority

+ */

+static void

+tcp_kill_prio(u8_t prio)

+{

+  struct tcp_pcb *pcb, *inactive;

+  u32_t inactivity;

+  u8_t mprio;

+

+

+  mprio = TCP_PRIO_MAX;

+

+  /* We kill the oldest active connection that has lower priority than prio. */

+  inactivity = 0;

+  inactive = NULL;

+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {

+    if (pcb->prio <= prio &&

+       pcb->prio <= mprio &&

+       (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {

+      inactivity = tcp_ticks - pcb->tmr;

+      inactive = pcb;

+      mprio = pcb->prio;

+    }

+  }

+  if (inactive != NULL) {

+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n",

+           (void *)inactive, inactivity));

+    tcp_abort(inactive);

+  }

+}

+

+/**

+ * Kills the oldest connection that is in TIME_WAIT state.

+ * Called from tcp_alloc() if no more connections are available.

+ */

+static void

+tcp_kill_timewait(void)

+{

+  struct tcp_pcb *pcb, *inactive;

+  u32_t inactivity;

+

+  inactivity = 0;

+  inactive = NULL;

+  /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */

+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {

+    if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {

+      inactivity = tcp_ticks - pcb->tmr;

+      inactive = pcb;

+    }

+  }

+  if (inactive != NULL) {

+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n",

+           (void *)inactive, inactivity));

+    tcp_abort(inactive);

+  }

+}

+

+/**

+ * Allocate a new tcp_pcb structure.

+ *

+ * @param prio priority for the new pcb

+ * @return a new tcp_pcb that initially is in state CLOSED

+ */

+struct tcp_pcb *

+tcp_alloc(u8_t prio)

+{

+  struct tcp_pcb *pcb;

+  u32_t iss;

+

+  pcb = memp_malloc(MEMP_TCP_PCB);

+  if (pcb == NULL) {

+    /* Try killing oldest connection in TIME-WAIT. */

+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n"));

+    tcp_kill_timewait();

+    /* Try to allocate a tcp_pcb again. */

+    pcb = memp_malloc(MEMP_TCP_PCB);

+    if (pcb == NULL) {

+      /* Try killing active connections with lower priority than the new one. */

+      tcp_kill_prio(prio);

+      /* Try to allocate a tcp_pcb again. */

+      pcb = memp_malloc(MEMP_TCP_PCB);

+    }

+  }

+  if (pcb != NULL) {

+    memset(pcb, 0, sizeof(struct tcp_pcb));

+    pcb->prio = TCP_PRIO_NORMAL;

+    pcb->snd_buf = TCP_SND_BUF;

+    pcb->snd_queuelen = 0;

+    pcb->rcv_wnd = TCP_WND;

+    pcb->rcv_ann_wnd = TCP_WND;

+    pcb->tos = 0;

+    pcb->ttl = TCP_TTL;

+    /* The send MSS is updated when an MSS option is received. */

+    pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;

+    pcb->rto = 3000 / TCP_SLOW_INTERVAL;

+    pcb->sa = 0;

+    pcb->sv = 3000 / TCP_SLOW_INTERVAL;

+    pcb->rtime = -1;

+    pcb->cwnd = 1;

+    iss = tcp_next_iss();

+    pcb->snd_wl2 = iss;

+    pcb->snd_nxt = iss;

+    pcb->snd_max = iss;

+    pcb->lastack = iss;

+    pcb->snd_lbb = iss;

+    pcb->tmr = tcp_ticks;

+

+    pcb->polltmr = 0;

+

+#if LWIP_CALLBACK_API

+    pcb->recv = tcp_recv_null;

+#endif /* LWIP_CALLBACK_API */

+

+    /* Init KEEPALIVE timer */

+    pcb->keep_idle  = TCP_KEEPIDLE_DEFAULT;

+

+#if LWIP_TCP_KEEPALIVE

+    pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT;

+    pcb->keep_cnt   = TCP_KEEPCNT_DEFAULT;

+#endif /* LWIP_TCP_KEEPALIVE */

+

+    pcb->keep_cnt_sent = 0;

+  }

+  return pcb;

+}

+

+/**

+ * Creates a new TCP protocol control block but doesn't place it on

+ * any of the TCP PCB lists.

+ * The pcb is not put on any list until binding using tcp_bind().

+ *

+ * @internal: Maybe there should be a idle TCP PCB list where these

+ * PCBs are put on. Port reservation using tcp_bind() is implemented but

+ * allocated pcbs that are not bound can't be killed automatically if wanting

+ * to allocate a pcb with higher prio (@see tcp_kill_prio())

+ *

+ * @return a new tcp_pcb that initially is in state CLOSED

+ */

+struct tcp_pcb *

+tcp_new(void)

+{

+  return tcp_alloc(TCP_PRIO_NORMAL);

+}

+

+/**

+ * Used to specify the argument that should be passed callback

+ * functions.

+ *

+ * @param pcb tcp_pcb to set the callback argument

+ * @param arg void pointer argument to pass to callback functions

+ */

+void

+tcp_arg(struct tcp_pcb *pcb, void *arg)

+{

+  pcb->callback_arg = arg;

+}

+#if LWIP_CALLBACK_API

+

+/**

+ * Used to specify the function that should be called when a TCP

+ * connection receives data.

+ *

+ * @param pcb tcp_pcb to set the recv callback

+ * @param recv callback function to call for this pcb when data is received

+ */

+void

+tcp_recv(struct tcp_pcb *pcb,

+   err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))

+{

+  pcb->recv = recv;

+}

+

+/**

+ * Used to specify the function that should be called when TCP data

+ * has been successfully delivered to the remote host.

+ *

+ * @param pcb tcp_pcb to set the sent callback

+ * @param sent callback function to call for this pcb when data is successfully sent

+ */

+void

+tcp_sent(struct tcp_pcb *pcb,

+   err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len))

+{

+  pcb->sent = sent;

+}

+

+/**

+ * Used to specify the function that should be called when a fatal error

+ * has occured on the connection.

+ *

+ * @param pcb tcp_pcb to set the err callback

+ * @param errf callback function to call for this pcb when a fatal error

+ *        has occured on the connection

+ */

+void

+tcp_err(struct tcp_pcb *pcb,

+   void (* errf)(void *arg, err_t err))

+{

+  pcb->errf = errf;

+}

+

+/**

+ * Used for specifying the function that should be called when a

+ * LISTENing connection has been connected to another host.

+ *

+ * @param pcb tcp_pcb to set the accept callback

+ * @param accept callback function to call for this pcb when LISTENing

+ *        connection has been connected to another host

+ */

+void

+tcp_accept(struct tcp_pcb *pcb,

+     err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))

+{

+  ((struct tcp_pcb_listen *)pcb)->accept = accept;

+}

+#endif /* LWIP_CALLBACK_API */

+

+

+/**

+ * Used to specify the function that should be called periodically

+ * from TCP. The interval is specified in terms of the TCP coarse

+ * timer interval, which is called twice a second.

+ *

+ */

+void

+tcp_poll(struct tcp_pcb *pcb,

+   err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval)

+{

+#if LWIP_CALLBACK_API

+  pcb->poll = poll;

+#endif /* LWIP_CALLBACK_API */

+  pcb->pollinterval = interval;

+}

+

+/**

+ * Purges a TCP PCB. Removes any buffered data and frees the buffer memory

+ * (pcb->ooseq, pcb->unsent and pcb->unacked are freed).

+ *

+ * @param pcb tcp_pcb to purge. The pcb itself is not deallocated!

+ */

+void

+tcp_pcb_purge(struct tcp_pcb *pcb)

+{

+  if (pcb->state != CLOSED &&

+     pcb->state != TIME_WAIT &&

+     pcb->state != LISTEN) {

+

+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));

+

+    if (pcb->refused_data != NULL) {

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n"));

+      pbuf_free(pcb->refused_data);

+      pcb->refused_data = NULL;

+    }

+    if (pcb->unsent != NULL) {

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));

+    }

+    if (pcb->unacked != NULL) {

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));

+    }

+#if TCP_QUEUE_OOSEQ /* LW */

+    if (pcb->ooseq != NULL) {

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));

+    }

+

+    /* Stop the retransmission timer as it will expect data on unacked

+       queue if it fires */

+    pcb->rtime = -1;

+

+    tcp_segs_free(pcb->ooseq);

+    pcb->ooseq = NULL;

+#endif /* TCP_QUEUE_OOSEQ */

+    tcp_segs_free(pcb->unsent);

+    tcp_segs_free(pcb->unacked);

+    pcb->unacked = pcb->unsent = NULL;

+  }

+}

+

+/**

+ * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.

+ *

+ * @param pcblist PCB list to purge.

+ * @param pcb tcp_pcb to purge. The pcb itself is also deallocated!

+ */

+void

+tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)

+{

+  TCP_RMV(pcblist, pcb);

+

+  tcp_pcb_purge(pcb);

+

+  /* if there is an outstanding delayed ACKs, send it */

+  if (pcb->state != TIME_WAIT &&

+     pcb->state != LISTEN &&

+     pcb->flags & TF_ACK_DELAY) {

+    pcb->flags |= TF_ACK_NOW;

+    tcp_output(pcb);

+  }

+

+  if (pcb->state != LISTEN) {

+    LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL);

+    LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL);

+#if TCP_QUEUE_OOSEQ

+    LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL);

+#endif /* TCP_QUEUE_OOSEQ */

+  }

+

+  pcb->state = CLOSED;

+

+  LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());

+}

+

+/**

+ * Calculates a new initial sequence number for new connections.

+ *

+ * @return u32_t pseudo random sequence number

+ */

+u32_t

+tcp_next_iss(void)

+{

+  static u32_t iss = 6510;

+

+  iss += tcp_ticks;       /* XXX */

+  return iss;

+}

+

+#if TCP_CALCULATE_EFF_SEND_MSS

+/**

+ * Calcluates the effective send mss that can be used for a specific IP address

+ * by using ip_route to determin the netif used to send to the address and

+ * calculating the minimum of TCP_MSS and that netif's mtu (if set).

+ */

+u16_t

+tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr)

+{

+  u16_t mss_s;

+  struct netif *outif;

+

+  outif = ip_route(addr);

+  if ((outif != NULL) && (outif->mtu != 0)) {

+    mss_s = outif->mtu - IP_HLEN - TCP_HLEN;

+    /* RFC 1122, chap 4.2.2.6:

+     * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize

+     * but we only send options with SYN and that is never filled with data! */

+    sendmss = LWIP_MIN(sendmss, mss_s);

+  }

+  return sendmss;

+}

+#endif /* TCP_CALCULATE_EFF_SEND_MSS */

+

+#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG

+/**

+ * Print a tcp header for debugging purposes.

+ *

+ * @param tcphdr pointer to a struct tcp_hdr

+ */

+void

+tcp_debug_print(struct tcp_hdr *tcphdr)

+{

+  LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n"));

+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(TCP_DEBUG, ("|    %5"U16_F"      |    %5"U16_F"      | (src port, dest port)\n",

+         ntohs(tcphdr->src), ntohs(tcphdr->dest)));

+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (seq no)\n",

+          ntohl(tcphdr->seqno)));

+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (ack no)\n",

+         ntohl(tcphdr->ackno)));

+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" |   |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"|     %5"U16_F"     | (hdrlen, flags (",

+       TCPH_HDRLEN(tcphdr),

+         TCPH_FLAGS(tcphdr) >> 5 & 1,

+         TCPH_FLAGS(tcphdr) >> 4 & 1,

+         TCPH_FLAGS(tcphdr) >> 3 & 1,

+         TCPH_FLAGS(tcphdr) >> 2 & 1,

+         TCPH_FLAGS(tcphdr) >> 1 & 1,

+         TCPH_FLAGS(tcphdr) & 1,

+         ntohs(tcphdr->wnd)));

+  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));

+  LWIP_DEBUGF(TCP_DEBUG, ("), win)\n"));

+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(TCP_DEBUG, ("|    0x%04"X16_F"     |     %5"U16_F"     | (chksum, urgp)\n",

+         ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));

+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));

+}

+

+/**

+ * Print a tcp state for debugging purposes.

+ *

+ * @param s enum tcp_state to print

+ */

+void

+tcp_debug_print_state(enum tcp_state s)

+{

+  LWIP_DEBUGF(TCP_DEBUG, ("State: "));

+  switch (s) {

+  case CLOSED:

+    LWIP_DEBUGF(TCP_DEBUG, ("CLOSED\n"));

+    break;

+ case LISTEN:

+   LWIP_DEBUGF(TCP_DEBUG, ("LISTEN\n"));

+   break;

+  case SYN_SENT:

+    LWIP_DEBUGF(TCP_DEBUG, ("SYN_SENT\n"));

+    break;

+  case SYN_RCVD:

+    LWIP_DEBUGF(TCP_DEBUG, ("SYN_RCVD\n"));

+    break;

+  case ESTABLISHED:

+    LWIP_DEBUGF(TCP_DEBUG, ("ESTABLISHED\n"));

+    break;

+  case FIN_WAIT_1:

+    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n"));

+    break;

+  case FIN_WAIT_2:

+    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n"));

+    break;

+  case CLOSE_WAIT:

+    LWIP_DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n"));

+    break;

+  case CLOSING:

+    LWIP_DEBUGF(TCP_DEBUG, ("CLOSING\n"));

+    break;

+  case LAST_ACK:

+    LWIP_DEBUGF(TCP_DEBUG, ("LAST_ACK\n"));

+    break;

+  case TIME_WAIT:

+    LWIP_DEBUGF(TCP_DEBUG, ("TIME_WAIT\n"));

+   break;

+  }

+}

+

+/**

+ * Print tcp flags for debugging purposes.

+ *

+ * @param flags tcp flags, all active flags are printed

+ */

+void

+tcp_debug_print_flags(u8_t flags)

+{

+  if (flags & TCP_FIN) {

+    LWIP_DEBUGF(TCP_DEBUG, ("FIN "));

+  }

+  if (flags & TCP_SYN) {

+    LWIP_DEBUGF(TCP_DEBUG, ("SYN "));

+  }

+  if (flags & TCP_RST) {

+    LWIP_DEBUGF(TCP_DEBUG, ("RST "));

+  }

+  if (flags & TCP_PSH) {

+    LWIP_DEBUGF(TCP_DEBUG, ("PSH "));

+  }

+  if (flags & TCP_ACK) {

+    LWIP_DEBUGF(TCP_DEBUG, ("ACK "));

+  }

+  if (flags & TCP_URG) {

+    LWIP_DEBUGF(TCP_DEBUG, ("URG "));

+  }

+  if (flags & TCP_ECE) {

+    LWIP_DEBUGF(TCP_DEBUG, ("ECE "));

+  }

+  if (flags & TCP_CWR) {

+    LWIP_DEBUGF(TCP_DEBUG, ("CWR "));

+  }

+}

+

+/**

+ * Print all tcp_pcbs in every list for debugging purposes.

+ */

+void

+tcp_debug_print_pcbs(void)

+{

+  struct tcp_pcb *pcb;

+  LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n"));

+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {

+    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",

+                       pcb->local_port, pcb->remote_port,

+                       pcb->snd_nxt, pcb->rcv_nxt));

+    tcp_debug_print_state(pcb->state);

+  }

+  LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n"));

+  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {

+    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",

+                       pcb->local_port, pcb->remote_port,

+                       pcb->snd_nxt, pcb->rcv_nxt));

+    tcp_debug_print_state(pcb->state);

+  }

+  LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n"));

+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {

+    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",

+                       pcb->local_port, pcb->remote_port,

+                       pcb->snd_nxt, pcb->rcv_nxt));

+    tcp_debug_print_state(pcb->state);

+  }

+}

+

+/**

+ * Check state consistency of the tcp_pcb lists.

+ */

+s16_t

+tcp_pcbs_sane(void)

+{

+  struct tcp_pcb *pcb;

+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {

+    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED);

+    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN);

+    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);

+  }

+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {

+    LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);

+  }

+  return 1;

+}

+#endif /* TCP_DEBUG */

+

+#endif /* LWIP_TCP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/tcp_in.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/tcp_in.c
new file mode 100644
index 0000000..0f79b54
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/tcp_in.c
@@ -0,0 +1,1352 @@
+/**

+ * @file

+ * Transmission Control Protocol, incoming traffic

+ *

+ * The input processing functions of the TCP layer.

+ *

+ * These functions are generally called in the order (ip_input() ->)

+ * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/tcp.h"

+#include "lwip/def.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/mem.h"

+#include "lwip/memp.h"

+#include "lwip/inet.h"

+#include "lwip/inet_chksum.h"

+#include "lwip/stats.h"

+#include "lwip/snmp.h"

+#include "arch/perf.h"

+

+/* These variables are global to all functions involved in the input

+   processing of TCP segments. They are set by the tcp_input()

+   function. */

+static struct tcp_seg inseg;

+static struct tcp_hdr *tcphdr;

+static struct ip_hdr *iphdr;

+static u32_t seqno, ackno;

+static u8_t flags;

+static u16_t tcplen;

+

+static u8_t recv_flags;

+static struct pbuf *recv_data;

+

+struct tcp_pcb *tcp_input_pcb;

+

+/* Forward declarations. */

+static err_t tcp_process(struct tcp_pcb *pcb);

+static u8_t tcp_receive(struct tcp_pcb *pcb);

+static void tcp_parseopt(struct tcp_pcb *pcb);

+

+static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);

+static err_t tcp_timewait_input(struct tcp_pcb *pcb);

+

+/**

+ * The initial input processing of TCP. It verifies the TCP header, demultiplexes

+ * the segment between the PCBs and passes it on to tcp_process(), which implements

+ * the TCP finite state machine. This function is called by the IP layer (in

+ * ip_input()).

+ *

+ * @param p received TCP segment to process (p->payload pointing to the IP header)

+ * @param inp network interface on which this segment was received

+ */

+void

+tcp_input(struct pbuf *p, struct netif *inp)

+{

+  struct tcp_pcb *pcb, *prev;

+  struct tcp_pcb_listen *lpcb;

+  u8_t hdrlen;

+  err_t err;

+

+  PERF_START;

+

+  TCP_STATS_INC(tcp.recv);

+  snmp_inc_tcpinsegs();

+

+  iphdr = p->payload;

+  tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);

+

+#if TCP_INPUT_DEBUG

+  tcp_debug_print(tcphdr);

+#endif

+

+  /* remove header from payload */

+  if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {

+    /* drop short packets */

+    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));

+    TCP_STATS_INC(tcp.lenerr);

+    TCP_STATS_INC(tcp.drop);

+    snmp_inc_tcpinerrs();

+    pbuf_free(p);

+    return;

+  }

+

+  /* Don't even process incoming broadcasts/multicasts. */

+  if (ip_addr_isbroadcast(&(iphdr->dest), inp) ||

+      ip_addr_ismulticast(&(iphdr->dest))) {

+    TCP_STATS_INC(tcp.proterr);

+    TCP_STATS_INC(tcp.drop);

+    snmp_inc_tcpinerrs();

+    pbuf_free(p);

+    return;

+  }

+

+#if CHECKSUM_CHECK_TCP

+  /* Verify TCP checksum. */

+  if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),

+      (struct ip_addr *)&(iphdr->dest),

+      IP_PROTO_TCP, p->tot_len) != 0) {

+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",

+        inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest),

+      IP_PROTO_TCP, p->tot_len)));

+#if TCP_DEBUG

+    tcp_debug_print(tcphdr);

+#endif /* TCP_DEBUG */

+    TCP_STATS_INC(tcp.chkerr);

+    TCP_STATS_INC(tcp.drop);

+    snmp_inc_tcpinerrs();

+    pbuf_free(p);

+    return;

+  }

+#endif

+

+  /* Move the payload pointer in the pbuf so that it points to the

+     TCP data instead of the TCP header. */

+  hdrlen = TCPH_HDRLEN(tcphdr);

+  if(pbuf_header(p, -(hdrlen * 4))){

+    /* drop short packets */

+    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));

+    TCP_STATS_INC(tcp.lenerr);

+    TCP_STATS_INC(tcp.drop);

+    snmp_inc_tcpinerrs();

+    pbuf_free(p);

+    return;

+  }

+

+  /* Convert fields in TCP header to host byte order. */

+  tcphdr->src = ntohs(tcphdr->src);

+  tcphdr->dest = ntohs(tcphdr->dest);

+  seqno = tcphdr->seqno = ntohl(tcphdr->seqno);

+  ackno = tcphdr->ackno = ntohl(tcphdr->ackno);

+  tcphdr->wnd = ntohs(tcphdr->wnd);

+

+  flags = TCPH_FLAGS(tcphdr) & TCP_FLAGS;

+  tcplen = p->tot_len + ((flags & TCP_FIN || flags & TCP_SYN)? 1: 0);

+

+  /* Demultiplex an incoming segment. First, we check if it is destined

+     for an active connection. */

+  prev = NULL;

+

+

+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {

+    LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);

+    LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);

+    LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);

+    if (pcb->remote_port == tcphdr->src &&

+       pcb->local_port == tcphdr->dest &&

+       ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&

+       ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {

+

+      /* Move this PCB to the front of the list so that subsequent

+         lookups will be faster (we exploit locality in TCP segment

+         arrivals). */

+      LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);

+      if (prev != NULL) {

+        prev->next = pcb->next;

+        pcb->next = tcp_active_pcbs;

+        tcp_active_pcbs = pcb;

+      }

+      LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);

+      break;

+    }

+    prev = pcb;

+  }

+

+  if (pcb == NULL) {

+    /* If it did not go to an active connection, we check the connections

+       in the TIME-WAIT state. */

+    for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {

+      LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);

+      if (pcb->remote_port == tcphdr->src &&

+         pcb->local_port == tcphdr->dest &&

+         ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&

+         ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {

+        /* We don't really care enough to move this PCB to the front

+           of the list since we are not very likely to receive that

+           many segments for connections in TIME-WAIT. */

+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));

+        tcp_timewait_input(pcb);

+        pbuf_free(p);

+        return;

+      }

+    }

+

+  /* Finally, if we still did not get a match, we check all PCBs that

+     are LISTENing for incoming connections. */

+    prev = NULL;

+    for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {

+      if ((ip_addr_isany(&(lpcb->local_ip)) ||

+        ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) &&

+        lpcb->local_port == tcphdr->dest) {

+        /* Move this PCB to the front of the list so that subsequent

+           lookups will be faster (we exploit locality in TCP segment

+           arrivals). */

+        if (prev != NULL) {

+          ((struct tcp_pcb_listen *)prev)->next = lpcb->next;

+                /* our successor is the remainder of the listening list */

+          lpcb->next = tcp_listen_pcbs.listen_pcbs;

+                /* put this listening pcb at the head of the listening list */

+          tcp_listen_pcbs.listen_pcbs = lpcb;

+        }

+

+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));

+        tcp_listen_input(lpcb);

+        pbuf_free(p);

+        return;

+      }

+      prev = (struct tcp_pcb *)lpcb;

+    }

+  }

+

+#if TCP_INPUT_DEBUG

+  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));

+  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));

+  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));

+#endif /* TCP_INPUT_DEBUG */

+

+

+  if (pcb != NULL) {

+    /* The incoming segment belongs to a connection. */

+#if TCP_INPUT_DEBUG

+#if TCP_DEBUG

+    tcp_debug_print_state(pcb->state);

+#endif /* TCP_DEBUG */

+#endif /* TCP_INPUT_DEBUG */

+

+    /* Set up a tcp_seg structure. */

+    inseg.next = NULL;

+    inseg.len = p->tot_len;

+    inseg.dataptr = p->payload;

+    inseg.p = p;

+    inseg.tcphdr = tcphdr;

+

+    recv_data = NULL;

+    recv_flags = 0;

+

+    /* If there is data which was previously "refused" by upper layer */

+    if (pcb->refused_data != NULL) {

+      /* Notify again application with data previously received. */

+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));

+      TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);

+      if (err == ERR_OK) {

+        pcb->refused_data = NULL;

+      } else {

+        /* drop incoming packets, because pcb is "full" */

+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));

+        TCP_STATS_INC(tcp.drop);

+        snmp_inc_tcpinerrs();

+        pbuf_free(p);

+        return;

+      }

+    }

+

+    tcp_input_pcb = pcb;

+    err = tcp_process(pcb);

+    tcp_input_pcb = NULL;

+    /* A return value of ERR_ABRT means that tcp_abort() was called

+       and that the pcb has been freed. If so, we don't do anything. */

+    if (err != ERR_ABRT) {

+      if (recv_flags & TF_RESET) {

+        /* TF_RESET means that the connection was reset by the other

+           end. We then call the error callback to inform the

+           application that the connection is dead before we

+           deallocate the PCB. */

+        TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);

+        tcp_pcb_remove(&tcp_active_pcbs, pcb);

+        memp_free(MEMP_TCP_PCB, pcb);

+      } else if (recv_flags & TF_CLOSED) {

+        /* The connection has been closed and we will deallocate the

+           PCB. */

+        tcp_pcb_remove(&tcp_active_pcbs, pcb);

+        memp_free(MEMP_TCP_PCB, pcb);

+      } else {

+        err = ERR_OK;

+        /* If the application has registered a "sent" function to be

+           called when new send buffer space is available, we call it

+           now. */

+        if (pcb->acked > 0) {

+          TCP_EVENT_SENT(pcb, pcb->acked, err);

+        }

+

+        if (recv_data != NULL) {

+          if(flags & TCP_PSH) {

+            recv_data->flags |= PBUF_FLAG_PUSH;

+          }

+

+          /* Notify application that data has been received. */

+          TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);

+

+          /* If the upper layer can't receive this data, store it */

+          if (err != ERR_OK) {

+            pcb->refused_data = recv_data;

+            LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n"));

+          }

+        }

+

+        /* If a FIN segment was received, we call the callback

+           function with a NULL buffer to indicate EOF. */

+        if (recv_flags & TF_GOT_FIN) {

+          TCP_EVENT_RECV(pcb, NULL, ERR_OK, err);

+        }

+

+        /* If there were no errors, we try to send something out. */

+        if (err == ERR_OK) {

+          tcp_output(pcb);

+        }

+      }

+    }

+

+

+    /* give up our reference to inseg.p */

+    if (inseg.p != NULL)

+    {

+      pbuf_free(inseg.p);

+      inseg.p = NULL;

+    }

+#if TCP_INPUT_DEBUG

+#if TCP_DEBUG

+    tcp_debug_print_state(pcb->state);

+#endif /* TCP_DEBUG */

+#endif /* TCP_INPUT_DEBUG */

+

+  } else {

+

+    /* If no matching PCB was found, send a TCP RST (reset) to the

+       sender. */

+    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));

+    if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {

+      TCP_STATS_INC(tcp.proterr);

+      TCP_STATS_INC(tcp.drop);

+      tcp_rst(ackno, seqno + tcplen,

+        &(iphdr->dest), &(iphdr->src),

+        tcphdr->dest, tcphdr->src);

+    }

+    pbuf_free(p);

+  }

+

+  LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());

+  PERF_STOP("tcp_input");

+}

+

+/**

+ * Called by tcp_input() when a segment arrives for a listening

+ * connection (from tcp_input()).

+ *

+ * @param pcb the tcp_pcb_listen for which a segment arrived

+ * @return ERR_OK if the segment was processed

+ *         another err_t on error

+ *

+ * @note the return value is not (yet?) used in tcp_input()

+ * @note the segment which arrived is saved in global variables, therefore only the pcb

+ *       involved is passed as a parameter to this function

+ */

+static err_t

+tcp_listen_input(struct tcp_pcb_listen *pcb)

+{

+  struct tcp_pcb *npcb;

+  u32_t optdata;

+

+  /* In the LISTEN state, we check for incoming SYN segments,

+     creates a new PCB, and responds with a SYN|ACK. */

+  if (flags & TCP_ACK) {

+    /* For incoming segments with the ACK flag set, respond with a

+       RST. */

+    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));

+    tcp_rst(ackno + 1, seqno + tcplen,

+      &(iphdr->dest), &(iphdr->src),

+      tcphdr->dest, tcphdr->src);

+  } else if (flags & TCP_SYN) {

+    LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));

+#if TCP_LISTEN_BACKLOG

+    if (pcb->accepts_pending >= pcb->backlog) {

+      return ERR_ABRT;

+    }

+#endif /* TCP_LISTEN_BACKLOG */

+    npcb = tcp_alloc(pcb->prio);

+    /* If a new PCB could not be created (probably due to lack of memory),

+       we don't do anything, but rely on the sender will retransmit the

+       SYN at a time when we have more memory available. */

+    if (npcb == NULL) {

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));

+      TCP_STATS_INC(tcp.memerr);

+      return ERR_MEM;

+    }

+#if TCP_LISTEN_BACKLOG

+    pcb->accepts_pending++;

+#endif /* TCP_LISTEN_BACKLOG */

+    /* Set up the new PCB. */

+    ip_addr_set(&(npcb->local_ip), &(iphdr->dest));

+    npcb->local_port = pcb->local_port;

+    ip_addr_set(&(npcb->remote_ip), &(iphdr->src));

+    npcb->remote_port = tcphdr->src;

+    npcb->state = SYN_RCVD;

+    npcb->rcv_nxt = seqno + 1;

+    npcb->snd_wnd = tcphdr->wnd;

+    npcb->ssthresh = npcb->snd_wnd;

+    npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */

+    npcb->callback_arg = pcb->callback_arg;

+#if LWIP_CALLBACK_API

+    npcb->accept = pcb->accept;

+#endif /* LWIP_CALLBACK_API */

+    /* inherit socket options */

+    npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER);

+    /* Register the new PCB so that we can begin receiving segments

+       for it. */

+    TCP_REG(&tcp_active_pcbs, npcb);

+

+    /* Parse any options in the SYN. */

+    tcp_parseopt(npcb);

+#if TCP_CALCULATE_EFF_SEND_MSS

+    npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));

+#endif /* TCP_CALCULATE_EFF_SEND_MSS */

+

+    snmp_inc_tcppassiveopens();

+

+    /* Build an MSS option. */

+    optdata = TCP_BUILD_MSS_OPTION();

+    /* Send a SYN|ACK together with the MSS option. */

+    tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, (u8_t *)&optdata, 4);

+    return tcp_output(npcb);

+  }

+  return ERR_OK;

+}

+

+/**

+ * Called by tcp_input() when a segment arrives for a connection in

+ * TIME_WAIT.

+ *

+ * @param pcb the tcp_pcb for which a segment arrived

+ *

+ * @note the segment which arrived is saved in global variables, therefore only the pcb

+ *       involved is passed as a parameter to this function

+ */

+static err_t

+tcp_timewait_input(struct tcp_pcb *pcb)

+{

+  if (TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) {

+    pcb->rcv_nxt = seqno + tcplen;

+  }

+  if (tcplen > 0) {

+    tcp_ack_now(pcb);

+  }

+  return tcp_output(pcb);

+}

+

+/**

+ * Implements the TCP state machine. Called by tcp_input. In some

+ * states tcp_receive() is called to receive data. The tcp_seg

+ * argument will be freed by the caller (tcp_input()) unless the

+ * recv_data pointer in the pcb is set.

+ *

+ * @param pcb the tcp_pcb for which a segment arrived

+ *

+ * @note the segment which arrived is saved in global variables, therefore only the pcb

+ *       involved is passed as a parameter to this function

+ */

+static err_t

+tcp_process(struct tcp_pcb *pcb)

+{

+  struct tcp_seg *rseg;

+  u8_t acceptable = 0;

+  err_t err;

+  u8_t accepted_inseq;

+

+  err = ERR_OK;

+

+  /* Process incoming RST segments. */

+  if (flags & TCP_RST) {

+    /* First, determine if the reset is acceptable. */

+    if (pcb->state == SYN_SENT) {

+      if (ackno == pcb->snd_nxt) {

+        acceptable = 1;

+      }

+    } else {

+      if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,

+                          pcb->rcv_nxt+pcb->rcv_ann_wnd)) {

+        acceptable = 1;

+      }

+    }

+

+    if (acceptable) {

+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));

+      LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);

+      recv_flags = TF_RESET;

+      pcb->flags &= ~TF_ACK_DELAY;

+      return ERR_RST;

+    } else {

+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",

+       seqno, pcb->rcv_nxt));

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",

+       seqno, pcb->rcv_nxt));

+      return ERR_OK;

+    }

+  }

+

+  /* Update the PCB (in)activity timer. */

+  pcb->tmr = tcp_ticks;

+  pcb->keep_cnt_sent = 0;

+

+  /* Do different things depending on the TCP state. */

+  switch (pcb->state) {

+  case SYN_SENT:

+    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,

+     pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));

+    /* received SYN ACK with expected sequence number? */

+    if ((flags & TCP_ACK) && (flags & TCP_SYN)

+        && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {

+      pcb->snd_buf++;

+      pcb->rcv_nxt = seqno + 1;

+      pcb->lastack = ackno;

+      pcb->snd_wnd = tcphdr->wnd;

+      pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */

+      pcb->state = ESTABLISHED;

+

+      /* Parse any options in the SYNACK before using pcb->mss since that

+       * can be changed by the received options! */

+      tcp_parseopt(pcb);

+#if TCP_CALCULATE_EFF_SEND_MSS

+      pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));

+#endif /* TCP_CALCULATE_EFF_SEND_MSS */

+

+      /* Set ssthresh again after changing pcb->mss (already set in tcp_connect

+       * but for the default value of pcb->mss) */

+      pcb->ssthresh = pcb->mss * 10;

+

+      pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);

+      LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));

+      --pcb->snd_queuelen;

+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));

+      rseg = pcb->unacked;

+      pcb->unacked = rseg->next;

+

+      /* If there's nothing left to acknowledge, stop the retransmit

+         timer, otherwise reset it to start again */

+      if(pcb->unacked == NULL)

+        pcb->rtime = -1;

+      else {

+        pcb->rtime = 0;

+        pcb->nrtx = 0;

+      }

+

+      tcp_seg_free(rseg);

+

+      /* Call the user specified function to call when sucessfully

+       * connected. */

+      TCP_EVENT_CONNECTED(pcb, ERR_OK, err);

+      tcp_ack_now(pcb);

+    }

+    /* received ACK? possibly a half-open connection */

+    else if (flags & TCP_ACK) {

+      /* send a RST to bring the other side in a non-synchronized state. */

+      tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),

+        tcphdr->dest, tcphdr->src);

+    }

+    break;

+  case SYN_RCVD:

+    if (flags & TCP_ACK &&

+       !(flags & TCP_RST)) {

+      /* expected ACK number? */

+      if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {

+        u16_t old_cwnd;

+        pcb->state = ESTABLISHED;

+        LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));

+#if LWIP_CALLBACK_API

+        LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);

+#endif

+        /* Call the accept function. */

+        TCP_EVENT_ACCEPT(pcb, ERR_OK, err);

+        if (err != ERR_OK) {

+          /* If the accept function returns with an error, we abort

+           * the connection. */

+          tcp_abort(pcb);

+          return ERR_ABRT;

+        }

+        old_cwnd = pcb->cwnd;

+        /* If there was any data contained within this ACK,

+         * we'd better pass it on to the application as well. */

+        accepted_inseq = tcp_receive(pcb);

+

+        pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);

+

+        if ((flags & TCP_FIN) && accepted_inseq) {

+          tcp_ack_now(pcb);

+          pcb->state = CLOSE_WAIT;

+        }

+      }

+      /* incorrect ACK number */

+      else {

+        /* send RST */

+        tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),

+                tcphdr->dest, tcphdr->src);

+      }

+    }

+    break;

+  case CLOSE_WAIT:

+    /* FALLTHROUGH */

+  case ESTABLISHED:

+    accepted_inseq = tcp_receive(pcb);

+    if ((flags & TCP_FIN) && accepted_inseq) { /* passive close */

+      tcp_ack_now(pcb);

+      pcb->state = CLOSE_WAIT;

+    }

+    break;

+  case FIN_WAIT_1:

+    tcp_receive(pcb);

+    if (flags & TCP_FIN) {

+      if (flags & TCP_ACK && ackno == pcb->snd_nxt) {

+        LWIP_DEBUGF(TCP_DEBUG,

+          ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));

+        tcp_ack_now(pcb);

+        tcp_pcb_purge(pcb);

+        TCP_RMV(&tcp_active_pcbs, pcb);

+        pcb->state = TIME_WAIT;

+        TCP_REG(&tcp_tw_pcbs, pcb);

+      } else {

+        tcp_ack_now(pcb);

+        pcb->state = CLOSING;

+      }

+    } else if (flags & TCP_ACK && ackno == pcb->snd_nxt) {

+      pcb->state = FIN_WAIT_2;

+    }

+    break;

+  case FIN_WAIT_2:

+    tcp_receive(pcb);

+    if (flags & TCP_FIN) {

+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));

+      tcp_ack_now(pcb);

+      tcp_pcb_purge(pcb);

+      TCP_RMV(&tcp_active_pcbs, pcb);

+      pcb->state = TIME_WAIT;

+      TCP_REG(&tcp_tw_pcbs, pcb);

+    }

+    break;

+  case CLOSING:

+    tcp_receive(pcb);

+    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {

+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));

+      tcp_ack_now(pcb);

+      tcp_pcb_purge(pcb);

+      TCP_RMV(&tcp_active_pcbs, pcb);

+      pcb->state = TIME_WAIT;

+      TCP_REG(&tcp_tw_pcbs, pcb);

+    }

+    break;

+  case LAST_ACK:

+    tcp_receive(pcb);

+    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {

+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));

+      /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */

+      recv_flags = TF_CLOSED;

+    }

+    break;

+  default:

+    break;

+  }

+  return ERR_OK;

+}

+

+/**

+ * Called by tcp_process. Checks if the given segment is an ACK for outstanding

+ * data, and if so frees the memory of the buffered data. Next, is places the

+ * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment

+ * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until

+ * i it has been removed from the buffer.

+ *

+ * If the incoming segment constitutes an ACK for a segment that was used for RTT

+ * estimation, the RTT is estimated here as well.

+ *

+ * Called from tcp_process().

+ *

+ * @return 1 if the incoming segment is the next in sequence, 0 if not

+ */

+static u8_t

+tcp_receive(struct tcp_pcb *pcb)

+{

+  struct tcp_seg *next;

+#if TCP_QUEUE_OOSEQ

+  struct tcp_seg *prev, *cseg;

+#endif

+  struct pbuf *p;

+  s32_t off;

+  s16_t m;

+  u32_t right_wnd_edge;

+  u16_t new_tot_len;

+  u8_t accepted_inseq = 0;

+

+  if (flags & TCP_ACK) {

+    right_wnd_edge = pcb->snd_wnd + pcb->snd_wl1;

+

+    /* Update window. */

+    if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||

+       (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||

+       (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {

+      pcb->snd_wnd = tcphdr->wnd;

+      pcb->snd_wl1 = seqno;

+      pcb->snd_wl2 = ackno;

+      if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {

+          pcb->persist_backoff = 0;

+      }

+      LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));

+#if TCP_WND_DEBUG

+    } else {

+      if (pcb->snd_wnd != tcphdr->wnd) {

+        LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: no window update lastack %"U32_F" snd_max %"U32_F" ackno %"U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",

+                               pcb->lastack, pcb->snd_max, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));

+      }

+#endif /* TCP_WND_DEBUG */

+    }

+

+    if (pcb->lastack == ackno) {

+      pcb->acked = 0;

+

+      if (pcb->snd_wl1 + pcb->snd_wnd == right_wnd_edge){

+        ++pcb->dupacks;

+        if (pcb->dupacks >= 3 && pcb->unacked != NULL) {

+          if (!(pcb->flags & TF_INFR)) {

+            /* This is fast retransmit. Retransmit the first unacked segment. */

+            LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %"U16_F" (%"U32_F"), fast retransmit %"U32_F"\n",

+                                       (u16_t)pcb->dupacks, pcb->lastack,

+                                       ntohl(pcb->unacked->tcphdr->seqno)));

+            tcp_rexmit(pcb);

+            /* Set ssthresh to max (FlightSize / 2, 2*SMSS) */

+            /*pcb->ssthresh = LWIP_MAX((pcb->snd_max -

+                                      pcb->lastack) / 2,

+                                      2 * pcb->mss);*/

+            /* Set ssthresh to half of the minimum of the current cwnd and the advertised window */

+            if (pcb->cwnd > pcb->snd_wnd)

+              pcb->ssthresh = pcb->snd_wnd / 2;

+            else

+              pcb->ssthresh = pcb->cwnd / 2;

+

+            /* The minimum value for ssthresh should be 2 MSS */

+            if (pcb->ssthresh < 2*pcb->mss) {

+              LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: The minimum value for ssthresh %"U16_F" should be min 2 mss %"U16_F"...\n", pcb->ssthresh, 2*pcb->mss));

+              pcb->ssthresh = 2*pcb->mss;

+            }

+

+            pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;

+            pcb->flags |= TF_INFR;

+          } else {

+            /* Inflate the congestion window, but not if it means that

+               the value overflows. */

+            if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {

+              pcb->cwnd += pcb->mss;

+            }

+          }

+        }

+      } else {

+        LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n",

+                                   pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge));

+      }

+    } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){

+      /* We come here when the ACK acknowledges new data. */

+

+      /* Reset the "IN Fast Retransmit" flag, since we are no longer

+         in fast retransmit. Also reset the congestion window to the

+         slow start threshold. */

+      if (pcb->flags & TF_INFR) {

+        pcb->flags &= ~TF_INFR;

+        pcb->cwnd = pcb->ssthresh;

+      }

+

+      /* Reset the number of retransmissions. */

+      pcb->nrtx = 0;

+

+      /* Reset the retransmission time-out. */

+      pcb->rto = (pcb->sa >> 3) + pcb->sv;

+

+      /* Update the send buffer space. Diff between the two can never exceed 64K? */

+      pcb->acked = (u16_t)(ackno - pcb->lastack);

+

+      pcb->snd_buf += pcb->acked;

+

+      /* Reset the fast retransmit variables. */

+      pcb->dupacks = 0;

+      pcb->lastack = ackno;

+

+      /* Update the congestion control variables (cwnd and

+         ssthresh). */

+      if (pcb->state >= ESTABLISHED) {

+        if (pcb->cwnd < pcb->ssthresh) {

+          if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {

+            pcb->cwnd += pcb->mss;

+          }

+          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));

+        } else {

+          u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);

+          if (new_cwnd > pcb->cwnd) {

+            pcb->cwnd = new_cwnd;

+          }

+          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));

+        }

+      }

+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",

+                                    ackno,

+                                    pcb->unacked != NULL?

+                                    ntohl(pcb->unacked->tcphdr->seqno): 0,

+                                    pcb->unacked != NULL?

+                                    ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));

+

+      /* Remove segment from the unacknowledged list if the incoming

+         ACK acknowlegdes them. */

+      while (pcb->unacked != NULL &&

+             TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +

+                         TCP_TCPLEN(pcb->unacked), ackno)) {

+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",

+                                      ntohl(pcb->unacked->tcphdr->seqno),

+                                      ntohl(pcb->unacked->tcphdr->seqno) +

+                                      TCP_TCPLEN(pcb->unacked)));

+

+        next = pcb->unacked;

+        pcb->unacked = pcb->unacked->next;

+

+        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));

+        LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));

+        pcb->snd_queuelen -= pbuf_clen(next->p);

+        tcp_seg_free(next);

+

+        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));

+        if (pcb->snd_queuelen != 0) {

+          LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||

+                      pcb->unsent != NULL);

+        }

+      }

+

+      /* If there's nothing left to acknowledge, stop the retransmit

+         timer, otherwise reset it to start again */

+      if(pcb->unacked == NULL)

+        pcb->rtime = -1;

+      else

+        pcb->rtime = 0;

+

+      pcb->polltmr = 0;

+    } else {

+      /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */

+      pcb->acked = 0;

+    }

+

+    /* We go through the ->unsent list to see if any of the segments

+       on the list are acknowledged by the ACK. This may seem

+       strange since an "unsent" segment shouldn't be acked. The

+       rationale is that lwIP puts all outstanding segments on the

+       ->unsent list after a retransmission, so these segments may

+       in fact have been sent once. */

+    while (pcb->unsent != NULL &&

+           /*TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), ackno) &&

+             TCP_SEQ_LEQ(ackno, pcb->snd_max)*/

+           TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), pcb->snd_max)

+           ) {

+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",

+                                    ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +

+                                    TCP_TCPLEN(pcb->unsent)));

+

+      next = pcb->unsent;

+      pcb->unsent = pcb->unsent->next;

+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));

+      LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));

+      pcb->snd_queuelen -= pbuf_clen(next->p);

+      tcp_seg_free(next);

+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));

+      if (pcb->snd_queuelen != 0) {

+        LWIP_ASSERT("tcp_receive: valid queue length",

+          pcb->unacked != NULL || pcb->unsent != NULL);

+      }

+

+      if (pcb->unsent != NULL) {

+        pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno);

+      }

+    }

+    /* End of ACK for new data processing. */

+

+    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",

+                                pcb->rttest, pcb->rtseq, ackno));

+

+    /* RTT estimation calculations. This is done by checking if the

+       incoming segment acknowledges the segment we use to take a

+       round-trip time measurement. */

+    if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {

+      /* diff between this shouldn't exceed 32K since this are tcp timer ticks

+         and a round-trip shouldn't be that long... */

+      m = (s16_t)(tcp_ticks - pcb->rttest);

+

+      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",

+                                  m, m * TCP_SLOW_INTERVAL));

+

+      /* This is taken directly from VJs original code in his paper */

+      m = m - (pcb->sa >> 3);

+      pcb->sa += m;

+      if (m < 0) {

+        m = -m;

+      }

+      m = m - (pcb->sv >> 2);

+      pcb->sv += m;

+      pcb->rto = (pcb->sa >> 3) + pcb->sv;

+

+      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n",

+                                  pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));

+

+      pcb->rttest = 0;

+    }

+  }

+

+  /* If the incoming segment contains data, we must process it

+     further. */

+  if (tcplen > 0) {

+    /* This code basically does three things:

+

+    +) If the incoming segment contains data that is the next

+    in-sequence data, this data is passed to the application. This

+    might involve trimming the first edge of the data. The rcv_nxt

+    variable and the advertised window are adjusted.

+

+    +) If the incoming segment has data that is above the next

+    sequence number expected (->rcv_nxt), the segment is placed on

+    the ->ooseq queue. This is done by finding the appropriate

+    place in the ->ooseq queue (which is ordered by sequence

+    number) and trim the segment in both ends if needed. An

+    immediate ACK is sent to indicate that we received an

+    out-of-sequence segment.

+

+    +) Finally, we check if the first segment on the ->ooseq queue

+    now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If

+    rcv_nxt > ooseq->seqno, we must trim the first edge of the

+    segment on ->ooseq before we adjust rcv_nxt. The data in the

+    segments that are now on sequence are chained onto the

+    incoming segment so that we only need to call the application

+    once.

+    */

+

+    /* First, we check if we must trim the first edge. We have to do

+       this if the sequence number of the incoming segment is less

+       than rcv_nxt, and the sequence number plus the length of the

+       segment is larger than rcv_nxt. */

+    /*    if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){

+          if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/

+    if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){

+      /* Trimming the first edge is done by pushing the payload

+         pointer in the pbuf downwards. This is somewhat tricky since

+         we do not want to discard the full contents of the pbuf up to

+         the new starting point of the data since we have to keep the

+         TCP header which is present in the first pbuf in the chain.

+

+         What is done is really quite a nasty hack: the first pbuf in

+         the pbuf chain is pointed to by inseg.p. Since we need to be

+         able to deallocate the whole pbuf, we cannot change this

+         inseg.p pointer to point to any of the later pbufs in the

+         chain. Instead, we point the ->payload pointer in the first

+         pbuf to data in one of the later pbufs. We also set the

+         inseg.data pointer to point to the right place. This way, the

+         ->p pointer will still point to the first pbuf, but the

+         ->p->payload pointer will point to data in another pbuf.

+

+         After we are done with adjusting the pbuf pointers we must

+         adjust the ->data pointer in the seg and the segment

+         length.*/

+

+      off = pcb->rcv_nxt - seqno;

+      p = inseg.p;

+      LWIP_ASSERT("inseg.p != NULL", inseg.p);

+      LWIP_ASSERT("insane offset!", (off < 0x7fff));

+      if (inseg.p->len < off) {

+        LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off));

+        new_tot_len = (u16_t)(inseg.p->tot_len - off);

+        while (p->len < off) {

+          off -= p->len;

+          /* KJM following line changed (with addition of new_tot_len var)

+             to fix bug #9076

+             inseg.p->tot_len -= p->len; */

+          p->tot_len = new_tot_len;

+          p->len = 0;

+          p = p->next;

+        }

+        if(pbuf_header(p, (s16_t)-off)) {

+          /* Do we need to cope with this failing?  Assert for now */

+          LWIP_ASSERT("pbuf_header failed", 0);

+        }

+      } else {

+        if(pbuf_header(inseg.p, (s16_t)-off)) {

+          /* Do we need to cope with this failing?  Assert for now */

+          LWIP_ASSERT("pbuf_header failed", 0);

+        }

+      }

+      /* KJM following line changed to use p->payload rather than inseg->p->payload

+         to fix bug #9076 */

+      inseg.dataptr = p->payload;

+      inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);

+      inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;

+    }

+    else {

+      if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){

+        /* the whole segment is < rcv_nxt */

+        /* must be a duplicate of a packet that has already been correctly handled */

+

+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));

+        tcp_ack_now(pcb);

+      }

+    }

+

+    /* The sequence number must be within the window (above rcv_nxt

+       and below rcv_nxt + rcv_wnd) in order to be further

+       processed. */

+    if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,

+                        pcb->rcv_nxt + pcb->rcv_ann_wnd - 1)){

+      if (pcb->rcv_nxt == seqno) {

+        accepted_inseq = 1;

+        /* The incoming segment is the next in sequence. We check if

+           we have to trim the end of the segment and update rcv_nxt

+           and pass the data to the application. */

+#if TCP_QUEUE_OOSEQ

+        if (pcb->ooseq != NULL &&

+                TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) {

+          if (pcb->ooseq->len > 0) {

+            /* We have to trim the second edge of the incoming

+               segment. */

+            inseg.len = (u16_t)(pcb->ooseq->tcphdr->seqno - seqno);

+            pbuf_realloc(inseg.p, inseg.len);

+          } else {

+            /* does the ooseq segment contain only flags that are in inseg also? */

+            if ((TCPH_FLAGS(inseg.tcphdr) & (TCP_FIN|TCP_SYN)) ==

+                (TCPH_FLAGS(pcb->ooseq->tcphdr) & (TCP_FIN|TCP_SYN))) {

+              struct tcp_seg *old_ooseq = pcb->ooseq;

+              pcb->ooseq = pcb->ooseq->next;

+              memp_free(MEMP_TCP_SEG, old_ooseq);

+            }

+          }

+        }

+#endif /* TCP_QUEUE_OOSEQ */

+

+        tcplen = TCP_TCPLEN(&inseg);

+

+        /* First received FIN will be ACKed +1, on any successive (duplicate)

+         * FINs we are already in CLOSE_WAIT and have already done +1.

+         */

+        if (pcb->state != CLOSE_WAIT) {

+          pcb->rcv_nxt += tcplen;

+        }

+

+        /* Update the receiver's (our) window. */

+        if (pcb->rcv_wnd < tcplen) {

+          pcb->rcv_wnd = 0;

+        } else {

+          pcb->rcv_wnd -= tcplen;

+        }

+

+        if (pcb->rcv_ann_wnd < tcplen) {

+          pcb->rcv_ann_wnd = 0;

+        } else {

+          pcb->rcv_ann_wnd -= tcplen;

+        }

+

+        /* If there is data in the segment, we make preparations to

+           pass this up to the application. The ->recv_data variable

+           is used for holding the pbuf that goes to the

+           application. The code for reassembling out-of-sequence data

+           chains its data on this pbuf as well.

+

+           If the segment was a FIN, we set the TF_GOT_FIN flag that will

+           be used to indicate to the application that the remote side has

+           closed its end of the connection. */

+        if (inseg.p->tot_len > 0) {

+          recv_data = inseg.p;

+          /* Since this pbuf now is the responsibility of the

+             application, we delete our reference to it so that we won't

+             (mistakingly) deallocate it. */

+          inseg.p = NULL;

+        }

+        if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {

+          LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));

+          recv_flags = TF_GOT_FIN;

+        }

+

+#if TCP_QUEUE_OOSEQ

+        /* We now check if we have segments on the ->ooseq queue that

+           is now in sequence. */

+        while (pcb->ooseq != NULL &&

+               pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {

+

+          cseg = pcb->ooseq;

+          seqno = pcb->ooseq->tcphdr->seqno;

+

+          pcb->rcv_nxt += TCP_TCPLEN(cseg);

+          if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {

+            pcb->rcv_wnd = 0;

+          } else {

+            pcb->rcv_wnd -= TCP_TCPLEN(cseg);

+          }

+          if (pcb->rcv_ann_wnd < TCP_TCPLEN(cseg)) {

+            pcb->rcv_ann_wnd = 0;

+          } else {

+            pcb->rcv_ann_wnd -= TCP_TCPLEN(cseg);

+          }

+

+          if (cseg->p->tot_len > 0) {

+            /* Chain this pbuf onto the pbuf that we will pass to

+               the application. */

+            if (recv_data) {

+              pbuf_cat(recv_data, cseg->p);

+            } else {

+              recv_data = cseg->p;

+            }

+            cseg->p = NULL;

+          }

+          if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {

+            LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));

+            recv_flags = TF_GOT_FIN;

+            if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */

+              pcb->state = CLOSE_WAIT;

+            }

+          }

+

+

+          pcb->ooseq = cseg->next;

+          tcp_seg_free(cseg);

+        }

+#endif /* TCP_QUEUE_OOSEQ */

+

+

+        /* Acknowledge the segment(s). */

+        tcp_ack(pcb);

+

+      } else {

+        /* We get here if the incoming segment is out-of-sequence. */

+        tcp_ack_now(pcb);

+#if TCP_QUEUE_OOSEQ

+        /* We queue the segment on the ->ooseq queue. */

+        if (pcb->ooseq == NULL) {

+          pcb->ooseq = tcp_seg_copy(&inseg);

+        } else {

+          /* If the queue is not empty, we walk through the queue and

+             try to find a place where the sequence number of the

+             incoming segment is between the sequence numbers of the

+             previous and the next segment on the ->ooseq queue. That is

+             the place where we put the incoming segment. If needed, we

+             trim the second edges of the previous and the incoming

+             segment so that it will fit into the sequence.

+

+             If the incoming segment has the same sequence number as a

+             segment on the ->ooseq queue, we discard the segment that

+             contains less data. */

+

+          prev = NULL;

+          for(next = pcb->ooseq; next != NULL; next = next->next) {

+            if (seqno == next->tcphdr->seqno) {

+              /* The sequence number of the incoming segment is the

+                 same as the sequence number of the segment on

+                 ->ooseq. We check the lengths to see which one to

+                 discard. */

+              if (inseg.len > next->len) {

+                /* The incoming segment is larger than the old

+                   segment. We replace the old segment with the new

+                   one. */

+                cseg = tcp_seg_copy(&inseg);

+                if (cseg != NULL) {

+                  cseg->next = next->next;

+                  if (prev != NULL) {

+                    prev->next = cseg;

+                  } else {

+                    pcb->ooseq = cseg;

+                  }

+                }

+                tcp_seg_free(next);

+                if (cseg->next != NULL) {

+                  next = cseg->next;

+                  if (TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {

+                    /* We need to trim the incoming segment. */

+                    cseg->len = (u16_t)(next->tcphdr->seqno - seqno);

+                    pbuf_realloc(cseg->p, cseg->len);

+                  }

+                }

+                break;

+              } else {

+                /* Either the lenghts are the same or the incoming

+                   segment was smaller than the old one; in either

+                   case, we ditch the incoming segment. */

+                break;

+              }

+            } else {

+              if (prev == NULL) {

+                if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {

+                  /* The sequence number of the incoming segment is lower

+                     than the sequence number of the first segment on the

+                     queue. We put the incoming segment first on the

+                     queue. */

+

+                  if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {

+                    /* We need to trim the incoming segment. */

+                    inseg.len = (u16_t)(next->tcphdr->seqno - seqno);

+                    pbuf_realloc(inseg.p, inseg.len);

+                  }

+                  cseg = tcp_seg_copy(&inseg);

+                  if (cseg != NULL) {

+                    cseg->next = next;

+                    pcb->ooseq = cseg;

+                  }

+                  break;

+                }

+              } else

+                /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&

+                  TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/

+                if(TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)){

+                /* The sequence number of the incoming segment is in

+                   between the sequence numbers of the previous and

+                   the next segment on ->ooseq. We trim and insert the

+                   incoming segment and trim the previous segment, if

+                   needed. */

+                if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {

+                  /* We need to trim the incoming segment. */

+                  inseg.len = (u16_t)(next->tcphdr->seqno - seqno);

+                  pbuf_realloc(inseg.p, inseg.len);

+                }

+

+                cseg = tcp_seg_copy(&inseg);

+                if (cseg != NULL) {

+                  cseg->next = next;

+                  prev->next = cseg;

+                  if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {

+                    /* We need to trim the prev segment. */

+                    prev->len = (u16_t)(seqno - prev->tcphdr->seqno);

+                    pbuf_realloc(prev->p, prev->len);

+                  }

+                }

+                break;

+              }

+              /* If the "next" segment is the last segment on the

+                 ooseq queue, we add the incoming segment to the end

+                 of the list. */

+              if (next->next == NULL &&

+                  TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {

+                next->next = tcp_seg_copy(&inseg);

+                if (next->next != NULL) {

+                  if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {

+                    /* We need to trim the last segment. */

+                    next->len = (u16_t)(seqno - next->tcphdr->seqno);

+                    pbuf_realloc(next->p, next->len);

+                  }

+                }

+                break;

+              }

+            }

+            prev = next;

+          }

+        }

+#endif /* TCP_QUEUE_OOSEQ */

+

+      }

+    } else {

+      if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,

+                          pcb->rcv_nxt + pcb->rcv_ann_wnd-1)){

+        tcp_ack_now(pcb);

+      }

+    }

+  } else {

+    /* Segments with length 0 is taken care of here. Segments that

+       fall out of the window are ACKed. */

+    /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||

+      TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/

+    if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){

+      tcp_ack_now(pcb);

+    }

+  }

+  return accepted_inseq;

+}

+

+/**

+ * Parses the options contained in the incoming segment. (Code taken

+ * from uIP with only small changes.)

+ *

+ * Called from tcp_listen_input() and tcp_process().

+ * Currently, only the MSS option is supported!

+ *

+ * @param pcb the tcp_pcb for which a segment arrived

+ */

+static void

+tcp_parseopt(struct tcp_pcb *pcb)

+{

+  u8_t c;

+  u8_t *opts, opt;

+  u16_t mss;

+

+  opts = (u8_t *)tcphdr + TCP_HLEN;

+

+  /* Parse the TCP MSS option, if present. */

+  if(TCPH_HDRLEN(tcphdr) > 0x5) {

+    for(c = 0; c < (TCPH_HDRLEN(tcphdr) - 5) << 2 ;) {

+      opt = opts[c];

+      if (opt == 0x00) {

+        /* End of options. */

+        break;

+      } else if (opt == 0x01) {

+        ++c;

+        /* NOP option. */

+      } else if (opt == 0x02 &&

+        opts[c + 1] == 0x04) {

+        /* An MSS option with the right option length. */

+        mss = (opts[c + 2] << 8) | opts[c + 3];

+        pcb->mss = mss > TCP_MSS? TCP_MSS: mss;

+

+        /* And we are done processing options. */

+        break;

+      } else {

+        if (opts[c + 1] == 0) {

+          /* If the length field is zero, the options are malformed

+             and we don't process them further. */

+          break;

+        }

+        /* All other options have a length field, so that we easily

+           can skip past them. */

+        c += opts[c + 1];

+      }

+    }

+  }

+}

+

+#endif /* LWIP_TCP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/tcp_out.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/tcp_out.c
new file mode 100644
index 0000000..a116d3c
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/tcp_out.c
@@ -0,0 +1,953 @@
+/**

+ * @file

+ * Transmission Control Protocol, outgoing traffic

+ *

+ * The output functions of TCP.

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/tcp.h"

+#include "lwip/def.h"

+#include "lwip/mem.h"

+#include "lwip/memp.h"

+#include "lwip/sys.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/inet.h"

+#include "lwip/inet_chksum.h"

+#include "lwip/stats.h"

+#include "lwip/snmp.h"

+

+#include <string.h>

+

+/* Forward declarations.*/

+static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);

+

+/**

+ * Called by tcp_close() to send a segment including flags but not data.

+ *

+ * @param pcb the tcp_pcb over which to send a segment

+ * @param flags the flags to set in the segment header

+ * @return ERR_OK if sent, another err_t otherwise

+ */

+err_t

+tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)

+{

+  /* no data, no length, flags, copy=1, no optdata, no optdatalen */

+  return tcp_enqueue(pcb, NULL, 0, flags, TCP_WRITE_FLAG_COPY, NULL, 0);

+}

+

+/**

+ * Write data for sending (but does not send it immediately).

+ *

+ * It waits in the expectation of more data being sent soon (as

+ * it can send them more efficiently by combining them together).

+ * To prompt the system to send data now, call tcp_output() after

+ * calling tcp_write().

+ *

+ * @param pcb Protocol control block of the TCP connection to enqueue data for.

+ * @param data pointer to the data to send

+ * @param len length (in bytes) of the data to send

+ * @param apiflags combination of following flags :

+ * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack

+ * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent,

+ * @return ERR_OK if enqueued, another err_t on error

+ *

+ * @see tcp_write()

+ */

+err_t

+tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags)

+{

+  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", (void *)pcb,

+    data, len, (u16_t)apiflags));

+  /* connection is in valid state for data transmission? */

+  if (pcb->state == ESTABLISHED ||

+     pcb->state == CLOSE_WAIT ||

+     pcb->state == SYN_SENT ||

+     pcb->state == SYN_RCVD) {

+    if (len > 0) {

+      return tcp_enqueue(pcb, (void *)data, len, 0, apiflags, NULL, 0);

+    }

+    return ERR_OK;

+  } else {

+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | 3, ("tcp_write() called in invalid state\n"));

+    return ERR_CONN;

+  }

+}

+

+/**

+ * Enqueue either data or TCP options (but not both) for tranmission

+ *

+ * Called by tcp_connect(), tcp_listen_input(), tcp_send_ctrl() and tcp_write().

+ *

+ * @param pcb Protocol control block for the TCP connection to enqueue data for.

+ * @param arg Pointer to the data to be enqueued for sending.

+ * @param len Data length in bytes

+ * @param flags tcp header flags to set in the outgoing segment

+ * @param apiflags combination of following flags :

+ * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack

+ * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent,

+ * @param optdata

+ * @param optlen

+ */

+err_t

+tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,

+  u8_t flags, u8_t apiflags,

+  u8_t *optdata, u8_t optlen)

+{

+  struct pbuf *p;

+  struct tcp_seg *seg, *useg, *queue;

+  u32_t seqno;

+  u16_t left, seglen;

+  void *ptr;

+  u16_t queuelen;

+

+  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", apiflags=%"U16_F")\n",

+    (void *)pcb, arg, len, (u16_t)flags, (u16_t)apiflags));

+  LWIP_ERROR("tcp_enqueue: len == 0 || optlen == 0 (programmer violates API)",

+      ((len == 0) || (optlen == 0)), return ERR_ARG;);

+  LWIP_ERROR("tcp_enqueue: arg == NULL || optdata == NULL (programmer violates API)",

+      ((arg == NULL) || (optdata == NULL)), return ERR_ARG;);

+  /* fail on too much data */

+  if (len > pcb->snd_buf) {

+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf));

+    pcb->flags |= TF_NAGLEMEMERR;

+    return ERR_MEM;

+  }

+  left = len;

+  ptr = arg;

+

+  /* seqno will be the sequence number of the first segment enqueued

+   * by the call to this function. */

+  seqno = pcb->snd_lbb;

+

+  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));

+

+  /* If total number of pbufs on the unsent/unacked queues exceeds the

+   * configured maximum, return an error */

+  queuelen = pcb->snd_queuelen;

+  /* check for configured max queuelen and possible overflow */

+  if ((queuelen >= TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {

+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %"U16_F" (max %"U16_F")\n", queuelen, TCP_SND_QUEUELEN));

+    TCP_STATS_INC(tcp.memerr);

+    pcb->flags |= TF_NAGLEMEMERR;

+    return ERR_MEM;

+  }

+  if (queuelen != 0) {

+    LWIP_ASSERT("tcp_enqueue: pbufs on queue => at least one queue non-empty",

+      pcb->unacked != NULL || pcb->unsent != NULL);

+  } else {

+    LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty",

+      pcb->unacked == NULL && pcb->unsent == NULL);

+  }

+

+  /* First, break up the data into segments and tuck them together in

+   * the local "queue" variable. */

+  useg = queue = seg = NULL;

+  seglen = 0;

+  while (queue == NULL || left > 0) {

+

+    /* The segment length should be the MSS if the data to be enqueued

+     * is larger than the MSS. */

+    seglen = left > pcb->mss? pcb->mss: left;

+

+    /* Allocate memory for tcp_seg, and fill in fields. */

+    seg = memp_malloc(MEMP_TCP_SEG);

+    if (seg == NULL) {

+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for tcp_seg\n"));

+      goto memerr;

+    }

+    seg->next = NULL;

+    seg->p = NULL;

+

+    /* first segment of to-be-queued data? */

+    if (queue == NULL) {

+      queue = seg;

+    }

+    /* subsequent segments of to-be-queued data */

+    else {

+      /* Attach the segment to the end of the queued segments */

+      LWIP_ASSERT("useg != NULL", useg != NULL);

+      useg->next = seg;

+    }

+    /* remember last segment of to-be-queued data for next iteration */

+    useg = seg;

+

+    /* If copy is set, memory should be allocated

+     * and data copied into pbuf, otherwise data comes from

+     * ROM or other static memory, and need not be copied. If

+     * optdata is != NULL, we have options instead of data. */

+

+    /* options? */

+    if (optdata != NULL) {

+      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {

+        goto memerr;

+      }

+      LWIP_ASSERT("check that first pbuf can hold optlen",

+                  (seg->p->len >= optlen));

+      queuelen += pbuf_clen(seg->p);

+      seg->dataptr = seg->p->payload;

+    }

+    /* copy from volatile memory? */

+    else if (apiflags & TCP_WRITE_FLAG_COPY) {

+      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {

+        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));

+        goto memerr;

+      }

+      LWIP_ASSERT("check that first pbuf can hold the complete seglen",

+                  (seg->p->len >= seglen));

+      queuelen += pbuf_clen(seg->p);

+      if (arg != NULL) {

+        MEMCPY(seg->p->payload, ptr, seglen);

+      }

+      seg->dataptr = seg->p->payload;

+    }

+    /* do not copy data */

+    else {

+      /* First, allocate a pbuf for holding the data.

+       * since the referenced data is available at least until it is sent out on the

+       * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM

+       * instead of PBUF_REF here.

+       */

+      if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {

+        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n"));

+        goto memerr;

+      }

+      ++queuelen;

+      /* reference the non-volatile payload data */

+      p->payload = ptr;

+      seg->dataptr = ptr;

+

+      /* Second, allocate a pbuf for the headers. */

+      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) {

+        /* If allocation fails, we have to deallocate the data pbuf as

+         * well. */

+        pbuf_free(p);

+        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for header pbuf\n"));

+        goto memerr;

+      }

+      queuelen += pbuf_clen(seg->p);

+

+      /* Concatenate the headers and data pbufs together. */

+      pbuf_cat(seg->p/*header*/, p/*data*/);

+      p = NULL;

+    }

+

+    /* Now that there are more segments queued, we check again if the

+    length of the queue exceeds the configured maximum or overflows. */

+    if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {

+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));

+      goto memerr;

+    }

+

+    seg->len = seglen;

+

+    /* build TCP header */

+    if (pbuf_header(seg->p, TCP_HLEN)) {

+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n"));

+      TCP_STATS_INC(tcp.err);

+      goto memerr;

+    }

+    seg->tcphdr = seg->p->payload;

+    seg->tcphdr->src = htons(pcb->local_port);

+    seg->tcphdr->dest = htons(pcb->remote_port);

+    seg->tcphdr->seqno = htonl(seqno);

+    seg->tcphdr->urgp = 0;

+    TCPH_FLAGS_SET(seg->tcphdr, flags);

+    /* don't fill in tcphdr->ackno and tcphdr->wnd until later */

+

+    /* Copy the options into the header, if they are present. */

+    if (optdata == NULL) {

+      TCPH_HDRLEN_SET(seg->tcphdr, 5);

+    }

+    else {

+      TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4));

+      /* Copy options into data portion of segment.

+       Options can thus only be sent in non data carrying

+       segments such as SYN|ACK. */

+      SMEMCPY(seg->dataptr, optdata, optlen);

+    }

+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_enqueue: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",

+      ntohl(seg->tcphdr->seqno),

+      ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),

+      (u16_t)flags));

+

+    left -= seglen;

+    seqno += seglen;

+    ptr = (void *)((u8_t *)ptr + seglen);

+  }

+

+  /* Now that the data to be enqueued has been broken up into TCP

+  segments in the queue variable, we add them to the end of the

+  pcb->unsent queue. */

+  if (pcb->unsent == NULL) {

+    useg = NULL;

+  }

+  else {

+    for (useg = pcb->unsent; useg->next != NULL; useg = useg->next){}

+  }

+  /* { useg is last segment on the unsent queue, NULL if list is empty } */

+

+  /* If there is room in the last pbuf on the unsent queue,

+  chain the first pbuf on the queue together with that. */

+  if (useg != NULL &&

+    TCP_TCPLEN(useg) != 0 &&

+    !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&

+    !(flags & (TCP_SYN | TCP_FIN)) &&

+    /* fit within max seg size */

+    useg->len + queue->len <= pcb->mss) {

+    /* Remove TCP header from first segment of our to-be-queued list */

+    if(pbuf_header(queue->p, -TCP_HLEN)) {

+      /* Can we cope with this failing?  Just assert for now */

+      LWIP_ASSERT("pbuf_header failed\n", 0);

+      TCP_STATS_INC(tcp.err);

+      goto memerr;

+    }

+    pbuf_cat(useg->p, queue->p);

+    useg->len += queue->len;

+    useg->next = queue->next;

+

+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("tcp_enqueue: chaining segments, new len %"U16_F"\n", useg->len));

+    if (seg == queue) {

+      seg = NULL;

+    }

+    memp_free(MEMP_TCP_SEG, queue);

+  }

+  else {

+    /* empty list */

+    if (useg == NULL) {

+      /* initialize list with this segment */

+      pcb->unsent = queue;

+    }

+    /* enqueue segment */

+    else {

+      useg->next = queue;

+    }

+  }

+  if ((flags & TCP_SYN) || (flags & TCP_FIN)) {

+    ++len;

+  }

+  if (flags & TCP_FIN) {

+    pcb->flags |= TF_FIN;

+  }

+  pcb->snd_lbb += len;

+

+  pcb->snd_buf -= len;

+

+  /* update number of segments on the queues */

+  pcb->snd_queuelen = queuelen;

+  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %"S16_F" (after enqueued)\n", pcb->snd_queuelen));

+  if (pcb->snd_queuelen != 0) {

+    LWIP_ASSERT("tcp_enqueue: valid queue length",

+      pcb->unacked != NULL || pcb->unsent != NULL);

+  }

+

+  /* Set the PSH flag in the last segment that we enqueued, but only

+  if the segment has data (indicated by seglen > 0). */

+  if (seg != NULL && seglen > 0 && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) {

+    TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);

+  }

+

+  return ERR_OK;

+memerr:

+  pcb->flags |= TF_NAGLEMEMERR;

+  TCP_STATS_INC(tcp.memerr);

+

+  if (queue != NULL) {

+    tcp_segs_free(queue);

+  }

+  if (pcb->snd_queuelen != 0) {

+    LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||

+      pcb->unsent != NULL);

+  }

+  LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_enqueue: %"S16_F" (with mem err)\n", pcb->snd_queuelen));

+  return ERR_MEM;

+}

+

+/**

+ * Find out what we can send and send it

+ *

+ * @param pcb Protocol control block for the TCP connection to send data

+ * @return ERR_OK if data has been sent or nothing to send

+ *         another err_t on error

+ */

+err_t

+tcp_output(struct tcp_pcb *pcb)

+{

+  struct pbuf *p;

+  struct tcp_hdr *tcphdr;

+  struct tcp_seg *seg, *useg;

+  u32_t wnd;

+#if TCP_CWND_DEBUG

+  s16_t i = 0;

+#endif /* TCP_CWND_DEBUG */

+

+  /* First, check if we are invoked by the TCP input processing

+     code. If so, we do not output anything. Instead, we rely on the

+     input processing code to call us when input processing is done

+     with. */

+  if (tcp_input_pcb == pcb) {

+    return ERR_OK;

+  }

+

+  wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);

+

+  seg = pcb->unsent;

+

+  /* useg should point to last segment on unacked queue */

+  useg = pcb->unacked;

+  if (useg != NULL) {

+    for (; useg->next != NULL; useg = useg->next){}

+  }

+

+  /* If the TF_ACK_NOW flag is set and no data will be sent (either

+   * because the ->unsent queue is empty or because the window does

+   * not allow it), construct an empty ACK segment and send it.

+   *

+   * If data is to be sent, we will just piggyback the ACK (see below).

+   */

+  if (pcb->flags & TF_ACK_NOW &&

+     (seg == NULL ||

+      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {

+    p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);

+    if (p == NULL) {

+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));

+      return ERR_BUF;

+    }

+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));

+    /* remove ACK flags from the PCB, as we send an empty ACK now */

+    pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);

+

+    tcphdr = p->payload;

+    tcphdr->src = htons(pcb->local_port);

+    tcphdr->dest = htons(pcb->remote_port);

+    tcphdr->seqno = htonl(pcb->snd_nxt);

+    tcphdr->ackno = htonl(pcb->rcv_nxt);

+    TCPH_FLAGS_SET(tcphdr, TCP_ACK);

+    tcphdr->wnd = htons(pcb->rcv_ann_wnd);

+    tcphdr->urgp = 0;

+    TCPH_HDRLEN_SET(tcphdr, 5);

+

+    tcphdr->chksum = 0;

+#if CHECKSUM_GEN_TCP

+    tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),

+          IP_PROTO_TCP, p->tot_len);

+#endif

+#if LWIP_NETIF_HWADDRHINT

+    {

+      struct netif *netif;

+      netif = ip_route(&pcb->remote_ip);

+      if(netif != NULL){

+        netif->addr_hint = &(pcb->addr_hint);

+        ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,

+                     pcb->tos, IP_PROTO_TCP, netif);

+        netif->addr_hint = NULL;

+      }

+    }

+#else /* LWIP_NETIF_HWADDRHINT*/

+    ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,

+        IP_PROTO_TCP);

+#endif /* LWIP_NETIF_HWADDRHINT*/

+    pbuf_free(p);

+

+    return ERR_OK;

+  }

+

+#if TCP_OUTPUT_DEBUG

+  if (seg == NULL) {

+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n",

+                                   (void*)pcb->unsent));

+  }

+#endif /* TCP_OUTPUT_DEBUG */

+#if TCP_CWND_DEBUG

+  if (seg == NULL) {

+    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F

+                                 ", cwnd %"U16_F", wnd %"U32_F

+                                 ", seg == NULL, ack %"U32_F"\n",

+                                 pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));

+  } else {

+    LWIP_DEBUGF(TCP_CWND_DEBUG,

+                ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F

+                 ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",

+                 pcb->snd_wnd, pcb->cwnd, wnd,

+                 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,

+                 ntohl(seg->tcphdr->seqno), pcb->lastack));

+  }

+#endif /* TCP_CWND_DEBUG */

+  /* data available and window allows it to be sent? */

+  while (seg != NULL &&

+         ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {

+    LWIP_ASSERT("RST not expected here!",

+                (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);

+    /* Stop sending if the nagle algorithm would prevent it

+     * Don't stop:

+     * - if tcp_enqueue had a memory error before (prevent delayed ACK timeout) or

+     * - if FIN was already enqueued for this PCB (SYN is always alone in a segment -

+     *   either seg->next != NULL or pcb->unacked == NULL;

+     *   RST is no sent using tcp_enqueue/tcp_output.

+     */

+    if((tcp_do_output_nagle(pcb) == 0) &&

+      ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){

+      break;

+    }

+#if TCP_CWND_DEBUG

+    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",

+                            pcb->snd_wnd, pcb->cwnd, wnd,

+                            ntohl(seg->tcphdr->seqno) + seg->len -

+                            pcb->lastack,

+                            ntohl(seg->tcphdr->seqno), pcb->lastack, i));

+    ++i;

+#endif /* TCP_CWND_DEBUG */

+

+    pcb->unsent = seg->next;

+

+    if (pcb->state != SYN_SENT) {

+      TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);

+      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);

+    }

+

+    tcp_output_segment(seg, pcb);

+    pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);

+    if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) {

+      pcb->snd_max = pcb->snd_nxt;

+    }

+    /* put segment on unacknowledged list if length > 0 */

+    if (TCP_TCPLEN(seg) > 0) {

+      seg->next = NULL;

+      /* unacked list is empty? */

+      if (pcb->unacked == NULL) {

+        pcb->unacked = seg;

+        useg = seg;

+      /* unacked list is not empty? */

+      } else {

+        /* In the case of fast retransmit, the packet should not go to the tail

+         * of the unacked queue, but rather at the head. We need to check for

+         * this case. -STJ Jul 27, 2004 */

+        if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){

+          /* add segment to head of unacked list */

+          seg->next = pcb->unacked;

+          pcb->unacked = seg;

+        } else {

+          /* add segment to tail of unacked list */

+          useg->next = seg;

+          useg = useg->next;

+        }

+      }

+    /* do not queue empty segments on the unacked list */

+    } else {

+      tcp_seg_free(seg);

+    }

+    seg = pcb->unsent;

+  }

+

+  if (seg != NULL && pcb->persist_backoff == 0 &&

+      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) {

+    /* prepare for persist timer */

+    pcb->persist_cnt = 0;

+    pcb->persist_backoff = 1;

+  }

+

+  pcb->flags &= ~TF_NAGLEMEMERR;

+  return ERR_OK;

+}

+

+/**

+ * Called by tcp_output() to actually send a TCP segment over IP.

+ *

+ * @param seg the tcp_seg to send

+ * @param pcb the tcp_pcb for the TCP connection used to send the segment

+ */

+static void

+tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)

+{

+  u16_t len;

+  struct netif *netif;

+

+  /** @bug Exclude retransmitted segments from this count. */

+  snmp_inc_tcpoutsegs();

+

+  /* The TCP header has already been constructed, but the ackno and

+   wnd fields remain. */

+  seg->tcphdr->ackno = htonl(pcb->rcv_nxt);

+

+  /* advertise our receive window size in this TCP segment */

+  seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);

+

+  /* If we don't have a local IP address, we get one by

+     calling ip_route(). */

+  if (ip_addr_isany(&(pcb->local_ip))) {

+    netif = ip_route(&(pcb->remote_ip));

+    if (netif == NULL) {

+      return;

+    }

+    ip_addr_set(&(pcb->local_ip), &(netif->ip_addr));

+  }

+

+  /* Set retransmission timer running if it is not currently enabled */

+  if(pcb->rtime == -1)

+    pcb->rtime = 0;

+

+  if (pcb->rttest == 0) {

+    pcb->rttest = tcp_ticks;

+    pcb->rtseq = ntohl(seg->tcphdr->seqno);

+

+    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));

+  }

+  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",

+          htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +

+          seg->len));

+

+  len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);

+

+  seg->p->len -= len;

+  seg->p->tot_len -= len;

+

+  seg->p->payload = seg->tcphdr;

+

+  seg->tcphdr->chksum = 0;

+#if CHECKSUM_GEN_TCP

+  seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,

+             &(pcb->local_ip),

+             &(pcb->remote_ip),

+             IP_PROTO_TCP, seg->p->tot_len);

+#endif

+  TCP_STATS_INC(tcp.xmit);

+

+#if LWIP_NETIF_HWADDRHINT

+  {

+    struct netif *netif;

+    netif = ip_route(&pcb->remote_ip);

+    if(netif != NULL){

+      netif->addr_hint = &(pcb->addr_hint);

+      ip_output_if(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,

+                   pcb->tos, IP_PROTO_TCP, netif);

+      netif->addr_hint = NULL;

+    }

+  }

+#else /* LWIP_NETIF_HWADDRHINT*/

+  ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,

+      IP_PROTO_TCP);

+#endif /* LWIP_NETIF_HWADDRHINT*/

+}

+

+/**

+ * Send a TCP RESET packet (empty segment with RST flag set) either to

+ * abort a connection or to show that there is no matching local connection

+ * for a received segment.

+ *

+ * Called by tcp_abort() (to abort a local connection), tcp_input() (if no

+ * matching local pcb was found), tcp_listen_input() (if incoming segment

+ * has ACK flag set) and tcp_process() (received segment in the wrong state)

+ *

+ * Since a RST segment is in most cases not sent for an active connection,

+ * tcp_rst() has a number of arguments that are taken from a tcp_pcb for

+ * most other segment output functions.

+ *

+ * @param seqno the sequence number to use for the outgoing segment

+ * @param ackno the acknowledge number to use for the outgoing segment

+ * @param local_ip the local IP address to send the segment from

+ * @param remote_ip the remote IP address to send the segment to

+ * @param local_port the local TCP port to send the segment from

+ * @param remote_port the remote TCP port to send the segment to

+ */

+void

+tcp_rst(u32_t seqno, u32_t ackno,

+  struct ip_addr *local_ip, struct ip_addr *remote_ip,

+  u16_t local_port, u16_t remote_port)

+{

+  struct pbuf *p;

+  struct tcp_hdr *tcphdr;

+  p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);

+  if (p == NULL) {

+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));

+      return;

+  }

+  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",

+              (p->len >= sizeof(struct tcp_hdr)));

+

+  tcphdr = p->payload;

+  tcphdr->src = htons(local_port);

+  tcphdr->dest = htons(remote_port);

+  tcphdr->seqno = htonl(seqno);

+  tcphdr->ackno = htonl(ackno);

+  TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK);

+  tcphdr->wnd = htons(TCP_WND);

+  tcphdr->urgp = 0;

+  TCPH_HDRLEN_SET(tcphdr, 5);

+

+  tcphdr->chksum = 0;

+#if CHECKSUM_GEN_TCP

+  tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,

+              IP_PROTO_TCP, p->tot_len);

+#endif

+  TCP_STATS_INC(tcp.xmit);

+  snmp_inc_tcpoutrsts();

+   /* Send output with hardcoded TTL since we have no access to the pcb */

+  ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);

+  pbuf_free(p);

+  LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));

+}

+

+/**

+ * Requeue all unacked segments for retransmission

+ *

+ * Called by tcp_slowtmr() for slow retransmission.

+ *

+ * @param pcb the tcp_pcb for which to re-enqueue all unacked segments

+ */

+void

+tcp_rexmit_rto(struct tcp_pcb *pcb)

+{

+  struct tcp_seg *seg;

+

+  if (pcb->unacked == NULL) {

+    return;

+  }

+

+  /* Move all unacked segments to the head of the unsent queue */

+  for (seg = pcb->unacked; seg->next != NULL; seg = seg->next){}

+  /* concatenate unsent queue after unacked queue */

+  seg->next = pcb->unsent;

+  /* unsent queue is the concatenated queue (of unacked, unsent) */

+  pcb->unsent = pcb->unacked;

+  /* unacked queue is now empty */

+  pcb->unacked = NULL;

+

+  pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);

+  /* increment number of retransmissions */

+  ++pcb->nrtx;

+

+  /* Don't take any RTT measurements after retransmitting. */

+  pcb->rttest = 0;

+

+  /* Do the actual retransmission */

+  tcp_output(pcb);

+}

+

+/**

+ * Requeue the first unacked segment for retransmission

+ *

+ * Called by tcp_receive() for fast retramsmit.

+ *

+ * @param pcb the tcp_pcb for which to retransmit the first unacked segment

+ */

+void

+tcp_rexmit(struct tcp_pcb *pcb)

+{

+  struct tcp_seg *seg;

+

+  if (pcb->unacked == NULL) {

+    return;

+  }

+

+  /* Move the first unacked segment to the unsent queue */

+  seg = pcb->unacked->next;

+  pcb->unacked->next = pcb->unsent;

+  pcb->unsent = pcb->unacked;

+  pcb->unacked = seg;

+

+  pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);

+

+  ++pcb->nrtx;

+

+  /* Don't take any rtt measurements after retransmitting. */

+  pcb->rttest = 0;

+

+  /* Do the actual retransmission. */

+  snmp_inc_tcpretranssegs();

+  tcp_output(pcb);

+}

+

+/**

+ * Send keepalive packets to keep a connection active although

+ * no data is sent over it.

+ *

+ * Called by tcp_slowtmr()

+ *

+ * @param pcb the tcp_pcb for which to send a keepalive packet

+ */

+void

+tcp_keepalive(struct tcp_pcb *pcb)

+{

+  struct pbuf *p;

+  struct tcp_hdr *tcphdr;

+

+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",

+                          ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),

+                          ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));

+

+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F"   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",

+                          tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));

+

+  p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);

+

+  if(p == NULL) {

+    LWIP_DEBUGF(TCP_DEBUG,

+                ("tcp_keepalive: could not allocate memory for pbuf\n"));

+    return;

+  }

+  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",

+              (p->len >= sizeof(struct tcp_hdr)));

+

+  tcphdr = p->payload;

+  tcphdr->src = htons(pcb->local_port);

+  tcphdr->dest = htons(pcb->remote_port);

+  tcphdr->seqno = htonl(pcb->snd_nxt - 1);

+  tcphdr->ackno = htonl(pcb->rcv_nxt);

+  TCPH_FLAGS_SET(tcphdr, 0);

+  tcphdr->wnd = htons(pcb->rcv_ann_wnd);

+  tcphdr->urgp = 0;

+  TCPH_HDRLEN_SET(tcphdr, 5);

+

+  tcphdr->chksum = 0;

+#if CHECKSUM_GEN_TCP

+  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,

+                                      IP_PROTO_TCP, p->tot_len);

+#endif

+  TCP_STATS_INC(tcp.xmit);

+

+  /* Send output to IP */

+#if LWIP_NETIF_HWADDRHINT

+  {

+    struct netif *netif;

+    netif = ip_route(&pcb->remote_ip);

+    if(netif != NULL){

+      netif->addr_hint = &(pcb->addr_hint);

+      ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,

+                   0, IP_PROTO_TCP, netif);

+      netif->addr_hint = NULL;

+    }

+  }

+#else /* LWIP_NETIF_HWADDRHINT*/

+  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);

+#endif /* LWIP_NETIF_HWADDRHINT*/

+

+  pbuf_free(p);

+

+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n",

+                          pcb->snd_nxt - 1, pcb->rcv_nxt));

+}

+

+

+/**

+ * Send persist timer zero-window probes to keep a connection active

+ * when a window update is lost.

+ *

+ * Called by tcp_slowtmr()

+ *

+ * @param pcb the tcp_pcb for which to send a zero-window probe packet

+ */

+void

+tcp_zero_window_probe(struct tcp_pcb *pcb)

+{

+  struct pbuf *p;

+  struct tcp_hdr *tcphdr;

+  struct tcp_seg *seg;

+

+  LWIP_DEBUGF(TCP_DEBUG,

+              ("tcp_zero_window_probe: sending ZERO WINDOW probe to %"

+               U16_F".%"U16_F".%"U16_F".%"U16_F"\n",

+               ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),

+               ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));

+

+  LWIP_DEBUGF(TCP_DEBUG,

+              ("tcp_zero_window_probe: tcp_ticks %"U32_F

+               "   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",

+               tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));

+

+  seg = pcb->unacked;

+

+  if(seg == NULL)

+    seg = pcb->unsent;

+

+  if(seg == NULL)

+    return;

+

+  p = pbuf_alloc(PBUF_IP, TCP_HLEN + 1, PBUF_RAM);

+

+  if(p == NULL) {

+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));

+    return;

+  }

+  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",

+              (p->len >= sizeof(struct tcp_hdr)));

+

+  tcphdr = p->payload;

+  tcphdr->src = htons(pcb->local_port);

+  tcphdr->dest = htons(pcb->remote_port);

+  tcphdr->seqno = seg->tcphdr->seqno;

+  tcphdr->ackno = htonl(pcb->rcv_nxt);

+  TCPH_FLAGS_SET(tcphdr, 0);

+  tcphdr->wnd = htons(pcb->rcv_ann_wnd);

+  tcphdr->urgp = 0;

+  TCPH_HDRLEN_SET(tcphdr, 5);

+

+  /* Copy in one byte from the head of the unacked queue */

+  *((char *)p->payload + sizeof(struct tcp_hdr)) = *(char *)seg->dataptr;

+

+  tcphdr->chksum = 0;

+#if CHECKSUM_GEN_TCP

+  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,

+                                      IP_PROTO_TCP, p->tot_len);

+#endif

+  TCP_STATS_INC(tcp.xmit);

+

+  /* Send output to IP */

+#if LWIP_NETIF_HWADDRHINT

+  {

+    struct netif *netif;

+    netif = ip_route(&pcb->remote_ip);

+    if(netif != NULL){

+      netif->addr_hint = &(pcb->addr_hint);

+      ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,

+                   0, IP_PROTO_TCP, netif);

+      netif->addr_hint = NULL;

+    }

+  }

+#else /* LWIP_NETIF_HWADDRHINT*/

+  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);

+#endif /* LWIP_NETIF_HWADDRHINT*/

+

+  pbuf_free(p);

+

+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F

+                          " ackno %"U32_F".\n",

+                          pcb->snd_nxt - 1, pcb->rcv_nxt));

+}

+#endif /* LWIP_TCP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/udp.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/udp.c
new file mode 100644
index 0000000..a87656b
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/core/udp.c
@@ -0,0 +1,824 @@
+/**

+ * @file

+ * User Datagram Protocol module

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+

+/* udp.c

+ *

+ * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).

+ *

+ */

+

+/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'!

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/udp.h"

+#include "lwip/def.h"

+#include "lwip/memp.h"

+#include "lwip/inet.h"

+#include "lwip/inet_chksum.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/icmp.h"

+#include "lwip/stats.h"

+#include "lwip/snmp.h"

+#include "arch/perf.h"

+#include "lwip/dhcp.h"

+

+#include <string.h>

+

+/* The list of UDP PCBs */

+/* exported in udp.h (was static) */

+struct udp_pcb *udp_pcbs;

+

+/**

+ * Process an incoming UDP datagram.

+ *

+ * Given an incoming UDP datagram (as a chain of pbufs) this function

+ * finds a corresponding UDP PCB and hands over the pbuf to the pcbs

+ * recv function. If no pcb is found or the datagram is incorrect, the

+ * pbuf is freed.

+ *

+ * @param p pbuf to be demultiplexed to a UDP PCB.

+ * @param inp network interface on which the datagram was received.

+ *

+ */

+void

+udp_input(struct pbuf *p, struct netif *inp)

+{

+  struct udp_hdr *udphdr;

+  struct udp_pcb *pcb, *prev;

+  struct udp_pcb *uncon_pcb;

+  struct ip_hdr *iphdr;

+  u16_t src, dest;

+  u8_t local_match;

+

+  PERF_START;

+

+  UDP_STATS_INC(udp.recv);

+

+  iphdr = p->payload;

+

+  /* Check minimum length (IP header + UDP header)

+   * and move payload pointer to UDP header */

+  if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) {

+    /* drop short packets */

+    LWIP_DEBUGF(UDP_DEBUG,

+                ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));

+    UDP_STATS_INC(udp.lenerr);

+    UDP_STATS_INC(udp.drop);

+    snmp_inc_udpinerrors();

+    pbuf_free(p);

+    goto end;

+  }

+

+  udphdr = (struct udp_hdr *)p->payload;

+

+  LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));

+

+  /* convert src and dest ports to host byte order */

+  src = ntohs(udphdr->src);

+  dest = ntohs(udphdr->dest);

+

+  udp_debug_print(udphdr);

+

+  /* print the UDP source and destination */

+  LWIP_DEBUGF(UDP_DEBUG,

+              ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "

+               "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",

+               ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest),

+               ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest),

+               ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),

+               ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src)));

+

+#if LWIP_DHCP

+  pcb = NULL;

+  /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by

+     the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */

+  if (dest == DHCP_CLIENT_PORT) {

+    /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */

+    if (src == DHCP_SERVER_PORT) {

+      if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) {

+        /* accept the packe if

+           (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!

+           - inp->dhcp->pcb->remote == ANY or iphdr->src */

+        if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||

+           ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &(iphdr->src)))) {

+          pcb = inp->dhcp->pcb;

+        }

+      }

+    }

+  } else

+#endif /* LWIP_DHCP */

+  {

+    prev = NULL;

+    local_match = 0;

+    uncon_pcb = NULL;

+    /* Iterate through the UDP pcb list for a matching pcb.

+     * 'Perfect match' pcbs (connected to the remote port & ip address) are

+     * preferred. If no perfect match is found, the first unconnected pcb that

+     * matches the local port and ip address gets the datagram. */

+    for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {

+      local_match = 0;

+      /* print the PCB local and remote address */

+      LWIP_DEBUGF(UDP_DEBUG,

+                  ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "

+                   "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",

+                   ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),

+                   ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,

+                   ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),

+                   ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port));

+

+      /* compare PCB local addr+port to UDP destination addr+port */

+      if ((pcb->local_port == dest) &&

+          (ip_addr_isany(&pcb->local_ip) ||

+           ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) ||

+#if LWIP_IGMP

+           ip_addr_ismulticast(&(iphdr->dest)) ||

+#endif /* LWIP_IGMP */

+           ip_addr_isbroadcast(&(iphdr->dest), inp))) {

+        local_match = 1;

+        if ((uncon_pcb == NULL) &&

+            ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {

+          /* the first unconnected matching PCB */

+          uncon_pcb = pcb;

+        }

+      }

+      /* compare PCB remote addr+port to UDP source addr+port */

+      if ((local_match != 0) &&

+          (pcb->remote_port == src) &&

+          (ip_addr_isany(&pcb->remote_ip) ||

+           ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) {

+        /* the first fully matching PCB */

+        if (prev != NULL) {

+          /* move the pcb to the front of udp_pcbs so that is

+             found faster next time */

+          prev->next = pcb->next;

+          pcb->next = udp_pcbs;

+          udp_pcbs = pcb;

+        } else {

+          UDP_STATS_INC(udp.cachehit);

+        }

+        break;

+      }

+      prev = pcb;

+    }

+    /* no fully matching pcb found? then look for an unconnected pcb */

+    if (pcb == NULL) {

+      pcb = uncon_pcb;

+    }

+  }

+

+  /* Check checksum if this is a match or if it was directed at us. */

+  if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) {

+    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n"));

+#if LWIP_UDPLITE

+    if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {

+      /* Do the UDP Lite checksum */

+#if CHECKSUM_CHECK_UDP

+      u16_t chklen = ntohs(udphdr->len);

+      if (chklen < sizeof(struct udp_hdr)) {

+        if (chklen == 0) {

+          /* For UDP-Lite, checksum length of 0 means checksum

+             over the complete packet (See RFC 3828 chap. 3.1) */

+          chklen = p->tot_len;

+        } else {

+          /* At least the UDP-Lite header must be covered by the

+             checksum! (Again, see RFC 3828 chap. 3.1) */

+          UDP_STATS_INC(udp.chkerr);

+          UDP_STATS_INC(udp.drop);

+          snmp_inc_udpinerrors();

+          pbuf_free(p);

+          goto end;

+        }

+      }

+      if (inet_chksum_pseudo_partial(p, (struct ip_addr *)&(iphdr->src),

+                             (struct ip_addr *)&(iphdr->dest),

+                             IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {

+        LWIP_DEBUGF(UDP_DEBUG | 2,

+                    ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));

+        UDP_STATS_INC(udp.chkerr);

+        UDP_STATS_INC(udp.drop);

+        snmp_inc_udpinerrors();

+        pbuf_free(p);

+        goto end;

+      }

+#endif /* CHECKSUM_CHECK_UDP */

+    } else

+#endif /* LWIP_UDPLITE */

+    {

+#if CHECKSUM_CHECK_UDP

+      if (udphdr->chksum != 0) {

+        if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),

+                               (struct ip_addr *)&(iphdr->dest),

+                               IP_PROTO_UDP, p->tot_len) != 0) {

+          LWIP_DEBUGF(UDP_DEBUG | 2,

+                      ("udp_input: UDP datagram discarded due to failing checksum\n"));

+          UDP_STATS_INC(udp.chkerr);

+          UDP_STATS_INC(udp.drop);

+          snmp_inc_udpinerrors();

+          pbuf_free(p);

+          goto end;

+        }

+      }

+#endif /* CHECKSUM_CHECK_UDP */

+    }

+    if(pbuf_header(p, -UDP_HLEN)) {

+      /* Can we cope with this failing? Just assert for now */

+      LWIP_ASSERT("pbuf_header failed\n", 0);

+      UDP_STATS_INC(udp.drop);

+      snmp_inc_udpinerrors();

+      pbuf_free(p);

+      goto end;

+    }

+    if (pcb != NULL) {

+      snmp_inc_udpindatagrams();

+      /* callback */

+      if (pcb->recv != NULL) {

+        /* now the recv function is responsible for freeing p */

+        pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);

+      } else {

+        /* no recv function registered? then we have to free the pbuf! */

+        pbuf_free(p);

+        goto end;

+      }

+    } else {

+      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n"));

+

+#if LWIP_ICMP

+      /* No match was found, send ICMP destination port unreachable unless

+         destination address was broadcast/multicast. */

+      if (!ip_addr_isbroadcast(&iphdr->dest, inp) &&

+          !ip_addr_ismulticast(&iphdr->dest)) {

+        /* move payload pointer back to ip header */

+        pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN);

+        LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr));

+        icmp_dest_unreach(p, ICMP_DUR_PORT);

+      }

+#endif /* LWIP_ICMP */

+      UDP_STATS_INC(udp.proterr);

+      UDP_STATS_INC(udp.drop);

+      snmp_inc_udpnoports();

+      pbuf_free(p);

+    }

+  } else {

+    pbuf_free(p);

+  }

+end:

+  PERF_STOP("udp_input");

+}

+

+/**

+ * Send data using UDP.

+ *

+ * @param pcb UDP PCB used to send the data.

+ * @param p chain of pbuf's to be sent.

+ *

+ * The datagram will be sent to the current remote_ip & remote_port

+ * stored in pcb. If the pcb is not bound to a port, it will

+ * automatically be bound to a random port.

+ *

+ * @return lwIP error code.

+ * - ERR_OK. Successful. No error occured.

+ * - ERR_MEM. Out of memory.

+ * - ERR_RTE. Could not find route to destination address.

+ * - More errors could be returned by lower protocol layers.

+ *

+ * @see udp_disconnect() udp_sendto()

+ */

+err_t

+udp_send(struct udp_pcb *pcb, struct pbuf *p)

+{

+  /* send to the packet using remote ip and port stored in the pcb */

+  return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);

+}

+

+/**

+ * Send data to a specified address using UDP.

+ *

+ * @param pcb UDP PCB used to send the data.

+ * @param p chain of pbuf's to be sent.

+ * @param dst_ip Destination IP address.

+ * @param dst_port Destination UDP port.

+ *

+ * dst_ip & dst_port are expected to be in the same byte order as in the pcb.

+ *

+ * If the PCB already has a remote address association, it will

+ * be restored after the data is sent.

+ *

+ * @return lwIP error code (@see udp_send for possible error codes)

+ *

+ * @see udp_disconnect() udp_send()

+ */

+err_t

+udp_sendto(struct udp_pcb *pcb, struct pbuf *p,

+  struct ip_addr *dst_ip, u16_t dst_port)

+{

+  struct netif *netif;

+

+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_send\n"));

+

+  /* find the outgoing network interface for this packet */

+#if LWIP_IGMP

+  netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));

+#else

+  netif = ip_route(dst_ip);

+#endif /* LWIP_IGMP */

+

+  /* no outgoing network interface could be found? */

+  if (netif == NULL) {

+    LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr));

+    UDP_STATS_INC(udp.rterr);

+    return ERR_RTE;

+  }

+  return udp_sendto_if(pcb, p, dst_ip, dst_port, netif);

+}

+

+/**

+ * Send data to a specified address using UDP.

+ * The netif used for sending can be specified.

+ *

+ * This function exists mainly for DHCP, to be able to send UDP packets

+ * on a netif that is still down.

+ *

+ * @param pcb UDP PCB used to send the data.

+ * @param p chain of pbuf's to be sent.

+ * @param dst_ip Destination IP address.

+ * @param dst_port Destination UDP port.

+ * @param netif the netif used for sending.

+ *

+ * dst_ip & dst_port are expected to be in the same byte order as in the pcb.

+ *

+ * @return lwIP error code (@see udp_send for possible error codes)

+ *

+ * @see udp_disconnect() udp_send()

+ */

+err_t

+udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,

+  struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif)

+{

+  struct udp_hdr *udphdr;

+  struct ip_addr *src_ip;

+  err_t err;

+  struct pbuf *q; /* q will be sent down the stack */

+

+  /* if the PCB is not yet bound to a port, bind it here */

+  if (pcb->local_port == 0) {

+    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));

+    err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);

+    if (err != ERR_OK) {

+      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: forced port bind failed\n"));

+      return err;

+    }

+  }

+

+  /* not enough space to add an UDP header to first pbuf in given p chain? */

+  if (pbuf_header(p, UDP_HLEN)) {

+    /* allocate header in a separate new pbuf */

+    q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);

+    /* new header pbuf could not be allocated? */

+    if (q == NULL) {

+      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: could not allocate header\n"));

+      return ERR_MEM;

+    }

+    /* chain header q in front of given pbuf p */

+    pbuf_chain(q, p);

+    /* first pbuf q points to header pbuf */

+    LWIP_DEBUGF(UDP_DEBUG,

+                ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));

+  } else {

+    /* adding space for header within p succeeded */

+    /* first pbuf q equals given pbuf */

+    q = p;

+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p));

+  }

+  LWIP_ASSERT("check that first pbuf can hold struct udp_hdr",

+              (q->len >= sizeof(struct udp_hdr)));

+  /* q now represents the packet to be sent */

+  udphdr = q->payload;

+  udphdr->src = htons(pcb->local_port);

+  udphdr->dest = htons(dst_port);

+  /* in UDP, 0 checksum means 'no checksum' */

+  udphdr->chksum = 0x0000;

+

+  /* PCB local address is IP_ANY_ADDR? */

+  if (ip_addr_isany(&pcb->local_ip)) {

+    /* use outgoing network interface IP address as source address */

+    src_ip = &(netif->ip_addr);

+  } else {

+    /* check if UDP PCB local IP address is correct

+     * this could be an old address if netif->ip_addr has changed */

+    if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {

+      /* local_ip doesn't match, drop the packet */

+      if (q != p) {

+        /* free the header pbuf */

+        pbuf_free(q);

+        q = NULL;

+        /* p is still referenced by the caller, and will live on */

+      }

+      return ERR_VAL;

+    }

+    /* use UDP PCB local IP address as source address */

+    src_ip = &(pcb->local_ip);

+  }

+

+  LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));

+

+#if LWIP_UDPLITE

+  /* UDP Lite protocol? */

+  if (pcb->flags & UDP_FLAGS_UDPLITE) {

+    u16_t chklen, chklen_hdr;

+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len));

+    /* set UDP message length in UDP header */

+    chklen_hdr = chklen = pcb->chksum_len_tx;

+    if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) {

+      if (chklen != 0) {

+        LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen));

+      }

+      /* For UDP-Lite, checksum length of 0 means checksum

+         over the complete packet. (See RFC 3828 chap. 3.1)

+         At least the UDP-Lite header must be covered by the

+         checksum, therefore, if chksum_len has an illegal

+         value, we generate the checksum over the complete

+         packet to be safe. */

+      chklen_hdr = 0;

+      chklen = q->tot_len;

+    }

+    udphdr->len = htons(chklen_hdr);

+    /* calculate checksum */

+#if CHECKSUM_GEN_UDP

+    udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip,

+                                        IP_PROTO_UDPLITE, q->tot_len, chklen);

+    /* chksum zero must become 0xffff, as zero means 'no checksum' */

+    if (udphdr->chksum == 0x0000)

+      udphdr->chksum = 0xffff;

+#endif /* CHECKSUM_CHECK_UDP */

+    /* output to IP */

+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));

+#if LWIP_NETIF_HWADDRHINT

+    netif->addr_hint = &(pcb->addr_hint);

+#endif /* LWIP_NETIF_HWADDRHINT*/

+    err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);

+#if LWIP_NETIF_HWADDRHINT

+    netif->addr_hint = NULL;

+#endif /* LWIP_NETIF_HWADDRHINT*/

+  } else

+#endif /* LWIP_UDPLITE */

+  {      /* UDP */

+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len));

+    udphdr->len = htons(q->tot_len);

+    /* calculate checksum */

+#if CHECKSUM_GEN_UDP

+    if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {

+      udphdr->chksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);

+      /* chksum zero must become 0xffff, as zero means 'no checksum' */

+      if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;

+    }

+#endif /* CHECKSUM_CHECK_UDP */

+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));

+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));

+    /* output to IP */

+#if LWIP_NETIF_HWADDRHINT

+    netif->addr_hint = &(pcb->addr_hint);

+#endif /* LWIP_NETIF_HWADDRHINT*/

+    err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);

+#if LWIP_NETIF_HWADDRHINT

+    netif->addr_hint = NULL;

+#endif /* LWIP_NETIF_HWADDRHINT*/

+  }

+  /* TODO: must this be increased even if error occured? */

+  snmp_inc_udpoutdatagrams();

+

+  /* did we chain a separate header pbuf earlier? */

+  if (q != p) {

+    /* free the header pbuf */

+    pbuf_free(q);

+    q = NULL;

+    /* p is still referenced by the caller, and will live on */

+  }

+

+  UDP_STATS_INC(udp.xmit);

+  return err;

+}

+

+/**

+ * Bind an UDP PCB.

+ *

+ * @param pcb UDP PCB to be bound with a local address ipaddr and port.

+ * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to

+ * bind to all local interfaces.

+ * @param port local UDP port to bind with. Use 0 to automatically bind

+ * to a random port between UDP_LOCAL_PORT_RANGE_START and

+ * UDP_LOCAL_PORT_RANGE_END.

+ *

+ * ipaddr & port are expected to be in the same byte order as in the pcb.

+ *

+ * @return lwIP error code.

+ * - ERR_OK. Successful. No error occured.

+ * - ERR_USE. The specified ipaddr and port are already bound to by

+ * another UDP PCB.

+ *

+ * @see udp_disconnect()

+ */

+err_t

+udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)

+{

+  struct udp_pcb *ipcb;

+  u8_t rebind;

+

+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_bind(ipaddr = "));

+  ip_addr_debug_print(UDP_DEBUG, ipaddr);

+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, (", port = %"U16_F")\n", port));

+

+  rebind = 0;

+  /* Check for double bind and rebind of the same pcb */

+  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {

+    /* is this UDP PCB already on active list? */

+    if (pcb == ipcb) {

+      /* pcb may occur at most once in active list */

+      LWIP_ASSERT("rebind == 0", rebind == 0);

+      /* pcb already in list, just rebind */

+      rebind = 1;

+    }

+

+    /* this code does not allow upper layer to share a UDP port for

+       listening to broadcast or multicast traffic (See SO_REUSE_ADDR and

+       SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR

+       combine with implementation of UDP PCB flags. Leon Woestenberg. */

+#ifdef LWIP_UDP_TODO

+    /* port matches that of PCB in list? */

+    else

+      if ((ipcb->local_port == port) &&

+          /* IP address matches, or one is IP_ADDR_ANY? */

+          (ip_addr_isany(&(ipcb->local_ip)) ||

+           ip_addr_isany(ipaddr) ||

+           ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {

+        /* other PCB already binds to this local IP and port */

+        LWIP_DEBUGF(UDP_DEBUG,

+                    ("udp_bind: local port %"U16_F" already bound by another pcb\n", port));

+        return ERR_USE;

+      }

+#endif

+  }

+

+  ip_addr_set(&pcb->local_ip, ipaddr);

+

+  /* no port specified? */

+  if (port == 0) {

+#ifndef UDP_LOCAL_PORT_RANGE_START

+#define UDP_LOCAL_PORT_RANGE_START 4096

+#define UDP_LOCAL_PORT_RANGE_END   0x7fff

+#endif

+    port = UDP_LOCAL_PORT_RANGE_START;

+    ipcb = udp_pcbs;

+    while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {

+      if (ipcb->local_port == port) {

+        /* port is already used by another udp_pcb */

+        port++;

+        /* restart scanning all udp pcbs */

+        ipcb = udp_pcbs;

+      } else

+        /* go on with next udp pcb */

+        ipcb = ipcb->next;

+    }

+    if (ipcb != NULL) {

+      /* no more ports available in local range */

+      LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));

+      return ERR_USE;

+    }

+  }

+  pcb->local_port = port;

+  snmp_insert_udpidx_tree(pcb);

+  /* pcb not active yet? */

+  if (rebind == 0) {

+    /* place the PCB on the active list if not already there */

+    pcb->next = udp_pcbs;

+    udp_pcbs = pcb;

+  }

+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,

+              ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",

+               (u16_t)(ntohl(pcb->local_ip.addr) >> 24 & 0xff),

+               (u16_t)(ntohl(pcb->local_ip.addr) >> 16 & 0xff),

+               (u16_t)(ntohl(pcb->local_ip.addr) >> 8 & 0xff),

+               (u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));

+  return ERR_OK;

+}

+/**

+ * Connect an UDP PCB.

+ *

+ * This will associate the UDP PCB with the remote address.

+ *

+ * @param pcb UDP PCB to be connected with remote address ipaddr and port.

+ * @param ipaddr remote IP address to connect with.

+ * @param port remote UDP port to connect with.

+ *

+ * @return lwIP error code

+ *

+ * ipaddr & port are expected to be in the same byte order as in the pcb.

+ *

+ * The udp pcb is bound to a random local port if not already bound.

+ *

+ * @see udp_disconnect()

+ */

+err_t

+udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)

+{

+  struct udp_pcb *ipcb;

+

+  if (pcb->local_port == 0) {

+    err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);

+    if (err != ERR_OK)

+      return err;

+  }

+

+  ip_addr_set(&pcb->remote_ip, ipaddr);

+  pcb->remote_port = port;

+  pcb->flags |= UDP_FLAGS_CONNECTED;

+/** TODO: this functionality belongs in upper layers */

+#ifdef LWIP_UDP_TODO

+  /* Nail down local IP for netconn_addr()/getsockname() */

+  if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {

+    struct netif *netif;

+

+    if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {

+      LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));

+      UDP_STATS_INC(udp.rterr);

+      return ERR_RTE;

+    }

+    /** TODO: this will bind the udp pcb locally, to the interface which

+        is used to route output packets to the remote address. However, we

+        might want to accept incoming packets on any interface! */

+    pcb->local_ip = netif->ip_addr;

+  } else if (ip_addr_isany(&pcb->remote_ip)) {

+    pcb->local_ip.addr = 0;

+  }

+#endif

+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,

+              ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",

+               (u16_t)(ntohl(pcb->remote_ip.addr) >> 24 & 0xff),

+               (u16_t)(ntohl(pcb->remote_ip.addr) >> 16 & 0xff),

+               (u16_t)(ntohl(pcb->remote_ip.addr) >> 8 & 0xff),

+               (u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));

+

+  /* Insert UDP PCB into the list of active UDP PCBs. */

+  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {

+    if (pcb == ipcb) {

+      /* already on the list, just return */

+      return ERR_OK;

+    }

+  }

+  /* PCB not yet on the list, add PCB now */

+  pcb->next = udp_pcbs;

+  udp_pcbs = pcb;

+  return ERR_OK;

+}

+

+/**

+ * Disconnect a UDP PCB

+ *

+ * @param pcb the udp pcb to disconnect.

+ */

+void

+udp_disconnect(struct udp_pcb *pcb)

+{

+  /* reset remote address association */

+  ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY);

+  pcb->remote_port = 0;

+  /* mark PCB as unconnected */

+  pcb->flags &= ~UDP_FLAGS_CONNECTED;

+}

+

+/**

+ * Set a receive callback for a UDP PCB

+ *

+ * This callback will be called when receiving a datagram for the pcb.

+ *

+ * @param pcb the pcb for wich to set the recv callback

+ * @param recv function pointer of the callback function

+ * @param recv_arg additional argument to pass to the callback function

+ */

+void

+udp_recv(struct udp_pcb *pcb,

+         void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p,

+                       struct ip_addr *addr, u16_t port),

+         void *recv_arg)

+{

+  /* remember recv() callback and user data */

+  pcb->recv = recv;

+  pcb->recv_arg = recv_arg;

+}

+

+/**

+ * Remove an UDP PCB.

+ *

+ * @param pcb UDP PCB to be removed. The PCB is removed from the list of

+ * UDP PCB's and the data structure is freed from memory.

+ *

+ * @see udp_new()

+ */

+void

+udp_remove(struct udp_pcb *pcb)

+{

+  struct udp_pcb *pcb2;

+

+  snmp_delete_udpidx_tree(pcb);

+  /* pcb to be removed is first in list? */

+  if (udp_pcbs == pcb) {

+    /* make list start at 2nd pcb */

+    udp_pcbs = udp_pcbs->next;

+    /* pcb not 1st in list */

+  } else

+    for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {

+      /* find pcb in udp_pcbs list */

+      if (pcb2->next != NULL && pcb2->next == pcb) {

+        /* remove pcb from list */

+        pcb2->next = pcb->next;

+      }

+    }

+  memp_free(MEMP_UDP_PCB, pcb);

+}

+

+/**

+ * Create a UDP PCB.

+ *

+ * @return The UDP PCB which was created. NULL if the PCB data structure

+ * could not be allocated.

+ *

+ * @see udp_remove()

+ */

+struct udp_pcb *

+udp_new(void)

+{

+  struct udp_pcb *pcb;

+  pcb = memp_malloc(MEMP_UDP_PCB);

+  /* could allocate UDP PCB? */

+  if (pcb != NULL) {

+    /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0

+     * which means checksum is generated over the whole datagram per default

+     * (recommended as default by RFC 3828). */

+    /* initialize PCB to all zeroes */

+    memset(pcb, 0, sizeof(struct udp_pcb));

+    pcb->ttl = UDP_TTL;

+  }

+  return pcb;

+}

+

+#if UDP_DEBUG

+/**

+ * Print UDP header information for debug purposes.

+ *

+ * @param udphdr pointer to the udp header in memory.

+ */

+void

+udp_debug_print(struct udp_hdr *udphdr)

+{

+  LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n"));

+  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(UDP_DEBUG, ("|     %5"U16_F"     |     %5"U16_F"     | (src port, dest port)\n",

+                          ntohs(udphdr->src), ntohs(udphdr->dest)));

+  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));

+  LWIP_DEBUGF(UDP_DEBUG, ("|     %5"U16_F"     |     0x%04"X16_F"    | (len, chksum)\n",

+                          ntohs(udphdr->len), ntohs(udphdr->chksum)));

+  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));

+}

+#endif /* UDP_DEBUG */

+

+#endif /* LWIP_UDP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/autoip.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/autoip.h
new file mode 100644
index 0000000..78e8475
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/autoip.h
@@ -0,0 +1,105 @@
+/**

+ * @file

+ *

+ * AutoIP Automatic LinkLocal IP Configuration

+ */

+

+/*

+ *

+ * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * Author: Dominik Spies <kontakt@dspies.de>

+ *

+ * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform

+ * with RFC 3927.

+ *

+ *

+ * Please coordinate changes and requests with Dominik Spies

+ * <kontakt@dspies.de>

+ */

+

+#ifndef __LWIP_AUTOIP_H__

+#define __LWIP_AUTOIP_H__

+

+#include "lwip/opt.h"

+

+#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/netif.h"

+#include "lwip/udp.h"

+#include "netif/etharp.h"

+

+/* AutoIP Timing */

+#define AUTOIP_TMR_INTERVAL      100

+#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL)

+

+/* RFC 3927 Constants */

+#define PROBE_WAIT               1   /* second   (initial random delay)                 */

+#define PROBE_MIN                1   /* second   (minimum delay till repeated probe)    */

+#define PROBE_MAX                2   /* seconds  (maximum delay till repeated probe)    */

+#define PROBE_NUM                3   /*          (number of probe packets)              */

+#define ANNOUNCE_NUM             2   /*          (number of announcement packets)       */

+#define ANNOUNCE_INTERVAL        2   /* seconds  (time between announcement packets)    */

+#define ANNOUNCE_WAIT            2   /* seconds  (delay before announcing)              */

+#define MAX_CONFLICTS            10  /*          (max conflicts before rate limiting)   */

+#define RATE_LIMIT_INTERVAL      60  /* seconds  (delay between successive attempts)    */

+#define DEFEND_INTERVAL          10  /* seconds  (min. wait between defensive ARPs)     */

+

+/* AutoIP client states */

+#define AUTOIP_STATE_OFF         0

+#define AUTOIP_STATE_PROBING     1

+#define AUTOIP_STATE_ANNOUNCING  2

+#define AUTOIP_STATE_BOUND       3

+

+struct autoip

+{

+  struct ip_addr llipaddr;  /* the currently selected, probed, announced or used LL IP-Address */

+  u8_t state;               /* current AutoIP state machine state */

+  u8_t sent_num;            /* sent number of probes or announces, dependent on state */

+  u16_t ttw;                /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */

+  u8_t lastconflict;        /* ticks until a conflict can be solved by defending */

+  u8_t tried_llipaddr;      /* total number of probed/used Link Local IP-Addresses */

+};

+

+

+/** Init srand, has to be called before entering mainloop */

+void autoip_init(void);

+

+/** Start AutoIP client */

+err_t autoip_start(struct netif *netif);

+

+/** Stop AutoIP client */

+err_t autoip_stop(struct netif *netif);

+

+/** Handles every incoming ARP Packet, called by etharp_arp_input */

+void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr);

+

+/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */

+void autoip_tmr(void);

+

+#endif /* LWIP_AUTOIP */

+

+#endif /* __LWIP_AUTOIP_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/icmp.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/icmp.h
new file mode 100644
index 0000000..39835cb
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/icmp.h
@@ -0,0 +1,130 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_ICMP_H__

+#define __LWIP_ICMP_H__

+

+#include "lwip/opt.h"

+

+#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/pbuf.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#define ICMP_ER 0      /* echo reply */

+#define ICMP_DUR 3     /* destination unreachable */

+#define ICMP_SQ 4      /* source quench */

+#define ICMP_RD 5      /* redirect */

+#define ICMP_ECHO 8    /* echo */

+#define ICMP_TE 11     /* time exceeded */

+#define ICMP_PP 12     /* parameter problem */

+#define ICMP_TS 13     /* timestamp */

+#define ICMP_TSR 14    /* timestamp reply */

+#define ICMP_IRQ 15    /* information request */

+#define ICMP_IR 16     /* information reply */

+

+enum icmp_dur_type {

+  ICMP_DUR_NET = 0,    /* net unreachable */

+  ICMP_DUR_HOST = 1,   /* host unreachable */

+  ICMP_DUR_PROTO = 2,  /* protocol unreachable */

+  ICMP_DUR_PORT = 3,   /* port unreachable */

+  ICMP_DUR_FRAG = 4,   /* fragmentation needed and DF set */

+  ICMP_DUR_SR = 5      /* source route failed */

+};

+

+enum icmp_te_type {

+  ICMP_TE_TTL = 0,     /* time to live exceeded in transit */

+  ICMP_TE_FRAG = 1     /* fragment reassembly time exceeded */

+};

+

+void icmp_input(struct pbuf *p, struct netif *inp);

+

+void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);

+void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);

+

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct icmp_echo_hdr {

+  PACK_STRUCT_FIELD(u16_t _type_code);

+  PACK_STRUCT_FIELD(u16_t chksum);

+  PACK_STRUCT_FIELD(u16_t id);

+  PACK_STRUCT_FIELD(u16_t seqno);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct icmp_dur_hdr {

+  PACK_STRUCT_FIELD(u16_t _type_code);

+  PACK_STRUCT_FIELD(u16_t chksum);

+  PACK_STRUCT_FIELD(u32_t unused);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct icmp_te_hdr {

+  PACK_STRUCT_FIELD(u16_t _type_code);

+  PACK_STRUCT_FIELD(u16_t chksum);

+  PACK_STRUCT_FIELD(u32_t unused);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+#define ICMPH_TYPE(hdr) (ntohs((hdr)->_type_code) >> 8)

+#define ICMPH_CODE(hdr) (ntohs((hdr)->_type_code) & 0xff)

+

+#define ICMPH_TYPE_SET(hdr, type) ((hdr)->_type_code = htons(ICMPH_CODE(hdr) | ((type) << 8)))

+#define ICMPH_CODE_SET(hdr, code) ((hdr)->_type_code = htons((code) | (ICMPH_TYPE(hdr) << 8)))

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* LWIP_ICMP */

+

+#endif /* __LWIP_ICMP_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/igmp.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/igmp.h
new file mode 100644
index 0000000..f942209
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/igmp.h
@@ -0,0 +1,165 @@
+/*

+ * Copyright (c) 2002 CITEL Technologies Ltd.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ * 1. Redistributions of source code must retain the above copyright

+ *    notice, this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright

+ *    notice, this list of conditions and the following disclaimer in the

+ *    documentation and/or other materials provided with the distribution.

+ * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors

+ *    may be used to endorse or promote products derived from this software

+ *    without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''

+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

+ * ARE DISCLAIMED.  IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE

+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL

+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS

+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)

+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY

+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF

+ * SUCH DAMAGE.

+ *

+ * This file is a contribution to the lwIP TCP/IP stack.

+ * The Swedish Institute of Computer Science and Adam Dunkels

+ * are specifically granted permission to redistribute this

+ * source code.

+*/

+

+#ifndef __LWIP_IGMP_H__

+#define __LWIP_IGMP_H__

+

+#include "lwip/opt.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/pbuf.h"

+

+#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+/*

+ * IGMP constants

+ */

+#define IP_PROTO_IGMP                  2

+#define IGMP_TTL                       1

+#define IGMP_MINLEN                    8

+#define ROUTER_ALERT                   0x9404

+#define ROUTER_ALERTLEN                4

+

+/*

+ * IGMP message types, including version number.

+ */

+#define IGMP_MEMB_QUERY                0x11 /* Membership query         */

+#define IGMP_V1_MEMB_REPORT            0x12 /* Ver. 1 membership report */

+#define IGMP_V2_MEMB_REPORT            0x16 /* Ver. 2 membership report */

+#define IGMP_LEAVE_GROUP               0x17 /* Leave-group message      */

+

+/* IGMP timer */

+#define IGMP_TMR_INTERVAL              100 /* Milliseconds */

+#define IGMP_V1_DELAYING_MEMBER_TMR   (1000/IGMP_TMR_INTERVAL)

+#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL)

+

+/* MAC Filter Actions */

+#define IGMP_DEL_MAC_FILTER            0

+#define IGMP_ADD_MAC_FILTER            1

+

+/* Group  membership states */

+#define IGMP_GROUP_NON_MEMBER          0

+#define IGMP_GROUP_DELAYING_MEMBER     1

+#define IGMP_GROUP_IDLE_MEMBER         2

+

+/*

+ * IGMP packet format.

+ */

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct igmp_msg {

+ PACK_STRUCT_FIELD(u8_t           igmp_msgtype);

+ PACK_STRUCT_FIELD(u8_t           igmp_maxresp);

+ PACK_STRUCT_FIELD(u16_t          igmp_checksum);

+ PACK_STRUCT_FIELD(struct ip_addr igmp_group_address);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+/*

+ * now a group structure - there is

+ * a list of groups for each interface

+ * these should really be linked from the interface, but

+ * if we keep them separate we will not affect the lwip original code

+ * too much

+ *

+ * There will be a group for the all systems group address but this

+ * will not run the state machine as it is used to kick off reports

+ * from all the other groups

+ */

+

+struct igmp_group {

+  struct igmp_group *next;

+  struct netif      *interface;

+  struct ip_addr     group_address;

+  u8_t               last_reporter_flag; /* signifies we were the last person to report */

+  u8_t               group_state;

+  u16_t              timer;

+  u8_t               use; /* counter of simultaneous uses */

+};

+

+

+/*  Prototypes */

+void   igmp_init(void);

+

+err_t  igmp_start( struct netif *netif);

+

+err_t  igmp_stop( struct netif *netif);

+

+void   igmp_report_groups( struct netif *netif);

+

+struct igmp_group *igmp_lookfor_group( struct netif *ifp, struct ip_addr *addr);

+

+struct igmp_group *igmp_lookup_group( struct netif *ifp, struct ip_addr *addr);

+

+err_t  igmp_remove_group( struct igmp_group *group);

+

+void   igmp_input( struct pbuf *p, struct netif *inp, struct ip_addr *dest);

+

+err_t  igmp_joingroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr);

+

+err_t  igmp_leavegroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr);

+

+void   igmp_tmr(void);

+

+void   igmp_timeout( struct igmp_group *group);

+

+void   igmp_start_timer( struct igmp_group *group, u8_t max_time);

+

+void   igmp_stop_timer( struct igmp_group *group);

+

+void   igmp_delaying_member( struct igmp_group *group, u8_t maxresp);

+

+err_t  igmp_ip_output_if( struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t proto, struct netif *netif);

+

+void   igmp_send( struct igmp_group *group, u8_t type);

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* LWIP_IGMP */

+

+#endif /* __LWIP_IGMP_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/inet.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/inet.h
new file mode 100644
index 0000000..2779a00
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/inet.h
@@ -0,0 +1,95 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_INET_H__

+#define __LWIP_INET_H__

+

+#include "lwip/opt.h"

+

+#include "lwip/ip_addr.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+u32_t inet_addr(const char *cp);

+int inet_aton(const char *cp, struct in_addr *addr);

+char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */

+

+#ifdef htons

+#undef htons

+#endif /* htons */

+#ifdef htonl

+#undef htonl

+#endif /* htonl */

+#ifdef ntohs

+#undef ntohs

+#endif /* ntohs */

+#ifdef ntohl

+#undef ntohl

+#endif /* ntohl */

+

+#ifndef LWIP_PLATFORM_BYTESWAP

+#define LWIP_PLATFORM_BYTESWAP 0

+#endif

+

+#if BYTE_ORDER == BIG_ENDIAN

+#define htons(x) (x)

+#define ntohs(x) (x)

+#define htonl(x) (x)

+#define ntohl(x) (x)

+#else /* BYTE_ORDER != BIG_ENDIAN */

+#ifdef LWIP_PREFIX_BYTEORDER_FUNCS

+/* workaround for naming collisions on some platforms */

+#define htons lwip_htons

+#define ntohs lwip_ntohs

+#define htonl lwip_htonl

+#define ntohl lwip_ntohl

+#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */

+#if LWIP_PLATFORM_BYTESWAP

+#define htons(x) LWIP_PLATFORM_HTONS(x)

+#define ntohs(x) LWIP_PLATFORM_HTONS(x)

+#define htonl(x) LWIP_PLATFORM_HTONL(x)

+#define ntohl(x) LWIP_PLATFORM_HTONL(x)

+#else /* LWIP_PLATFORM_BYTESWAP */

+u16_t htons(u16_t x);

+u16_t ntohs(u16_t x);

+u32_t htonl(u32_t x);

+u32_t ntohl(u32_t x);

+#endif /* LWIP_PLATFORM_BYTESWAP */

+

+#endif /* BYTE_ORDER == BIG_ENDIAN */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_INET_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/inet_chksum.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/inet_chksum.h
new file mode 100644
index 0000000..7a381a0
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/inet_chksum.h
@@ -0,0 +1,58 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_INET_CHKSUM_H__

+#define __LWIP_INET_CHKSUM_H__

+

+#include "lwip/opt.h"

+

+#include "lwip/pbuf.h"

+#include "lwip/ip_addr.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+u16_t inet_chksum(void *dataptr, u16_t len);

+u16_t inet_chksum_pbuf(struct pbuf *p);

+u16_t inet_chksum_pseudo(struct pbuf *p,

+       struct ip_addr *src, struct ip_addr *dest,

+       u8_t proto, u16_t proto_len);

+u16_t inet_chksum_pseudo_partial(struct pbuf *p,

+       struct ip_addr *src, struct ip_addr *dest,

+       u8_t proto, u16_t proto_len, u16_t chksum_len);

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_INET_H__ */

+

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip.h
new file mode 100644
index 0000000..946837d
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip.h
@@ -0,0 +1,176 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_IP_H__

+#define __LWIP_IP_H__

+

+#include "lwip/opt.h"

+

+#include "lwip/def.h"

+#include "lwip/pbuf.h"

+#include "lwip/ip_addr.h"

+#include "lwip/err.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#define ip_init() /* Compatibility define, not init needed. */

+struct netif *ip_route(struct ip_addr *dest);

+err_t ip_input(struct pbuf *p, struct netif *inp);

+err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,

+    u8_t ttl, u8_t tos, u8_t proto);

+err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,

+       u8_t ttl, u8_t tos, u8_t proto,

+       struct netif *netif);

+

+#define IP_HLEN 20

+

+#define IP_PROTO_ICMP    1

+#define IP_PROTO_UDP     17

+#define IP_PROTO_UDPLITE 136

+#define IP_PROTO_TCP     6

+

+/* This is passed as the destination address to ip_output_if (not

+   to ip_output), meaning that an IP header already is constructed

+   in the pbuf. This is used when TCP retransmits. */

+#ifdef IP_HDRINCL

+#undef IP_HDRINCL

+#endif /* IP_HDRINCL */

+#define IP_HDRINCL  NULL

+

+#if LWIP_NETIF_HWADDRHINT

+#define IP_PCB_ADDRHINT ;u8_t addr_hint

+#else

+#define IP_PCB_ADDRHINT

+#endif /* LWIP_NETIF_HWADDRHINT */

+

+/* This is the common part of all PCB types. It needs to be at the

+   beginning of a PCB type definition. It is located here so that

+   changes to this common part are made in one location instead of

+   having to change all PCB structs. */

+#define IP_PCB \

+  /* ip addresses in network byte order */ \

+  struct ip_addr local_ip; \

+  struct ip_addr remote_ip; \

+   /* Socket options */  \

+  u16_t so_options;      \

+   /* Type Of Service */ \

+  u8_t tos;              \

+  /* Time To Live */     \

+  u8_t ttl               \

+  /* link layer address resolution hint */ \

+  IP_PCB_ADDRHINT

+

+struct ip_pcb {

+/* Common members of all PCB types */

+  IP_PCB;

+};

+

+/*

+ * Option flags per-socket. These are the same like SO_XXX.

+ */

+#define SOF_DEBUG       (u16_t)0x0001U    /* turn on debugging info recording */

+#define SOF_ACCEPTCONN  (u16_t)0x0002U    /* socket has had listen() */

+#define SOF_REUSEADDR   (u16_t)0x0004U    /* allow local address reuse */

+#define SOF_KEEPALIVE   (u16_t)0x0008U    /* keep connections alive */

+#define SOF_DONTROUTE   (u16_t)0x0010U    /* just use interface addresses */

+#define SOF_BROADCAST   (u16_t)0x0020U    /* permit sending of broadcast msgs */

+#define SOF_USELOOPBACK (u16_t)0x0040U    /* bypass hardware when possible */

+#define SOF_LINGER      (u16_t)0x0080U    /* linger on close if data present */

+#define SOF_OOBINLINE   (u16_t)0x0100U    /* leave received OOB data in line */

+#define SOF_REUSEPORT   (u16_t)0x0200U    /* allow local address & port reuse */

+

+

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct ip_hdr {

+  /* version / header length / type of service */

+  PACK_STRUCT_FIELD(u16_t _v_hl_tos);

+  /* total length */

+  PACK_STRUCT_FIELD(u16_t _len);

+  /* identification */

+  PACK_STRUCT_FIELD(u16_t _id);

+  /* fragment offset field */

+  PACK_STRUCT_FIELD(u16_t _offset);

+#define IP_RF 0x8000        /* reserved fragment flag */

+#define IP_DF 0x4000        /* dont fragment flag */

+#define IP_MF 0x2000        /* more fragments flag */

+#define IP_OFFMASK 0x1fff   /* mask for fragmenting bits */

+  /* time to live / protocol*/

+  PACK_STRUCT_FIELD(u16_t _ttl_proto);

+  /* checksum */

+  PACK_STRUCT_FIELD(u16_t _chksum);

+  /* source and destination IP addresses */

+  PACK_STRUCT_FIELD(struct ip_addr src);

+  PACK_STRUCT_FIELD(struct ip_addr dest);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+#define IPH_V(hdr)  (ntohs((hdr)->_v_hl_tos) >> 12)

+#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f)

+#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff)

+#define IPH_LEN(hdr) ((hdr)->_len)

+#define IPH_ID(hdr) ((hdr)->_id)

+#define IPH_OFFSET(hdr) ((hdr)->_offset)

+#define IPH_TTL(hdr) (ntohs((hdr)->_ttl_proto) >> 8)

+#define IPH_PROTO(hdr) (ntohs((hdr)->_ttl_proto) & 0xff)

+#define IPH_CHKSUM(hdr) ((hdr)->_chksum)

+

+#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos)))

+#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)

+#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)

+#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)

+#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl_proto = (htons(IPH_PROTO(hdr) | ((u16_t)(ttl) << 8)))

+#define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8)))

+#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)

+

+#if IP_DEBUG

+void ip_debug_print(struct pbuf *p);

+#else

+#define ip_debug_print(p)

+#endif /* IP_DEBUG */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_IP_H__ */

+

+

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip_addr.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip_addr.h
new file mode 100644
index 0000000..acc51e3
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip_addr.h
@@ -0,0 +1,176 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_IP_ADDR_H__

+#define __LWIP_IP_ADDR_H__

+

+#include "lwip/opt.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct ip_addr {

+  PACK_STRUCT_FIELD(u32_t addr);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+/*

+ * struct ipaddr2 is used in the definition of the ARP packet format in

+ * order to support compilers that don't have structure packing.

+ */

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct ip_addr2 {

+  PACK_STRUCT_FIELD(u16_t addrw[2]);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+/* For compatibility with BSD code */

+struct in_addr {

+  u32_t s_addr;

+};

+

+struct netif;

+

+extern const struct ip_addr ip_addr_any;

+extern const struct ip_addr ip_addr_broadcast;

+

+/** IP_ADDR_ can be used as a fixed IP address

+ *  for the wildcard and the broadcast address

+ */

+#define IP_ADDR_ANY         ((struct ip_addr *)&ip_addr_any)

+#define IP_ADDR_BROADCAST   ((struct ip_addr *)&ip_addr_broadcast)

+

+#define INADDR_NONE         ((u32_t)0xffffffffUL)  /* 255.255.255.255 */

+#define INADDR_LOOPBACK     ((u32_t)0x7f000001UL)  /* 127.0.0.1 */

+

+/* Definitions of the bits in an Internet address integer.

+

+   On subnets, host and network parts are found according to

+   the subnet mask, not these masks.  */

+

+#define IN_CLASSA(a)        ((((u32_t)(a)) & 0x80000000UL) == 0)

+#define IN_CLASSA_NET       0xff000000

+#define IN_CLASSA_NSHIFT    24

+#define IN_CLASSA_HOST      (0xffffffff & ~IN_CLASSA_NET)

+#define IN_CLASSA_MAX       128

+

+#define IN_CLASSB(a)        ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)

+#define IN_CLASSB_NET       0xffff0000

+#define IN_CLASSB_NSHIFT    16

+#define IN_CLASSB_HOST      (0xffffffff & ~IN_CLASSB_NET)

+#define IN_CLASSB_MAX       65536

+

+#define IN_CLASSC(a)        ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)

+#define IN_CLASSC_NET       0xffffff00

+#define IN_CLASSC_NSHIFT    8

+#define IN_CLASSC_HOST      (0xffffffff & ~IN_CLASSC_NET)

+

+#define IN_CLASSD(a)        (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)

+#define IN_CLASSD_NET       0xf0000000          /* These ones aren't really */

+#define IN_CLASSD_NSHIFT    28                  /*   net and host fields, but */

+#define IN_CLASSD_HOST      0x0fffffff          /*   routing needn't know. */

+#define IN_MULTICAST(a)     IN_CLASSD(a)

+

+#define IN_EXPERIMENTAL(a)  (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)

+#define IN_BADCLASS(a)      (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)

+

+#define IN_LOOPBACKNET      127                 /* official! */

+

+#define IP4_ADDR(ipaddr, a,b,c,d) \

+        (ipaddr)->addr = htonl(((u32_t)((a) & 0xff) << 24) | \

+                               ((u32_t)((b) & 0xff) << 16) | \

+                               ((u32_t)((c) & 0xff) << 8) | \

+                                (u32_t)((d) & 0xff))

+

+#define ip_addr_set(dest, src) (dest)->addr = \

+                               ((src) == NULL? 0:\

+                               (src)->addr)

+/**

+ * Determine if two address are on the same network.

+ *

+ * @arg addr1 IP address 1

+ * @arg addr2 IP address 2

+ * @arg mask network identifier mask

+ * @return !0 if the network identifiers of both address match

+ */

+#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \

+                                              (mask)->addr) == \

+                                             ((addr2)->addr & \

+                                              (mask)->addr))

+#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)

+

+#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0)

+

+u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *);

+

+#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000UL)) == ntohl(0xe0000000UL))

+

+#define ip_addr_islinklocal(addr1) (((addr1)->addr & ntohl(0xffff0000UL)) == ntohl(0xa9fe0000UL))

+

+#define ip_addr_debug_print(debug, ipaddr) \

+        LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \

+                ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \

+                ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0, \

+                ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0, \

+                ipaddr ? (u16_t)ntohl((ipaddr)->addr) & 0xff : 0))

+

+/* These are cast to u16_t, with the intent that they are often arguments

+ * to printf using the U16_F format from cc.h. */

+#define ip4_addr1(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff)

+#define ip4_addr2(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff)

+#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff)

+#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff)

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_IP_ADDR_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip_frag.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip_frag.h
new file mode 100644
index 0000000..a025ca1
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip_frag.h
@@ -0,0 +1,76 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Jani Monoses <jani@iv.ro>

+ *

+ */

+

+#ifndef __LWIP_IP_FRAG_H__

+#define __LWIP_IP_FRAG_H__

+

+#include "lwip/opt.h"

+#include "lwip/err.h"

+#include "lwip/pbuf.h"

+#include "lwip/netif.h"

+#include "lwip/ip_addr.h"

+#include "lwip/ip.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#if IP_REASSEMBLY

+/* The IP reassembly timer interval in milliseconds. */

+#define IP_TMR_INTERVAL 1000

+

+/* IP reassembly helper struct.

+ * This is exported because memp needs to know the size.

+ */

+struct ip_reassdata {

+  struct ip_reassdata *next;

+  struct pbuf *p;

+  struct ip_hdr iphdr;

+  u16_t datagram_len;

+  u8_t flags;

+  u8_t timer;

+};

+

+void ip_reass_init(void);

+void ip_reass_tmr(void);

+struct pbuf * ip_reass(struct pbuf *p);

+#endif /* IP_REASSEMBLY */

+

+#if IP_FRAG

+err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest);

+#endif /* IP_FRAG */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_IP_FRAG_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/icmp.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/icmp.h
new file mode 100644
index 0000000..cbdf07a
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/icmp.h
@@ -0,0 +1,100 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved. 

+ * 

+ * Redistribution and use in source and binary forms, with or without modification, 

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ * 

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_ICMP_H__

+#define __LWIP_ICMP_H__

+

+#include "lwip/opt.h"

+

+#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/pbuf.h"

+#include "lwip/netif.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#define ICMP6_DUR  1

+#define ICMP6_TE   3

+#define ICMP6_ECHO 128    /* echo */

+#define ICMP6_ER   129      /* echo reply */

+

+

+enum icmp_dur_type {

+  ICMP_DUR_NET = 0,    /* net unreachable */

+  ICMP_DUR_HOST = 1,   /* host unreachable */

+  ICMP_DUR_PROTO = 2,  /* protocol unreachable */

+  ICMP_DUR_PORT = 3,   /* port unreachable */

+  ICMP_DUR_FRAG = 4,   /* fragmentation needed and DF set */

+  ICMP_DUR_SR = 5      /* source route failed */

+};

+

+enum icmp_te_type {

+  ICMP_TE_TTL = 0,     /* time to live exceeded in transit */

+  ICMP_TE_FRAG = 1     /* fragment reassembly time exceeded */

+};

+

+void icmp_input(struct pbuf *p, struct netif *inp);

+

+void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);

+void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);

+

+struct icmp_echo_hdr {

+  u8_t type;

+  u8_t icode;

+  u16_t chksum;

+  u16_t id;

+  u16_t seqno;

+};

+

+struct icmp_dur_hdr {

+  u8_t type;

+  u8_t icode;

+  u16_t chksum;

+  u32_t unused;

+};

+

+struct icmp_te_hdr {

+  u8_t type;

+  u8_t icode;

+  u16_t chksum;

+  u32_t unused;

+};

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* LWIP_ICMP */

+

+#endif /* __LWIP_ICMP_H__ */

+

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/inet.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/inet.h
new file mode 100644
index 0000000..216ebd7
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/inet.h
@@ -0,0 +1,68 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved. 

+ * 

+ * Redistribution and use in source and binary forms, with or without modification, 

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ * 

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_INET_H__

+#define __LWIP_INET_H__

+

+#include "lwip/opt.h"

+#include "lwip/pbuf.h"

+#include "lwip/ip_addr.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+u16_t inet_chksum(void *data, u16_t len);

+u16_t inet_chksum_pbuf(struct pbuf *p);

+u16_t inet_chksum_pseudo(struct pbuf *p,

+       struct ip_addr *src, struct ip_addr *dest,

+       u8_t proto, u32_t proto_len);

+

+u32_t inet_addr(const char *cp);

+s8_t inet_aton(const char *cp, struct in_addr *addr);

+

+#ifndef _MACHINE_ENDIAN_H_

+#ifndef _NETINET_IN_H

+#ifndef _LINUX_BYTEORDER_GENERIC_H

+u16_t htons(u16_t n);

+u16_t ntohs(u16_t n);

+u32_t htonl(u32_t n);

+u32_t ntohl(u32_t n);

+#endif /* _LINUX_BYTEORDER_GENERIC_H */

+#endif /* _NETINET_IN_H */

+#endif /* _MACHINE_ENDIAN_H_ */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_INET_H__ */

+

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/ip.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/ip.h
new file mode 100644
index 0000000..e73bf4b
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/ip.h
@@ -0,0 +1,127 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved. 

+ * 

+ * Redistribution and use in source and binary forms, with or without modification, 

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ * 

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_IP_H__

+#define __LWIP_IP_H__

+

+#include "lwip/opt.h"

+#include "lwip/def.h"

+#include "lwip/pbuf.h"

+#include "lwip/ip_addr.h"

+

+#include "lwip/err.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#define IP_HLEN 40

+

+#define IP_PROTO_ICMP    58

+#define IP_PROTO_UDP     17

+#define IP_PROTO_UDPLITE 136

+#define IP_PROTO_TCP     6

+

+/* This is passed as the destination address to ip_output_if (not

+   to ip_output), meaning that an IP header already is constructed

+   in the pbuf. This is used when TCP retransmits. */

+#ifdef IP_HDRINCL

+#undef IP_HDRINCL

+#endif /* IP_HDRINCL */

+#define IP_HDRINCL  NULL

+

+#if LWIP_NETIF_HWADDRHINT

+#define IP_PCB_ADDRHINT ;u8_t addr_hint

+#else

+#define IP_PCB_ADDRHINT

+#endif /* LWIP_NETIF_HWADDRHINT */

+

+/* This is the common part of all PCB types. It needs to be at the

+   beginning of a PCB type definition. It is located here so that

+   changes to this common part are made in one location instead of

+   having to change all PCB structs. */

+#define IP_PCB struct ip_addr local_ip; \

+  struct ip_addr remote_ip; \

+   /* Socket options */  \

+  u16_t so_options;      \

+   /* Type Of Service */ \

+  u8_t tos;              \

+  /* Time To Live */     \

+  u8_t ttl;              \

+  /* link layer address resolution hint */ \

+  IP_PCB_ADDRHINT

+

+

+/* The IPv6 header. */

+struct ip_hdr {

+#if BYTE_ORDER == LITTLE_ENDIAN

+  u8_t tclass1:4, v:4;

+  u8_t flow1:4, tclass2:4;  

+#else

+  u8_t v:4, tclass1:4;

+  u8_t tclass2:8, flow1:4;

+#endif

+  u16_t flow2;

+  u16_t len;                /* payload length */

+  u8_t nexthdr;             /* next header */

+  u8_t hoplim;              /* hop limit (TTL) */

+  struct ip_addr src, dest;          /* source and destination IP addresses */

+};

+

+#define IPH_PROTO(hdr) (iphdr->nexthdr)

+

+void ip_init(void);

+

+#include "lwip/netif.h"

+

+struct netif *ip_route(struct ip_addr *dest);

+

+void ip_input(struct pbuf *p, struct netif *inp);

+

+/* source and destination addresses in network byte order, please */

+err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,

+         u8_t ttl, u8_t proto);

+

+err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,

+      u8_t ttl, u8_t proto,

+      struct netif *netif);

+

+#if IP_DEBUG

+void ip_debug_print(struct pbuf *p);

+#endif /* IP_DEBUG */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_IP_H__ */

+

+

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/ip_addr.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/ip_addr.h
new file mode 100644
index 0000000..6aeba20
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/ip_addr.h
@@ -0,0 +1,103 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved. 

+ * 

+ * Redistribution and use in source and binary forms, with or without modification, 

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ * 

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_IP_ADDR_H__

+#define __LWIP_IP_ADDR_H__

+

+#include "lwip/opt.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#define IP_ADDR_ANY 0

+

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+ struct ip_addr {

+  PACK_STRUCT_FIELD(u32_t addr[4]);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+/*

+ * struct ipaddr2 is used in the definition of the ARP packet format in

+ * order to support compilers that don't have structure packing.

+ */

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct ip_addr2 {

+  PACK_STRUCT_FIELD(u16_t addrw[2]);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+#define IP6_ADDR(ipaddr, a,b,c,d,e,f,g,h) do { (ipaddr)->addr[0] = htonl((u32_t)((a & 0xffff) << 16) | (b & 0xffff)); \

+                                               (ipaddr)->addr[1] = htonl(((c & 0xffff) << 16) | (d & 0xffff)); \

+                                               (ipaddr)->addr[2] = htonl(((e & 0xffff) << 16) | (f & 0xffff)); \

+                                               (ipaddr)->addr[3] = htonl(((g & 0xffff) << 16) | (h & 0xffff)); } while(0)

+

+u8_t ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,

+        struct ip_addr *mask);

+u8_t ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2);

+void ip_addr_set(struct ip_addr *dest, struct ip_addr *src);

+u8_t ip_addr_isany(struct ip_addr *addr);

+

+#define ip_addr_debug_print(debug, ipaddr) \

+        LWIP_DEBUGF(debug, ("%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F"\n", \

+         (ntohl(ipaddr->addr[0]) >> 16) & 0xffff, \

+         ntohl(ipaddr->addr[0]) & 0xffff, \

+         (ntohl(ipaddr->addr[1]) >> 16) & 0xffff, \

+         ntohl(ipaddr->addr[1]) & 0xffff, \

+         (ntohl(ipaddr->addr[2]) >> 16) & 0xffff, \

+         ntohl(ipaddr->addr[2]) & 0xffff, \

+         (ntohl(ipaddr->addr[3]) >> 16) & 0xffff, \

+         ntohl(ipaddr->addr[3]) & 0xffff));

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_IP_ADDR_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/api.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/api.h
new file mode 100644
index 0000000..c26dada
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/api.h
@@ -0,0 +1,217 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_API_H__

+#define __LWIP_API_H__

+

+#include "lwip/opt.h"

+

+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/netbuf.h"

+#include "lwip/sys.h"

+#include "lwip/ip_addr.h"

+#include "lwip/err.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+/* Throughout this file, IP addresses and port numbers are expected to be in

+ * the same byte order as in the corresponding pcb.

+ */

+

+/* Flags for netconn_write */

+#define NETCONN_NOFLAG 0x00

+#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */

+#define NETCONN_COPY   0x01

+#define NETCONN_MORE   0x02

+

+/* Helpers to process several netconn_types by the same code */

+#define NETCONNTYPE_GROUP(t)    (t&0xF0)

+#define NETCONNTYPE_DATAGRAM(t) (t&0xE0)

+

+enum netconn_type {

+  NETCONN_INVALID    = 0,

+  /* NETCONN_TCP Group */

+  NETCONN_TCP        = 0x10,

+  /* NETCONN_UDP Group */

+  NETCONN_UDP        = 0x20,

+  NETCONN_UDPLITE    = 0x21,

+  NETCONN_UDPNOCHKSUM= 0x22,

+  /* NETCONN_RAW Group */

+  NETCONN_RAW        = 0x40

+};

+

+enum netconn_state {

+  NETCONN_NONE,

+  NETCONN_WRITE,

+  NETCONN_LISTEN,

+  NETCONN_CONNECT,

+  NETCONN_CLOSE

+};

+

+enum netconn_evt {

+  NETCONN_EVT_RCVPLUS,

+  NETCONN_EVT_RCVMINUS,

+  NETCONN_EVT_SENDPLUS,

+  NETCONN_EVT_SENDMINUS

+};

+

+#if LWIP_IGMP

+enum netconn_igmp {

+  NETCONN_JOIN,

+  NETCONN_LEAVE

+};

+#endif /* LWIP_IGMP */

+

+/* forward-declare some structs to avoid to include their headers */

+struct ip_pcb;

+struct tcp_pcb;

+struct udp_pcb;

+struct raw_pcb;

+struct netconn;

+

+/** A callback prototype to inform about events for a netconn */

+typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len);

+

+/** A netconn descriptor */

+struct netconn {

+  /** type of the netconn (TCP, UDP or RAW) */

+  enum netconn_type type;

+  /** current state of the netconn */

+  enum netconn_state state;

+  /** the lwIP internal protocol control block */

+  union {

+    struct ip_pcb  *ip;

+    struct tcp_pcb *tcp;

+    struct udp_pcb *udp;

+    struct raw_pcb *raw;

+  } pcb;

+  /** the last error this netconn had */

+  err_t err;

+  /** sem that is used to synchroneously execute functions in the core context */

+  sys_sem_t op_completed;

+  /** mbox where received packets are stored until they are fetched

+      by the netconn application thread (can grow quite big) */

+  sys_mbox_t recvmbox;

+  /** mbox where new connections are stored until processed

+      by the application thread */

+  sys_mbox_t acceptmbox;

+  /** only used for socket layer */

+  int socket;

+#if LWIP_SO_RCVTIMEO

+  /** timeout to wait for new data to be received

+      (or connections to arrive for listening netconns) */

+  int recv_timeout;

+#endif /* LWIP_SO_RCVTIMEO */

+#if LWIP_SO_RCVBUF

+  /** maximum amount of bytes queued in recvmbox */

+  int recv_bufsize;

+#endif /* LWIP_SO_RCVBUF */

+  u16_t recv_avail;

+  /** TCP: when data passed to netconn_write doesn't fit into the send buffer,

+      this temporarily stores the message. */

+  struct api_msg_msg *write_msg;

+  /** TCP: when data passed to netconn_write doesn't fit into the send buffer,

+      this temporarily stores how much is already sent. */

+  int write_offset;

+#if LWIP_TCPIP_CORE_LOCKING

+  /** TCP: when data passed to netconn_write doesn't fit into the send buffer,

+      this temporarily stores whether to wake up the original application task

+      if data couldn't be sent in the first try. */

+  u8_t write_delayed;

+#endif /* LWIP_TCPIP_CORE_LOCKING */

+  /** A callback function that is informed about events for this netconn */

+  netconn_callback callback;

+};

+

+/* Register an Network connection event */

+#define API_EVENT(c,e,l) if (c->callback) {         \

+                           (*c->callback)(c, e, l); \

+                         }

+

+/* Network connection functions: */

+#define netconn_new(t)                  netconn_new_with_proto_and_callback(t, 0, NULL)

+#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c)

+struct

+netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,

+                                   netconn_callback callback);

+err_t             netconn_delete  (struct netconn *conn);

+enum netconn_type netconn_type    (struct netconn *conn);

+

+err_t             netconn_getaddr (struct netconn *conn,

+                                   struct ip_addr *addr,

+                                   u16_t *port,

+                                   u8_t local);

+#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0)

+#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1)

+

+err_t             netconn_bind    (struct netconn *conn,

+                                   struct ip_addr *addr,

+                                   u16_t port);

+err_t             netconn_connect (struct netconn *conn,

+                                   struct ip_addr *addr,

+                                   u16_t port);

+err_t             netconn_disconnect (struct netconn *conn);

+err_t             netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);

+#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG)

+struct netconn *  netconn_accept  (struct netconn *conn);

+struct netbuf *   netconn_recv    (struct netconn *conn);

+err_t             netconn_sendto  (struct netconn *conn,

+                                   struct netbuf *buf, struct ip_addr *addr, u16_t port);

+err_t             netconn_send    (struct netconn *conn,

+                                   struct netbuf *buf);

+err_t             netconn_write   (struct netconn *conn,

+                                   const void *dataptr, int size,

+                                   u8_t apiflags);

+err_t             netconn_close   (struct netconn *conn);

+

+#if LWIP_IGMP

+err_t             netconn_join_leave_group (struct netconn *conn,

+                                            struct ip_addr *multiaddr,

+                                            struct ip_addr *interface,

+                                            enum netconn_igmp join_or_leave);

+#endif /* LWIP_IGMP */

+#if LWIP_DNS

+err_t             netconn_gethostbyname(const char *name, struct ip_addr *addr);

+#endif /* LWIP_DNS */

+

+#define netconn_err(conn)          ((conn)->err)

+#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* LWIP_NETCONN */

+

+#endif /* __LWIP_API_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/api_msg.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/api_msg.h
new file mode 100644
index 0000000..7635f9d
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/api_msg.h
@@ -0,0 +1,160 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_API_MSG_H__

+#define __LWIP_API_MSG_H__

+

+#include "lwip/opt.h"

+

+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/ip_addr.h"

+#include "lwip/err.h"

+#include "lwip/sys.h"

+#include "lwip/igmp.h"

+#include "lwip/api.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+/* IP addresses and port numbers are expected to be in

+ * the same byte order as in the corresponding pcb.

+ */

+/** This struct includes everything that is necessary to execute a function

+    for a netconn in another thread context (mainly used to process netconns

+    in the tcpip_thread context to be thread safe). */

+struct api_msg_msg {

+  /** The netconn which to process - always needed: it includes the semaphore

+      which is used to block the application thread until the function finished. */

+  struct netconn *conn;

+  /** Depending on the executed function, one of these union members is used */

+  union {

+    /** used for do_send */

+    struct netbuf *b;

+    /** used for do_newconn */

+    struct {

+      u8_t proto;

+    } n;

+    /** used for do_bind and do_connect */

+    struct {

+      struct ip_addr *ipaddr;

+      u16_t port;

+    } bc;

+    /** used for do_getaddr */

+    struct {

+      struct ip_addr *ipaddr;

+      u16_t *port;

+      u8_t local;

+    } ad;

+    /** used for do_write */

+    struct {

+      const void *dataptr;

+      int len;

+      u8_t apiflags;

+    } w;

+    /** used ofr do_recv */

+    struct {

+      u16_t len;

+    } r;

+#if LWIP_IGMP

+    /** used for do_join_leave_group */

+    struct {

+      struct ip_addr *multiaddr;

+      struct ip_addr *interface;

+      enum netconn_igmp join_or_leave;

+    } jl;

+#endif /* LWIP_IGMP */

+#if TCP_LISTEN_BACKLOG

+    struct {

+      u8_t backlog;

+    } lb;

+#endif /* TCP_LISTEN_BACKLOG */

+  } msg;

+};

+

+/** This struct contains a function to execute in another thread context and

+    a struct api_msg_msg that serves as an argument for this function.

+    This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */

+struct api_msg {

+  /** function to execute in tcpip_thread context */

+  void (* function)(struct api_msg_msg *msg);

+  /** arguments for this function */

+  struct api_msg_msg msg;

+};

+

+#if LWIP_DNS

+/** As do_gethostbyname requires more arguments but doesn't require a netconn,

+    it has its own struct (to avoid struct api_msg getting bigger than necessary).

+    do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg

+    (see netconn_gethostbyname). */

+struct dns_api_msg {

+  /** Hostname to query or dotted IP address string */

+  const char *name;

+  /** Rhe resolved address is stored here */

+  struct ip_addr *addr;

+  /** This semaphore is posted when the name is resolved, the application thread

+      should wait on it. */

+  sys_sem_t sem;

+  /** Errors are given back here */

+  err_t *err;

+};

+#endif /* LWIP_DNS */

+

+void do_newconn         ( struct api_msg_msg *msg);

+void do_delconn         ( struct api_msg_msg *msg);

+void do_bind            ( struct api_msg_msg *msg);

+void do_connect         ( struct api_msg_msg *msg);

+void do_disconnect      ( struct api_msg_msg *msg);

+void do_listen          ( struct api_msg_msg *msg);

+void do_send            ( struct api_msg_msg *msg);

+void do_recv            ( struct api_msg_msg *msg);

+void do_write           ( struct api_msg_msg *msg);

+void do_getaddr         ( struct api_msg_msg *msg);

+void do_close           ( struct api_msg_msg *msg);

+#if LWIP_IGMP

+void do_join_leave_group( struct api_msg_msg *msg);

+#endif /* LWIP_IGMP */

+

+#if LWIP_DNS

+void do_gethostbyname(void *arg);

+#endif /* LWIP_DNS */

+

+struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback);

+void netconn_free(struct netconn *conn);

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* LWIP_NETCONN */

+

+#endif /* __LWIP_API_MSG_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/arch.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/arch.h
new file mode 100644
index 0000000..7ecca8b
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/arch.h
@@ -0,0 +1,228 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_ARCH_H__

+#define __LWIP_ARCH_H__

+

+#ifndef LITTLE_ENDIAN

+#define LITTLE_ENDIAN 1234

+#endif

+

+#ifndef BIG_ENDIAN

+#define BIG_ENDIAN 4321

+#endif

+

+#include "arch/cc.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#ifndef PACK_STRUCT_BEGIN

+#define PACK_STRUCT_BEGIN

+#endif /* PACK_STRUCT_BEGIN */

+

+#ifndef PACK_STRUCT_END

+#define PACK_STRUCT_END

+#endif /* PACK_STRUCT_END */

+

+#ifndef PACK_STRUCT_FIELD

+#define PACK_STRUCT_FIELD(x) x

+#endif /* PACK_STRUCT_FIELD */

+

+

+#ifndef LWIP_UNUSED_ARG

+#define LWIP_UNUSED_ARG(x) (void)x

+#endif /* LWIP_UNUSED_ARG */

+

+

+#ifdef LWIP_PROVIDE_ERRNO

+

+#define  EPERM     1  /* Operation not permitted */

+#define  ENOENT     2  /* No such file or directory */

+#define  ESRCH     3  /* No such process */

+#define  EINTR     4  /* Interrupted system call */

+#define  EIO     5  /* I/O error */

+#define  ENXIO     6  /* No such device or address */

+#define  E2BIG     7  /* Arg list too long */

+#define  ENOEXEC     8  /* Exec format error */

+#define  EBADF     9  /* Bad file number */

+#define  ECHILD    10  /* No child processes */

+#define  EAGAIN    11  /* Try again */

+#define  ENOMEM    12  /* Out of memory */

+#define  EACCES    13  /* Permission denied */

+#define  EFAULT    14  /* Bad address */

+#define  ENOTBLK    15  /* Block device required */

+#define  EBUSY    16  /* Device or resource busy */

+#define  EEXIST    17  /* File exists */

+#define  EXDEV    18  /* Cross-device link */

+#define  ENODEV    19  /* No such device */

+#define  ENOTDIR    20  /* Not a directory */

+#define  EISDIR    21  /* Is a directory */

+#define  EINVAL    22  /* Invalid argument */

+#define  ENFILE    23  /* File table overflow */

+#define  EMFILE    24  /* Too many open files */

+#define  ENOTTY    25  /* Not a typewriter */

+#define  ETXTBSY    26  /* Text file busy */

+#define  EFBIG    27  /* File too large */

+#define  ENOSPC    28  /* No space left on device */

+#define  ESPIPE    29  /* Illegal seek */

+#define  EROFS    30  /* Read-only file system */

+#define  EMLINK    31  /* Too many links */

+#define  EPIPE    32  /* Broken pipe */

+#define  EDOM    33  /* Math argument out of domain of func */

+#define  ERANGE    34  /* Math result not representable */

+#define  EDEADLK    35  /* Resource deadlock would occur */

+#define  ENAMETOOLONG  36  /* File name too long */

+#define  ENOLCK    37  /* No record locks available */

+#define  ENOSYS    38  /* Function not implemented */

+#define  ENOTEMPTY  39  /* Directory not empty */

+#define  ELOOP    40  /* Too many symbolic links encountered */

+#define  EWOULDBLOCK  EAGAIN  /* Operation would block */

+#define  ENOMSG    42  /* No message of desired type */

+#define  EIDRM    43  /* Identifier removed */

+#define  ECHRNG    44  /* Channel number out of range */

+#define  EL2NSYNC  45  /* Level 2 not synchronized */

+#define  EL3HLT    46  /* Level 3 halted */

+#define  EL3RST    47  /* Level 3 reset */

+#define  ELNRNG    48  /* Link number out of range */

+#define  EUNATCH    49  /* Protocol driver not attached */

+#define  ENOCSI    50  /* No CSI structure available */

+#define  EL2HLT    51  /* Level 2 halted */

+#define  EBADE    52  /* Invalid exchange */

+#define  EBADR    53  /* Invalid request descriptor */

+#define  EXFULL    54  /* Exchange full */

+#define  ENOANO    55  /* No anode */

+#define  EBADRQC    56  /* Invalid request code */

+#define  EBADSLT    57  /* Invalid slot */

+

+#define  EDEADLOCK  EDEADLK

+

+#define  EBFONT    59  /* Bad font file format */

+#define  ENOSTR    60  /* Device not a stream */

+#define  ENODATA    61  /* No data available */

+#define  ETIME    62  /* Timer expired */

+#define  ENOSR    63  /* Out of streams resources */

+#define  ENONET    64  /* Machine is not on the network */

+#define  ENOPKG    65  /* Package not installed */

+#define  EREMOTE    66  /* Object is remote */

+#define  ENOLINK    67  /* Link has been severed */

+#define  EADV    68  /* Advertise error */

+#define  ESRMNT    69  /* Srmount error */

+#define  ECOMM    70  /* Communication error on send */

+#define  EPROTO    71  /* Protocol error */

+#define  EMULTIHOP  72  /* Multihop attempted */

+#define  EDOTDOT    73  /* RFS specific error */

+#define  EBADMSG    74  /* Not a data message */

+#define  EOVERFLOW  75  /* Value too large for defined data type */

+#define  ENOTUNIQ  76  /* Name not unique on network */

+#define  EBADFD    77  /* File descriptor in bad state */

+#define  EREMCHG    78  /* Remote address changed */

+#define  ELIBACC    79  /* Can not access a needed shared library */

+#define  ELIBBAD    80  /* Accessing a corrupted shared library */

+#define  ELIBSCN    81  /* .lib section in a.out corrupted */

+#define  ELIBMAX    82  /* Attempting to link in too many shared libraries */

+#define  ELIBEXEC  83  /* Cannot exec a shared library directly */

+#define  EILSEQ    84  /* Illegal byte sequence */

+#define  ERESTART  85  /* Interrupted system call should be restarted */

+#define  ESTRPIPE  86  /* Streams pipe error */

+#define  EUSERS    87  /* Too many users */

+#define  ENOTSOCK  88  /* Socket operation on non-socket */

+#define  EDESTADDRREQ  89  /* Destination address required */

+#define  EMSGSIZE  90  /* Message too long */

+#define  EPROTOTYPE  91  /* Protocol wrong type for socket */

+#define  ENOPROTOOPT  92  /* Protocol not available */

+#define  EPROTONOSUPPORT  93  /* Protocol not supported */

+#define  ESOCKTNOSUPPORT  94  /* Socket type not supported */

+#define  EOPNOTSUPP  95  /* Operation not supported on transport endpoint */

+#define  EPFNOSUPPORT  96  /* Protocol family not supported */

+#define  EAFNOSUPPORT  97  /* Address family not supported by protocol */

+#define  EADDRINUSE  98  /* Address already in use */

+#define  EADDRNOTAVAIL  99  /* Cannot assign requested address */

+#define  ENETDOWN  100  /* Network is down */

+#define  ENETUNREACH  101  /* Network is unreachable */

+#define  ENETRESET  102  /* Network dropped connection because of reset */

+#define  ECONNABORTED  103  /* Software caused connection abort */

+#define  ECONNRESET  104  /* Connection reset by peer */

+#define  ENOBUFS    105  /* No buffer space available */

+#define  EISCONN    106  /* Transport endpoint is already connected */

+#define  ENOTCONN  107  /* Transport endpoint is not connected */

+#define  ESHUTDOWN  108  /* Cannot send after transport endpoint shutdown */

+#define  ETOOMANYREFS  109  /* Too many references: cannot splice */

+#define  ETIMEDOUT  110  /* Connection timed out */

+#define  ECONNREFUSED  111  /* Connection refused */

+#define  EHOSTDOWN  112  /* Host is down */

+#define  EHOSTUNREACH  113  /* No route to host */

+#define  EALREADY  114  /* Operation already in progress */

+#define  EINPROGRESS  115  /* Operation now in progress */

+#define  ESTALE    116  /* Stale NFS file handle */

+#define  EUCLEAN    117  /* Structure needs cleaning */

+#define  ENOTNAM    118  /* Not a XENIX named type file */

+#define  ENAVAIL    119  /* No XENIX semaphores available */

+#define  EISNAM    120  /* Is a named type file */

+#define  EREMOTEIO  121  /* Remote I/O error */

+#define  EDQUOT    122  /* Quota exceeded */

+

+#define  ENOMEDIUM  123  /* No medium found */

+#define  EMEDIUMTYPE  124  /* Wrong medium type */

+

+

+#define ENSROK    0 /* DNS server returned answer with no data */

+#define ENSRNODATA  160 /* DNS server returned answer with no data */

+#define ENSRFORMERR 161 /* DNS server claims query was misformatted */

+#define ENSRSERVFAIL 162  /* DNS server returned general failure */

+#define ENSRNOTFOUND 163  /* Domain name not found */

+#define ENSRNOTIMP  164 /* DNS server does not implement requested operation */

+#define ENSRREFUSED 165 /* DNS server refused query */

+#define ENSRBADQUERY 166  /* Misformatted DNS query */

+#define ENSRBADNAME 167 /* Misformatted domain name */

+#define ENSRBADFAMILY 168 /* Unsupported address family */

+#define ENSRBADRESP 169 /* Misformatted DNS reply */

+#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */

+#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */

+#define ENSROF    172 /* End of file */

+#define ENSRFILE  173 /* Error reading file */

+#define ENSRNOMEM 174 /* Out of memory */

+#define ENSRDESTRUCTION 175 /* Application terminated lookup */

+#define ENSRQUERYDOMAINTOOLONG  176 /* Domain name is too long */

+#define ENSRCNAMELOOP 177 /* Domain name is too long */

+

+#ifndef errno

+extern int errno;

+#endif

+

+#endif /* LWIP_PROVIDE_ERRNO */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_ARCH_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/debug.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/debug.h
new file mode 100644
index 0000000..1e468f6
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/debug.h
@@ -0,0 +1,95 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_DEBUG_H__

+#define __LWIP_DEBUG_H__

+

+#include "lwip/arch.h"

+

+/** lower two bits indicate debug level

+ * - 0 off

+ * - 1 warning

+ * - 2 serious

+ * - 3 severe

+ */

+#define LWIP_DBG_LEVEL_OFF     0x00

+#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */

+#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */

+#define LWIP_DBG_LEVEL_SEVERE  0x03

+#define LWIP_DBG_MASK_LEVEL    0x03

+

+/** flag for LWIP_DEBUGF to enable that debug message */

+#define LWIP_DBG_ON            0x80U

+/** flag for LWIP_DEBUGF to disable that debug message */

+#define LWIP_DBG_OFF           0x00U

+

+/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */

+#define LWIP_DBG_TRACE         0x40U

+/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */

+#define LWIP_DBG_STATE         0x20U

+/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */

+#define LWIP_DBG_FRESH         0x10U

+/** flag for LWIP_DEBUGF to halt after printing this debug message */

+#define LWIP_DBG_HALT          0x08U

+

+#ifndef LWIP_NOASSERT

+#define LWIP_ASSERT(x,y) do { if(!(y)) LWIP_PLATFORM_ASSERT(x); } while(0)

+#else  /* LWIP_NOASSERT */

+#define LWIP_ASSERT(x,y)

+#endif /* LWIP_NOASSERT */

+

+/** print "m" message only if "e" is true, and execute "h" expression */

+#ifndef LWIP_ERROR

+#define LWIP_ERROR(m,e,h) do { if (!(e)) { LWIP_PLATFORM_ASSERT(m); h;}} while(0)

+#endif /* LWIP_ERROR */

+

+#ifdef LWIP_DEBUG

+/** print debug message only if debug message type is enabled...

+ *  AND is of correct type AND is at least LWIP_DBG_LEVEL

+ */

+#define LWIP_DEBUGF(debug,x) do { \

+                               if ( \

+                                   ((debug) & LWIP_DBG_ON) && \

+                                   ((debug) & LWIP_DBG_TYPES_ON) && \

+                                   ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \

+                                 LWIP_PLATFORM_DIAG(x); \

+                                 if ((debug) & LWIP_DBG_HALT) { \

+                                   while(1); \

+                                 } \

+                               } \

+                             } while(0)

+

+#else  /* LWIP_DEBUG */

+#define LWIP_DEBUGF(debug,x)

+#endif /* LWIP_DEBUG */

+

+#endif /* __LWIP_DEBUG_H__ */

+

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/def.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/def.h
new file mode 100644
index 0000000..f64c120
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/def.h
@@ -0,0 +1,47 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_DEF_H__

+#define __LWIP_DEF_H__

+

+/* this might define NULL already */

+#include "lwip/arch.h"

+

+#define LWIP_MAX(x , y)  (((x) > (y)) ? (x) : (y))

+#define LWIP_MIN(x , y)  (((x) < (y)) ? (x) : (y))

+

+#ifndef NULL

+#define NULL ((void *)0)

+#endif

+

+

+#endif /* __LWIP_DEF_H__ */

+

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/dhcp.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/dhcp.h
new file mode 100644
index 0000000..1644690
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/dhcp.h
@@ -0,0 +1,249 @@
+/** @file

+ */

+

+#ifndef __LWIP_DHCP_H__

+#define __LWIP_DHCP_H__

+

+#include "lwip/opt.h"

+

+#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/netif.h"

+#include "lwip/udp.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+/** period (in seconds) of the application calling dhcp_coarse_tmr() */

+#define DHCP_COARSE_TIMER_SECS 60

+/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */

+#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS*1000)

+/** period (in milliseconds) of the application calling dhcp_fine_tmr() */

+#define DHCP_FINE_TIMER_MSECS 500

+

+struct dhcp

+{

+  /** current DHCP state machine state */

+  u8_t state;

+  /** retries of current request */

+  u8_t tries;

+  /** transaction identifier of last sent request */

+  u32_t xid;

+  /** our connection to the DHCP server */

+  struct udp_pcb *pcb;

+  /** (first) pbuf of incoming msg */

+  struct pbuf *p;

+  /** incoming msg */

+  struct dhcp_msg *msg_in;

+  /** incoming msg options */

+  struct dhcp_msg *options_in;

+  /** ingoing msg options length */

+  u16_t options_in_len;

+

+  struct pbuf *p_out; /* pbuf of outcoming msg */

+  struct dhcp_msg *msg_out; /* outgoing msg */

+  u16_t options_out_len; /* outgoing msg options length */

+  u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */

+  u16_t t1_timeout;  /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */

+  u16_t t2_timeout;  /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */

+  struct ip_addr server_ip_addr; /* dhcp server address that offered this lease */

+  struct ip_addr offered_ip_addr;

+  struct ip_addr offered_sn_mask;

+  struct ip_addr offered_gw_addr;

+  struct ip_addr offered_bc_addr;

+#define DHCP_MAX_DNS 2

+  u32_t dns_count; /* actual number of DNS servers obtained */

+  struct ip_addr offered_dns_addr[DHCP_MAX_DNS]; /* DNS server addresses */

+

+  u32_t offered_t0_lease; /* lease period (in seconds) */

+  u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */

+  u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period)  */

+#if LWIP_DHCP_AUTOIP_COOP

+  u8_t autoip_coop_state;

+#endif

+/** Patch #1308

+ *  TODO: See dhcp.c "TODO"s

+ */

+#if 0

+  struct ip_addr offered_si_addr;

+  u8_t *boot_file_name;

+#endif

+};

+

+/* MUST be compiled with "pack structs" or equivalent! */

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+/** minimum set of fields of any DHCP message */

+struct dhcp_msg

+{

+  PACK_STRUCT_FIELD(u8_t op);

+  PACK_STRUCT_FIELD(u8_t htype);

+  PACK_STRUCT_FIELD(u8_t hlen);

+  PACK_STRUCT_FIELD(u8_t hops);

+  PACK_STRUCT_FIELD(u32_t xid);

+  PACK_STRUCT_FIELD(u16_t secs);

+  PACK_STRUCT_FIELD(u16_t flags);

+  PACK_STRUCT_FIELD(struct ip_addr ciaddr);

+  PACK_STRUCT_FIELD(struct ip_addr yiaddr);

+  PACK_STRUCT_FIELD(struct ip_addr siaddr);

+  PACK_STRUCT_FIELD(struct ip_addr giaddr);

+#define DHCP_CHADDR_LEN 16U

+  PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);

+#define DHCP_SNAME_LEN 64U

+  PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);

+#define DHCP_FILE_LEN 128U

+  PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);

+  PACK_STRUCT_FIELD(u32_t cookie);

+#define DHCP_MIN_OPTIONS_LEN 68U

+/** make sure user does not configure this too small */

+#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN))

+#  undef DHCP_OPTIONS_LEN

+#endif

+/** allow this to be configured in lwipopts.h, but not too small */

+#if (!defined(DHCP_OPTIONS_LEN))

+/** set this to be sufficient for your options in outgoing DHCP msgs */

+#  define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN

+#endif

+  PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+/** start DHCP configuration */

+err_t dhcp_start(struct netif *netif);

+/** enforce early lease renewal (not needed normally)*/

+err_t dhcp_renew(struct netif *netif);

+/** release the DHCP lease, usually called before dhcp_stop()*/

+err_t dhcp_release(struct netif *netif);

+/** stop DHCP configuration */

+void dhcp_stop(struct netif *netif);

+/** inform server of our manual IP address */

+void dhcp_inform(struct netif *netif);

+

+/** if enabled, check whether the offered IP address is not in use, using ARP */

+#if DHCP_DOES_ARP_CHECK

+void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr);

+#endif

+

+/** to be called every minute */

+void dhcp_coarse_tmr(void);

+/** to be called every half second */

+void dhcp_fine_tmr(void);

+

+/** DHCP message item offsets and length */

+#define DHCP_MSG_OFS (UDP_DATA_OFS)

+  #define DHCP_OP_OFS (DHCP_MSG_OFS + 0)

+  #define DHCP_HTYPE_OFS (DHCP_MSG_OFS + 1)

+  #define DHCP_HLEN_OFS (DHCP_MSG_OFS + 2)

+  #define DHCP_HOPS_OFS (DHCP_MSG_OFS + 3)

+  #define DHCP_XID_OFS (DHCP_MSG_OFS + 4)

+  #define DHCP_SECS_OFS (DHCP_MSG_OFS + 8)

+  #define DHCP_FLAGS_OFS (DHCP_MSG_OFS + 10)

+  #define DHCP_CIADDR_OFS (DHCP_MSG_OFS + 12)

+  #define DHCP_YIADDR_OFS (DHCP_MSG_OFS + 16)

+  #define DHCP_SIADDR_OFS (DHCP_MSG_OFS + 20)

+  #define DHCP_GIADDR_OFS (DHCP_MSG_OFS + 24)

+  #define DHCP_CHADDR_OFS (DHCP_MSG_OFS + 28)

+  #define DHCP_SNAME_OFS (DHCP_MSG_OFS + 44)

+  #define DHCP_FILE_OFS (DHCP_MSG_OFS + 108)

+#define DHCP_MSG_LEN 236

+

+#define DHCP_COOKIE_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN)

+#define DHCP_OPTIONS_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN + 4)

+

+#define DHCP_CLIENT_PORT 68

+#define DHCP_SERVER_PORT 67

+

+/** DHCP client states */

+#define DHCP_REQUESTING 1

+#define DHCP_INIT 2

+#define DHCP_REBOOTING 3

+#define DHCP_REBINDING 4

+#define DHCP_RENEWING 5

+#define DHCP_SELECTING 6

+#define DHCP_INFORMING 7

+#define DHCP_CHECKING 8

+#define DHCP_PERMANENT 9

+#define DHCP_BOUND 10

+/** not yet implemented #define DHCP_RELEASING 11 */

+#define DHCP_BACKING_OFF 12

+#define DHCP_OFF 13

+

+/** AUTOIP cooperatation flags */

+#define DHCP_AUTOIP_COOP_STATE_OFF 0

+#define DHCP_AUTOIP_COOP_STATE_ON 1

+

+#define DHCP_BOOTREQUEST 1

+#define DHCP_BOOTREPLY 2

+

+#define DHCP_DISCOVER 1

+#define DHCP_OFFER 2

+#define DHCP_REQUEST 3

+#define DHCP_DECLINE 4

+#define DHCP_ACK 5

+#define DHCP_NAK 6

+#define DHCP_RELEASE 7

+#define DHCP_INFORM 8

+

+#define DHCP_HTYPE_ETH 1

+

+#define DHCP_HLEN_ETH 6

+

+#define DHCP_BROADCAST_FLAG 15

+#define DHCP_BROADCAST_MASK (1 << DHCP_FLAG_BROADCAST)

+

+/** BootP options */

+#define DHCP_OPTION_PAD 0

+#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */

+#define DHCP_OPTION_ROUTER 3

+#define DHCP_OPTION_DNS_SERVER 6

+#define DHCP_OPTION_HOSTNAME 12

+#define DHCP_OPTION_IP_TTL 23

+#define DHCP_OPTION_MTU 26

+#define DHCP_OPTION_BROADCAST 28

+#define DHCP_OPTION_TCP_TTL 37

+#define DHCP_OPTION_END 255

+

+/** DHCP options */

+#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */

+#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */

+#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */

+

+#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */

+#define DHCP_OPTION_MESSAGE_TYPE_LEN 1

+

+

+#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */

+#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */

+

+#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */

+#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2

+

+#define DHCP_OPTION_T1 58 /* T1 renewal time */

+#define DHCP_OPTION_T2 59 /* T2 rebinding time */

+#define DHCP_OPTION_US 60

+#define DHCP_OPTION_CLIENT_ID 61

+#define DHCP_OPTION_TFTP_SERVERNAME 66

+#define DHCP_OPTION_BOOTFILE 67

+

+/** possible combinations of overloading the file and sname fields with options */

+#define DHCP_OVERLOAD_NONE 0

+#define DHCP_OVERLOAD_FILE 1

+#define DHCP_OVERLOAD_SNAME  2

+#define DHCP_OVERLOAD_SNAME_FILE 3

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* LWIP_DHCP */

+

+#endif /*__LWIP_DHCP_H__*/

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/dns.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/dns.h
new file mode 100644
index 0000000..851fe58
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/dns.h
@@ -0,0 +1,92 @@
+/**

+ * lwip DNS resolver header file.

+

+ * Author: Jim Pettinato

+ *   April 2007

+

+ * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ * 1. Redistributions of source code must retain the above copyright

+ *    notice, this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright

+ *    notice, this list of conditions and the following disclaimer in the

+ *    documentation and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote

+ *    products derived from this software without specific prior

+ *    written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS

+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY

+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL

+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE

+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,

+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING

+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ */

+

+#ifndef __LWIP_DNS_H__

+#define __LWIP_DNS_H__

+

+#include "lwip/opt.h"

+

+#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */

+

+/** DNS timer period */

+#define DNS_TMR_INTERVAL          1000

+

+/** DNS field TYPE used for "Resource Records" */

+#define DNS_RRTYPE_A              1     /* a host address */

+#define DNS_RRTYPE_NS             2     /* an authoritative name server */

+#define DNS_RRTYPE_MD             3     /* a mail destination (Obsolete - use MX) */

+#define DNS_RRTYPE_MF             4     /* a mail forwarder (Obsolete - use MX) */

+#define DNS_RRTYPE_CNAME          5     /* the canonical name for an alias */

+#define DNS_RRTYPE_SOA            6     /* marks the start of a zone of authority */

+#define DNS_RRTYPE_MB             7     /* a mailbox domain name (EXPERIMENTAL) */

+#define DNS_RRTYPE_MG             8     /* a mail group member (EXPERIMENTAL) */

+#define DNS_RRTYPE_MR             9     /* a mail rename domain name (EXPERIMENTAL) */

+#define DNS_RRTYPE_NULL           10    /* a null RR (EXPERIMENTAL) */

+#define DNS_RRTYPE_WKS            11    /* a well known service description */

+#define DNS_RRTYPE_PTR            12    /* a domain name pointer */

+#define DNS_RRTYPE_HINFO          13    /* host information */

+#define DNS_RRTYPE_MINFO          14    /* mailbox or mail list information */

+#define DNS_RRTYPE_MX             15    /* mail exchange */

+#define DNS_RRTYPE_TXT            16    /* text strings */

+

+/** DNS field CLASS used for "Resource Records" */

+#define DNS_RRCLASS_IN            1     /* the Internet */

+#define DNS_RRCLASS_CS            2     /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */

+#define DNS_RRCLASS_CH            3     /* the CHAOS class */

+#define DNS_RRCLASS_HS            4     /* Hesiod [Dyer 87] */

+#define DNS_RRCLASS_FLUSH         0x800 /* Flush bit */

+

+/** Callback which is invoked when a hostname is found.

+ * A function of this type must be implemented by the application using the DNS resolver.

+ * @param name pointer to the name that was looked up.

+ * @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname,

+ *        or NULL if the name could not be found (or on any other error).

+ * @param callback_arg a user-specified callback argument passed to dns_gethostbyname

+*/

+typedef void (*dns_found_callback)(const char *name, struct ip_addr *ipaddr, void *callback_arg);

+

+

+void           dns_init(void);

+

+void           dns_tmr(void);

+

+void           dns_setserver(u8_t numdns, struct ip_addr *dnsserver);

+

+struct ip_addr dns_getserver(u8_t numdns);

+

+err_t          dns_gethostbyname(const char *hostname, struct ip_addr *addr,

+                                 dns_found_callback found, void *callback_arg);

+

+#endif /* LWIP_DNS */

+

+#endif /* __LWIP_DNS_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/err.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/err.h
new file mode 100644
index 0000000..1685fa9
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/err.h
@@ -0,0 +1,81 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_ERR_H__

+#define __LWIP_ERR_H__

+

+#include "lwip/opt.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+typedef s8_t err_t;

+

+/* Definitions for error constants. */

+

+#define ERR_OK          0    /* No error, everything OK. */

+#define ERR_MEM        -1    /* Out of memory error.     */

+#define ERR_BUF        -2    /* Buffer error.            */

+#define ERR_RTE        -3    /* Routing problem.         */

+

+#define ERR_IS_FATAL(e) ((e) < ERR_RTE)

+

+#define ERR_ABRT       -4    /* Connection aborted.      */

+#define ERR_RST        -5    /* Connection reset.        */

+#define ERR_CLSD       -6    /* Connection closed.       */

+#define ERR_CONN       -7    /* Not connected.           */

+

+#define ERR_VAL        -8    /* Illegal value.           */

+

+#define ERR_ARG        -9    /* Illegal argument.        */

+

+#define ERR_USE        -10   /* Address in use.          */

+

+#define ERR_IF         -11   /* Low-level netif error    */

+#define ERR_ISCONN     -12   /* Already connected.       */

+

+#define ERR_TIMEOUT    -13   /* Timeout.                 */

+

+#define ERR_INPROGRESS -14   /* Operation in progress    */

+

+

+#ifdef LWIP_DEBUG

+extern const char *lwip_strerr(err_t err);

+#else

+#define lwip_strerr(x) ""

+#endif /* LWIP_DEBUG */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_ERR_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/init.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/init.h
new file mode 100644
index 0000000..7fe5799
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/init.h
@@ -0,0 +1,48 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_INIT_H__

+#define __LWIP_INIT_H__

+

+#include "lwip/opt.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+/* Modules initialization */

+void lwip_init(void);

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_INIT_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/mem.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/mem.h
new file mode 100644
index 0000000..21c48f8
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/mem.h
@@ -0,0 +1,103 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_MEM_H__

+#define __LWIP_MEM_H__

+

+#include "lwip/opt.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#if MEM_LIBC_MALLOC

+

+#include <stddef.h> /* for size_t */

+

+typedef size_t mem_size_t;

+

+/* aliases for C library malloc() */

+#define mem_init()

+/* in case C library malloc() needs extra protection,

+ * allow these defines to be overridden.

+ */

+#ifndef mem_free

+#define mem_free(x) free(x)

+#endif

+#ifndef mem_malloc

+#define mem_malloc(x) malloc(x)

+#endif

+#ifndef mem_calloc

+#define mem_calloc(x, y) calloc(x, y)

+#endif

+#ifndef mem_realloc

+#define mem_realloc(x, size) (x)

+#endif

+#else /* MEM_LIBC_MALLOC */

+

+/* MEM_SIZE would have to be aligned, but using 64000 here instead of

+ * 65535 leaves some room for alignment...

+ */

+#if MEM_SIZE > 64000l

+typedef u32_t mem_size_t;

+#else

+typedef u16_t mem_size_t;

+#endif /* MEM_SIZE > 64000 */

+

+#if MEM_USE_POOLS

+/** mem_init is not used when using pools instead of a heap */

+#define mem_init()

+/** mem_realloc is not used when using pools instead of a heap:

+    we can't free part of a pool element and don't want to copy the rest */

+#define mem_realloc(mem, size) (mem)

+#else /* MEM_USE_POOLS */

+/* lwIP alternative malloc */

+void  mem_init(void);

+void *mem_realloc(void *mem, mem_size_t size);

+#endif /* MEM_USE_POOLS */

+void *mem_malloc(mem_size_t size);

+void *mem_calloc(mem_size_t count, mem_size_t size);

+void  mem_free(void *mem);

+#endif /* MEM_LIBC_MALLOC */

+

+#ifndef LWIP_MEM_ALIGN_SIZE

+#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))

+#endif

+

+#ifndef LWIP_MEM_ALIGN

+#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1)))

+#endif

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_MEM_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/memp.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/memp.h
new file mode 100644
index 0000000..18f8831
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/memp.h
@@ -0,0 +1,94 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#ifndef __LWIP_MEMP_H__

+#define __LWIP_MEMP_H__

+

+#include "lwip/opt.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+/* Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */

+typedef enum {

+#define LWIP_MEMPOOL(name,num,size,desc)  MEMP_##name,

+#include "lwip/memp_std.h"

+  MEMP_MAX

+} memp_t;

+

+#if MEM_USE_POOLS

+/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */

+typedef enum {

+    /* Get the first (via:

+       MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/

+    MEMP_POOL_HELPER_FIRST = ((u8_t)

+#define LWIP_MEMPOOL(name,num,size,desc)

+#define LWIP_MALLOC_MEMPOOL_START 1

+#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0

+#define LWIP_MALLOC_MEMPOOL_END

+#include "lwip/memp_std.h"

+    ) ,

+    /* Get the last (via:

+       MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */

+    MEMP_POOL_HELPER_LAST = ((u8_t)

+#define LWIP_MEMPOOL(name,num,size,desc)

+#define LWIP_MALLOC_MEMPOOL_START

+#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size *

+#define LWIP_MALLOC_MEMPOOL_END 1

+#include "lwip/memp_std.h"

+    )

+} memp_pool_helper_t;

+

+/* The actual start and stop values are here (cast them over)

+   We use this helper type and these defines so we can avoid using const memp_t values */

+#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST)

+#define MEMP_POOL_LAST   ((memp_t) MEMP_POOL_HELPER_LAST)

+

+extern const u16_t memp_sizes[MEMP_MAX];

+#endif /* MEM_USE_POOLS */

+

+void  memp_init(void);

+

+#if MEMP_OVERFLOW_CHECK

+void *memp_malloc_fn(memp_t type, const char* file, const int line);

+#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__)

+#else

+void *memp_malloc(memp_t type);

+#endif

+void  memp_free(memp_t type, void *mem);

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_MEMP_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/memp_std.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/memp_std.h
new file mode 100644
index 0000000..ac51813
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/memp_std.h
@@ -0,0 +1,101 @@
+/*

+ * SETUP: Make sure we define everything we will need.

+ *

+ * We have create three types of pools:

+ *   1) MEMPOOL - standard pools

+ *   2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c

+ *   3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct

+ *

+ * If the include'r doesn't require any special treatment of each of the types

+ * above, then will declare #2 & #3 to be just standard mempools.

+ */

+#ifndef LWIP_MALLOC_MEMPOOL

+/* This treats "malloc pools" just like any other pool */

+#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, size, "MALLOC_"#size)

+#define LWIP_MALLOC_MEMPOOL_START

+#define LWIP_MALLOC_MEMPOOL_END

+#endif /* LWIP_MALLOC_MEMPOOL */

+

+#ifndef LWIP_PBUF_MEMPOOL

+/* This treats "pbuf pools" just like any other pool.

+ * Allocates buffers for a pbuf struct AND a payload size */

+#define LWIP_PBUF_MEMPOOL(name, num, payload, desc) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc)

+#endif /* LWIP_PBUF_MEMPOOL */

+

+

+/*

+ * A list of internal pools used by LWIP.

+ *

+ * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description)

+ *     creates a pool name MEMP_pool_name. description is used in stats.c

+ */

+#if LWIP_RAW

+LWIP_MEMPOOL(RAW_PCB,        MEMP_NUM_RAW_PCB,         sizeof(struct raw_pcb),        "RAW_PCB")

+#endif /* LWIP_RAW */

+

+#if LWIP_UDP

+LWIP_MEMPOOL(UDP_PCB,        MEMP_NUM_UDP_PCB,         sizeof(struct udp_pcb),        "UDP_PCB")

+#endif /* LWIP_UDP */

+

+#if LWIP_TCP

+LWIP_MEMPOOL(TCP_PCB,        MEMP_NUM_TCP_PCB,         sizeof(struct tcp_pcb),        "TCP_PCB")

+LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN,  sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN")

+LWIP_MEMPOOL(TCP_SEG,        MEMP_NUM_TCP_SEG,         sizeof(struct tcp_seg),        "TCP_SEG")

+#endif /* LWIP_TCP */

+

+#if IP_REASSEMBLY

+LWIP_MEMPOOL(REASSDATA,      MEMP_NUM_REASSDATA,       sizeof(struct ip_reassdata),   "REASSDATA")

+#endif /* IP_REASSEMBLY */

+

+#if LWIP_NETCONN

+LWIP_MEMPOOL(NETBUF,         MEMP_NUM_NETBUF,          sizeof(struct netbuf),         "NETBUF")

+LWIP_MEMPOOL(NETCONN,        MEMP_NUM_NETCONN,         sizeof(struct netconn),        "NETCONN")

+#endif /* LWIP_NETCONN */

+

+#if NO_SYS==0

+LWIP_MEMPOOL(TCPIP_MSG_API,  MEMP_NUM_TCPIP_MSG_API,   sizeof(struct tcpip_msg),      "TCPIP_MSG_API")

+LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg),      "TCPIP_MSG_INPKT")

+#endif /* NO_SYS==0 */

+

+#if ARP_QUEUEING

+LWIP_MEMPOOL(ARP_QUEUE,      MEMP_NUM_ARP_QUEUE,       sizeof(struct etharp_q_entry), "ARP_QUEUE")

+#endif /* ARP_QUEUEING */

+

+#if LWIP_IGMP

+LWIP_MEMPOOL(IGMP_GROUP,     MEMP_NUM_IGMP_GROUP,      sizeof(struct igmp_group),     "IGMP_GROUP")

+#endif /* LWIP_IGMP */

+

+#if NO_SYS==0

+LWIP_MEMPOOL(SYS_TIMEOUT,    MEMP_NUM_SYS_TIMEOUT,     sizeof(struct sys_timeo),      "SYS_TIMEOUT")

+#endif /* NO_SYS==0 */

+

+

+/*

+ * A list of pools of pbuf's used by LWIP.

+ *

+ * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description)

+ *     creates a pool name MEMP_pool_name. description is used in stats.c

+ *     This allocates enough space for the pbuf struct and a payload.

+ *     (Example: pbuf_payload_size=0 allocates only size for the struct)

+ */

+LWIP_PBUF_MEMPOOL(PBUF,      MEMP_NUM_PBUF,            0,                             "PBUF_REF/ROM")

+LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE,           PBUF_POOL_BUFSIZE,             "PBUF_POOL")

+

+

+/*

+ * Allow for user-defined pools; this must be explicitly set in lwipopts.h

+ * since the default is to NOT look for lwippools.h

+ */

+#if MEMP_USE_CUSTOM_POOLS

+#include "lwippools.h"

+#endif /* MEMP_USE_CUSTOM_POOLS */

+

+/*

+ * REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later

+ * (#undef is ignored for something that is not defined)

+ */

+#undef LWIP_MEMPOOL

+#undef LWIP_MALLOC_MEMPOOL

+#undef LWIP_MALLOC_MEMPOOL_START

+#undef LWIP_MALLOC_MEMPOOL_END

+#undef LWIP_PBUF_MEMPOOL

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/netbuf.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/netbuf.h
new file mode 100644
index 0000000..131f8a3
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/netbuf.h
@@ -0,0 +1,76 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_NETBUF_H__

+#define __LWIP_NETBUF_H__

+

+#include "lwip/opt.h"

+#include "lwip/pbuf.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+struct netbuf {

+  struct pbuf *p, *ptr;

+  struct ip_addr *addr;

+  u16_t port;

+};

+

+/* Network buffer functions: */

+struct netbuf *   netbuf_new      (void);

+void              netbuf_delete   (struct netbuf *buf);

+void *            netbuf_alloc    (struct netbuf *buf, u16_t size);

+void              netbuf_free     (struct netbuf *buf);

+err_t             netbuf_ref      (struct netbuf *buf,

+           const void *dataptr, u16_t size);

+void              netbuf_chain    (struct netbuf *head,

+           struct netbuf *tail);

+

+u16_t             netbuf_len      (struct netbuf *buf);

+err_t             netbuf_data     (struct netbuf *buf,

+           void **dataptr, u16_t *len);

+s8_t              netbuf_next     (struct netbuf *buf);

+void              netbuf_first    (struct netbuf *buf);

+

+

+#define netbuf_copy_partial(buf, dataptr, len, offset) \

+  pbuf_copy_partial((buf)->p, (dataptr), (len), (offset))

+#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0)

+#define netbuf_len(buf)              ((buf)->p->tot_len)

+#define netbuf_fromaddr(buf)         ((buf)->addr)

+#define netbuf_fromport(buf)         ((buf)->port)

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_NETBUF_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/netdb.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/netdb.h
new file mode 100644
index 0000000..f344b31
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/netdb.h
@@ -0,0 +1,109 @@
+/*

+ * Redistribution and use in source and binary forms, with or without modification, 

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ * 

+ * Author: Simon Goldschmidt

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_DNS && LWIP_SOCKET

+

+#include "lwip/sockets.h"

+

+/* some rarely used options */

+#ifndef LWIP_DNS_API_DECLARE_H_ERRNO

+#define LWIP_DNS_API_DECLARE_H_ERRNO 1

+#endif

+

+#ifndef LWIP_DNS_API_DEFINE_ERRORS

+#define LWIP_DNS_API_DEFINE_ERRORS 1

+#endif

+

+#ifndef LWIP_DNS_API_DECLARE_STRUCTS

+#define LWIP_DNS_API_DECLARE_STRUCTS 1

+#endif

+

+#if LWIP_DNS_API_DEFINE_ERRORS

+/** Errors used by the DNS API functions, h_errno can be one of them */

+#define EAI_NONAME      200

+#define EAI_SERVICE     201

+#define EAI_FAIL        202

+#define EAI_MEMORY      203

+

+#define HOST_NOT_FOUND  210

+#define NO_DATA         211

+#define NO_RECOVERY     212

+#define TRY_AGAIN       213

+#endif /* LWIP_DNS_API_DEFINE_ERRORS */

+

+#if LWIP_DNS_API_DECLARE_STRUCTS

+struct hostent {

+    char  *h_name;      /* Official name of the host. */

+    char **h_aliases;   /* A pointer to an array of pointers to alternative host names,

+                           terminated by a null pointer. */

+    int    h_addrtype;  /* Address type. */

+    int    h_length;    /* The length, in bytes, of the address. */

+    char **h_addr_list; /* A pointer to an array of pointers to network addresses (in

+                           network byte order) for the host, terminated by a null pointer. */

+#define h_addr h_addr_list[0] /* for backward compatibility */

+};

+

+struct addrinfo {

+    int               ai_flags;      /* Input flags. */

+    int               ai_family;     /* Address family of socket. */

+    int               ai_socktype;   /* Socket type. */

+    int               ai_protocol;   /* Protocol of socket. */

+    socklen_t         ai_addrlen;    /* Length of socket address. */

+    struct sockaddr  *ai_addr;       /* Socket address of socket. */

+    char             *ai_canonname;  /* Canonical name of service location. */

+    struct addrinfo  *ai_next;       /* Pointer to next in list. */

+};

+#endif /* LWIP_DNS_API_DECLARE_STRUCTS */

+

+#if LWIP_DNS_API_DECLARE_H_ERRNO

+/* application accessable error code set by the DNS API functions */

+extern int h_errno;

+#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/

+

+struct hostent *lwip_gethostbyname(const char *name);

+int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,

+                size_t buflen, struct hostent **result, int *h_errnop);

+void lwip_freeaddrinfo(struct addrinfo *ai);

+int lwip_getaddrinfo(const char *nodename,

+       const char *servname,

+       const struct addrinfo *hints,

+       struct addrinfo **res);

+

+#if LWIP_COMPAT_SOCKETS

+#define gethostbyname(name) lwip_gethostbyname(name)

+#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \

+       lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop)

+#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(a)

+#define getaddrinfo(nodname, servname, hints, res) \

+       lwip_getaddrinfo(nodname, servname, hints, res)

+#endif /* LWIP_COMPAT_SOCKETS */

+

+#endif /* LWIP_DNS && LWIP_SOCKET */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/netif.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/netif.h
new file mode 100644
index 0000000..d8a59ae
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/netif.h
@@ -0,0 +1,245 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_NETIF_H__

+#define __LWIP_NETIF_H__

+

+#include "lwip/opt.h"

+

+#include "lwip/err.h"

+

+#include "lwip/ip_addr.h"

+

+#include "lwip/inet.h"

+#include "lwip/pbuf.h"

+#if LWIP_DHCP

+struct dhcp;

+#endif

+#if LWIP_AUTOIP

+struct autoip;

+#endif

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+/* Throughout this file, IP addresses are expected to be in

+ * the same byte order as in IP_PCB. */

+

+/** must be the maximum of all used hardware address lengths

+    across all types of interfaces in use */

+#define NETIF_MAX_HWADDR_LEN 6U

+

+/** TODO: define the use (where, when, whom) of netif flags */

+

+/** whether the network interface is 'up'. this is

+ * a software flag used to control whether this network

+ * interface is enabled and processes traffic.

+ */

+#define NETIF_FLAG_UP           0x01U

+/** if set, the netif has broadcast capability */

+#define NETIF_FLAG_BROADCAST    0x02U

+/** if set, the netif is one end of a point-to-point connection */

+#define NETIF_FLAG_POINTTOPOINT 0x04U

+/** if set, the interface is configured using DHCP */

+#define NETIF_FLAG_DHCP         0x08U

+/** if set, the interface has an active link

+ *  (set by the network interface driver) */

+#define NETIF_FLAG_LINK_UP      0x10U

+/** if set, the netif is an device using ARP */

+#define NETIF_FLAG_ETHARP       0x20U

+/** if set, the netif has IGMP capability */

+#define NETIF_FLAG_IGMP         0x40U

+

+/** Generic data structure used for all lwIP network interfaces.

+ *  The following fields should be filled in by the initialization

+ *  function for the device driver: hwaddr_len, hwaddr[], mtu, flags */

+

+struct netif {

+  /** pointer to next in linked list */

+  struct netif *next;

+

+  /** IP address configuration in network byte order */

+  struct ip_addr ip_addr;

+  struct ip_addr netmask;

+  struct ip_addr gw;

+

+  /** This function is called by the network device driver

+   *  to pass a packet up the TCP/IP stack. */

+  err_t (* input)(struct pbuf *p, struct netif *inp);

+  /** This function is called by the IP module when it wants

+   *  to send a packet on the interface. This function typically

+   *  first resolves the hardware address, then sends the packet. */

+  err_t (* output)(struct netif *netif, struct pbuf *p,

+       struct ip_addr *ipaddr);

+  /** This function is called by the ARP module when it wants

+   *  to send a packet on the interface. This function outputs

+   *  the pbuf as-is on the link medium. */

+  err_t (* linkoutput)(struct netif *netif, struct pbuf *p);

+#if LWIP_NETIF_STATUS_CALLBACK

+  /** This function is called when the netif state is set to up or down

+   */

+  void (* status_callback)(struct netif *netif);

+#endif /* LWIP_NETIF_STATUS_CALLBACK */

+#if LWIP_NETIF_LINK_CALLBACK

+  /** This function is called when the netif link is set to up or down

+   */

+  void (* link_callback)(struct netif *netif);

+#endif /* LWIP_NETIF_LINK_CALLBACK */

+  /** This field can be set by the device driver and could point

+   *  to state information for the device. */

+  void *state;

+#if LWIP_DHCP

+  /** the DHCP client state information for this netif */

+  struct dhcp *dhcp;

+#endif /* LWIP_DHCP */

+#if LWIP_AUTOIP

+  /** the AutoIP client state information for this netif */

+  struct autoip *autoip;

+#endif

+#if LWIP_NETIF_HOSTNAME

+  /* the hostname for this netif, NULL is a valid value */

+  char*  hostname;

+#endif /* LWIP_NETIF_HOSTNAME */

+  /** number of bytes used in hwaddr */

+  u8_t hwaddr_len;

+  /** link level hardware address of this interface */

+  u8_t hwaddr[NETIF_MAX_HWADDR_LEN];

+  /** maximum transfer unit (in bytes) */

+  u16_t mtu;

+  /** flags (see NETIF_FLAG_ above) */

+  u8_t flags;

+  /** descriptive abbreviation */

+  char name[2];

+  /** number of this interface */

+  u8_t num;

+#if LWIP_SNMP

+  /** link type (from "snmp_ifType" enum from snmp.h) */

+  u8_t link_type;

+  /** (estimate) link speed */

+  u32_t link_speed;

+  /** timestamp at last change made (up/down) */

+  u32_t ts;

+  /** counters */

+  u32_t ifinoctets;

+  u32_t ifinucastpkts;

+  u32_t ifinnucastpkts;

+  u32_t ifindiscards;

+  u32_t ifoutoctets;

+  u32_t ifoutucastpkts;

+  u32_t ifoutnucastpkts;

+  u32_t ifoutdiscards;

+#endif /* LWIP_SNMP */

+#if LWIP_IGMP

+  /* This function could be called to add or delete a entry in the multicast filter table of the ethernet MAC.*/

+  err_t (*igmp_mac_filter)( struct netif *netif, struct ip_addr *group, u8_t action);

+#endif /* LWIP_IGMP */

+#if LWIP_NETIF_HWADDRHINT

+  u8_t *addr_hint;

+#endif /* LWIP_NETIF_HWADDRHINT */

+};

+

+#if LWIP_SNMP

+#define NETIF_INIT_SNMP(netif, type, speed) \

+  /* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \

+  netif->link_type = type;    \

+  /* your link speed here (units: bits per second) */  \

+  netif->link_speed = speed;  \

+  netif->ts = 0;              \

+  netif->ifinoctets = 0;      \

+  netif->ifinucastpkts = 0;   \

+  netif->ifinnucastpkts = 0;  \

+  netif->ifindiscards = 0;    \

+  netif->ifoutoctets = 0;     \

+  netif->ifoutucastpkts = 0;  \

+  netif->ifoutnucastpkts = 0; \

+  netif->ifoutdiscards = 0

+#else /* LWIP_SNMP */

+#define NETIF_INIT_SNMP(netif, type, speed)

+#endif /* LWIP_SNMP */

+

+

+/** The list of network interfaces. */

+extern struct netif *netif_list;

+/** The default network interface. */

+extern struct netif *netif_default;

+

+#define netif_init() /* Compatibility define, not init needed. */

+

+struct netif *netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,

+      struct ip_addr *gw,

+      void *state,

+      err_t (* init)(struct netif *netif),

+      err_t (* input)(struct pbuf *p, struct netif *netif));

+

+void

+netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask,

+    struct ip_addr *gw);

+void netif_remove(struct netif * netif);

+

+/* Returns a network interface given its name. The name is of the form

+   "et0", where the first two letters are the "name" field in the

+   netif structure, and the digit is in the num field in the same

+   structure. */

+struct netif *netif_find(char *name);

+

+void netif_set_default(struct netif *netif);

+

+void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr);

+void netif_set_netmask(struct netif *netif, struct ip_addr *netmask);

+void netif_set_gw(struct netif *netif, struct ip_addr *gw);

+

+void netif_set_up(struct netif *netif);

+void netif_set_down(struct netif *netif);

+u8_t netif_is_up(struct netif *netif);

+

+#if LWIP_NETIF_STATUS_CALLBACK

+/*

+ * Set callback to be called when interface is brought up/down

+ */

+void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif));

+#endif /* LWIP_NETIF_STATUS_CALLBACK */

+

+#if LWIP_NETIF_LINK_CALLBACK

+void netif_set_link_up(struct netif *netif);

+void netif_set_link_down(struct netif *netif);

+u8_t netif_is_link_up(struct netif *netif);

+/*

+ * Set callback to be called when link is brought up/down

+ */

+void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif));

+#endif /* LWIP_NETIF_LINK_CALLBACK */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_NETIF_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/netifapi.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/netifapi.h
new file mode 100644
index 0000000..88f8d31
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/netifapi.h
@@ -0,0 +1,100 @@
+/*

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ */

+

+#ifndef __LWIP_NETIFAPI_H__

+#define __LWIP_NETIFAPI_H__

+

+#include "lwip/opt.h"

+

+#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/sys.h"

+#include "lwip/netif.h"

+#include "lwip/dhcp.h"

+#include "lwip/autoip.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+struct netifapi_msg_msg {

+#if !LWIP_TCPIP_CORE_LOCKING

+  sys_sem_t sem;

+#endif /* !LWIP_TCPIP_CORE_LOCKING */

+  err_t err;

+  struct netif *netif;

+  union {

+    struct {

+      struct ip_addr *ipaddr;

+      struct ip_addr *netmask;

+      struct ip_addr *gw;

+      void *state;

+      err_t (* init) (struct netif *netif);

+      err_t (* input)(struct pbuf *p, struct netif *netif);

+    } add;

+    struct {

+      void  (* voidfunc)(struct netif *netif);

+      err_t (* errtfunc)(struct netif *netif);

+    } common;

+  } msg;

+};

+

+struct netifapi_msg {

+  void (* function)(struct netifapi_msg_msg *msg);

+  struct netifapi_msg_msg msg;

+};

+

+

+/* API for application */

+err_t netifapi_netif_add       ( struct netif *netif,

+                                 struct ip_addr *ipaddr,

+                                 struct ip_addr *netmask,

+                                 struct ip_addr *gw,

+                                 void *state,

+                                 err_t (* init)(struct netif *netif),

+                                 err_t (* input)(struct pbuf *p, struct netif *netif) );

+

+err_t netifapi_netif_common    ( struct netif *netif,

+                                 void  (* voidfunc)(struct netif *netif),

+                                 err_t (* errtfunc)(struct netif *netif) );

+

+#define netifapi_netif_remove(n)      netifapi_netif_common(n, netif_remove, NULL)

+#define netifapi_netif_set_up(n)      netifapi_netif_common(n, netif_set_up, NULL)

+#define netifapi_netif_set_down(n)    netifapi_netif_common(n, netif_set_down, NULL)

+#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL)

+#define netifapi_dhcp_start(n)        netifapi_netif_common(n, NULL, dhcp_start)

+#define netifapi_dhcp_stop(n)         netifapi_netif_common(n, dhcp_stop, NULL)

+#define netifapi_autoip_start(n)      netifapi_netif_common(n, NULL, autoip_start)

+#define netifapi_autoip_stop(n)       netifapi_netif_common(n, NULL, autoip_stop)

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* LWIP_NETIF_API */

+

+#endif /* __LWIP_NETIFAPI_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/opt.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/opt.h
new file mode 100644
index 0000000..98058b4
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/opt.h
@@ -0,0 +1,1654 @@
+/**

+ * @file

+ *

+ * lwIP Options Configuration

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_OPT_H__

+#define __LWIP_OPT_H__

+

+/*

+ * Include user defined options first. Anything not defined in these files

+ * will be set to standard values. Override anything you dont like!

+ */

+#include "lwipopts.h"

+#include "lwip/debug.h"

+

+/*

+   -----------------------------------------------

+   ---------- Platform specific locking ----------

+   -----------------------------------------------

+*/

+

+/**

+ * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain

+ * critical regions during buffer allocation, deallocation and memory

+ * allocation and deallocation.

+ */

+#ifndef SYS_LIGHTWEIGHT_PROT

+#define SYS_LIGHTWEIGHT_PROT            0

+#endif

+

+/**

+ * NO_SYS==1: Provides VERY minimal functionality. Otherwise,

+ * use lwIP facilities.

+ */

+#ifndef NO_SYS

+#define NO_SYS                          0

+#endif

+

+/**

+ * MEMCPY: override this if you have a faster implementation at hand than the

+ * one included in your C library

+ */

+#ifndef MEMCPY

+#define MEMCPY(dst,src,len)             memcpy(dst,src,len)

+#endif

+

+/**

+ * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a

+ * call to memcpy() if the length is known at compile time and is small.

+ */

+#ifndef SMEMCPY

+#define SMEMCPY(dst,src,len)            memcpy(dst,src,len)

+#endif

+

+/*

+   ------------------------------------

+   ---------- Memory options ----------

+   ------------------------------------

+*/

+/**

+ * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library

+ * instead of the lwip internal allocator. Can save code size if you

+ * already use it.

+ */

+#ifndef MEM_LIBC_MALLOC

+#define MEM_LIBC_MALLOC                 0

+#endif

+

+/**

+ * MEM_ALIGNMENT: should be set to the alignment of the CPU

+ *    4 byte alignment -> #define MEM_ALIGNMENT 4

+ *    2 byte alignment -> #define MEM_ALIGNMENT 2

+ */

+#ifndef MEM_ALIGNMENT

+#define MEM_ALIGNMENT                   1

+#endif

+

+/**

+ * MEM_SIZE: the size of the heap memory. If the application will send

+ * a lot of data that needs to be copied, this should be set high.

+ */

+#ifndef MEM_SIZE

+#define MEM_SIZE                        1600

+#endif

+

+/**

+ * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable

+ * amount of bytes before and after each memp element in every pool and fills

+ * it with a prominent default value.

+ *    MEMP_OVERFLOW_CHECK == 0 no checking

+ *    MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed

+ *    MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time

+ *      memp_malloc() or memp_free() is called (useful but slow!)

+ */

+#ifndef MEMP_OVERFLOW_CHECK

+#define MEMP_OVERFLOW_CHECK             0

+#endif

+

+/**

+ * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make

+ * sure that there are no cycles in the linked lists.

+ */

+#ifndef MEMP_SANITY_CHECK

+#define MEMP_SANITY_CHECK               0

+#endif

+

+/**

+ * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set

+ * of memory pools of various sizes. When mem_malloc is called, an element of

+ * the smallest pool that can provide the lenght needed is returned.

+ */

+#ifndef MEM_USE_POOLS

+#define MEM_USE_POOLS                   0

+#endif

+

+/**

+ * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h

+ * that defines additional pools beyond the "standard" ones required

+ * by lwIP. If you set this to 1, you must have lwippools.h in your

+ * inlude path somewhere.

+ */

+#ifndef MEMP_USE_CUSTOM_POOLS

+#define MEMP_USE_CUSTOM_POOLS           0

+#endif

+

+

+/*

+   ------------------------------------------------

+   ---------- Internal Memory Pool Sizes ----------

+   ------------------------------------------------

+*/

+/**

+ * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF).

+ * If the application sends a lot of data out of ROM (or other static memory),

+ * this should be set high.

+ */

+#ifndef MEMP_NUM_PBUF

+#define MEMP_NUM_PBUF                   16

+#endif

+

+/**

+ * MEMP_NUM_RAW_PCB: Number of raw connection PCBs

+ * (requires the LWIP_RAW option)

+ */

+#ifndef MEMP_NUM_RAW_PCB

+#define MEMP_NUM_RAW_PCB                4

+#endif

+

+/**

+ * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One

+ * per active UDP "connection".

+ * (requires the LWIP_UDP option)

+ */

+#ifndef MEMP_NUM_UDP_PCB

+#define MEMP_NUM_UDP_PCB                4

+#endif

+

+/**

+ * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections.

+ * (requires the LWIP_TCP option)

+ */

+#ifndef MEMP_NUM_TCP_PCB

+#define MEMP_NUM_TCP_PCB                5

+#endif

+

+/**

+ * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections.

+ * (requires the LWIP_TCP option)

+ */

+#ifndef MEMP_NUM_TCP_PCB_LISTEN

+#define MEMP_NUM_TCP_PCB_LISTEN         8

+#endif

+

+/**

+ * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments.

+ * (requires the LWIP_TCP option)

+ */

+#ifndef MEMP_NUM_TCP_SEG

+#define MEMP_NUM_TCP_SEG                16

+#endif

+

+/**

+ * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for

+ * reassembly (whole packets, not fragments!)

+ */

+#ifndef MEMP_NUM_REASSDATA

+#define MEMP_NUM_REASSDATA              5

+#endif

+

+/**

+ * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing

+ * packets (pbufs) that are waiting for an ARP request (to resolve

+ * their destination address) to finish.

+ * (requires the ARP_QUEUEING option)

+ */

+#ifndef MEMP_NUM_ARP_QUEUE

+#define MEMP_NUM_ARP_QUEUE              30

+#endif

+

+/**

+ * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces

+ * can be members et the same time (one per netif - allsystems group -, plus one

+ * per netif membership).

+ * (requires the LWIP_IGMP option)

+ */

+#ifndef MEMP_NUM_IGMP_GROUP

+#define MEMP_NUM_IGMP_GROUP             8

+#endif

+

+/**

+ * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts.

+ * (requires NO_SYS==0)

+ */

+#ifndef MEMP_NUM_SYS_TIMEOUT

+#define MEMP_NUM_SYS_TIMEOUT            3

+#endif

+

+/**

+ * MEMP_NUM_NETBUF: the number of struct netbufs.

+ * (only needed if you use the sequential API, like api_lib.c)

+ */

+#ifndef MEMP_NUM_NETBUF

+#define MEMP_NUM_NETBUF                 2

+#endif

+

+/**

+ * MEMP_NUM_NETCONN: the number of struct netconns.

+ * (only needed if you use the sequential API, like api_lib.c)

+ */

+#ifndef MEMP_NUM_NETCONN

+#define MEMP_NUM_NETCONN                4

+#endif

+

+/**

+ * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used

+ * for callback/timeout API communication.

+ * (only needed if you use tcpip.c)

+ */

+#ifndef MEMP_NUM_TCPIP_MSG_API

+#define MEMP_NUM_TCPIP_MSG_API          8

+#endif

+

+/**

+ * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used

+ * for incoming packets.

+ * (only needed if you use tcpip.c)

+ */

+#ifndef MEMP_NUM_TCPIP_MSG_INPKT

+#define MEMP_NUM_TCPIP_MSG_INPKT        8

+#endif

+

+/**

+ * PBUF_POOL_SIZE: the number of buffers in the pbuf pool.

+ */

+#ifndef PBUF_POOL_SIZE

+#define PBUF_POOL_SIZE                  16

+#endif

+

+/*

+   ---------------------------------

+   ---------- ARP options ----------

+   ---------------------------------

+*/

+/**

+ * LWIP_ARP==1: Enable ARP functionality.

+ */

+#ifndef LWIP_ARP

+#define LWIP_ARP                        1

+#endif

+

+/**

+ * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached.

+ */

+#ifndef ARP_TABLE_SIZE

+#define ARP_TABLE_SIZE                  10

+#endif

+

+/**

+ * ARP_QUEUEING==1: Outgoing packets are queued during hardware address

+ * resolution.

+ */

+#ifndef ARP_QUEUEING

+#define ARP_QUEUEING                    1

+#endif

+

+/**

+ * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be

+ * updated with the source MAC and IP addresses supplied in the packet.

+ * You may want to disable this if you do not trust LAN peers to have the

+ * correct addresses, or as a limited approach to attempt to handle

+ * spoofing. If disabled, lwIP will need to make a new ARP request if

+ * the peer is not already in the ARP table, adding a little latency.

+ */

+#ifndef ETHARP_TRUST_IP_MAC

+#define ETHARP_TRUST_IP_MAC             1

+#endif

+

+/*

+   --------------------------------

+   ---------- IP options ----------

+   --------------------------------

+*/

+/**

+ * IP_FORWARD==1: Enables the ability to forward IP packets across network

+ * interfaces. If you are going to run lwIP on a device with only one network

+ * interface, define this to 0.

+ */

+#ifndef IP_FORWARD

+#define IP_FORWARD                      0

+#endif

+

+/**

+ * IP_OPTIONS_ALLOWED: Defines the behavior for IP options.

+ *      IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped.

+ *      IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed).

+ */

+#ifndef IP_OPTIONS_ALLOWED

+#define IP_OPTIONS_ALLOWED              1

+#endif

+

+/**

+ * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that

+ * this option does not affect outgoing packet sizes, which can be controlled

+ * via IP_FRAG.

+ */

+#ifndef IP_REASSEMBLY

+#define IP_REASSEMBLY                   1

+#endif

+

+/**

+ * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note

+ * that this option does not affect incoming packet sizes, which can be

+ * controlled via IP_REASSEMBLY.

+ */

+#ifndef IP_FRAG

+#define IP_FRAG                         1

+#endif

+

+/**

+ * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally)

+ * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived

+ * in this time, the whole packet is discarded.

+ */

+#ifndef IP_REASS_MAXAGE

+#define IP_REASS_MAXAGE                 3

+#endif

+

+/**

+ * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled.

+ * Since the received pbufs are enqueued, be sure to configure

+ * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive

+ * packets even if the maximum amount of fragments is enqueued for reassembly!

+ */

+#ifndef IP_REASS_MAX_PBUFS

+#define IP_REASS_MAX_PBUFS              10

+#endif

+

+/**

+ * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP

+ * fragmentation. Otherwise pbufs are allocated and reference the original

+ * packet data to be fragmented.

+ */

+#ifndef IP_FRAG_USES_STATIC_BUF

+#define IP_FRAG_USES_STATIC_BUF         1

+#endif

+

+/**

+ * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer

+ * (requires IP_FRAG_USES_STATIC_BUF==1)

+ */

+#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU)

+#define IP_FRAG_MAX_MTU                 1500

+#endif

+

+/**

+ * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers.

+ */

+#ifndef IP_DEFAULT_TTL

+#define IP_DEFAULT_TTL                  255

+#endif

+

+/*

+   ----------------------------------

+   ---------- ICMP options ----------

+   ----------------------------------

+*/

+/**

+ * LWIP_ICMP==1: Enable ICMP module inside the IP stack.

+ * Be careful, disable that make your product non-compliant to RFC1122

+ */

+#ifndef LWIP_ICMP

+#define LWIP_ICMP                       1

+#endif

+

+/**

+ * ICMP_TTL: Default value for Time-To-Live used by ICMP packets.

+ */

+#ifndef ICMP_TTL

+#define ICMP_TTL                       (IP_DEFAULT_TTL)

+#endif

+

+/*

+   ---------------------------------

+   ---------- RAW options ----------

+   ---------------------------------

+*/

+/**

+ * LWIP_RAW==1: Enable application layer to hook into the IP layer itself.

+ */

+#ifndef LWIP_RAW

+#define LWIP_RAW                        1

+#endif

+

+/**

+ * LWIP_RAW==1: Enable application layer to hook into the IP layer itself.

+ */

+#ifndef RAW_TTL

+#define RAW_TTL                        (IP_DEFAULT_TTL)

+#endif

+

+/*

+   ----------------------------------

+   ---------- DHCP options ----------

+   ----------------------------------

+*/

+/**

+ * LWIP_DHCP==1: Enable DHCP module.

+ */

+#ifndef LWIP_DHCP

+#define LWIP_DHCP                       0

+#endif

+

+/**

+ * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address.

+ */

+#ifndef DHCP_DOES_ARP_CHECK

+#define DHCP_DOES_ARP_CHECK             ((LWIP_DHCP) && (LWIP_ARP))

+#endif

+

+/*

+   ------------------------------------

+   ---------- AUTOIP options ----------

+   ------------------------------------

+*/

+/**

+ * LWIP_AUTOIP==1: Enable AUTOIP module.

+ */

+#ifndef LWIP_AUTOIP

+#define LWIP_AUTOIP                     0

+#endif

+

+/**

+ * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on

+ * the same interface at the same time.

+ */

+#ifndef LWIP_DHCP_AUTOIP_COOP

+#define LWIP_DHCP_AUTOIP_COOP           0

+#endif

+

+/*

+   ----------------------------------

+   ---------- SNMP options ----------

+   ----------------------------------

+*/

+/**

+ * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP

+ * transport.

+ */

+#ifndef LWIP_SNMP

+#define LWIP_SNMP                       0

+#endif

+

+/**

+ * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will

+ * allow. At least one request buffer is required.

+ */

+#ifndef SNMP_CONCURRENT_REQUESTS

+#define SNMP_CONCURRENT_REQUESTS        1

+#endif

+

+/**

+ * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap

+ * destination is required

+ */

+#ifndef SNMP_TRAP_DESTINATIONS

+#define SNMP_TRAP_DESTINATIONS          1

+#endif

+

+/**

+ * SNMP_PRIVATE_MIB:

+ */

+#ifndef SNMP_PRIVATE_MIB

+#define SNMP_PRIVATE_MIB                0

+#endif

+

+/**

+ * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not

+ * a safe action and disabled when SNMP_SAFE_REQUESTS = 1).

+ * Unsafe requests are disabled by default!

+ */

+#ifndef SNMP_SAFE_REQUESTS

+#define SNMP_SAFE_REQUESTS              1

+#endif

+

+/*

+   ----------------------------------

+   ---------- IGMP options ----------

+   ----------------------------------

+*/

+/**

+ * LWIP_IGMP==1: Turn on IGMP module.

+ */

+#ifndef LWIP_IGMP

+#define LWIP_IGMP                       0

+#endif

+

+/*

+   ----------------------------------

+   ---------- DNS options -----------

+   ----------------------------------

+*/

+/**

+ * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS

+ * transport.

+ */

+#ifndef LWIP_DNS

+#define LWIP_DNS                        0

+#endif

+

+/** DNS maximum number of entries to maintain locally. */

+#ifndef DNS_TABLE_SIZE

+#define DNS_TABLE_SIZE                  4

+#endif

+

+/** DNS maximum host name length supported in the name table. */

+#ifndef DNS_MAX_NAME_LENGTH

+#define DNS_MAX_NAME_LENGTH             256

+#endif

+

+/** The maximum of DNS servers */

+#ifndef DNS_MAX_SERVERS

+#define DNS_MAX_SERVERS                 2

+#endif

+

+/** DNS do a name checking between the query and the response. */

+#ifndef DNS_DOES_NAME_CHECK

+#define DNS_DOES_NAME_CHECK             1

+#endif

+

+/** DNS use a local buffer if DNS_USES_STATIC_BUF=0, a static one if

+    DNS_USES_STATIC_BUF=1, or a dynamic one if DNS_USES_STATIC_BUF=2.

+    The buffer will be of size DNS_MSG_SIZE */

+#ifndef DNS_USES_STATIC_BUF

+#define DNS_USES_STATIC_BUF             1

+#endif

+

+/** DNS message max. size. Default value is RFC compliant. */

+#ifndef DNS_MSG_SIZE

+#define DNS_MSG_SIZE                    512

+#endif

+

+/*

+   ---------------------------------

+   ---------- UDP options ----------

+   ---------------------------------

+*/

+/**

+ * LWIP_UDP==1: Turn on UDP.

+ */

+#ifndef LWIP_UDP

+#define LWIP_UDP                        1

+#endif

+

+/**

+ * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP)

+ */

+#ifndef LWIP_UDPLITE

+#define LWIP_UDPLITE                    0

+#endif

+

+/**

+ * UDP_TTL: Default Time-To-Live value.

+ */

+#ifndef UDP_TTL

+#define UDP_TTL                         (IP_DEFAULT_TTL)

+#endif

+

+/*

+   ---------------------------------

+   ---------- TCP options ----------

+   ---------------------------------

+*/

+/**

+ * LWIP_TCP==1: Turn on TCP.

+ */

+#ifndef LWIP_TCP

+#define LWIP_TCP                        1

+#endif

+

+/**

+ * TCP_TTL: Default Time-To-Live value.

+ */

+#ifndef TCP_TTL

+#define TCP_TTL                         (IP_DEFAULT_TTL)

+#endif

+

+/**

+ * TCP_WND: The size of a TCP window.

+ */

+#ifndef TCP_WND

+#define TCP_WND                         2048

+#endif

+

+/**

+ * TCP_MAXRTX: Maximum number of retransmissions of data segments.

+ */

+#ifndef TCP_MAXRTX

+#define TCP_MAXRTX                      12

+#endif

+

+/**

+ * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments.

+ */

+#ifndef TCP_SYNMAXRTX

+#define TCP_SYNMAXRTX                   6

+#endif

+

+/**

+ * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order.

+ * Define to 0 if your device is low on memory.

+ */

+#ifndef TCP_QUEUE_OOSEQ

+#define TCP_QUEUE_OOSEQ                 1

+#endif

+

+/**

+ * TCP_MSS: TCP Maximum segment size. (default is 128, a *very*

+ * conservative default.)

+ * For the receive side, this MSS is advertised to the remote side

+ * when opening a connection. For the transmit size, this MSS sets

+ * an upper limit on the MSS advertised by the remote host.

+ */

+#ifndef TCP_MSS

+#define TCP_MSS                         128

+#endif

+

+/**

+ * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really

+ * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which

+ * reflects the available reassembly buffer size at the remote host) and the

+ * largest size permitted by the IP layer" (RFC 1122)

+ * Setting this to 1 enables code that checks TCP_MSS against the MTU of the

+ * netif used for a connection and limits the MSS if it would be too big otherwise.

+ */

+#ifndef TCP_CALCULATE_EFF_SEND_MSS

+#define TCP_CALCULATE_EFF_SEND_MSS      1

+#endif

+

+

+/**

+ * TCP_SND_BUF: TCP sender buffer space (bytes).

+ */

+#ifndef TCP_SND_BUF

+#define TCP_SND_BUF                     256

+#endif

+

+/**

+ * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least

+ * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work.

+ */

+#ifndef TCP_SND_QUEUELEN

+#define TCP_SND_QUEUELEN                (4 * (TCP_SND_BUF/TCP_MSS))

+#endif

+

+/**

+ * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than or equal

+ * to TCP_SND_BUF. It is the amount of space which must be available in the

+ * TCP snd_buf for select to return writable.

+ */

+#ifndef TCP_SNDLOWAT

+#define TCP_SNDLOWAT                    (TCP_SND_BUF/2)

+#endif

+

+/**

+ * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb.

+ */

+#ifndef TCP_LISTEN_BACKLOG

+#define TCP_LISTEN_BACKLOG              0

+#endif

+

+/**

+ * The maximum allowed backlog for TCP listen netconns.

+ * This backlog is used unless another is explicitly specified.

+ * 0xff is the maximum (u8_t).

+ */

+#ifndef TCP_DEFAULT_LISTEN_BACKLOG

+#define TCP_DEFAULT_LISTEN_BACKLOG      0xff

+#endif

+

+/**

+ * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1.

+ *     LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all

+ *         events (accept, sent, etc) that happen in the system.

+ *     LWIP_CALLBACK_API==1: The PCB callback function is called directly

+ *         for the event.

+ */

+#ifndef LWIP_EVENT_API

+#define LWIP_EVENT_API                  0

+#define LWIP_CALLBACK_API               1

+#else

+#define LWIP_EVENT_API                  1

+#define LWIP_CALLBACK_API               0

+#endif

+

+

+/*

+   ----------------------------------

+   ---------- Pbuf options ----------

+   ----------------------------------

+*/

+/**

+ * PBUF_LINK_HLEN: the number of bytes that should be allocated for a

+ * link level header. The default is 14, the standard value for

+ * Ethernet.

+ */

+#ifndef PBUF_LINK_HLEN

+#define PBUF_LINK_HLEN                  14

+#endif

+

+/**

+ * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is

+ * designed to accomodate single full size TCP frame in one pbuf, including

+ * TCP_MSS, IP header, and link header.

+ */

+#ifndef PBUF_POOL_BUFSIZE

+#define PBUF_POOL_BUFSIZE               LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN)

+#endif

+

+/*

+   ------------------------------------------------

+   ---------- Network Interfaces options ----------

+   ------------------------------------------------

+*/

+/**

+ * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname

+ * field.

+ */

+#ifndef LWIP_NETIF_HOSTNAME

+#define LWIP_NETIF_HOSTNAME             0

+#endif

+

+/**

+ * LWIP_NETIF_API==1: Support netif api (in netifapi.c)

+ */

+#ifndef LWIP_NETIF_API

+#define LWIP_NETIF_API                  0

+#endif

+

+/**

+ * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface

+ * changes its up/down status (i.e., due to DHCP IP acquistion)

+ */

+#ifndef LWIP_NETIF_STATUS_CALLBACK

+#define LWIP_NETIF_STATUS_CALLBACK      0

+#endif

+

+/**

+ * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface

+ * whenever the link changes (i.e., link down)

+ */

+#ifndef LWIP_NETIF_LINK_CALLBACK

+#define LWIP_NETIF_LINK_CALLBACK        0

+#endif

+

+/**

+ * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table

+ * indices) in struct netif. TCP and UDP can make use of this to prevent

+ * scanning the ARP table for every sent packet. While this is faster for big

+ * ARP tables or many concurrent connections, it might be counterproductive

+ * if you have a tiny ARP table or if there never are concurrent connections.

+ */

+#ifndef LWIP_NETIF_HWADDRHINT

+#define LWIP_NETIF_HWADDRHINT           0

+#endif

+

+/*

+   ------------------------------------

+   ---------- LOOPIF options ----------

+   ------------------------------------

+*/

+/**

+ * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c

+ */

+#ifndef LWIP_HAVE_LOOPIF

+#define LWIP_HAVE_LOOPIF                0

+#endif

+

+/**

+ * LWIP_LOOPIF_MULTITHREADING: Indicates whether threading is enabled in

+ * the system, as LOOPIF must change how it behaves depending on this setting.

+ * Setting this is needed to avoid reentering non-reentrant functions like

+ * tcp_input().

+ *    LWIP_LOOPIF_MULTITHREADING==1: Indicates that the user is using a

+ *       multithreaded environment like tcpip.c. In this case, netif->input()

+ *       is called directly.

+ *    LWIP_LOOPIF_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup.

+ *       The packets are put on a list and loopif_poll() must be called in

+ *       the main application loop.

+ */

+#ifndef LWIP_LOOPIF_MULTITHREADING

+#define LWIP_LOOPIF_MULTITHREADING      1

+#endif

+

+/*

+   ------------------------------------

+   ---------- Thread options ----------

+   ------------------------------------

+*/

+/**

+ * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread.

+ */

+#ifndef TCPIP_THREAD_NAME

+#define TCPIP_THREAD_NAME              "tcpip_thread"

+#endif

+

+/**

+ * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread.

+ * The stack size value itself is platform-dependent, but is passed to

+ * sys_thread_new() when the thread is created.

+ */

+#ifndef TCPIP_THREAD_STACKSIZE

+#define TCPIP_THREAD_STACKSIZE          0

+#endif

+

+/**

+ * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread.

+ * The priority value itself is platform-dependent, but is passed to

+ * sys_thread_new() when the thread is created.

+ */

+#ifndef TCPIP_THREAD_PRIO

+#define TCPIP_THREAD_PRIO               1

+#endif

+

+/**

+ * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages

+ * The queue size value itself is platform-dependent, but is passed to

+ * sys_mbox_new() when tcpip_init is called.

+ */

+#ifndef TCPIP_MBOX_SIZE

+#define TCPIP_MBOX_SIZE                 0

+#endif

+

+/**

+ * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread.

+ */

+#ifndef SLIPIF_THREAD_NAME

+#define SLIPIF_THREAD_NAME             "slipif_loop"

+#endif

+

+/**

+ * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread.

+ * The stack size value itself is platform-dependent, but is passed to

+ * sys_thread_new() when the thread is created.

+ */

+#ifndef SLIPIF_THREAD_STACKSIZE

+#define SLIPIF_THREAD_STACKSIZE         0

+#endif

+

+/**

+ * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread.

+ * The priority value itself is platform-dependent, but is passed to

+ * sys_thread_new() when the thread is created.

+ */

+#ifndef SLIPIF_THREAD_PRIO

+#define SLIPIF_THREAD_PRIO              1

+#endif

+

+/**

+ * PPP_THREAD_NAME: The name assigned to the pppMain thread.

+ */

+#ifndef PPP_THREAD_NAME

+#define PPP_THREAD_NAME                "pppMain"

+#endif

+

+/**

+ * PPP_THREAD_STACKSIZE: The stack size used by the pppMain thread.

+ * The stack size value itself is platform-dependent, but is passed to

+ * sys_thread_new() when the thread is created.

+ */

+#ifndef PPP_THREAD_STACKSIZE

+#define PPP_THREAD_STACKSIZE            0

+#endif

+

+/**

+ * PPP_THREAD_PRIO: The priority assigned to the pppMain thread.

+ * The priority value itself is platform-dependent, but is passed to

+ * sys_thread_new() when the thread is created.

+ */

+#ifndef PPP_THREAD_PRIO

+#define PPP_THREAD_PRIO                 1

+#endif

+

+/**

+ * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread.

+ */

+#ifndef DEFAULT_THREAD_NAME

+#define DEFAULT_THREAD_NAME            "lwIP"

+#endif

+

+/**

+ * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread.

+ * The stack size value itself is platform-dependent, but is passed to

+ * sys_thread_new() when the thread is created.

+ */

+#ifndef DEFAULT_THREAD_STACKSIZE

+#define DEFAULT_THREAD_STACKSIZE        0

+#endif

+

+/**

+ * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread.

+ * The priority value itself is platform-dependent, but is passed to

+ * sys_thread_new() when the thread is created.

+ */

+#ifndef DEFAULT_THREAD_PRIO

+#define DEFAULT_THREAD_PRIO             1

+#endif

+

+/**

+ * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a

+ * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed

+ * to sys_mbox_new() when the recvmbox is created.

+ */

+#ifndef DEFAULT_RAW_RECVMBOX_SIZE

+#define DEFAULT_RAW_RECVMBOX_SIZE       0

+#endif

+

+/**

+ * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a

+ * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed

+ * to sys_mbox_new() when the recvmbox is created.

+ */

+#ifndef DEFAULT_UDP_RECVMBOX_SIZE

+#define DEFAULT_UDP_RECVMBOX_SIZE       0

+#endif

+

+/**

+ * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a

+ * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed

+ * to sys_mbox_new() when the recvmbox is created.

+ */

+#ifndef DEFAULT_TCP_RECVMBOX_SIZE

+#define DEFAULT_TCP_RECVMBOX_SIZE       0

+#endif

+

+/**

+ * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections.

+ * The queue size value itself is platform-dependent, but is passed to

+ * sys_mbox_new() when the acceptmbox is created.

+ */

+#ifndef DEFAULT_ACCEPTMBOX_SIZE

+#define DEFAULT_ACCEPTMBOX_SIZE         0

+#endif

+

+/*

+   ----------------------------------------------

+   ---------- Sequential layer options ----------

+   ----------------------------------------------

+*/

+/**

+ * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!)

+ * Don't use it if you're not an active lwIP project member

+ */

+#ifndef LWIP_TCPIP_CORE_LOCKING

+#define LWIP_TCPIP_CORE_LOCKING         0

+#endif

+

+/**

+ * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)

+ */

+#ifndef LWIP_NETCONN

+#define LWIP_NETCONN                    1

+#endif

+

+/*

+   ------------------------------------

+   ---------- Socket options ----------

+   ------------------------------------

+*/

+/**

+ * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)

+ */

+#ifndef LWIP_SOCKET

+#define LWIP_SOCKET                     1

+#endif

+

+/**

+ * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names.

+ * (only used if you use sockets.c)

+ */

+#ifndef LWIP_COMPAT_SOCKETS

+#define LWIP_COMPAT_SOCKETS             1

+#endif

+

+/**

+ * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names.

+ * Disable this option if you use a POSIX operating system that uses the same

+ * names (read, write & close). (only used if you use sockets.c)

+ */

+#ifndef LWIP_POSIX_SOCKETS_IO_NAMES

+#define LWIP_POSIX_SOCKETS_IO_NAMES     1

+#endif

+

+/**

+ * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT

+ * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set

+ * in seconds. (does not require sockets.c, and will affect tcp.c)

+ */

+#ifndef LWIP_TCP_KEEPALIVE

+#define LWIP_TCP_KEEPALIVE              0

+#endif

+

+/**

+ * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing.

+ */

+#ifndef LWIP_SO_RCVTIMEO

+#define LWIP_SO_RCVTIMEO                0

+#endif

+

+/**

+ * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing.

+ */

+#ifndef LWIP_SO_RCVBUF

+#define LWIP_SO_RCVBUF                  0

+#endif

+

+/**

+ * SO_REUSE==1: Enable SO_REUSEADDR and SO_REUSEPORT options. DO NOT USE!

+ */

+#ifndef SO_REUSE

+#define SO_REUSE                        0

+#endif

+

+/*

+   ----------------------------------------

+   ---------- Statistics options ----------

+   ----------------------------------------

+*/

+/**

+ * LWIP_STATS==1: Enable statistics collection in lwip_stats.

+ */

+#ifndef LWIP_STATS

+#define LWIP_STATS                      1

+#endif

+

+#if LWIP_STATS

+

+/**

+ * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions.

+ */

+#ifndef LWIP_STATS_DISPLAY

+#define LWIP_STATS_DISPLAY              0

+#endif

+

+/**

+ * LINK_STATS==1: Enable link stats.

+ */

+#ifndef LINK_STATS

+#define LINK_STATS                      1

+#endif

+

+/**

+ * ETHARP_STATS==1: Enable etharp stats.

+ */

+#ifndef ETHARP_STATS

+#define ETHARP_STATS                    (LWIP_ARP)

+#endif

+

+/**

+ * IP_STATS==1: Enable IP stats.

+ */

+#ifndef IP_STATS

+#define IP_STATS                        1

+#endif

+

+/**

+ * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is

+ * on if using either frag or reass.

+ */

+#ifndef IPFRAG_STATS

+#define IPFRAG_STATS                    (IP_REASSEMBLY || IP_FRAG)

+#endif

+

+/**

+ * ICMP_STATS==1: Enable ICMP stats.

+ */

+#ifndef ICMP_STATS

+#define ICMP_STATS                      1

+#endif

+

+/**

+ * IGMP_STATS==1: Enable IGMP stats.

+ */

+#ifndef IGMP_STATS

+#define IGMP_STATS                      (LWIP_IGMP)

+#endif

+

+/**

+ * UDP_STATS==1: Enable UDP stats. Default is on if

+ * UDP enabled, otherwise off.

+ */

+#ifndef UDP_STATS

+#define UDP_STATS                       (LWIP_UDP)

+#endif

+

+/**

+ * TCP_STATS==1: Enable TCP stats. Default is on if TCP

+ * enabled, otherwise off.

+ */

+#ifndef TCP_STATS

+#define TCP_STATS                       (LWIP_TCP)

+#endif

+

+/**

+ * MEM_STATS==1: Enable mem.c stats.

+ */

+#ifndef MEM_STATS

+#define MEM_STATS                       1

+#endif

+

+/**

+ * MEMP_STATS==1: Enable memp.c pool stats.

+ */

+#ifndef MEMP_STATS

+#define MEMP_STATS                      1

+#endif

+

+/**

+ * SYS_STATS==1: Enable system stats (sem and mbox counts, etc).

+ */

+#ifndef SYS_STATS

+#define SYS_STATS                       1

+#endif

+

+#else

+

+#define LINK_STATS                      0

+#define IP_STATS                        0

+#define IPFRAG_STATS                    0

+#define ICMP_STATS                      0

+#define IGMP_STATS                      0

+#define UDP_STATS                       0

+#define TCP_STATS                       0

+#define MEM_STATS                       0

+#define MEMP_STATS                      0

+#define SYS_STATS                       0

+#define LWIP_STATS_DISPLAY              0

+

+#endif /* LWIP_STATS */

+

+/*

+   ---------------------------------

+   ---------- PPP options ----------

+   ---------------------------------

+*/

+/**

+ * PPP_SUPPORT==1: Enable PPP.

+ */

+#ifndef PPP_SUPPORT

+#define PPP_SUPPORT                     0

+#endif

+

+/**

+ * PPPOE_SUPPORT==1: Enable PPP Over Ethernet

+ */

+#ifndef PPPOE_SUPPORT

+#define PPPOE_SUPPORT                   0

+#endif

+

+/**

+ * PPPOS_SUPPORT==1: Enable PPP Over Serial

+ */

+#ifndef PPPOS_SUPPORT

+#define PPPOS_SUPPORT                   PPP_SUPPORT

+#endif

+

+#if PPP_SUPPORT

+

+/**

+ * NUM_PPP: Max PPP sessions.

+ */

+#ifndef NUM_PPP

+#define NUM_PPP                         1

+#endif

+

+/**

+ * PAP_SUPPORT==1: Support PAP.

+ */

+#ifndef PAP_SUPPORT

+#define PAP_SUPPORT                     0

+#endif

+

+/**

+ * CHAP_SUPPORT==1: Support CHAP.

+ */

+#ifndef CHAP_SUPPORT

+#define CHAP_SUPPORT                    0

+#endif

+

+/**

+ * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET!

+ */

+#ifndef MSCHAP_SUPPORT

+#define MSCHAP_SUPPORT                  0

+#endif

+

+/**

+ * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET!

+ */

+#ifndef CBCP_SUPPORT

+#define CBCP_SUPPORT                    0

+#endif

+

+/**

+ * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET!

+ */

+#ifndef CCP_SUPPORT

+#define CCP_SUPPORT                     0

+#endif

+

+/**

+ * VJ_SUPPORT==1: Support VJ header compression.

+ */

+#ifndef VJ_SUPPORT

+#define VJ_SUPPORT                      0

+#endif

+

+/**

+ * MD5_SUPPORT==1: Support MD5 (see also CHAP).

+ */

+#ifndef MD5_SUPPORT

+#define MD5_SUPPORT                     0

+#endif

+

+/*

+ * Timeouts

+ */

+#ifndef FSM_DEFTIMEOUT

+#define FSM_DEFTIMEOUT                  6       /* Timeout time in seconds */

+#endif

+

+#ifndef FSM_DEFMAXTERMREQS

+#define FSM_DEFMAXTERMREQS              2       /* Maximum Terminate-Request transmissions */

+#endif

+

+#ifndef FSM_DEFMAXCONFREQS

+#define FSM_DEFMAXCONFREQS              10      /* Maximum Configure-Request transmissions */

+#endif

+

+#ifndef FSM_DEFMAXNAKLOOPS

+#define FSM_DEFMAXNAKLOOPS              5       /* Maximum number of nak loops */

+#endif

+

+#ifndef UPAP_DEFTIMEOUT

+#define UPAP_DEFTIMEOUT                 6       /* Timeout (seconds) for retransmitting req */

+#endif

+

+#ifndef UPAP_DEFREQTIME

+#define UPAP_DEFREQTIME                 30      /* Time to wait for auth-req from peer */

+#endif

+

+#ifndef CHAP_DEFTIMEOUT

+#define CHAP_DEFTIMEOUT                 6       /* Timeout time in seconds */

+#endif

+

+#ifndef CHAP_DEFTRANSMITS

+#define CHAP_DEFTRANSMITS               10      /* max # times to send challenge */

+#endif

+

+/* Interval in seconds between keepalive echo requests, 0 to disable. */

+#ifndef LCP_ECHOINTERVAL

+#define LCP_ECHOINTERVAL                0

+#endif

+

+/* Number of unanswered echo requests before failure. */

+#ifndef LCP_MAXECHOFAILS

+#define LCP_MAXECHOFAILS                3

+#endif

+

+/* Max Xmit idle time (in jiffies) before resend flag char. */

+#ifndef PPP_MAXIDLEFLAG

+#define PPP_MAXIDLEFLAG                 100

+#endif

+

+/*

+ * Packet sizes

+ *

+ * Note - lcp shouldn't be allowed to negotiate stuff outside these

+ *    limits.  See lcp.h in the pppd directory.

+ * (XXX - these constants should simply be shared by lcp.c instead

+ *    of living in lcp.h)

+ */

+#define PPP_MTU                         1500     /* Default MTU (size of Info field) */

+#ifndef PPP_MAXMTU

+/* #define PPP_MAXMTU  65535 - (PPP_HDRLEN + PPP_FCSLEN) */

+#define PPP_MAXMTU                      1500 /* Largest MTU we allow */

+#endif

+#define PPP_MINMTU                      64

+#define PPP_MRU                         1500     /* default MRU = max length of info field */

+#define PPP_MAXMRU                      1500     /* Largest MRU we allow */

+#ifndef PPP_DEFMRU

+#define PPP_DEFMRU                      296             /* Try for this */

+#endif

+#define PPP_MINMRU                      128             /* No MRUs below this */

+

+

+#define MAXNAMELEN                      256     /* max length of hostname or name for auth */

+#define MAXSECRETLEN                    256     /* max length of password or secret */

+

+#endif /* PPP_SUPPORT */

+

+/*

+   --------------------------------------

+   ---------- Checksum options ----------

+   --------------------------------------

+*/

+/**

+ * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.

+ */

+#ifndef CHECKSUM_GEN_IP

+#define CHECKSUM_GEN_IP                 1

+#endif

+

+/**

+ * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.

+ */

+#ifndef CHECKSUM_GEN_UDP

+#define CHECKSUM_GEN_UDP                1

+#endif

+

+/**

+ * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.

+ */

+#ifndef CHECKSUM_GEN_TCP

+#define CHECKSUM_GEN_TCP                1

+#endif

+

+/**

+ * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.

+ */

+#ifndef CHECKSUM_CHECK_IP

+#define CHECKSUM_CHECK_IP               1

+#endif

+

+/**

+ * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.

+ */

+#ifndef CHECKSUM_CHECK_UDP

+#define CHECKSUM_CHECK_UDP              1

+#endif

+

+/**

+ * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.

+ */

+#ifndef CHECKSUM_CHECK_TCP

+#define CHECKSUM_CHECK_TCP              1

+#endif

+

+/*

+   ---------------------------------------

+   ---------- Debugging options ----------

+   ---------------------------------------

+*/

+/**

+ * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is

+ * compared against this value. If it is smaller, then debugging

+ * messages are written.

+ */

+#ifndef LWIP_DBG_MIN_LEVEL

+#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_OFF

+#endif

+

+/**

+ * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable

+ * debug messages of certain types.

+ */

+#ifndef LWIP_DBG_TYPES_ON

+#define LWIP_DBG_TYPES_ON               LWIP_DBG_ON

+#endif

+

+/**

+ * ETHARP_DEBUG: Enable debugging in etharp.c.

+ */

+#ifndef ETHARP_DEBUG

+#define ETHARP_DEBUG                    LWIP_DBG_OFF

+#endif

+

+/**

+ * NETIF_DEBUG: Enable debugging in netif.c.

+ */

+#ifndef NETIF_DEBUG

+#define NETIF_DEBUG                     LWIP_DBG_OFF

+#endif

+

+/**

+ * PBUF_DEBUG: Enable debugging in pbuf.c.

+ */

+#ifndef PBUF_DEBUG

+#define PBUF_DEBUG                      LWIP_DBG_OFF

+#endif

+

+/**

+ * API_LIB_DEBUG: Enable debugging in api_lib.c.

+ */

+#ifndef API_LIB_DEBUG

+#define API_LIB_DEBUG                   LWIP_DBG_OFF

+#endif

+

+/**

+ * API_MSG_DEBUG: Enable debugging in api_msg.c.

+ */

+#ifndef API_MSG_DEBUG

+#define API_MSG_DEBUG                   LWIP_DBG_OFF

+#endif

+

+/**

+ * SOCKETS_DEBUG: Enable debugging in sockets.c.

+ */

+#ifndef SOCKETS_DEBUG

+#define SOCKETS_DEBUG                   LWIP_DBG_OFF

+#endif

+

+/**

+ * ICMP_DEBUG: Enable debugging in icmp.c.

+ */

+#ifndef ICMP_DEBUG

+#define ICMP_DEBUG                      LWIP_DBG_OFF

+#endif

+

+/**

+ * IGMP_DEBUG: Enable debugging in igmp.c.

+ */

+#ifndef IGMP_DEBUG

+#define IGMP_DEBUG                      LWIP_DBG_OFF

+#endif

+

+/**

+ * INET_DEBUG: Enable debugging in inet.c.

+ */

+#ifndef INET_DEBUG

+#define INET_DEBUG                      LWIP_DBG_OFF

+#endif

+

+/**

+ * IP_DEBUG: Enable debugging for IP.

+ */

+#ifndef IP_DEBUG

+#define IP_DEBUG                        LWIP_DBG_OFF

+#endif

+

+/**

+ * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass.

+ */

+#ifndef IP_REASS_DEBUG

+#define IP_REASS_DEBUG                  LWIP_DBG_OFF

+#endif

+

+/**

+ * RAW_DEBUG: Enable debugging in raw.c.

+ */

+#ifndef RAW_DEBUG

+#define RAW_DEBUG                       LWIP_DBG_OFF

+#endif

+

+/**

+ * MEM_DEBUG: Enable debugging in mem.c.

+ */

+#ifndef MEM_DEBUG

+#define MEM_DEBUG                       LWIP_DBG_OFF

+#endif

+

+/**

+ * MEMP_DEBUG: Enable debugging in memp.c.

+ */

+#ifndef MEMP_DEBUG

+#define MEMP_DEBUG                      LWIP_DBG_OFF

+#endif

+

+/**

+ * SYS_DEBUG: Enable debugging in sys.c.

+ */

+#ifndef SYS_DEBUG

+#define SYS_DEBUG                       LWIP_DBG_OFF

+#endif

+

+/**

+ * TCP_DEBUG: Enable debugging for TCP.

+ */

+#ifndef TCP_DEBUG

+#define TCP_DEBUG                       LWIP_DBG_OFF

+#endif

+

+/**

+ * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug.

+ */

+#ifndef TCP_INPUT_DEBUG

+#define TCP_INPUT_DEBUG                 LWIP_DBG_OFF

+#endif

+

+/**

+ * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit.

+ */

+#ifndef TCP_FR_DEBUG

+#define TCP_FR_DEBUG                    LWIP_DBG_OFF

+#endif

+

+/**

+ * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit

+ * timeout.

+ */

+#ifndef TCP_RTO_DEBUG

+#define TCP_RTO_DEBUG                   LWIP_DBG_OFF

+#endif

+

+/**

+ * TCP_CWND_DEBUG: Enable debugging for TCP congestion window.

+ */

+#ifndef TCP_CWND_DEBUG

+#define TCP_CWND_DEBUG                  LWIP_DBG_OFF

+#endif

+

+/**

+ * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating.

+ */

+#ifndef TCP_WND_DEBUG

+#define TCP_WND_DEBUG                   LWIP_DBG_OFF

+#endif

+

+/**

+ * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions.

+ */

+#ifndef TCP_OUTPUT_DEBUG

+#define TCP_OUTPUT_DEBUG                LWIP_DBG_OFF

+#endif

+

+/**

+ * TCP_RST_DEBUG: Enable debugging for TCP with the RST message.

+ */

+#ifndef TCP_RST_DEBUG

+#define TCP_RST_DEBUG                   LWIP_DBG_OFF

+#endif

+

+/**

+ * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths.

+ */

+#ifndef TCP_QLEN_DEBUG

+#define TCP_QLEN_DEBUG                  LWIP_DBG_OFF

+#endif

+

+/**

+ * UDP_DEBUG: Enable debugging in UDP.

+ */

+#ifndef UDP_DEBUG

+#define UDP_DEBUG                       LWIP_DBG_OFF

+#endif

+

+/**

+ * TCPIP_DEBUG: Enable debugging in tcpip.c.

+ */

+#ifndef TCPIP_DEBUG

+#define TCPIP_DEBUG                     LWIP_DBG_OFF

+#endif

+

+/**

+ * PPP_DEBUG: Enable debugging for PPP.

+ */

+#ifndef PPP_DEBUG

+#define PPP_DEBUG                       LWIP_DBG_OFF

+#endif

+

+/**

+ * SLIP_DEBUG: Enable debugging in slipif.c.

+ */

+#ifndef SLIP_DEBUG

+#define SLIP_DEBUG                      LWIP_DBG_OFF

+#endif

+

+/**

+ * DHCP_DEBUG: Enable debugging in dhcp.c.

+ */

+#ifndef DHCP_DEBUG

+#define DHCP_DEBUG                      LWIP_DBG_OFF

+#endif

+

+/**

+ * AUTOIP_DEBUG: Enable debugging in autoip.c.

+ */

+#ifndef AUTOIP_DEBUG

+#define AUTOIP_DEBUG                    LWIP_DBG_OFF

+#endif

+

+/**

+ * SNMP_MSG_DEBUG: Enable debugging for SNMP messages.

+ */

+#ifndef SNMP_MSG_DEBUG

+#define SNMP_MSG_DEBUG                  LWIP_DBG_OFF

+#endif

+

+/**

+ * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs.

+ */

+#ifndef SNMP_MIB_DEBUG

+#define SNMP_MIB_DEBUG                  LWIP_DBG_OFF

+#endif

+

+/**

+ * DNS_DEBUG: Enable debugging for DNS.

+ */

+#ifndef DNS_DEBUG

+#define DNS_DEBUG                       LWIP_DBG_OFF

+#endif

+

+#endif /* __LWIP_OPT_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/pbuf.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/pbuf.h
new file mode 100644
index 0000000..d02ab45
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/pbuf.h
@@ -0,0 +1,118 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#ifndef __LWIP_PBUF_H__

+#define __LWIP_PBUF_H__

+

+#include "lwip/opt.h"

+#include "lwip/err.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#define PBUF_TRANSPORT_HLEN 20

+#define PBUF_IP_HLEN        20

+

+typedef enum {

+  PBUF_TRANSPORT,

+  PBUF_IP,

+  PBUF_LINK,

+  PBUF_RAW

+} pbuf_layer;

+

+typedef enum {

+  PBUF_RAM, /* pbuf data is stored in RAM */

+  PBUF_ROM, /* pbuf data is stored in ROM */

+  PBUF_REF, /* pbuf comes from the pbuf pool */

+  PBUF_POOL /* pbuf payload refers to RAM */

+} pbuf_type;

+

+

+/** indicates this packet's data should be immediately passed to the application */

+#define PBUF_FLAG_PUSH 0x01U

+

+struct pbuf {

+  /** next pbuf in singly linked pbuf chain */

+  struct pbuf *next;

+

+  /** pointer to the actual data in the buffer */

+  void *payload;

+

+  /**

+   * total length of this buffer and all next buffers in chain

+   * belonging to the same packet.

+   *

+   * For non-queue packet chains this is the invariant:

+   * p->tot_len == p->len + (p->next? p->next->tot_len: 0)

+   */

+  u16_t tot_len;

+

+  /** length of this buffer */

+  u16_t len;

+

+  /** pbuf_type as u8_t instead of enum to save space */

+  u8_t /*pbuf_type*/ type;

+

+  /** misc flags */

+  u8_t flags;

+

+  /**

+   * the reference count always equals the number of pointers

+   * that refer to this pbuf. This can be pointers from an application,

+   * the stack itself, or pbuf->next pointers from a chain.

+   */

+  u16_t ref;

+

+};

+

+/* Initializes the pbuf module. This call is empty for now, but may not be in future. */

+#define pbuf_init()

+

+struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_type type);

+void pbuf_realloc(struct pbuf *p, u16_t size);

+u8_t pbuf_header(struct pbuf *p, s16_t header_size);

+void pbuf_ref(struct pbuf *p);

+void pbuf_ref_chain(struct pbuf *p);

+u8_t pbuf_free(struct pbuf *p);

+u8_t pbuf_clen(struct pbuf *p);

+void pbuf_cat(struct pbuf *head, struct pbuf *tail);

+void pbuf_chain(struct pbuf *head, struct pbuf *tail);

+struct pbuf *pbuf_dechain(struct pbuf *p);

+err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);

+u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset);

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_PBUF_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/raw.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/raw.h
new file mode 100644
index 0000000..8681ce2
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/raw.h
@@ -0,0 +1,97 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_RAW_H__

+#define __LWIP_RAW_H__

+

+#include "lwip/opt.h"

+

+#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/pbuf.h"

+#include "lwip/inet.h"

+#include "lwip/ip.h"

+#include "lwip/ip_addr.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+struct raw_pcb {

+/* Common members of all PCB types */

+  IP_PCB;

+

+  struct raw_pcb *next;

+

+  u8_t protocol;

+

+  /* receive callback function

+   * @param arg user supplied argument (raw_pcb.recv_arg)

+   * @param pcb the raw_pcb which received data

+   * @param p the packet buffer that was received

+   * @param addr the remote IP address from which the packet was received

+   * @return 1 if the packet was 'eaten' (aka. deleted),

+   *         0 if the packet lives on

+   * If returning 1, the callback is responsible for freeing the pbuf

+   * if it's not used any more.

+   */

+  u8_t (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p,

+    struct ip_addr *addr);

+  /* user-supplied argument for the recv callback */

+  void *recv_arg;

+};

+

+/* The following functions is the application layer interface to the

+   RAW code. */

+struct raw_pcb * raw_new        (u8_t proto);

+void             raw_remove     (struct raw_pcb *pcb);

+err_t            raw_bind       (struct raw_pcb *pcb, struct ip_addr *ipaddr);

+err_t            raw_connect    (struct raw_pcb *pcb, struct ip_addr *ipaddr);

+

+void             raw_recv       (struct raw_pcb *pcb,

+                                 u8_t (* recv)(void *arg, struct raw_pcb *pcb,

+                                              struct pbuf *p,

+                                              struct ip_addr *addr),

+                                 void *recv_arg);

+err_t            raw_sendto     (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr);

+err_t            raw_send       (struct raw_pcb *pcb, struct pbuf *p);

+

+/* The following functions are the lower layer interface to RAW. */

+u8_t             raw_input      (struct pbuf *p, struct netif *inp);

+#define raw_init() /* Compatibility define, not init needed. */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* LWIP_RAW */

+

+#endif /* __LWIP_RAW_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/sio.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/sio.h
new file mode 100644
index 0000000..79cf292
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/sio.h
@@ -0,0 +1,71 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved. 

+ * 

+ * Redistribution and use in source and binary forms, with or without modification, 

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ */

+

+/*

+ * This is the interface to the platform specific serial IO module

+ * It needs to be implemented by those platforms which need SLIP or PPP

+ */

+

+#include "lwip/arch.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#ifndef __sio_fd_t_defined

+typedef void * sio_fd_t;

+#endif

+

+#ifndef sio_open

+sio_fd_t sio_open(u8_t);

+#endif

+

+#ifndef sio_send

+void sio_send(u8_t, sio_fd_t);

+#endif

+

+#ifndef sio_recv

+u8_t sio_recv(sio_fd_t);

+#endif

+

+#ifndef sio_read

+u32_t sio_read(sio_fd_t, u8_t *, u32_t);

+#endif

+

+#ifndef sio_write

+u32_t sio_write(sio_fd_t, u8_t *, u32_t);

+#endif

+

+#ifndef sio_read_abort

+void sio_read_abort(sio_fd_t);

+#endif

+

+#ifdef __cplusplus

+}

+#endif

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp.h
new file mode 100644
index 0000000..d775d3e
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp.h
@@ -0,0 +1,364 @@
+/*

+ * Copyright (c) 2001, 2002 Leon Woestenberg <leon.woestenberg@axon.tv>

+ * Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Leon Woestenberg <leon.woestenberg@axon.tv>

+ *

+ */

+#ifndef __LWIP_SNMP_H__

+#define __LWIP_SNMP_H__

+

+#include "lwip/opt.h"

+#include "lwip/netif.h"

+#include "lwip/udp.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+/**

+ * @see RFC1213, "MIB-II, 6. Definitions"

+ */

+enum snmp_ifType {

+  snmp_ifType_other=1,                /* none of the following */

+  snmp_ifType_regular1822,

+  snmp_ifType_hdh1822,

+  snmp_ifType_ddn_x25,

+  snmp_ifType_rfc877_x25,

+  snmp_ifType_ethernet_csmacd,

+  snmp_ifType_iso88023_csmacd,

+  snmp_ifType_iso88024_tokenBus,

+  snmp_ifType_iso88025_tokenRing,

+  snmp_ifType_iso88026_man,

+  snmp_ifType_starLan,

+  snmp_ifType_proteon_10Mbit,

+  snmp_ifType_proteon_80Mbit,

+  snmp_ifType_hyperchannel,

+  snmp_ifType_fddi,

+  snmp_ifType_lapb,

+  snmp_ifType_sdlc,

+  snmp_ifType_ds1,                    /* T-1 */

+  snmp_ifType_e1,                     /* european equiv. of T-1 */

+  snmp_ifType_basicISDN,

+  snmp_ifType_primaryISDN,            /* proprietary serial */

+  snmp_ifType_propPointToPointSerial,

+  snmp_ifType_ppp,

+  snmp_ifType_softwareLoopback,

+  snmp_ifType_eon,                    /* CLNP over IP [11] */

+  snmp_ifType_ethernet_3Mbit,

+  snmp_ifType_nsip,                   /* XNS over IP */

+  snmp_ifType_slip,                   /* generic SLIP */

+  snmp_ifType_ultra,                  /* ULTRA technologies */

+  snmp_ifType_ds3,                    /* T-3 */

+  snmp_ifType_sip,                    /* SMDS */

+  snmp_ifType_frame_relay

+};

+

+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */

+

+/** SNMP "sysuptime" Interval */

+#define SNMP_SYSUPTIME_INTERVAL 10

+

+/** fixed maximum length for object identifier type */

+#define LWIP_SNMP_OBJ_ID_LEN 32

+

+/** internal object identifier representation */

+struct snmp_obj_id

+{

+  u8_t len;

+  s32_t id[LWIP_SNMP_OBJ_ID_LEN];

+};

+

+/* system */

+void snmp_set_sysdesr(u8_t* str, u8_t* len);

+void snmp_set_sysobjid(struct snmp_obj_id *oid);

+void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid);

+void snmp_inc_sysuptime(void);

+void snmp_add_sysuptime(u32_t value);

+void snmp_get_sysuptime(u32_t *value);

+void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen);

+void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen);

+void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen);

+

+/* network interface */

+void snmp_add_ifinoctets(struct netif *ni, u32_t value);

+void snmp_inc_ifinucastpkts(struct netif *ni);

+void snmp_inc_ifinnucastpkts(struct netif *ni);

+void snmp_inc_ifindiscards(struct netif *ni);

+void snmp_add_ifoutoctets(struct netif *ni, u32_t value);

+void snmp_inc_ifoutucastpkts(struct netif *ni);

+void snmp_inc_ifoutnucastpkts(struct netif *ni);

+void snmp_inc_ifoutdiscards(struct netif *ni);

+void snmp_inc_iflist(void);

+void snmp_dec_iflist(void);

+

+/* ARP (for atTable and ipNetToMediaTable) */

+void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip);

+void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip);

+

+/* IP */

+void snmp_inc_ipinreceives(void);

+void snmp_inc_ipinhdrerrors(void);

+void snmp_inc_ipinaddrerrors(void);

+void snmp_inc_ipforwdatagrams(void);

+void snmp_inc_ipinunknownprotos(void);

+void snmp_inc_ipindiscards(void);

+void snmp_inc_ipindelivers(void);

+void snmp_inc_ipoutrequests(void);

+void snmp_inc_ipoutdiscards(void);

+void snmp_inc_ipoutnoroutes(void);

+void snmp_inc_ipreasmreqds(void);

+void snmp_inc_ipreasmoks(void);

+void snmp_inc_ipreasmfails(void);

+void snmp_inc_ipfragoks(void);

+void snmp_inc_ipfragfails(void);

+void snmp_inc_ipfragcreates(void);

+void snmp_inc_iproutingdiscards(void);

+void snmp_insert_ipaddridx_tree(struct netif *ni);

+void snmp_delete_ipaddridx_tree(struct netif *ni);

+void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni);

+void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni);

+

+/* ICMP */

+void snmp_inc_icmpinmsgs(void);

+void snmp_inc_icmpinerrors(void);

+void snmp_inc_icmpindestunreachs(void);

+void snmp_inc_icmpintimeexcds(void);

+void snmp_inc_icmpinparmprobs(void);

+void snmp_inc_icmpinsrcquenchs(void);

+void snmp_inc_icmpinredirects(void);

+void snmp_inc_icmpinechos(void);

+void snmp_inc_icmpinechoreps(void);

+void snmp_inc_icmpintimestamps(void);

+void snmp_inc_icmpintimestampreps(void);

+void snmp_inc_icmpinaddrmasks(void);

+void snmp_inc_icmpinaddrmaskreps(void);

+void snmp_inc_icmpoutmsgs(void);

+void snmp_inc_icmpouterrors(void);

+void snmp_inc_icmpoutdestunreachs(void);

+void snmp_inc_icmpouttimeexcds(void);

+void snmp_inc_icmpoutparmprobs(void);

+void snmp_inc_icmpoutsrcquenchs(void);

+void snmp_inc_icmpoutredirects(void);

+void snmp_inc_icmpoutechos(void);

+void snmp_inc_icmpoutechoreps(void);

+void snmp_inc_icmpouttimestamps(void);

+void snmp_inc_icmpouttimestampreps(void);

+void snmp_inc_icmpoutaddrmasks(void);

+void snmp_inc_icmpoutaddrmaskreps(void);

+

+/* TCP */

+void snmp_inc_tcpactiveopens(void);

+void snmp_inc_tcppassiveopens(void);

+void snmp_inc_tcpattemptfails(void);

+void snmp_inc_tcpestabresets(void);

+void snmp_inc_tcpinsegs(void);

+void snmp_inc_tcpoutsegs(void);

+void snmp_inc_tcpretranssegs(void);

+void snmp_inc_tcpinerrs(void);

+void snmp_inc_tcpoutrsts(void);

+

+/* UDP */

+void snmp_inc_udpindatagrams(void);

+void snmp_inc_udpnoports(void);

+void snmp_inc_udpinerrors(void);

+void snmp_inc_udpoutdatagrams(void);

+void snmp_insert_udpidx_tree(struct udp_pcb *pcb);

+void snmp_delete_udpidx_tree(struct udp_pcb *pcb);

+

+/* SNMP */

+void snmp_inc_snmpinpkts(void);

+void snmp_inc_snmpoutpkts(void);

+void snmp_inc_snmpinbadversions(void);

+void snmp_inc_snmpinbadcommunitynames(void);

+void snmp_inc_snmpinbadcommunityuses(void);

+void snmp_inc_snmpinasnparseerrs(void);

+void snmp_inc_snmpintoobigs(void);

+void snmp_inc_snmpinnosuchnames(void);

+void snmp_inc_snmpinbadvalues(void);

+void snmp_inc_snmpinreadonlys(void);

+void snmp_inc_snmpingenerrs(void);

+void snmp_add_snmpintotalreqvars(u8_t value);

+void snmp_add_snmpintotalsetvars(u8_t value);

+void snmp_inc_snmpingetrequests(void);

+void snmp_inc_snmpingetnexts(void);

+void snmp_inc_snmpinsetrequests(void);

+void snmp_inc_snmpingetresponses(void);

+void snmp_inc_snmpintraps(void);

+void snmp_inc_snmpouttoobigs(void);

+void snmp_inc_snmpoutnosuchnames(void);

+void snmp_inc_snmpoutbadvalues(void);

+void snmp_inc_snmpoutgenerrs(void);

+void snmp_inc_snmpoutgetrequests(void);

+void snmp_inc_snmpoutgetnexts(void);

+void snmp_inc_snmpoutsetrequests(void);

+void snmp_inc_snmpoutgetresponses(void);

+void snmp_inc_snmpouttraps(void);

+void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid);

+void snmp_set_snmpenableauthentraps(u8_t *value);

+void snmp_get_snmpenableauthentraps(u8_t *value);

+

+/* LWIP_SNMP support not available */

+/* define everything to be empty */

+#else

+

+/* system */

+#define snmp_set_sysdesr(str, len)

+#define snmp_set_sysobjid(oid);

+#define snmp_get_sysobjid_ptr(oid)

+#define snmp_inc_sysuptime()

+#define snmp_add_sysuptime(value)

+#define snmp_get_sysuptime(value)

+#define snmp_set_syscontact(ocstr, ocstrlen);

+#define snmp_set_sysname(ocstr, ocstrlen);

+#define snmp_set_syslocation(ocstr, ocstrlen);

+

+/* network interface */

+#define snmp_add_ifinoctets(ni,value)

+#define snmp_inc_ifinucastpkts(ni)

+#define snmp_inc_ifinnucastpkts(ni)

+#define snmp_inc_ifindiscards(ni)

+#define snmp_add_ifoutoctets(ni,value)

+#define snmp_inc_ifoutucastpkts(ni)

+#define snmp_inc_ifoutnucastpkts(ni)

+#define snmp_inc_ifoutdiscards(ni)

+#define snmp_inc_iflist()

+#define snmp_dec_iflist()

+

+/* ARP */

+#define snmp_insert_arpidx_tree(ni,ip)

+#define snmp_delete_arpidx_tree(ni,ip)

+

+/* IP */

+#define snmp_inc_ipinreceives()

+#define snmp_inc_ipinhdrerrors()

+#define snmp_inc_ipinaddrerrors()

+#define snmp_inc_ipforwdatagrams()

+#define snmp_inc_ipinunknownprotos()

+#define snmp_inc_ipindiscards()

+#define snmp_inc_ipindelivers()

+#define snmp_inc_ipoutrequests()

+#define snmp_inc_ipoutdiscards()

+#define snmp_inc_ipoutnoroutes()

+#define snmp_inc_ipreasmreqds()

+#define snmp_inc_ipreasmoks()

+#define snmp_inc_ipreasmfails()

+#define snmp_inc_ipfragoks()

+#define snmp_inc_ipfragfails()

+#define snmp_inc_ipfragcreates()

+#define snmp_inc_iproutingdiscards()

+#define snmp_insert_ipaddridx_tree(ni)

+#define snmp_delete_ipaddridx_tree(ni)

+#define snmp_insert_iprteidx_tree(dflt, ni)

+#define snmp_delete_iprteidx_tree(dflt, ni)

+

+/* ICMP */

+#define snmp_inc_icmpinmsgs()

+#define snmp_inc_icmpinerrors()

+#define snmp_inc_icmpindestunreachs()

+#define snmp_inc_icmpintimeexcds()

+#define snmp_inc_icmpinparmprobs()

+#define snmp_inc_icmpinsrcquenchs()

+#define snmp_inc_icmpinredirects()

+#define snmp_inc_icmpinechos()

+#define snmp_inc_icmpinechoreps()

+#define snmp_inc_icmpintimestamps()

+#define snmp_inc_icmpintimestampreps()

+#define snmp_inc_icmpinaddrmasks()

+#define snmp_inc_icmpinaddrmaskreps()

+#define snmp_inc_icmpoutmsgs()

+#define snmp_inc_icmpouterrors()

+#define snmp_inc_icmpoutdestunreachs()

+#define snmp_inc_icmpouttimeexcds()

+#define snmp_inc_icmpoutparmprobs()

+#define snmp_inc_icmpoutsrcquenchs()

+#define snmp_inc_icmpoutredirects()

+#define snmp_inc_icmpoutechos()

+#define snmp_inc_icmpoutechoreps()

+#define snmp_inc_icmpouttimestamps()

+#define snmp_inc_icmpouttimestampreps()

+#define snmp_inc_icmpoutaddrmasks()

+#define snmp_inc_icmpoutaddrmaskreps()

+/* TCP */

+#define snmp_inc_tcpactiveopens()

+#define snmp_inc_tcppassiveopens()

+#define snmp_inc_tcpattemptfails()

+#define snmp_inc_tcpestabresets()

+#define snmp_inc_tcpinsegs()

+#define snmp_inc_tcpoutsegs()

+#define snmp_inc_tcpretranssegs()

+#define snmp_inc_tcpinerrs()

+#define snmp_inc_tcpoutrsts()

+

+/* UDP */

+#define snmp_inc_udpindatagrams()

+#define snmp_inc_udpnoports()

+#define snmp_inc_udpinerrors()

+#define snmp_inc_udpoutdatagrams()

+#define snmp_insert_udpidx_tree(pcb)

+#define snmp_delete_udpidx_tree(pcb)

+

+/* SNMP */

+#define snmp_inc_snmpinpkts()

+#define snmp_inc_snmpoutpkts()

+#define snmp_inc_snmpinbadversions()

+#define snmp_inc_snmpinbadcommunitynames()

+#define snmp_inc_snmpinbadcommunityuses()

+#define snmp_inc_snmpinasnparseerrs()

+#define snmp_inc_snmpintoobigs()

+#define snmp_inc_snmpinnosuchnames()

+#define snmp_inc_snmpinbadvalues()

+#define snmp_inc_snmpinreadonlys()

+#define snmp_inc_snmpingenerrs()

+#define snmp_add_snmpintotalreqvars(value)

+#define snmp_add_snmpintotalsetvars(value)

+#define snmp_inc_snmpingetrequests()

+#define snmp_inc_snmpingetnexts()

+#define snmp_inc_snmpinsetrequests()

+#define snmp_inc_snmpingetresponses()

+#define snmp_inc_snmpintraps()

+#define snmp_inc_snmpouttoobigs()

+#define snmp_inc_snmpoutnosuchnames()

+#define snmp_inc_snmpoutbadvalues()

+#define snmp_inc_snmpoutgenerrs()

+#define snmp_inc_snmpoutgetrequests()

+#define snmp_inc_snmpoutgetnexts()

+#define snmp_inc_snmpoutsetrequests()

+#define snmp_inc_snmpoutgetresponses()

+#define snmp_inc_snmpouttraps()

+#define snmp_get_snmpgrpid_ptr(oid)

+#define snmp_set_snmpenableauthentraps(value)

+#define snmp_get_snmpenableauthentraps(value)

+

+#endif /* LWIP_SNMP */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_SNMP_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_asn1.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_asn1.h
new file mode 100644
index 0000000..fd1c4ec
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_asn1.h
@@ -0,0 +1,97 @@
+/**

+ * @file

+ * Abstract Syntax Notation One (ISO 8824, 8825) codec.

+ */

+ 

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * Author: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#ifndef __LWIP_SNMP_ASN1_H__

+#define __LWIP_SNMP_ASN1_H__

+

+#include "lwip/opt.h"

+#include "lwip/err.h"

+#include "lwip/pbuf.h"

+#include "lwip/snmp.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#define SNMP_ASN1_UNIV   (!0x80 | !0x40)

+#define SNMP_ASN1_APPLIC (!0x80 |  0x40)

+#define SNMP_ASN1_CONTXT ( 0x80 | !0x40)

+

+#define SNMP_ASN1_CONSTR (0x20)

+#define SNMP_ASN1_PRIMIT (!0x20)

+

+/* universal tags */

+#define SNMP_ASN1_INTEG  2

+#define SNMP_ASN1_OC_STR 4

+#define SNMP_ASN1_NUL    5

+#define SNMP_ASN1_OBJ_ID 6

+#define SNMP_ASN1_SEQ    16

+

+/* application specific (SNMP) tags */

+#define SNMP_ASN1_IPADDR 0    /* octet string size(4) */

+#define SNMP_ASN1_COUNTER 1   /* u32_t */

+#define SNMP_ASN1_GAUGE 2     /* u32_t */

+#define SNMP_ASN1_TIMETICKS 3 /* u32_t */

+#define SNMP_ASN1_OPAQUE 4    /* octet string */

+

+/* context specific (SNMP) tags */

+#define SNMP_ASN1_PDU_GET_REQ 0

+#define SNMP_ASN1_PDU_GET_NEXT_REQ 1

+#define SNMP_ASN1_PDU_GET_RESP 2

+#define SNMP_ASN1_PDU_SET_REQ 3

+#define SNMP_ASN1_PDU_TRAP 4

+

+err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type);

+err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length);

+err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value);

+err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value);

+err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid);

+err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw);

+

+void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed);

+void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed);

+void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);

+void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed);

+err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type);

+err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length);

+err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value);

+err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value);

+err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident);

+err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw);

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_SNMP_ASN1_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_msg.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_msg.h
new file mode 100644
index 0000000..017be6a
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_msg.h
@@ -0,0 +1,307 @@
+/**

+ * @file

+ * SNMP Agent message handling structures.

+ */

+

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * Author: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#ifndef __LWIP_SNMP_MSG_H__

+#define __LWIP_SNMP_MSG_H__

+

+#include "lwip/opt.h"

+#include "lwip/snmp.h"

+#include "lwip/snmp_structs.h"

+

+#if SNMP_PRIVATE_MIB

+#include "private_mib.h"

+#endif

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+/* The listen port of the SNMP agent. Clients have to make their requests to

+   this port. Most standard clients won't work if you change this! */

+#ifndef SNMP_IN_PORT

+#define SNMP_IN_PORT 161

+#endif

+/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't

+   work if you change this! */

+#ifndef SNMP_TRAP_PORT

+#define SNMP_TRAP_PORT 162

+#endif

+

+#define SNMP_ES_NOERROR 0

+#define SNMP_ES_TOOBIG 1

+#define SNMP_ES_NOSUCHNAME 2

+#define SNMP_ES_BADVALUE 3

+#define SNMP_ES_READONLY 4

+#define SNMP_ES_GENERROR 5

+

+#define SNMP_GENTRAP_COLDSTART 0

+#define SNMP_GENTRAP_WARMSTART 1

+#define SNMP_GENTRAP_AUTHFAIL 4

+#define SNMP_GENTRAP_ENTERPRISESPC 6

+

+struct snmp_varbind

+{

+  /* next pointer, NULL for last in list */

+  struct snmp_varbind *next;

+  /* previous pointer, NULL for first in list */

+  struct snmp_varbind *prev;

+

+  /* object identifier length (in s32_t) */

+  u8_t ident_len;

+  /* object identifier array */

+  s32_t *ident;

+

+  /* object value ASN1 type */

+  u8_t value_type;

+  /* object value length (in u8_t) */

+  u8_t value_len;

+  /* object value */

+  void *value;

+

+  /* encoding varbind seq length length */

+  u8_t seqlenlen;

+  /* encoding object identifier length length */

+  u8_t olenlen;

+  /* encoding object value length length */

+  u8_t vlenlen;

+  /* encoding varbind seq length */

+  u16_t seqlen;

+  /* encoding object identifier length */

+  u16_t olen;

+  /* encoding object value length */

+  u16_t vlen;

+};

+

+struct snmp_varbind_root

+{

+  struct snmp_varbind *head;

+  struct snmp_varbind *tail;

+  /* number of variable bindings in list */

+  u8_t count;

+  /* encoding varbind-list seq length length */

+  u8_t seqlenlen;

+  /* encoding varbind-list seq length */

+  u16_t seqlen;

+};

+

+/** output response message header length fields */

+struct snmp_resp_header_lengths

+{

+  /* encoding error-index length length */

+  u8_t erridxlenlen;

+  /* encoding error-status length length */

+  u8_t errstatlenlen;

+  /* encoding request id length length */

+  u8_t ridlenlen;

+  /* encoding pdu length length */

+  u8_t pdulenlen;

+  /* encoding community length length */

+  u8_t comlenlen;

+  /* encoding version length length */

+  u8_t verlenlen;

+  /* encoding sequence length length */

+  u8_t seqlenlen;

+

+  /* encoding error-index length */

+  u16_t erridxlen;

+  /* encoding error-status length */

+  u16_t errstatlen;

+  /* encoding request id length */

+  u16_t ridlen;

+  /* encoding pdu length */

+  u16_t pdulen;

+  /* encoding community length */

+  u16_t comlen;

+  /* encoding version length */

+  u16_t verlen;

+  /* encoding sequence length */

+  u16_t seqlen;

+};

+

+/** output response message header length fields */

+struct snmp_trap_header_lengths

+{

+  /* encoding timestamp length length */

+  u8_t tslenlen;

+  /* encoding specific-trap length length */

+  u8_t strplenlen;

+  /* encoding generic-trap length length */

+  u8_t gtrplenlen;

+  /* encoding agent-addr length length */

+  u8_t aaddrlenlen;

+  /* encoding enterprise-id length length */

+  u8_t eidlenlen;

+  /* encoding pdu length length */

+  u8_t pdulenlen;

+  /* encoding community length length */

+  u8_t comlenlen;

+  /* encoding version length length */

+  u8_t verlenlen;

+  /* encoding sequence length length */

+  u8_t seqlenlen;

+

+  /* encoding timestamp length */

+  u16_t tslen;

+  /* encoding specific-trap length */

+  u16_t strplen;

+  /* encoding generic-trap length */

+  u16_t gtrplen;

+  /* encoding agent-addr length */

+  u16_t aaddrlen;

+  /* encoding enterprise-id length */

+  u16_t eidlen;

+  /* encoding pdu length */

+  u16_t pdulen;

+  /* encoding community length */

+  u16_t comlen;

+  /* encoding version length */

+  u16_t verlen;

+  /* encoding sequence length */

+  u16_t seqlen;

+};

+

+/* Accepting new SNMP messages. */

+#define SNMP_MSG_EMPTY                 0

+/* Search for matching object for variable binding. */

+#define SNMP_MSG_SEARCH_OBJ            1

+/* Perform SNMP operation on in-memory object.

+   Pass-through states, for symmetry only. */

+#define SNMP_MSG_INTERNAL_GET_OBJDEF   2

+#define SNMP_MSG_INTERNAL_GET_VALUE    3

+#define SNMP_MSG_INTERNAL_SET_TEST     4

+#define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5

+#define SNMP_MSG_INTERNAL_SET_VALUE    6

+/* Perform SNMP operation on object located externally.

+   In theory this could be used for building a proxy agent.

+   Practical use is for an enterprise spc. app. gateway. */

+#define SNMP_MSG_EXTERNAL_GET_OBJDEF   7

+#define SNMP_MSG_EXTERNAL_GET_VALUE    8

+#define SNMP_MSG_EXTERNAL_SET_TEST     9

+#define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10

+#define SNMP_MSG_EXTERNAL_SET_VALUE    11

+

+#define SNMP_COMMUNITY_STR_LEN 64

+struct snmp_msg_pstat

+{

+  /* lwIP local port (161) binding */

+  struct udp_pcb *pcb;

+  /* source IP address */

+  struct ip_addr sip;

+  /* source UDP port */

+  u16_t sp;

+  /* request type */

+  u8_t rt;

+  /* request ID */

+  s32_t rid;

+  /* error status */

+  s32_t error_status;

+  /* error index */

+  s32_t error_index;

+  /* community name (zero terminated) */

+  u8_t community[SNMP_COMMUNITY_STR_LEN + 1];

+  /* community string length (exclusive zero term) */

+  u8_t com_strlen;

+  /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */

+  u8_t state;

+  /* saved arguments for MSG_EXTERNAL_x */

+  struct mib_external_node *ext_mib_node;

+  struct snmp_name_ptr ext_name_ptr;

+  struct obj_def ext_object_def;

+  struct snmp_obj_id ext_oid;

+  /* index into input variable binding list */

+  u8_t vb_idx;

+  /* ptr into input variable binding list */

+  struct snmp_varbind *vb_ptr;

+  /* list of variable bindings from input */

+  struct snmp_varbind_root invb;

+  /* list of variable bindings to output */

+  struct snmp_varbind_root outvb;

+  /* output response lengths used in ASN encoding */

+  struct snmp_resp_header_lengths rhl;

+};

+

+struct snmp_msg_trap

+{

+  /* lwIP local port (161) binding */

+  struct udp_pcb *pcb;

+  /* destination IP address in network order */

+  struct ip_addr dip;

+

+  /* source enterprise ID (sysObjectID) */

+  struct snmp_obj_id *enterprise;

+  /* source IP address, raw network order format */

+  u8_t sip_raw[4];

+  /* generic trap code */

+  u32_t gen_trap;

+  /* specific trap code */

+  u32_t spc_trap;

+  /* timestamp */

+  u32_t ts;

+  /* list of variable bindings to output */

+  struct snmp_varbind_root outvb;

+  /* output trap lengths used in ASN encoding */

+  struct snmp_trap_header_lengths thl;

+};

+

+/** Agent Version constant, 0 = v1 oddity */

+extern const s32_t snmp_version;

+/** Agent default "public" community string */

+extern const char snmp_publiccommunity[7];

+

+extern struct snmp_msg_trap trap_msg;

+

+/** Agent setup, start listening to port 161. */

+void snmp_init(void);

+void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable);

+void snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst);

+

+/** Varbind-list functions. */

+struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len);

+void snmp_varbind_free(struct snmp_varbind *vb);

+void snmp_varbind_list_free(struct snmp_varbind_root *root);

+void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb);

+struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root);

+

+/** Handle an internal (recv) or external (private response) event. */

+void snmp_msg_event(u8_t request_id);

+err_t snmp_send_response(struct snmp_msg_pstat *m_stat);

+err_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap);

+void snmp_coldstart_trap(void);

+void snmp_authfail_trap(void);

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_SNMP_MSG_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_structs.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_structs.h
new file mode 100644
index 0000000..2c86a98
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_structs.h
@@ -0,0 +1,262 @@
+/**

+ * @file

+ * Generic MIB tree structures.

+ *

+ * @todo namespace prefixes

+ */

+

+/*

+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * Author: Christiaan Simons <christiaan.simons@axon.tv>

+ */

+

+#ifndef __LWIP_SNMP_STRUCTS_H__

+#define __LWIP_SNMP_STRUCTS_H__

+

+#include "lwip/opt.h"

+

+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/snmp.h"

+

+#if SNMP_PRIVATE_MIB

+#include "private_mib.h"

+#endif

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+/* MIB object instance */

+#define MIB_OBJECT_NONE 0 

+#define MIB_OBJECT_SCALAR 1

+#define MIB_OBJECT_TAB 2

+

+/* MIB object access */

+#define MIB_OBJECT_READ_ONLY 0

+#define MIB_OBJECT_READ_WRITE 1

+#define MIB_OBJECT_WRITE_ONLY 2

+#define MIB_OBJECT_NOT_ACCESSIBLE 3

+

+/** object definition returned by (get_object_def)() */

+struct obj_def

+{

+  /* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */

+  u8_t instance;

+  /* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */

+  u8_t access;

+  /* ASN type for this object */

+  u8_t asn_type;

+  /* value length (host length) */

+  u16_t v_len;

+  /* length of instance part of supplied object identifier */

+  u8_t  id_inst_len;

+  /* instance part of supplied object identifier */

+  s32_t *id_inst_ptr;

+};

+

+struct snmp_name_ptr

+{

+  u8_t ident_len;

+  s32_t *ident;

+};

+

+/** MIB const scalar (.0) node */

+#define MIB_NODE_SC 0x01

+/** MIB const array node */

+#define MIB_NODE_AR 0x02

+/** MIB array node (mem_malloced from RAM) */

+#define MIB_NODE_RA 0x03

+/** MIB list root node (mem_malloced from RAM) */

+#define MIB_NODE_LR 0x04

+/** MIB node for external objects */

+#define MIB_NODE_EX 0x05

+

+/** node "base class" layout, the mandatory fields for a node  */

+struct mib_node

+{

+  /** returns struct obj_def for the given object identifier */

+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);

+  /** returns object value for the given object identifier,

+     @note the caller must allocate at least len bytes for the value */

+  void (*get_value)(struct obj_def *od, u16_t len, void *value);

+  /** tests length and/or range BEFORE setting */

+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);

+  /** sets object value, only to be called when set_test()  */

+  void (*set_value)(struct obj_def *od, u16_t len, void *value);  

+  /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */

+  const u8_t node_type;

+  /* array or max list length */

+  const u16_t maxlength;

+};

+

+/** derived node for scalars .0 index */

+typedef struct mib_node mib_scalar_node;

+

+/** derived node, points to a fixed size const array

+    of sub-identifiers plus a 'child' pointer */

+struct mib_array_node

+{

+  /* inherited "base class" members */

+  void (* const get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);

+  void (* const get_value)(struct obj_def *od, u16_t len, void *value);

+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);

+  void (*set_value)(struct obj_def *od, u16_t len, void *value);

+

+  const u8_t node_type;

+  const u16_t maxlength;

+

+  /* aditional struct members */

+  const s32_t *objid;

+  struct mib_node* const *nptr;

+};

+

+/** derived node, points to a fixed size mem_malloced array

+    of sub-identifiers plus a 'child' pointer */

+struct mib_ram_array_node

+{

+  /* inherited "base class" members */

+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);

+  void (*get_value)(struct obj_def *od, u16_t len, void *value);

+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);

+  void (*set_value)(struct obj_def *od, u16_t len, void *value);

+

+  u8_t node_type;

+  u16_t maxlength;

+

+  /* aditional struct members */

+  s32_t *objid;

+  struct mib_node **nptr;

+};

+

+struct mib_list_node

+{

+  struct mib_list_node *prev;  

+  struct mib_list_node *next;

+  s32_t objid;

+  struct mib_node *nptr;

+};

+

+/** derived node, points to a doubly linked list

+    of sub-identifiers plus a 'child' pointer */

+struct mib_list_rootnode

+{

+  /* inherited "base class" members */

+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);

+  void (*get_value)(struct obj_def *od, u16_t len, void *value);

+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);

+  void (*set_value)(struct obj_def *od, u16_t len, void *value);

+

+  u8_t node_type;

+  u16_t maxlength;

+

+  /* aditional struct members */

+  struct mib_list_node *head;

+  struct mib_list_node *tail;

+  /* counts list nodes in list  */

+  u16_t count;

+};

+

+/** derived node, has access functions for mib object in external memory or device

+    using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */

+struct mib_external_node

+{

+  /* inherited "base class" members */

+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);

+  void (*get_value)(struct obj_def *od, u16_t len, void *value);

+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);

+  void (*set_value)(struct obj_def *od, u16_t len, void *value);

+

+  u8_t node_type;

+  u16_t maxlength;

+

+  /* aditional struct members */

+  /** points to an extenal (in memory) record of some sort of addressing

+      information, passed to and interpreted by the funtions below */

+  void* addr_inf;

+  /** tree levels under this node */

+  u8_t tree_levels;

+  /** number of objects at this level */

+  u16_t (*level_length)(void* addr_inf, u8_t level);

+  /** compares object sub identifier with external id

+      return zero when equal, nonzero when unequal */

+  s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id);

+  void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id);

+

+  /** async Questions */

+  void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident);

+  void (*get_value_q)(u8_t rid, struct obj_def *od);

+  void (*set_test_q)(u8_t rid, struct obj_def *od);

+  void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value);

+  /** async Answers */

+  void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od);

+  void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);

+  u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);

+  void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);

+  /** async Panic Close (agent returns error reply, 

+      e.g. used for external transaction cleanup) */

+  void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident);

+  void (*get_value_pc)(u8_t rid, struct obj_def *od);

+  void (*set_test_pc)(u8_t rid, struct obj_def *od);

+  void (*set_value_pc)(u8_t rid, struct obj_def *od);

+};

+

+/** export MIB tree from mib2.c */

+extern const struct mib_array_node internet;

+

+/** dummy function pointers for non-leaf MIB nodes from mib2.c */

+void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);

+void noleafs_get_value(struct obj_def *od, u16_t len, void *value);

+u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value);

+void noleafs_set_value(struct obj_def *od, u16_t len, void *value);

+

+void snmp_oidtoip(s32_t *ident, struct ip_addr *ip);

+void snmp_iptooid(struct ip_addr *ip, s32_t *ident);

+void snmp_ifindextonetif(s32_t ifindex, struct netif **netif);

+void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx);

+

+struct mib_list_node* snmp_mib_ln_alloc(s32_t id);

+void snmp_mib_ln_free(struct mib_list_node *ln);

+struct mib_list_rootnode* snmp_mib_lrn_alloc(void);

+void snmp_mib_lrn_free(struct mib_list_rootnode *lrn);

+

+s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn);

+s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn);

+struct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n);

+

+struct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np);

+struct mib_node* snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);

+u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident);

+u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* LWIP_SNMP */

+

+#endif /* __LWIP_SNMP_STRUCTS_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/sockets.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/sockets.h
new file mode 100644
index 0000000..aa3e65c
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/sockets.h
@@ -0,0 +1,337 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+

+#ifndef __LWIP_SOCKETS_H__

+#define __LWIP_SOCKETS_H__

+

+#include "lwip/opt.h"

+

+#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/ip_addr.h"

+#include "lwip/inet.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+/* members are in network byte order */

+struct sockaddr_in {

+  u8_t sin_len;

+  u8_t sin_family;

+  u16_t sin_port;

+  struct in_addr sin_addr;

+  char sin_zero[8];

+};

+

+struct sockaddr {

+  u8_t sa_len;

+  u8_t sa_family;

+  char sa_data[14];

+};

+

+#ifndef socklen_t

+#  define socklen_t u32_t

+#endif

+

+/* Socket protocol types (TCP/UDP/RAW) */

+#define SOCK_STREAM     1

+#define SOCK_DGRAM      2

+#define SOCK_RAW        3

+

+/*

+ * Option flags per-socket. These must match the SOF_ flags in ip.h!

+ */

+#define  SO_DEBUG       0x0001 /* Unimplemented: turn on debugging info recording */

+#define  SO_ACCEPTCONN  0x0002 /* socket has had listen() */

+#define  SO_REUSEADDR   0x0004 /* Unimplemented: allow local address reuse */

+#define  SO_KEEPALIVE   0x0008 /* keep connections alive */

+#define  SO_DONTROUTE   0x0010 /* Unimplemented: just use interface addresses */

+#define  SO_BROADCAST   0x0020 /* Unimplemented: permit sending of broadcast msgs */

+#define  SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */

+#define  SO_LINGER      0x0080 /* linger on close if data present */

+#define  SO_OOBINLINE   0x0100 /* Unimplemented: leave received OOB data in line */

+#define  SO_REUSEPORT   0x0200 /* Unimplemented: allow local address & port reuse */

+

+#define SO_DONTLINGER   ((int)(~SO_LINGER))

+

+/*

+ * Additional options, not kept in so_options.

+ */

+#define SO_SNDBUF    0x1001    /* Unimplemented: send buffer size */

+#define SO_RCVBUF    0x1002    /* receive buffer size */

+#define SO_SNDLOWAT  0x1003    /* Unimplemented: send low-water mark */

+#define SO_RCVLOWAT  0x1004    /* Unimplemented: receive low-water mark */

+#define SO_SNDTIMEO  0x1005    /* Unimplemented: send timeout */

+#define SO_RCVTIMEO  0x1006    /* receive timeout */

+#define SO_ERROR     0x1007    /* get error status and clear */

+#define SO_TYPE      0x1008    /* get socket type */

+#define SO_CONTIMEO  0x1009    /* Unimplemented: connect timeout */

+#define SO_NO_CHECK  0x100a    /* don't create UDP checksum */

+

+

+/*

+ * Structure used for manipulating linger option.

+ */

+struct linger {

+       int l_onoff;                /* option on/off */

+       int l_linger;               /* linger time */

+};

+

+/*

+ * Level number for (get/set)sockopt() to apply to socket itself.

+ */

+#define  SOL_SOCKET  0xfff    /* options for socket level */

+

+

+#define AF_UNSPEC       0

+#define AF_INET         2

+#define PF_INET         AF_INET

+#define PF_UNSPEC       AF_UNSPEC

+

+#define IPPROTO_IP      0

+#define IPPROTO_TCP     6

+#define IPPROTO_UDP     17

+#define IPPROTO_UDPLITE 136

+

+#define INADDR_ANY       0

+#define INADDR_BROADCAST 0xffffffff

+

+/* Flags we can use with send and recv. */

+#define MSG_PEEK       0x01    /* Peeks at an incoming message */

+#define MSG_WAITALL    0x02    /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */

+#define MSG_OOB        0x04    /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */

+#define MSG_DONTWAIT   0x08    /* Nonblocking i/o for this operation only */

+#define MSG_MORE       0x10    /* Sender will send more */

+

+

+/*

+ * Options for level IPPROTO_IP

+ */

+#define IP_TOS             1

+#define IP_TTL             2

+

+#if LWIP_TCP

+/*

+ * Options for level IPPROTO_TCP

+ */

+#define TCP_NODELAY    0x01    /* don't delay send to coalesce packets */

+#define TCP_KEEPALIVE  0x02    /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */

+#define TCP_KEEPIDLE   0x03    /* set pcb->keep_idle  - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */

+#define TCP_KEEPINTVL  0x04    /* set pcb->keep_intvl - Use seconds for get/setsockopt */

+#define TCP_KEEPCNT    0x05    /* set pcb->keep_cnt   - Use number of probes sent for get/setsockopt */

+#endif /* LWIP_TCP */

+

+#if LWIP_UDP && LWIP_UDPLITE

+/*

+ * Options for level IPPROTO_UDPLITE

+ */

+#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */

+#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */

+#endif /* LWIP_UDP && LWIP_UDPLITE*/

+

+

+#if LWIP_IGMP

+/*

+ * Options and types for UDP multicast traffic handling

+ */

+#define IP_ADD_MEMBERSHIP  3

+#define IP_DROP_MEMBERSHIP 4

+#define IP_MULTICAST_TTL   5

+#define IP_MULTICAST_IF    6

+#define IP_MULTICAST_LOOP  7

+

+typedef struct ip_mreq {

+    struct in_addr imr_multiaddr; /* IP multicast address of group */

+    struct in_addr imr_interface; /* local IP address of interface */

+} ip_mreq;

+#endif /* LWIP_IGMP */

+

+/* Unimplemented for now... */

+#define IPTOS_TOS_MASK          0x1E

+#define IPTOS_TOS(tos)          ((tos) & IPTOS_TOS_MASK)

+#define IPTOS_LOWDELAY          0x10

+#define IPTOS_THROUGHPUT        0x08

+#define IPTOS_RELIABILITY       0x04

+#define IPTOS_LOWCOST           0x02

+#define IPTOS_MINCOST           IPTOS_LOWCOST

+

+/*

+ * Definitions for IP precedence (also in ip_tos) (Unimplemented)

+ */

+#define IPTOS_PREC_MASK                 0xe0

+#define IPTOS_PREC(tos)                ((tos) & IPTOS_PREC_MASK)

+#define IPTOS_PREC_NETCONTROL           0xe0

+#define IPTOS_PREC_INTERNETCONTROL      0xc0

+#define IPTOS_PREC_CRITIC_ECP           0xa0

+#define IPTOS_PREC_FLASHOVERRIDE        0x80

+#define IPTOS_PREC_FLASH                0x60

+#define IPTOS_PREC_IMMEDIATE            0x40

+#define IPTOS_PREC_PRIORITY             0x20

+#define IPTOS_PREC_ROUTINE              0x00

+

+

+/*

+ * Commands for ioctlsocket(),  taken from the BSD file fcntl.h.

+ * lwip_ioctl only supports FIONREAD and FIONBIO, for now

+ *

+ * Ioctl's have the command encoded in the lower word,

+ * and the size of any in or out parameters in the upper

+ * word.  The high 2 bits of the upper word are used

+ * to encode the in/out status of the parameter; for now

+ * we restrict parameters to at most 128 bytes.

+ */

+#if !defined(FIONREAD) || !defined(FIONBIO)

+#define IOCPARM_MASK    0x7fU           /* parameters must be < 128 bytes */

+#define IOC_VOID        0x20000000UL    /* no parameters */

+#define IOC_OUT         0x40000000UL    /* copy out parameters */

+#define IOC_IN          0x80000000UL    /* copy in parameters */

+#define IOC_INOUT       (IOC_IN|IOC_OUT)

+                                        /* 0x20000000 distinguishes new &

+                                           old ioctl's */

+#define _IO(x,y)        (IOC_VOID|((x)<<8)|(y))

+

+#define _IOR(x,y,t)     (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))

+

+#define _IOW(x,y,t)     (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))

+#endif /* !defined(FIONREAD) || !defined(FIONBIO) */

+

+#ifndef FIONREAD

+#define FIONREAD    _IOR('f', 127, unsigned long) /* get # bytes to read */

+#endif

+#ifndef FIONBIO

+#define FIONBIO     _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */

+#endif

+

+/* Socket I/O Controls: unimplemented */

+#ifndef SIOCSHIWAT

+#define SIOCSHIWAT  _IOW('s',  0, unsigned long)  /* set high watermark */

+#define SIOCGHIWAT  _IOR('s',  1, unsigned long)  /* get high watermark */

+#define SIOCSLOWAT  _IOW('s',  2, unsigned long)  /* set low watermark */

+#define SIOCGLOWAT  _IOR('s',  3, unsigned long)  /* get low watermark */

+#define SIOCATMARK  _IOR('s',  7, unsigned long)  /* at oob mark? */

+#endif

+

+/* Socket flags: */

+#ifndef O_NONBLOCK

+#define O_NONBLOCK    04000U

+#endif

+

+/* FD_SET used for lwip_select */

+#ifndef FD_SET

+  #undef  FD_SETSIZE

+  /* Make FD_SETSIZE match NUM_SOCKETS in socket.c */

+  #define FD_SETSIZE    MEMP_NUM_NETCONN

+  #define FD_SET(n, p)  ((p)->fd_bits[(n)/8] |=  (1 << ((n) & 7)))

+  #define FD_CLR(n, p)  ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7)))

+  #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] &   (1 << ((n) & 7)))

+  #define FD_ZERO(p)    memset((void*)(p),0,sizeof(*(p)))

+

+  typedef struct fd_set {

+          unsigned char fd_bits [(FD_SETSIZE+7)/8];

+        } fd_set;

+

+#endif /* FD_SET */

+

+/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided

+ * by your system, set this to 0 and include <sys/time.h> in cc.h */

+#ifndef LWIP_TIMEVAL_PRIVATE

+#define LWIP_TIMEVAL_PRIVATE 1

+#endif

+

+#if LWIP_TIMEVAL_PRIVATE

+struct timeval {

+  long    tv_sec;         /* seconds */

+  long    tv_usec;        /* and microseconds */

+};

+#endif /* LWIP_TIMEVAL_PRIVATE */

+

+void lwip_socket_init(void);

+

+int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen);

+int lwip_bind(int s, struct sockaddr *name, socklen_t namelen);

+int lwip_shutdown(int s, int how);

+int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen);

+int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen);

+int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen);

+int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen);

+int lwip_close(int s);

+int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen);

+int lwip_listen(int s, int backlog);

+int lwip_recv(int s, void *mem, int len, unsigned int flags);

+int lwip_read(int s, void *mem, int len);

+int lwip_recvfrom(int s, void *mem, int len, unsigned int flags,

+      struct sockaddr *from, socklen_t *fromlen);

+int lwip_send(int s, const void *dataptr, int size, unsigned int flags);

+int lwip_sendto(int s, const void *dataptr, int size, unsigned int flags,

+    struct sockaddr *to, socklen_t tolen);

+int lwip_socket(int domain, int type, int protocol);

+int lwip_write(int s, const void *dataptr, int size);

+int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,

+                struct timeval *timeout);

+int lwip_ioctl(int s, long cmd, void *argp);

+

+#if LWIP_COMPAT_SOCKETS

+#define accept(a,b,c)         lwip_accept(a,b,c)

+#define bind(a,b,c)           lwip_bind(a,b,c)

+#define shutdown(a,b)         lwip_shutdown(a,b)

+#define closesocket(s)        lwip_close(s)

+#define connect(a,b,c)        lwip_connect(a,b,c)

+#define getsockname(a,b,c)    lwip_getsockname(a,b,c)

+#define getpeername(a,b,c)    lwip_getpeername(a,b,c)

+#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e)

+#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e)

+#define listen(a,b)           lwip_listen(a,b)

+#define recv(a,b,c,d)         lwip_recv(a,b,c,d)

+#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f)

+#define send(a,b,c,d)         lwip_send(a,b,c,d)

+#define sendto(a,b,c,d,e,f)   lwip_sendto(a,b,c,d,e,f)

+#define socket(a,b,c)         lwip_socket(a,b,c)

+#define select(a,b,c,d,e)     lwip_select(a,b,c,d,e)

+#define ioctlsocket(a,b,c)    lwip_ioctl(a,b,c)

+

+#if LWIP_POSIX_SOCKETS_IO_NAMES

+#define read(a,b,c)           lwip_read(a,b,c)

+#define write(a,b,c)          lwip_write(a,b,c)

+#define close(s)              lwip_close(s)

+#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */

+

+#endif /* LWIP_COMPAT_SOCKETS */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* LWIP_SOCKET */

+

+#endif /* __LWIP_SOCKETS_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/stats.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/stats.h
new file mode 100644
index 0000000..aebf490
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/stats.h
@@ -0,0 +1,209 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_STATS_H__

+#define __LWIP_STATS_H__

+

+#include "lwip/opt.h"

+

+#include "lwip/mem.h"

+#include "lwip/memp.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#if LWIP_STATS

+

+#ifndef LWIP_STATS_LARGE

+#define LWIP_STATS_LARGE 0

+#endif

+

+#if LWIP_STATS_LARGE

+#define STAT_COUNTER     u32_t

+#define STAT_COUNTER_F   U32_F

+#else

+#define STAT_COUNTER     u16_t

+#define STAT_COUNTER_F   U16_F

+#endif

+

+struct stats_proto {

+  STAT_COUNTER xmit;             /* Transmitted packets. */

+  STAT_COUNTER rexmit;           /* Retransmitted packets. */

+  STAT_COUNTER recv;             /* Received packets. */

+  STAT_COUNTER fw;               /* Forwarded packets. */

+  STAT_COUNTER drop;             /* Dropped packets. */

+  STAT_COUNTER chkerr;           /* Checksum error. */

+  STAT_COUNTER lenerr;           /* Invalid length error. */

+  STAT_COUNTER memerr;           /* Out of memory error. */

+  STAT_COUNTER rterr;            /* Routing error. */

+  STAT_COUNTER proterr;          /* Protocol error. */

+  STAT_COUNTER opterr;           /* Error in options. */

+  STAT_COUNTER err;              /* Misc error. */

+  STAT_COUNTER cachehit;

+};

+

+struct stats_igmp {

+  STAT_COUNTER lenerr;           /* Invalid length error. */

+  STAT_COUNTER chkerr;           /* Checksum error. */

+  STAT_COUNTER v1_rxed;          /* */

+  STAT_COUNTER join_sent;        /* */

+  STAT_COUNTER leave_sent;       /* */

+  STAT_COUNTER unicast_query;    /* */

+  STAT_COUNTER report_sent;      /* */

+  STAT_COUNTER report_rxed;      /* */

+  STAT_COUNTER group_query_rxed; /* */

+};

+

+struct stats_mem {

+  mem_size_t avail;

+  mem_size_t used;

+  mem_size_t max;

+  mem_size_t err;

+};

+

+struct stats_syselem {

+  STAT_COUNTER used;

+  STAT_COUNTER max;

+  STAT_COUNTER err;

+};

+

+struct stats_sys {

+  struct stats_syselem sem;

+  struct stats_syselem mbox;

+};

+

+struct stats_ {

+#if LINK_STATS

+  struct stats_proto link;

+#endif

+#if ETHARP_STATS

+  struct stats_proto etharp;

+#endif

+#if IPFRAG_STATS

+  struct stats_proto ip_frag;

+#endif

+#if IP_STATS

+  struct stats_proto ip;

+#endif

+#if ICMP_STATS

+  struct stats_proto icmp;

+#endif

+#if IGMP_STATS

+  struct stats_igmp igmp;

+#endif

+#if UDP_STATS

+  struct stats_proto udp;

+#endif

+#if TCP_STATS

+  struct stats_proto tcp;

+#endif

+#if MEM_STATS

+  struct stats_mem mem;

+#endif

+#if MEMP_STATS

+  struct stats_mem memp[MEMP_MAX];

+#endif

+#if SYS_STATS

+  struct stats_sys sys;

+#endif

+};

+

+extern struct stats_ lwip_stats;

+

+#define stats_init() /* Compatibility define, not init needed. */

+

+#define STATS_INC(x) ++lwip_stats.x

+#else

+#define stats_init()

+#define STATS_INC(x)

+#endif /* LWIP_STATS */

+

+#if TCP_STATS

+#define TCP_STATS_INC(x) STATS_INC(x)

+#else

+#define TCP_STATS_INC(x)

+#endif

+

+#if UDP_STATS

+#define UDP_STATS_INC(x) STATS_INC(x)

+#else

+#define UDP_STATS_INC(x)

+#endif

+

+#if ICMP_STATS

+#define ICMP_STATS_INC(x) STATS_INC(x)

+#else

+#define ICMP_STATS_INC(x)

+#endif

+

+#if IGMP_STATS

+#define IGMP_STATS_INC(x) STATS_INC(x)

+#else

+#define IGMP_STATS_INC(x)

+#endif

+

+#if IP_STATS

+#define IP_STATS_INC(x) STATS_INC(x)

+#else

+#define IP_STATS_INC(x)

+#endif

+

+#if IPFRAG_STATS

+#define IPFRAG_STATS_INC(x) STATS_INC(x)

+#else

+#define IPFRAG_STATS_INC(x)

+#endif

+

+#if ETHARP_STATS

+#define ETHARP_STATS_INC(x) STATS_INC(x)

+#else

+#define ETHARP_STATS_INC(x)

+#endif

+

+#if LINK_STATS

+#define LINK_STATS_INC(x) STATS_INC(x)

+#else

+#define LINK_STATS_INC(x)

+#endif

+

+/* Display of statistics */

+#if LWIP_STATS_DISPLAY

+void stats_display(void);

+#else

+#define stats_display()

+#endif /* LWIP_STATS_DISPLAY */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_STATS_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/sys.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/sys.h
new file mode 100644
index 0000000..f713f1e
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/sys.h
@@ -0,0 +1,246 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_SYS_H__

+#define __LWIP_SYS_H__

+

+#include "lwip/opt.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#if NO_SYS

+

+/* For a totally minimal and standalone system, we provide null

+   definitions of the sys_ functions. */

+typedef u8_t sys_sem_t;

+typedef u8_t sys_mbox_t;

+typedef u8_t sys_prot_t;

+struct sys_timeo {u8_t dummy;};

+

+#define sys_init()

+#define sys_timeout(m,h,a)

+#define sys_untimeout(m,a)

+#define sys_sem_new(c) c

+#define sys_sem_signal(s)

+#define sys_sem_wait(s)

+#define sys_sem_wait_timeout(s,t)

+#define sys_arch_sem_wait(s,t)

+#define sys_sem_free(s)

+#define sys_mbox_new(s) 0

+#define sys_mbox_fetch(m,d)

+#define sys_mbox_tryfetch(m,d)

+#define sys_mbox_post(m,d)

+#define sys_mbox_trypost(m,d)

+#define sys_mbox_free(m)

+

+#define sys_thread_new(n,t,a,s,p)

+

+#else /* NO_SYS */

+

+/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */

+#define SYS_ARCH_TIMEOUT 0xffffffffUL

+

+/* sys_mbox_tryfetch returns SYS_MBOX_EMPTY if appropriate.

+ * For now we use the same magic value, but we allow this to change in future.

+ */

+#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT

+

+#include "lwip/err.h"

+#include "arch/sys_arch.h"

+

+typedef void (* sys_timeout_handler)(void *arg);

+

+struct sys_timeo {

+  struct sys_timeo *next;

+  u32_t time;

+  sys_timeout_handler h;

+  void *arg;

+};

+

+struct sys_timeouts {

+  struct sys_timeo *next;

+};

+

+/* sys_init() must be called before anthing else. */

+void sys_init(void);

+

+/*

+ * sys_timeout():

+ *

+ * Schedule a timeout a specified amount of milliseconds in the

+ * future. When the timeout occurs, the specified timeout handler will

+ * be called. The handler will be passed the "arg" argument when

+ * called.

+ *

+ */

+void sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg);

+void sys_untimeout(sys_timeout_handler h, void *arg);

+struct sys_timeouts *sys_arch_timeouts(void);

+

+/* Semaphore functions. */

+sys_sem_t sys_sem_new(u8_t count);

+void sys_sem_signal(sys_sem_t sem);

+u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout);

+void sys_sem_free(sys_sem_t sem);

+void sys_sem_wait(sys_sem_t sem);

+int sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout);

+

+/* Time functions. */

+#ifndef sys_msleep

+void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */

+#endif

+#ifndef sys_jiffies

+u32_t sys_jiffies(void); /* since power up. */

+#endif

+

+/* Mailbox functions. */

+sys_mbox_t sys_mbox_new(int size);

+void sys_mbox_post(sys_mbox_t mbox, void *msg);

+err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg);

+u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout);

+#ifndef sys_arch_mbox_tryfetch /* Allow port to override with a macro */

+u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg);

+#endif

+/* For now, we map straight to sys_arch implementation. */

+#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg)

+void sys_mbox_free(sys_mbox_t mbox);

+void sys_mbox_fetch(sys_mbox_t mbox, void **msg);

+

+/* Thread functions. */

+sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio);

+

+/* The following functions are used only in Unix code, and

+   can be omitted when porting the stack. */

+/* Returns the current time in microseconds. */

+unsigned long sys_now(void);

+

+#endif /* NO_SYS */

+

+/* Critical Region Protection */

+/* These functions must be implemented in the sys_arch.c file.

+   In some implementations they can provide a more light-weight protection

+   mechanism than using semaphores. Otherwise semaphores can be used for

+   implementation */

+#ifndef SYS_ARCH_PROTECT

+/** SYS_LIGHTWEIGHT_PROT

+ * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection

+ * for certain critical regions during buffer allocation, deallocation and memory

+ * allocation and deallocation.

+ */

+#if SYS_LIGHTWEIGHT_PROT

+

+/** SYS_ARCH_DECL_PROTECT

+ * declare a protection variable. This macro will default to defining a variable of

+ * type sys_prot_t. If a particular port needs a different implementation, then

+ * this macro may be defined in sys_arch.h.

+ */

+#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev

+/** SYS_ARCH_PROTECT

+ * Perform a "fast" protect. This could be implemented by

+ * disabling interrupts for an embedded system or by using a semaphore or

+ * mutex. The implementation should allow calling SYS_ARCH_PROTECT when

+ * already protected. The old protection level is returned in the variable

+ * "lev". This macro will default to calling the sys_arch_protect() function

+ * which should be implemented in sys_arch.c. If a particular port needs a

+ * different implementation, then this macro may be defined in sys_arch.h

+ */

+#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect()

+/** SYS_ARCH_UNPROTECT

+ * Perform a "fast" set of the protection level to "lev". This could be

+ * implemented by setting the interrupt level to "lev" within the MACRO or by

+ * using a semaphore or mutex.  This macro will default to calling the

+ * sys_arch_unprotect() function which should be implemented in

+ * sys_arch.c. If a particular port needs a different implementation, then

+ * this macro may be defined in sys_arch.h

+ */

+#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev)

+sys_prot_t sys_arch_protect(void);

+void sys_arch_unprotect(sys_prot_t pval);

+

+#else

+

+#define SYS_ARCH_DECL_PROTECT(lev)

+#define SYS_ARCH_PROTECT(lev)

+#define SYS_ARCH_UNPROTECT(lev)

+

+#endif /* SYS_LIGHTWEIGHT_PROT */

+

+#endif /* SYS_ARCH_PROTECT */

+

+/*

+ * Macros to set/get and increase/decrease variables in a thread-safe way.

+ * Use these for accessing variable that are used from more than one thread.

+ */

+

+#ifndef SYS_ARCH_INC

+#define SYS_ARCH_INC(var, val) do { \

+                                SYS_ARCH_DECL_PROTECT(old_level); \

+                                SYS_ARCH_PROTECT(old_level); \

+                                var += val; \

+                                SYS_ARCH_UNPROTECT(old_level); \

+                              } while(0)

+#endif /* SYS_ARCH_INC */

+

+#ifndef SYS_ARCH_DEC

+#define SYS_ARCH_DEC(var, val) do { \

+                                SYS_ARCH_DECL_PROTECT(old_level); \

+                                SYS_ARCH_PROTECT(old_level); \

+                                var -= val; \

+                                SYS_ARCH_UNPROTECT(old_level); \

+                              } while(0)

+#endif /* SYS_ARCH_DEC */

+

+#ifndef SYS_ARCH_GET

+#define SYS_ARCH_GET(var, ret) do { \

+                                SYS_ARCH_DECL_PROTECT(old_level); \

+                                SYS_ARCH_PROTECT(old_level); \

+                                ret = var; \

+                                SYS_ARCH_UNPROTECT(old_level); \

+                              } while(0)

+#endif /* SYS_ARCH_GET */

+

+#ifndef SYS_ARCH_SET

+#define SYS_ARCH_SET(var, val) do { \

+                                SYS_ARCH_DECL_PROTECT(old_level); \

+                                SYS_ARCH_PROTECT(old_level); \

+                                var = val; \

+                                SYS_ARCH_UNPROTECT(old_level); \

+                              } while(0)

+#endif /* SYS_ARCH_SET */

+

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __LWIP_SYS_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/tcp.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/tcp.h
new file mode 100644
index 0000000..9912be0
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/tcp.h
@@ -0,0 +1,644 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_TCP_H__

+#define __LWIP_TCP_H__

+

+#include "lwip/opt.h"

+

+#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/sys.h"

+#include "lwip/mem.h"

+#include "lwip/pbuf.h"

+#include "lwip/ip.h"

+#include "lwip/icmp.h"

+#include "lwip/err.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+struct tcp_pcb;

+

+/* Functions for interfacing with TCP: */

+

+/* Lower layer interface to TCP: */

+#define tcp_init() /* Compatibility define, not init needed. */

+void             tcp_tmr     (void);  /* Must be called every

+                                         TCP_TMR_INTERVAL

+                                         ms. (Typically 250 ms). */

+/* Application program's interface: */

+struct tcp_pcb * tcp_new     (void);

+struct tcp_pcb * tcp_alloc   (u8_t prio);

+

+void             tcp_arg     (struct tcp_pcb *pcb, void *arg);

+void             tcp_accept  (struct tcp_pcb *pcb,

+                              err_t (* accept)(void *arg, struct tcp_pcb *newpcb,

+                 err_t err));

+void             tcp_recv    (struct tcp_pcb *pcb,

+                              err_t (* recv)(void *arg, struct tcp_pcb *tpcb,

+                              struct pbuf *p, err_t err));

+void             tcp_sent    (struct tcp_pcb *pcb,

+                              err_t (* sent)(void *arg, struct tcp_pcb *tpcb,

+                              u16_t len));

+void             tcp_poll    (struct tcp_pcb *pcb,

+                              err_t (* poll)(void *arg, struct tcp_pcb *tpcb),

+                              u8_t interval);

+void             tcp_err     (struct tcp_pcb *pcb,

+                              void (* err)(void *arg, err_t err));

+

+#define          tcp_mss(pcb)      ((pcb)->mss)

+#define          tcp_sndbuf(pcb)   ((pcb)->snd_buf)

+

+#if TCP_LISTEN_BACKLOG

+#define          tcp_accepted(pcb) (((struct tcp_pcb_listen *)(pcb))->accepts_pending--)

+#else  /* TCP_LISTEN_BACKLOG */

+#define          tcp_accepted(pcb)

+#endif /* TCP_LISTEN_BACKLOG */

+

+void             tcp_recved  (struct tcp_pcb *pcb, u16_t len);

+err_t            tcp_bind    (struct tcp_pcb *pcb, struct ip_addr *ipaddr,

+                              u16_t port);

+err_t            tcp_connect (struct tcp_pcb *pcb, struct ip_addr *ipaddr,

+                              u16_t port, err_t (* connected)(void *arg,

+                              struct tcp_pcb *tpcb,

+                              err_t err));

+

+struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog);

+#define          tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)

+

+void             tcp_abort   (struct tcp_pcb *pcb);

+err_t            tcp_close   (struct tcp_pcb *pcb);

+

+/* Flags for "apiflags" parameter in tcp_write and tcp_enqueue */

+#define TCP_WRITE_FLAG_COPY 0x01

+#define TCP_WRITE_FLAG_MORE 0x02

+

+err_t            tcp_write   (struct tcp_pcb *pcb, const void *dataptr, u16_t len,

+                              u8_t apiflags);

+

+void             tcp_setprio (struct tcp_pcb *pcb, u8_t prio);

+

+#define TCP_PRIO_MIN    1

+#define TCP_PRIO_NORMAL 64

+#define TCP_PRIO_MAX    127

+

+/* It is also possible to call these two functions at the right

+   intervals (instead of calling tcp_tmr()). */

+void             tcp_slowtmr (void);

+void             tcp_fasttmr (void);

+

+

+/* Only used by IP to pass a TCP segment to TCP: */

+void             tcp_input   (struct pbuf *p, struct netif *inp);

+/* Used within the TCP code only: */

+err_t            tcp_output  (struct tcp_pcb *pcb);

+void             tcp_rexmit  (struct tcp_pcb *pcb);

+void             tcp_rexmit_rto  (struct tcp_pcb *pcb);

+

+/**

+ * This is the Nagle algorithm: inhibit the sending of new TCP

+ * segments when new outgoing data arrives from the user if any

+ * previously transmitted data on the connection remains

+ * unacknowledged.

+ */

+#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \

+                            ((tpcb)->flags & TF_NODELAY) || \

+                            (((tpcb)->unsent != NULL) && ((tpcb)->unsent->next != NULL))) ? \

+                                1 : 0)

+#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK)

+

+

+/** This returns a TCP header option for MSS in an u32_t */

+#define TCP_BUILD_MSS_OPTION()  htonl(((u32_t)2 << 24) | \

+                                ((u32_t)4 << 16) | \

+                                (((u32_t)TCP_MSS / 256) << 8) | \

+                                (TCP_MSS & 255))

+

+#define TCP_SEQ_LT(a,b)     ((s32_t)((a)-(b)) < 0)

+#define TCP_SEQ_LEQ(a,b)    ((s32_t)((a)-(b)) <= 0)

+#define TCP_SEQ_GT(a,b)     ((s32_t)((a)-(b)) > 0)

+#define TCP_SEQ_GEQ(a,b)    ((s32_t)((a)-(b)) >= 0)

+/* is b<=a<=c? */

+#if 0 /* see bug #10548 */

+#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b))

+#endif

+#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c))

+#define TCP_FIN 0x01U

+#define TCP_SYN 0x02U

+#define TCP_RST 0x04U

+#define TCP_PSH 0x08U

+#define TCP_ACK 0x10U

+#define TCP_URG 0x20U

+#define TCP_ECE 0x40U

+#define TCP_CWR 0x80U

+

+#define TCP_FLAGS 0x3fU

+

+/* Length of the TCP header, excluding options. */

+#define TCP_HLEN 20

+

+#ifndef TCP_TMR_INTERVAL

+#define TCP_TMR_INTERVAL       250  /* The TCP timer interval in milliseconds. */

+#endif /* TCP_TMR_INTERVAL */

+

+#ifndef TCP_FAST_INTERVAL

+#define TCP_FAST_INTERVAL      TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */

+#endif /* TCP_FAST_INTERVAL */

+

+#ifndef TCP_SLOW_INTERVAL

+#define TCP_SLOW_INTERVAL      (2*TCP_TMR_INTERVAL)  /* the coarse grained timeout in milliseconds */

+#endif /* TCP_SLOW_INTERVAL */

+

+#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */

+#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */

+

+#define TCP_OOSEQ_TIMEOUT        6U /* x RTO */

+

+#ifndef TCP_MSL

+#define TCP_MSL 60000U /* The maximum segment lifetime in milliseconds */

+#endif

+

+/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */

+#ifndef  TCP_KEEPIDLE_DEFAULT

+#define  TCP_KEEPIDLE_DEFAULT     7200000UL /* Default KEEPALIVE timer in milliseconds */

+#endif

+

+#ifndef  TCP_KEEPINTVL_DEFAULT

+#define  TCP_KEEPINTVL_DEFAULT    75000UL   /* Default Time between KEEPALIVE probes in milliseconds */

+#endif

+

+#ifndef  TCP_KEEPCNT_DEFAULT

+#define  TCP_KEEPCNT_DEFAULT      9U        /* Default Counter for KEEPALIVE probes */

+#endif

+

+#define  TCP_MAXIDLE              TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT  /* Maximum KEEPALIVE probe time */

+

+/* Fields are (of course) in network byte order.

+ * Some fields are converted to host byte order in tcp_input().

+ */

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct tcp_hdr {

+  PACK_STRUCT_FIELD(u16_t src);

+  PACK_STRUCT_FIELD(u16_t dest);

+  PACK_STRUCT_FIELD(u32_t seqno);

+  PACK_STRUCT_FIELD(u32_t ackno);

+  PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);

+  PACK_STRUCT_FIELD(u16_t wnd);

+  PACK_STRUCT_FIELD(u16_t chksum);

+  PACK_STRUCT_FIELD(u16_t urgp);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8)

+#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)

+#define TCPH_FLAGS(phdr)  (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS)

+

+#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr))

+#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr))

+#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons((ntohs((phdr)->_hdrlen_rsvd_flags) & ~TCP_FLAGS) | (flags))

+#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (flags))

+#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) )

+

+#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & TCP_FIN || \

+          TCPH_FLAGS((seg)->tcphdr) & TCP_SYN)? 1: 0))

+

+enum tcp_state {

+  CLOSED      = 0,

+  LISTEN      = 1,

+  SYN_SENT    = 2,

+  SYN_RCVD    = 3,

+  ESTABLISHED = 4,

+  FIN_WAIT_1  = 5,

+  FIN_WAIT_2  = 6,

+  CLOSE_WAIT  = 7,

+  CLOSING     = 8,

+  LAST_ACK    = 9,

+  TIME_WAIT   = 10

+};

+

+/** Flags used on input processing, not on pcb->flags

+*/

+#define TF_RESET     (u8_t)0x08U   /* Connection was reset. */

+#define TF_CLOSED    (u8_t)0x10U   /* Connection was sucessfully closed. */

+#define TF_GOT_FIN   (u8_t)0x20U   /* Connection was closed by the remote end. */

+

+/**

+ * members common to struct tcp_pcb and struct tcp_listen_pcb

+ */

+#define TCP_PCB_COMMON(type) \

+  type *next; /* for the linked list */ \

+  enum tcp_state state; /* TCP state */ \

+  u8_t prio; \

+  void *callback_arg; \

+  /* ports are in host byte order */ \

+  u16_t local_port

+

+/* the TCP protocol control block */

+struct tcp_pcb {

+/** common PCB members */

+  IP_PCB;

+/** protocol specific PCB members */

+  TCP_PCB_COMMON(struct tcp_pcb);

+

+  /* ports are in host byte order */

+  u16_t remote_port;

+

+  u8_t flags;

+#define TF_ACK_DELAY   (u8_t)0x01U   /* Delayed ACK. */

+#define TF_ACK_NOW     (u8_t)0x02U   /* Immediate ACK. */

+#define TF_INFR        (u8_t)0x04U   /* In fast recovery. */

+#define TF_FIN         (u8_t)0x20U   /* Connection was closed locally (FIN segment enqueued). */

+#define TF_NODELAY     (u8_t)0x40U   /* Disable Nagle algorithm */

+#define TF_NAGLEMEMERR (u8_t)0x80U /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */

+

+  /* the rest of the fields are in host byte order

+     as we have to do some math with them */

+  /* receiver variables */

+  u32_t rcv_nxt;   /* next seqno expected */

+  u16_t rcv_wnd;   /* receiver window */

+  u16_t rcv_ann_wnd; /* announced receive window */

+

+  /* Timers */

+  u32_t tmr;

+  u8_t polltmr, pollinterval;

+

+  /* Retransmission timer. */

+  s16_t rtime;

+

+  u16_t mss;   /* maximum segment size */

+

+  /* RTT (round trip time) estimation variables */

+  u32_t rttest; /* RTT estimate in 500ms ticks */

+  u32_t rtseq;  /* sequence number being timed */

+  s16_t sa, sv; /* @todo document this */

+

+  s16_t rto;    /* retransmission time-out */

+  u8_t nrtx;    /* number of retransmissions */

+

+  /* fast retransmit/recovery */

+  u32_t lastack; /* Highest acknowledged seqno. */

+  u8_t dupacks;

+

+  /* congestion avoidance/control variables */

+  u16_t cwnd;

+  u16_t ssthresh;

+

+  /* sender variables */

+  u32_t snd_nxt,   /* next seqno to be sent */

+    snd_max;       /* Highest seqno sent. */

+  u16_t snd_wnd;   /* sender window */

+  u32_t snd_wl1, snd_wl2, /* Sequence and acknowledgement numbers of last

+                             window update. */

+    snd_lbb;       /* Sequence number of next byte to be buffered. */

+

+  u16_t acked;

+

+  u16_t snd_buf;   /* Available buffer space for sending (in bytes). */

+#define TCP_SNDQUEUELEN_OVERFLOW (0xffff-3)

+  u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */

+

+

+  /* These are ordered by sequence number: */

+  struct tcp_seg *unsent;   /* Unsent (queued) segments. */

+  struct tcp_seg *unacked;  /* Sent but unacknowledged segments. */

+#if TCP_QUEUE_OOSEQ

+  struct tcp_seg *ooseq;    /* Received out of sequence segments. */

+#endif /* TCP_QUEUE_OOSEQ */

+

+  struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */

+

+#if LWIP_CALLBACK_API

+  /* Function to be called when more send buffer space is available.

+   * @param arg user-supplied argument (tcp_pcb.callback_arg)

+   * @param pcb the tcp_pcb which has send buffer space available

+   * @param space the amount of bytes available

+   * @return ERR_OK: try to send some data by calling tcp_output

+   */

+  err_t (* sent)(void *arg, struct tcp_pcb *pcb, u16_t space);

+

+  /* Function to be called when (in-sequence) data has arrived.

+   * @param arg user-supplied argument (tcp_pcb.callback_arg)

+   * @param pcb the tcp_pcb for which data has arrived

+   * @param p the packet buffer which arrived

+   * @param err an error argument (TODO: that is current always ERR_OK?)

+   * @return ERR_OK: try to send some data by calling tcp_output

+   */

+  err_t (* recv)(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);

+

+  /* Function to be called when a connection has been set up.

+   * @param arg user-supplied argument (tcp_pcb.callback_arg)

+   * @param pcb the tcp_pcb that now is connected

+   * @param err an error argument (TODO: that is current always ERR_OK?)

+   * @return value is currently ignored

+   */

+  err_t (* connected)(void *arg, struct tcp_pcb *pcb, err_t err);

+

+  /* Function to call when a listener has been connected.

+   * @param arg user-supplied argument (tcp_pcb.callback_arg)

+   * @param pcb a new tcp_pcb that now is connected

+   * @param err an error argument (TODO: that is current always ERR_OK?)

+   * @return ERR_OK: accept the new connection,

+   *                 any other err_t abortsthe new connection

+   */

+  err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err);

+

+  /* Function which is called periodically.

+   * The period can be adjusted in multiples of the TCP slow timer interval

+   * by changing tcp_pcb.polltmr.

+   * @param arg user-supplied argument (tcp_pcb.callback_arg)

+   * @param pcb the tcp_pcb to poll for

+   * @return ERR_OK: try to send some data by calling tcp_output

+   */

+  err_t (* poll)(void *arg, struct tcp_pcb *pcb);

+

+  /* Function to be called whenever a fatal error occurs.

+   * There is no pcb parameter since most of the times, the pcb is

+   * already deallocated (or there is no pcb) when this function is called.

+   * @param arg user-supplied argument (tcp_pcb.callback_arg)

+   * @param err an indication why the error callback is called:

+   *            ERR_ABRT: aborted through tcp_abort or by a TCP timer

+   *            ERR_RST: the connection was reset by the remote host

+   */

+  void (* errf)(void *arg, err_t err);

+#endif /* LWIP_CALLBACK_API */

+

+  /* idle time before KEEPALIVE is sent */

+  u32_t keep_idle;

+#if LWIP_TCP_KEEPALIVE

+  u32_t keep_intvl;

+  u32_t keep_cnt;

+#endif /* LWIP_TCP_KEEPALIVE */

+

+  /* Persist timer counter */

+  u32_t persist_cnt;

+  /* Persist timer back-off */

+  u8_t persist_backoff;

+

+  /* KEEPALIVE counter */

+  u8_t keep_cnt_sent;

+};

+

+struct tcp_pcb_listen {

+/* Common members of all PCB types */

+  IP_PCB;

+/* Protocol specific PCB members */

+  TCP_PCB_COMMON(struct tcp_pcb_listen);

+

+#if LWIP_CALLBACK_API

+  /* Function to call when a listener has been connected.

+   * @param arg user-supplied argument (tcp_pcb.callback_arg)

+   * @param pcb a new tcp_pcb that now is connected

+   * @param err an error argument (TODO: that is current always ERR_OK?)

+   * @return ERR_OK: accept the new connection,

+   *                 any other err_t abortsthe new connection

+   */

+  err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err);

+#endif /* LWIP_CALLBACK_API */

+#if TCP_LISTEN_BACKLOG

+  u8_t backlog;

+  u8_t accepts_pending;

+#endif /* TCP_LISTEN_BACKLOG */

+};

+

+#if LWIP_EVENT_API

+

+enum lwip_event {

+  LWIP_EVENT_ACCEPT,

+  LWIP_EVENT_SENT,

+  LWIP_EVENT_RECV,

+  LWIP_EVENT_CONNECTED,

+  LWIP_EVENT_POLL,

+  LWIP_EVENT_ERR

+};

+

+err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,

+         enum lwip_event,

+         struct pbuf *p,

+         u16_t size,

+         err_t err);

+

+#define TCP_EVENT_ACCEPT(pcb,err,ret)    ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\

+                LWIP_EVENT_ACCEPT, NULL, 0, err)

+#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\

+                   LWIP_EVENT_SENT, NULL, space, ERR_OK)

+#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\

+                LWIP_EVENT_RECV, (p), 0, (err))

+#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\

+                LWIP_EVENT_CONNECTED, NULL, 0, (err))

+#define TCP_EVENT_POLL(pcb,ret)       ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\

+                LWIP_EVENT_POLL, NULL, 0, ERR_OK)

+#define TCP_EVENT_ERR(errf,arg,err)  lwip_tcp_event((arg), NULL, \

+                LWIP_EVENT_ERR, NULL, 0, (err))

+#else /* LWIP_EVENT_API */

+#define TCP_EVENT_ACCEPT(pcb,err,ret)     \

+                        if((pcb)->accept != NULL) \

+                        (ret = (pcb)->accept((pcb)->callback_arg,(pcb),(err)))

+#define TCP_EVENT_SENT(pcb,space,ret) \

+                        if((pcb)->sent != NULL) \

+                        (ret = (pcb)->sent((pcb)->callback_arg,(pcb),(space)))

+#define TCP_EVENT_RECV(pcb,p,err,ret) \

+                        if((pcb)->recv != NULL) \

+                        { ret = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); } else { \

+                          ret = ERR_OK; \

+                          if (p) pbuf_free(p); }

+#define TCP_EVENT_CONNECTED(pcb,err,ret) \

+                        if((pcb)->connected != NULL) \

+                        (ret = (pcb)->connected((pcb)->callback_arg,(pcb),(err)))

+#define TCP_EVENT_POLL(pcb,ret) \

+                        if((pcb)->poll != NULL) \

+                        (ret = (pcb)->poll((pcb)->callback_arg,(pcb)))

+#define TCP_EVENT_ERR(errf,arg,err) \

+                        if((errf) != NULL) \

+                        (errf)((arg),(err))

+#endif /* LWIP_EVENT_API */

+

+/* This structure represents a TCP segment on the unsent and unacked queues */

+struct tcp_seg {

+  struct tcp_seg *next;    /* used when putting segements on a queue */

+  struct pbuf *p;          /* buffer containing data + TCP header */

+  void *dataptr;           /* pointer to the TCP data in the pbuf */

+  u16_t len;               /* the TCP length of this segment */

+  struct tcp_hdr *tcphdr;  /* the TCP header */

+};

+

+/* Internal functions and global variables: */

+struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb);

+void tcp_pcb_purge(struct tcp_pcb *pcb);

+void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb);

+

+u8_t tcp_segs_free(struct tcp_seg *seg);

+u8_t tcp_seg_free(struct tcp_seg *seg);

+struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg);

+

+#define tcp_ack(pcb)     if((pcb)->flags & TF_ACK_DELAY) { \

+                            (pcb)->flags &= ~TF_ACK_DELAY; \

+                            (pcb)->flags |= TF_ACK_NOW; \

+                            tcp_output(pcb); \

+                         } else { \

+                            (pcb)->flags |= TF_ACK_DELAY; \

+                         }

+

+#define tcp_ack_now(pcb) (pcb)->flags |= TF_ACK_NOW; \

+                         tcp_output(pcb)

+

+err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags);

+err_t tcp_enqueue(struct tcp_pcb *pcb, void *dataptr, u16_t len,

+    u8_t flags, u8_t apiflags,

+                u8_t *optdata, u8_t optlen);

+

+void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg);

+

+void tcp_rst(u32_t seqno, u32_t ackno,

+       struct ip_addr *local_ip, struct ip_addr *remote_ip,

+       u16_t local_port, u16_t remote_port);

+

+u32_t tcp_next_iss(void);

+

+void tcp_keepalive(struct tcp_pcb *pcb);

+void tcp_zero_window_probe(struct tcp_pcb *pcb);

+

+#if TCP_CALCULATE_EFF_SEND_MSS

+u16_t tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr);

+#endif /* TCP_CALCULATE_EFF_SEND_MSS */

+

+extern struct tcp_pcb *tcp_input_pcb;

+extern u32_t tcp_ticks;

+

+#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG

+void tcp_debug_print(struct tcp_hdr *tcphdr);

+void tcp_debug_print_flags(u8_t flags);

+void tcp_debug_print_state(enum tcp_state s);

+void tcp_debug_print_pcbs(void);

+s16_t tcp_pcbs_sane(void);

+#else

+#  define tcp_debug_print(tcphdr)

+#  define tcp_debug_print_flags(flags)

+#  define tcp_debug_print_state(s)

+#  define tcp_debug_print_pcbs()

+#  define tcp_pcbs_sane() 1

+#endif /* TCP_DEBUG */

+

+#if NO_SYS

+#define tcp_timer_needed()

+#else

+void tcp_timer_needed(void);

+#endif

+

+/* The TCP PCB lists. */

+union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */

+  struct tcp_pcb_listen *listen_pcbs;

+  struct tcp_pcb *pcbs;

+};

+extern union tcp_listen_pcbs_t tcp_listen_pcbs;

+extern struct tcp_pcb *tcp_active_pcbs;  /* List of all TCP PCBs that are in a

+              state in which they accept or send

+              data. */

+extern struct tcp_pcb *tcp_tw_pcbs;      /* List of all TCP PCBs in TIME-WAIT. */

+

+extern struct tcp_pcb *tcp_tmp_pcb;      /* Only used for temporary storage. */

+

+/* Axioms about the above lists:

+   1) Every TCP PCB that is not CLOSED is in one of the lists.

+   2) A PCB is only in one of the lists.

+   3) All PCBs in the tcp_listen_pcbs list is in LISTEN state.

+   4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state.

+*/

+

+/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB

+   with a PCB list or removes a PCB from a list, respectively. */

+#if 0

+#define TCP_REG(pcbs, npcb) do {\

+                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", npcb, npcb->local_port)); \

+                            for(tcp_tmp_pcb = *pcbs; \

+          tcp_tmp_pcb != NULL; \

+        tcp_tmp_pcb = tcp_tmp_pcb->next) { \

+                                LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != npcb); \

+                            } \

+                            LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", npcb->state != CLOSED); \

+                            npcb->next = *pcbs; \

+                            LWIP_ASSERT("TCP_REG: npcb->next != npcb", npcb->next != npcb); \

+                            *(pcbs) = npcb; \

+                            LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \

+              tcp_timer_needed(); \

+                            } while(0)

+#define TCP_RMV(pcbs, npcb) do { \

+                            LWIP_ASSERT("TCP_RMV: pcbs != NULL", *pcbs != NULL); \

+                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", npcb, *pcbs)); \

+                            if(*pcbs == npcb) { \

+                               *pcbs = (*pcbs)->next; \

+                            } else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \

+                               if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \

+                                  tcp_tmp_pcb->next = npcb->next; \

+                                  break; \

+                               } \

+                            } \

+                            npcb->next = NULL; \

+                            LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \

+                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", npcb, *pcbs)); \

+                            } while(0)

+

+#else /* LWIP_DEBUG */

+#define TCP_REG(pcbs, npcb) do { \

+                            npcb->next = *pcbs; \

+                            *(pcbs) = npcb; \

+              tcp_timer_needed(); \

+                            } while(0)

+#define TCP_RMV(pcbs, npcb) do { \

+                            if(*(pcbs) == npcb) { \

+                               (*(pcbs)) = (*pcbs)->next; \

+                            } else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \

+                               if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \

+                                  tcp_tmp_pcb->next = npcb->next; \

+                                  break; \

+                               } \

+                            } \

+                            npcb->next = NULL; \

+                            } while(0)

+#endif /* LWIP_DEBUG */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* LWIP_TCP */

+

+#endif /* __LWIP_TCP_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/tcpip.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/tcpip.h
new file mode 100644
index 0000000..7822437
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/tcpip.h
@@ -0,0 +1,135 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_TCPIP_H__

+#define __LWIP_TCPIP_H__

+

+#include "lwip/opt.h"

+

+#if !NO_SYS /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/api_msg.h"

+#include "lwip/netifapi.h"

+#include "lwip/pbuf.h"

+#include "lwip/api.h"

+#include "lwip/sys.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#if LWIP_TCPIP_CORE_LOCKING

+/** The global semaphore to lock the stack. */

+extern sys_sem_t lock_tcpip_core;

+#define LOCK_TCPIP_CORE()     sys_sem_wait(lock_tcpip_core)

+#define UNLOCK_TCPIP_CORE()   sys_sem_signal(lock_tcpip_core)

+#define TCPIP_APIMSG(m)       tcpip_apimsg_lock(m)

+#define TCPIP_APIMSG_ACK(m)

+#define TCPIP_NETIFAPI(m)     tcpip_netifapi_lock(m)

+#define TCPIP_NETIFAPI_ACK(m)

+#else

+#define LOCK_TCPIP_CORE()

+#define UNLOCK_TCPIP_CORE()

+#define TCPIP_APIMSG(m)       tcpip_apimsg(m)

+#define TCPIP_APIMSG_ACK(m)   sys_sem_signal(m->conn->op_completed)

+#define TCPIP_NETIFAPI(m)     tcpip_netifapi(m)

+#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(m->sem)

+#endif /* LWIP_TCPIP_CORE_LOCKING */

+

+void tcpip_init(void (* tcpip_init_done)(void *), void *arg);

+

+#if LWIP_NETCONN

+err_t tcpip_apimsg(struct api_msg *apimsg);

+#if LWIP_TCPIP_CORE_LOCKING

+err_t tcpip_apimsg_lock(struct api_msg *apimsg);

+#endif /* LWIP_TCPIP_CORE_LOCKING */

+#endif /* LWIP_NETCONN */

+

+err_t tcpip_input(struct pbuf *p, struct netif *inp);

+

+#if LWIP_NETIF_API

+err_t tcpip_netifapi(struct netifapi_msg *netifapimsg);

+#if LWIP_TCPIP_CORE_LOCKING

+err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg);

+#endif /* LWIP_TCPIP_CORE_LOCKING */

+#endif /* LWIP_NETIF_API */

+

+err_t tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block);

+#define tcpip_callback(f,ctx) tcpip_callback_with_block(f,ctx,1)

+

+err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg);

+#define tcpip_untimeout(h, arg) tcpip_timeout(0xffffffff, h, arg)

+

+enum tcpip_msg_type {

+#if LWIP_NETCONN

+  TCPIP_MSG_API,

+#endif /* LWIP_NETCONN */

+  TCPIP_MSG_INPKT,

+#if LWIP_NETIF_API

+  TCPIP_MSG_NETIFAPI,

+#endif /* LWIP_NETIF_API */

+  TCPIP_MSG_CALLBACK,

+  TCPIP_MSG_TIMEOUT

+};

+

+struct tcpip_msg {

+  enum tcpip_msg_type type;

+  sys_sem_t *sem;

+  union {

+#if LWIP_NETCONN

+    struct api_msg *apimsg;

+#endif /* LWIP_NETCONN */

+#if LWIP_NETIF_API

+    struct netifapi_msg *netifapimsg;

+#endif /* LWIP_NETIF_API */

+    struct {

+      struct pbuf *p;

+      struct netif *netif;

+    } inp;

+    struct {

+      void (*f)(void *ctx);

+      void *ctx;

+    } cb;

+    struct {

+      u32_t msecs;

+      sys_timeout_handler h;

+      void *arg;

+    } tmo;

+  } msg;

+};

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* !NO_SYS */

+

+#endif /* __LWIP_TCPIP_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/udp.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/udp.h
new file mode 100644
index 0000000..7cdcdfe
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/lwip/udp.h
@@ -0,0 +1,153 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __LWIP_UDP_H__

+#define __LWIP_UDP_H__

+

+#include "lwip/opt.h"

+

+#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/pbuf.h"

+#include "lwip/netif.h"

+#include "lwip/ip_addr.h"

+#include "lwip/ip.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#define UDP_HLEN 8

+

+/* Fields are (of course) in network byte order. */

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct udp_hdr {

+  PACK_STRUCT_FIELD(u16_t src);

+  PACK_STRUCT_FIELD(u16_t dest);  /* src/dest UDP ports */

+  PACK_STRUCT_FIELD(u16_t len);

+  PACK_STRUCT_FIELD(u16_t chksum);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+#define UDP_FLAGS_NOCHKSUM 0x01U

+#define UDP_FLAGS_UDPLITE  0x02U

+#define UDP_FLAGS_CONNECTED  0x04U

+

+struct udp_pcb {

+/* Common members of all PCB types */

+  IP_PCB;

+

+/* Protocol specific PCB members */

+

+  struct udp_pcb *next;

+

+  u8_t flags;

+  /* ports are in host byte order */

+  u16_t local_port, remote_port;

+

+#if LWIP_IGMP

+  /* outgoing network interface for multicast packets */

+  struct ip_addr multicast_ip;

+#endif /* LWIP_IGMP */

+

+#if LWIP_UDPLITE

+  /* used for UDP_LITE only */

+  u16_t chksum_len_rx, chksum_len_tx;

+#endif /* LWIP_UDPLITE */

+

+  /* receive callback function

+   * addr and port are in same byte order as in the pcb

+   * The callback is responsible for freeing the pbuf

+   * if it's not used any more.

+   *

+   * @param arg user supplied argument (udp_pcb.recv_arg)

+   * @param pcb the udp_pcb which received data

+   * @param p the packet buffer that was received

+   * @param addr the remote IP address from which the packet was received

+   * @param port the remote port from which the packet was received

+   */

+  void (* recv)(void *arg, struct udp_pcb *pcb, struct pbuf *p,

+    struct ip_addr *addr, u16_t port);

+  /* user-supplied argument for the recv callback */

+  void *recv_arg;

+};

+/* udp_pcbs export for exernal reference (e.g. SNMP agent) */

+extern struct udp_pcb *udp_pcbs;

+

+/* The following functions is the application layer interface to the

+   UDP code. */

+struct udp_pcb * udp_new        (void);

+void             udp_remove     (struct udp_pcb *pcb);

+err_t            udp_bind       (struct udp_pcb *pcb, struct ip_addr *ipaddr,

+                 u16_t port);

+err_t            udp_connect    (struct udp_pcb *pcb, struct ip_addr *ipaddr,

+                 u16_t port);

+void             udp_disconnect    (struct udp_pcb *pcb);

+void             udp_recv       (struct udp_pcb *pcb,

+         void (* recv)(void *arg, struct udp_pcb *upcb,

+                 struct pbuf *p,

+                 struct ip_addr *addr,

+                 u16_t port),

+         void *recv_arg);

+err_t            udp_sendto_if  (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif);

+err_t            udp_sendto     (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port);

+err_t            udp_send       (struct udp_pcb *pcb, struct pbuf *p);

+

+#define          udp_flags(pcb)  ((pcb)->flags)

+#define          udp_setflags(pcb, f)  ((pcb)->flags = (f))

+

+/* The following functions are the lower layer interface to UDP. */

+void             udp_input      (struct pbuf *p, struct netif *inp);

+

+#define udp_init() /* Compatibility define, not init needed. */

+

+#if UDP_DEBUG

+void udp_debug_print(struct udp_hdr *udphdr);

+#else

+#define udp_debug_print(udphdr)

+#endif

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* LWIP_UDP */

+

+#endif /* __LWIP_UDP_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/netif/etharp.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/netif/etharp.h
new file mode 100644
index 0000000..3cea6ca
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/netif/etharp.h
@@ -0,0 +1,187 @@
+/*

+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.

+ * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>

+ * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+#ifndef __NETIF_ETHARP_H__

+#define __NETIF_ETHARP_H__

+

+#include "lwip/opt.h"

+

+#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/pbuf.h"

+#include "lwip/ip_addr.h"

+#include "lwip/netif.h"

+#include "lwip/ip.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#ifndef ETH_PAD_SIZE

+#define ETH_PAD_SIZE          0

+#endif

+

+#ifndef ETHARP_HWADDR_LEN

+#define ETHARP_HWADDR_LEN     6

+#endif

+

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct eth_addr {

+  PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct eth_hdr {

+#if ETH_PAD_SIZE

+  PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);

+#endif

+  PACK_STRUCT_FIELD(struct eth_addr dest);

+  PACK_STRUCT_FIELD(struct eth_addr src);

+  PACK_STRUCT_FIELD(u16_t type);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+/** the ARP message */

+struct etharp_hdr {

+  PACK_STRUCT_FIELD(struct eth_hdr ethhdr);

+  PACK_STRUCT_FIELD(u16_t hwtype);

+  PACK_STRUCT_FIELD(u16_t proto);

+  PACK_STRUCT_FIELD(u16_t _hwlen_protolen);

+  PACK_STRUCT_FIELD(u16_t opcode);

+  PACK_STRUCT_FIELD(struct eth_addr shwaddr);

+  PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);

+  PACK_STRUCT_FIELD(struct eth_addr dhwaddr);

+  PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct ethip_hdr {

+  PACK_STRUCT_FIELD(struct eth_hdr eth);

+  PACK_STRUCT_FIELD(struct ip_hdr ip);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+/** 5 seconds period */

+#define ARP_TMR_INTERVAL 5000

+

+#define ETHTYPE_ARP       0x0806

+#define ETHTYPE_IP        0x0800

+#define ETHTYPE_PPPOEDISC 0x8863  /* PPP Over Ethernet Discovery Stage */

+#define ETHTYPE_PPPOE     0x8864  /* PPP Over Ethernet Session Stage */

+

+/** ARP message types (opcodes) */

+#define ARP_REQUEST 1

+#define ARP_REPLY   2

+

+#if ARP_QUEUEING

+/** struct for queueing outgoing packets for unknown address

+  * defined here to be accessed by memp.h

+  */

+struct etharp_q_entry {

+  struct etharp_q_entry *next;

+  struct pbuf *p;

+};

+#endif /* ARP_QUEUEING */

+

+#define etharp_init() /* Compatibility define, not init needed. */

+void etharp_tmr(void);

+s8_t etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr,

+         struct eth_addr **eth_ret, struct ip_addr **ip_ret);

+void etharp_ip_input(struct netif *netif, struct pbuf *p);

+void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr,

+         struct pbuf *p);

+err_t etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr);

+err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q);

+err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr);

+

+err_t ethernet_input(struct pbuf *p, struct netif *netif);

+

+#if LWIP_AUTOIP

+err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,

+                 const struct eth_addr *ethdst_addr,

+                 const struct eth_addr *hwsrc_addr, const struct ip_addr *ipsrc_addr,

+                 const struct eth_addr *hwdst_addr, const struct ip_addr *ipdst_addr,

+                 const u16_t opcode);

+#endif /* LWIP_AUTOIP */

+

+#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0)

+

+extern const struct eth_addr ethbroadcast, ethzero;

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* LWIP_ARP */

+

+#endif /* __NETIF_ARP_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/netif/loopif.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/netif/loopif.h
new file mode 100644
index 0000000..979ac7a
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/netif/loopif.h
@@ -0,0 +1,52 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __NETIF_LOOPIF_H__

+#define __NETIF_LOOPIF_H__

+

+#include "lwip/netif.h"

+#include "lwip/err.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#if !LWIP_LOOPIF_MULTITHREADING

+void loopif_poll(struct netif *netif);

+#endif

+

+err_t loopif_init(struct netif *netif);

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* __NETIF_LOOPIF_H__ */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/netif/ppp_oe.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/netif/ppp_oe.h
new file mode 100644
index 0000000..aa95382
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/netif/ppp_oe.h
@@ -0,0 +1,167 @@
+/*****************************************************************************

+* ppp_oe.h - PPP Over Ethernet implementation for lwIP.

+*

+* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 06-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+*****************************************************************************/

+

+

+

+/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */

+

+/*-

+ * Copyright (c) 2002 The NetBSD Foundation, Inc.

+ * All rights reserved.

+ *

+ * This code is derived from software contributed to The NetBSD Foundation

+ * by Martin Husemann <martin@NetBSD.org>.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ * 1. Redistributions of source code must retain the above copyright

+ *    notice, this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright

+ *    notice, this list of conditions and the following disclaimer in the

+ *    documentation and/or other materials provided with the distribution.

+ * 3. All advertising materials mentioning features or use of this software

+ *    must display the following acknowledgement:

+ *        This product includes software developed by the NetBSD

+ *        Foundation, Inc. and its contributors.

+ * 4. Neither the name of The NetBSD Foundation nor the names of its

+ *    contributors may be used to endorse or promote products derived

+ *    from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS

+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED

+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR

+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS

+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

+ * POSSIBILITY OF SUCH DAMAGE.

+ */

+#ifndef PPP_OE_H

+#define PPP_OE_H

+

+#include "lwip/opt.h"

+

+#if PPPOE_SUPPORT > 0

+

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct pppoehdr {

+	PACK_STRUCT_FIELD(u8_t vertype);

+	PACK_STRUCT_FIELD(u8_t code);

+	PACK_STRUCT_FIELD(u16_t session);

+	PACK_STRUCT_FIELD(u16_t plen);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/bpstruct.h"

+#endif

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct pppoetag {

+	PACK_STRUCT_FIELD(u16_t tag);

+	PACK_STRUCT_FIELD(u16_t len);

+} PACK_STRUCT_STRUCT;

+PACK_STRUCT_END

+#ifdef PACK_STRUCT_USE_INCLUDES

+#  include "arch/epstruct.h"

+#endif

+

+

+#define PPPOE_STATE_INITIAL	0

+#define PPPOE_STATE_PADI_SENT	1

+#define	PPPOE_STATE_PADR_SENT	2

+#define	PPPOE_STATE_SESSION	3

+#define	PPPOE_STATE_CLOSING	4

+/* passive */

+#define	PPPOE_STATE_PADO_SENT	1

+

+#define PPPOE_HEADERLEN	sizeof(struct pppoehdr)

+#define	PPPOE_VERTYPE	0x11	/* VER=1, TYPE = 1 */

+

+#define	PPPOE_TAG_EOL		0x0000		/* end of list */

+#define	PPPOE_TAG_SNAME		0x0101		/* service name */

+#define	PPPOE_TAG_ACNAME	0x0102		/* access concentrator name */

+#define	PPPOE_TAG_HUNIQUE	0x0103		/* host unique */

+#define	PPPOE_TAG_ACCOOKIE	0x0104		/* AC cookie */

+#define	PPPOE_TAG_VENDOR	0x0105		/* vendor specific */

+#define	PPPOE_TAG_RELAYSID	0x0110		/* relay session id */

+#define	PPPOE_TAG_SNAME_ERR	0x0201		/* service name error */

+#define	PPPOE_TAG_ACSYS_ERR	0x0202		/* AC system error */

+#define	PPPOE_TAG_GENERIC_ERR	0x0203		/* gerneric error */

+

+#define PPPOE_CODE_PADI		0x09		/* Active Discovery Initiation */

+#define	PPPOE_CODE_PADO		0x07		/* Active Discovery Offer */

+#define	PPPOE_CODE_PADR		0x19		/* Active Discovery Request */

+#define	PPPOE_CODE_PADS		0x65		/* Active Discovery Session confirmation */

+#define	PPPOE_CODE_PADT		0xA7		/* Active Discovery Terminate */

+

+#ifndef ETHERMTU

+#define ETHERMTU 1500

+#endif

+

+/* two byte PPP protocol discriminator, then IP data */

+#define	PPPOE_MAXMTU	(ETHERMTU-PPPOE_HEADERLEN-2)

+

+struct pppoe_softc;

+

+

+void pppoe_init(void);

+

+err_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr);

+err_t pppoe_destroy(struct netif *ifp);

+

+int pppoe_connect(struct pppoe_softc *sc);

+void pppoe_disconnect(struct pppoe_softc *sc);

+

+void pppoe_disc_input(struct netif *netif, struct pbuf *p);

+void pppoe_data_input(struct netif *netif, struct pbuf *p);

+

+err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb);

+

+extern int pppoe_hdrlen;

+

+#endif /* PPPOE_SUPPORT */

+

+#endif /* PPP_OE_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/netif/slipif.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/netif/slipif.h
new file mode 100644
index 0000000..ef11e97
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/include/netif/slipif.h
@@ -0,0 +1,50 @@
+/*

+ * Copyright (c) 2001, Swedish Institute of Computer Science.

+ * All rights reserved. 

+ *

+ * Redistribution and use in source and binary forms, with or without 

+ * modification, are permitted provided that the following conditions 

+ * are met: 

+ * 1. Redistributions of source code must retain the above copyright 

+ *    notice, this list of conditions and the following disclaimer. 

+ * 2. Redistributions in binary form must reproduce the above copyright 

+ *    notice, this list of conditions and the following disclaimer in the 

+ *    documentation and/or other materials provided with the distribution. 

+ * 3. Neither the name of the Institute nor the names of its contributors 

+ *    may be used to endorse or promote products derived from this software 

+ *    without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 

+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 

+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 

+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 

+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 

+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 

+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 

+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 

+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 

+ * SUCH DAMAGE. 

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ * 

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#ifndef __NETIF_SLIPIF_H__

+#define __NETIF_SLIPIF_H__

+

+#include "lwip/netif.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+err_t slipif_init(struct netif * netif);

+

+#ifdef __cplusplus

+}

+#endif

+ 

+#endif 

+

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/FILES b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/FILES
new file mode 100644
index 0000000..a0dca19
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/FILES
@@ -0,0 +1,25 @@
+This directory contains generic network interface device drivers that

+do not contain any hardware or architecture specific code. The files

+are:

+

+etharp.c

+          Implements the ARP (Address Resolution Protocol) over

+          Ethernet. The code in this file should be used together with

+          Ethernet device drivers. Note that this module has been

+          largely made Ethernet independent so you should be able to

+          adapt this for other link layers (such as Firewire).

+

+ethernetif.c

+          An example of how an Ethernet device driver could look. This

+          file can be used as a "skeleton" for developing new Ethernet

+          network device drivers. It uses the etharp.c ARP code.

+

+loopif.c

+          A "loopback" network interface driver. It requires configuration

+          through the define LWIP_LOOPIF_MULTITHREADING (see opt.h).

+

+slipif.c

+          A generic implementation of the SLIP (Serial Line IP)

+          protocol. It requires a sio (serial I/O) module to work.

+

+ppp/      Point-to-Point Protocol stack

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/etharp.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/etharp.c
new file mode 100644
index 0000000..27ae689
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/etharp.c
@@ -0,0 +1,1177 @@
+/**

+ * @file

+ * Address Resolution Protocol module for IP over Ethernet

+ *

+ * Functionally, ARP is divided into two parts. The first maps an IP address

+ * to a physical address when sending a packet, and the second part answers

+ * requests from other machines for our physical address.

+ *

+ * This implementation complies with RFC 826 (Ethernet ARP). It supports

+ * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6

+ * if an interface calls etharp_query(our_netif, its_ip_addr, NULL) upon

+ * address change.

+ */

+

+/*

+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.

+ * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>

+ * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ */

+

+#include "lwip/opt.h"

+

+#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/inet.h"

+#include "lwip/ip.h"

+#include "lwip/stats.h"

+#include "lwip/snmp.h"

+#include "lwip/dhcp.h"

+#include "lwip/autoip.h"

+#include "netif/etharp.h"

+

+#if PPPOE_SUPPORT

+#include "netif/ppp_oe.h"

+#endif /* PPPOE_SUPPORT */

+

+#include <string.h>

+

+/** the time an ARP entry stays valid after its last update,

+ *  for ARP_TMR_INTERVAL = 5000, this is

+ *  (240 * 5) seconds = 20 minutes.

+ */

+#define ARP_MAXAGE 240

+/** the time an ARP entry stays pending after first request,

+ *  for ARP_TMR_INTERVAL = 5000, this is

+ *  (2 * 5) seconds = 10 seconds.

+ *

+ *  @internal Keep this number at least 2, otherwise it might

+ *  run out instantly if the timeout occurs directly after a request.

+ */

+#define ARP_MAXPENDING 2

+

+#define HWTYPE_ETHERNET 1

+

+#define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8)

+#define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff)

+

+#define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8))

+#define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8))

+

+enum etharp_state {

+  ETHARP_STATE_EMPTY = 0,

+  ETHARP_STATE_PENDING,

+  ETHARP_STATE_STABLE

+};

+

+struct etharp_entry {

+#if ARP_QUEUEING

+  /**

+   * Pointer to queue of pending outgoing packets on this ARP entry.

+   */

+  struct etharp_q_entry *q;

+#endif

+  struct ip_addr ipaddr;

+  struct eth_addr ethaddr;

+  enum etharp_state state;

+  u8_t ctime;

+  struct netif *netif;

+};

+

+const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};

+const struct eth_addr ethzero = {{0,0,0,0,0,0}};

+static struct etharp_entry arp_table[ARP_TABLE_SIZE];

+#if !LWIP_NETIF_HWADDRHINT

+static u8_t etharp_cached_entry;

+#endif

+

+/**

+ * Try hard to create a new entry - we want the IP address to appear in

+ * the cache (even if this means removing an active entry or so). */

+#define ETHARP_TRY_HARD 1

+#define ETHARP_FIND_ONLY  2

+

+#if LWIP_NETIF_HWADDRHINT

+#define NETIF_SET_HINT(netif, hint)  if (((netif) != NULL) && ((netif)->addr_hint != NULL))  \

+                                      *((netif)->addr_hint) = (hint);

+static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif);

+#else /* LWIP_NETIF_HWADDRHINT */

+static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags);

+#endif /* LWIP_NETIF_HWADDRHINT */

+

+static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);

+

+

+/* Some checks, instead of etharp_init(): */

+#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))

+  #error "If you want to use ARP, ARP_TABLE_SIZE must fit in an s8_t, so, you have to reduce it in your lwipopts.h"

+#endif

+

+

+#if ARP_QUEUEING

+/**

+ * Free a complete queue of etharp entries

+ *

+ * @param q a qeueue of etharp_q_entry's to free

+ */

+static void

+free_etharp_q(struct etharp_q_entry *q)

+{

+  struct etharp_q_entry *r;

+  LWIP_ASSERT("q != NULL", q != NULL);

+  LWIP_ASSERT("q->p != NULL", q->p != NULL);

+  while (q) {

+    r = q;

+    q = q->next;

+    LWIP_ASSERT("r->p != NULL", (r->p != NULL));

+    pbuf_free(r->p);

+    memp_free(MEMP_ARP_QUEUE, r);

+  }

+}

+#endif

+

+/**

+ * Clears expired entries in the ARP table.

+ *

+ * This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds),

+ * in order to expire entries in the ARP table.

+ */

+void

+etharp_tmr(void)

+{

+  u8_t i;

+

+  LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));

+  /* remove expired entries from the ARP table */

+  for (i = 0; i < ARP_TABLE_SIZE; ++i) {

+    arp_table[i].ctime++;

+    if (((arp_table[i].state == ETHARP_STATE_STABLE) &&

+         (arp_table[i].ctime >= ARP_MAXAGE)) ||

+        ((arp_table[i].state == ETHARP_STATE_PENDING)  &&

+         (arp_table[i].ctime >= ARP_MAXPENDING))) {

+         /* pending or stable entry has become old! */

+      LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n",

+           arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));

+      /* clean up entries that have just been expired */

+      /* remove from SNMP ARP index tree */

+      snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);

+#if ARP_QUEUEING

+      /* and empty packet queue */

+      if (arp_table[i].q != NULL) {

+        /* remove all queued packets */

+        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));

+        free_etharp_q(arp_table[i].q);

+        arp_table[i].q = NULL;

+      }

+#endif

+      /* recycle entry for re-use */

+      arp_table[i].state = ETHARP_STATE_EMPTY;

+    }

+#if ARP_QUEUEING

+    /* still pending entry? (not expired) */

+    if (arp_table[i].state == ETHARP_STATE_PENDING) {

+        /* resend an ARP query here? */

+    }

+#endif

+  }

+}

+

+/**

+ * Search the ARP table for a matching or new entry.

+ *

+ * If an IP address is given, return a pending or stable ARP entry that matches

+ * the address. If no match is found, create a new entry with this address set,

+ * but in state ETHARP_EMPTY. The caller must check and possibly change the

+ * state of the returned entry.

+ *

+ * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.

+ *

+ * In all cases, attempt to create new entries from an empty entry. If no

+ * empty entries are available and ETHARP_TRY_HARD flag is set, recycle

+ * old entries. Heuristic choose the least important entry for recycling.

+ *

+ * @param ipaddr IP address to find in ARP cache, or to add if not found.

+ * @param flags

+ * - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of

+ * active (stable or pending) entries.

+ *

+ * @return The ARP entry index that matched or is created, ERR_MEM if no

+ * entry is found or could be recycled.

+ */

+static s8_t

+#if LWIP_NETIF_HWADDRHINT

+find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif)

+#else /* LWIP_NETIF_HWADDRHINT */

+find_entry(struct ip_addr *ipaddr, u8_t flags)

+#endif /* LWIP_NETIF_HWADDRHINT */

+{

+  s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;

+  s8_t empty = ARP_TABLE_SIZE;

+  u8_t i = 0, age_pending = 0, age_stable = 0;

+#if ARP_QUEUEING

+  /* oldest entry with packets on queue */

+  s8_t old_queue = ARP_TABLE_SIZE;

+  /* its age */

+  u8_t age_queue = 0;

+#endif

+

+  /* First, test if the last call to this function asked for the

+   * same address. If so, we're really fast! */

+  if (ipaddr) {

+    /* ipaddr to search for was given */

+#if LWIP_NETIF_HWADDRHINT

+    if ((netif != NULL) && (netif->addr_hint != NULL)) {

+      /* per-pcb cached entry was given */

+      u8_t per_pcb_cache = *(netif->addr_hint);

+      if ((per_pcb_cache < ARP_TABLE_SIZE) && arp_table[per_pcb_cache].state == ETHARP_STATE_STABLE) {

+        /* the per-pcb-cached entry is stable */

+        if (ip_addr_cmp(ipaddr, &arp_table[per_pcb_cache].ipaddr)) {

+          /* per-pcb cached entry was the right one! */

+          ETHARP_STATS_INC(etharp.cachehit);

+          return per_pcb_cache;

+        }

+      }

+    }

+#else /* #if LWIP_NETIF_HWADDRHINT */

+    if (arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) {

+      /* the cached entry is stable */

+      if (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr)) {

+        /* cached entry was the right one! */

+        ETHARP_STATS_INC(etharp.cachehit);

+        return etharp_cached_entry;

+      }

+    }

+#endif /* #if LWIP_NETIF_HWADDRHINT */

+  }

+

+  /**

+   * a) do a search through the cache, remember candidates

+   * b) select candidate entry

+   * c) create new entry

+   */

+

+  /* a) in a single search sweep, do all of this

+   * 1) remember the first empty entry (if any)

+   * 2) remember the oldest stable entry (if any)

+   * 3) remember the oldest pending entry without queued packets (if any)

+   * 4) remember the oldest pending entry with queued packets (if any)

+   * 5) search for a matching IP entry, either pending or stable

+   *    until 5 matches, or all entries are searched for.

+   */

+

+  for (i = 0; i < ARP_TABLE_SIZE; ++i) {

+    /* no empty entry found yet and now we do find one? */

+    if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_EMPTY)) {

+      LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));

+      /* remember first empty entry */

+      empty = i;

+    }

+    /* pending entry? */

+    else if (arp_table[i].state == ETHARP_STATE_PENDING) {

+      /* if given, does IP address match IP address in ARP entry? */

+      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {

+        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i));

+        /* found exact IP address match, simply bail out */

+#if LWIP_NETIF_HWADDRHINT

+        NETIF_SET_HINT(netif, i);

+#else /* #if LWIP_NETIF_HWADDRHINT */

+        etharp_cached_entry = i;

+#endif /* #if LWIP_NETIF_HWADDRHINT */

+        return i;

+#if ARP_QUEUEING

+      /* pending with queued packets? */

+      } else if (arp_table[i].q != NULL) {

+        if (arp_table[i].ctime >= age_queue) {

+          old_queue = i;

+          age_queue = arp_table[i].ctime;

+        }

+#endif

+      /* pending without queued packets? */

+      } else {

+        if (arp_table[i].ctime >= age_pending) {

+          old_pending = i;

+          age_pending = arp_table[i].ctime;

+        }

+      }

+    }

+    /* stable entry? */

+    else if (arp_table[i].state == ETHARP_STATE_STABLE) {

+      /* if given, does IP address match IP address in ARP entry? */

+      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {

+        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i));

+        /* found exact IP address match, simply bail out */

+#if LWIP_NETIF_HWADDRHINT

+        NETIF_SET_HINT(netif, i);

+#else /* #if LWIP_NETIF_HWADDRHINT */

+        etharp_cached_entry = i;

+#endif /* #if LWIP_NETIF_HWADDRHINT */

+        return i;

+      /* remember entry with oldest stable entry in oldest, its age in maxtime */

+      } else if (arp_table[i].ctime >= age_stable) {

+        old_stable = i;

+        age_stable = arp_table[i].ctime;

+      }

+    }

+  }

+  /* { we have no match } => try to create a new entry */

+

+  /* no empty entry found and not allowed to recycle? */

+  if (((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0))

+      /* or don't create new entry, only search? */

+      || ((flags & ETHARP_FIND_ONLY) != 0)) {

+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n"));

+    return (s8_t)ERR_MEM;

+  }

+

+  /* b) choose the least destructive entry to recycle:

+   * 1) empty entry

+   * 2) oldest stable entry

+   * 3) oldest pending entry without queued packets

+   * 4) oldest pending entry without queued packets

+   *

+   * { ETHARP_TRY_HARD is set at this point }

+   */

+

+  /* 1) empty entry available? */

+  if (empty < ARP_TABLE_SIZE) {

+    i = empty;

+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));

+  }

+  /* 2) found recyclable stable entry? */

+  else if (old_stable < ARP_TABLE_SIZE) {

+    /* recycle oldest stable*/

+    i = old_stable;

+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));

+#if ARP_QUEUEING

+    /* no queued packets should exist on stable entries */

+    LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);

+#endif

+  /* 3) found recyclable pending entry without queued packets? */

+  } else if (old_pending < ARP_TABLE_SIZE) {

+    /* recycle oldest pending */

+    i = old_pending;

+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));

+#if ARP_QUEUEING

+  /* 4) found recyclable pending entry with queued packets? */

+  } else if (old_queue < ARP_TABLE_SIZE) {

+    /* recycle oldest pending */

+    i = old_queue;

+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q)));

+    free_etharp_q(arp_table[i].q);

+    arp_table[i].q = NULL;

+#endif

+    /* no empty or recyclable entries found */

+  } else {

+    return (s8_t)ERR_MEM;

+  }

+

+  /* { empty or recyclable entry found } */

+  LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);

+

+  if (arp_table[i].state != ETHARP_STATE_EMPTY)

+  {

+    snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);

+  }

+  /* recycle entry (no-op for an already empty entry) */

+  arp_table[i].state = ETHARP_STATE_EMPTY;

+

+  /* IP address given? */

+  if (ipaddr != NULL) {

+    /* set IP address */

+    ip_addr_set(&arp_table[i].ipaddr, ipaddr);

+  }

+  arp_table[i].ctime = 0;

+#if LWIP_NETIF_HWADDRHINT

+  NETIF_SET_HINT(netif, i);

+#else /* #if LWIP_NETIF_HWADDRHINT */

+  etharp_cached_entry = i;

+#endif /* #if LWIP_NETIF_HWADDRHINT */

+  return (err_t)i;

+}

+

+/**

+ * Send an IP packet on the network using netif->linkoutput

+ * The ethernet header is filled in before sending.

+ *

+ * @params netif the lwIP network interface on which to send the packet

+ * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header

+ * @params src the source MAC address to be copied into the ethernet header

+ * @params dst the destination MAC address to be copied into the ethernet header

+ * @return ERR_OK if the packet was sent, any other err_t on failure

+ */

+static err_t

+etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst)

+{

+  struct eth_hdr *ethhdr = p->payload;

+  u8_t k;

+

+  LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",

+              (netif->hwaddr_len == ETHARP_HWADDR_LEN));

+  k = ETHARP_HWADDR_LEN;

+  while(k > 0) {

+    k--;

+    ethhdr->dest.addr[k] = dst->addr[k];

+    ethhdr->src.addr[k]  = src->addr[k];

+  }

+  ethhdr->type = htons(ETHTYPE_IP);

+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p));

+  /* send the packet */

+  return netif->linkoutput(netif, p);

+}

+

+/**

+ * Update (or insert) a IP/MAC address pair in the ARP cache.

+ *

+ * If a pending entry is resolved, any queued packets will be sent

+ * at this point.

+ *

+ * @param ipaddr IP address of the inserted ARP entry.

+ * @param ethaddr Ethernet address of the inserted ARP entry.

+ * @param flags Defines behaviour:

+ * - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified,

+ * only existing ARP entries will be updated.

+ *

+ * @return

+ * - ERR_OK Succesfully updated ARP cache.

+ * - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set.

+ * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.

+ *

+ * @see pbuf_free()

+ */

+static err_t

+update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)

+{

+  s8_t i;

+  u8_t k;

+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 3, ("update_arp_entry()\n"));

+  LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN);

+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",

+                                        ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr),

+                                        ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],

+                                        ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));

+  /* non-unicast address? */

+  if (ip_addr_isany(ipaddr) ||

+      ip_addr_isbroadcast(ipaddr, netif) ||

+      ip_addr_ismulticast(ipaddr)) {

+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));

+    return ERR_ARG;

+  }

+  /* find or create ARP entry */

+#if LWIP_NETIF_HWADDRHINT

+  i = find_entry(ipaddr, flags, netif);

+#else /* LWIP_NETIF_HWADDRHINT */

+  i = find_entry(ipaddr, flags);

+#endif /* LWIP_NETIF_HWADDRHINT */

+  /* bail out if no entry could be found */

+  if (i < 0)

+    return (err_t)i;

+

+  /* mark it stable */

+  arp_table[i].state = ETHARP_STATE_STABLE;

+  /* record network interface */

+  arp_table[i].netif = netif;

+

+  /* insert in SNMP ARP index tree */

+  snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);

+

+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));

+  /* update address */

+  k = ETHARP_HWADDR_LEN;

+  while (k > 0) {

+    k--;

+    arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];

+  }

+  /* reset time stamp */

+  arp_table[i].ctime = 0;

+#if ARP_QUEUEING

+  /* this is where we will send out queued packets! */

+  while (arp_table[i].q != NULL) {

+    struct pbuf *p;

+    /* remember remainder of queue */

+    struct etharp_q_entry *q = arp_table[i].q;

+    /* pop first item off the queue */

+    arp_table[i].q = q->next;

+    /* get the packet pointer */

+    p = q->p;

+    /* now queue entry can be freed */

+    memp_free(MEMP_ARP_QUEUE, q);

+    /* send the queued IP packet */

+    etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr);

+    /* free the queued IP packet */

+    pbuf_free(p);

+  }

+#endif

+  return ERR_OK;

+}

+

+/**

+ * Finds (stable) ethernet/IP address pair from ARP table

+ * using interface and IP address index.

+ * @note the addresses in the ARP table are in network order!

+ *

+ * @param netif points to interface index

+ * @param ipaddr points to the (network order) IP address index

+ * @param eth_ret points to return pointer

+ * @param ip_ret points to return pointer

+ * @return table index if found, -1 otherwise

+ */

+s8_t

+etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr,

+         struct eth_addr **eth_ret, struct ip_addr **ip_ret)

+{

+  s8_t i;

+

+  LWIP_UNUSED_ARG(netif);

+

+#if LWIP_NETIF_HWADDRHINT

+  i = find_entry(ipaddr, ETHARP_FIND_ONLY, NULL);

+#else /* LWIP_NETIF_HWADDRHINT */

+  i = find_entry(ipaddr, ETHARP_FIND_ONLY);

+#endif /* LWIP_NETIF_HWADDRHINT */

+  if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) {

+      *eth_ret = &arp_table[i].ethaddr;

+      *ip_ret = &arp_table[i].ipaddr;

+      return i;

+  }

+  return -1;

+}

+

+/**

+ * Updates the ARP table using the given IP packet.

+ *

+ * Uses the incoming IP packet's source address to update the

+ * ARP cache for the local network. The function does not alter

+ * or free the packet. This function must be called before the

+ * packet p is passed to the IP layer.

+ *

+ * @param netif The lwIP network interface on which the IP packet pbuf arrived.

+ * @param p The IP packet that arrived on netif.

+ *

+ * @return NULL

+ *

+ * @see pbuf_free()

+ */

+void

+etharp_ip_input(struct netif *netif, struct pbuf *p)

+{

+  struct ethip_hdr *hdr;

+  LWIP_ERROR("netif != NULL", (netif != NULL), return;);

+  /* Only insert an entry if the source IP address of the

+     incoming IP packet comes from a host on the local network. */

+  hdr = p->payload;

+  /* source is not on the local network? */

+  if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {

+    /* do nothing */

+    return;

+  }

+

+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));

+  /* update ARP table */

+  /* @todo We could use ETHARP_TRY_HARD if we think we are going to talk

+   * back soon (for example, if the destination IP address is ours. */

+  update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0);

+}

+

+

+/**

+ * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache

+ * send out queued IP packets. Updates cache with snooped address pairs.

+ *

+ * Should be called for incoming ARP packets. The pbuf in the argument

+ * is freed by this function.

+ *

+ * @param netif The lwIP network interface on which the ARP packet pbuf arrived.

+ * @param ethaddr Ethernet address of netif.

+ * @param p The ARP packet that arrived on netif. Is freed by this function.

+ *

+ * @return NULL

+ *

+ * @see pbuf_free()

+ */

+void

+etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)

+{

+  struct etharp_hdr *hdr;

+  /* these are aligned properly, whereas the ARP header fields might not be */

+  struct ip_addr sipaddr, dipaddr;

+  u8_t i;

+  u8_t for_us;

+#if LWIP_AUTOIP

+  const u8_t * ethdst_hwaddr;

+#endif /* LWIP_AUTOIP */

+

+  LWIP_ERROR("netif != NULL", (netif != NULL), return;);

+

+  /* drop short ARP packets: we have to check for p->len instead of p->tot_len here

+     since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */

+  if (p->len < sizeof(struct etharp_hdr)) {

+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 1, ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, (s16_t)sizeof(struct etharp_hdr)));

+    ETHARP_STATS_INC(etharp.lenerr);

+    ETHARP_STATS_INC(etharp.drop);

+    pbuf_free(p);

+    return;

+  }

+

+  hdr = p->payload;

+

+  /* RFC 826 "Packet Reception": */

+  if ((hdr->hwtype != htons(HWTYPE_ETHERNET)) ||

+      (hdr->_hwlen_protolen != htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr))) ||

+      (hdr->proto != htons(ETHTYPE_IP)) ||

+      (hdr->ethhdr.type != htons(ETHTYPE_ARP)))  {

+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 1,

+      ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",

+      hdr->hwtype, ARPH_HWLEN(hdr), hdr->proto, ARPH_PROTOLEN(hdr), hdr->ethhdr.type));

+    ETHARP_STATS_INC(etharp.proterr);

+    ETHARP_STATS_INC(etharp.drop);

+    pbuf_free(p);

+    return;

+  }

+  ETHARP_STATS_INC(etharp.recv);

+

+#if LWIP_AUTOIP

+  /* We have to check if a host already has configured our random

+   * created link local address and continously check if there is

+   * a host with this IP-address so we can detect collisions */

+  autoip_arp_reply(netif, hdr);

+#endif /* LWIP_AUTOIP */

+

+  /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without

+   * structure packing (not using structure copy which breaks strict-aliasing rules). */

+  SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));

+  SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));

+

+  /* this interface is not configured? */

+  if (netif->ip_addr.addr == 0) {

+    for_us = 0;

+  } else {

+    /* ARP packet directed to us? */

+    for_us = ip_addr_cmp(&dipaddr, &(netif->ip_addr));

+  }

+

+  /* ARP message directed to us? */

+  if (for_us) {

+    /* add IP address in ARP cache; assume requester wants to talk to us.

+     * can result in directly sending the queued packets for this host. */

+    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);

+  /* ARP message not directed to us? */

+  } else {

+    /* update the source IP address in the cache, if present */

+    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0);

+  }

+

+  /* now act on the message itself */

+  switch (htons(hdr->opcode)) {

+  /* ARP request? */

+  case ARP_REQUEST:

+    /* ARP request. If it asked for our address, we send out a

+     * reply. In any case, we time-stamp any existing ARP entry,

+     * and possiby send out an IP packet that was queued on it. */

+

+    LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP request\n"));

+    /* ARP request for our address? */

+    if (for_us) {

+

+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n"));

+      /* Re-use pbuf to send ARP reply.

+         Since we are re-using an existing pbuf, we can't call etharp_raw since

+         that would allocate a new pbuf. */

+      hdr->opcode = htons(ARP_REPLY);

+

+      hdr->dipaddr = hdr->sipaddr;

+      hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;

+

+      LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",

+                  (netif->hwaddr_len == ETHARP_HWADDR_LEN));

+      i = ETHARP_HWADDR_LEN;

+#if LWIP_AUTOIP

+      /* If we are using Link-Local, ARP packets must be broadcast on the

+       * link layer. (See RFC3927 Section 2.5) */

+      ethdst_hwaddr = ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) ? (u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr;

+#endif /* LWIP_AUTOIP */

+

+      while(i > 0) {

+        i--;

+        hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];

+#if LWIP_AUTOIP

+        hdr->ethhdr.dest.addr[i] = ethdst_hwaddr[i];

+#else  /* LWIP_AUTOIP */

+        hdr->ethhdr.dest.addr[i] = hdr->shwaddr.addr[i];

+#endif /* LWIP_AUTOIP */

+        hdr->shwaddr.addr[i] = ethaddr->addr[i];

+        hdr->ethhdr.src.addr[i] = ethaddr->addr[i];

+      }

+

+      /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header

+         are already correct, we tested that before */

+

+      /* return ARP reply */

+      netif->linkoutput(netif, p);

+    /* we are not configured? */

+    } else if (netif->ip_addr.addr == 0) {

+      /* { for_us == 0 and netif->ip_addr.addr == 0 } */

+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));

+    /* request was not directed to us */

+    } else {

+      /* { for_us == 0 and netif->ip_addr.addr != 0 } */

+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n"));

+    }

+    break;

+  case ARP_REPLY:

+    /* ARP reply. We already updated the ARP cache earlier. */

+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));

+#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)

+    /* DHCP wants to know about ARP replies from any host with an

+     * IP address also offered to us by the DHCP server. We do not

+     * want to take a duplicate IP address on a single network.

+     * @todo How should we handle redundant (fail-over) interfaces? */

+    dhcp_arp_reply(netif, &sipaddr);

+#endif

+    break;

+  default:

+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode)));

+    ETHARP_STATS_INC(etharp.err);

+    break;

+  }

+  /* free ARP packet */

+  pbuf_free(p);

+}

+

+/**

+ * Resolve and fill-in Ethernet address header for outgoing IP packet.

+ *

+ * For IP multicast and broadcast, corresponding Ethernet addresses

+ * are selected and the packet is transmitted on the link.

+ *

+ * For unicast addresses, the packet is submitted to etharp_query(). In

+ * case the IP address is outside the local network, the IP address of

+ * the gateway is used.

+ *

+ * @param netif The lwIP network interface which the IP packet will be sent on.

+ * @param q The pbuf(s) containing the IP packet to be sent.

+ * @param ipaddr The IP address of the packet destination.

+ *

+ * @return

+ * - ERR_RTE No route to destination (no gateway to external networks),

+ * or the return type of either etharp_query() or etharp_send_ip().

+ */

+err_t

+etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr)

+{

+  struct eth_addr *dest, mcastaddr;

+

+  /* make room for Ethernet header - should not fail */

+  if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {

+    /* bail out */

+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n"));

+    LINK_STATS_INC(link.lenerr);

+    return ERR_BUF;

+  }

+

+  /* assume unresolved Ethernet address */

+  dest = NULL;

+  /* Determine on destination hardware address. Broadcasts and multicasts

+   * are special, other IP addresses are looked up in the ARP table. */

+

+  /* broadcast destination IP address? */

+  if (ip_addr_isbroadcast(ipaddr, netif)) {

+    /* broadcast on Ethernet also */

+    dest = (struct eth_addr *)&ethbroadcast;

+  /* multicast destination IP address? */

+  } else if (ip_addr_ismulticast(ipaddr)) {

+    /* Hash IP multicast address to MAC address.*/

+    mcastaddr.addr[0] = 0x01;

+    mcastaddr.addr[1] = 0x00;

+    mcastaddr.addr[2] = 0x5e;

+    mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;

+    mcastaddr.addr[4] = ip4_addr3(ipaddr);

+    mcastaddr.addr[5] = ip4_addr4(ipaddr);

+    /* destination Ethernet address is multicast */

+    dest = &mcastaddr;

+  /* unicast destination IP address? */

+  } else {

+    /* outside local network? */

+    if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {

+      /* interface has default gateway? */

+      if (netif->gw.addr != 0) {

+        /* send to hardware address of default gateway IP address */

+        ipaddr = &(netif->gw);

+      /* no default gateway available */

+      } else {

+        /* no route to destination error (default gateway missing) */

+        return ERR_RTE;

+      }

+    }

+    /* queue on destination Ethernet address belonging to ipaddr */

+    return etharp_query(netif, ipaddr, q);

+  }

+

+  /* continuation for multicast/broadcast destinations */

+  /* obtain source Ethernet address of the given interface */

+  /* send packet directly on the link */

+  return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest);

+}

+

+/**

+ * Send an ARP request for the given IP address and/or queue a packet.

+ *

+ * If the IP address was not yet in the cache, a pending ARP cache entry

+ * is added and an ARP request is sent for the given address. The packet

+ * is queued on this entry.

+ *

+ * If the IP address was already pending in the cache, a new ARP request

+ * is sent for the given address. The packet is queued on this entry.

+ *

+ * If the IP address was already stable in the cache, and a packet is

+ * given, it is directly sent and no ARP request is sent out.

+ *

+ * If the IP address was already stable in the cache, and no packet is

+ * given, an ARP request is sent out.

+ *

+ * @param netif The lwIP network interface on which ipaddr

+ * must be queried for.

+ * @param ipaddr The IP address to be resolved.

+ * @param q If non-NULL, a pbuf that must be delivered to the IP address.

+ * q is not freed by this function.

+ *

+ * @note q must only be ONE packet, not a packet queue!

+ *

+ * @return

+ * - ERR_BUF Could not make room for Ethernet header.

+ * - ERR_MEM Hardware address unknown, and no more ARP entries available

+ *   to query for address or queue the packet.

+ * - ERR_MEM Could not queue packet due to memory shortage.

+ * - ERR_RTE No route to destination (no gateway to external networks).

+ * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.

+ *

+ */

+err_t

+etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)

+{

+  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;

+  err_t result = ERR_MEM;

+  s8_t i; /* ARP entry index */

+

+  /* non-unicast address? */

+  if (ip_addr_isbroadcast(ipaddr, netif) ||

+      ip_addr_ismulticast(ipaddr) ||

+      ip_addr_isany(ipaddr)) {

+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n"));

+    return ERR_ARG;

+  }

+

+  /* find entry in ARP cache, ask to create entry if queueing packet */

+#if LWIP_NETIF_HWADDRHINT

+  i = find_entry(ipaddr, ETHARP_TRY_HARD, netif);

+#else /* LWIP_NETIF_HWADDRHINT */

+  i = find_entry(ipaddr, ETHARP_TRY_HARD);

+#endif /* LWIP_NETIF_HWADDRHINT */

+

+  /* could not find or create entry? */

+  if (i < 0) {

+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n"));

+    if (q) {

+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n"));

+      ETHARP_STATS_INC(etharp.memerr);

+    }

+    return (err_t)i;

+  }

+

+  /* mark a fresh entry as pending (we just sent a request) */

+  if (arp_table[i].state == ETHARP_STATE_EMPTY) {

+    arp_table[i].state = ETHARP_STATE_PENDING;

+  }

+

+  /* { i is either a STABLE or (new or existing) PENDING entry } */

+  LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",

+  ((arp_table[i].state == ETHARP_STATE_PENDING) ||

+   (arp_table[i].state == ETHARP_STATE_STABLE)));

+

+  /* do we have a pending entry? or an implicit query request? */

+  if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {

+    /* try to resolve it; send out ARP request */

+    result = etharp_request(netif, ipaddr);

+    if (result != ERR_OK) {

+      /* ARP request couldn't be sent */

+      /* We don't re-send arp request in etharp_tmr, but we still queue packets,

+         since this failure could be temporary, and the next packet calling

+         etharp_query again could lead to sending the queued packets. */

+    }

+  }

+

+  /* packet given? */

+  if (q != NULL) {

+    /* stable entry? */

+    if (arp_table[i].state == ETHARP_STATE_STABLE) {

+      /* we have a valid IP->Ethernet address mapping */

+      /* send the packet */

+      result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));

+    /* pending entry? (either just created or already pending */

+    } else if (arp_table[i].state == ETHARP_STATE_PENDING) {

+#if ARP_QUEUEING /* queue the given q packet */

+      struct pbuf *p;

+      int copy_needed = 0;

+      /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but

+       * to copy the whole queue into a new PBUF_RAM (see bug #11400)

+       * PBUF_ROMs can be left as they are, since ROM must not get changed. */

+      p = q;

+      while (p) {

+        LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0));

+        if(p->type != PBUF_ROM) {

+          copy_needed = 1;

+          break;

+        }

+        p = p->next;

+      }

+      if(copy_needed) {

+        /* copy the whole packet into new pbufs */

+        p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);

+        if(p != NULL) {

+          if (pbuf_copy(p, q) != ERR_OK) {

+            pbuf_free(p);

+            p = NULL;

+          }

+        }

+      } else {

+        /* referencing the old pbuf is enough */

+        p = q;

+        pbuf_ref(p);

+      }

+      /* packet could be taken over? */

+      if (p != NULL) {

+        /* queue packet ... */

+        struct etharp_q_entry *new_entry;

+        /* allocate a new arp queue entry */

+        new_entry = memp_malloc(MEMP_ARP_QUEUE);

+        if (new_entry != NULL) {

+          new_entry->next = 0;

+          new_entry->p = p;

+          if(arp_table[i].q != NULL) {

+            /* queue was already existent, append the new entry to the end */

+            struct etharp_q_entry *r;

+            r = arp_table[i].q;

+            while (r->next != NULL) {

+              r = r->next;

+            }

+            r->next = new_entry;

+          } else {

+            /* queue did not exist, first item in queue */

+            arp_table[i].q = new_entry;

+          }

+          LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));

+          result = ERR_OK;

+        } else {

+          /* the pool MEMP_ARP_QUEUE is empty */

+          pbuf_free(p);

+          LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));

+          /* { result == ERR_MEM } through initialization */

+        }

+      } else {

+        ETHARP_STATS_INC(etharp.memerr);

+        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));

+        /* { result == ERR_MEM } through initialization */

+      }

+#else /* ARP_QUEUEING == 0 */

+      /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */

+      /* { result == ERR_MEM } through initialization */

+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));

+#endif

+    }

+  }

+  return result;

+}

+

+/**

+ * Send a raw ARP packet (opcode and all addresses can be modified)

+ *

+ * @param netif the lwip network interface on which to send the ARP packet

+ * @param ethsrc_addr the source MAC address for the ethernet header

+ * @param ethdst_addr the destination MAC address for the ethernet header

+ * @param hwsrc_addr the source MAC address for the ARP protocol header

+ * @param ipsrc_addr the source IP address for the ARP protocol header

+ * @param hwdst_addr the destination MAC address for the ARP protocol header

+ * @param ipdst_addr the destination IP address for the ARP protocol header

+ * @param opcode the type of the ARP packet

+ * @return ERR_OK if the ARP packet has been sent

+ *         ERR_MEM if the ARP packet couldn't be allocated

+ *         any other err_t on failure

+ */

+#if !LWIP_AUTOIP

+static

+#endif /* LWIP_AUTOIP */

+err_t

+etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,

+           const struct eth_addr *ethdst_addr,

+           const struct eth_addr *hwsrc_addr, const struct ip_addr *ipsrc_addr,

+           const struct eth_addr *hwdst_addr, const struct ip_addr *ipdst_addr,

+           const u16_t opcode)

+{

+  struct pbuf *p;

+  err_t result = ERR_OK;

+  u8_t k; /* ARP entry index */

+  struct etharp_hdr *hdr;

+#if LWIP_AUTOIP

+  const u8_t * ethdst_hwaddr;

+#endif /* LWIP_AUTOIP */

+

+  /* allocate a pbuf for the outgoing ARP request packet */

+  p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);

+  /* could allocate a pbuf for an ARP request? */

+  if (p == NULL) {

+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2, ("etharp_raw: could not allocate pbuf for ARP request.\n"));

+    ETHARP_STATS_INC(etharp.memerr);

+    return ERR_MEM;

+  }

+  LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr",

+              (p->len >= sizeof(struct etharp_hdr)));

+

+  hdr = p->payload;

+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n"));

+  hdr->opcode = htons(opcode);

+

+  LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",

+              (netif->hwaddr_len == ETHARP_HWADDR_LEN));

+  k = ETHARP_HWADDR_LEN;

+#if LWIP_AUTOIP

+  /* If we are using Link-Local, ARP packets must be broadcast on the

+   * link layer. (See RFC3927 Section 2.5) */

+  ethdst_hwaddr = ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr;

+#endif /* LWIP_AUTOIP */

+  /* Write MAC-Addresses (combined loop for both headers) */

+  while(k > 0) {

+    k--;

+    /* Write the ARP MAC-Addresses */

+    hdr->shwaddr.addr[k] = hwsrc_addr->addr[k];

+    hdr->dhwaddr.addr[k] = hwdst_addr->addr[k];

+    /* Write the Ethernet MAC-Addresses */

+#if LWIP_AUTOIP

+    hdr->ethhdr.dest.addr[k] = ethdst_hwaddr[k];

+#else  /* LWIP_AUTOIP */

+    hdr->ethhdr.dest.addr[k] = ethdst_addr->addr[k];

+#endif /* LWIP_AUTOIP */

+    hdr->ethhdr.src.addr[k]  = ethsrc_addr->addr[k];

+  }

+  hdr->sipaddr = *(struct ip_addr2 *)ipsrc_addr;

+  hdr->dipaddr = *(struct ip_addr2 *)ipdst_addr;

+

+  hdr->hwtype = htons(HWTYPE_ETHERNET);

+  hdr->proto = htons(ETHTYPE_IP);

+  /* set hwlen and protolen together */

+  hdr->_hwlen_protolen = htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr));

+

+  hdr->ethhdr.type = htons(ETHTYPE_ARP);

+  /* send ARP query */

+  result = netif->linkoutput(netif, p);

+  ETHARP_STATS_INC(etharp.xmit);

+  /* free ARP query packet */

+  pbuf_free(p);

+  p = NULL;

+  /* could not allocate pbuf for ARP request */

+

+  return result;

+}

+

+/**

+ * Send an ARP request packet asking for ipaddr.

+ *

+ * @param netif the lwip network interface on which to send the request

+ * @param ipaddr the IP address for which to ask

+ * @return ERR_OK if the request has been sent

+ *         ERR_MEM if the ARP packet couldn't be allocated

+ *         any other err_t on failure

+ */

+err_t

+etharp_request(struct netif *netif, struct ip_addr *ipaddr)

+{

+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n"));

+  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,

+                    (struct eth_addr *)netif->hwaddr, &netif->ip_addr, &ethzero,

+                    ipaddr, ARP_REQUEST);

+}

+

+/**

+ * Process received ethernet frames. Using this function instead of directly

+ * calling ip_input and passing ARP frames through etharp in ethernetif_input,

+ * the ARP cache is protected from concurrent access.

+ *

+ * @param p the recevied packet, p->payload pointing to the ethernet header

+ * @param netif the network interface on which the packet was received

+ */

+err_t

+ethernet_input(struct pbuf *p, struct netif *netif)

+{

+  struct eth_hdr* ethhdr;

+

+  /* points to packet payload, which starts with an Ethernet header */

+  ethhdr = p->payload;

+

+  switch (htons(ethhdr->type)) {

+    /* IP packet? */

+    case ETHTYPE_IP:

+#if ETHARP_TRUST_IP_MAC

+      /* update ARP table */

+      etharp_ip_input(netif, p);

+#endif /* ETHARP_TRUST_IP_MAC */

+      /* skip Ethernet header */

+      if(pbuf_header(p, -(s16_t)sizeof(struct eth_hdr))) {

+        LWIP_ASSERT("Can't move over header in packet", 0);

+        pbuf_free(p);

+        p = NULL;

+      } else {

+        /* pass to IP layer */

+        ip_input(p, netif);

+      }

+      break;

+

+    case ETHTYPE_ARP:

+      /* pass p to ARP module */

+      etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p);

+      break;

+

+#if PPPOE_SUPPORT

+    case ETHTYPE_PPPOEDISC: /* PPP Over Ethernet Discovery Stage */

+      pppoe_disc_input(netif, p);

+      break;

+

+    case ETHTYPE_PPPOE: /* PPP Over Ethernet Session Stage */

+      pppoe_data_input(netif, p);

+      break;

+#endif /* PPPOE_SUPPORT */

+

+    default:

+      pbuf_free(p);

+      p = NULL;

+      break;

+  }

+

+  /* This means the pbuf is freed or consumed,

+     so the caller doesn't have to free it again */

+  return ERR_OK;

+}

+#endif /* LWIP_ARP */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ethernetif.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ethernetif.c
new file mode 100644
index 0000000..58b879d
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ethernetif.c
@@ -0,0 +1,313 @@
+/**

+ * @file

+ * Ethernet Interface Skeleton

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved. 

+ * 

+ * Redistribution and use in source and binary forms, with or without modification, 

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ * 

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+/*

+ * This file is a skeleton for developing Ethernet network interface

+ * drivers for lwIP. Add code to the low_level functions and do a

+ * search-and-replace for the word "ethernetif" to replace it with

+ * something that better describes your network interface.

+ */

+

+#include "lwip/opt.h"

+

+#if 0 /* don't build, this is only a skeleton, see previous comment */

+

+#include "lwip/def.h"

+#include "lwip/mem.h"

+#include "lwip/pbuf.h"

+#include "lwip/sys.h"

+#include <lwip/stats.h>

+#include <lwip/snmp.h>

+#include "netif/etharp.h"

+#include "netif/ppp_oe.h"

+

+/* Define those to better describe your network interface. */

+#define IFNAME0 'e'

+#define IFNAME1 'n'

+

+/**

+ * Helper struct to hold private data used to operate your ethernet interface.

+ * Keeping the ethernet address of the MAC in this struct is not necessary

+ * as it is already kept in the struct netif.

+ * But this is only an example, anyway...

+ */

+struct ethernetif {

+  struct eth_addr *ethaddr;

+  /* Add whatever per-interface state that is needed here. */

+};

+

+/* Forward declarations. */

+static void  ethernetif_input(struct netif *netif);

+

+/**

+ * In this function, the hardware should be initialized.

+ * Called from ethernetif_init().

+ *

+ * @param netif the already initialized lwip network interface structure

+ *        for this ethernetif

+ */

+static void

+low_level_init(struct netif *netif)

+{

+  struct ethernetif *ethernetif = netif->state;

+  

+  /* set MAC hardware address length */

+  netif->hwaddr_len = ETHARP_HWADDR_LEN;

+

+  /* set MAC hardware address */

+  netif->hwaddr[0] = ;

+  ...

+  netif->hwaddr[5] = ;

+

+  /* maximum transfer unit */

+  netif->mtu = 1500;

+  

+  /* device capabilities */

+  /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */

+  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;

+ 

+  /* Do whatever else is needed to initialize interface. */  

+}

+

+/**

+ * This function should do the actual transmission of the packet. The packet is

+ * contained in the pbuf that is passed to the function. This pbuf

+ * might be chained.

+ *

+ * @param netif the lwip network interface structure for this ethernetif

+ * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)

+ * @return ERR_OK if the packet could be sent

+ *         an err_t value if the packet couldn't be sent

+ *

+ * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to

+ *       strange results. You might consider waiting for space in the DMA queue

+ *       to become availale since the stack doesn't retry to send a packet

+ *       dropped because of memory failure (except for the TCP timers).

+ */

+

+static err_t

+low_level_output(struct netif *netif, struct pbuf *p)

+{

+  struct ethernetif *ethernetif = netif->state;

+  struct pbuf *q;

+

+  initiate transfer();

+  

+#if ETH_PAD_SIZE

+  pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */

+#endif

+

+  for(q = p; q != NULL; q = q->next) {

+    /* Send the data from the pbuf to the interface, one pbuf at a

+       time. The size of the data in each pbuf is kept in the ->len

+       variable. */

+    send data from(q->payload, q->len);

+  }

+

+  signal that packet should be sent();

+

+#if ETH_PAD_SIZE

+  pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */

+#endif

+  

+  LINK_STATS_INC(link.xmit);

+

+  return ERR_OK;

+}

+

+/**

+ * Should allocate a pbuf and transfer the bytes of the incoming

+ * packet from the interface into the pbuf.

+ *

+ * @param netif the lwip network interface structure for this ethernetif

+ * @return a pbuf filled with the received packet (including MAC header)

+ *         NULL on memory error

+ */

+static struct pbuf *

+low_level_input(struct netif *netif)

+{

+  struct ethernetif *ethernetif = netif->state;

+  struct pbuf *p, *q;

+  u16_t len;

+

+  /* Obtain the size of the packet and put it into the "len"

+     variable. */

+  len = ;

+

+#if ETH_PAD_SIZE

+  len += ETH_PAD_SIZE; /* allow room for Ethernet padding */

+#endif

+

+  /* We allocate a pbuf chain of pbufs from the pool. */

+  p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);

+  

+  if (p != NULL) {

+

+#if ETH_PAD_SIZE

+    pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */

+#endif

+

+    /* We iterate over the pbuf chain until we have read the entire

+     * packet into the pbuf. */

+    for(q = p; q != NULL; q = q->next) {

+      /* Read enough bytes to fill this pbuf in the chain. The

+       * available data in the pbuf is given by the q->len

+       * variable. */

+      read data into(q->payload, q->len);

+    }

+    acknowledge that packet has been read();

+

+#if ETH_PAD_SIZE

+    pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */

+#endif

+

+    LINK_STATS_INC(link.recv);

+  } else {

+    drop packet();

+    LINK_STATS_INC(link.memerr);

+    LINK_STATS_INC(link.drop);

+  }

+

+  return p;  

+}

+

+/**

+ * This function should be called when a packet is ready to be read

+ * from the interface. It uses the function low_level_input() that

+ * should handle the actual reception of bytes from the network

+ * interface. Then the type of the received packet is determined and

+ * the appropriate input function is called.

+ *

+ * @param netif the lwip network interface structure for this ethernetif

+ */

+static void

+ethernetif_input(struct netif *netif)

+{

+  struct ethernetif *ethernetif;

+  struct eth_hdr *ethhdr;

+  struct pbuf *p;

+

+  ethernetif = netif->state;

+

+  /* move received packet into a new pbuf */

+  p = low_level_input(netif);

+  /* no packet could be read, silently ignore this */

+  if (p == NULL) return;

+  /* points to packet payload, which starts with an Ethernet header */

+  ethhdr = p->payload;

+

+  switch (htons(ethhdr->type)) {

+  /* IP or ARP packet? */

+  case ETHTYPE_IP:

+  case ETHTYPE_ARP:

+#if PPPOE_SUPPORT

+  /* PPPoE packet? */

+  case ETHTYPE_PPPOEDISC:

+  case ETHTYPE_PPPOE:

+#endif /* PPPOE_SUPPORT */

+    /* full packet send to tcpip_thread to process */

+    if (netif->input(p, netif)!=ERR_OK)

+     { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));

+       pbuf_free(p);

+       p = NULL;

+     }

+    break;

+

+  default:

+    pbuf_free(p);

+    p = NULL;

+    break;

+  }

+}

+

+/**

+ * Should be called at the beginning of the program to set up the

+ * network interface. It calls the function low_level_init() to do the

+ * actual setup of the hardware.

+ *

+ * This function should be passed as a parameter to netif_add().

+ *

+ * @param netif the lwip network interface structure for this ethernetif

+ * @return ERR_OK if the loopif is initialized

+ *         ERR_MEM if private data couldn't be allocated

+ *         any other err_t on error

+ */

+err_t

+ethernetif_init(struct netif *netif)

+{

+  struct ethernetif *ethernetif;

+

+  LWIP_ASSERT("netif != NULL", (netif != NULL));

+    

+  ethernetif = mem_malloc(sizeof(struct ethernetif));

+  if (ethernetif == NULL) {

+    LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));

+    return ERR_MEM;

+  }

+

+#if LWIP_NETIF_HOSTNAME

+  /* Initialize interface hostname */

+  netif->hostname = "lwip";

+#endif /* LWIP_NETIF_HOSTNAME */

+

+  /*

+   * Initialize the snmp variables and counters inside the struct netif.

+   * The last argument should be replaced with your link speed, in units

+   * of bits per second.

+   */

+  NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, ???);

+

+  netif->state = ethernetif;

+  netif->name[0] = IFNAME0;

+  netif->name[1] = IFNAME1;

+  /* We directly use etharp_output() here to save a function call.

+   * You can instead declare your own function an call etharp_output()

+   * from it if you have to do some checks before sending (e.g. if link

+   * is available...) */

+  netif->output = etharp_output;

+  netif->linkoutput = low_level_output;

+  

+  ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);

+  

+  /* initialize the hardware */

+  low_level_init(netif);

+

+  return ERR_OK;

+}

+

+#endif /* 0 */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/loopif.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/loopif.c
new file mode 100644
index 0000000..a84c842
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/loopif.c
@@ -0,0 +1,217 @@
+/**

+ * @file

+ * Loop Interface

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved. 

+ * 

+ * Redistribution and use in source and binary forms, with or without modification, 

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ * 

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+#include "lwip/opt.h"

+

+#if LWIP_HAVE_LOOPIF

+

+#include "netif/loopif.h"

+#include "lwip/pbuf.h"

+#include "lwip/snmp.h"

+

+#include <string.h>

+

+#if !LWIP_LOOPIF_MULTITHREADING

+

+#include "lwip/sys.h"

+#include "lwip/mem.h"

+

+/* helper struct for the linked list of pbufs */

+struct loopif_private {

+  struct pbuf *first;

+  struct pbuf *last;

+};

+

+/**

+ * Call loopif_poll() in the main loop of your application. This is to prevent

+ * reentering non-reentrant functions like tcp_input(). Packets passed to

+ * loopif_output() are put on a list that is passed to netif->input() by

+ * loopif_poll().

+ *

+ * @param netif the lwip network interface structure for this loopif

+ */

+void

+loopif_poll(struct netif *netif)

+{

+  SYS_ARCH_DECL_PROTECT(lev);

+  struct pbuf *in, *in_end;

+  struct loopif_private *priv = (struct loopif_private*)netif->state;

+

+  LWIP_ERROR("priv != NULL", (priv != NULL), return;);

+

+  do {

+    /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */

+    SYS_ARCH_PROTECT(lev);

+    in = priv->first;

+    if(in) {

+      in_end = in;

+      while(in_end->len != in_end->tot_len) {

+        LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);

+        in_end = in_end->next;

+      }

+      /* 'in_end' now points to the last pbuf from 'in' */

+      if(in_end == priv->last) {

+        /* this was the last pbuf in the list */

+        priv->first = priv->last = NULL;

+      } else {

+        /* pop the pbuf off the list */

+        priv->first = in_end->next;

+        LWIP_ASSERT("should not be null since first != last!", priv->first != NULL);

+      }

+    }

+    SYS_ARCH_UNPROTECT(lev);

+  

+    if(in != NULL) {

+      if(in_end->next != NULL) {

+        /* De-queue the pbuf from its successors on the 'priv' list. */

+        in_end->next = NULL;

+      }

+      if(netif->input(in, netif) != ERR_OK) {

+        pbuf_free(in);

+      }

+      /* Don't reference the packet any more! */

+      in = NULL;

+      in_end = NULL;

+    }

+  /* go on while there is a packet on the list */

+  } while(priv->first != NULL);

+}

+#endif /* LWIP_LOOPIF_MULTITHREADING */

+

+/**

+ * Send an IP packet over the loopback interface.

+ * The pbuf is simply copied and handed back to netif->input.

+ * In multithreaded mode, this is done directly since netif->input must put

+ * the packet on a queue.

+ * In callback mode, the packet is put on an internal queue and is fed to

+ * netif->input by loopif_poll().

+ *

+ * @param netif the lwip network interface structure for this loopif

+ * @param p the (IP) packet to 'send'

+ * @param ipaddr the ip address to send the packet to (not used for loopif)

+ * @return ERR_OK if the packet has been sent

+ *         ERR_MEM if the pbuf used to copy the packet couldn't be allocated

+ */

+static err_t

+loopif_output(struct netif *netif, struct pbuf *p,

+       struct ip_addr *ipaddr)

+{

+#if !LWIP_LOOPIF_MULTITHREADING

+  SYS_ARCH_DECL_PROTECT(lev);

+  struct loopif_private *priv;

+  struct pbuf *last;

+#endif /* LWIP_LOOPIF_MULTITHREADING */

+  struct pbuf *r;

+  err_t err;

+

+  LWIP_UNUSED_ARG(ipaddr);

+

+  /* Allocate a new pbuf */

+  r = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);

+  if (r == NULL) {

+    return ERR_MEM;

+  }

+

+  /* Copy the whole pbuf queue p into the single pbuf r */

+  if ((err = pbuf_copy(r, p)) != ERR_OK) {

+    pbuf_free(r);

+    r = NULL;

+    return err;

+  }

+

+#if LWIP_LOOPIF_MULTITHREADING

+  /* Multithreading environment, netif->input() is supposed to put the packet

+     into a mailbox, so we can safely call it here without risking to re-enter

+     functions that are not reentrant (TCP!!!) */

+  if(netif->input(r, netif) != ERR_OK) {

+    pbuf_free(r);

+    r = NULL;

+  }

+#else /* LWIP_LOOPIF_MULTITHREADING */

+  /* Raw API without threads: put the packet on a linked list which gets emptied

+     through calling loopif_poll(). */

+  priv = (struct loopif_private*)netif->state;

+

+  /* let last point to the last pbuf in chain r */

+  for (last = r; last->next != NULL; last = last->next);

+  SYS_ARCH_PROTECT(lev);

+  if(priv->first != NULL) {

+    LWIP_ASSERT("if first != NULL, last must also be != NULL", priv->last != NULL);

+    priv->last->next = r;

+    priv->last = last;

+  } else {

+    priv->first = r;

+    priv->last = last;

+  }

+  SYS_ARCH_UNPROTECT(lev);

+#endif /* LWIP_LOOPIF_MULTITHREADING */

+

+  return ERR_OK;    

+}

+

+/**

+ * Initialize a lwip network interface structure for a loopback interface

+ *

+ * @param netif the lwip network interface structure for this loopif

+ * @return ERR_OK if the loopif is initialized

+ *         ERR_MEM if private data couldn't be allocated

+ */

+err_t

+loopif_init(struct netif *netif)

+{

+#if !LWIP_LOOPIF_MULTITHREADING

+  struct loopif_private *priv;

+

+  priv = (struct loopif_private*)mem_malloc(sizeof(struct loopif_private));

+  if(priv == NULL) 

+    return ERR_MEM;

+  priv->first = priv->last = NULL;

+  netif->state = priv;

+#endif /* LWIP_LOOPIF_MULTITHREADING */

+

+  /* initialize the snmp variables and counters inside the struct netif

+   * ifSpeed: no assumption can be made!

+   */

+  NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0);

+

+  netif->name[0] = 'l';

+  netif->name[1] = 'o';

+  netif->output = loopif_output;

+  return ERR_OK;

+}

+

+#endif /* LWIP_HAVE_LOOPIF */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/auth.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/auth.c
new file mode 100644
index 0000000..c637c2d
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/auth.c
@@ -0,0 +1,988 @@
+/*****************************************************************************

+* auth.c - Network Authentication and Phase Control program file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.

+*   Ported from public pppd code.

+*****************************************************************************/

+/*

+ * auth.c - PPP authentication and phase control.

+ *

+ * Copyright (c) 1993 The Australian National University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by the Australian National University.  The name of the University

+ * may not be used to endorse or promote products derived from this

+ * software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ *

+ * Copyright (c) 1989 Carnegie Mellon University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Carnegie Mellon University.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ */

+

+#include "lwip/opt.h"

+

+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#include "ppp.h"

+#include "pppdebug.h"

+

+#include "fsm.h"

+#include "lcp.h"

+#include "pap.h"

+#include "chap.h"

+#include "auth.h"

+#include "ipcp.h"

+

+#if CBCP_SUPPORT

+#include "cbcp.h"

+#endif /* CBCP_SUPPORT */

+

+/*************************/

+/*** LOCAL DEFINITIONS ***/

+/*************************/

+

+/* Bits in auth_pending[] */

+#define PAP_WITHPEER    1

+#define PAP_PEER        2

+#define CHAP_WITHPEER   4

+#define CHAP_PEER       8

+

+

+/************************/

+/*** LOCAL DATA TYPES ***/

+/************************/

+/* Used for storing a sequence of words.  Usually malloced. */

+struct wordlist {

+  struct wordlist *next;

+  char        word[1];

+};

+

+

+/***********************************/

+/*** LOCAL FUNCTION DECLARATIONS ***/

+/***********************************/

+extern char *crypt (const char *, const char *);

+

+/* Prototypes for procedures local to this file. */

+

+static void network_phase (int);

+static void check_idle (void *);

+static void connect_time_expired (void *);

+#if 0

+static int  login (char *, char *, char **, int *);

+#endif

+static void logout (void);

+static int  null_login (int);

+static int  get_pap_passwd (int, char *, char *);

+static int  have_pap_secret (void);

+static int  have_chap_secret (char *, char *, u32_t);

+static int  ip_addr_check (u32_t, struct wordlist *);

+#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */

+static void set_allowed_addrs(int unit, struct wordlist *addrs);

+static void free_wordlist (struct wordlist *);

+#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */

+#if CBCP_SUPPORT

+static void callback_phase (int);

+#endif /* CBCP_SUPPORT */

+

+

+/******************************/

+/*** PUBLIC DATA STRUCTURES ***/

+/******************************/

+

+

+/*****************************/

+/*** LOCAL DATA STRUCTURES ***/

+/*****************************/

+#if PAP_SUPPORT || CHAP_SUPPORT

+/* The name by which the peer authenticated itself to us. */

+static char peer_authname[MAXNAMELEN];

+#endif /* PAP_SUPPORT || CHAP_SUPPORT */

+

+/* Records which authentication operations haven't completed yet. */

+static int auth_pending[NUM_PPP];

+

+/* Set if we have successfully called login() */

+static int logged_in;

+

+/* Set if we have run the /etc/ppp/auth-up script. */

+static int did_authup;

+

+/* List of addresses which the peer may use. */

+static struct wordlist *addresses[NUM_PPP];

+

+/* Number of network protocols which we have opened. */

+static int num_np_open;

+

+/* Number of network protocols which have come up. */

+static int num_np_up;

+

+#if PAP_SUPPORT || CHAP_SUPPORT

+/* Set if we got the contents of passwd[] from the pap-secrets file. */

+static int passwd_from_file;

+#endif /* PAP_SUPPORT || CHAP_SUPPORT */

+

+

+/***********************************/

+/*** PUBLIC FUNCTION DEFINITIONS ***/

+/***********************************/

+/*

+ * An Open on LCP has requested a change from Dead to Establish phase.

+ * Do what's necessary to bring the physical layer up.

+ */

+void

+link_required(int unit)

+{

+  LWIP_UNUSED_ARG(unit);

+

+  AUTHDEBUG((LOG_INFO, "link_required: %d\n", unit));

+}

+

+/*

+ * LCP has terminated the link; go to the Dead phase and take the

+ * physical layer down.

+ */

+void

+link_terminated(int unit)

+{

+  AUTHDEBUG((LOG_INFO, "link_terminated: %d\n", unit));

+  if (lcp_phase[unit] == PHASE_DEAD) {

+    return;

+  }

+  if (logged_in) {

+    logout();

+  }

+  lcp_phase[unit] = PHASE_DEAD;

+  AUTHDEBUG((LOG_NOTICE, "Connection terminated.\n"));

+  pppLinkTerminated(unit);

+}

+

+/*

+ * LCP has gone down; it will either die or try to re-establish.

+ */

+void

+link_down(int unit)

+{

+  int i;

+  struct protent *protp;

+  

+  AUTHDEBUG((LOG_INFO, "link_down: %d\n", unit));

+  if (did_authup) {

+    /* XXX Do link down processing. */

+    did_authup = 0;

+  }

+  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {

+    if (!protp->enabled_flag) {

+      continue;

+    }

+    if (protp->protocol != PPP_LCP && protp->lowerdown != NULL) {

+      (*protp->lowerdown)(unit);

+    }

+    if (protp->protocol < 0xC000 && protp->close != NULL) {

+      (*protp->close)(unit, "LCP down");

+    }

+  }

+  num_np_open = 0;

+  num_np_up = 0;

+  if (lcp_phase[unit] != PHASE_DEAD) {

+    lcp_phase[unit] = PHASE_TERMINATE;

+  }

+  pppLinkDown(unit);

+}

+

+/*

+ * The link is established.

+ * Proceed to the Dead, Authenticate or Network phase as appropriate.

+ */

+void

+link_established(int unit)

+{

+  int auth;

+  int i;

+  struct protent *protp;

+  lcp_options *wo = &lcp_wantoptions[unit];

+  lcp_options *go = &lcp_gotoptions[unit];

+#if PAP_SUPPORT || CHAP_SUPPORT

+  lcp_options *ho = &lcp_hisoptions[unit];

+#endif /* PAP_SUPPORT || CHAP_SUPPORT */

+

+  AUTHDEBUG((LOG_INFO, "link_established: %d\n", unit));

+  /*

+   * Tell higher-level protocols that LCP is up.

+   */

+  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {

+    if (protp->protocol != PPP_LCP && protp->enabled_flag && protp->lowerup != NULL) {

+      (*protp->lowerup)(unit);

+    }

+  }

+  if (ppp_settings.auth_required && !(go->neg_chap || go->neg_upap)) {

+    /*

+     * We wanted the peer to authenticate itself, and it refused:

+     * treat it as though it authenticated with PAP using a username

+     * of "" and a password of "".  If that's not OK, boot it out.

+     */

+    if (!wo->neg_upap || !null_login(unit)) {

+      AUTHDEBUG((LOG_WARNING, "peer refused to authenticate\n"));

+      lcp_close(unit, "peer refused to authenticate");

+      return;

+    }

+  }

+    

+  lcp_phase[unit] = PHASE_AUTHENTICATE;

+  auth = 0;

+#if CHAP_SUPPORT

+  if (go->neg_chap) {

+    ChapAuthPeer(unit, ppp_settings.our_name, go->chap_mdtype);

+    auth |= CHAP_PEER;

+  } 

+#endif /* CHAP_SUPPORT */

+#if PAP_SUPPORT && CHAP_SUPPORT

+  else

+#endif /* PAP_SUPPORT && CHAP_SUPPORT */

+#if PAP_SUPPORT

+  if (go->neg_upap) {

+    upap_authpeer(unit);

+    auth |= PAP_PEER;

+  }

+#endif /* PAP_SUPPORT */

+#if CHAP_SUPPORT

+  if (ho->neg_chap) {

+    ChapAuthWithPeer(unit, ppp_settings.user, ho->chap_mdtype);

+    auth |= CHAP_WITHPEER;

+  }

+#endif /* CHAP_SUPPORT */

+#if PAP_SUPPORT && CHAP_SUPPORT

+  else

+#endif /* PAP_SUPPORT && CHAP_SUPPORT */

+#if PAP_SUPPORT

+  if (ho->neg_upap) {

+    if (ppp_settings.passwd[0] == 0) {

+      passwd_from_file = 1;

+      if (!get_pap_passwd(unit, ppp_settings.user, ppp_settings.passwd)) {

+        AUTHDEBUG((LOG_ERR, "No secret found for PAP login\n"));

+      }

+    }

+    upap_authwithpeer(unit, ppp_settings.user, ppp_settings.passwd);

+    auth |= PAP_WITHPEER;

+  }

+#endif /* PAP_SUPPORT */

+  auth_pending[unit] = auth;

+

+  if (!auth) {

+    network_phase(unit);

+  }

+}

+

+/*

+ * The peer has failed to authenticate himself using `protocol'.

+ */

+void

+auth_peer_fail(int unit, u16_t protocol)

+{

+  LWIP_UNUSED_ARG(protocol);

+

+  AUTHDEBUG((LOG_INFO, "auth_peer_fail: %d proto=%X\n", unit, protocol));

+  /*

+   * Authentication failure: take the link down

+   */

+  lcp_close(unit, "Authentication failed");

+}

+

+

+#if PAP_SUPPORT || CHAP_SUPPORT

+/*

+ * The peer has been successfully authenticated using `protocol'.

+ */

+void

+auth_peer_success(int unit, u16_t protocol, char *name, int namelen)

+{

+  int pbit;

+  

+  AUTHDEBUG((LOG_INFO, "auth_peer_success: %d proto=%X\n", unit, protocol));

+  switch (protocol) {

+    case PPP_CHAP:

+      pbit = CHAP_PEER;

+      break;

+    case PPP_PAP:

+      pbit = PAP_PEER;

+      break;

+    default:

+      AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n", protocol));

+      return;

+  }

+  

+  /*

+   * Save the authenticated name of the peer for later.

+   */

+  if (namelen > sizeof(peer_authname) - 1) {

+    namelen = sizeof(peer_authname) - 1;

+  }

+  BCOPY(name, peer_authname, namelen);

+  peer_authname[namelen] = 0;

+  

+  /*

+   * If there is no more authentication still to be done,

+   * proceed to the network (or callback) phase.

+   */

+  if ((auth_pending[unit] &= ~pbit) == 0) {

+    network_phase(unit);

+  }

+}

+

+/*

+ * We have failed to authenticate ourselves to the peer using `protocol'.

+ */

+void

+auth_withpeer_fail(int unit, u16_t protocol)

+{

+  int errCode = PPPERR_AUTHFAIL;

+  

+  LWIP_UNUSED_ARG(protocol);

+

+  AUTHDEBUG((LOG_INFO, "auth_withpeer_fail: %d proto=%X\n", unit, protocol));

+  if (passwd_from_file) {

+    BZERO(ppp_settings.passwd, MAXSECRETLEN);

+  }

+  /* 

+   * XXX Warning: the unit number indicates the interface which is

+   * not necessarily the PPP connection.  It works here as long

+   * as we are only supporting PPP interfaces.

+   */

+  pppIOCtl(unit, PPPCTLS_ERRCODE, &errCode);

+

+  /*

+   * We've failed to authenticate ourselves to our peer.

+   * He'll probably take the link down, and there's not much

+   * we can do except wait for that.

+   */

+}

+

+/*

+ * We have successfully authenticated ourselves with the peer using `protocol'.

+ */

+void

+auth_withpeer_success(int unit, u16_t protocol)

+{

+  int pbit;

+  

+  AUTHDEBUG((LOG_INFO, "auth_withpeer_success: %d proto=%X\n", unit, protocol));

+  switch (protocol) {

+    case PPP_CHAP:

+      pbit = CHAP_WITHPEER;

+      break;

+    case PPP_PAP:

+      if (passwd_from_file) {

+        BZERO(ppp_settings.passwd, MAXSECRETLEN);

+      }

+      pbit = PAP_WITHPEER;

+      break;

+    default:

+      AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n", protocol));

+      pbit = 0;

+  }

+  

+  /*

+   * If there is no more authentication still being done,

+   * proceed to the network (or callback) phase.

+   */

+  if ((auth_pending[unit] &= ~pbit) == 0) {

+    network_phase(unit);

+  }

+}

+#endif /* PAP_SUPPORT || CHAP_SUPPORT */

+

+

+/*

+ * np_up - a network protocol has come up.

+ */

+void

+np_up(int unit, u16_t proto)

+{

+  LWIP_UNUSED_ARG(unit);

+  LWIP_UNUSED_ARG(proto);

+

+  AUTHDEBUG((LOG_INFO, "np_up: %d proto=%X\n", unit, proto));

+  if (num_np_up == 0) {

+    AUTHDEBUG((LOG_INFO, "np_up: maxconnect=%d idle_time_limit=%d\n",ppp_settings.maxconnect,ppp_settings.idle_time_limit));

+    /*

+     * At this point we consider that the link has come up successfully.

+     */

+    if (ppp_settings.idle_time_limit > 0) {

+      TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit);

+    }

+    

+    /*

+     * Set a timeout to close the connection once the maximum

+     * connect time has expired.

+     */

+    if (ppp_settings.maxconnect > 0) {

+      TIMEOUT(connect_time_expired, 0, ppp_settings.maxconnect);

+    }

+  }

+  ++num_np_up;

+}

+

+/*

+ * np_down - a network protocol has gone down.

+ */

+void

+np_down(int unit, u16_t proto)

+{

+  LWIP_UNUSED_ARG(unit);

+  LWIP_UNUSED_ARG(proto);

+

+  AUTHDEBUG((LOG_INFO, "np_down: %d proto=%X\n", unit, proto));

+  if (--num_np_up == 0 && ppp_settings.idle_time_limit > 0) {

+    UNTIMEOUT(check_idle, NULL);

+  }

+}

+

+/*

+ * np_finished - a network protocol has finished using the link.

+ */

+void

+np_finished(int unit, u16_t proto)

+{

+  LWIP_UNUSED_ARG(unit);

+  LWIP_UNUSED_ARG(proto);

+

+  AUTHDEBUG((LOG_INFO, "np_finished: %d proto=%X\n", unit, proto));

+  if (--num_np_open <= 0) {

+    /* no further use for the link: shut up shop. */

+    lcp_close(0, "No network protocols running");

+  }

+}

+

+/*

+ * auth_reset - called when LCP is starting negotiations to recheck

+ * authentication options, i.e. whether we have appropriate secrets

+ * to use for authenticating ourselves and/or the peer.

+ */

+void

+auth_reset(int unit)

+{

+  lcp_options *go = &lcp_gotoptions[unit];

+  lcp_options *ao = &lcp_allowoptions[0];

+  ipcp_options *ipwo = &ipcp_wantoptions[0];

+  u32_t remote;

+

+  AUTHDEBUG((LOG_INFO, "auth_reset: %d\n", unit));

+  ao->neg_upap = !ppp_settings.refuse_pap && (ppp_settings.passwd[0] != 0 || get_pap_passwd(unit, NULL, NULL));

+  ao->neg_chap = !ppp_settings.refuse_chap && ppp_settings.passwd[0] != 0 /*have_chap_secret(ppp_settings.user, ppp_settings.remote_name, (u32_t)0)*/;

+

+  if (go->neg_upap && !have_pap_secret()) {

+    go->neg_upap = 0;

+  }

+  if (go->neg_chap) {

+    remote = ipwo->accept_remote? 0: ipwo->hisaddr;

+    if (!have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote)) {

+      go->neg_chap = 0;

+    }

+  }

+}

+

+#if PAP_SUPPORT

+/*

+ * check_passwd - Check the user name and passwd against the PAP secrets

+ * file.  If requested, also check against the system password database,

+ * and login the user if OK.

+ *

+ * returns:

+ *  UPAP_AUTHNAK: Authentication failed.

+ *  UPAP_AUTHACK: Authentication succeeded.

+ * In either case, msg points to an appropriate message.

+ */

+int

+check_passwd( int unit, char *auser, int userlen, char *apasswd, int passwdlen, char **msg, int *msglen)

+{

+#if 1

+  LWIP_UNUSED_ARG(unit);

+  LWIP_UNUSED_ARG(auser);

+  LWIP_UNUSED_ARG(userlen);

+  LWIP_UNUSED_ARG(apasswd);

+  LWIP_UNUSED_ARG(passwdlen);

+  LWIP_UNUSED_ARG(msglen);

+  *msg = (char *) 0;

+  return UPAP_AUTHACK;     /* XXX Assume all entries OK. */

+#else

+  int ret = 0;

+  struct wordlist *addrs = NULL;

+  char passwd[256], user[256];

+  char secret[MAXWORDLEN];

+  static u_short attempts = 0;

+  

+  /*

+   * Make copies of apasswd and auser, then null-terminate them.

+   */

+  BCOPY(apasswd, passwd, passwdlen);

+  passwd[passwdlen] = '\0';

+  BCOPY(auser, user, userlen);

+  user[userlen] = '\0';

+  *msg = (char *) 0;

+

+  /* XXX Validate user name and password. */

+  ret = UPAP_AUTHACK;     /* XXX Assume all entries OK. */

+      

+  if (ret == UPAP_AUTHNAK) {

+    if (*msg == (char *) 0) {

+      *msg = "Login incorrect";

+    }

+    *msglen = strlen(*msg);

+    /*

+     * Frustrate passwd stealer programs.

+     * Allow 10 tries, but start backing off after 3 (stolen from login).

+     * On 10'th, drop the connection.

+     */

+    if (attempts++ >= 10) {

+      AUTHDEBUG((LOG_WARNING, "%d LOGIN FAILURES BY %s\n", attempts, user));

+      /*ppp_panic("Excess Bad Logins");*/

+    }

+    if (attempts > 3) {

+      sys_msleep((attempts - 3) * 5);

+    }

+    if (addrs != NULL) {

+      free_wordlist(addrs);

+    }

+  } else {

+    attempts = 0; /* Reset count */

+    if (*msg == (char *) 0) {

+      *msg = "Login ok";

+    }

+    *msglen = strlen(*msg);

+    set_allowed_addrs(unit, addrs);

+  }

+

+  BZERO(passwd, sizeof(passwd));

+  BZERO(secret, sizeof(secret));

+

+  return ret;

+#endif

+}

+#endif /* PAP_SUPPORT */

+

+

+/*

+ * auth_ip_addr - check whether the peer is authorized to use

+ * a given IP address.  Returns 1 if authorized, 0 otherwise.

+ */

+int

+auth_ip_addr(int unit, u32_t addr)

+{

+  return ip_addr_check(addr, addresses[unit]);

+}

+

+/*

+ * bad_ip_adrs - return 1 if the IP address is one we don't want

+ * to use, such as an address in the loopback net or a multicast address.

+ * addr is in network byte order.

+ */

+int

+bad_ip_adrs(u32_t addr)

+{

+  addr = ntohl(addr);

+  return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET

+      || IN_MULTICAST(addr) || IN_BADCLASS(addr);

+}

+

+

+#if CHAP_SUPPORT

+/*

+ * get_secret - open the CHAP secret file and return the secret

+ * for authenticating the given client on the given server.

+ * (We could be either client or server).

+ */

+int get_secret( int unit, char *client, char *server, char *secret, int *secret_len, int save_addrs)

+{

+#if 1

+  int len;

+  struct wordlist *addrs;

+

+  LWIP_UNUSED_ARG(unit);

+  LWIP_UNUSED_ARG(server);

+  LWIP_UNUSED_ARG(save_addrs);

+

+  addrs = NULL;

+

+  if(!client || !client[0] || strcmp(client, ppp_settings.user)) {

+    return 0;

+  }

+

+  len = strlen(ppp_settings.passwd);

+  if (len > MAXSECRETLEN) {

+    AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server));

+    len = MAXSECRETLEN;

+  }

+

+  BCOPY(ppp_settings.passwd, secret, len);

+  *secret_len = len;

+

+  return 1;

+#else

+  int ret = 0, len;

+  struct wordlist *addrs;

+  char secbuf[MAXWORDLEN];

+  

+  addrs = NULL;

+  secbuf[0] = 0;

+

+  /* XXX Find secret. */

+  if (ret < 0) {

+    return 0;

+  }

+

+  if (save_addrs) {

+    set_allowed_addrs(unit, addrs);

+  }

+

+  len = strlen(secbuf);

+  if (len > MAXSECRETLEN) {

+    AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server));

+    len = MAXSECRETLEN;

+  }

+

+  BCOPY(secbuf, secret, len);

+  BZERO(secbuf, sizeof(secbuf));

+  *secret_len = len;

+

+  return 1;

+#endif

+}

+#endif /* CHAP_SUPPORT */

+

+

+#if 0 /* UNUSED */

+/*

+ * auth_check_options - called to check authentication options.

+ */

+void

+auth_check_options(void)

+{

+  lcp_options *wo = &lcp_wantoptions[0];

+  int can_auth;

+  ipcp_options *ipwo = &ipcp_wantoptions[0];

+  u32_t remote;

+

+  /* Default our_name to hostname, and user to our_name */

+  if (ppp_settings.our_name[0] == 0 || ppp_settings.usehostname) {

+      strcpy(ppp_settings.our_name, ppp_settings.hostname);

+  }

+

+  if (ppp_settings.user[0] == 0) {

+    strcpy(ppp_settings.user, ppp_settings.our_name);

+  }

+

+  /* If authentication is required, ask peer for CHAP or PAP. */

+  if (ppp_settings.auth_required && !wo->neg_chap && !wo->neg_upap) {

+    wo->neg_chap = 1;

+    wo->neg_upap = 1;

+  }

+  

+  /*

+   * Check whether we have appropriate secrets to use

+   * to authenticate the peer.

+   */

+  can_auth = wo->neg_upap && have_pap_secret();

+  if (!can_auth && wo->neg_chap) {

+    remote = ipwo->accept_remote? 0: ipwo->hisaddr;

+    can_auth = have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote);

+  }

+

+  if (ppp_settings.auth_required && !can_auth) {

+    ppp_panic("No auth secret");

+  }

+}

+#endif

+

+

+/**********************************/

+/*** LOCAL FUNCTION DEFINITIONS ***/

+/**********************************/

+/*

+ * Proceed to the network phase.

+ */

+static void

+network_phase(int unit)

+{

+  int i;

+  struct protent *protp;

+  lcp_options *go = &lcp_gotoptions[unit];

+  

+  /*

+   * If the peer had to authenticate, run the auth-up script now.

+   */

+  if ((go->neg_chap || go->neg_upap) && !did_authup) {

+    /* XXX Do setup for peer authentication. */

+    did_authup = 1;

+  }

+

+#if CBCP_SUPPORT

+  /*

+   * If we negotiated callback, do it now.

+   */

+  if (go->neg_cbcp) {

+    lcp_phase[unit] = PHASE_CALLBACK;

+    (*cbcp_protent.open)(unit);

+    return;

+  }

+#endif /* CBCP_SUPPORT */

+

+  lcp_phase[unit] = PHASE_NETWORK;

+  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {

+    if (protp->protocol < 0xC000 && protp->enabled_flag && protp->open != NULL) {

+      (*protp->open)(unit);

+      if (protp->protocol != PPP_CCP) {

+        ++num_np_open;

+      }

+    }

+  }

+

+  if (num_np_open == 0) {

+    /* nothing to do */

+    lcp_close(0, "No network protocols running");

+  }

+}

+

+/*

+ * check_idle - check whether the link has been idle for long

+ * enough that we can shut it down.

+ */

+static void

+check_idle(void *arg)

+{

+  struct ppp_idle idle;

+  u_short itime;

+  

+  LWIP_UNUSED_ARG(arg);

+  if (!get_idle_time(0, &idle)) {

+    return;

+  }

+  itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle);

+  if (itime >= ppp_settings.idle_time_limit) {

+    /* link is idle: shut it down. */

+    AUTHDEBUG((LOG_INFO, "Terminating connection due to lack of activity.\n"));

+    lcp_close(0, "Link inactive");

+  } else {

+    TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit - itime);

+  }

+}

+

+/*

+ * connect_time_expired - log a message and close the connection.

+ */

+static void

+connect_time_expired(void *arg)

+{

+  LWIP_UNUSED_ARG(arg);

+

+  AUTHDEBUG((LOG_INFO, "Connect time expired\n"));

+  lcp_close(0, "Connect time expired");   /* Close connection */

+}

+

+#if 0

+/*

+ * login - Check the user name and password against the system

+ * password database, and login the user if OK.

+ *

+ * returns:

+ *  UPAP_AUTHNAK: Login failed.

+ *  UPAP_AUTHACK: Login succeeded.

+ * In either case, msg points to an appropriate message.

+ */

+static int

+login(char *user, char *passwd, char **msg, int *msglen)

+{

+  /* XXX Fail until we decide that we want to support logins. */

+  return (UPAP_AUTHNAK);

+}

+#endif

+

+/*

+ * logout - Logout the user.

+ */

+static void

+logout(void)

+{

+  logged_in = 0;

+}

+

+/*

+ * null_login - Check if a username of "" and a password of "" are

+ * acceptable, and iff so, set the list of acceptable IP addresses

+ * and return 1.

+ */

+static int

+null_login(int unit)

+{

+  LWIP_UNUSED_ARG(unit);

+  /* XXX Fail until we decide that we want to support logins. */

+  return 0;

+}

+

+/*

+ * get_pap_passwd - get a password for authenticating ourselves with

+ * our peer using PAP.  Returns 1 on success, 0 if no suitable password

+ * could be found.

+ */

+static int

+get_pap_passwd(int unit, char *user, char *passwd)

+{

+  LWIP_UNUSED_ARG(unit);

+/* normally we would reject PAP if no password is provided,

+   but this causes problems with some providers (like CHT in Taiwan)

+   who incorrectly request PAP and expect a bogus/empty password, so

+   always provide a default user/passwd of "none"/"none"

+*/

+  if(user) {

+    strcpy(user, "none");

+  }

+  if(passwd) {

+    strcpy(passwd, "none");

+  }

+  return 1;

+}

+

+/*

+ * have_pap_secret - check whether we have a PAP file with any

+ * secrets that we could possibly use for authenticating the peer.

+ */

+static int

+have_pap_secret(void)

+{

+  /* XXX Fail until we set up our passwords. */

+  return 0;

+}

+

+/*

+ * have_chap_secret - check whether we have a CHAP file with a

+ * secret that we could possibly use for authenticating `client'

+ * on `server'.  Either can be the null string, meaning we don't

+ * know the identity yet.

+ */

+static int

+have_chap_secret(char *client, char *server, u32_t remote)

+{

+  LWIP_UNUSED_ARG(client);

+  LWIP_UNUSED_ARG(server);

+  LWIP_UNUSED_ARG(remote);

+  /* XXX Fail until we set up our passwords. */

+  return 0;

+}

+

+#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */

+/*

+ * set_allowed_addrs() - set the list of allowed addresses.

+ */

+static void

+set_allowed_addrs(int unit, struct wordlist *addrs)

+{

+  if (addresses[unit] != NULL) {

+    free_wordlist(addresses[unit]);

+  }

+  addresses[unit] = addrs;

+

+#if 0

+  /*

+   * If there's only one authorized address we might as well

+   * ask our peer for that one right away

+   */

+  if (addrs != NULL && addrs->next == NULL) {

+    char *p = addrs->word;

+    struct ipcp_options *wo = &ipcp_wantoptions[unit];

+    u32_t a;

+    struct hostent *hp;

+    

+    if (wo->hisaddr == 0 && *p != '!' && *p != '-' && strchr(p, '/') == NULL) {

+      hp = gethostbyname(p);

+      if (hp != NULL && hp->h_addrtype == AF_INET) {

+        a = *(u32_t *)hp->h_addr;

+      } else {

+        a = inet_addr(p);

+      }

+      if (a != (u32_t) -1) {

+        wo->hisaddr = a;

+      }

+    }

+  }

+#endif

+}

+#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */

+

+static int

+ip_addr_check(u32_t addr, struct wordlist *addrs)

+{

+  /* don't allow loopback or multicast address */

+  if (bad_ip_adrs(addr)) {

+    return 0;

+  }

+

+  if (addrs == NULL) {

+    return !ppp_settings.auth_required; /* no addresses authorized */

+  }

+

+  /* XXX All other addresses allowed. */

+  return 1;

+}

+

+#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */

+/*

+ * free_wordlist - release memory allocated for a wordlist.

+ */

+static void

+free_wordlist(struct wordlist *wp)

+{

+  struct wordlist *next;

+  

+  while (wp != NULL) {

+    next = wp->next;

+    free(wp);

+    wp = next;

+  }

+}

+#endif  /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */

+

+#endif /* PPP_SUPPORT */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/auth.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/auth.h
new file mode 100644
index 0000000..6e9e000
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/auth.h
@@ -0,0 +1,111 @@
+/*****************************************************************************

+* auth.h -  PPP Authentication and phase control header file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1998 Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.

+*   Original derived from BSD pppd.h.

+*****************************************************************************/

+/*

+ * pppd.h - PPP daemon global declarations.

+ *

+ * Copyright (c) 1989 Carnegie Mellon University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Carnegie Mellon University.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ *

+ */

+

+#ifndef AUTH_H

+#define AUTH_H

+

+/***********************

+*** PUBLIC FUNCTIONS ***

+***********************/

+

+/* we are starting to use the link */

+void link_required (int);

+

+/* we are finished with the link */

+void link_terminated (int);

+

+/* the LCP layer has left the Opened state */

+void link_down (int);

+

+/* the link is up; authenticate now */

+void link_established (int);

+

+/* a network protocol has come up */

+void np_up (int, u16_t);

+

+/* a network protocol has gone down */

+void np_down (int, u16_t);

+

+/* a network protocol no longer needs link */

+void np_finished (int, u16_t);

+

+/* peer failed to authenticate itself */

+void auth_peer_fail (int, u16_t);

+

+/* peer successfully authenticated itself */

+void auth_peer_success (int, u16_t, char *, int);

+

+/* we failed to authenticate ourselves */

+void auth_withpeer_fail (int, u16_t);

+

+/* we successfully authenticated ourselves */

+void auth_withpeer_success (int, u16_t);

+

+/* check authentication options supplied */

+void auth_check_options (void);

+

+/* check what secrets we have */

+void auth_reset (int);

+

+/* Check peer-supplied username/password */

+int  check_passwd (int, char *, int, char *, int, char **, int *);

+

+/* get "secret" for chap */

+int  get_secret (int, char *, char *, char *, int *, int);

+

+/* check if IP address is authorized */

+int  auth_ip_addr (int, u32_t);

+

+/* check if IP address is unreasonable */

+int  bad_ip_adrs (u32_t);

+

+#endif /* AUTH_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chap.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chap.c
new file mode 100644
index 0000000..938994a
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chap.c
@@ -0,0 +1,902 @@
+/*** WARNING - THIS HAS NEVER BEEN FINISHED ***/

+/*****************************************************************************

+* chap.c - Network Challenge Handshake Authentication Protocol program file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1997 by Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.

+*   Original based on BSD chap.c.

+*****************************************************************************/

+/*

+ * chap.c - Challenge Handshake Authentication Protocol.

+ *

+ * Copyright (c) 1993 The Australian National University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by the Australian National University.  The name of the University

+ * may not be used to endorse or promote products derived from this

+ * software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ *

+ * Copyright (c) 1991 Gregory M. Christy.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Gregory M. Christy.  The name of the author may not be used to

+ * endorse or promote products derived from this software without

+ * specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ */

+

+#include "lwip/opt.h"

+

+#if PPP_SUPPORT  /* don't build if not configured for use in lwipopts.h */

+

+#if CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#include "ppp.h"

+#include "pppdebug.h"

+

+#include "magic.h"

+#include "randm.h"

+#include "auth.h"

+#include "md5.h"

+#include "chap.h"

+#include "chpms.h"

+

+

+/*************************/

+/*** LOCAL DEFINITIONS ***/

+/*************************/

+

+

+/************************/

+/*** LOCAL DATA TYPES ***/

+/************************/

+

+

+/***********************************/

+/*** LOCAL FUNCTION DECLARATIONS ***/

+/***********************************/

+/*

+ * Protocol entry points.

+ */

+static void ChapInit (int);

+static void ChapLowerUp (int);

+static void ChapLowerDown (int);

+static void ChapInput (int, u_char *, int);

+static void ChapProtocolReject (int);

+#if 0

+static int  ChapPrintPkt (u_char *, int, void (*) (void *, char *, ...), void *);

+#endif

+

+static void ChapChallengeTimeout (void *);

+static void ChapResponseTimeout (void *);

+static void ChapReceiveChallenge (chap_state *, u_char *, int, int);

+static void ChapRechallenge (void *);

+static void ChapReceiveResponse (chap_state *, u_char *, int, int);

+static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);

+static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);

+static void ChapSendStatus (chap_state *, int);

+static void ChapSendChallenge (chap_state *);

+static void ChapSendResponse (chap_state *);

+static void ChapGenChallenge (chap_state *);

+

+

+/******************************/

+/*** PUBLIC DATA STRUCTURES ***/

+/******************************/

+chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */

+

+struct protent chap_protent = {

+  PPP_CHAP,

+  ChapInit,

+  ChapInput,

+  ChapProtocolReject,

+  ChapLowerUp,

+  ChapLowerDown,

+  NULL,

+  NULL,

+#if 0

+  ChapPrintPkt,

+  NULL,

+#endif

+  1,

+  "CHAP",

+#if 0

+  NULL,

+  NULL,

+  NULL

+#endif

+};

+

+

+/***********************************/

+/*** PUBLIC FUNCTION DEFINITIONS ***/

+/***********************************/

+/*

+ * ChapAuthWithPeer - Authenticate us with our peer (start client).

+ *

+ */

+void

+ChapAuthWithPeer(int unit, char *our_name, int digest)

+{

+  chap_state *cstate = &chap[unit];

+

+  cstate->resp_name = our_name;

+  cstate->resp_type = digest;

+

+  if (cstate->clientstate == CHAPCS_INITIAL ||

+      cstate->clientstate == CHAPCS_PENDING) {

+    /* lower layer isn't up - wait until later */

+    cstate->clientstate = CHAPCS_PENDING;

+    return;

+  }

+

+  /*

+   * We get here as a result of LCP coming up.

+   * So even if CHAP was open before, we will 

+   * have to re-authenticate ourselves.

+   */

+  cstate->clientstate = CHAPCS_LISTEN;

+}

+

+

+/*

+ * ChapAuthPeer - Authenticate our peer (start server).

+ */

+void

+ChapAuthPeer(int unit, char *our_name, int digest)

+{

+  chap_state *cstate = &chap[unit];

+

+  cstate->chal_name = our_name;

+  cstate->chal_type = digest;

+  

+  if (cstate->serverstate == CHAPSS_INITIAL ||

+      cstate->serverstate == CHAPSS_PENDING) {

+    /* lower layer isn't up - wait until later */

+    cstate->serverstate = CHAPSS_PENDING;

+    return;

+  }

+

+  ChapGenChallenge(cstate);

+  ChapSendChallenge(cstate);    /* crank it up dude! */

+  cstate->serverstate = CHAPSS_INITIAL_CHAL;

+}

+

+

+/**********************************/

+/*** LOCAL FUNCTION DEFINITIONS ***/

+/**********************************/

+/*

+ * ChapInit - Initialize a CHAP unit.

+ */

+static void

+ChapInit(int unit)

+{

+  chap_state *cstate = &chap[unit];

+

+  BZERO(cstate, sizeof(*cstate));

+  cstate->unit = unit;

+  cstate->clientstate = CHAPCS_INITIAL;

+  cstate->serverstate = CHAPSS_INITIAL;

+  cstate->timeouttime = CHAP_DEFTIMEOUT;

+  cstate->max_transmits = CHAP_DEFTRANSMITS;

+  /* random number generator is initialized in magic_init */

+}

+

+

+/*

+ * ChapChallengeTimeout - Timeout expired on sending challenge.

+ */

+static void

+ChapChallengeTimeout(void *arg)

+{

+  chap_state *cstate = (chap_state *) arg;

+

+  /* if we aren't sending challenges, don't worry.  then again we */

+  /* probably shouldn't be here either */

+  if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&

+      cstate->serverstate != CHAPSS_RECHALLENGE) {

+    return;

+  }

+

+  if (cstate->chal_transmits >= cstate->max_transmits) {

+    /* give up on peer */

+    CHAPDEBUG((LOG_ERR, "Peer failed to respond to CHAP challenge\n"));

+    cstate->serverstate = CHAPSS_BADAUTH;

+    auth_peer_fail(cstate->unit, PPP_CHAP);

+    return;

+  }

+

+  ChapSendChallenge(cstate); /* Re-send challenge */

+}

+

+

+/*

+ * ChapResponseTimeout - Timeout expired on sending response.

+ */

+static void

+ChapResponseTimeout(void *arg)

+{

+  chap_state *cstate = (chap_state *) arg;

+

+  /* if we aren't sending a response, don't worry. */

+  if (cstate->clientstate != CHAPCS_RESPONSE) {

+    return;

+  }

+

+  ChapSendResponse(cstate);    /* re-send response */

+}

+

+

+/*

+ * ChapRechallenge - Time to challenge the peer again.

+ */

+static void

+ChapRechallenge(void *arg)

+{

+  chap_state *cstate = (chap_state *) arg;

+  

+  /* if we aren't sending a response, don't worry. */

+  if (cstate->serverstate != CHAPSS_OPEN) {

+    return;

+  }

+

+  ChapGenChallenge(cstate);

+  ChapSendChallenge(cstate);

+  cstate->serverstate = CHAPSS_RECHALLENGE;

+}

+

+

+/*

+ * ChapLowerUp - The lower layer is up.

+ *

+ * Start up if we have pending requests.

+ */

+static void

+ChapLowerUp(int unit)

+{

+  chap_state *cstate = &chap[unit];

+

+  if (cstate->clientstate == CHAPCS_INITIAL) {

+    cstate->clientstate = CHAPCS_CLOSED;

+  } else if (cstate->clientstate == CHAPCS_PENDING) {

+    cstate->clientstate = CHAPCS_LISTEN;

+  }

+

+  if (cstate->serverstate == CHAPSS_INITIAL) {

+    cstate->serverstate = CHAPSS_CLOSED;

+  } else if (cstate->serverstate == CHAPSS_PENDING) {

+    ChapGenChallenge(cstate);

+    ChapSendChallenge(cstate);

+    cstate->serverstate = CHAPSS_INITIAL_CHAL;

+  }

+}

+

+

+/*

+ * ChapLowerDown - The lower layer is down.

+ *

+ * Cancel all timeouts.

+ */

+static void

+ChapLowerDown(int unit)

+{

+  chap_state *cstate = &chap[unit];

+

+  /* Timeout(s) pending?  Cancel if so. */

+  if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||

+      cstate->serverstate == CHAPSS_RECHALLENGE) {

+    UNTIMEOUT(ChapChallengeTimeout, cstate);

+  } else if (cstate->serverstate == CHAPSS_OPEN

+      && cstate->chal_interval != 0) {

+    UNTIMEOUT(ChapRechallenge, cstate);

+  }

+  if (cstate->clientstate == CHAPCS_RESPONSE) {

+    UNTIMEOUT(ChapResponseTimeout, cstate);

+  }

+  cstate->clientstate = CHAPCS_INITIAL;

+  cstate->serverstate = CHAPSS_INITIAL;

+}

+

+

+/*

+ * ChapProtocolReject - Peer doesn't grok CHAP.

+ */

+static void

+ChapProtocolReject(int unit)

+{

+  chap_state *cstate = &chap[unit];

+  

+  if (cstate->serverstate != CHAPSS_INITIAL &&

+      cstate->serverstate != CHAPSS_CLOSED) {

+    auth_peer_fail(unit, PPP_CHAP);

+  }

+  if (cstate->clientstate != CHAPCS_INITIAL &&

+      cstate->clientstate != CHAPCS_CLOSED) {

+    auth_withpeer_fail(unit, PPP_CHAP);

+  }

+  ChapLowerDown(unit); /* shutdown chap */

+}

+

+

+/*

+ * ChapInput - Input CHAP packet.

+ */

+static void

+ChapInput(int unit, u_char *inpacket, int packet_len)

+{

+  chap_state *cstate = &chap[unit];

+  u_char *inp;

+  u_char code, id;

+  int len;

+  

+  /*

+   * Parse header (code, id and length).

+   * If packet too short, drop it.

+   */

+  inp = inpacket;

+  if (packet_len < CHAP_HEADERLEN) {

+    CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.\n"));

+    return;

+  }

+  GETCHAR(code, inp);

+  GETCHAR(id, inp);

+  GETSHORT(len, inp);

+  if (len < CHAP_HEADERLEN) {

+    CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.\n"));

+    return;

+  }

+  if (len > packet_len) {

+    CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.\n"));

+    return;

+  }

+  len -= CHAP_HEADERLEN;

+  

+  /*

+   * Action depends on code (as in fact it usually does :-).

+   */

+  switch (code) {

+    case CHAP_CHALLENGE:

+      ChapReceiveChallenge(cstate, inp, id, len);

+      break;

+    

+    case CHAP_RESPONSE:

+      ChapReceiveResponse(cstate, inp, id, len);

+      break;

+    

+    case CHAP_FAILURE:

+      ChapReceiveFailure(cstate, inp, id, len);

+      break;

+    

+    case CHAP_SUCCESS:

+      ChapReceiveSuccess(cstate, inp, id, len);

+      break;

+    

+    default:        /* Need code reject? */

+      CHAPDEBUG((LOG_WARNING, "Unknown CHAP code (%d) received.\n", code));

+      break;

+  }

+}

+

+

+/*

+ * ChapReceiveChallenge - Receive Challenge and send Response.

+ */

+static void

+ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len)

+{

+  int rchallenge_len;

+  u_char *rchallenge;

+  int secret_len;

+  char secret[MAXSECRETLEN];

+  char rhostname[256];

+  MD5_CTX mdContext;

+  u_char hash[MD5_SIGNATURE_SIZE];

+  

+  CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.\n", id));

+  if (cstate->clientstate == CHAPCS_CLOSED ||

+    cstate->clientstate == CHAPCS_PENDING) {

+    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d\n",

+         cstate->clientstate));

+    return;

+  }

+

+  if (len < 2) {

+    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));

+    return;

+  }

+

+  GETCHAR(rchallenge_len, inp);

+  len -= sizeof (u_char) + rchallenge_len;  /* now name field length */

+  if (len < 0) {

+    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));

+    return;

+  }

+  rchallenge = inp;

+  INCPTR(rchallenge_len, inp);

+

+  if (len >= sizeof(rhostname)) {

+    len = sizeof(rhostname) - 1;

+  }

+  BCOPY(inp, rhostname, len);

+  rhostname[len] = '\000';

+

+  CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'\n", rhostname));

+

+  /* Microsoft doesn't send their name back in the PPP packet */

+  if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {

+    strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));

+    rhostname[sizeof(rhostname) - 1] = 0;

+    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name\n", rhostname));

+  }

+

+  /* get secret for authenticating ourselves with the specified host */

+  if (!get_secret(cstate->unit, cstate->resp_name, rhostname, secret, &secret_len, 0)) {

+    secret_len = 0;    /* assume null secret if can't find one */

+    CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating us to %s\n", rhostname));

+  }

+

+  /* cancel response send timeout if necessary */

+  if (cstate->clientstate == CHAPCS_RESPONSE) {

+    UNTIMEOUT(ChapResponseTimeout, cstate);

+  }

+

+  cstate->resp_id = id;

+  cstate->resp_transmits = 0;

+

+  /*  generate MD based on negotiated type */

+  switch (cstate->resp_type) { 

+

+  case CHAP_DIGEST_MD5:

+    MD5Init(&mdContext);

+    MD5Update(&mdContext, &cstate->resp_id, 1);

+    MD5Update(&mdContext, (u_char*)secret, secret_len);

+    MD5Update(&mdContext, rchallenge, rchallenge_len);

+    MD5Final(hash, &mdContext);

+    BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);

+    cstate->resp_length = MD5_SIGNATURE_SIZE;

+    break;

+  

+#ifdef CHAPMS

+  case CHAP_MICROSOFT:

+    ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);

+    break;

+#endif

+

+  default:

+    CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->resp_type));

+    return;

+  }

+

+  BZERO(secret, sizeof(secret));

+  ChapSendResponse(cstate);

+}

+

+

+/*

+ * ChapReceiveResponse - Receive and process response.

+ */

+static void

+ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)

+{

+  u_char *remmd, remmd_len;

+  int secret_len, old_state;

+  int code;

+  char rhostname[256];

+  MD5_CTX mdContext;

+  char secret[MAXSECRETLEN];

+  u_char hash[MD5_SIGNATURE_SIZE];

+  

+  CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.\n", id));

+  

+  if (cstate->serverstate == CHAPSS_CLOSED ||

+      cstate->serverstate == CHAPSS_PENDING) {

+    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d\n",

+    cstate->serverstate));

+    return;

+  }

+

+  if (id != cstate->chal_id) {

+    return;      /* doesn't match ID of last challenge */

+  }

+

+  /*

+  * If we have received a duplicate or bogus Response,

+  * we have to send the same answer (Success/Failure)

+  * as we did for the first Response we saw.

+  */

+  if (cstate->serverstate == CHAPSS_OPEN) {

+    ChapSendStatus(cstate, CHAP_SUCCESS);

+    return;

+  }

+  if (cstate->serverstate == CHAPSS_BADAUTH) {

+    ChapSendStatus(cstate, CHAP_FAILURE);

+    return;

+  }

+  

+  if (len < 2) {

+    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));

+    return;

+  }

+  GETCHAR(remmd_len, inp); /* get length of MD */

+  remmd = inp;             /* get pointer to MD */

+  INCPTR(remmd_len, inp);

+  

+  len -= sizeof (u_char) + remmd_len;

+  if (len < 0) {

+    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));

+    return;

+  }

+

+  UNTIMEOUT(ChapChallengeTimeout, cstate);

+  

+  if (len >= sizeof(rhostname)) {

+    len = sizeof(rhostname) - 1;

+  }

+  BCOPY(inp, rhostname, len);

+  rhostname[len] = '\000';

+

+  CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s\n", rhostname));

+

+  /*

+  * Get secret for authenticating them with us,

+  * do the hash ourselves, and compare the result.

+  */

+  code = CHAP_FAILURE;

+  if (!get_secret(cstate->unit, rhostname, cstate->chal_name, secret, &secret_len, 1)) {

+    /* CHAPDEBUG((LOG_WARNING, TL_CHAP, "No CHAP secret found for authenticating %s\n", rhostname)); */

+    CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating %s\n",

+    rhostname));

+  } else {

+    /*  generate MD based on negotiated type */

+    switch (cstate->chal_type) {

+

+      case CHAP_DIGEST_MD5:    /* only MD5 is defined for now */

+        if (remmd_len != MD5_SIGNATURE_SIZE) {

+          break;      /* it's not even the right length */

+        }

+        MD5Init(&mdContext);

+        MD5Update(&mdContext, &cstate->chal_id, 1);

+        MD5Update(&mdContext, (u_char*)secret, secret_len);

+        MD5Update(&mdContext, cstate->challenge, cstate->chal_len);

+        MD5Final(hash, &mdContext); 

+        

+        /* compare local and remote MDs and send the appropriate status */

+        if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0) {

+          code = CHAP_SUCCESS;  /* they are the same! */

+        }

+        break;

+      

+      default:

+        CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->chal_type));

+    }

+  }

+  

+  BZERO(secret, sizeof(secret));

+  ChapSendStatus(cstate, code);

+

+  if (code == CHAP_SUCCESS) {

+    old_state = cstate->serverstate;

+    cstate->serverstate = CHAPSS_OPEN;

+    if (old_state == CHAPSS_INITIAL_CHAL) {

+      auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);

+    }

+    if (cstate->chal_interval != 0) {

+      TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);

+    }

+  } else {

+    CHAPDEBUG((LOG_ERR, "CHAP peer authentication failed\n"));

+    cstate->serverstate = CHAPSS_BADAUTH;

+    auth_peer_fail(cstate->unit, PPP_CHAP);

+  }

+}

+

+/*

+ * ChapReceiveSuccess - Receive Success

+ */

+static void

+ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)

+{

+  LWIP_UNUSED_ARG(id);

+  LWIP_UNUSED_ARG(inp);

+

+  CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.\n", id));

+

+  if (cstate->clientstate == CHAPCS_OPEN) {

+    /* presumably an answer to a duplicate response */

+    return;

+  }

+

+  if (cstate->clientstate != CHAPCS_RESPONSE) {

+    /* don't know what this is */

+    CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n", cstate->clientstate));

+    return;

+  }

+  

+  UNTIMEOUT(ChapResponseTimeout, cstate);

+  

+  /*

+   * Print message.

+   */

+  if (len > 0) {

+    PRINTMSG(inp, len);

+  }

+

+  cstate->clientstate = CHAPCS_OPEN;

+

+  auth_withpeer_success(cstate->unit, PPP_CHAP);

+}

+

+

+/*

+ * ChapReceiveFailure - Receive failure.

+ */

+static void

+ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)

+{

+  LWIP_UNUSED_ARG(id);

+  LWIP_UNUSED_ARG(inp);

+

+  CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.\n", id));

+

+  if (cstate->clientstate != CHAPCS_RESPONSE) {

+    /* don't know what this is */

+    CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n", cstate->clientstate));

+    return;

+  }

+

+  UNTIMEOUT(ChapResponseTimeout, cstate);

+

+  /*

+   * Print message.

+   */

+  if (len > 0) {

+    PRINTMSG(inp, len);

+  }

+

+  CHAPDEBUG((LOG_ERR, "CHAP authentication failed\n"));

+  auth_withpeer_fail(cstate->unit, PPP_CHAP);

+}

+

+

+/*

+ * ChapSendChallenge - Send an Authenticate challenge.

+ */

+static void

+ChapSendChallenge(chap_state *cstate)

+{

+  u_char *outp;

+  int chal_len, name_len;

+  int outlen;

+  

+  chal_len = cstate->chal_len;

+  name_len = strlen(cstate->chal_name);

+  outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;

+  outp = outpacket_buf[cstate->unit];

+  

+  MAKEHEADER(outp, PPP_CHAP);    /* paste in a CHAP header */

+  

+  PUTCHAR(CHAP_CHALLENGE, outp);

+  PUTCHAR(cstate->chal_id, outp);

+  PUTSHORT(outlen, outp);

+  

+  PUTCHAR(chal_len, outp);    /* put length of challenge */

+  BCOPY(cstate->challenge, outp, chal_len);

+  INCPTR(chal_len, outp);

+  

+  BCOPY(cstate->chal_name, outp, name_len);  /* append hostname */

+  

+  pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);

+  

+  CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.\n", cstate->chal_id));

+  

+  TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);

+  ++cstate->chal_transmits;

+}

+

+

+/*

+ * ChapSendStatus - Send a status response (ack or nak).

+ */

+static void

+ChapSendStatus(chap_state *cstate, int code)

+{

+  u_char *outp;

+  int outlen, msglen;

+  char msg[256];

+  

+  if (code == CHAP_SUCCESS) {

+    strcpy(msg, "Welcome!");

+  } else {

+    strcpy(msg, "I don't like you.  Go 'way.");

+  }

+  msglen = strlen(msg);

+  

+  outlen = CHAP_HEADERLEN + msglen;

+  outp = outpacket_buf[cstate->unit];

+  

+  MAKEHEADER(outp, PPP_CHAP);    /* paste in a header */

+  

+  PUTCHAR(code, outp);

+  PUTCHAR(cstate->chal_id, outp);

+  PUTSHORT(outlen, outp);

+  BCOPY(msg, outp, msglen);

+  pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);

+  

+  CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.\n", code, cstate->chal_id));

+}

+

+/*

+ * ChapGenChallenge is used to generate a pseudo-random challenge string of

+ * a pseudo-random length between min_len and max_len.  The challenge

+ * string and its length are stored in *cstate, and various other fields of

+ * *cstate are initialized.

+ */

+

+static void

+ChapGenChallenge(chap_state *cstate)

+{

+  int chal_len;

+  u_char *ptr = cstate->challenge;

+  int i;

+  

+  /* pick a random challenge length between MIN_CHALLENGE_LENGTH and 

+     MAX_CHALLENGE_LENGTH */  

+  chal_len = (unsigned)

+        ((((magic() >> 16) *

+              (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)

+           + MIN_CHALLENGE_LENGTH);

+  cstate->chal_len = chal_len;

+  cstate->chal_id = ++cstate->id;

+  cstate->chal_transmits = 0;

+  

+  /* generate a random string */

+  for (i = 0; i < chal_len; i++ ) {

+    *ptr++ = (char) (magic() & 0xff);

+  }

+}

+

+/*

+ * ChapSendResponse - send a response packet with values as specified

+ * in *cstate.

+ */

+/* ARGSUSED */

+static void

+ChapSendResponse(chap_state *cstate)

+{

+  u_char *outp;

+  int outlen, md_len, name_len;

+  

+  md_len = cstate->resp_length;

+  name_len = strlen(cstate->resp_name);

+  outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;

+  outp = outpacket_buf[cstate->unit];

+  

+  MAKEHEADER(outp, PPP_CHAP);

+  

+  PUTCHAR(CHAP_RESPONSE, outp);  /* we are a response */

+  PUTCHAR(cstate->resp_id, outp);  /* copy id from challenge packet */

+  PUTSHORT(outlen, outp);      /* packet length */

+  

+  PUTCHAR(md_len, outp);      /* length of MD */

+  BCOPY(cstate->response, outp, md_len);    /* copy MD to buffer */

+  INCPTR(md_len, outp);

+  

+  BCOPY(cstate->resp_name, outp, name_len);  /* append our name */

+  

+  /* send the packet */

+  pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);

+  

+  cstate->clientstate = CHAPCS_RESPONSE;

+  TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);

+  ++cstate->resp_transmits;

+}

+

+#if 0

+static char *ChapCodenames[] = {

+  "Challenge", "Response", "Success", "Failure"

+};

+/*

+ * ChapPrintPkt - print the contents of a CHAP packet.

+ */

+static int

+ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)

+{

+  int code, id, len;

+  int clen, nlen;

+  u_char x;

+  

+  if (plen < CHAP_HEADERLEN) {

+    return 0;

+  }

+  GETCHAR(code, p);

+  GETCHAR(id, p);

+  GETSHORT(len, p);

+  if (len < CHAP_HEADERLEN || len > plen) {

+    return 0;

+  }

+  if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) {

+    printer(arg, " %s", ChapCodenames[code-1]);

+  } else {

+    printer(arg, " code=0x%x", code);

+  }

+  printer(arg, " id=0x%x", id);

+  len -= CHAP_HEADERLEN;

+  switch (code) {

+    case CHAP_CHALLENGE:

+    case CHAP_RESPONSE:

+      if (len < 1) {

+        break;

+      }

+      clen = p[0];

+      if (len < clen + 1) {

+        break;

+      }

+      ++p;

+      nlen = len - clen - 1;

+      printer(arg, " <");

+      for (; clen > 0; --clen) {

+        GETCHAR(x, p);

+        printer(arg, "%.2x", x);

+      }

+      printer(arg, ">, name = %.*Z", nlen, p);

+      break;

+    case CHAP_FAILURE:

+    case CHAP_SUCCESS:

+      printer(arg, " %.*Z", len, p);

+      break;

+    default:

+      for (clen = len; clen > 0; --clen) {

+        GETCHAR(x, p);

+        printer(arg, " %.2x", x);

+      }

+  }

+

+  return len + CHAP_HEADERLEN;

+}

+#endif

+

+#endif /* CHAP_SUPPORT */

+

+#endif /* PPP_SUPPORT */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chap.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chap.h
new file mode 100644
index 0000000..b48eecb
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chap.h
@@ -0,0 +1,166 @@
+/*****************************************************************************

+* chap.h - Network Challenge Handshake Authentication Protocol header file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1998 Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-12-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.

+*   Original built from BSD network code.

+******************************************************************************/

+/*

+ * chap.h - Challenge Handshake Authentication Protocol definitions.

+ *

+ * Copyright (c) 1993 The Australian National University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by the Australian National University.  The name of the University

+ * may not be used to endorse or promote products derived from this

+ * software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ *

+ * Copyright (c) 1991 Gregory M. Christy

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by the author.

+ *

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ *

+ * $Id: chap.h,v 1.4 2007/12/19 20:47:22 fbernon Exp $

+ */

+

+#ifndef CHAP_H

+#define CHAP_H

+

+/*************************

+*** PUBLIC DEFINITIONS ***

+*************************/

+

+/* Code + ID + length */

+#define CHAP_HEADERLEN 4

+

+/*

+ * CHAP codes.

+ */

+

+#define CHAP_DIGEST_MD5      5    /* use MD5 algorithm */

+#define MD5_SIGNATURE_SIZE   16   /* 16 bytes in a MD5 message digest */

+#define CHAP_MICROSOFT       0x80 /* use Microsoft-compatible alg. */

+#define MS_CHAP_RESPONSE_LEN 49   /* Response length for MS-CHAP */

+

+#define CHAP_CHALLENGE       1

+#define CHAP_RESPONSE        2

+#define CHAP_SUCCESS         3

+#define CHAP_FAILURE         4

+

+/*

+ *  Challenge lengths (for challenges we send) and other limits.

+ */

+#define MIN_CHALLENGE_LENGTH 32

+#define MAX_CHALLENGE_LENGTH 64

+#define MAX_RESPONSE_LENGTH  64 /* sufficient for MD5 or MS-CHAP */

+

+/*

+ * Client (peer) states.

+ */

+#define CHAPCS_INITIAL       0 /* Lower layer down, not opened */

+#define CHAPCS_CLOSED        1 /* Lower layer up, not opened */

+#define CHAPCS_PENDING       2 /* Auth us to peer when lower up */

+#define CHAPCS_LISTEN        3 /* Listening for a challenge */

+#define CHAPCS_RESPONSE      4 /* Sent response, waiting for status */

+#define CHAPCS_OPEN          5 /* We've received Success */

+

+/*

+ * Server (authenticator) states.

+ */

+#define CHAPSS_INITIAL       0 /* Lower layer down, not opened */

+#define CHAPSS_CLOSED        1 /* Lower layer up, not opened */

+#define CHAPSS_PENDING       2 /* Auth peer when lower up */

+#define CHAPSS_INITIAL_CHAL  3 /* We've sent the first challenge */

+#define CHAPSS_OPEN          4 /* We've sent a Success msg */

+#define CHAPSS_RECHALLENGE   5 /* We've sent another challenge */

+#define CHAPSS_BADAUTH       6 /* We've sent a Failure msg */

+

+/************************

+*** PUBLIC DATA TYPES ***

+************************/

+

+/*

+ * Each interface is described by a chap structure.

+ */

+

+typedef struct chap_state {

+  int unit;                               /* Interface unit number */

+  int clientstate;                        /* Client state */

+  int serverstate;                        /* Server state */

+  u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */

+  u_char chal_len;                        /* challenge length */

+  u_char chal_id;                         /* ID of last challenge */

+  u_char chal_type;                       /* hash algorithm for challenges */

+  u_char id;                              /* Current id */

+  char *chal_name;                        /* Our name to use with challenge */

+  int chal_interval;                      /* Time until we challenge peer again */

+  int timeouttime;                        /* Timeout time in seconds */

+  int max_transmits;                      /* Maximum # of challenge transmissions */

+  int chal_transmits;                     /* Number of transmissions of challenge */

+  int resp_transmits;                     /* Number of transmissions of response */

+  u_char response[MAX_RESPONSE_LENGTH];   /* Response to send */

+  u_char resp_length;                     /* length of response */

+  u_char resp_id;                         /* ID for response messages */

+  u_char resp_type;                       /* hash algorithm for responses */

+  char *resp_name;                        /* Our name to send with response */

+} chap_state;

+

+

+/******************

+*** PUBLIC DATA ***

+******************/

+extern chap_state chap[];

+

+extern struct protent chap_protent;

+

+

+/***********************

+*** PUBLIC FUNCTIONS ***

+***********************/

+

+void ChapAuthWithPeer (int, char *, int);

+void ChapAuthPeer (int, char *, int);

+

+#endif /* CHAP_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chpms.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chpms.c
new file mode 100644
index 0000000..900db42
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chpms.c
@@ -0,0 +1,396 @@
+/*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/

+/*****************************************************************************

+* chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.

+*   Original based on BSD chap_ms.c.

+*****************************************************************************/

+/*

+ * chap_ms.c - Microsoft MS-CHAP compatible implementation.

+ *

+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.

+ * http://www.strataware.com/

+ *

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Eric Rosenquist.  The name of the author may not be used to

+ * endorse or promote products derived from this software without

+ * specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ */

+

+/*

+ * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997

+ *

+ *   Implemented LANManager type password response to MS-CHAP challenges.

+ *   Now pppd provides both NT style and LANMan style blocks, and the

+ *   prefered is set by option "ms-lanman". Default is to use NT.

+ *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.

+ *

+ *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80

+ */

+

+#define USE_CRYPT

+

+#include "lwip/opt.h"

+

+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#if MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#include "ppp.h"

+#include "pppdebug.h"

+

+#include "md4.h"

+#ifndef USE_CRYPT

+#include "des.h"

+#endif

+#include "chap.h"

+#include "chpms.h"

+

+

+/*************************/

+/*** LOCAL DEFINITIONS ***/

+/*************************/

+

+

+/************************/

+/*** LOCAL DATA TYPES ***/

+/************************/

+typedef struct {

+    u_char LANManResp[24];

+    u_char NTResp[24];

+    u_char UseNT; /* If 1, ignore the LANMan response field */

+} MS_ChapResponse;

+/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),

+   in case this struct gets padded. */

+

+

+

+/***********************************/

+/*** LOCAL FUNCTION DECLARATIONS ***/

+/***********************************/

+

+/* XXX Don't know what to do with these. */

+extern void setkey(const char *);

+extern void encrypt(char *, int);

+

+static void DesEncrypt (u_char *, u_char *, u_char *);

+static void MakeKey (u_char *, u_char *);

+

+#ifdef USE_CRYPT

+static void Expand (u_char *, u_char *);

+static void Collapse (u_char *, u_char *);

+#endif

+

+static void ChallengeResponse(

+  u_char *challenge, /* IN   8 octets */

+  u_char *pwHash,    /* IN  16 octets */

+  u_char *response   /* OUT 24 octets */

+);

+static void ChapMS_NT(

+  char *rchallenge,

+  int rchallenge_len,

+  char *secret,

+  int secret_len,

+  MS_ChapResponse *response

+);

+static u_char Get7Bits(

+  u_char *input,

+  int startBit

+);

+

+

+/***********************************/

+/*** PUBLIC FUNCTION DEFINITIONS ***/

+/***********************************/

+void

+ChapMS( chap_state *cstate, char *rchallenge, int rchallenge_len, char *secret, int secret_len)

+{

+  MS_ChapResponse response;

+#ifdef MSLANMAN

+  extern int ms_lanman;

+#endif

+

+#if 0

+  CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'\n", secret_len, secret));

+#endif

+  BZERO(&response, sizeof(response));

+

+  /* Calculate both always */

+  ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);

+

+#ifdef MSLANMAN

+  ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);

+

+  /* prefered method is set by option  */

+  response.UseNT = !ms_lanman;

+#else

+  response.UseNT = 1;

+#endif

+

+  BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);

+  cstate->resp_length = MS_CHAP_RESPONSE_LEN;

+}

+

+

+/**********************************/

+/*** LOCAL FUNCTION DEFINITIONS ***/

+/**********************************/

+static void

+ChallengeResponse( u_char *challenge, /* IN   8 octets */

+                   u_char *pwHash,    /* IN  16 octets */

+                   u_char *response   /* OUT 24 octets */)

+{

+  char    ZPasswordHash[21];

+

+  BZERO(ZPasswordHash, sizeof(ZPasswordHash));

+  BCOPY(pwHash, ZPasswordHash, 16);

+

+#if 0

+  log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);

+#endif

+

+  DesEncrypt(challenge, ZPasswordHash +  0, response + 0);

+  DesEncrypt(challenge, ZPasswordHash +  7, response + 8);

+  DesEncrypt(challenge, ZPasswordHash + 14, response + 16);

+

+#if 0

+  log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);

+#endif

+}

+

+

+#ifdef USE_CRYPT

+static void

+DesEncrypt( u_char *clear, /* IN  8 octets */

+            u_char *key,   /* IN  7 octets */

+            u_char *cipher /* OUT 8 octets */)

+{

+  u_char des_key[8];

+  u_char crypt_key[66];

+  u_char des_input[66];

+

+  MakeKey(key, des_key);

+

+  Expand(des_key, crypt_key);

+  setkey(crypt_key);

+

+#if 0

+  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",

+             clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));

+#endif

+

+  Expand(clear, des_input);

+  encrypt(des_input, 0);

+  Collapse(des_input, cipher);

+

+#if 0

+  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",

+             cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));

+#endif

+}

+

+#else /* USE_CRYPT */

+

+static void

+DesEncrypt( u_char *clear, /* IN  8 octets */

+            u_char *key,   /* IN  7 octets */

+            u_char *cipher /* OUT 8 octets */)

+{

+  des_cblock    des_key;

+  des_key_schedule  key_schedule;

+

+  MakeKey(key, des_key);

+

+  des_set_key(&des_key, key_schedule);

+

+#if 0

+  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",

+             clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));

+#endif

+

+  des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);

+

+#if 0

+  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",

+             cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));

+#endif

+}

+

+#endif /* USE_CRYPT */

+

+

+static u_char

+Get7Bits( u_char *input, int startBit)

+{

+  register unsigned int  word;

+

+  word  = (unsigned)input[startBit / 8] << 8;

+  word |= (unsigned)input[startBit / 8 + 1];

+

+  word >>= 15 - (startBit % 8 + 7);

+

+  return word & 0xFE;

+}

+

+#ifdef USE_CRYPT

+

+/* in == 8-byte string (expanded version of the 56-bit key)

+ * out == 64-byte string where each byte is either 1 or 0

+ * Note that the low-order "bit" is always ignored by by setkey()

+ */

+static void

+Expand(u_char *in, u_char *out)

+{

+  int j, c;

+  int i;

+

+  for(i = 0; i < 64; in++){

+    c = *in;

+    for(j = 7; j >= 0; j--) {

+      *out++ = (c >> j) & 01;

+    }

+    i += 8;

+  }

+}

+

+/* The inverse of Expand

+ */

+static void

+Collapse(u_char *in, u_char *out)

+{

+  int j;

+  int i;

+  unsigned int c;

+

+  for (i = 0; i < 64; i += 8, out++) {

+    c = 0;

+    for (j = 7; j >= 0; j--, in++) {

+      c |= *in << j;

+    }

+    *out = c & 0xff;

+  }

+}

+#endif

+

+static void

+MakeKey( u_char *key,    /* IN  56 bit DES key missing parity bits */

+         u_char *des_key /* OUT 64 bit DES key with parity bits added */)

+{

+  des_key[0] = Get7Bits(key,  0);

+  des_key[1] = Get7Bits(key,  7);

+  des_key[2] = Get7Bits(key, 14);

+  des_key[3] = Get7Bits(key, 21);

+  des_key[4] = Get7Bits(key, 28);

+  des_key[5] = Get7Bits(key, 35);

+  des_key[6] = Get7Bits(key, 42);

+  des_key[7] = Get7Bits(key, 49);

+  

+#ifndef USE_CRYPT

+  des_set_odd_parity((des_cblock *)des_key);

+#endif

+  

+#if 0

+  CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n",

+             key[0], key[1], key[2], key[3], key[4], key[5], key[6]));

+  CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n",

+             des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));

+#endif

+}

+

+static void

+ChapMS_NT( char *rchallenge,

+           int rchallenge_len,

+           char *secret,

+           int secret_len,

+           MS_ChapResponse *response)

+{

+  int      i;

+  MDstruct  md4Context;

+  u_char    unicodePassword[MAX_NT_PASSWORD * 2];

+  static int  low_byte_first = -1;

+

+  /* Initialize the Unicode version of the secret (== password). */

+  /* This implicitly supports 8-bit ISO8859/1 characters. */

+  BZERO(unicodePassword, sizeof(unicodePassword));

+  for (i = 0; i < secret_len; i++) {

+    unicodePassword[i * 2] = (u_char)secret[i];

+  }

+  MDbegin(&md4Context);

+  MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8);  /* Unicode is 2 bytes/char, *8 for bit count */

+

+  if (low_byte_first == -1) {

+    low_byte_first = (htons((unsigned short int)1) != 1);

+  }

+  if (low_byte_first == 0) {

+    MDreverse((u_long *)&md4Context);  /*  sfb 961105 */

+  }

+

+  MDupdate(&md4Context, NULL, 0);  /* Tell MD4 we're done */

+

+  ChallengeResponse(rchallenge, (char *)md4Context.buffer, response->NTResp);

+}

+

+#ifdef MSLANMAN

+static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */

+

+static void

+ChapMS_LANMan( char *rchallenge,

+               int rchallenge_len,

+               char *secret,

+               int secret_len,

+               MS_ChapResponse  *response)

+{

+  int      i;

+  u_char    UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */

+  u_char    PasswordHash[16];

+  

+  /* LANMan password is case insensitive */

+  BZERO(UcasePassword, sizeof(UcasePassword));

+  for (i = 0; i < secret_len; i++) {

+    UcasePassword[i] = (u_char)toupper(secret[i]);

+  }

+  DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );

+  DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );

+  ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);

+}

+#endif

+

+#endif /* MSCHAP_SUPPORT */

+

+#endif /* PPP_SUPPORT */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chpms.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chpms.h
new file mode 100644
index 0000000..f023cce
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chpms.h
@@ -0,0 +1,64 @@
+/*****************************************************************************

+* chpms.h - Network Microsoft Challenge Handshake Protocol header file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1998 Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 98-01-30 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.

+*   Original built from BSD network code.

+******************************************************************************/

+/*

+ * chap.h - Challenge Handshake Authentication Protocol definitions.

+ *

+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.

+ * http://www.strataware.com/

+ *

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Eric Rosenquist.  The name of the author may not be used to

+ * endorse or promote products derived from this software without

+ * specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ *

+ * $Id: chpms.h,v 1.5 2007/12/19 20:47:23 fbernon Exp $

+ */

+

+#ifndef CHPMS_H

+#define CHPMS_H

+

+#define MAX_NT_PASSWORD 256 /* Maximum number of (Unicode) chars in an NT password */

+

+void ChapMS (chap_state *, char *, int, char *, int);

+

+#endif /* CHPMS_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/fsm.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/fsm.c
new file mode 100644
index 0000000..8c2fab4
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/fsm.c
@@ -0,0 +1,906 @@
+/*****************************************************************************

+* fsm.c - Network Control Protocol Finite State Machine program file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1997 by Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.

+*   Original based on BSD fsm.c.

+*****************************************************************************/

+/*

+ * fsm.c - {Link, IP} Control Protocol Finite State Machine.

+ *

+ * Copyright (c) 1989 Carnegie Mellon University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Carnegie Mellon University.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ */

+

+/*

+ * TODO:

+ * Randomize fsm id on link/init.

+ * Deal with variable outgoing MTU.

+ */

+

+#include "lwip/opt.h"

+

+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#include "ppp.h"

+#include "pppdebug.h"

+

+#include "fsm.h"

+

+

+/*************************/

+/*** LOCAL DEFINITIONS ***/

+/*************************/

+

+#if PPP_DEBUG

+

+static const char *ppperr_strerr[] = {

+           "LS_INITIAL",  /* LS_INITIAL  0 */

+           "LS_STARTING", /* LS_STARTING 1 */

+           "LS_CLOSED",   /* LS_CLOSED   2 */

+           "LS_STOPPED",  /* LS_STOPPED  3 */

+           "LS_CLOSING",  /* LS_CLOSING  4 */

+           "LS_STOPPING", /* LS_STOPPING 5 */

+           "LS_REQSENT",  /* LS_REQSENT  6 */

+           "LS_ACKRCVD",  /* LS_ACKRCVD  7 */

+           "LS_ACKSENT",  /* LS_ACKSENT  8 */

+           "LS_OPENED"    /* LS_OPENED   9 */

+};

+

+#endif /* PPP_DEBUG */

+

+/************************/

+/*** LOCAL DATA TYPES ***/

+/************************/

+

+

+/***********************************/

+/*** LOCAL FUNCTION DECLARATIONS ***/

+/***********************************/

+static void fsm_timeout (void *);

+static void fsm_rconfreq (fsm *, u_char, u_char *, int);

+static void fsm_rconfack (fsm *, int, u_char *, int);

+static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);

+static void fsm_rtermreq (fsm *, int, u_char *, int);

+static void fsm_rtermack (fsm *);

+static void fsm_rcoderej (fsm *, u_char *, int);

+static void fsm_sconfreq (fsm *, int);

+

+#define PROTO_NAME(f) ((f)->callbacks->proto_name)

+

+

+/******************************/

+/*** PUBLIC DATA STRUCTURES ***/

+/******************************/

+

+

+/*****************************/

+/*** LOCAL DATA STRUCTURES ***/

+/*****************************/

+int peer_mru[NUM_PPP];

+

+

+/***********************************/

+/*** PUBLIC FUNCTION DEFINITIONS ***/

+/***********************************/

+

+/*

+ * fsm_init - Initialize fsm.

+ *

+ * Initialize fsm state.

+ */

+void

+fsm_init(fsm *f)

+{

+  f->state = LS_INITIAL;

+  f->flags = 0;

+  f->id = 0;        /* XXX Start with random id? */

+  f->timeouttime = FSM_DEFTIMEOUT;

+  f->maxconfreqtransmits = FSM_DEFMAXCONFREQS;

+  f->maxtermtransmits = FSM_DEFMAXTERMREQS;

+  f->maxnakloops = FSM_DEFMAXNAKLOOPS;

+  f->term_reason_len = 0;

+}

+

+

+/*

+ * fsm_lowerup - The lower layer is up.

+ */

+void

+fsm_lowerup(fsm *f)

+{

+  int oldState = f->state;

+

+  LWIP_UNUSED_ARG(oldState);

+

+  switch( f->state ) {

+    case LS_INITIAL:

+      f->state = LS_CLOSED;

+      break;

+

+    case LS_STARTING:

+      if( f->flags & OPT_SILENT ) {

+        f->state = LS_STOPPED;

+      } else {

+        /* Send an initial configure-request */

+        fsm_sconfreq(f, 0);

+        f->state = LS_REQSENT;

+      }

+    break;

+

+    default:

+      FSMDEBUG((LOG_INFO, "%s: Up event in state %d (%s)!\n",

+          PROTO_NAME(f), f->state, ppperr_strerr[f->state]));

+  }

+  

+  FSMDEBUG((LOG_INFO, "%s: lowerup state %d (%s) -> %d (%s)\n",

+      PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));

+}

+

+

+/*

+ * fsm_lowerdown - The lower layer is down.

+ *

+ * Cancel all timeouts and inform upper layers.

+ */

+void

+fsm_lowerdown(fsm *f)

+{

+  int oldState = f->state;

+

+  LWIP_UNUSED_ARG(oldState);

+

+  switch( f->state ) {

+    case LS_CLOSED:

+      f->state = LS_INITIAL;

+      break;

+

+    case LS_STOPPED:

+      f->state = LS_STARTING;

+      if( f->callbacks->starting ) {

+        (*f->callbacks->starting)(f);

+      }

+      break;

+

+    case LS_CLOSING:

+      f->state = LS_INITIAL;

+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */

+      break;

+

+    case LS_STOPPING:

+    case LS_REQSENT:

+    case LS_ACKRCVD:

+    case LS_ACKSENT:

+      f->state = LS_STARTING;

+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */

+      break;

+

+    case LS_OPENED:

+      if( f->callbacks->down ) {

+        (*f->callbacks->down)(f);

+      }

+      f->state = LS_STARTING;

+      break;

+

+    default:

+      FSMDEBUG((LOG_INFO, "%s: Down event in state %d (%s)!\n",

+          PROTO_NAME(f), f->state, ppperr_strerr[f->state]));

+  }

+

+  FSMDEBUG((LOG_INFO, "%s: lowerdown state %d (%s) -> %d (%s)\n",

+      PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));

+}

+

+

+/*

+ * fsm_open - Link is allowed to come up.

+ */

+void

+fsm_open(fsm *f)

+{

+  int oldState = f->state;

+

+  LWIP_UNUSED_ARG(oldState);

+

+  switch( f->state ) {

+    case LS_INITIAL:

+      f->state = LS_STARTING;

+      if( f->callbacks->starting ) {

+        (*f->callbacks->starting)(f);

+      }

+      break;

+

+    case LS_CLOSED:

+      if( f->flags & OPT_SILENT ) {

+        f->state = LS_STOPPED;

+      } else {

+        /* Send an initial configure-request */

+        fsm_sconfreq(f, 0);

+        f->state = LS_REQSENT;

+      }

+      break;

+  

+    case LS_CLOSING:

+      f->state = LS_STOPPING;

+      /* fall through */

+    case LS_STOPPED:

+    case LS_OPENED:

+      if( f->flags & OPT_RESTART ) {

+        fsm_lowerdown(f);

+        fsm_lowerup(f);

+      }

+      break;

+  }

+

+  FSMDEBUG((LOG_INFO, "%s: open state %d (%s) -> %d (%s)\n",

+      PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));

+}

+

+

+/*

+ * fsm_close - Start closing connection.

+ *

+ * Cancel timeouts and either initiate close or possibly go directly to

+ * the LS_CLOSED state.

+ */

+void

+fsm_close(fsm *f, char *reason)

+{

+  int oldState = f->state;

+

+  LWIP_UNUSED_ARG(oldState);

+

+  f->term_reason = reason;

+  f->term_reason_len = (reason == NULL? 0: strlen(reason));

+  switch( f->state ) {

+    case LS_STARTING:

+      f->state = LS_INITIAL;

+      break;

+    case LS_STOPPED:

+      f->state = LS_CLOSED;

+      break;

+    case LS_STOPPING:

+      f->state = LS_CLOSING;

+      break;

+

+    case LS_REQSENT:

+    case LS_ACKRCVD:

+    case LS_ACKSENT:

+    case LS_OPENED:

+      if( f->state != LS_OPENED ) {

+        UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */

+      } else if( f->callbacks->down ) {

+        (*f->callbacks->down)(f);  /* Inform upper layers we're down */

+      }

+      /* Init restart counter, send Terminate-Request */

+      f->retransmits = f->maxtermtransmits;

+      fsm_sdata(f, TERMREQ, f->reqid = ++f->id,

+            (u_char *) f->term_reason, f->term_reason_len);

+      TIMEOUT(fsm_timeout, f, f->timeouttime);

+      --f->retransmits;

+

+      f->state = LS_CLOSING;

+      break;

+  }

+

+  FSMDEBUG((LOG_INFO, "%s: close reason=%s state %d (%s) -> %d (%s)\n",

+      PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));

+}

+

+

+/*

+ * fsm_sdata - Send some data.

+ *

+ * Used for all packets sent to our peer by this module.

+ */

+void

+fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen)

+{

+  u_char *outp;

+  int outlen;

+

+  /* Adjust length to be smaller than MTU */

+  outp = outpacket_buf[f->unit];

+  if (datalen > peer_mru[f->unit] - (int)HEADERLEN) {

+    datalen = peer_mru[f->unit] - HEADERLEN;

+  }

+  if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) {

+    BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);

+  }

+  outlen = datalen + HEADERLEN;

+  MAKEHEADER(outp, f->protocol);

+  PUTCHAR(code, outp);

+  PUTCHAR(id, outp);

+  PUTSHORT(outlen, outp);

+  pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);

+  FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d,%d,%d.\n",

+        PROTO_NAME(f), code, id, outlen));

+}

+

+

+/*

+ * fsm_input - Input packet.

+ */

+void

+fsm_input(fsm *f, u_char *inpacket, int l)

+{

+  u_char *inp = inpacket;

+  u_char code, id;

+  int len;

+

+  /*

+  * Parse header (code, id and length).

+  * If packet too short, drop it.

+  */

+  if (l < HEADERLEN) {

+    FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.\n",

+          f->protocol));

+    return;

+  }

+  GETCHAR(code, inp);

+  GETCHAR(id, inp);

+  GETSHORT(len, inp);

+  if (len < HEADERLEN) {

+    FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.\n",

+        f->protocol));

+    return;

+  }

+  if (len > l) {

+    FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.\n",

+        f->protocol));

+    return;

+  }

+  len -= HEADERLEN;    /* subtract header length */

+

+  if( f->state == LS_INITIAL || f->state == LS_STARTING ) {

+    FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d (%s).\n",

+        f->protocol, f->state, ppperr_strerr[f->state]));

+    return;

+  }

+  FSMDEBUG((LOG_INFO, "fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));

+  /*

+   * Action depends on code.

+   */

+  switch (code) {

+    case CONFREQ:

+      fsm_rconfreq(f, id, inp, len);

+      break;

+    

+    case CONFACK:

+      fsm_rconfack(f, id, inp, len);

+      break;

+    

+    case CONFNAK:

+    case CONFREJ:

+      fsm_rconfnakrej(f, code, id, inp, len);

+      break;

+    

+    case TERMREQ:

+      fsm_rtermreq(f, id, inp, len);

+      break;

+    

+    case TERMACK:

+      fsm_rtermack(f);

+      break;

+    

+    case CODEREJ:

+      fsm_rcoderej(f, inp, len);

+      break;

+    

+    default:

+      if( !f->callbacks->extcode ||

+          !(*f->callbacks->extcode)(f, code, id, inp, len) ) {

+        fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);

+      }

+      break;

+  }

+}

+

+

+/*

+ * fsm_protreject - Peer doesn't speak this protocol.

+ *

+ * Treat this as a catastrophic error (RXJ-).

+ */

+void

+fsm_protreject(fsm *f)

+{

+  switch( f->state ) {

+    case LS_CLOSING:

+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */

+      /* fall through */

+    case LS_CLOSED:

+      f->state = LS_CLOSED;

+      if( f->callbacks->finished ) {

+        (*f->callbacks->finished)(f);

+      }

+      break;

+

+    case LS_STOPPING:

+    case LS_REQSENT:

+    case LS_ACKRCVD:

+    case LS_ACKSENT:

+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */

+      /* fall through */

+    case LS_STOPPED:

+      f->state = LS_STOPPED;

+      if( f->callbacks->finished ) {

+        (*f->callbacks->finished)(f);

+      }

+      break;

+    

+    case LS_OPENED:

+      if( f->callbacks->down ) {

+        (*f->callbacks->down)(f);

+      }

+      /* Init restart counter, send Terminate-Request */

+      f->retransmits = f->maxtermtransmits;

+      fsm_sdata(f, TERMREQ, f->reqid = ++f->id,

+            (u_char *) f->term_reason, f->term_reason_len);

+      TIMEOUT(fsm_timeout, f, f->timeouttime);

+      --f->retransmits;

+      

+      f->state = LS_STOPPING;

+      break;

+    

+    default:

+      FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d (%s)!\n",

+            PROTO_NAME(f), f->state, ppperr_strerr[f->state]));

+    }

+}

+

+

+

+

+

+/**********************************/

+/*** LOCAL FUNCTION DEFINITIONS ***/

+/**********************************/

+

+/*

+ * fsm_timeout - Timeout expired.

+ */

+static void

+fsm_timeout(void *arg)

+{

+  fsm *f = (fsm *) arg;

+

+  switch (f->state) {

+    case LS_CLOSING:

+    case LS_STOPPING:

+      if( f->retransmits <= 0 ) {

+        FSMDEBUG((LOG_WARNING, "%s: timeout sending Terminate-Request state=%d (%s)\n",

+             PROTO_NAME(f), f->state, ppperr_strerr[f->state]));

+        /*

+         * We've waited for an ack long enough.  Peer probably heard us.

+         */

+        f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED;

+        if( f->callbacks->finished ) {

+          (*f->callbacks->finished)(f);

+        }

+      } else {

+        FSMDEBUG((LOG_WARNING, "%s: timeout resending Terminate-Requests state=%d (%s)\n",

+             PROTO_NAME(f), f->state, ppperr_strerr[f->state]));

+        /* Send Terminate-Request */

+        fsm_sdata(f, TERMREQ, f->reqid = ++f->id,

+            (u_char *) f->term_reason, f->term_reason_len);

+        TIMEOUT(fsm_timeout, f, f->timeouttime);

+        --f->retransmits;

+      }

+      break;

+

+    case LS_REQSENT:

+    case LS_ACKRCVD:

+    case LS_ACKSENT:

+      if (f->retransmits <= 0) {

+        FSMDEBUG((LOG_WARNING, "%s: timeout sending Config-Requests state=%d (%s)\n",

+         PROTO_NAME(f), f->state, ppperr_strerr[f->state]));

+        f->state = LS_STOPPED;

+        if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) {

+          (*f->callbacks->finished)(f);

+        }

+      } else {

+        FSMDEBUG((LOG_WARNING, "%s: timeout resending Config-Request state=%d (%s)\n",

+         PROTO_NAME(f), f->state, ppperr_strerr[f->state]));

+        /* Retransmit the configure-request */

+        if (f->callbacks->retransmit) {

+          (*f->callbacks->retransmit)(f);

+        }

+        fsm_sconfreq(f, 1);    /* Re-send Configure-Request */

+        if( f->state == LS_ACKRCVD ) {

+          f->state = LS_REQSENT;

+        }

+      }

+      break;

+

+    default:

+      FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d (%s)!\n",

+          PROTO_NAME(f), f->state, ppperr_strerr[f->state]));

+  }

+}

+

+

+/*

+ * fsm_rconfreq - Receive Configure-Request.

+ */

+static void

+fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)

+{

+  int code, reject_if_disagree;

+

+  FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n", 

+        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));

+  switch( f->state ) {

+    case LS_CLOSED:

+      /* Go away, we're closed */

+      fsm_sdata(f, TERMACK, id, NULL, 0);

+      return;

+    case LS_CLOSING:

+    case LS_STOPPING:

+      return;

+

+    case LS_OPENED:

+      /* Go down and restart negotiation */

+      if( f->callbacks->down ) {

+        (*f->callbacks->down)(f);  /* Inform upper layers */

+      }

+      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */

+      break;

+

+    case LS_STOPPED:

+      /* Negotiation started by our peer */

+      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */

+      f->state = LS_REQSENT;

+      break;

+  }

+  

+  /*

+  * Pass the requested configuration options

+  * to protocol-specific code for checking.

+  */

+  if (f->callbacks->reqci) {    /* Check CI */

+    reject_if_disagree = (f->nakloops >= f->maxnakloops);

+    code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);

+  } else if (len) {

+    code = CONFREJ;      /* Reject all CI */

+  } else {

+    code = CONFACK;

+  }

+  

+  /* send the Ack, Nak or Rej to the peer */

+  fsm_sdata(f, (u_char)code, id, inp, len);

+  

+  if (code == CONFACK) {

+    if (f->state == LS_ACKRCVD) {

+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */

+      f->state = LS_OPENED;

+      if (f->callbacks->up) {

+        (*f->callbacks->up)(f);  /* Inform upper layers */

+      }

+    } else {

+      f->state = LS_ACKSENT;

+    }

+    f->nakloops = 0;

+  } else {

+    /* we sent CONFACK or CONFREJ */

+    if (f->state != LS_ACKRCVD) {

+      f->state = LS_REQSENT;

+    }

+    if( code == CONFNAK ) {

+      ++f->nakloops;

+    }

+  }

+}

+

+

+/*

+ * fsm_rconfack - Receive Configure-Ack.

+ */

+static void

+fsm_rconfack(fsm *f, int id, u_char *inp, int len)

+{

+  FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n",

+        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));

+  

+  if (id != f->reqid || f->seen_ack) {   /* Expected id? */

+    return; /* Nope, toss... */

+  }

+  if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ) {

+    /* Ack is bad - ignore it */

+    FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)\n",

+          PROTO_NAME(f), len));

+    return;

+  }

+  f->seen_ack = 1;

+  

+  switch (f->state) {

+    case LS_CLOSED:

+    case LS_STOPPED:

+      fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);

+      break;

+    

+    case LS_REQSENT:

+      f->state = LS_ACKRCVD;

+      f->retransmits = f->maxconfreqtransmits;

+      break;

+    

+    case LS_ACKRCVD:

+      /* Huh? an extra valid Ack? oh well... */

+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */

+      fsm_sconfreq(f, 0);

+      f->state = LS_REQSENT;

+      break;

+    

+    case LS_ACKSENT:

+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */

+      f->state = LS_OPENED;

+      f->retransmits = f->maxconfreqtransmits;

+      if (f->callbacks->up) {

+        (*f->callbacks->up)(f);  /* Inform upper layers */

+      }

+      break;

+    

+    case LS_OPENED:

+      /* Go down and restart negotiation */

+      if (f->callbacks->down) {

+        (*f->callbacks->down)(f);  /* Inform upper layers */

+      }

+      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */

+      f->state = LS_REQSENT;

+      break;

+  }

+}

+

+

+/*

+ * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.

+ */

+static void

+fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)

+{

+  int (*proc) (fsm *, u_char *, int);

+  int ret;

+

+  FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n",

+        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));

+

+  if (id != f->reqid || f->seen_ack) { /* Expected id? */

+    return;        /* Nope, toss... */

+  }

+  proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;

+  if (!proc || !((ret = proc(f, inp, len)))) {

+    /* Nak/reject is bad - ignore it */

+    FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)\n",

+          PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));

+    return;

+  }

+  f->seen_ack = 1;

+

+  switch (f->state) {

+    case LS_CLOSED:

+    case LS_STOPPED:

+      fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);

+      break;

+    

+    case LS_REQSENT:

+    case LS_ACKSENT:

+      /* They didn't agree to what we wanted - try another request */

+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */

+      if (ret < 0) {

+        f->state = LS_STOPPED;    /* kludge for stopping CCP */

+      } else {

+        fsm_sconfreq(f, 0);    /* Send Configure-Request */

+      }

+      break;

+    

+    case LS_ACKRCVD:

+      /* Got a Nak/reject when we had already had an Ack?? oh well... */

+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */

+      fsm_sconfreq(f, 0);

+      f->state = LS_REQSENT;

+      break;

+    

+    case LS_OPENED:

+      /* Go down and restart negotiation */

+      if (f->callbacks->down) {

+        (*f->callbacks->down)(f);  /* Inform upper layers */

+      }

+      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */

+      f->state = LS_REQSENT;

+      break;

+  }

+}

+

+

+/*

+ * fsm_rtermreq - Receive Terminate-Req.

+ */

+static void

+fsm_rtermreq(fsm *f, int id, u_char *p, int len)

+{

+  LWIP_UNUSED_ARG(p);

+

+  FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n",

+        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));

+

+  switch (f->state) {

+    case LS_ACKRCVD:

+    case LS_ACKSENT:

+      f->state = LS_REQSENT;    /* Start over but keep trying */

+      break;

+

+    case LS_OPENED:

+      if (len > 0) {

+        FSMDEBUG((LOG_INFO, "%s terminated by peer (%x)\n", PROTO_NAME(f), p));

+      } else {

+        FSMDEBUG((LOG_INFO, "%s terminated by peer\n", PROTO_NAME(f)));

+      }

+      if (f->callbacks->down) {

+        (*f->callbacks->down)(f);  /* Inform upper layers */

+      }

+      f->retransmits = 0;

+      f->state = LS_STOPPING;

+      TIMEOUT(fsm_timeout, f, f->timeouttime);

+      break;

+  }

+

+  fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);

+}

+

+

+/*

+ * fsm_rtermack - Receive Terminate-Ack.

+ */

+static void

+fsm_rtermack(fsm *f)

+{

+  FSMDEBUG((LOG_INFO, "fsm_rtermack(%s): state=%d (%s)\n", 

+        PROTO_NAME(f), f->state, ppperr_strerr[f->state]));

+  

+  switch (f->state) {

+    case LS_CLOSING:

+      UNTIMEOUT(fsm_timeout, f);

+      f->state = LS_CLOSED;

+      if( f->callbacks->finished ) {

+        (*f->callbacks->finished)(f);

+      }

+      break;

+

+    case LS_STOPPING:

+      UNTIMEOUT(fsm_timeout, f);

+      f->state = LS_STOPPED;

+      if( f->callbacks->finished ) {

+        (*f->callbacks->finished)(f);

+      }

+      break;

+    

+    case LS_ACKRCVD:

+      f->state = LS_REQSENT;

+      break;

+    

+    case LS_OPENED:

+      if (f->callbacks->down) {

+        (*f->callbacks->down)(f);  /* Inform upper layers */

+      }

+      fsm_sconfreq(f, 0);

+      break;

+  }

+}

+

+

+/*

+ * fsm_rcoderej - Receive an Code-Reject.

+ */

+static void

+fsm_rcoderej(fsm *f, u_char *inp, int len)

+{

+  u_char code, id;

+  

+  FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s): state=%d (%s)\n", 

+        PROTO_NAME(f), f->state, ppperr_strerr[f->state]));

+  

+  if (len < HEADERLEN) {

+    FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!\n"));

+    return;

+  }

+  GETCHAR(code, inp);

+  GETCHAR(id, inp);

+  FSMDEBUG((LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d\n",

+        PROTO_NAME(f), code, id));

+  

+  if( f->state == LS_ACKRCVD ) {

+    f->state = LS_REQSENT;

+  }

+}

+

+

+/*

+ * fsm_sconfreq - Send a Configure-Request.

+ */

+static void

+fsm_sconfreq(fsm *f, int retransmit)

+{

+  u_char *outp;

+  int cilen;

+  

+  if( f->state != LS_REQSENT && f->state != LS_ACKRCVD && f->state != LS_ACKSENT ) {

+    /* Not currently negotiating - reset options */

+    if( f->callbacks->resetci ) {

+      (*f->callbacks->resetci)(f);

+    }

+    f->nakloops = 0;

+  }

+  

+  if( !retransmit ) {

+    /* New request - reset retransmission counter, use new ID */

+    f->retransmits = f->maxconfreqtransmits;

+    f->reqid = ++f->id;

+  }

+  

+  f->seen_ack = 0;

+  

+  /*

+   * Make up the request packet

+   */

+  outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN;

+  if( f->callbacks->cilen && f->callbacks->addci ) {

+    cilen = (*f->callbacks->cilen)(f);

+    if( cilen > peer_mru[f->unit] - (int)HEADERLEN ) {

+      cilen = peer_mru[f->unit] - HEADERLEN;

+    }

+    if (f->callbacks->addci) {

+      (*f->callbacks->addci)(f, outp, &cilen);

+    }

+  } else {

+    cilen = 0;

+  }

+

+  /* send the request to our peer */

+  fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);

+  

+  /* start the retransmit timer */

+  --f->retransmits;

+  TIMEOUT(fsm_timeout, f, f->timeouttime);

+  

+  FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d\n",

+        PROTO_NAME(f), f->reqid));

+}

+

+#endif /* PPP_SUPPORT */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/fsm.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/fsm.h
new file mode 100644
index 0000000..02af4ee
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/fsm.h
@@ -0,0 +1,169 @@
+/*****************************************************************************

+* fsm.h - Network Control Protocol Finite State Machine header file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* Copyright (c) 1997 Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.

+*   Original based on BSD code.

+*****************************************************************************/

+/*

+ * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions.

+ *

+ * Copyright (c) 1989 Carnegie Mellon University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Carnegie Mellon University.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ *

+ * $Id: fsm.h,v 1.4 2007/12/19 20:47:23 fbernon Exp $

+ */

+

+#ifndef FSM_H

+#define FSM_H

+

+/*****************************************************************************

+************************* PUBLIC DEFINITIONS *********************************

+*****************************************************************************/

+/*

+ * LCP Packet header = Code, id, length.

+ */

+#define HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))

+

+

+/*

+ *  CP (LCP, IPCP, etc.) codes.

+ */

+#define CONFREQ     1 /* Configuration Request */

+#define CONFACK     2 /* Configuration Ack */

+#define CONFNAK     3 /* Configuration Nak */

+#define CONFREJ     4 /* Configuration Reject */

+#define TERMREQ     5 /* Termination Request */

+#define TERMACK     6 /* Termination Ack */

+#define CODEREJ     7 /* Code Reject */

+

+/*

+ * Link states.

+ */

+#define LS_INITIAL  0 /* Down, hasn't been opened */

+#define LS_STARTING 1 /* Down, been opened */

+#define LS_CLOSED   2 /* Up, hasn't been opened */

+#define LS_STOPPED  3 /* Open, waiting for down event */

+#define LS_CLOSING  4 /* Terminating the connection, not open */

+#define LS_STOPPING 5 /* Terminating, but open */

+#define LS_REQSENT  6 /* We've sent a Config Request */

+#define LS_ACKRCVD  7 /* We've received a Config Ack */

+#define LS_ACKSENT  8 /* We've sent a Config Ack */

+#define LS_OPENED   9 /* Connection available */

+

+/*

+ * Flags - indicate options controlling FSM operation

+ */

+#define OPT_PASSIVE 1 /* Don't die if we don't get a response */

+#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */

+#define OPT_SILENT  4 /* Wait for peer to speak first */

+

+

+/*****************************************************************************

+************************* PUBLIC DATA TYPES **********************************

+*****************************************************************************/

+/*

+ * Each FSM is described by an fsm structure and fsm callbacks.

+ */

+typedef struct fsm {

+  int unit;                        /* Interface unit number */

+  u_short protocol;                /* Data Link Layer Protocol field value */

+  int state;                       /* State */

+  int flags;                       /* Contains option bits */

+  u_char id;                       /* Current id */

+  u_char reqid;                    /* Current request id */

+  u_char seen_ack;                 /* Have received valid Ack/Nak/Rej to Req */

+  int timeouttime;                 /* Timeout time in milliseconds */

+  int maxconfreqtransmits;         /* Maximum Configure-Request transmissions */

+  int retransmits;                 /* Number of retransmissions left */

+  int maxtermtransmits;            /* Maximum Terminate-Request transmissions */

+  int nakloops;                    /* Number of nak loops since last ack */

+  int maxnakloops;                 /* Maximum number of nak loops tolerated */

+  struct fsm_callbacks* callbacks; /* Callback routines */

+  char* term_reason;               /* Reason for closing protocol */

+  int term_reason_len;             /* Length of term_reason */

+} fsm;

+

+

+typedef struct fsm_callbacks {

+  void (*resetci)(fsm*);                            /* Reset our Configuration Information */

+  int  (*cilen)(fsm*);                              /* Length of our Configuration Information */

+  void (*addci)(fsm*, u_char*, int*);               /* Add our Configuration Information */

+  int  (*ackci)(fsm*, u_char*, int);                /* ACK our Configuration Information */

+  int  (*nakci)(fsm*, u_char*, int);                /* NAK our Configuration Information */

+  int  (*rejci)(fsm*, u_char*, int);                /* Reject our Configuration Information */

+  int  (*reqci)(fsm*, u_char*, int*, int);          /* Request peer's Configuration Information */

+  void (*up)(fsm*);                                 /* Called when fsm reaches LS_OPENED state */

+  void (*down)(fsm*);                               /* Called when fsm leaves LS_OPENED state */

+  void (*starting)(fsm*);                           /* Called when we want the lower layer */

+  void (*finished)(fsm*);                           /* Called when we don't want the lower layer */

+  void (*protreject)(int);                          /* Called when Protocol-Reject received */

+  void (*retransmit)(fsm*);                         /* Retransmission is necessary */

+  int  (*extcode)(fsm*, int, u_char, u_char*, int); /* Called when unknown code received */

+  char *proto_name;                                 /* String name for protocol (for messages) */

+} fsm_callbacks;

+

+

+/*****************************************************************************

+*********************** PUBLIC DATA STRUCTURES *******************************

+*****************************************************************************/

+/*

+ * Variables

+ */

+extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */

+

+

+/*****************************************************************************

+************************** PUBLIC FUNCTIONS **********************************

+*****************************************************************************/

+

+/*

+ * Prototypes

+ */

+void fsm_init (fsm*);

+void fsm_lowerup (fsm*);

+void fsm_lowerdown (fsm*);

+void fsm_open (fsm*);

+void fsm_close (fsm*, char*);

+void fsm_input (fsm*, u_char*, int);

+void fsm_protreject (fsm*);

+void fsm_sdata (fsm*, u_char, u_char, u_char*, int);

+

+#endif /* FSM_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ipcp.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ipcp.c
new file mode 100644
index 0000000..7567091
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ipcp.c
@@ -0,0 +1,1440 @@
+/*****************************************************************************

+* ipcp.c - Network PPP IP Control Protocol program file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1997 by Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.

+*   Original.

+*****************************************************************************/

+/*

+ * ipcp.c - PPP IP Control Protocol.

+ *

+ * Copyright (c) 1989 Carnegie Mellon University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Carnegie Mellon University.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ */

+

+#include "lwip/opt.h"

+

+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#include "ppp.h"

+#include "pppdebug.h"

+

+#include "auth.h"

+#include "fsm.h"

+#include "vj.h"

+#include "ipcp.h"

+

+#include <string.h>

+

+/*************************/

+/*** LOCAL DEFINITIONS ***/

+/*************************/

+/* #define OLD_CI_ADDRS 1 */ /* Support deprecated address negotiation. */

+

+/*

+ * Lengths of configuration options.

+ */

+#define CILEN_VOID     2

+#define CILEN_COMPRESS 4  /* min length for compression protocol opt. */

+#define CILEN_VJ       6  /* length for RFC1332 Van-Jacobson opt. */

+#define CILEN_ADDR     6  /* new-style single address option */

+#define CILEN_ADDRS    10 /* old-style dual address option */

+

+

+

+/***********************************/

+/*** LOCAL FUNCTION DECLARATIONS ***/

+/***********************************/

+/*

+ * Callbacks for fsm code.  (CI = Configuration Information)

+ */

+static void ipcp_resetci (fsm *);                     /* Reset our CI */

+static int  ipcp_cilen (fsm *);                       /* Return length of our CI */

+static void ipcp_addci (fsm *, u_char *, int *);      /* Add our CI */

+static int  ipcp_ackci (fsm *, u_char *, int);        /* Peer ack'd our CI */

+static int  ipcp_nakci (fsm *, u_char *, int);        /* Peer nak'd our CI */

+static int  ipcp_rejci (fsm *, u_char *, int);        /* Peer rej'd our CI */

+static int  ipcp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */

+static void ipcp_up (fsm *);                          /* We're UP */

+static void ipcp_down (fsm *);                        /* We're DOWN */

+#if 0

+static void ipcp_script (fsm *, char *); /* Run an up/down script */

+#endif

+static void ipcp_finished (fsm *);                    /* Don't need lower layer */

+

+/*

+ * Protocol entry points from main code.

+ */

+static void ipcp_init (int);

+static void ipcp_open (int);

+static void ipcp_close (int, char *);

+static void ipcp_lowerup (int);

+static void ipcp_lowerdown (int);

+static void ipcp_input (int, u_char *, int);

+static void ipcp_protrej (int);

+

+static void ipcp_clear_addrs (int);

+

+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \

+                     (x) == CONFNAK ? "NAK" : "REJ")

+

+

+

+/******************************/

+/*** PUBLIC DATA STRUCTURES ***/

+/******************************/

+/* global vars */

+ipcp_options ipcp_wantoptions[NUM_PPP];  /* Options that we want to request */

+ipcp_options ipcp_gotoptions[NUM_PPP];   /* Options that peer ack'd */

+ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */

+ipcp_options ipcp_hisoptions[NUM_PPP];   /* Options that we ack'd */

+

+fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */

+

+struct protent ipcp_protent = {

+  PPP_IPCP,

+  ipcp_init,

+  ipcp_input,

+  ipcp_protrej,

+  ipcp_lowerup,

+  ipcp_lowerdown,

+  ipcp_open,

+  ipcp_close,

+#if 0

+  ipcp_printpkt,

+  NULL,

+#endif

+  1,

+  "IPCP",

+#if 0

+  ip_check_options,

+  NULL,

+  ip_active_pkt

+#endif

+};

+

+

+

+/*****************************/

+/*** LOCAL DATA STRUCTURES ***/

+/*****************************/

+/* local vars */

+static int cis_received[NUM_PPP];      /* # Conf-Reqs received */

+static int default_route_set[NUM_PPP]; /* Have set up a default route */

+

+static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */

+  ipcp_resetci,  /* Reset our Configuration Information */

+  ipcp_cilen,    /* Length of our Configuration Information */

+  ipcp_addci,    /* Add our Configuration Information */

+  ipcp_ackci,    /* ACK our Configuration Information */

+  ipcp_nakci,    /* NAK our Configuration Information */

+  ipcp_rejci,    /* Reject our Configuration Information */

+  ipcp_reqci,    /* Request peer's Configuration Information */

+  ipcp_up,       /* Called when fsm reaches LS_OPENED state */

+  ipcp_down,     /* Called when fsm leaves LS_OPENED state */

+  NULL,          /* Called when we want the lower layer up */

+  ipcp_finished, /* Called when we want the lower layer down */

+  NULL,          /* Called when Protocol-Reject received */

+  NULL,          /* Retransmission is necessary */

+  NULL,          /* Called to handle protocol-specific codes */

+  "IPCP"         /* String name of protocol */

+};

+

+

+

+/**********************************/

+/*** LOCAL FUNCTION DEFINITIONS ***/

+/**********************************/

+

+/*

+ * Non-standard inet_ntoa left here for compat with original ppp

+ * sources. Assumes u32_t instead of struct in_addr.

+ */ 

+

+char *

+_inet_ntoa(u32_t n)

+{

+  struct in_addr ia;

+  ia.s_addr = n;

+  return inet_ntoa(ia);

+}

+

+#define inet_ntoa _inet_ntoa

+

+/*

+ * ipcp_init - Initialize IPCP.

+ */

+static void

+ipcp_init(int unit)

+{

+  fsm           *f = &ipcp_fsm[unit];

+  ipcp_options *wo = &ipcp_wantoptions[unit];

+  ipcp_options *ao = &ipcp_allowoptions[unit];

+

+  f->unit      = unit;

+  f->protocol  = PPP_IPCP;

+  f->callbacks = &ipcp_callbacks;

+  fsm_init(&ipcp_fsm[unit]);

+

+  memset(wo, 0, sizeof(*wo));

+  memset(ao, 0, sizeof(*ao));

+

+  wo->neg_addr      = 1;

+  wo->ouraddr       = 0;

+#if VJ_SUPPORT

+  wo->neg_vj        = 1;

+#else  /* VJ_SUPPORT */

+  wo->neg_vj        = 0;

+#endif /* VJ_SUPPORT */

+  wo->vj_protocol   = IPCP_VJ_COMP;

+  wo->maxslotindex  = MAX_SLOTS - 1;

+  wo->cflag         = 0;

+  wo->default_route = 1;

+

+  ao->neg_addr      = 1;

+#if VJ_SUPPORT

+  ao->neg_vj        = 1;

+#else  /* VJ_SUPPORT */

+  ao->neg_vj        = 0;

+#endif /* VJ_SUPPORT */

+  ao->maxslotindex  = MAX_SLOTS - 1;

+  ao->cflag         = 1;

+  ao->default_route = 1;

+}

+

+

+/*

+ * ipcp_open - IPCP is allowed to come up.

+ */

+static void

+ipcp_open(int unit)

+{

+  fsm_open(&ipcp_fsm[unit]);

+}

+

+

+/*

+ * ipcp_close - Take IPCP down.

+ */

+static void

+ipcp_close(int unit, char *reason)

+{

+  fsm_close(&ipcp_fsm[unit], reason);

+}

+

+

+/*

+ * ipcp_lowerup - The lower layer is up.

+ */

+static void

+ipcp_lowerup(int unit)

+{

+  fsm_lowerup(&ipcp_fsm[unit]);

+}

+

+

+/*

+ * ipcp_lowerdown - The lower layer is down.

+ */

+static void

+ipcp_lowerdown(int unit)

+{

+  fsm_lowerdown(&ipcp_fsm[unit]);

+}

+

+

+/*

+ * ipcp_input - Input IPCP packet.

+ */

+static void

+ipcp_input(int unit, u_char *p, int len)

+{

+  fsm_input(&ipcp_fsm[unit], p, len);

+}

+

+

+/*

+ * ipcp_protrej - A Protocol-Reject was received for IPCP.

+ *

+ * Pretend the lower layer went down, so we shut up.

+ */

+static void

+ipcp_protrej(int unit)

+{

+  fsm_lowerdown(&ipcp_fsm[unit]);

+}

+

+

+/*

+ * ipcp_resetci - Reset our CI.

+ */

+static void

+ipcp_resetci(fsm *f)

+{

+  ipcp_options *wo = &ipcp_wantoptions[f->unit];

+  

+  wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;

+  if (wo->ouraddr == 0) {

+    wo->accept_local = 1;

+  }

+  if (wo->hisaddr == 0) {

+    wo->accept_remote = 1;

+  }

+  /* Request DNS addresses from the peer */

+  wo->req_dns1 = ppp_settings.usepeerdns;

+  wo->req_dns2 = ppp_settings.usepeerdns;

+  ipcp_gotoptions[f->unit] = *wo;

+  cis_received[f->unit] = 0;

+}

+

+

+/*

+ * ipcp_cilen - Return length of our CI.

+ */

+static int

+ipcp_cilen(fsm *f)

+{

+  ipcp_options *go = &ipcp_gotoptions[f->unit];

+  ipcp_options *wo = &ipcp_wantoptions[f->unit];

+  ipcp_options *ho = &ipcp_hisoptions[f->unit];

+

+#define LENCIVJ(neg, old)   (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)

+#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)

+#define LENCIDNS(neg)       (neg ? (CILEN_ADDR) : 0)

+

+  /*

+   * First see if we want to change our options to the old

+   * forms because we have received old forms from the peer.

+   */

+  if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {

+    /* use the old style of address negotiation */

+    go->neg_addr = 1;

+    go->old_addrs = 1;

+  }

+  if (wo->neg_vj && !go->neg_vj && !go->old_vj) {

+    /* try an older style of VJ negotiation */

+    if (cis_received[f->unit] == 0) {

+      /* keep trying the new style until we see some CI from the peer */

+      go->neg_vj = 1;

+    } else {

+      /* use the old style only if the peer did */

+      if (ho->neg_vj && ho->old_vj) {

+        go->neg_vj = 1;

+        go->old_vj = 1;

+        go->vj_protocol = ho->vj_protocol;

+      }

+    }

+  }

+

+  return (LENCIADDR(go->neg_addr, go->old_addrs) +

+          LENCIVJ(go->neg_vj, go->old_vj) +

+          LENCIDNS(go->req_dns1) +

+          LENCIDNS(go->req_dns2));

+}

+

+

+/*

+ * ipcp_addci - Add our desired CIs to a packet.

+ */

+static void

+ipcp_addci(fsm *f, u_char *ucp, int *lenp)

+{

+  ipcp_options *go = &ipcp_gotoptions[f->unit];

+  int len = *lenp;

+

+#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \

+  if (neg) { \

+    int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \

+    if (len >= vjlen) { \

+      PUTCHAR(opt, ucp); \

+      PUTCHAR(vjlen, ucp); \

+      PUTSHORT(val, ucp); \

+      if (!old) { \

+        PUTCHAR(maxslotindex, ucp); \

+        PUTCHAR(cflag, ucp); \

+      } \

+      len -= vjlen; \

+    } else { \

+      neg = 0; \

+    } \

+  }

+

+#define ADDCIADDR(opt, neg, old, val1, val2) \

+  if (neg) { \

+    int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \

+    if (len >= addrlen) { \

+      u32_t l; \

+      PUTCHAR(opt, ucp); \

+      PUTCHAR(addrlen, ucp); \

+      l = ntohl(val1); \

+      PUTLONG(l, ucp); \

+      if (old) { \

+        l = ntohl(val2); \

+        PUTLONG(l, ucp); \

+      } \

+      len -= addrlen; \

+    } else { \

+      neg = 0; \

+    } \

+  }

+

+#define ADDCIDNS(opt, neg, addr) \

+  if (neg) { \

+    if (len >= CILEN_ADDR) { \

+      u32_t l; \

+      PUTCHAR(opt, ucp); \

+      PUTCHAR(CILEN_ADDR, ucp); \

+      l = ntohl(addr); \

+      PUTLONG(l, ucp); \

+      len -= CILEN_ADDR; \

+    } else { \

+      neg = 0; \

+    } \

+  }

+

+  ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,

+      go->old_addrs, go->ouraddr, go->hisaddr);

+

+  ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,

+      go->maxslotindex, go->cflag);

+

+  ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);

+

+  ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);

+

+  *lenp -= len;

+}

+

+

+/*

+ * ipcp_ackci - Ack our CIs.

+ *

+ * Returns:

+ *  0 - Ack was bad.

+ *  1 - Ack was good.

+ */

+static int

+ipcp_ackci(fsm *f, u_char *p, int len)

+{

+  ipcp_options *go = &ipcp_gotoptions[f->unit];

+  u_short cilen, citype, cishort;

+  u32_t cilong;

+  u_char cimaxslotindex, cicflag;

+

+  /*

+   * CIs must be in exactly the same order that we sent...

+   * Check packet length and CI length at each step.

+   * If we find any deviations, then this packet is bad.

+   */

+

+#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \

+  if (neg) { \

+    int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \

+    if ((len -= vjlen) < 0) { \

+      goto bad; \

+    } \

+    GETCHAR(citype, p); \

+    GETCHAR(cilen, p); \

+    if (cilen != vjlen || \

+        citype != opt) { \

+      goto bad; \

+    } \

+    GETSHORT(cishort, p); \

+    if (cishort != val) { \

+      goto bad; \

+    } \

+    if (!old) { \

+      GETCHAR(cimaxslotindex, p); \

+      if (cimaxslotindex != maxslotindex) { \

+        goto bad; \

+      } \

+      GETCHAR(cicflag, p); \

+      if (cicflag != cflag) { \

+        goto bad; \

+      } \

+    } \

+  }

+  

+#define ACKCIADDR(opt, neg, old, val1, val2) \

+  if (neg) { \

+    int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \

+    u32_t l; \

+    if ((len -= addrlen) < 0) { \

+      goto bad; \

+    } \

+    GETCHAR(citype, p); \

+    GETCHAR(cilen, p); \

+    if (cilen != addrlen || \

+        citype != opt) { \

+      goto bad; \

+    } \

+    GETLONG(l, p); \

+    cilong = htonl(l); \

+    if (val1 != cilong) { \

+      goto bad; \

+    } \

+    if (old) { \

+      GETLONG(l, p); \

+      cilong = htonl(l); \

+      if (val2 != cilong) { \

+        goto bad; \

+      } \

+    } \

+  }

+

+#define ACKCIDNS(opt, neg, addr) \

+  if (neg) { \

+    u32_t l; \

+    if ((len -= CILEN_ADDR) < 0) { \

+      goto bad; \

+    } \

+    GETCHAR(citype, p); \

+    GETCHAR(cilen, p); \

+    if (cilen != CILEN_ADDR || \

+        citype != opt) { \

+      goto bad; \

+    } \

+    GETLONG(l, p); \

+    cilong = htonl(l); \

+    if (addr != cilong) { \

+      goto bad; \

+    } \

+  }

+

+  ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,

+        go->old_addrs, go->ouraddr, go->hisaddr);

+

+  ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,

+      go->maxslotindex, go->cflag);

+

+  ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);

+

+  ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);

+

+  /*

+   * If there are any remaining CIs, then this packet is bad.

+   */

+  if (len != 0) {

+    goto bad;

+  }

+  return (1);

+  

+bad:

+  IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!\n"));

+  return (0);

+}

+

+/*

+ * ipcp_nakci - Peer has sent a NAK for some of our CIs.

+ * This should not modify any state if the Nak is bad

+ * or if IPCP is in the LS_OPENED state.

+ *

+ * Returns:

+ *  0 - Nak was bad.

+ *  1 - Nak was good.

+ */

+static int

+ipcp_nakci(fsm *f, u_char *p, int len)

+{

+  ipcp_options *go = &ipcp_gotoptions[f->unit];

+  u_char cimaxslotindex, cicflag;

+  u_char citype, cilen, *next;

+  u_short cishort;

+  u32_t ciaddr1, ciaddr2, l, cidnsaddr;

+  ipcp_options no;    /* options we've seen Naks for */

+  ipcp_options try;    /* options to request next time */

+

+  BZERO(&no, sizeof(no));

+  try = *go;

+

+  /*

+   * Any Nak'd CIs must be in exactly the same order that we sent.

+   * Check packet length and CI length at each step.

+   * If we find any deviations, then this packet is bad.

+   */

+#define NAKCIADDR(opt, neg, old, code) \

+  if (go->neg && \

+      len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \

+      p[1] == cilen && \

+      p[0] == opt) { \

+    len -= cilen; \

+    INCPTR(2, p); \

+    GETLONG(l, p); \

+    ciaddr1 = htonl(l); \

+    if (old) { \

+      GETLONG(l, p); \

+      ciaddr2 = htonl(l); \

+      no.old_addrs = 1; \

+    } else { \

+      ciaddr2 = 0; \

+    } \

+    no.neg = 1; \

+    code \

+  }

+

+#define NAKCIVJ(opt, neg, code) \

+  if (go->neg && \

+      ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \

+      len >= cilen && \

+      p[0] == opt) { \

+    len -= cilen; \

+    INCPTR(2, p); \

+    GETSHORT(cishort, p); \

+    no.neg = 1; \

+    code \

+  }

+  

+#define NAKCIDNS(opt, neg, code) \

+  if (go->neg && \

+      ((cilen = p[1]) == CILEN_ADDR) && \

+      len >= cilen && \

+      p[0] == opt) { \

+    len -= cilen; \

+    INCPTR(2, p); \

+    GETLONG(l, p); \

+    cidnsaddr = htonl(l); \

+    no.neg = 1; \

+    code \

+  }

+

+  /*

+   * Accept the peer's idea of {our,his} address, if different

+   * from our idea, only if the accept_{local,remote} flag is set.

+   */

+  NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,

+    if (go->accept_local && ciaddr1) { /* Do we know our address? */

+      try.ouraddr = ciaddr1;

+      IPCPDEBUG((LOG_INFO, "local IP address %s\n",

+           inet_ntoa(ciaddr1)));

+    }

+    if (go->accept_remote && ciaddr2) { /* Does he know his? */

+      try.hisaddr = ciaddr2;

+      IPCPDEBUG((LOG_INFO, "remote IP address %s\n",

+           inet_ntoa(ciaddr2)));

+    }

+  );

+

+  /*

+   * Accept the peer's value of maxslotindex provided that it

+   * is less than what we asked for.  Turn off slot-ID compression

+   * if the peer wants.  Send old-style compress-type option if

+   * the peer wants.

+   */

+  NAKCIVJ(CI_COMPRESSTYPE, neg_vj,

+    if (cilen == CILEN_VJ) {

+      GETCHAR(cimaxslotindex, p);

+      GETCHAR(cicflag, p);

+      if (cishort == IPCP_VJ_COMP) {

+        try.old_vj = 0;

+        if (cimaxslotindex < go->maxslotindex) {

+          try.maxslotindex = cimaxslotindex;

+        }

+        if (!cicflag) {

+          try.cflag = 0;

+        }

+      } else {

+        try.neg_vj = 0;

+      }

+    } else {

+      if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {

+        try.old_vj = 1;

+        try.vj_protocol = cishort;

+      } else {

+        try.neg_vj = 0;

+      }

+    }

+  );

+

+  NAKCIDNS(CI_MS_DNS1, req_dns1,

+      try.dnsaddr[0] = cidnsaddr;

+        IPCPDEBUG((LOG_INFO, "primary DNS address %s\n", inet_ntoa(cidnsaddr)));

+      );

+

+  NAKCIDNS(CI_MS_DNS2, req_dns2,

+      try.dnsaddr[1] = cidnsaddr;

+        IPCPDEBUG((LOG_INFO, "secondary DNS address %s\n", inet_ntoa(cidnsaddr)));

+      );

+

+  /*

+  * There may be remaining CIs, if the peer is requesting negotiation

+  * on an option that we didn't include in our request packet.

+  * If they want to negotiate about IP addresses, we comply.

+  * If they want us to ask for compression, we refuse.

+  */

+  while (len > CILEN_VOID) {

+    GETCHAR(citype, p);

+    GETCHAR(cilen, p);

+    if( (len -= cilen) < 0 ) {

+      goto bad;

+    }

+    next = p + cilen - 2;

+

+    switch (citype) {

+      case CI_COMPRESSTYPE:

+        if (go->neg_vj || no.neg_vj ||

+            (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {

+          goto bad;

+        }

+        no.neg_vj = 1;

+        break;

+      case CI_ADDRS:

+        if ((go->neg_addr && go->old_addrs) || no.old_addrs

+            || cilen != CILEN_ADDRS) {

+          goto bad;

+        }

+        try.neg_addr = 1;

+        try.old_addrs = 1;

+        GETLONG(l, p);

+        ciaddr1 = htonl(l);

+        if (ciaddr1 && go->accept_local) {

+          try.ouraddr = ciaddr1;

+        }

+        GETLONG(l, p);

+        ciaddr2 = htonl(l);

+        if (ciaddr2 && go->accept_remote) {

+          try.hisaddr = ciaddr2;

+        }

+        no.old_addrs = 1;

+        break;

+      case CI_ADDR:

+        if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) {

+          goto bad;

+        }

+        try.old_addrs = 0;

+        GETLONG(l, p);

+        ciaddr1 = htonl(l);

+        if (ciaddr1 && go->accept_local) {

+          try.ouraddr = ciaddr1;

+        }

+        if (try.ouraddr != 0) {

+          try.neg_addr = 1;

+        }

+        no.neg_addr = 1;

+        break;

+    }

+    p = next;

+  }

+

+  /* If there is still anything left, this packet is bad. */

+  if (len != 0) {

+    goto bad;

+  }

+

+  /*

+   * OK, the Nak is good.  Now we can update state.

+   */

+  if (f->state != LS_OPENED) {

+    *go = try;

+  }

+

+  return 1;

+

+bad:

+  IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!\n"));

+  return 0;

+}

+

+

+/*

+ * ipcp_rejci - Reject some of our CIs.

+ */

+static int

+ipcp_rejci(fsm *f, u_char *p, int len)

+{

+  ipcp_options *go = &ipcp_gotoptions[f->unit];

+  u_char cimaxslotindex, ciflag, cilen;

+  u_short cishort;

+  u32_t cilong;

+  ipcp_options try;    /* options to request next time */

+

+  try = *go;

+  /*

+   * Any Rejected CIs must be in exactly the same order that we sent.

+   * Check packet length and CI length at each step.

+   * If we find any deviations, then this packet is bad.

+   */

+#define REJCIADDR(opt, neg, old, val1, val2) \

+  if (go->neg && \

+      len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \

+      p[1] == cilen && \

+      p[0] == opt) { \

+    u32_t l; \

+    len -= cilen; \

+    INCPTR(2, p); \

+    GETLONG(l, p); \

+    cilong = htonl(l); \

+    /* Check rejected value. */ \

+    if (cilong != val1) { \

+      goto bad; \

+    } \

+    if (old) { \

+      GETLONG(l, p); \

+      cilong = htonl(l); \

+      /* Check rejected value. */ \

+      if (cilong != val2) { \

+        goto bad; \

+      } \

+    } \

+    try.neg = 0; \

+  }

+

+#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \

+  if (go->neg && \

+      p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \

+      len >= p[1] && \

+      p[0] == opt) { \

+    len -= p[1]; \

+    INCPTR(2, p); \

+    GETSHORT(cishort, p); \

+    /* Check rejected value. */  \

+    if (cishort != val) { \

+      goto bad; \

+    } \

+    if (!old) { \

+      GETCHAR(cimaxslotindex, p); \

+      if (cimaxslotindex != maxslot) { \

+        goto bad; \

+      } \

+      GETCHAR(ciflag, p); \

+      if (ciflag != cflag) { \

+        goto bad; \

+      } \

+    } \

+    try.neg = 0; \

+  }

+

+#define REJCIDNS(opt, neg, dnsaddr) \

+  if (go->neg && \

+      ((cilen = p[1]) == CILEN_ADDR) && \

+      len >= cilen && \

+      p[0] == opt) { \

+    u32_t l; \

+    len -= cilen; \

+    INCPTR(2, p); \

+    GETLONG(l, p); \

+    cilong = htonl(l); \

+    /* Check rejected value. */ \

+    if (cilong != dnsaddr) { \

+      goto bad; \

+    } \

+    try.neg = 0; \

+  }

+

+  REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,

+        go->old_addrs, go->ouraddr, go->hisaddr);

+

+  REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,

+      go->maxslotindex, go->cflag);

+

+  REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]);

+

+  REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]);

+

+  /*

+   * If there are any remaining CIs, then this packet is bad.

+   */

+  if (len != 0) {

+    goto bad;

+  }

+  /*

+   * Now we can update state.

+   */

+  if (f->state != LS_OPENED) {

+    *go = try;

+  }

+  return 1;

+

+bad:

+  IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!\n"));

+  return 0;

+}

+

+

+/*

+ * ipcp_reqci - Check the peer's requested CIs and send appropriate response.

+ *

+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified

+ * appropriately.  If reject_if_disagree is non-zero, doesn't return

+ * CONFNAK; returns CONFREJ if it can't return CONFACK.

+ */

+static int

+ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested CIs */,int reject_if_disagree)

+{

+  ipcp_options *wo = &ipcp_wantoptions[f->unit];

+  ipcp_options *ho = &ipcp_hisoptions[f->unit];

+  ipcp_options *ao = &ipcp_allowoptions[f->unit];

+#ifdef OLD_CI_ADDRS

+  ipcp_options *go = &ipcp_gotoptions[f->unit];

+#endif

+  u_char *cip, *next;     /* Pointer to current and next CIs */

+  u_short cilen, citype;  /* Parsed len, type */

+  u_short cishort;        /* Parsed short value */

+  u32_t tl, ciaddr1;      /* Parsed address values */

+#ifdef OLD_CI_ADDRS

+  u32_t ciaddr2;          /* Parsed address values */

+#endif

+  int rc = CONFACK;       /* Final packet return code */

+  int orc;                /* Individual option return code */

+  u_char *p;              /* Pointer to next char to parse */

+  u_char *ucp = inp;      /* Pointer to current output char */

+  int l = *len;           /* Length left */

+  u_char maxslotindex, cflag;

+  int d;

+

+  cis_received[f->unit] = 1;

+

+  /*

+   * Reset all his options.

+   */

+  BZERO(ho, sizeof(*ho));

+

+  /*

+   * Process all his options.

+   */

+  next = inp;

+  while (l) {

+    orc = CONFACK;       /* Assume success */

+    cip = p = next;      /* Remember begining of CI */

+    if (l < 2 ||         /* Not enough data for CI header or */

+        p[1] < 2 ||      /*  CI length too small or */

+        p[1] > l) {      /*  CI length too big? */

+      IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!\n"));

+      orc = CONFREJ;     /* Reject bad CI */

+      cilen = l;         /* Reject till end of packet */

+      l = 0;             /* Don't loop again */

+      goto endswitch;

+    }

+    GETCHAR(citype, p);  /* Parse CI type */

+    GETCHAR(cilen, p);   /* Parse CI length */

+    l -= cilen;          /* Adjust remaining length */

+    next += cilen;       /* Step to next CI */

+

+    switch (citype) {      /* Check CI type */

+#ifdef OLD_CI_ADDRS /* Need to save space... */

+      case CI_ADDRS:

+        IPCPDEBUG((LOG_INFO, "ipcp_reqci: received ADDRS\n"));

+        if (!ao->neg_addr ||

+            cilen != CILEN_ADDRS) {  /* Check CI length */

+          orc = CONFREJ;    /* Reject CI */

+          break;

+        }

+

+        /*

+         * If he has no address, or if we both have his address but

+         * disagree about it, then NAK it with our idea.

+         * In particular, if we don't know his address, but he does,

+         * then accept it.

+         */

+        GETLONG(tl, p);    /* Parse source address (his) */

+        ciaddr1 = htonl(tl);

+        IPCPDEBUG((LOG_INFO, "his addr %s\n", inet_ntoa(ciaddr1)));

+        if (ciaddr1 != wo->hisaddr

+            && (ciaddr1 == 0 || !wo->accept_remote)) {

+          orc = CONFNAK;

+          if (!reject_if_disagree) {

+            DECPTR(sizeof(u32_t), p);

+            tl = ntohl(wo->hisaddr);

+            PUTLONG(tl, p);

+          }

+        } else if (ciaddr1 == 0 && wo->hisaddr == 0) {

+          /*

+           * If neither we nor he knows his address, reject the option.

+           */

+          orc = CONFREJ;

+          wo->req_addr = 0;  /* don't NAK with 0.0.0.0 later */

+          break;

+        }

+

+        /*

+         * If he doesn't know our address, or if we both have our address

+         * but disagree about it, then NAK it with our idea.

+         */

+        GETLONG(tl, p);    /* Parse desination address (ours) */

+        ciaddr2 = htonl(tl);

+        IPCPDEBUG((LOG_INFO, "our addr %s\n", inet_ntoa(ciaddr2)));

+        if (ciaddr2 != wo->ouraddr) {

+          if (ciaddr2 == 0 || !wo->accept_local) {

+            orc = CONFNAK;

+            if (!reject_if_disagree) {

+              DECPTR(sizeof(u32_t), p);

+              tl = ntohl(wo->ouraddr);

+              PUTLONG(tl, p);

+            }

+          } else {

+            go->ouraddr = ciaddr2;  /* accept peer's idea */

+          }

+        }

+

+        ho->neg_addr = 1;

+        ho->old_addrs = 1;

+        ho->hisaddr = ciaddr1;

+        ho->ouraddr = ciaddr2;

+        break;

+#endif

+

+      case CI_ADDR:

+        if (!ao->neg_addr) {

+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR not allowed\n"));

+          orc = CONFREJ;        /* Reject CI */

+          break;

+        } else if (cilen != CILEN_ADDR) {  /* Check CI length */

+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR bad len\n"));

+          orc = CONFREJ;        /* Reject CI */

+          break;

+        }

+

+        /*

+         * If he has no address, or if we both have his address but

+         * disagree about it, then NAK it with our idea.

+         * In particular, if we don't know his address, but he does,

+         * then accept it.

+         */

+        GETLONG(tl, p);  /* Parse source address (his) */

+        ciaddr1 = htonl(tl);

+        if (ciaddr1 != wo->hisaddr

+            && (ciaddr1 == 0 || !wo->accept_remote)) {

+          orc = CONFNAK;

+          if (!reject_if_disagree) {

+            DECPTR(sizeof(u32_t), p);

+            tl = ntohl(wo->hisaddr);

+            PUTLONG(tl, p);

+          }

+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Nak ADDR %s\n", inet_ntoa(ciaddr1)));

+        } else if (ciaddr1 == 0 && wo->hisaddr == 0) {

+          /*

+           * Don't ACK an address of 0.0.0.0 - reject it instead.

+           */

+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR %s\n", inet_ntoa(ciaddr1)));

+          orc = CONFREJ;

+          wo->req_addr = 0;  /* don't NAK with 0.0.0.0 later */

+          break;

+        }

+

+        ho->neg_addr = 1;

+        ho->hisaddr = ciaddr1;

+        IPCPDEBUG((LOG_INFO, "ipcp_reqci: ADDR %s\n", inet_ntoa(ciaddr1)));

+        break;

+

+      case CI_MS_DNS1:

+      case CI_MS_DNS2:

+        /* Microsoft primary or secondary DNS request */

+        d = citype == CI_MS_DNS2;

+

+        /* If we do not have a DNS address then we cannot send it */

+        if (ao->dnsaddr[d] == 0 ||

+            cilen != CILEN_ADDR) {  /* Check CI length */

+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting DNS%d Request\n", d+1));

+          orc = CONFREJ;        /* Reject CI */

+          break;

+        }

+        GETLONG(tl, p);

+        if (htonl(tl) != ao->dnsaddr[d]) {

+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking DNS%d Request %d\n",

+                d+1, inet_ntoa(tl)));

+          DECPTR(sizeof(u32_t), p);

+          tl = ntohl(ao->dnsaddr[d]);

+          PUTLONG(tl, p);

+          orc = CONFNAK;

+        }

+        IPCPDEBUG((LOG_INFO, "ipcp_reqci: received DNS%d Request\n", d+1));

+        break;

+

+      case CI_MS_WINS1:

+      case CI_MS_WINS2:

+        /* Microsoft primary or secondary WINS request */

+        d = citype == CI_MS_WINS2;

+        IPCPDEBUG((LOG_INFO, "ipcp_reqci: received WINS%d Request\n", d+1));

+

+        /* If we do not have a DNS address then we cannot send it */

+        if (ao->winsaddr[d] == 0 ||

+          cilen != CILEN_ADDR) {  /* Check CI length */

+          orc = CONFREJ;      /* Reject CI */

+          break;

+        }

+        GETLONG(tl, p);

+        if (htonl(tl) != ao->winsaddr[d]) {

+          DECPTR(sizeof(u32_t), p);

+          tl = ntohl(ao->winsaddr[d]);

+          PUTLONG(tl, p);

+          orc = CONFNAK;

+        }

+        break;

+

+      case CI_COMPRESSTYPE:

+        if (!ao->neg_vj) {

+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE not allowed\n"));

+          orc = CONFREJ;

+          break;

+        } else if (cilen != CILEN_VJ && cilen != CILEN_COMPRESS) {

+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE len=%d\n", cilen));

+          orc = CONFREJ;

+          break;

+        }

+        GETSHORT(cishort, p);

+

+        if (!(cishort == IPCP_VJ_COMP ||

+            (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {

+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE %d\n", cishort));

+          orc = CONFREJ;

+          break;

+        }

+

+        ho->neg_vj = 1;

+        ho->vj_protocol = cishort;

+        if (cilen == CILEN_VJ) {

+          GETCHAR(maxslotindex, p);

+          if (maxslotindex > ao->maxslotindex) { 

+            IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ max slot %d\n", maxslotindex));

+            orc = CONFNAK;

+            if (!reject_if_disagree) {

+              DECPTR(1, p);

+              PUTCHAR(ao->maxslotindex, p);

+            }

+          }

+          GETCHAR(cflag, p);

+          if (cflag && !ao->cflag) {

+            IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ cflag %d\n", cflag));

+            orc = CONFNAK;

+            if (!reject_if_disagree) {

+              DECPTR(1, p);

+              PUTCHAR(wo->cflag, p);

+            }

+          }

+          ho->maxslotindex = maxslotindex;

+          ho->cflag = cflag;

+        } else {

+          ho->old_vj = 1;

+          ho->maxslotindex = MAX_SLOTS - 1;

+          ho->cflag = 1;

+        }

+        IPCPDEBUG((LOG_INFO, 

+              "ipcp_reqci: received COMPRESSTYPE p=%d old=%d maxslot=%d cflag=%d\n",

+              ho->vj_protocol, ho->old_vj, ho->maxslotindex, ho->cflag));

+        break;

+

+      default:

+        IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting unknown CI type %d\n", citype));

+        orc = CONFREJ;

+        break;

+    }

+

+endswitch:

+    if (orc == CONFACK &&    /* Good CI */

+        rc != CONFACK) {     /*  but prior CI wasnt? */

+      continue;              /* Don't send this one */

+    }

+

+    if (orc == CONFNAK) {    /* Nak this CI? */

+      if (reject_if_disagree) {  /* Getting fed up with sending NAKs? */

+        IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting too many naks\n"));

+        orc = CONFREJ;       /* Get tough if so */

+      } else {

+        if (rc == CONFREJ) { /* Rejecting prior CI? */

+          continue;          /* Don't send this one */

+        }

+        if (rc == CONFACK) { /* Ack'd all prior CIs? */

+          rc = CONFNAK;      /* Not anymore... */

+          ucp = inp;         /* Backup */

+        }

+      }

+    }

+

+    if (orc == CONFREJ &&    /* Reject this CI */

+        rc != CONFREJ) {  /*  but no prior ones? */

+      rc = CONFREJ;

+      ucp = inp;        /* Backup */

+    }

+    

+    /* Need to move CI? */

+    if (ucp != cip) {

+      BCOPY(cip, ucp, cilen);  /* Move it */

+    }

+

+    /* Update output pointer */

+    INCPTR(cilen, ucp);

+  }

+

+  /*

+   * If we aren't rejecting this packet, and we want to negotiate

+   * their address, and they didn't send their address, then we

+   * send a NAK with a CI_ADDR option appended.  We assume the

+   * input buffer is long enough that we can append the extra

+   * option safely.

+   */

+  if (rc != CONFREJ && !ho->neg_addr &&

+      wo->req_addr && !reject_if_disagree) {

+    IPCPDEBUG((LOG_INFO, "ipcp_reqci: Requesting peer address\n"));

+    if (rc == CONFACK) {

+      rc = CONFNAK;

+      ucp = inp;        /* reset pointer */

+      wo->req_addr = 0;    /* don't ask again */

+    }

+    PUTCHAR(CI_ADDR, ucp);

+    PUTCHAR(CILEN_ADDR, ucp);

+    tl = ntohl(wo->hisaddr);

+    PUTLONG(tl, ucp);

+  }

+

+  *len = (int)(ucp - inp);    /* Compute output length */

+  IPCPDEBUG((LOG_INFO, "ipcp_reqci: returning Configure-%s\n", CODENAME(rc)));

+  return (rc);      /* Return final code */

+}

+

+

+#if 0

+/*

+ * ip_check_options - check that any IP-related options are OK,

+ * and assign appropriate defaults.

+ */

+static void

+ip_check_options(u_long localAddr)

+{

+  ipcp_options *wo = &ipcp_wantoptions[0];

+

+  /*

+   * Load our default IP address but allow the remote host to give us

+   * a new address.

+   */

+  if (wo->ouraddr == 0 && !ppp_settings.disable_defaultip) {

+    wo->accept_local = 1;  /* don't insist on this default value */

+    wo->ouraddr = htonl(localAddr);

+  }

+}

+#endif

+

+

+/*

+ * ipcp_up - IPCP has come UP.

+ *

+ * Configure the IP network interface appropriately and bring it up.

+ */

+static void

+ipcp_up(fsm *f)

+{

+  u32_t mask;

+  ipcp_options *ho = &ipcp_hisoptions[f->unit];

+  ipcp_options *go = &ipcp_gotoptions[f->unit];

+  ipcp_options *wo = &ipcp_wantoptions[f->unit];

+

+  np_up(f->unit, PPP_IP);

+  IPCPDEBUG((LOG_INFO, "ipcp: up\n"));

+

+  /*

+   * We must have a non-zero IP address for both ends of the link.

+   */

+  if (!ho->neg_addr) {

+    ho->hisaddr = wo->hisaddr;

+  }

+

+  if (ho->hisaddr == 0) {

+    IPCPDEBUG((LOG_ERR, "Could not determine remote IP address\n"));

+    ipcp_close(f->unit, "Could not determine remote IP address");

+    return;

+  }

+  if (go->ouraddr == 0) {

+    IPCPDEBUG((LOG_ERR, "Could not determine local IP address\n"));

+    ipcp_close(f->unit, "Could not determine local IP address");

+    return;

+  }

+

+  if (ppp_settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) {

+    /*pppGotDNSAddrs(go->dnsaddr[0], go->dnsaddr[1]);*/

+  }

+

+  /*

+   * Check that the peer is allowed to use the IP address it wants.

+   */

+  if (!auth_ip_addr(f->unit, ho->hisaddr)) {

+    IPCPDEBUG((LOG_ERR, "Peer is not authorized to use remote address %s\n",

+        inet_ntoa(ho->hisaddr)));

+    ipcp_close(f->unit, "Unauthorized remote IP address");

+    return;

+  }

+

+  /* set tcp compression */

+  sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);

+

+  /*

+   * Set IP addresses and (if specified) netmask.

+   */

+  mask = GetMask(go->ouraddr);

+

+  if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask, go->dnsaddr[0], go->dnsaddr[1])) {

+    IPCPDEBUG((LOG_WARNING, "sifaddr failed\n"));

+    ipcp_close(f->unit, "Interface configuration failed");

+    return;

+  }

+

+  /* bring the interface up for IP */

+  if (!sifup(f->unit)) {

+    IPCPDEBUG((LOG_WARNING, "sifup failed\n"));

+    ipcp_close(f->unit, "Interface configuration failed");

+    return;

+  }

+

+  sifnpmode(f->unit, PPP_IP, NPMODE_PASS);

+

+  /* assign a default route through the interface if required */

+  if (ipcp_wantoptions[f->unit].default_route) {

+    if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) {

+      default_route_set[f->unit] = 1;

+    }

+  }

+

+  IPCPDEBUG((LOG_NOTICE, "local  IP address %s\n", inet_ntoa(go->ouraddr)));

+  IPCPDEBUG((LOG_NOTICE, "remote IP address %s\n", inet_ntoa(ho->hisaddr)));

+  if (go->dnsaddr[0]) {

+    IPCPDEBUG((LOG_NOTICE, "primary   DNS address %s\n", inet_ntoa(go->dnsaddr[0])));

+  }

+  if (go->dnsaddr[1]) {

+    IPCPDEBUG((LOG_NOTICE, "secondary DNS address %s\n", inet_ntoa(go->dnsaddr[1])));

+  }

+}

+

+

+/*

+ * ipcp_down - IPCP has gone DOWN.

+ *

+ * Take the IP network interface down, clear its addresses

+ * and delete routes through it.

+ */

+static void

+ipcp_down(fsm *f)

+{

+  IPCPDEBUG((LOG_INFO, "ipcp: down\n"));

+  np_down(f->unit, PPP_IP);

+  sifvjcomp(f->unit, 0, 0, 0);

+

+  sifdown(f->unit);

+  ipcp_clear_addrs(f->unit);

+}

+

+

+/*

+ * ipcp_clear_addrs() - clear the interface addresses, routes, etc.

+ */

+static void

+ipcp_clear_addrs(int unit)

+{

+  u32_t ouraddr, hisaddr;

+

+  ouraddr = ipcp_gotoptions[unit].ouraddr;

+  hisaddr = ipcp_hisoptions[unit].hisaddr;

+  if (default_route_set[unit]) {

+    cifdefaultroute(unit, ouraddr, hisaddr);

+    default_route_set[unit] = 0;

+  }

+  cifaddr(unit, ouraddr, hisaddr);

+}

+

+

+/*

+ * ipcp_finished - possibly shut down the lower layers.

+ */

+static void

+ipcp_finished(fsm *f)

+{

+  np_finished(f->unit, PPP_IP);

+}

+

+#if 0

+static int

+ipcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)

+{

+  LWIP_UNUSED_ARG(p);

+  LWIP_UNUSED_ARG(plen);

+  LWIP_UNUSED_ARG(printer);

+  LWIP_UNUSED_ARG(arg);

+  return 0;

+}

+

+/*

+ * ip_active_pkt - see if this IP packet is worth bringing the link up for.

+ * We don't bring the link up for IP fragments or for TCP FIN packets

+ * with no data.

+ */

+#define IP_HDRLEN   20  /* bytes */

+#define IP_OFFMASK  0x1fff

+#define IPPROTO_TCP 6

+#define TCP_HDRLEN  20

+#define TH_FIN      0x01

+

+/*

+ * We use these macros because the IP header may be at an odd address,

+ * and some compilers might use word loads to get th_off or ip_hl.

+ */

+

+#define net_short(x)    (((x)[0] << 8) + (x)[1])

+#define get_iphl(x)     (((unsigned char *)(x))[0] & 0xF)

+#define get_ipoff(x)    net_short((unsigned char *)(x) + 6)

+#define get_ipproto(x)  (((unsigned char *)(x))[9])

+#define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)

+#define get_tcpflags(x) (((unsigned char *)(x))[13])

+

+static int

+ip_active_pkt(u_char *pkt, int len)

+{

+  u_char *tcp;

+  int hlen;

+

+  len -= PPP_HDRLEN;

+  pkt += PPP_HDRLEN;

+  if (len < IP_HDRLEN) {

+    return 0;

+  }

+  if ((get_ipoff(pkt) & IP_OFFMASK) != 0) {

+    return 0;

+  }

+  if (get_ipproto(pkt) != IPPROTO_TCP) {

+    return 1;

+  }

+  hlen = get_iphl(pkt) * 4;

+  if (len < hlen + TCP_HDRLEN) {

+    return 0;

+  }

+  tcp = pkt + hlen;

+  if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) {

+    return 0;

+  }

+  return 1;

+}

+#endif

+

+#endif /* PPP_SUPPORT */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ipcp.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ipcp.h
new file mode 100644
index 0000000..80e0190
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ipcp.h
@@ -0,0 +1,124 @@
+/*****************************************************************************

+* ipcp.h -  PPP IP NCP: Internet Protocol Network Control Protocol header file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1997 Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.

+*   Original derived from BSD codes.

+*****************************************************************************/

+/*

+ * ipcp.h - IP Control Protocol definitions.

+ *

+ * Copyright (c) 1989 Carnegie Mellon University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Carnegie Mellon University.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ *

+ * $Id: ipcp.h,v 1.3 2007/12/19 20:47:23 fbernon Exp $

+ */

+

+#ifndef IPCP_H

+#define IPCP_H

+

+/*************************

+*** PUBLIC DEFINITIONS ***

+*************************/

+/*

+ * Options.

+ */

+#define CI_ADDRS            1      /* IP Addresses */

+#define CI_COMPRESSTYPE     2      /* Compression Type */

+#define CI_ADDR             3

+

+#define CI_MS_WINS1         128    /* Primary WINS value */

+#define CI_MS_DNS1          129    /* Primary DNS value */

+#define CI_MS_WINS2         130    /* Secondary WINS value */

+#define CI_MS_DNS2          131    /* Secondary DNS value */

+

+#define IPCP_VJMODE_OLD     1      /* "old" mode (option # = 0x0037) */

+#define IPCP_VJMODE_RFC1172 2      /* "old-rfc"mode (option # = 0x002d) */

+#define IPCP_VJMODE_RFC1332 3      /* "new-rfc"mode (option # = 0x002d, */

+                                   /*  maxslot and slot number compression) */

+

+#define IPCP_VJ_COMP        0x002d /* current value for VJ compression option */

+#define IPCP_VJ_COMP_OLD    0x0037 /* "old" (i.e, broken) value for VJ */

+                                   /* compression option */ 

+

+

+/************************

+*** PUBLIC DATA TYPES ***

+************************/

+

+typedef struct ipcp_options {

+  u_int   neg_addr      : 1; /* Negotiate IP Address? */

+  u_int   old_addrs     : 1; /* Use old (IP-Addresses) option? */

+  u_int   req_addr      : 1; /* Ask peer to send IP address? */

+  u_int   default_route : 1; /* Assign default route through interface? */

+  u_int   proxy_arp     : 1; /* Make proxy ARP entry for peer? */

+  u_int   neg_vj        : 1; /* Van Jacobson Compression? */

+  u_int   old_vj        : 1; /* use old (short) form of VJ option? */

+  u_int   accept_local  : 1; /* accept peer's value for ouraddr */

+  u_int   accept_remote : 1; /* accept peer's value for hisaddr */

+  u_int   req_dns1      : 1; /* Ask peer to send primary DNS address? */

+  u_int   req_dns2      : 1; /* Ask peer to send secondary DNS address? */

+  u_short vj_protocol;       /* protocol value to use in VJ option */

+  u_char  maxslotindex;      /* VJ slots - 1. */

+  u_char  cflag;             /* VJ slot compression flag. */

+  u32_t   ouraddr, hisaddr;  /* Addresses in NETWORK BYTE ORDER */

+  u32_t   dnsaddr[2];        /* Primary and secondary MS DNS entries */

+  u32_t   winsaddr[2];       /* Primary and secondary MS WINS entries */

+} ipcp_options;

+

+

+/*****************************

+*** PUBLIC DATA STRUCTURES ***

+*****************************/

+

+extern fsm ipcp_fsm[];

+extern ipcp_options ipcp_wantoptions[];

+extern ipcp_options ipcp_gotoptions[];

+extern ipcp_options ipcp_allowoptions[];

+extern ipcp_options ipcp_hisoptions[];

+

+extern struct protent ipcp_protent;

+

+

+/***********************

+*** PUBLIC FUNCTIONS ***

+***********************/

+

+#endif /* IPCP_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/lcp.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/lcp.c
new file mode 100644
index 0000000..f8af228
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/lcp.c
@@ -0,0 +1,2035 @@
+/*****************************************************************************

+* lcp.c - Network Link Control Protocol program file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1997 by Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.

+*   Original.

+*****************************************************************************/

+

+/*

+ * lcp.c - PPP Link Control Protocol.

+ *

+ * Copyright (c) 1989 Carnegie Mellon University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Carnegie Mellon University.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ */

+ 

+

+#include "lwip/opt.h"

+

+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#include "ppp.h"

+#include "pppdebug.h"

+

+#include "fsm.h"

+#include "chap.h"

+#include "magic.h"

+#include "auth.h"

+#include "lcp.h"

+

+#include <string.h>

+

+#if PPPOE_SUPPORT

+#include "netif/ppp_oe.h"

+#else

+#define PPPOE_MAXMTU PPP_MAXMRU

+#endif

+

+

+/*************************/

+/*** LOCAL DEFINITIONS ***/

+/*************************/

+/*

+ * Length of each type of configuration option (in octets)

+ */

+#define CILEN_VOID  2

+#define CILEN_CHAR  3

+#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */

+#define CILEN_CHAP  5 /* CILEN_VOID + sizeof(short) + 1 */

+#define CILEN_LONG  6 /* CILEN_VOID + sizeof(long) */

+#define CILEN_LQR   8 /* CILEN_VOID + sizeof(short) + sizeof(long) */

+#define CILEN_CBCP  3

+

+

+/***********************************/

+/*** LOCAL FUNCTION DECLARATIONS ***/

+/***********************************/

+/*

+ * Callbacks for fsm code.  (CI = Configuration Information)

+ */

+static void lcp_resetci (fsm*);                   /* Reset our CI */

+static int  lcp_cilen (fsm*);                     /* Return length of our CI */

+static void lcp_addci (fsm*, u_char*, int*);      /* Add our CI to pkt */

+static int  lcp_ackci (fsm*, u_char*, int);       /* Peer ack'd our CI */

+static int  lcp_nakci (fsm*, u_char*, int);       /* Peer nak'd our CI */

+static int  lcp_rejci (fsm*, u_char*, int);       /* Peer rej'd our CI */

+static int  lcp_reqci (fsm*, u_char*, int*, int); /* Rcv peer CI */

+static void lcp_up (fsm*);                        /* We're UP */

+static void lcp_down (fsm*);                      /* We're DOWN */

+static void lcp_starting (fsm*);                  /* We need lower layer up */

+static void lcp_finished (fsm*);                  /* We need lower layer down */

+static int  lcp_extcode (fsm*, int, u_char, u_char*, int);

+

+static void lcp_rprotrej (fsm*, u_char*, int);

+

+/*

+ * routines to send LCP echos to peer

+ */

+static void lcp_echo_lowerup (int);

+static void lcp_echo_lowerdown (int);

+static void LcpEchoTimeout (void*);

+static void lcp_received_echo_reply (fsm*, int, u_char*, int);

+static void LcpSendEchoRequest (fsm*);

+static void LcpLinkFailure (fsm*);

+static void LcpEchoCheck (fsm*);

+

+/*

+ * Protocol entry points.

+ * Some of these are called directly.

+ */

+static void lcp_input (int, u_char *, int);

+static void lcp_protrej (int);

+

+#define CODENAME(x) ((x) == CONFACK ? "ACK" : (x) == CONFNAK ? "NAK" : "REJ")

+

+

+/******************************/

+/*** PUBLIC DATA STRUCTURES ***/

+/******************************/

+/* global vars */

+LinkPhase lcp_phase[NUM_PPP];          /* Phase of link session (RFC 1661) */

+lcp_options lcp_wantoptions[NUM_PPP];  /* Options that we want to request */

+lcp_options lcp_gotoptions[NUM_PPP];   /* Options that peer ack'd */

+lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */

+lcp_options lcp_hisoptions[NUM_PPP];   /* Options that we ack'd */

+ext_accm xmit_accm[NUM_PPP];           /* extended transmit ACCM */

+

+

+

+/*****************************/

+/*** LOCAL DATA STRUCTURES ***/

+/*****************************/

+static fsm lcp_fsm[NUM_PPP];                            /* LCP fsm structure (global)*/

+static u_int lcp_echo_interval      = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */

+static u_int lcp_echo_fails         = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */

+static u32_t lcp_echos_pending      = 0;                /* Number of outstanding echo msgs */

+static u32_t lcp_echo_number        = 0;                /* ID number of next echo frame */

+static u32_t lcp_echo_timer_running = 0;                /* TRUE if a timer is running */

+

+static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */

+

+static fsm_callbacks lcp_callbacks = { /* LCP callback routines */

+  lcp_resetci,  /* Reset our Configuration Information */

+  lcp_cilen,    /* Length of our Configuration Information */

+  lcp_addci,    /* Add our Configuration Information */

+  lcp_ackci,    /* ACK our Configuration Information */

+  lcp_nakci,    /* NAK our Configuration Information */

+  lcp_rejci,    /* Reject our Configuration Information */

+  lcp_reqci,    /* Request peer's Configuration Information */

+  lcp_up,       /* Called when fsm reaches LS_OPENED state */

+  lcp_down,     /* Called when fsm leaves LS_OPENED state */

+  lcp_starting, /* Called when we want the lower layer up */

+  lcp_finished, /* Called when we want the lower layer down */

+  NULL,         /* Called when Protocol-Reject received */

+  NULL,         /* Retransmission is necessary */

+  lcp_extcode,  /* Called to handle LCP-specific codes */

+  "LCP"         /* String name of protocol */

+};

+

+struct protent lcp_protent = {

+    PPP_LCP,

+    lcp_init,

+    lcp_input,

+    lcp_protrej,

+    lcp_lowerup,

+    lcp_lowerdown,

+    lcp_open,

+    lcp_close,

+#if 0

+    lcp_printpkt,

+    NULL,

+#endif

+    1,

+    "LCP",

+#if 0

+    NULL,

+    NULL,

+    NULL

+#endif

+};

+

+int lcp_loopbackfail = DEFLOOPBACKFAIL;

+

+

+

+/***********************************/

+/*** PUBLIC FUNCTION DEFINITIONS ***/

+/***********************************/

+/*

+ * lcp_init - Initialize LCP.

+ */

+void

+lcp_init(int unit)

+{

+  fsm         *f  = &lcp_fsm[unit];

+  lcp_options *wo = &lcp_wantoptions[unit];

+  lcp_options *ao = &lcp_allowoptions[unit];

+  

+  f->unit      = unit;

+  f->protocol  = PPP_LCP;

+  f->callbacks = &lcp_callbacks;

+  

+  fsm_init(f);

+  

+  wo->passive           = 0;

+  wo->silent            = 0;

+  wo->restart           = 0;               /* Set to 1 in kernels or multi-line implementations */

+  wo->neg_mru           = 1;

+  wo->mru               = PPP_DEFMRU;

+  wo->neg_asyncmap      = 1;

+  wo->asyncmap          = 0x00000000l;     /* Assume don't need to escape any ctl chars. */

+  wo->neg_chap          = 0;               /* Set to 1 on server */

+  wo->neg_upap          = 0;               /* Set to 1 on server */

+  wo->chap_mdtype       = CHAP_DIGEST_MD5;

+  wo->neg_magicnumber   = 1;

+  wo->neg_pcompression  = 1;

+  wo->neg_accompression = 1;

+  wo->neg_lqr           = 0;               /* no LQR implementation yet */

+  wo->neg_cbcp          = 0;

+  

+  ao->neg_mru           = 1;

+  ao->mru               = PPP_MAXMRU;

+  ao->neg_asyncmap      = 1;

+  ao->asyncmap          = 0x00000000l;     /* Assume don't need to escape any ctl chars. */

+  ao->neg_chap          = (CHAP_SUPPORT != 0);

+  ao->chap_mdtype       = CHAP_DIGEST_MD5;

+  ao->neg_upap          = (PAP_SUPPORT != 0);

+  ao->neg_magicnumber   = 1;

+  ao->neg_pcompression  = 1;

+  ao->neg_accompression = 1;

+  ao->neg_lqr           = 0;               /* no LQR implementation yet */

+  ao->neg_cbcp          = (CBCP_SUPPORT != 0);

+

+  /* 

+   * Set transmit escape for the flag and escape characters plus anything

+   * set for the allowable options.

+   */

+  memset(xmit_accm[unit], 0, sizeof(xmit_accm[0]));

+  xmit_accm[unit][15] = 0x60;

+  xmit_accm[unit][0]  = (u_char)((ao->asyncmap        & 0xFF));

+  xmit_accm[unit][1]  = (u_char)((ao->asyncmap >> 8)  & 0xFF);

+  xmit_accm[unit][2]  = (u_char)((ao->asyncmap >> 16) & 0xFF);

+  xmit_accm[unit][3]  = (u_char)((ao->asyncmap >> 24) & 0xFF);

+  LCPDEBUG((LOG_INFO, "lcp_init: xmit_accm=%X %X %X %X\n",

+        xmit_accm[unit][0],

+        xmit_accm[unit][1],

+        xmit_accm[unit][2],

+        xmit_accm[unit][3]));

+  

+  lcp_phase[unit] = PHASE_INITIALIZE;

+}

+

+

+/*

+ * lcp_open - LCP is allowed to come up.

+ */

+void

+lcp_open(int unit)

+{

+  fsm         *f  = &lcp_fsm[unit];

+  lcp_options *wo = &lcp_wantoptions[unit];

+

+  f->flags = 0;

+  if (wo->passive) {

+    f->flags |= OPT_PASSIVE;

+  }

+  if (wo->silent) {

+    f->flags |= OPT_SILENT;

+  }

+  fsm_open(f);

+

+  lcp_phase[unit] = PHASE_ESTABLISH;

+}

+

+

+/*

+ * lcp_close - Take LCP down.

+ */

+void

+lcp_close(int unit, char *reason)

+{

+  fsm *f = &lcp_fsm[unit];

+

+  if (lcp_phase[unit] != PHASE_DEAD) {

+    lcp_phase[unit] = PHASE_TERMINATE;

+  }

+  if (f->state == LS_STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) {

+    /*

+     * This action is not strictly according to the FSM in RFC1548,

+     * but it does mean that the program terminates if you do an

+     * lcp_close() in passive/silent mode when a connection hasn't

+     * been established.

+     */

+    f->state = LS_CLOSED;

+    lcp_finished(f);

+  } else {

+    fsm_close(&lcp_fsm[unit], reason);

+  }

+}

+

+

+/*

+ * lcp_lowerup - The lower layer is up.

+ */

+void

+lcp_lowerup(int unit)

+{

+  lcp_options *wo = &lcp_wantoptions[unit];

+

+  /*

+   * Don't use A/C or protocol compression on transmission,

+   * but accept A/C and protocol compressed packets

+   * if we are going to ask for A/C and protocol compression.

+   */

+  ppp_set_xaccm(unit, &xmit_accm[unit]);

+  ppp_send_config(unit, PPP_MRU, 0xffffffffl, 0, 0);

+  ppp_recv_config(unit, PPP_MRU, 0x00000000l,

+  wo->neg_pcompression, wo->neg_accompression);

+  peer_mru[unit] = PPP_MRU;

+  lcp_allowoptions[unit].asyncmap = (u_long)xmit_accm[unit][0]

+                                 | ((u_long)xmit_accm[unit][1] << 8)

+                                 | ((u_long)xmit_accm[unit][2] << 16)

+                                 | ((u_long)xmit_accm[unit][3] << 24);

+  LCPDEBUG((LOG_INFO, "lcp_lowerup: asyncmap=%X %X %X %X\n",

+            xmit_accm[unit][3],

+            xmit_accm[unit][2],

+            xmit_accm[unit][1],

+            xmit_accm[unit][0]));

+

+  fsm_lowerup(&lcp_fsm[unit]);

+}

+

+

+/*

+ * lcp_lowerdown - The lower layer is down.

+ */

+void

+lcp_lowerdown(int unit)

+{

+  fsm_lowerdown(&lcp_fsm[unit]);

+}

+

+/*

+ * lcp_sprotrej - Send a Protocol-Reject for some protocol.

+ */

+void

+lcp_sprotrej(int unit, u_char *p, int len)

+{

+  /*

+   * Send back the protocol and the information field of the

+   * rejected packet.  We only get here if LCP is in the LS_OPENED state.

+   */

+

+  fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id, p, len);

+}

+

+

+

+/**********************************/

+/*** LOCAL FUNCTION DEFINITIONS ***/

+/**********************************/

+/*

+ * lcp_input - Input LCP packet.

+ */

+static void

+lcp_input(int unit, u_char *p, int len)

+{

+  fsm *f = &lcp_fsm[unit];

+

+  fsm_input(f, p, len);

+}

+

+

+/*

+ * lcp_extcode - Handle a LCP-specific code.

+ */

+static int

+lcp_extcode(fsm *f, int code, u_char id, u_char *inp, int len)

+{

+  u_char *magp;

+

+  switch( code ){

+    case PROTREJ:

+      lcp_rprotrej(f, inp, len);

+      break;

+  

+    case ECHOREQ:

+      if (f->state != LS_OPENED) {

+        break;

+      }

+      LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d\n", id));

+      magp = inp;

+      PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp);

+      fsm_sdata(f, ECHOREP, id, inp, len);

+      break;

+

+    case ECHOREP:

+      lcp_received_echo_reply(f, id, inp, len);

+      break;

+    

+    case DISCREQ:

+      break;

+    

+    default:

+      return 0;

+  }

+  return 1;

+}

+

+

+/*

+ * lcp_rprotrej - Receive an Protocol-Reject.

+ *

+ * Figure out which protocol is rejected and inform it.

+ */

+static void

+lcp_rprotrej(fsm *f, u_char *inp, int len)

+{

+  int i;

+  struct protent *protp;

+  u_short prot;

+

+  if (len < sizeof (u_short)) {

+    LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd short Protocol-Reject packet!\n"));

+    return;

+  }

+

+  GETSHORT(prot, inp);

+

+  LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!\n", prot));

+

+  /*

+   * Protocol-Reject packets received in any state other than the LCP

+   * LS_OPENED state SHOULD be silently discarded.

+   */

+  if( f->state != LS_OPENED ) {

+    LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d\n", f->state));

+    return;

+  }

+

+  /*

+   * Upcall the proper Protocol-Reject routine.

+   */

+  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {

+    if (protp->protocol == prot && protp->enabled_flag) {

+      (*protp->protrej)(f->unit);

+      return;

+    }

+  }

+

+  LCPDEBUG((LOG_WARNING, "Protocol-Reject for unsupported protocol 0x%x\n", prot));

+}

+

+

+/*

+ * lcp_protrej - A Protocol-Reject was received.

+ */

+static void

+lcp_protrej(int unit)

+{

+  LWIP_UNUSED_ARG(unit);

+  /*

+   * Can't reject LCP!

+   */

+  LCPDEBUG((LOG_WARNING, "lcp_protrej: Received Protocol-Reject for LCP!\n"));

+  fsm_protreject(&lcp_fsm[unit]);

+}

+

+

+/*

+ * lcp_resetci - Reset our CI.

+ */

+static void

+lcp_resetci(fsm *f)

+{

+  lcp_wantoptions[f->unit].magicnumber = magic();

+  lcp_wantoptions[f->unit].numloops = 0;

+  lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit];

+  peer_mru[f->unit] = PPP_MRU;

+  auth_reset(f->unit);

+}

+

+

+/*

+ * lcp_cilen - Return length of our CI.

+ */

+static int lcp_cilen(fsm *f)

+{

+  lcp_options *go = &lcp_gotoptions[f->unit];

+

+#define LENCIVOID(neg)  ((neg) ? CILEN_VOID : 0)

+#define LENCICHAP(neg)  ((neg) ? CILEN_CHAP : 0)

+#define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0)

+#define LENCILONG(neg)  ((neg) ? CILEN_LONG : 0)

+#define LENCILQR(neg)   ((neg) ? CILEN_LQR: 0)

+#define LENCICBCP(neg)  ((neg) ? CILEN_CBCP: 0)

+  /*

+   * NB: we only ask for one of CHAP and UPAP, even if we will

+   * accept either.

+   */

+  return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) +

+          LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) +

+          LENCICHAP(go->neg_chap) +

+          LENCISHORT(!go->neg_chap && go->neg_upap) +

+          LENCILQR(go->neg_lqr) +

+          LENCICBCP(go->neg_cbcp) +

+          LENCILONG(go->neg_magicnumber) +

+          LENCIVOID(go->neg_pcompression) +

+          LENCIVOID(go->neg_accompression));

+}

+

+

+/*

+ * lcp_addci - Add our desired CIs to a packet.

+ */

+static void

+lcp_addci(fsm *f, u_char *ucp, int *lenp)

+{

+  lcp_options *go = &lcp_gotoptions[f->unit];

+  u_char *start_ucp = ucp;

+

+#define ADDCIVOID(opt, neg) \

+  if (neg) { \

+    LCPDEBUG((LOG_INFO, "lcp_addci: opt=%d\n", opt)); \

+    PUTCHAR(opt, ucp); \

+    PUTCHAR(CILEN_VOID, ucp); \

+  }

+#define ADDCISHORT(opt, neg, val) \

+  if (neg) { \

+    LCPDEBUG((LOG_INFO, "lcp_addci: INT opt=%d %X\n", opt, val)); \

+    PUTCHAR(opt, ucp); \

+    PUTCHAR(CILEN_SHORT, ucp); \

+    PUTSHORT(val, ucp); \

+  }

+#define ADDCICHAP(opt, neg, val, digest) \

+  if (neg) { \

+    LCPDEBUG((LOG_INFO, "lcp_addci: CHAP opt=%d %X\n", opt, val)); \

+    PUTCHAR(opt, ucp); \

+    PUTCHAR(CILEN_CHAP, ucp); \

+    PUTSHORT(val, ucp); \

+    PUTCHAR(digest, ucp); \

+  }

+#define ADDCILONG(opt, neg, val) \

+  if (neg) { \

+    LCPDEBUG((LOG_INFO, "lcp_addci: L opt=%d %lX\n", opt, val)); \

+    PUTCHAR(opt, ucp); \

+    PUTCHAR(CILEN_LONG, ucp); \

+    PUTLONG(val, ucp); \

+  }

+#define ADDCILQR(opt, neg, val) \

+  if (neg) { \

+    LCPDEBUG((LOG_INFO, "lcp_addci: LQR opt=%d %lX\n", opt, val)); \

+    PUTCHAR(opt, ucp); \

+    PUTCHAR(CILEN_LQR, ucp); \

+    PUTSHORT(PPP_LQR, ucp); \

+    PUTLONG(val, ucp); \

+  }

+#define ADDCICHAR(opt, neg, val) \

+  if (neg) { \

+    LCPDEBUG((LOG_INFO, "lcp_addci: CHAR opt=%d %X '%z'\n", opt, val, val)); \

+    PUTCHAR(opt, ucp); \

+    PUTCHAR(CILEN_CHAR, ucp); \

+    PUTCHAR(val, ucp); \

+  }

+

+  ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);

+  ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap);

+  ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);

+  ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);

+  ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);

+  ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);

+  ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);

+  ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);

+  ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);

+

+  if (ucp - start_ucp != *lenp) {

+    /* this should never happen, because peer_mtu should be 1500 */

+    LCPDEBUG((LOG_ERR, "Bug in lcp_addci: wrong length\n"));

+  }

+}

+

+

+/*

+ * lcp_ackci - Ack our CIs.

+ * This should not modify any state if the Ack is bad.

+ *

+ * Returns:

+ *  0 - Ack was bad.

+ *  1 - Ack was good.

+ */

+static int

+lcp_ackci(fsm *f, u_char *p, int len)

+{

+  lcp_options *go = &lcp_gotoptions[f->unit];

+  u_char cilen, citype, cichar;

+  u_short cishort;

+  u32_t cilong;

+

+  /*

+   * CIs must be in exactly the same order that we sent.

+   * Check packet length and CI length at each step.

+   * If we find any deviations, then this packet is bad.

+   */

+#define ACKCIVOID(opt, neg) \

+  if (neg) { \

+    if ((len -= CILEN_VOID) < 0) \

+      goto bad; \

+    GETCHAR(citype, p); \

+    GETCHAR(cilen, p); \

+    if (cilen != CILEN_VOID || citype != opt) \

+      goto bad; \

+  }

+#define ACKCISHORT(opt, neg, val) \

+  if (neg) { \

+    if ((len -= CILEN_SHORT) < 0) \

+      goto bad; \

+    GETCHAR(citype, p); \

+    GETCHAR(cilen, p); \

+    if (cilen != CILEN_SHORT || citype != opt) \

+      goto bad; \

+    GETSHORT(cishort, p); \

+    if (cishort != val) \

+      goto bad; \

+  }

+#define ACKCICHAR(opt, neg, val) \

+  if (neg) { \

+    if ((len -= CILEN_CHAR) < 0) \

+      goto bad; \

+    GETCHAR(citype, p); \

+    GETCHAR(cilen, p); \

+    if (cilen != CILEN_CHAR || citype != opt) \

+      goto bad; \

+    GETCHAR(cichar, p); \

+    if (cichar != val) \

+      goto bad; \

+  }

+#define ACKCICHAP(opt, neg, val, digest) \

+  if (neg) { \

+    if ((len -= CILEN_CHAP) < 0) \

+      goto bad; \

+    GETCHAR(citype, p); \

+    GETCHAR(cilen, p); \

+    if (cilen != CILEN_CHAP || citype != opt) \

+      goto bad; \

+    GETSHORT(cishort, p); \

+    if (cishort != val) \

+      goto bad; \

+    GETCHAR(cichar, p); \

+    if (cichar != digest) \

+      goto bad; \

+  }

+#define ACKCILONG(opt, neg, val) \

+  if (neg) { \

+    if ((len -= CILEN_LONG) < 0) \

+      goto bad; \

+    GETCHAR(citype, p); \

+    GETCHAR(cilen, p); \

+    if (cilen != CILEN_LONG ||  citype != opt) \

+      goto bad; \

+    GETLONG(cilong, p); \

+    if (cilong != val) \

+      goto bad; \

+  }

+#define ACKCILQR(opt, neg, val) \

+  if (neg) { \

+    if ((len -= CILEN_LQR) < 0) \

+      goto bad; \

+    GETCHAR(citype, p); \

+    GETCHAR(cilen, p); \

+    if (cilen != CILEN_LQR || citype != opt) \

+      goto bad; \

+    GETSHORT(cishort, p); \

+    if (cishort != PPP_LQR) \

+      goto bad; \

+    GETLONG(cilong, p); \

+    if (cilong != val) \

+      goto bad; \

+  }

+

+  ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);

+  ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap);

+  ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);

+  ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);

+  ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);

+  ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);

+  ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);

+  ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);

+  ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);

+

+  /*

+   * If there are any remaining CIs, then this packet is bad.

+   */

+  if (len != 0) {

+    goto bad;

+  }

+  LCPDEBUG((LOG_INFO, "lcp_acki: Ack\n"));

+  return (1);

+bad:

+  LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!\n"));

+  return (0);

+}

+

+

+/*

+ * lcp_nakci - Peer has sent a NAK for some of our CIs.

+ * This should not modify any state if the Nak is bad

+ * or if LCP is in the LS_OPENED state.

+ *

+ * Returns:

+ *  0 - Nak was bad.

+ *  1 - Nak was good.

+ */

+static int

+lcp_nakci(fsm *f, u_char *p, int len)

+{

+  lcp_options *go = &lcp_gotoptions[f->unit];

+  lcp_options *wo = &lcp_wantoptions[f->unit];

+  u_char citype, cichar, *next;

+  u_short cishort;

+  u32_t cilong;

+  lcp_options no;     /* options we've seen Naks for */

+  lcp_options try;    /* options to request next time */

+  int looped_back = 0;

+  int cilen;

+

+  BZERO(&no, sizeof(no));

+  try = *go;

+

+  /*

+   * Any Nak'd CIs must be in exactly the same order that we sent.

+   * Check packet length and CI length at each step.

+   * If we find any deviations, then this packet is bad.

+   */

+#define NAKCIVOID(opt, neg, code) \

+  if (go->neg && \

+      len >= CILEN_VOID && \

+      p[1] == CILEN_VOID && \

+      p[0] == opt) { \

+    len -= CILEN_VOID; \

+    INCPTR(CILEN_VOID, p); \

+    no.neg = 1; \

+    code \

+  }

+#define NAKCICHAP(opt, neg, code) \

+  if (go->neg && \

+      len >= CILEN_CHAP && \

+      p[1] == CILEN_CHAP && \

+      p[0] == opt) { \

+    len -= CILEN_CHAP; \

+    INCPTR(2, p); \

+    GETSHORT(cishort, p); \

+    GETCHAR(cichar, p); \

+    no.neg = 1; \

+    code \

+  }

+#define NAKCICHAR(opt, neg, code) \

+  if (go->neg && \

+      len >= CILEN_CHAR && \

+      p[1] == CILEN_CHAR && \

+      p[0] == opt) { \

+    len -= CILEN_CHAR; \

+    INCPTR(2, p); \

+    GETCHAR(cichar, p); \

+    no.neg = 1; \

+    code \

+  }

+#define NAKCISHORT(opt, neg, code) \

+  if (go->neg && \

+      len >= CILEN_SHORT && \

+      p[1] == CILEN_SHORT && \

+      p[0] == opt) { \

+    len -= CILEN_SHORT; \

+    INCPTR(2, p); \

+    GETSHORT(cishort, p); \

+    no.neg = 1; \

+    code \

+  }

+#define NAKCILONG(opt, neg, code) \

+  if (go->neg && \

+      len >= CILEN_LONG && \

+      p[1] == CILEN_LONG && \

+      p[0] == opt) { \

+    len -= CILEN_LONG; \

+    INCPTR(2, p); \

+    GETLONG(cilong, p); \

+    no.neg = 1; \

+    code \

+  }

+#define NAKCILQR(opt, neg, code) \

+  if (go->neg && \

+      len >= CILEN_LQR && \

+      p[1] == CILEN_LQR && \

+      p[0] == opt) { \

+    len -= CILEN_LQR; \

+    INCPTR(2, p); \

+    GETSHORT(cishort, p); \

+    GETLONG(cilong, p); \

+    no.neg = 1; \

+    code \

+  }

+

+  /*

+   * We don't care if they want to send us smaller packets than

+   * we want.  Therefore, accept any MRU less than what we asked for,

+   * but then ignore the new value when setting the MRU in the kernel.

+   * If they send us a bigger MRU than what we asked, accept it, up to

+   * the limit of the default MRU we'd get if we didn't negotiate.

+   */

+  if (go->neg_mru && go->mru != PPP_DEFMRU) {

+    NAKCISHORT(CI_MRU, neg_mru,

+      if (cishort <= wo->mru || cishort < PPP_DEFMRU) {

+        try.mru = cishort;

+      }

+    );

+  }

+

+  /*

+   * Add any characters they want to our (receive-side) asyncmap.

+   */

+  if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) {

+    NAKCILONG(CI_ASYNCMAP, neg_asyncmap,

+      try.asyncmap = go->asyncmap | cilong;

+    );

+  }

+

+  /*

+   * If they've nak'd our authentication-protocol, check whether

+   * they are proposing a different protocol, or a different

+   * hash algorithm for CHAP.

+   */

+  if ((go->neg_chap || go->neg_upap)

+      && len >= CILEN_SHORT

+      && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {

+    cilen = p[1];

+    len -= cilen;

+    no.neg_chap = go->neg_chap;

+    no.neg_upap = go->neg_upap;

+    INCPTR(2, p);

+    GETSHORT(cishort, p);

+    if (cishort == PPP_PAP && cilen == CILEN_SHORT) {

+      /*

+       * If we were asking for CHAP, they obviously don't want to do it.

+       * If we weren't asking for CHAP, then we were asking for PAP,

+       * in which case this Nak is bad.

+       */

+      if (!go->neg_chap) {

+        goto bad;

+      }

+      try.neg_chap = 0;

+    

+    } else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {

+      GETCHAR(cichar, p);

+      if (go->neg_chap) {

+        /*

+         * We were asking for CHAP/MD5; they must want a different

+         * algorithm.  If they can't do MD5, we'll have to stop

+         * asking for CHAP.

+         */

+        if (cichar != go->chap_mdtype) {

+          try.neg_chap = 0;

+        }

+      } else {

+        /*

+         * Stop asking for PAP if we were asking for it.

+         */

+        try.neg_upap = 0;

+      }

+    

+    } else {

+      /*

+       * We don't recognize what they're suggesting.

+       * Stop asking for what we were asking for.

+       */

+      if (go->neg_chap) {

+        try.neg_chap = 0;

+      } else {

+        try.neg_upap = 0;

+      }

+      p += cilen - CILEN_SHORT;

+    }

+  }

+

+  /*

+   * If they can't cope with our link quality protocol, we'll have

+   * to stop asking for LQR.  We haven't got any other protocol.

+   * If they Nak the reporting period, take their value XXX ?

+   */

+  NAKCILQR(CI_QUALITY, neg_lqr,

+    if (cishort != PPP_LQR) {

+      try.neg_lqr = 0;

+    } else {

+      try.lqr_period = cilong;

+    }

+  );

+

+  /*

+   * Only implementing CBCP...not the rest of the callback options

+   */

+  NAKCICHAR(CI_CALLBACK, neg_cbcp,

+    try.neg_cbcp = 0;

+  );

+

+  /*

+   * Check for a looped-back line.

+   */

+  NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,

+    try.magicnumber = magic();

+    looped_back = 1;

+  );

+

+  /*

+   * Peer shouldn't send Nak for protocol compression or

+   * address/control compression requests; they should send

+   * a Reject instead.  If they send a Nak, treat it as a Reject.

+   */

+  NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,

+    try.neg_pcompression = 0;

+  );

+  NAKCIVOID(CI_ACCOMPRESSION, neg_accompression,

+    try.neg_accompression = 0;

+  );

+

+  /*

+   * There may be remaining CIs, if the peer is requesting negotiation

+   * on an option that we didn't include in our request packet.

+   * If we see an option that we requested, or one we've already seen

+   * in this packet, then this packet is bad.

+   * If we wanted to respond by starting to negotiate on the requested

+   * option(s), we could, but we don't, because except for the

+   * authentication type and quality protocol, if we are not negotiating

+   * an option, it is because we were told not to.

+   * For the authentication type, the Nak from the peer means

+   * `let me authenticate myself with you' which is a bit pointless.

+   * For the quality protocol, the Nak means `ask me to send you quality

+   * reports', but if we didn't ask for them, we don't want them.

+   * An option we don't recognize represents the peer asking to

+   * negotiate some option we don't support, so ignore it.

+   */

+  while (len > CILEN_VOID) {

+    GETCHAR(citype, p);

+    GETCHAR(cilen, p);

+    if (cilen < CILEN_VOID || (len -= cilen) < 0) {

+      goto bad;

+    }

+    next = p + cilen - 2;

+

+    switch (citype) {

+      case CI_MRU:

+        if ((go->neg_mru && go->mru != PPP_DEFMRU)

+            || no.neg_mru || cilen != CILEN_SHORT) {

+          goto bad;

+        }

+        GETSHORT(cishort, p);

+        if (cishort < PPP_DEFMRU) {

+          try.mru = cishort;

+        }

+        break;

+      case CI_ASYNCMAP:

+        if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl)

+            || no.neg_asyncmap || cilen != CILEN_LONG) {

+          goto bad;

+        }

+        break;

+      case CI_AUTHTYPE:

+        if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap) {

+          goto bad;

+        }

+        break;

+      case CI_MAGICNUMBER:

+        if (go->neg_magicnumber || no.neg_magicnumber ||

+            cilen != CILEN_LONG) {

+          goto bad;

+        }

+        break;

+      case CI_PCOMPRESSION:

+        if (go->neg_pcompression || no.neg_pcompression

+            || cilen != CILEN_VOID) {

+          goto bad;

+        }

+        break;

+      case CI_ACCOMPRESSION:

+        if (go->neg_accompression || no.neg_accompression

+            || cilen != CILEN_VOID) {

+          goto bad;

+        }

+        break;

+      case CI_QUALITY:

+        if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) {

+          goto bad;

+        }

+        break;

+    }

+    p = next;

+  }

+

+  /* If there is still anything left, this packet is bad. */

+  if (len != 0) {

+    goto bad;

+  }

+

+  /*

+  * OK, the Nak is good.  Now we can update state.

+  */

+  if (f->state != LS_OPENED) {

+    if (looped_back) {

+      if (++try.numloops >= lcp_loopbackfail) {

+        LCPDEBUG((LOG_NOTICE, "Serial line is looped back.\n"));

+        lcp_close(f->unit, "Loopback detected");

+      }

+    } else {

+      try.numloops = 0;

+    }

+    *go = try;

+  }

+

+  return 1;

+

+bad:

+  LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!\n"));

+  return 0;

+}

+

+

+/*

+ * lcp_rejci - Peer has Rejected some of our CIs.

+ * This should not modify any state if the Reject is bad

+ * or if LCP is in the LS_OPENED state.

+ *

+ * Returns:

+ *  0 - Reject was bad.

+ *  1 - Reject was good.

+ */

+static int

+lcp_rejci(fsm *f, u_char *p, int len)

+{

+  lcp_options *go = &lcp_gotoptions[f->unit];

+  u_char cichar;

+  u_short cishort;

+  u32_t cilong;

+  lcp_options try; /* options to request next time */

+

+  try = *go;

+

+  /*

+   * Any Rejected CIs must be in exactly the same order that we sent.

+   * Check packet length and CI length at each step.

+   * If we find any deviations, then this packet is bad.

+   */

+#define REJCIVOID(opt, neg) \

+  if (go->neg && \

+      len >= CILEN_VOID && \

+      p[1] == CILEN_VOID && \

+      p[0] == opt) { \

+    len -= CILEN_VOID; \

+    INCPTR(CILEN_VOID, p); \

+    try.neg = 0; \

+    LCPDEBUG((LOG_INFO, "lcp_rejci: void opt %d rejected\n", opt)); \

+  }

+#define REJCISHORT(opt, neg, val) \

+  if (go->neg && \

+      len >= CILEN_SHORT && \

+      p[1] == CILEN_SHORT && \

+      p[0] == opt) { \

+    len -= CILEN_SHORT; \

+    INCPTR(2, p); \

+    GETSHORT(cishort, p); \

+    /* Check rejected value. */ \

+    if (cishort != val) { \

+      goto bad; \

+    } \

+    try.neg = 0; \

+    LCPDEBUG((LOG_INFO,"lcp_rejci: short opt %d rejected\n", opt)); \

+  }

+#define REJCICHAP(opt, neg, val, digest) \

+  if (go->neg && \

+      len >= CILEN_CHAP && \

+      p[1] == CILEN_CHAP && \

+      p[0] == opt) { \

+    len -= CILEN_CHAP; \

+    INCPTR(2, p); \

+    GETSHORT(cishort, p); \

+    GETCHAR(cichar, p); \

+    /* Check rejected value. */ \

+    if (cishort != val || cichar != digest) { \

+      goto bad; \

+    } \

+    try.neg = 0; \

+    try.neg_upap = 0; \

+    LCPDEBUG((LOG_INFO,"lcp_rejci: chap opt %d rejected\n", opt)); \

+  }

+#define REJCILONG(opt, neg, val) \

+  if (go->neg && \

+      len >= CILEN_LONG && \

+      p[1] == CILEN_LONG && \

+      p[0] == opt) { \

+    len -= CILEN_LONG; \

+    INCPTR(2, p); \

+    GETLONG(cilong, p); \

+    /* Check rejected value. */ \

+    if (cilong != val) { \

+      goto bad; \

+    } \

+    try.neg = 0; \

+    LCPDEBUG((LOG_INFO,"lcp_rejci: long opt %d rejected\n", opt)); \

+  }

+#define REJCILQR(opt, neg, val) \

+  if (go->neg && \

+      len >= CILEN_LQR && \

+      p[1] == CILEN_LQR && \

+      p[0] == opt) { \

+    len -= CILEN_LQR; \

+    INCPTR(2, p); \

+    GETSHORT(cishort, p); \

+    GETLONG(cilong, p); \

+    /* Check rejected value. */ \

+    if (cishort != PPP_LQR || cilong != val) { \

+      goto bad; \

+    } \

+    try.neg = 0; \

+    LCPDEBUG((LOG_INFO,"lcp_rejci: LQR opt %d rejected\n", opt)); \

+  }

+#define REJCICBCP(opt, neg, val) \

+  if (go->neg && \

+      len >= CILEN_CBCP && \

+      p[1] == CILEN_CBCP && \

+      p[0] == opt) { \

+    len -= CILEN_CBCP; \

+    INCPTR(2, p); \

+    GETCHAR(cichar, p); \

+    /* Check rejected value. */ \

+    if (cichar != val) { \

+      goto bad; \

+    } \

+    try.neg = 0; \

+    LCPDEBUG((LOG_INFO,"lcp_rejci: Callback opt %d rejected\n", opt)); \

+  }

+  

+  REJCISHORT(CI_MRU, neg_mru, go->mru);

+  REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);

+  REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);

+  if (!go->neg_chap) {

+    REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);

+  }

+  REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);

+  REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);

+  REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);

+  REJCIVOID(CI_PCOMPRESSION, neg_pcompression);

+  REJCIVOID(CI_ACCOMPRESSION, neg_accompression);

+  

+  /*

+   * If there are any remaining CIs, then this packet is bad.

+   */

+  if (len != 0) {

+    goto bad;

+  }

+  /*

+   * Now we can update state.

+   */

+  if (f->state != LS_OPENED) {

+    *go = try;

+  }

+  return 1;

+  

+bad:

+  LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!\n"));

+  return 0;

+}

+

+

+/*

+ * lcp_reqci - Check the peer's requested CIs and send appropriate response.

+ *

+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified

+ * appropriately.  If reject_if_disagree is non-zero, doesn't return

+ * CONFNAK; returns CONFREJ if it can't return CONFACK.

+ */

+static int

+lcp_reqci(fsm *f, 

+          u_char *inp,    /* Requested CIs */

+          int *lenp,      /* Length of requested CIs */

+          int reject_if_disagree)

+{

+  lcp_options *go = &lcp_gotoptions[f->unit];

+  lcp_options *ho = &lcp_hisoptions[f->unit];

+  lcp_options *ao = &lcp_allowoptions[f->unit];

+  u_char *cip, *next;         /* Pointer to current and next CIs */

+  int cilen, citype, cichar;  /* Parsed len, type, char value */

+  u_short cishort;            /* Parsed short value */

+  u32_t cilong;               /* Parse long value */

+  int rc = CONFACK;           /* Final packet return code */

+  int orc;                    /* Individual option return code */

+  u_char *p;                  /* Pointer to next char to parse */

+  u_char *rejp;               /* Pointer to next char in reject frame */

+  u_char *nakp;               /* Pointer to next char in Nak frame */

+  int l = *lenp;              /* Length left */

+#if TRACELCP > 0

+  char traceBuf[80];

+  int traceNdx = 0;

+#endif

+

+  /*

+   * Reset all his options.

+   */

+  BZERO(ho, sizeof(*ho));

+

+  /*

+   * Process all his options.

+   */

+  next = inp;

+  nakp = nak_buffer;

+  rejp = inp;

+  while (l) {

+    orc = CONFACK;      /* Assume success */

+    cip = p = next;     /* Remember begining of CI */

+    if (l < 2 ||        /* Not enough data for CI header or */

+        p[1] < 2 ||     /*  CI length too small or */

+        p[1] > l) {     /*  CI length too big? */

+      LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!\n"));

+      orc = CONFREJ;    /* Reject bad CI */

+      cilen = l;        /* Reject till end of packet */

+      l = 0;            /* Don't loop again */

+      citype = 0;

+      goto endswitch;

+    }

+    GETCHAR(citype, p); /* Parse CI type */

+    GETCHAR(cilen, p);  /* Parse CI length */

+    l -= cilen;         /* Adjust remaining length */

+    next += cilen;      /* Step to next CI */

+

+    switch (citype) {   /* Check CI type */

+      case CI_MRU:

+        if (!ao->neg_mru) {    /* Allow option? */

+          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - not allowed\n"));

+          orc = CONFREJ;    /* Reject CI */

+          break;

+        } else if (cilen != CILEN_SHORT) {  /* Check CI length */

+          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - bad length\n"));

+          orc = CONFREJ;    /* Reject CI */

+          break;

+        }

+        GETSHORT(cishort, p);  /* Parse MRU */

+

+        /*

+         * He must be able to receive at least our minimum.

+         * No need to check a maximum.  If he sends a large number,

+         * we'll just ignore it.

+         */

+        if (cishort < PPP_MINMRU) {

+          LCPDEBUG((LOG_INFO, "lcp_reqci: Nak - MRU too small\n"));

+          orc = CONFNAK;    /* Nak CI */

+          PUTCHAR(CI_MRU, nakp);

+          PUTCHAR(CILEN_SHORT, nakp);

+          PUTSHORT(PPP_MINMRU, nakp);  /* Give him a hint */

+          break;

+        }

+        ho->neg_mru = 1;    /* Remember he sent MRU */

+        ho->mru = cishort;    /* And remember value */

+#if TRACELCP > 0

+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MRU %d", cishort);

+        traceNdx = strlen(traceBuf);

+#endif

+        break;

+

+      case CI_ASYNCMAP:

+        if (!ao->neg_asyncmap) {

+          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP not allowed\n"));

+          orc = CONFREJ;

+          break;

+        } else if (cilen != CILEN_LONG) {

+          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP bad length\n"));

+          orc = CONFREJ;

+          break;

+        }

+        GETLONG(cilong, p);

+        

+        /*

+         * Asyncmap must have set at least the bits

+         * which are set in lcp_allowoptions[unit].asyncmap.

+         */

+        if ((ao->asyncmap & ~cilong) != 0) {

+          LCPDEBUG((LOG_INFO, "lcp_reqci: Nak ASYNCMAP %lX missing %lX\n", 

+                    cilong, ao->asyncmap));

+          orc = CONFNAK;

+          PUTCHAR(CI_ASYNCMAP, nakp);

+          PUTCHAR(CILEN_LONG, nakp);

+          PUTLONG(ao->asyncmap | cilong, nakp);

+          break;

+        }

+        ho->neg_asyncmap = 1;

+        ho->asyncmap = cilong;

+#if TRACELCP > 0

+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ASYNCMAP=%lX", cilong);

+        traceNdx = strlen(traceBuf);

+#endif

+        break;

+

+      case CI_AUTHTYPE:

+        if (cilen < CILEN_SHORT) {

+          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE missing arg\n"));

+          orc = CONFREJ;

+          break;

+        } else if (!(ao->neg_upap || ao->neg_chap)) {

+          /*

+           * Reject the option if we're not willing to authenticate.

+           */

+          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE not allowed\n"));

+          orc = CONFREJ;

+          break;

+        }

+        GETSHORT(cishort, p);

+        

+        /*

+         * Authtype must be UPAP or CHAP.

+         *

+         * Note: if both ao->neg_upap and ao->neg_chap are set,

+         * and the peer sends a Configure-Request with two

+         * authenticate-protocol requests, one for CHAP and one

+         * for UPAP, then we will reject the second request.

+         * Whether we end up doing CHAP or UPAP depends then on

+         * the ordering of the CIs in the peer's Configure-Request.

+         */

+        

+        if (cishort == PPP_PAP) {

+          if (ho->neg_chap) {  /* we've already accepted CHAP */

+            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP already accepted\n"));

+            orc = CONFREJ;

+            break;

+          } else if (cilen != CILEN_SHORT) {

+            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP bad len\n"));

+            orc = CONFREJ;

+            break;

+          }

+          if (!ao->neg_upap) {  /* we don't want to do PAP */

+            LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE PAP not allowed\n"));

+            orc = CONFNAK;  /* NAK it and suggest CHAP */

+            PUTCHAR(CI_AUTHTYPE, nakp);

+            PUTCHAR(CILEN_CHAP, nakp);

+            PUTSHORT(PPP_CHAP, nakp);

+            PUTCHAR(ao->chap_mdtype, nakp);

+            break;

+          }

+          ho->neg_upap = 1;

+#if TRACELCP > 0

+          snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PAP (%X)", cishort);

+          traceNdx = strlen(traceBuf);

+#endif

+          break;

+        }

+        if (cishort == PPP_CHAP) {

+          if (ho->neg_upap) {  /* we've already accepted PAP */

+            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP accepted PAP\n"));

+            orc = CONFREJ;

+            break;

+          } else if (cilen != CILEN_CHAP) {

+            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP bad len\n"));

+            orc = CONFREJ;

+            break;

+          }

+          if (!ao->neg_chap) {  /* we don't want to do CHAP */

+            LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP not allowed\n"));

+            orc = CONFNAK;  /* NAK it and suggest PAP */

+            PUTCHAR(CI_AUTHTYPE, nakp);

+            PUTCHAR(CILEN_SHORT, nakp);

+            PUTSHORT(PPP_PAP, nakp);

+            break;

+          }

+          GETCHAR(cichar, p);  /* get digest type*/

+          if (cichar != CHAP_DIGEST_MD5

+#ifdef CHAPMS

+              && cichar != CHAP_MICROSOFT

+#endif

+          ) {

+            LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP digest=%d\n", cichar));

+            orc = CONFNAK;

+            PUTCHAR(CI_AUTHTYPE, nakp);

+            PUTCHAR(CILEN_CHAP, nakp);

+            PUTSHORT(PPP_CHAP, nakp);

+            PUTCHAR(ao->chap_mdtype, nakp);

+            break;

+          }

+#if TRACELCP > 0

+          snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CHAP %X,%d", cishort, cichar);

+          traceNdx = strlen(traceBuf);

+#endif

+          ho->chap_mdtype = cichar; /* save md type */

+          ho->neg_chap = 1;

+          break;

+        }

+        

+        /*

+         * We don't recognize the protocol they're asking for.

+         * Nak it with something we're willing to do.

+         * (At this point we know ao->neg_upap || ao->neg_chap.)

+         */

+        orc = CONFNAK;

+        PUTCHAR(CI_AUTHTYPE, nakp);

+        if (ao->neg_chap) {

+          LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req CHAP\n", cishort));

+          PUTCHAR(CILEN_CHAP, nakp);

+          PUTSHORT(PPP_CHAP, nakp);

+          PUTCHAR(ao->chap_mdtype, nakp);

+        } else {

+          LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req PAP\n", cishort));

+          PUTCHAR(CILEN_SHORT, nakp);

+          PUTSHORT(PPP_PAP, nakp);

+        }

+        break;

+      

+      case CI_QUALITY:

+        GETSHORT(cishort, p);

+        GETLONG(cilong, p);

+#if TRACELCP > 0

+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " QUALITY (%x %x)", cishort, (unsigned int) cilong);

+        traceNdx = strlen(traceBuf);

+#endif

+

+        if (!ao->neg_lqr ||

+            cilen != CILEN_LQR) {

+          orc = CONFREJ;

+          break;

+        }

+        

+        /*

+         * Check the protocol and the reporting period.

+         * XXX When should we Nak this, and what with?

+         */

+        if (cishort != PPP_LQR) {

+          orc = CONFNAK;

+          PUTCHAR(CI_QUALITY, nakp);

+          PUTCHAR(CILEN_LQR, nakp);

+          PUTSHORT(PPP_LQR, nakp);

+          PUTLONG(ao->lqr_period, nakp);

+          break;

+        }

+        break;

+      

+      case CI_MAGICNUMBER:

+        if (!(ao->neg_magicnumber || go->neg_magicnumber) ||

+            cilen != CILEN_LONG) {

+          orc = CONFREJ;

+          break;

+        }

+        GETLONG(cilong, p);

+#if TRACELCP > 0

+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MAGICNUMBER (%lX)", cilong);

+        traceNdx = strlen(traceBuf);

+#endif

+

+        /*

+         * He must have a different magic number.

+         */

+        if (go->neg_magicnumber &&

+            cilong == go->magicnumber) {

+          cilong = magic();  /* Don't put magic() inside macro! */

+          orc = CONFNAK;

+          PUTCHAR(CI_MAGICNUMBER, nakp);

+          PUTCHAR(CILEN_LONG, nakp);

+          PUTLONG(cilong, nakp);

+          break;

+        }

+        ho->neg_magicnumber = 1;

+        ho->magicnumber = cilong;

+        break;

+      

+      

+      case CI_PCOMPRESSION:

+#if TRACELCP > 0

+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PCOMPRESSION");

+        traceNdx = strlen(traceBuf);

+#endif

+        if (!ao->neg_pcompression ||

+            cilen != CILEN_VOID) {

+          orc = CONFREJ;

+          break;

+        }

+        ho->neg_pcompression = 1;

+        break;

+      

+      case CI_ACCOMPRESSION:

+#if TRACELCP > 0

+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ACCOMPRESSION");

+        traceNdx = strlen(traceBuf);

+#endif

+        if (!ao->neg_accompression ||

+            cilen != CILEN_VOID) {

+          orc = CONFREJ;

+          break;

+        }

+        ho->neg_accompression = 1;

+        break;

+      

+      case CI_MRRU:

+#if TRACELCP > 0

+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_MRRU");

+        traceNdx = strlen(traceBuf);

+#endif

+        orc = CONFREJ;

+        break;

+      

+      case CI_SSNHF:

+#if TRACELCP > 0

+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_SSNHF");

+        traceNdx = strlen(traceBuf);

+#endif

+        orc = CONFREJ;

+        break;

+      

+      case CI_EPDISC:

+#if TRACELCP > 0

+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_EPDISC");

+        traceNdx = strlen(traceBuf);

+#endif

+        orc = CONFREJ;

+        break;

+      

+      default:

+#if TRACELCP

+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " unknown %d", citype);

+        traceNdx = strlen(traceBuf);

+#endif

+        orc = CONFREJ;

+        break;

+    }

+

+  endswitch:

+#if TRACELCP

+    if (traceNdx >= 80 - 32) {

+      LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd%s\n", traceBuf));

+      traceNdx = 0;

+    }

+#endif

+    if (orc == CONFACK && /* Good CI */

+        rc != CONFACK) {  /*  but prior CI wasnt? */

+      continue;           /* Don't send this one */

+    }

+

+    if (orc == CONFNAK) {     /* Nak this CI? */

+      if (reject_if_disagree  /* Getting fed up with sending NAKs? */

+          && citype != CI_MAGICNUMBER) {

+        orc = CONFREJ;        /* Get tough if so */

+      } else {

+        if (rc == CONFREJ) {  /* Rejecting prior CI? */

+          continue;           /* Don't send this one */

+        }

+        rc = CONFNAK;

+      }

+    }

+    if (orc == CONFREJ) {        /* Reject this CI */

+      rc = CONFREJ;

+      if (cip != rejp) {         /* Need to move rejected CI? */

+        BCOPY(cip, rejp, cilen); /* Move it */

+      }

+      INCPTR(cilen, rejp);       /* Update output pointer */

+    }

+  }

+

+  /*

+   * If we wanted to send additional NAKs (for unsent CIs), the

+   * code would go here.  The extra NAKs would go at *nakp.

+   * At present there are no cases where we want to ask the

+   * peer to negotiate an option.

+   */

+

+  switch (rc) {

+    case CONFACK:

+      *lenp = (int)(next - inp);

+      break;

+    case CONFNAK:

+      /*

+       * Copy the Nak'd options from the nak_buffer to the caller's buffer.

+       */

+      *lenp = (int)(nakp - nak_buffer);

+      BCOPY(nak_buffer, inp, *lenp);

+      break;

+    case CONFREJ:

+      *lenp = (int)(rejp - inp);

+      break;

+  }

+

+#if TRACELCP > 0

+  if (traceNdx > 0) {

+    LCPDEBUG((LOG_INFO, "lcp_reqci: %s\n", traceBuf));

+  }

+#endif

+  LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.\n", CODENAME(rc)));

+  return (rc);      /* Return final code */

+}

+

+

+/*

+ * lcp_up - LCP has come UP.

+ */

+static void

+lcp_up(fsm *f)

+{

+  lcp_options *wo = &lcp_wantoptions[f->unit];

+  lcp_options *ho = &lcp_hisoptions[f->unit];

+  lcp_options *go = &lcp_gotoptions[f->unit];

+  lcp_options *ao = &lcp_allowoptions[f->unit];

+

+  if (!go->neg_magicnumber) {

+    go->magicnumber = 0;

+  }

+  if (!ho->neg_magicnumber) {

+    ho->magicnumber = 0;

+  }

+

+  /*

+   * Set our MTU to the smaller of the MTU we wanted and

+   * the MRU our peer wanted.  If we negotiated an MRU,

+   * set our MRU to the larger of value we wanted and

+   * the value we got in the negotiation.

+   */

+  ppp_send_config(f->unit, LWIP_MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)),

+                 (ho->neg_asyncmap? ho->asyncmap: 0xffffffffl),

+                  ho->neg_pcompression, ho->neg_accompression);

+  /*

+   * If the asyncmap hasn't been negotiated, we really should

+   * set the receive asyncmap to ffffffff, but we set it to 0

+   * for backwards contemptibility.

+   */

+  ppp_recv_config(f->unit, (go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU),

+                 (go->neg_asyncmap? go->asyncmap: 0x00000000),

+                  go->neg_pcompression, go->neg_accompression);

+

+  if (ho->neg_mru) {

+    peer_mru[f->unit] = ho->mru;

+  }

+

+  lcp_echo_lowerup(f->unit); /* Enable echo messages */

+

+  link_established(f->unit);

+}

+

+

+/*

+ * lcp_down - LCP has gone DOWN.

+ *

+ * Alert other protocols.

+ */

+static void

+lcp_down(fsm *f)

+{

+  lcp_options *go = &lcp_gotoptions[f->unit];

+

+  lcp_echo_lowerdown(f->unit);

+

+  link_down(f->unit);

+

+  ppp_send_config(f->unit, PPP_MRU, 0xffffffffl, 0, 0);

+  ppp_recv_config(f->unit, PPP_MRU,

+                  (go->neg_asyncmap? go->asyncmap: 0x00000000),

+                   go->neg_pcompression, go->neg_accompression);

+  peer_mru[f->unit] = PPP_MRU;

+}

+

+

+/*

+ * lcp_starting - LCP needs the lower layer up.

+ */

+static void

+lcp_starting(fsm *f)

+{

+  link_required(f->unit);

+}

+

+

+/*

+ * lcp_finished - LCP has finished with the lower layer.

+ */

+static void

+lcp_finished(fsm *f)

+{

+  link_terminated(f->unit);

+}

+

+

+#if 0

+/*

+ * print_string - print a readable representation of a string using

+ * printer.

+ */

+static void

+print_string( char *p, int len, void (*printer) (void *, char *, ...), void *arg)

+{

+  int c;

+  

+  printer(arg, "\"");

+  for (; len > 0; --len) {

+    c = *p++;

+    if (' ' <= c && c <= '~') {

+        if (c == '\\' || c == '"') {

+          printer(arg, "\\");

+        }

+        printer(arg, "%c", c);

+    } else {

+      switch (c) {

+        case '\n':

+          printer(arg, "\\n");

+          break;

+        case '\r':

+          printer(arg, "\\r");

+          break;

+        case '\t':

+          printer(arg, "\\t");

+          break;

+        default:

+          printer(arg, "\\%.3o", c);

+        }

+    }

+  }

+  printer(arg, "\"");

+}

+

+

+/*

+ * lcp_printpkt - print the contents of an LCP packet.

+ */

+static char *lcp_codenames[] = {

+  "ConfReq", "ConfAck", "ConfNak", "ConfRej",

+  "TermReq", "TermAck", "CodeRej", "ProtRej",

+  "EchoReq", "EchoRep", "DiscReq"

+};

+

+static int

+lcp_printpkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)

+{

+  int code, id, len, olen;

+  u_char *pstart, *optend;

+  u_short cishort;

+  u32_t cilong;

+

+  if (plen < HEADERLEN) {

+    return 0;

+  }

+  pstart = p;

+  GETCHAR(code, p);

+  GETCHAR(id, p);

+  GETSHORT(len, p);

+  if (len < HEADERLEN || len > plen) {

+    return 0;

+  }

+

+  if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *)) {

+    printer(arg, " %s", lcp_codenames[code-1]);

+  } else {

+    printer(arg, " code=0x%x", code);

+  }

+  printer(arg, " id=0x%x", id);

+  len -= HEADERLEN;

+  switch (code) {

+    case CONFREQ:

+    case CONFACK:

+    case CONFNAK:

+    case CONFREJ:

+      /* print option list */

+      while (len >= 2) {

+        GETCHAR(code, p);

+        GETCHAR(olen, p);

+        p -= 2;

+        if (olen < 2 || olen > len) {

+          break;

+        }

+        printer(arg, " <");

+        len -= olen;

+        optend = p + olen;

+        switch (code) {

+          case CI_MRU:

+            if (olen == CILEN_SHORT) {

+              p += 2;

+              GETSHORT(cishort, p);

+              printer(arg, "mru %d", cishort);

+            }

+            break;

+          case CI_ASYNCMAP:

+            if (olen == CILEN_LONG) {

+              p += 2;

+              GETLONG(cilong, p);

+              printer(arg, "asyncmap 0x%lx", cilong);

+            }

+            break;

+          case CI_AUTHTYPE:

+            if (olen >= CILEN_SHORT) {

+              p += 2;

+              printer(arg, "auth ");

+              GETSHORT(cishort, p);

+              switch (cishort) {

+                case PPP_PAP:

+                  printer(arg, "pap");

+                  break;

+                case PPP_CHAP:

+                  printer(arg, "chap");

+                  break;

+                default:

+                  printer(arg, "0x%x", cishort);

+              }

+            }

+            break;

+          case CI_QUALITY:

+            if (olen >= CILEN_SHORT) {

+              p += 2;

+              printer(arg, "quality ");

+              GETSHORT(cishort, p);

+              switch (cishort) {

+                case PPP_LQR:

+                  printer(arg, "lqr");

+                  break;

+                default:

+                  printer(arg, "0x%x", cishort);

+              }

+            }

+            break;

+          case CI_CALLBACK:

+            if (olen >= CILEN_CHAR) {

+              p += 2;

+              printer(arg, "callback ");

+              GETSHORT(cishort, p);

+              switch (cishort) {

+                case CBCP_OPT:

+                  printer(arg, "CBCP");

+                  break;

+                default:

+                  printer(arg, "0x%x", cishort);

+              }

+            }

+            break;

+          case CI_MAGICNUMBER:

+            if (olen == CILEN_LONG) {

+              p += 2;

+              GETLONG(cilong, p);

+              printer(arg, "magic 0x%x", cilong);

+            }

+            break;

+          case CI_PCOMPRESSION:

+            if (olen == CILEN_VOID) {

+              p += 2;

+              printer(arg, "pcomp");

+            }

+            break;

+          case CI_ACCOMPRESSION:

+            if (olen == CILEN_VOID) {

+              p += 2;

+              printer(arg, "accomp");

+            }

+            break;

+        }

+        while (p < optend) {

+          GETCHAR(code, p);

+          printer(arg, " %.2x", code);

+        }

+        printer(arg, ">");

+      }

+      break;

+    

+    case TERMACK:

+    case TERMREQ:

+      if (len > 0 && *p >= ' ' && *p < 0x7f) {

+        printer(arg, " ");

+        print_string((char*)p, len, printer, arg);

+        p += len;

+        len = 0;

+      }

+      break;

+    

+    case ECHOREQ:

+    case ECHOREP:

+    case DISCREQ:

+      if (len >= 4) {

+        GETLONG(cilong, p);

+        printer(arg, " magic=0x%x", cilong);

+        p += 4;

+        len -= 4;

+      }

+      break;

+  }

+

+  /* print the rest of the bytes in the packet */

+  for (; len > 0; --len) {

+    GETCHAR(code, p);

+    printer(arg, " %.2x", code);

+  }

+

+  return (int)(p - pstart);

+}

+#endif

+

+/*

+ * Time to shut down the link because there is nothing out there.

+ */

+static void

+LcpLinkFailure (fsm *f)

+{

+  if (f->state == LS_OPENED) {

+    LCPDEBUG((LOG_INFO, "No response to %d echo-requests\n", lcp_echos_pending));

+    LCPDEBUG((LOG_NOTICE, "Serial link appears to be disconnected.\n"));

+    lcp_close(f->unit, "Peer not responding");

+  }

+}

+

+/*

+ * Timer expired for the LCP echo requests from this process.

+ */

+static void

+LcpEchoCheck (fsm *f)

+{

+  LcpSendEchoRequest (f);

+

+  /*

+   * Start the timer for the next interval.

+   */

+  LWIP_ASSERT("lcp_echo_timer_running == 0", lcp_echo_timer_running == 0);

+

+  TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval);

+  lcp_echo_timer_running = 1;

+}

+

+/*

+ * LcpEchoTimeout - Timer expired on the LCP echo

+ */

+static void

+LcpEchoTimeout (void *arg)

+{

+  if (lcp_echo_timer_running != 0) {

+    lcp_echo_timer_running = 0;

+    LcpEchoCheck ((fsm *) arg);

+  }

+}

+

+/*

+ * LcpEchoReply - LCP has received a reply to the echo

+ */

+static void

+lcp_received_echo_reply (fsm *f, int id, u_char *inp, int len)

+{

+  u32_t magic;

+

+  LWIP_UNUSED_ARG(id);

+

+  /* Check the magic number - don't count replies from ourselves. */

+  if (len < 4) {

+    LCPDEBUG((LOG_WARNING, "lcp: received short Echo-Reply, length %d\n", len));

+    return;

+  }

+  GETLONG(magic, inp);

+  if (lcp_gotoptions[f->unit].neg_magicnumber && magic == lcp_gotoptions[f->unit].magicnumber) {

+    LCPDEBUG((LOG_WARNING, "appear to have received our own echo-reply!\n"));

+    return;

+  }

+  

+  /* Reset the number of outstanding echo frames */

+  lcp_echos_pending = 0;

+}

+

+/*

+ * LcpSendEchoRequest - Send an echo request frame to the peer

+ */

+static void

+LcpSendEchoRequest (fsm *f)

+{

+  u32_t lcp_magic;

+  u_char pkt[4], *pktp;

+

+  /*

+   * Detect the failure of the peer at this point.

+   */

+  if (lcp_echo_fails != 0) {

+    if (lcp_echos_pending++ >= lcp_echo_fails) {

+      LcpLinkFailure(f);

+      lcp_echos_pending = 0;

+    }

+  }

+

+  /*

+   * Make and send the echo request frame.

+   */

+  if (f->state == LS_OPENED) {

+    lcp_magic = lcp_gotoptions[f->unit].magicnumber;

+    pktp = pkt;

+    PUTLONG(lcp_magic, pktp);

+    fsm_sdata(f, ECHOREQ, (u_char)(lcp_echo_number++ & 0xFF), pkt, (int)(pktp - pkt));

+  }

+}

+

+/*

+ * lcp_echo_lowerup - Start the timer for the LCP frame

+ */

+

+static void

+lcp_echo_lowerup (int unit)

+{

+  fsm *f = &lcp_fsm[unit];

+

+  /* Clear the parameters for generating echo frames */

+  lcp_echos_pending      = 0;

+  lcp_echo_number        = 0;

+  lcp_echo_timer_running = 0;

+

+  /* If a timeout interval is specified then start the timer */

+  if (lcp_echo_interval != 0) {

+    LcpEchoCheck (f);

+  }

+}

+

+/*

+ * lcp_echo_lowerdown - Stop the timer for the LCP frame

+ */

+

+static void

+lcp_echo_lowerdown (int unit)

+{

+  fsm *f = &lcp_fsm[unit];

+

+  if (lcp_echo_timer_running != 0) {

+    UNTIMEOUT (LcpEchoTimeout, f);

+    lcp_echo_timer_running = 0;

+  }

+}

+

+#endif /* PPP_SUPPORT */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/lcp.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/lcp.h
new file mode 100644
index 0000000..5e3f757
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/lcp.h
@@ -0,0 +1,167 @@
+/*****************************************************************************

+* lcp.h - Network Link Control Protocol header file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1997 Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.

+*   Original derived from BSD codes.

+*****************************************************************************/

+/*

+ * lcp.h - Link Control Protocol definitions.

+ *

+ * Copyright (c) 1989 Carnegie Mellon University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Carnegie Mellon University.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ *

+ * $Id: lcp.h,v 1.3 2007/12/19 20:47:23 fbernon Exp $

+ */

+

+#ifndef LCP_H

+#define LCP_H

+

+/*************************

+*** PUBLIC DEFINITIONS ***

+*************************/

+/*

+ * Options.

+ */

+#define CI_MRU           1  /* Maximum Receive Unit */

+#define CI_ASYNCMAP      2  /* Async Control Character Map */

+#define CI_AUTHTYPE      3  /* Authentication Type */

+#define CI_QUALITY       4  /* Quality Protocol */

+#define CI_MAGICNUMBER   5  /* Magic Number */

+#define CI_PCOMPRESSION  7  /* Protocol Field Compression */

+#define CI_ACCOMPRESSION 8  /* Address/Control Field Compression */

+#define CI_CALLBACK      13 /* callback */

+#define CI_MRRU          17 /* max reconstructed receive unit; multilink */

+#define CI_SSNHF         18 /* short sequence numbers for multilink */

+#define CI_EPDISC        19 /* endpoint discriminator */

+

+/*

+ * LCP-specific packet types.

+ */

+#define PROTREJ          8  /* Protocol Reject */

+#define ECHOREQ          9  /* Echo Request */

+#define ECHOREP          10 /* Echo Reply */

+#define DISCREQ          11 /* Discard Request */

+#define CBCP_OPT         6  /* Use callback control protocol */

+

+

+/************************

+*** PUBLIC DATA TYPES ***

+************************/

+

+/*

+ * The state of options is described by an lcp_options structure.

+ */

+typedef struct lcp_options {

+    u_int passive           : 1; /* Don't die if we don't get a response */

+    u_int silent            : 1; /* Wait for the other end to start first */

+    u_int restart           : 1; /* Restart vs. exit after close */

+    u_int neg_mru           : 1; /* Negotiate the MRU? */

+    u_int neg_asyncmap      : 1; /* Negotiate the async map? */

+    u_int neg_upap          : 1; /* Ask for UPAP authentication? */

+    u_int neg_chap          : 1; /* Ask for CHAP authentication? */

+    u_int neg_magicnumber   : 1; /* Ask for magic number? */

+    u_int neg_pcompression  : 1; /* HDLC Protocol Field Compression? */

+    u_int neg_accompression : 1; /* HDLC Address/Control Field Compression? */

+    u_int neg_lqr           : 1; /* Negotiate use of Link Quality Reports */

+    u_int neg_cbcp          : 1; /* Negotiate use of CBCP */

+#ifdef PPP_MULTILINK

+    u_int neg_mrru          : 1; /* Negotiate multilink MRRU */

+    u_int neg_ssnhf         : 1; /* Negotiate short sequence numbers */

+    u_int neg_endpoint      : 1; /* Negotiate endpoint discriminator */

+#endif

+    u_short mru;                 /* Value of MRU */

+#ifdef PPP_MULTILINK

+    u_short mrru;                /* Value of MRRU, and multilink enable */

+#endif

+    u_char chap_mdtype;          /* which MD type (hashing algorithm) */

+    u32_t asyncmap;              /* Value of async map */

+    u32_t magicnumber;

+    int numloops;                /* Number of loops during magic number neg. */

+    u32_t lqr_period;            /* Reporting period for LQR 1/100ths second */

+#ifdef PPP_MULTILINK

+    struct epdisc endpoint;      /* endpoint discriminator */

+#endif

+} lcp_options;

+

+/*

+ * Values for phase from BSD pppd.h based on RFC 1661.

+ */

+typedef enum {

+  PHASE_DEAD = 0,

+  PHASE_INITIALIZE,

+  PHASE_ESTABLISH,

+  PHASE_AUTHENTICATE,

+  PHASE_CALLBACK,

+  PHASE_NETWORK,

+  PHASE_TERMINATE

+} LinkPhase;

+

+

+/*****************************

+*** PUBLIC DATA STRUCTURES ***

+*****************************/

+

+extern LinkPhase lcp_phase[NUM_PPP]; /* Phase of link session (RFC 1661) */

+extern lcp_options lcp_wantoptions[];

+extern lcp_options lcp_gotoptions[];

+extern lcp_options lcp_allowoptions[];

+extern lcp_options lcp_hisoptions[];

+extern ext_accm xmit_accm[];

+

+

+/***********************

+*** PUBLIC FUNCTIONS ***

+***********************/

+

+void lcp_init     (int);

+void lcp_open     (int);

+void lcp_close    (int, char *);

+void lcp_lowerup  (int);

+void lcp_lowerdown(int);

+void lcp_sprotrej (int, u_char *, int); /* send protocol reject */

+

+extern struct protent lcp_protent;

+

+/* Default number of times we receive our magic number from the peer

+   before deciding the link is looped-back. */

+#define DEFLOOPBACKFAIL 10

+

+#endif /* LCP_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/magic.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/magic.c
new file mode 100644
index 0000000..e4ff2e6
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/magic.c
@@ -0,0 +1,82 @@
+/*****************************************************************************

+* magic.c - Network Random Number Generator program file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1997 by Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.

+*   Original based on BSD magic.c.

+*****************************************************************************/

+/*

+ * magic.c - PPP Magic Number routines.

+ *

+ * Copyright (c) 1989 Carnegie Mellon University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Carnegie Mellon University.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ */

+

+#include "lwip/opt.h"

+

+#if PPP_SUPPORT

+

+#include "ppp.h"

+#include "randm.h"

+#include "magic.h"

+

+/***********************************/

+/*** PUBLIC FUNCTION DEFINITIONS ***/

+/***********************************/

+/*

+ * magicInit - Initialize the magic number generator.

+ *

+ * Since we use another random number generator that has its own

+ * initialization, we do nothing here.

+ */

+void magicInit()

+{

+  return;

+}

+

+/*

+ * magic - Returns the next magic number.

+ */

+u32_t magic()

+{

+  return avRandom();

+}

+

+#endif /* PPP_SUPPORT */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/magic.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/magic.h
new file mode 100644
index 0000000..2082349
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/magic.h
@@ -0,0 +1,67 @@
+/*****************************************************************************

+* magic.h - Network Random Number Generator header file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1997 Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.

+*   Original derived from BSD codes.

+*****************************************************************************/

+/*

+ * magic.h - PPP Magic Number definitions.

+ *

+ * Copyright (c) 1989 Carnegie Mellon University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Carnegie Mellon University.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ *

+ * $Id: magic.h,v 1.2 2007/12/02 22:35:55 fbernon Exp $

+ */

+

+#ifndef MAGIC_H

+#define MAGIC_H

+

+/*****************************************************************************

+************************** PUBLIC FUNCTIONS **********************************

+*****************************************************************************/

+

+/* Initialize the magic number generator */

+void  magicInit(void);

+

+/* Returns the next magic number */

+u32_t magic(void);

+

+#endif /* MAGIC_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/md5.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/md5.c
new file mode 100644
index 0000000..87c219c
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/md5.c
@@ -0,0 +1,318 @@
+/*

+ ***********************************************************************

+ ** md5.c -- the source code for MD5 routines                         **

+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **

+ ** Created: 2/17/90 RLR                                              **

+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **

+ ***********************************************************************

+ */

+

+/*

+ ***********************************************************************

+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **

+ **                                                                   **

+ ** License to copy and use this software is granted provided that    **

+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **

+ ** Digest Algorithm" in all material mentioning or referencing this  **

+ ** software or this function.                                        **

+ **                                                                   **

+ ** License is also granted to make and use derivative works          **

+ ** provided that such works are identified as "derived from the RSA  **

+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **

+ ** material mentioning or referencing the derived work.              **

+ **                                                                   **

+ ** RSA Data Security, Inc. makes no representations concerning       **

+ ** either the merchantability of this software or the suitability    **

+ ** of this software for any particular purpose.  It is provided "as  **

+ ** is" without express or implied warranty of any kind.              **

+ **                                                                   **

+ ** These notices must be retained in any copies of any part of this  **

+ ** documentation and/or software.                                    **

+ ***********************************************************************

+ */

+

+#include "lwip/opt.h"

+

+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#if CHAP_SUPPORT || MD5_SUPPORT

+

+#include "ppp.h"

+#include "pppdebug.h"

+

+#include "md5.h"

+

+/*

+ ***********************************************************************

+ **  Message-digest routines:                                         **

+ **  To form the message digest for a message M                       **

+ **    (1) Initialize a context buffer mdContext using MD5Init        **

+ **    (2) Call MD5Update on mdContext and M                          **

+ **    (3) Call MD5Final on mdContext                                 **

+ **  The message digest is now in mdContext->digest[0...15]           **

+ ***********************************************************************

+ */

+

+/* forward declaration */

+static void Transform (u32_t *buf, u32_t *in);

+

+static unsigned char PADDING[64] = {

+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

+};

+

+/* F, G, H and I are basic MD5 functions */

+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))

+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))

+#define H(x, y, z) ((x) ^ (y) ^ (z))

+#define I(x, y, z) ((y) ^ ((x) | (~z)))

+

+/* ROTATE_LEFT rotates x left n bits */

+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

+

+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */

+/* Rotation is separate from addition to prevent recomputation */

+#define FF(a, b, c, d, x, s, ac) \

+  {(a) += F ((b), (c), (d)) + (x) + (u32_t)(ac); \

+   (a) = ROTATE_LEFT ((a), (s)); \

+   (a) += (b); \

+  }

+#define GG(a, b, c, d, x, s, ac) \

+  {(a) += G ((b), (c), (d)) + (x) + (u32_t)(ac); \

+   (a) = ROTATE_LEFT ((a), (s)); \

+   (a) += (b); \

+  }

+#define HH(a, b, c, d, x, s, ac) \

+  {(a) += H ((b), (c), (d)) + (x) + (u32_t)(ac); \

+   (a) = ROTATE_LEFT ((a), (s)); \

+   (a) += (b); \

+  }

+#define II(a, b, c, d, x, s, ac) \

+  {(a) += I ((b), (c), (d)) + (x) + (u32_t)(ac); \

+   (a) = ROTATE_LEFT ((a), (s)); \

+   (a) += (b); \

+  }

+

+#ifdef __STDC__

+#define UL(x) x##UL

+#else

+#ifdef WIN32

+#define UL(x) x##UL

+#else

+#define UL(x) x

+#endif

+#endif

+

+/* The routine MD5Init initializes the message-digest context

+   mdContext. All fields are set to zero.

+ */

+void

+MD5Init (MD5_CTX *mdContext)

+{

+  mdContext->i[0] = mdContext->i[1] = (u32_t)0;

+

+  /* Load magic initialization constants. */

+  mdContext->buf[0] = (u32_t)0x67452301UL;

+  mdContext->buf[1] = (u32_t)0xefcdab89UL;

+  mdContext->buf[2] = (u32_t)0x98badcfeUL;

+  mdContext->buf[3] = (u32_t)0x10325476UL;

+}

+

+/* The routine MD5Update updates the message-digest context to

+   account for the presence of each of the characters inBuf[0..inLen-1]

+   in the message whose digest is being computed.

+ */

+void

+MD5Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen)

+{

+  u32_t in[16];

+  int mdi;

+  unsigned int i, ii;

+

+#if 0

+  ppp_trace(LOG_INFO, "MD5Update: %u:%.*H\n", inLen, MIN(inLen, 20) * 2, inBuf);

+  ppp_trace(LOG_INFO, "MD5Update: %u:%s\n", inLen, inBuf);

+#endif

+  

+  /* compute number of bytes mod 64 */

+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);

+

+  /* update number of bits */

+  if ((mdContext->i[0] + ((u32_t)inLen << 3)) < mdContext->i[0]) {

+    mdContext->i[1]++;

+  }

+  mdContext->i[0] += ((u32_t)inLen << 3);

+  mdContext->i[1] += ((u32_t)inLen >> 29);

+

+  while (inLen--) {

+    /* add new character to buffer, increment mdi */

+    mdContext->in[mdi++] = *inBuf++;

+

+    /* transform if necessary */

+    if (mdi == 0x40) {

+      for (i = 0, ii = 0; i < 16; i++, ii += 4) {

+        in[i] = (((u32_t)mdContext->in[ii+3]) << 24) |

+                (((u32_t)mdContext->in[ii+2]) << 16) |

+                (((u32_t)mdContext->in[ii+1]) << 8)  |

+                ((u32_t)mdContext->in[ii]);

+      }

+      Transform (mdContext->buf, in);

+      mdi = 0;

+    }

+  }

+}

+

+/* The routine MD5Final terminates the message-digest computation and

+   ends with the desired message digest in mdContext->digest[0...15].

+ */

+void

+MD5Final (unsigned char hash[], MD5_CTX *mdContext)

+{

+  u32_t in[16];

+  int mdi;

+  unsigned int i, ii;

+  unsigned int padLen;

+

+  /* save number of bits */

+  in[14] = mdContext->i[0];

+  in[15] = mdContext->i[1];

+

+  /* compute number of bytes mod 64 */

+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);

+

+  /* pad out to 56 mod 64 */

+  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);

+  MD5Update (mdContext, PADDING, padLen);

+

+  /* append length in bits and transform */

+  for (i = 0, ii = 0; i < 14; i++, ii += 4) {

+    in[i] = (((u32_t)mdContext->in[ii+3]) << 24) |

+            (((u32_t)mdContext->in[ii+2]) << 16) |

+            (((u32_t)mdContext->in[ii+1]) << 8)  |

+            ((u32_t)mdContext->in[ii]);

+  }

+  Transform (mdContext->buf, in);

+

+  /* store buffer in digest */

+  for (i = 0, ii = 0; i < 4; i++, ii += 4) {

+    mdContext->digest[ii]   = (unsigned char)(mdContext->buf[i] & 0xFF);

+    mdContext->digest[ii+1] =

+      (unsigned char)((mdContext->buf[i] >> 8)  & 0xFF);

+    mdContext->digest[ii+2] =

+      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);

+    mdContext->digest[ii+3] =

+      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);

+  }

+  SMEMCPY(hash, mdContext->digest, 16);

+}

+

+/* Basic MD5 step. Transforms buf based on in.

+ */

+static void

+Transform (u32_t *buf, u32_t *in)

+{

+  u32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3];

+

+  /* Round 1 */

+#define S11 7

+#define S12 12

+#define S13 17

+#define S14 22

+  FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */

+  FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */

+  FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */

+  FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */

+  FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */

+  FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */

+  FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */

+  FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */

+  FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */

+  FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */

+  FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */

+  FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */

+  FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */

+  FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */

+  FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */

+  FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */

+

+  /* Round 2 */

+#define S21 5

+#define S22 9

+#define S23 14

+#define S24 20

+  GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */

+  GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */

+  GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */

+  GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */

+  GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */

+  GG ( d, a, b, c, in[10], S22, UL(  38016083)); /* 22 */

+  GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */

+  GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */

+  GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */

+  GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */

+  GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */

+  GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */

+  GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */

+  GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */

+  GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */

+  GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */

+

+  /* Round 3 */

+#define S31 4

+#define S32 11

+#define S33 16

+#define S34 23

+  HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */

+  HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */

+  HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */

+  HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */

+  HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */

+  HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */

+  HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */

+  HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */

+  HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */

+  HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */

+  HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */

+  HH ( b, c, d, a, in[ 6], S34, UL(  76029189)); /* 44 */

+  HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */

+  HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */

+  HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */

+  HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */

+

+  /* Round 4 */

+#define S41 6

+#define S42 10

+#define S43 15

+#define S44 21

+  II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */

+  II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */

+  II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */

+  II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */

+  II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */

+  II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */

+  II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */

+  II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */

+  II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */

+  II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */

+  II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */

+  II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */

+  II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */

+  II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */

+  II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */

+  II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */

+

+  buf[0] += a;

+  buf[1] += b;

+  buf[2] += c;

+  buf[3] += d;

+}

+

+#endif /* CHAP_SUPPORT || MD5_SUPPORT */

+

+#endif /* PPP_SUPPORT */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/md5.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/md5.h
new file mode 100644
index 0000000..0bcb23c
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/md5.h
@@ -0,0 +1,55 @@
+/*

+ ***********************************************************************

+ ** md5.h -- header file for implementation of MD5                    **

+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **

+ ** Created: 2/17/90 RLR                                              **

+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version               **

+ ** Revised (for MD5): RLR 4/27/91                                    **

+ **   -- G modified to have y&~z instead of y&z                       **

+ **   -- FF, GG, HH modified to add in last register done             **

+ **   -- Access pattern: round 2 works mod 5, round 3 works mod 3     **

+ **   -- distinct additive constant for each step                     **

+ **   -- round 4 added, working mod 7                                 **

+ ***********************************************************************

+ */

+

+/*

+ ***********************************************************************

+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **

+ **                                                                   **

+ ** License to copy and use this software is granted provided that    **

+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **

+ ** Digest Algorithm" in all material mentioning or referencing this  **

+ ** software or this function.                                        **

+ **                                                                   **

+ ** License is also granted to make and use derivative works          **

+ ** provided that such works are identified as "derived from the RSA  **

+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **

+ ** material mentioning or referencing the derived work.              **

+ **                                                                   **

+ ** RSA Data Security, Inc. makes no representations concerning       **

+ ** either the merchantability of this software or the suitability    **

+ ** of this software for any particular purpose.  It is provided "as  **

+ ** is" without express or implied warranty of any kind.              **

+ **                                                                   **

+ ** These notices must be retained in any copies of any part of this  **

+ ** documentation and/or software.                                    **

+ ***********************************************************************

+ */

+

+#ifndef MD5_H

+#define MD5_H

+

+/* Data structure for MD5 (Message-Digest) computation */

+typedef struct {

+  u32_t i[2];               /* number of _bits_ handled mod 2^64 */

+  u32_t buf[4];             /* scratch buffer */

+  unsigned char in[64];     /* input buffer */

+  unsigned char digest[16]; /* actual digest after MD5Final call */

+} MD5_CTX;

+

+void MD5Init  ( MD5_CTX *mdContext);

+void MD5Update( MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen);

+void MD5Final ( unsigned char hash[], MD5_CTX *mdContext);

+

+#endif /* MD5_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pap.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pap.c
new file mode 100644
index 0000000..fea7bbd
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pap.c
@@ -0,0 +1,617 @@
+/*****************************************************************************

+* pap.c - Network Password Authentication Protocol program file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1997 by Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-12-12 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.

+*   Original.

+*****************************************************************************/

+/*

+ * upap.c - User/Password Authentication Protocol.

+ *

+ * Copyright (c) 1989 Carnegie Mellon University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Carnegie Mellon University.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ */

+

+#include "lwip/opt.h"

+

+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#include "ppp.h"

+#include "pppdebug.h"

+

+#include "auth.h"

+#include "pap.h"

+

+/***********************************/

+/*** LOCAL FUNCTION DECLARATIONS ***/

+/***********************************/

+/*

+ * Protocol entry points.

+ */

+static void upap_init      (int);

+static void upap_lowerup   (int);

+static void upap_lowerdown (int);

+static void upap_input     (int, u_char *, int);

+static void upap_protrej   (int);

+

+static void upap_timeout   (void *);

+static void upap_reqtimeout(void *);

+static void upap_rauthreq  (upap_state *, u_char *, int, int);

+static void upap_rauthack  (upap_state *, u_char *, int, int);

+static void upap_rauthnak  (upap_state *, u_char *, int, int);

+static void upap_sauthreq  (upap_state *);

+static void upap_sresp     (upap_state *, u_char, u_char, char *, int);

+

+

+/******************************/

+/*** PUBLIC DATA STRUCTURES ***/

+/******************************/

+struct protent pap_protent = {

+  PPP_PAP,

+  upap_init,

+  upap_input,

+  upap_protrej,

+  upap_lowerup,

+  upap_lowerdown,

+  NULL,

+  NULL,

+#if 0

+  upap_printpkt,

+  NULL,

+#endif

+  1,

+  "PAP",

+#if 0

+  NULL,

+  NULL,

+  NULL

+#endif

+};

+

+upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */

+

+

+

+/***********************************/

+/*** PUBLIC FUNCTION DEFINITIONS ***/

+/***********************************/

+/*

+ *  Set the default login name and password for the pap sessions

+ */

+void

+upap_setloginpasswd(int unit, const char *luser, const char *lpassword)

+{

+  upap_state *u = &upap[unit];

+  

+  /* Save the username and password we're given */

+  u->us_user = luser;

+  u->us_userlen = strlen(luser);

+  u->us_passwd = lpassword;

+  u->us_passwdlen = strlen(lpassword);

+}

+

+

+/*

+ * upap_authwithpeer - Authenticate us with our peer (start client).

+ *

+ * Set new state and send authenticate's.

+ */

+void

+upap_authwithpeer(int unit, char *user, char *password)

+{

+  upap_state *u = &upap[unit];

+

+  UPAPDEBUG((LOG_INFO, "upap_authwithpeer: %d user=%s password=%s s=%d\n",

+             unit, user, password, u->us_clientstate));

+

+  upap_setloginpasswd(unit, user, password);

+

+  u->us_transmits = 0;

+

+  /* Lower layer up yet? */

+  if (u->us_clientstate == UPAPCS_INITIAL ||

+      u->us_clientstate == UPAPCS_PENDING) {

+    u->us_clientstate = UPAPCS_PENDING;

+    return;

+  }

+

+  upap_sauthreq(u);      /* Start protocol */

+}

+

+

+/*

+ * upap_authpeer - Authenticate our peer (start server).

+ *

+ * Set new state.

+ */

+void

+upap_authpeer(int unit)

+{

+  upap_state *u = &upap[unit];

+

+  /* Lower layer up yet? */

+  if (u->us_serverstate == UPAPSS_INITIAL ||

+      u->us_serverstate == UPAPSS_PENDING) {

+    u->us_serverstate = UPAPSS_PENDING;

+    return;

+  }

+

+  u->us_serverstate = UPAPSS_LISTEN;

+  if (u->us_reqtimeout > 0) {

+    TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);

+  }

+}

+

+

+

+/**********************************/

+/*** LOCAL FUNCTION DEFINITIONS ***/

+/**********************************/

+/*

+ * upap_init - Initialize a UPAP unit.

+ */

+static void

+upap_init(int unit)

+{

+  upap_state *u = &upap[unit];

+

+  UPAPDEBUG((LOG_INFO, "upap_init: %d\n", unit));

+  u->us_unit         = unit;

+  u->us_user         = NULL;

+  u->us_userlen      = 0;

+  u->us_passwd       = NULL;

+  u->us_passwdlen    = 0;

+  u->us_clientstate  = UPAPCS_INITIAL;

+  u->us_serverstate  = UPAPSS_INITIAL;

+  u->us_id           = 0;

+  u->us_timeouttime  = UPAP_DEFTIMEOUT;

+  u->us_maxtransmits = 10;

+  u->us_reqtimeout   = UPAP_DEFREQTIME;

+}

+

+/*

+ * upap_timeout - Retransmission timer for sending auth-reqs expired.

+ */

+static void

+upap_timeout(void *arg)

+{

+  upap_state *u = (upap_state *) arg;

+

+  UPAPDEBUG((LOG_INFO, "upap_timeout: %d timeout %d expired s=%d\n", 

+        u->us_unit, u->us_timeouttime, u->us_clientstate));

+

+  if (u->us_clientstate != UPAPCS_AUTHREQ) {

+    return;

+  }

+

+  if (u->us_transmits >= u->us_maxtransmits) {

+    /* give up in disgust */

+    UPAPDEBUG((LOG_ERR, "No response to PAP authenticate-requests\n"));

+    u->us_clientstate = UPAPCS_BADAUTH;

+    auth_withpeer_fail(u->us_unit, PPP_PAP);

+    return;

+  }

+

+  upap_sauthreq(u);    /* Send Authenticate-Request */

+}

+

+

+/*

+ * upap_reqtimeout - Give up waiting for the peer to send an auth-req.

+ */

+static void

+upap_reqtimeout(void *arg)

+{

+  upap_state *u = (upap_state *) arg;

+

+  if (u->us_serverstate != UPAPSS_LISTEN) {

+    return; /* huh?? */

+  }

+

+  auth_peer_fail(u->us_unit, PPP_PAP);

+  u->us_serverstate = UPAPSS_BADAUTH;

+}

+

+

+/*

+ * upap_lowerup - The lower layer is up.

+ *

+ * Start authenticating if pending.

+ */

+static void

+upap_lowerup(int unit)

+{

+  upap_state *u = &upap[unit];

+

+  UPAPDEBUG((LOG_INFO, "upap_lowerup: %d s=%d\n", unit, u->us_clientstate));

+

+  if (u->us_clientstate == UPAPCS_INITIAL) {

+    u->us_clientstate = UPAPCS_CLOSED;

+  } else if (u->us_clientstate == UPAPCS_PENDING) {

+    upap_sauthreq(u);  /* send an auth-request */

+  }

+

+  if (u->us_serverstate == UPAPSS_INITIAL) {

+    u->us_serverstate = UPAPSS_CLOSED;

+  } else if (u->us_serverstate == UPAPSS_PENDING) {

+    u->us_serverstate = UPAPSS_LISTEN;

+    if (u->us_reqtimeout > 0) {

+      TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);

+    }

+  }

+}

+

+

+/*

+ * upap_lowerdown - The lower layer is down.

+ *

+ * Cancel all timeouts.

+ */

+static void

+upap_lowerdown(int unit)

+{

+  upap_state *u = &upap[unit];

+

+  UPAPDEBUG((LOG_INFO, "upap_lowerdown: %d s=%d\n", unit, u->us_clientstate));

+

+  if (u->us_clientstate == UPAPCS_AUTHREQ) { /* Timeout pending? */

+    UNTIMEOUT(upap_timeout, u);    /* Cancel timeout */

+  }

+  if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0) {

+    UNTIMEOUT(upap_reqtimeout, u);

+  }

+

+  u->us_clientstate = UPAPCS_INITIAL;

+  u->us_serverstate = UPAPSS_INITIAL;

+}

+

+

+/*

+ * upap_protrej - Peer doesn't speak this protocol.

+ *

+ * This shouldn't happen.  In any case, pretend lower layer went down.

+ */

+static void

+upap_protrej(int unit)

+{

+  upap_state *u = &upap[unit];

+

+  if (u->us_clientstate == UPAPCS_AUTHREQ) {

+    UPAPDEBUG((LOG_ERR, "PAP authentication failed due to protocol-reject\n"));

+    auth_withpeer_fail(unit, PPP_PAP);

+  }

+  if (u->us_serverstate == UPAPSS_LISTEN) {

+    UPAPDEBUG((LOG_ERR, "PAP authentication of peer failed (protocol-reject)\n"));

+    auth_peer_fail(unit, PPP_PAP);

+  }

+  upap_lowerdown(unit);

+}

+

+

+/*

+ * upap_input - Input UPAP packet.

+ */

+static void

+upap_input(int unit, u_char *inpacket, int l)

+{

+  upap_state *u = &upap[unit];

+  u_char *inp;

+  u_char code, id;

+  int len;

+

+  /*

+   * Parse header (code, id and length).

+   * If packet too short, drop it.

+   */

+  inp = inpacket;

+  if (l < UPAP_HEADERLEN) {

+    UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header.\n"));

+    return;

+  }

+  GETCHAR(code, inp);

+  GETCHAR(id, inp);

+  GETSHORT(len, inp);

+  if (len < UPAP_HEADERLEN) {

+    UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length.\n"));

+    return;

+  }

+  if (len > l) {

+    UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet.\n"));

+    return;

+  }

+  len -= UPAP_HEADERLEN;

+

+  /*

+   * Action depends on code.

+   */

+  switch (code) {

+    case UPAP_AUTHREQ:

+      upap_rauthreq(u, inp, id, len);

+      break;

+

+    case UPAP_AUTHACK:

+      upap_rauthack(u, inp, id, len);

+      break;

+

+    case UPAP_AUTHNAK:

+      upap_rauthnak(u, inp, id, len);

+      break;

+

+    default:        /* XXX Need code reject */

+      break;

+  }

+}

+

+

+/*

+ * upap_rauth - Receive Authenticate.

+ */

+static void

+upap_rauthreq(upap_state *u, u_char *inp, int id, int len)

+{

+  u_char ruserlen, rpasswdlen;

+  char *ruser, *rpasswd;

+  int retcode;

+  char *msg;

+  int msglen;

+

+  UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.\n", id));

+

+  if (u->us_serverstate < UPAPSS_LISTEN) {

+    return;

+  }

+

+  /*

+   * If we receive a duplicate authenticate-request, we are

+   * supposed to return the same status as for the first request.

+   */

+  if (u->us_serverstate == UPAPSS_OPEN) {

+    upap_sresp(u, UPAP_AUTHACK, id, "", 0);  /* return auth-ack */

+    return;

+  }

+  if (u->us_serverstate == UPAPSS_BADAUTH) {

+    upap_sresp(u, UPAP_AUTHNAK, id, "", 0);  /* return auth-nak */

+    return;

+  }

+

+  /*

+   * Parse user/passwd.

+   */

+  if (len < sizeof (u_char)) {

+    UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));

+    return;

+  }

+  GETCHAR(ruserlen, inp);

+  len -= sizeof (u_char) + ruserlen + sizeof (u_char);

+  if (len < 0) {

+    UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));

+    return;

+  }

+  ruser = (char *) inp;

+  INCPTR(ruserlen, inp);

+  GETCHAR(rpasswdlen, inp);

+  if (len < rpasswdlen) {

+    UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));

+    return;

+  }

+  rpasswd = (char *) inp;

+

+  /*

+   * Check the username and password given.

+   */

+  retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen);

+  BZERO(rpasswd, rpasswdlen);

+

+  upap_sresp(u, retcode, id, msg, msglen);

+

+  if (retcode == UPAP_AUTHACK) {

+    u->us_serverstate = UPAPSS_OPEN;

+    auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);

+  } else {

+    u->us_serverstate = UPAPSS_BADAUTH;

+    auth_peer_fail(u->us_unit, PPP_PAP);

+  }

+

+  if (u->us_reqtimeout > 0) {

+    UNTIMEOUT(upap_reqtimeout, u);

+  }

+}

+

+

+/*

+ * upap_rauthack - Receive Authenticate-Ack.

+ */

+static void

+upap_rauthack(upap_state *u, u_char *inp, int id, int len)

+{

+  u_char msglen;

+  char *msg;

+

+  LWIP_UNUSED_ARG(id);

+

+  UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d s=%d\n", id, u->us_clientstate));

+

+  if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */

+    return;

+  }

+

+  /*

+   * Parse message.

+   */

+  if (len < sizeof (u_char)) {

+    UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n"));

+    return;

+  }

+  GETCHAR(msglen, inp);

+  len -= sizeof (u_char);

+  if (len < msglen) {

+    UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n"));

+    return;

+  }

+  msg = (char *) inp;

+  PRINTMSG(msg, msglen);

+

+  u->us_clientstate = UPAPCS_OPEN;

+

+  auth_withpeer_success(u->us_unit, PPP_PAP);

+}

+

+

+/*

+ * upap_rauthnak - Receive Authenticate-Nakk.

+ */

+static void

+upap_rauthnak(upap_state *u, u_char *inp, int id, int len)

+{

+  u_char msglen;

+  char *msg;

+

+  LWIP_UNUSED_ARG(id);

+

+  UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d s=%d\n", id, u->us_clientstate));

+

+  if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */

+    return;

+  }

+

+  /*

+   * Parse message.

+   */

+  if (len < sizeof (u_char)) {

+    UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));

+    return;

+  }

+  GETCHAR(msglen, inp);

+  len -= sizeof (u_char);

+  if (len < msglen) {

+    UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));

+    return;

+  }

+  msg = (char *) inp;

+  PRINTMSG(msg, msglen);

+

+  u->us_clientstate = UPAPCS_BADAUTH;

+

+  UPAPDEBUG((LOG_ERR, "PAP authentication failed\n"));

+  auth_withpeer_fail(u->us_unit, PPP_PAP);

+}

+

+

+/*

+ * upap_sauthreq - Send an Authenticate-Request.

+ */

+static void

+upap_sauthreq(upap_state *u)

+{

+  u_char *outp;

+  int outlen;

+

+  outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) 

+         + u->us_userlen + u->us_passwdlen;

+  outp = outpacket_buf[u->us_unit];

+

+  MAKEHEADER(outp, PPP_PAP);

+

+  PUTCHAR(UPAP_AUTHREQ, outp);

+  PUTCHAR(++u->us_id, outp);

+  PUTSHORT(outlen, outp);

+  PUTCHAR(u->us_userlen, outp);

+  BCOPY(u->us_user, outp, u->us_userlen);

+  INCPTR(u->us_userlen, outp);

+  PUTCHAR(u->us_passwdlen, outp);

+  BCOPY(u->us_passwd, outp, u->us_passwdlen);

+

+  pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);

+

+  UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d\n", u->us_id));

+

+  TIMEOUT(upap_timeout, u, u->us_timeouttime);

+  ++u->us_transmits;

+  u->us_clientstate = UPAPCS_AUTHREQ;

+}

+

+

+/*

+ * upap_sresp - Send a response (ack or nak).

+ */

+static void

+upap_sresp(upap_state *u, u_char code, u_char id, char *msg, int msglen)

+{

+  u_char *outp;

+  int outlen;

+

+  outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;

+  outp = outpacket_buf[u->us_unit];

+  MAKEHEADER(outp, PPP_PAP);

+

+  PUTCHAR(code, outp);

+  PUTCHAR(id, outp);

+  PUTSHORT(outlen, outp);

+  PUTCHAR(msglen, outp);

+  BCOPY(msg, outp, msglen);

+  pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);

+

+  UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d s=%d\n", code, id, u->us_clientstate));

+}

+

+#if 0

+/*

+ * upap_printpkt - print the contents of a PAP packet.

+ */

+static int upap_printpkt(

+  u_char *p,

+  int plen,

+  void (*printer) (void *, char *, ...),

+  void *arg

+)

+{

+  LWIP_UNUSED_ARG(p);

+  LWIP_UNUSED_ARG(plen);

+  LWIP_UNUSED_ARG(printer);

+  LWIP_UNUSED_ARG(arg);

+  return 0;

+}

+#endif /* 0 */

+

+#endif /* PAP_SUPPORT */

+

+#endif /* PPP_SUPPORT */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pap.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pap.h
new file mode 100644
index 0000000..fdff86e
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pap.h
@@ -0,0 +1,131 @@
+/*****************************************************************************

+* pap.h -  PPP Password Authentication Protocol header file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1997 Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.

+*   Original derived from BSD codes.

+*****************************************************************************/

+/*

+ * upap.h - User/Password Authentication Protocol definitions.

+ *

+ * Copyright (c) 1989 Carnegie Mellon University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Carnegie Mellon University.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ */

+

+#ifndef PAP_H

+#define PAP_H

+

+#if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+/*************************

+*** PUBLIC DEFINITIONS ***

+*************************/

+/*

+ * Packet header = Code, id, length.

+ */

+#define UPAP_HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))

+

+

+/*

+ * UPAP codes.

+ */

+#define UPAP_AUTHREQ 1 /* Authenticate-Request */

+#define UPAP_AUTHACK 2 /* Authenticate-Ack */

+#define UPAP_AUTHNAK 3 /* Authenticate-Nak */

+

+/*

+ * Client states.

+ */

+#define UPAPCS_INITIAL 0 /* Connection down */

+#define UPAPCS_CLOSED  1 /* Connection up, haven't requested auth */

+#define UPAPCS_PENDING 2 /* Connection down, have requested auth */

+#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */

+#define UPAPCS_OPEN    4 /* We've received an Ack */

+#define UPAPCS_BADAUTH 5 /* We've received a Nak */

+

+/*

+ * Server states.

+ */

+#define UPAPSS_INITIAL 0 /* Connection down */

+#define UPAPSS_CLOSED  1 /* Connection up, haven't requested auth */

+#define UPAPSS_PENDING 2 /* Connection down, have requested auth */

+#define UPAPSS_LISTEN  3 /* Listening for an Authenticate */

+#define UPAPSS_OPEN    4 /* We've sent an Ack */

+#define UPAPSS_BADAUTH 5 /* We've sent a Nak */

+

+

+/************************

+*** PUBLIC DATA TYPES ***

+************************/

+

+/*

+ * Each interface is described by upap structure.

+ */

+typedef struct upap_state {

+  int us_unit;           /* Interface unit number */

+  const char *us_user;   /* User */

+  int us_userlen;        /* User length */

+  const char *us_passwd; /* Password */

+  int us_passwdlen;      /* Password length */

+  int us_clientstate;    /* Client state */

+  int us_serverstate;    /* Server state */

+  u_char us_id;          /* Current id */

+  int us_timeouttime;    /* Timeout (seconds) for auth-req retrans. */

+  int us_transmits;      /* Number of auth-reqs sent */

+  int us_maxtransmits;   /* Maximum number of auth-reqs to send */

+  int us_reqtimeout;     /* Time to wait for auth-req from peer */

+} upap_state;

+

+

+/***********************

+*** PUBLIC FUNCTIONS ***

+***********************/

+

+extern upap_state upap[];

+

+void upap_setloginpasswd(int unit, const char *luser, const char *lpassword);

+void upap_authwithpeer  (int, char *, char *);

+void upap_authpeer      (int);

+

+extern struct protent pap_protent;

+

+#endif /* PAP_SUPPORT */

+

+#endif /* PAP_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp.c
new file mode 100644
index 0000000..9267dd2
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp.c
@@ -0,0 +1,2003 @@
+/*****************************************************************************

+* ppp.c - Network Point to Point Protocol program file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1997 by Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.

+*   Original.

+*****************************************************************************/

+

+/*

+ * ppp_defs.h - PPP definitions.

+ *

+ * if_pppvar.h - private structures and declarations for PPP.

+ *

+ * Copyright (c) 1994 The Australian National University.

+ * All rights reserved.

+ *

+ * Permission to use, copy, modify, and distribute this software and its

+ * documentation is hereby granted, provided that the above copyright

+ * notice appears in all copies.  This software is provided without any

+ * warranty, express or implied. The Australian National University

+ * makes no representations about the suitability of this software for

+ * any purpose.

+ *

+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY

+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES

+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF

+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,

+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY

+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS

+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO

+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,

+ * OR MODIFICATIONS.

+ */

+

+/*

+ * if_ppp.h - Point-to-Point Protocol definitions.

+ *

+ * Copyright (c) 1989 Carnegie Mellon University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Carnegie Mellon University.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ */

+

+#include "lwip/opt.h"

+

+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/ip.h" /* for ip_input() */

+

+#include "ppp.h"

+#include "pppdebug.h"

+

+#include "randm.h"

+#include "fsm.h"

+#if PAP_SUPPORT

+#include "pap.h"

+#endif /* PAP_SUPPORT */

+#if CHAP_SUPPORT

+#include "chap.h"

+#endif /* CHAP_SUPPORT */

+#include "ipcp.h"

+#include "lcp.h"

+#include "magic.h"

+#include "auth.h"

+#if VJ_SUPPORT

+#include "vj.h"

+#endif /* VJ_SUPPORT */

+#if PPPOE_SUPPORT

+#include "netif/ppp_oe.h"

+#endif /* PPPOE_SUPPORT */

+

+#include <string.h>

+

+/*************************/

+/*** LOCAL DEFINITIONS ***/

+/*************************/

+

+/*

+ * The basic PPP frame.

+ */

+#define PPP_ADDRESS(p)  (((u_char *)(p))[0])

+#define PPP_CONTROL(p)  (((u_char *)(p))[1])

+#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])

+

+/* PPP packet parser states.  Current state indicates operation yet to be

+ * completed. */

+typedef enum {

+  PDIDLE = 0,  /* Idle state - waiting. */

+  PDSTART,     /* Process start flag. */

+  PDADDRESS,   /* Process address field. */

+  PDCONTROL,   /* Process control field. */

+  PDPROTOCOL1, /* Process protocol field 1. */

+  PDPROTOCOL2, /* Process protocol field 2. */

+  PDDATA       /* Process data byte. */

+} PPPDevStates;

+

+#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])

+

+/************************/

+/*** LOCAL DATA TYPES ***/

+/************************/

+/*

+ * PPP interface control block.

+ */

+typedef struct PPPControl_s {

+  char openFlag;                /* True when in use. */

+#if PPPOE_SUPPORT

+  struct netif *ethif;

+  struct pppoe_softc *pppoe_sc;

+#endif /* PPPOE_SUPPORT */

+  int  if_up;                   /* True when the interface is up. */

+  int  errCode;                 /* Code indicating why interface is down. */

+#if PPPOS_SUPPORT

+  sio_fd_t fd;                  /* File device ID of port. */

+  int  kill_link;               /* Shut the link down. */

+  int  sig_hup;                 /* Carrier lost. */

+  struct pbuf *inHead, *inTail; /* The input packet. */

+  PPPDevStates inState;         /* The input process state. */

+  char inEscaped;               /* Escape next character. */

+  u16_t inProtocol;             /* The input protocol code. */

+  u16_t inFCS;                  /* Input Frame Check Sequence value. */

+#endif /* PPPOS_SUPPORT */

+  int  mtu;                     /* Peer's mru */

+  int  pcomp;                   /* Does peer accept protocol compression? */

+  int  accomp;                  /* Does peer accept addr/ctl compression? */

+  u_long lastXMit;              /* Time of last transmission. */

+  ext_accm inACCM;              /* Async-Ctl-Char-Map for input. */

+  ext_accm outACCM;             /* Async-Ctl-Char-Map for output. */

+#if PPPOS_SUPPORT && VJ_SUPPORT

+  int  vjEnabled;               /* Flag indicating VJ compression enabled. */

+  struct vjcompress vjComp;     /* Van Jabobsen compression header. */

+#endif /* PPPOS_SUPPORT && VJ_SUPPORT */

+

+  struct netif netif;

+

+  struct ppp_addrs addrs;

+

+  void (*linkStatusCB)(void *ctx, int errCode, void *arg);

+  void *linkStatusCtx;

+

+} PPPControl;

+

+

+/*

+ * Ioctl definitions.

+ */

+

+struct npioctl {

+  int         protocol; /* PPP procotol, e.g. PPP_IP */

+  enum NPmode mode;

+};

+

+

+

+/***********************************/

+/*** LOCAL FUNCTION DECLARATIONS ***/

+/***********************************/

+#if PPPOS_SUPPORT

+static void pppMain(void *pd);

+static void pppDrop(PPPControl *pc);

+static void pppInProc(int pd, u_char *s, int l);

+#endif /* PPPOS_SUPPORT */

+

+

+/******************************/

+/*** PUBLIC DATA STRUCTURES ***/

+/******************************/

+u_long subnetMask;

+

+static PPPControl pppControl[NUM_PPP]; /* The PPP interface control blocks. */

+

+/*

+ * PPP Data Link Layer "protocol" table.

+ * One entry per supported protocol.

+ * The last entry must be NULL.

+ */

+struct protent *ppp_protocols[] = {

+  &lcp_protent,

+#if PAP_SUPPORT

+  &pap_protent,

+#endif /* PAP_SUPPORT */

+#if CHAP_SUPPORT

+  &chap_protent,

+#endif /* CHAP_SUPPORT */

+#if CBCP_SUPPORT

+  &cbcp_protent,

+#endif /* CBCP_SUPPORT */

+  &ipcp_protent,

+#if CCP_SUPPORT

+  &ccp_protent,

+#endif /* CCP_SUPPORT */

+  NULL

+};

+

+

+/*

+ * Buffers for outgoing packets.  This must be accessed only from the appropriate

+ * PPP task so that it doesn't need to be protected to avoid collisions.

+ */

+u_char *outpacket_buf[NUM_PPP];  

+

+

+/*****************************/

+/*** LOCAL DATA STRUCTURES ***/

+/*****************************/

+

+#if PPPOS_SUPPORT

+/*

+ * FCS lookup table as calculated by genfcstab.

+ */

+static const u_short fcstab[256] = {

+  0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,

+  0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,

+  0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,

+  0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,

+  0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,

+  0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,

+  0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,

+  0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,

+  0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,

+  0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,

+  0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,

+  0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,

+  0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,

+  0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,

+  0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,

+  0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,

+  0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,

+  0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,

+  0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,

+  0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,

+  0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,

+  0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,

+  0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,

+  0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,

+  0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,

+  0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,

+  0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,

+  0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,

+  0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,

+  0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,

+  0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,

+  0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78

+};

+

+/* PPP's Asynchronous-Control-Character-Map.  The mask array is used

+ * to select the specific bit for a character. */

+static u_char pppACCMMask[] = {

+  0x01,

+  0x02,

+  0x04,

+  0x08,

+  0x10,

+  0x20,

+  0x40,

+  0x80

+};

+

+

+void

+pppMainWakeup(int pd)

+{

+  PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d\n", pd));

+  sio_read_abort(pppControl[pd].fd);

+}

+#endif /* PPPOS_SUPPORT */

+

+void

+pppLinkTerminated(int pd)

+{

+  PPPControl *pc = &pppControl[pd];

+

+  PPPDEBUG((LOG_DEBUG, "pppLinkTerminated: unit %d\n", pd));

+

+#if PPPOE_SUPPORT

+  if(pc->ethif) {

+    pppoe_disconnect(pc->pppoe_sc);

+  } else

+#endif /* PPPOE_SUPPORT */

+  {

+#if PPPOS_SUPPORT

+    pppMainWakeup(pd);

+#endif /* PPPOS_SUPPORT */

+  }

+}

+

+void

+pppLinkDown(int pd)

+{

+  PPPControl *pc = &pppControl[pd];

+

+  PPPDEBUG((LOG_DEBUG, "pppLinkDown: unit %d\n", pd));

+

+#if PPPOE_SUPPORT

+  if(pc->ethif) {

+    pppoe_disconnect(pc->pppoe_sc);

+  } else

+#endif /* PPPOE_SUPPORT */

+  {

+#if PPPOS_SUPPORT

+    pppMainWakeup(pd);

+#endif /* PPPOS_SUPPORT */

+  }

+}

+

+/* these callbacks are necessary because lcp_* functions

+   must be called in the same context as pppInput(),

+   namely the tcpip_thread(), essentially because

+   they manipulate timeouts which are thread-private

+*/

+

+static void

+pppStartCB(void *arg)

+{

+  int pd = (int)arg;

+

+  PPPDEBUG((LOG_DEBUG, "pppStartCB: unit %d\n", pd));

+  lcp_lowerup(pd);

+  lcp_open(pd); /* Start protocol */

+}

+

+static void

+pppStopCB(void *arg)

+{

+  int pd = (int)arg;

+

+  PPPDEBUG((LOG_DEBUG, "pppStopCB: unit %d\n", pd));

+  lcp_close(pd, "User request");

+}

+

+static void

+pppHupCB(void *arg)

+{

+  int pd = (int)arg;

+

+  PPPDEBUG((LOG_DEBUG, "pppHupCB: unit %d\n", pd));

+  lcp_lowerdown(pd);

+  link_terminated(pd);

+}

+

+/***********************************/

+/*** PUBLIC FUNCTION DEFINITIONS ***/

+/***********************************/

+/* Initialize the PPP subsystem. */

+

+struct ppp_settings ppp_settings;

+

+err_t

+pppInit(void)

+{

+  struct protent *protp;

+  int i, j;

+

+  memset(&ppp_settings, 0, sizeof(ppp_settings));

+  ppp_settings.usepeerdns = 1;

+  pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);

+

+  magicInit();

+

+  for (i = 0; i < NUM_PPP; i++) {

+    pppControl[i].openFlag = 0;

+

+    subnetMask = htonl(0xffffff00);

+

+    outpacket_buf[i] = (u_char *)mem_malloc(PPP_MRU+PPP_HDRLEN);

+    if(!outpacket_buf[i]) {

+      return ERR_MEM;

+    }

+

+    /*

+     * Initialize to the standard option set.

+     */

+    for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j) {

+      (*protp->init)(i);

+    }

+  }

+

+#if LINK_STATS

+  /** @todo already done in stats_init (in fact, zeroed at boot). So, remove it? */

+  /* Clear the statistics. */

+  memset(&lwip_stats.link, 0, sizeof(lwip_stats.link));

+#endif /* LINK_STATS */

+

+#if PPPOE_SUPPORT

+  pppoe_init();

+#endif /* PPPOE_SUPPORT */

+

+  return ERR_OK;

+}

+

+void

+pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)

+{

+  switch(authType) {

+    case PPPAUTHTYPE_NONE:

+    default:

+#ifdef LWIP_PPP_STRICT_PAP_REJECT

+      ppp_settings.refuse_pap = 1;

+#else  /* LWIP_PPP_STRICT_PAP_REJECT */

+      /* some providers request pap and accept an empty login/pw */

+      ppp_settings.refuse_pap = 0;

+#endif /* LWIP_PPP_STRICT_PAP_REJECT */

+      ppp_settings.refuse_chap = 1;

+      break;

+

+    case PPPAUTHTYPE_ANY:

+      /* Warning: Using PPPAUTHTYPE_ANY might have security consequences.

+       * RFC 1994 says:

+       *

+       * In practice, within or associated with each PPP server, there is a

+       * database which associates "user" names with authentication

+       * information ("secrets").  It is not anticipated that a particular

+       * named user would be authenticated by multiple methods.  This would

+       * make the user vulnerable to attacks which negotiate the least secure

+       * method from among a set (such as PAP rather than CHAP).  If the same

+       * secret was used, PAP would reveal the secret to be used later with

+       * CHAP.

+       *

+       * Instead, for each user name there should be an indication of exactly

+       * one method used to authenticate that user name.  If a user needs to

+       * make use of different authentication methods under different

+       * circumstances, then distinct user names SHOULD be employed, each of

+       * which identifies exactly one authentication method.

+       *

+       */

+      ppp_settings.refuse_pap = 0;

+      ppp_settings.refuse_chap = 0;

+      break;

+

+    case PPPAUTHTYPE_PAP:

+      ppp_settings.refuse_pap = 0;

+      ppp_settings.refuse_chap = 1;

+      break;

+

+    case PPPAUTHTYPE_CHAP:

+      ppp_settings.refuse_pap = 1;

+      ppp_settings.refuse_chap = 0;

+      break;

+  }

+

+  if(user) {

+    strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);

+    ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';

+  } else {

+    ppp_settings.user[0] = '\0';

+  }

+

+  if(passwd) {

+    strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);

+    ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';

+  } else {

+    ppp_settings.passwd[0] = '\0';

+  }

+}

+

+#if PPPOS_SUPPORT

+/* Open a new PPP connection using the given I/O device.

+ * This initializes the PPP control block but does not

+ * attempt to negotiate the LCP session.  If this port

+ * connects to a modem, the modem connection must be

+ * established before calling this.

+ * Return a new PPP connection descriptor on success or

+ * an error code (negative) on failure. */

+int

+pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)

+{

+  PPPControl *pc;

+  int pd;

+

+  /* Find a free PPP session descriptor. Critical region? */

+  for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);

+

+  if (pd >= NUM_PPP) {

+    pd = PPPERR_OPEN;

+  } else {

+    pppControl[pd].openFlag = !0;

+  }

+

+  /* Launch a deamon thread. */

+  if (pd >= 0) {

+    pppControl[pd].openFlag = 1;

+

+    lcp_init(pd);

+    pc = &pppControl[pd];

+    pc->fd = fd;

+#if PPPOE_SUPPORT

+    pc->ethif= NULL;

+#endif /* PPPOE_SUPPORT */

+    pc->kill_link = 0;

+    pc->sig_hup = 0;

+    pc->if_up = 0;

+    pc->errCode = 0;

+    pc->inState = PDIDLE;

+    pc->inHead = NULL;

+    pc->inTail = NULL;

+    pc->inEscaped = 0;

+    pc->lastXMit = 0;

+

+#if VJ_SUPPORT

+    pc->vjEnabled = 0;

+    vj_compress_init(&pc->vjComp);

+#endif /* VJ_SUPPORT */

+

+    /* 

+     * Default the in and out accm so that escape and flag characters

+     * are always escaped. 

+     */

+    memset(pc->inACCM, 0, sizeof(ext_accm));

+    pc->inACCM[15] = 0x60;

+    memset(pc->outACCM, 0, sizeof(ext_accm));

+    pc->outACCM[15] = 0x60;

+

+    pc->linkStatusCB = linkStatusCB;

+    pc->linkStatusCtx = linkStatusCtx;

+

+    sys_thread_new(PPP_THREAD_NAME, pppMain, (void*)pd, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO);

+    if(!linkStatusCB) {

+      while(pd >= 0 && !pc->if_up) {

+        sys_msleep(500);

+        if (lcp_phase[pd] == PHASE_DEAD) {

+          pppClose(pd);

+          if (pc->errCode) {

+            pd = pc->errCode;

+          } else {

+            pd = PPPERR_CONNECT;

+          }

+        }

+      }

+    }

+  }

+

+  return pd;

+}

+#endif /* PPPOS_SUPPORT */

+

+#if PPPOE_SUPPORT

+static void pppOverEthernetLinkStatusCB(int pd, int up);

+

+void

+pppOverEthernetClose(int pd)

+{

+  PPPControl* pc = &pppControl[pd];

+

+  /* *TJL* There's no lcp_deinit */

+  lcp_close(pd, NULL);

+

+  pppoe_destroy(&pc->netif);

+}

+

+int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)

+{

+  PPPControl *pc;

+  int pd;

+

+  LWIP_UNUSED_ARG(service_name);

+  LWIP_UNUSED_ARG(concentrator_name);

+

+  /* Find a free PPP session descriptor. Critical region? */

+  for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);

+  if (pd >= NUM_PPP) {

+    pd = PPPERR_OPEN;

+  } else {

+    pppControl[pd].openFlag = !0;

+  }

+

+  /* Launch a deamon thread. */

+  if (pd >= 0) {

+

+    pppControl[pd].openFlag = 1;

+

+    lcp_init(pd);

+

+    lcp_wantoptions[pd].mru = PPPOE_MAXMTU;

+    lcp_wantoptions[pd].neg_asyncmap = 0;

+    lcp_wantoptions[pd].neg_pcompression = 0;

+    lcp_wantoptions[pd].neg_accompression = 0;

+

+    lcp_allowoptions[pd].mru = PPPOE_MAXMTU;

+    lcp_allowoptions[pd].neg_asyncmap = 0;

+    lcp_allowoptions[pd].neg_pcompression = 0;

+    lcp_allowoptions[pd].neg_accompression = 0;

+

+    pc = &pppControl[pd];

+    pc->if_up = 0;

+    pc->errCode = 0;

+    pc->lastXMit = 0;

+#if PPPOS_SUPPORT

+    pc->kill_link = 0;

+    pc->sig_hup = 0;

+    pc->inState = PDIDLE;

+    pc->inHead = NULL;

+    pc->inTail = NULL;

+    pc->inEscaped = 0;

+#if VJ_SUPPORT

+    pc->vjEnabled = 0;

+#endif /* VJ_SUPPORT */

+#endif /* PPPOS_SUPPORT */

+    pc->ethif= ethif;

+

+    memset(pc->inACCM,  0, sizeof(ext_accm));

+    memset(pc->outACCM, 0, sizeof(ext_accm));

+

+    pc->linkStatusCB  = linkStatusCB;

+    pc->linkStatusCtx = linkStatusCtx;

+

+    if(pppoe_create(ethif, pd, pppOverEthernetLinkStatusCB, &pc->pppoe_sc) != ERR_OK) {

+      pc->openFlag = 0;

+      return PPPERR_OPEN;

+    }

+

+    pppoe_connect(pc->pppoe_sc);

+

+    if(!linkStatusCB) {

+      while(pd >= 0 && !pc->if_up) {

+        sys_msleep(500);

+        if (lcp_phase[pd] == PHASE_DEAD) {

+          pppClose(pd);

+          if (pc->errCode) {

+            pd = pc->errCode;

+          } else {

+            pd = PPPERR_CONNECT;

+          }

+        }

+      }

+    }

+  }

+

+  return pd;

+}

+#endif /* PPPOE_SUPPORT */

+

+

+/* Close a PPP connection and release the descriptor. 

+ * Any outstanding packets in the queues are dropped.

+ * Return 0 on success, an error code on failure. */

+int

+pppClose(int pd)

+{

+  PPPControl *pc = &pppControl[pd];

+  int st = 0;

+

+  /* Disconnect */

+#if PPPOE_SUPPORT

+  if(pc->ethif) {

+    PPPDEBUG((LOG_DEBUG, "pppClose: unit %d kill_link -> pppStopCB\n", pd));

+    pc->errCode = PPPERR_USER;

+    /* This will leave us at PHASE_DEAD. */

+    tcpip_callback(pppStopCB, (void*)pd);

+  } else

+#endif /* PPPOE_SUPPORT */

+  {

+#if PPPOS_SUPPORT

+    pc->kill_link = !0;

+    pppMainWakeup(pd);

+#endif /* PPPOS_SUPPORT */

+  }

+

+  if(!pc->linkStatusCB) {

+    while(st >= 0 && lcp_phase[pd] != PHASE_DEAD) {

+      sys_msleep(500);

+      break;

+    }

+  }

+

+  return st;

+}

+

+/* This function is called when carrier is lost on the PPP channel. */

+void

+pppSigHUP(int pd)

+{

+  PPPControl *pc = &pppControl[pd];

+

+#if PPPOE_SUPPORT

+  if(pc->ethif) {

+    PPPDEBUG((LOG_DEBUG, "pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));

+    tcpip_callback(pppHupCB, (void*)pd);

+  } else

+#endif /* PPPOE_SUPPORT */

+  {

+#if PPPOS_SUPPORT

+    pc->sig_hup = 1;

+    pppMainWakeup(pd);

+#endif /* PPPOS_SUPPORT */

+  }

+}

+

+#if PPPOS_SUPPORT

+static void

+nPut(PPPControl *pc, struct pbuf *nb)

+{

+  struct pbuf *b;

+  int c;

+

+  for(b = nb; b != NULL; b = b->next) {

+    if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {

+      PPPDEBUG((LOG_WARNING,

+               "PPP nPut: incomplete sio_write(%d,, %u) = %d\n", pc->fd, b->len, c));

+      LINK_STATS_INC(link.err);

+      pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */

+      break;

+    }

+  }

+

+  pbuf_free(nb);

+  LINK_STATS_INC(link.xmit);

+}

+

+/* 

+ * pppAppend - append given character to end of given pbuf.  If outACCM

+ * is not NULL and the character needs to be escaped, do so.

+ * If pbuf is full, append another.

+ * Return the current pbuf.

+ */

+static struct pbuf *

+pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)

+{

+  struct pbuf *tb = nb;

+  

+  /* Make sure there is room for the character and an escape code.

+   * Sure we don't quite fill the buffer if the character doesn't

+   * get escaped but is one character worth complicating this? */

+  /* Note: We assume no packet header. */

+  if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) {

+    tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);

+    if (tb) {

+      nb->next = tb;

+    } else {

+      LINK_STATS_INC(link.memerr);

+    }

+    nb = tb;

+  }

+

+  if (nb) {

+    if (outACCM && ESCAPE_P(*outACCM, c)) {

+      *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE;

+      *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS;

+    } else {

+      *((u_char*)nb->payload + nb->len++) = c;

+    }

+  }

+

+  return tb;

+}

+#endif /* PPPOS_SUPPORT */

+

+#if PPPOE_SUPPORT

+static err_t

+pppifOutputOverEthernet(int pd, struct pbuf *p)

+{

+  PPPControl *pc = &pppControl[pd];

+  struct pbuf *pb;

+  u_short protocol = PPP_IP;

+  int i=0;

+

+  pb = pbuf_alloc(PBUF_LINK, pppoe_hdrlen + sizeof(protocol), PBUF_RAM);

+  if(!pb) {

+    LINK_STATS_INC(link.memerr);

+    LINK_STATS_INC(link.proterr);

+    return ERR_MEM;

+  }

+

+  pbuf_header(pb, -pppoe_hdrlen);

+

+  pc->lastXMit = sys_jiffies();

+

+  if (!pc->pcomp || protocol > 0xFF) {

+    *((u_char*)pb->payload + i++) = (protocol >> 8) & 0xFF;

+  }

+  *((u_char*)pb->payload + i) = protocol & 0xFF;

+

+  pbuf_chain(pb, p);

+

+  if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {

+    LINK_STATS_INC(link.err);

+    return PPPERR_DEVICE;

+  }

+

+  LINK_STATS_INC(link.xmit);

+  return ERR_OK;

+}

+#endif /* PPPOE_SUPPORT */

+

+/* Send a packet on the given connection. */

+static err_t

+pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr)

+{

+  int pd = (int)netif->state;

+  u_short protocol = PPP_IP;

+  PPPControl *pc = &pppControl[pd];

+#if PPPOS_SUPPORT

+  u_int fcsOut = PPP_INITFCS;

+  struct pbuf *headMB = NULL, *tailMB = NULL, *p;

+  u_char c;

+#endif /* PPPOS_SUPPORT */

+

+  LWIP_UNUSED_ARG(ipaddr);

+

+  /* Validate parameters. */

+  /* We let any protocol value go through - it can't hurt us

+   * and the peer will just drop it if it's not accepting it. */

+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {

+    PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad parms prot=%d pb=%p\n",

+              pd, protocol, pb));

+    LINK_STATS_INC(link.opterr);

+    LINK_STATS_INC(link.drop);

+    return ERR_ARG;

+  }

+

+  /* Check that the link is up. */

+  if (lcp_phase[pd] == PHASE_DEAD) {

+    PPPDEBUG((LOG_ERR, "pppifOutput[%d]: link not up\n", pd));

+    LINK_STATS_INC(link.rterr);

+    LINK_STATS_INC(link.drop);

+    return ERR_RTE;

+  }

+

+#if PPPOE_SUPPORT

+  if(pc->ethif) {

+    return pppifOutputOverEthernet(pd, pb);

+  }

+#endif /* PPPOE_SUPPORT */

+

+#if PPPOS_SUPPORT

+  /* Grab an output buffer. */

+  headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);

+  if (headMB == NULL) {

+    PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: first alloc fail\n", pd));

+    LINK_STATS_INC(link.memerr);

+    LINK_STATS_INC(link.drop);

+    return ERR_MEM;

+  }

+

+#if VJ_SUPPORT

+  /* 

+   * Attempt Van Jacobson header compression if VJ is configured and

+   * this is an IP packet. 

+   */

+  if (protocol == PPP_IP && pc->vjEnabled) {

+    switch (vj_compress_tcp(&pc->vjComp, pb)) {

+      case TYPE_IP:

+        /* No change...

+           protocol = PPP_IP_PROTOCOL; */

+        break;

+      case TYPE_COMPRESSED_TCP:

+        protocol = PPP_VJC_COMP;

+        break;

+      case TYPE_UNCOMPRESSED_TCP:

+        protocol = PPP_VJC_UNCOMP;

+        break;

+      default:

+        PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad IP packet\n", pd));

+        LINK_STATS_INC(link.proterr);

+        LINK_STATS_INC(link.drop);

+        pbuf_free(headMB);

+        return ERR_VAL;

+    }

+  }

+#endif /* VJ_SUPPORT */

+

+  tailMB = headMB;

+

+  /* Build the PPP header. */

+  if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {

+    tailMB = pppAppend(PPP_FLAG, tailMB, NULL);

+  }

+

+  pc->lastXMit = sys_jiffies();

+  if (!pc->accomp) {

+    fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);

+    tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM);

+    fcsOut = PPP_FCS(fcsOut, PPP_UI);

+    tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM);

+  }

+  if (!pc->pcomp || protocol > 0xFF) {

+    c = (protocol >> 8) & 0xFF;

+    fcsOut = PPP_FCS(fcsOut, c);

+    tailMB = pppAppend(c, tailMB, &pc->outACCM);

+  }

+  c = protocol & 0xFF;

+  fcsOut = PPP_FCS(fcsOut, c);

+  tailMB = pppAppend(c, tailMB, &pc->outACCM);

+

+  /* Load packet. */

+  for(p = pb; p; p = p->next) {

+    int n;

+    u_char *sPtr;

+

+    sPtr = (u_char*)p->payload;

+    n = p->len;

+    while (n-- > 0) {

+      c = *sPtr++;

+

+      /* Update FCS before checking for special characters. */

+      fcsOut = PPP_FCS(fcsOut, c);

+      

+      /* Copy to output buffer escaping special characters. */

+      tailMB = pppAppend(c, tailMB, &pc->outACCM);

+    }

+  }

+

+  /* Add FCS and trailing flag. */

+  c = ~fcsOut & 0xFF;

+  tailMB = pppAppend(c, tailMB, &pc->outACCM);

+  c = (~fcsOut >> 8) & 0xFF;

+  tailMB = pppAppend(c, tailMB, &pc->outACCM);

+  tailMB = pppAppend(PPP_FLAG, tailMB, NULL);

+

+  /* If we failed to complete the packet, throw it away. */

+  if (!tailMB) {

+    PPPDEBUG((LOG_WARNING,

+             "pppifOutput[%d]: Alloc err - dropping proto=%d\n", 

+              pd, protocol));

+    pbuf_free(headMB);

+    LINK_STATS_INC(link.memerr);

+    LINK_STATS_INC(link.drop);

+    return ERR_MEM;

+  }

+

+  /* Send it. */

+  PPPDEBUG((LOG_INFO, "pppifOutput[%d]: proto=0x%04X\n", pd, protocol));

+

+  nPut(pc, headMB);

+#endif /* PPPOS_SUPPORT */

+

+  return ERR_OK;

+}

+

+/* Get and set parameters for the given connection.

+ * Return 0 on success, an error code on failure. */

+int

+pppIOCtl(int pd, int cmd, void *arg)

+{

+  PPPControl *pc = &pppControl[pd];

+  int st = 0;

+

+  if (pd < 0 || pd >= NUM_PPP) {

+    st = PPPERR_PARAM;

+  } else {

+    switch(cmd) {

+    case PPPCTLG_UPSTATUS:      /* Get the PPP up status. */

+      if (arg) {

+        *(int *)arg = (int)(pc->if_up);

+      } else {

+        st = PPPERR_PARAM;

+      }

+      break;

+    case PPPCTLS_ERRCODE:       /* Set the PPP error code. */

+      if (arg) {

+        pc->errCode = *(int *)arg;

+      } else {

+        st = PPPERR_PARAM;

+      }

+      break;

+    case PPPCTLG_ERRCODE:       /* Get the PPP error code. */

+      if (arg) {

+        *(int *)arg = (int)(pc->errCode);

+      } else {

+        st = PPPERR_PARAM;

+      }

+      break;

+#if PPPOS_SUPPORT

+    case PPPCTLG_FD:

+      if (arg) {

+        *(sio_fd_t *)arg = pc->fd;

+      } else {

+        st = PPPERR_PARAM;

+      }

+      break;

+#endif /* PPPOS_SUPPORT */

+    default:

+      st = PPPERR_PARAM;

+      break;

+    }

+  }

+

+  return st;

+}

+

+/*

+ * Return the Maximum Transmission Unit for the given PPP connection.

+ */

+u_int

+pppMTU(int pd)

+{

+  PPPControl *pc = &pppControl[pd];

+  u_int st;

+

+  /* Validate parameters. */

+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {

+    st = 0;

+  } else {

+    st = pc->mtu;

+  }

+

+  return st;

+}

+

+#if PPPOE_SUPPORT

+int

+pppWriteOverEthernet(int pd, const u_char *s, int n)

+{

+  PPPControl *pc = &pppControl[pd];

+  struct pbuf *pb;

+

+  /* skip address & flags */

+  s += 2;

+  n -= 2;

+

+  pb = pbuf_alloc(PBUF_LINK, pppoe_hdrlen + n, PBUF_RAM);

+  if(!pb) {

+    LINK_STATS_INC(link.memerr);

+    LINK_STATS_INC(link.proterr);

+    return PPPERR_ALLOC;

+  }

+

+  pbuf_header(pb, -pppoe_hdrlen);

+

+  pc->lastXMit = sys_jiffies();

+

+  SMEMCPY(pb->payload, s, n);

+

+  if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {

+    LINK_STATS_INC(link.err);

+    return PPPERR_DEVICE;

+  }

+

+  LINK_STATS_INC(link.xmit);

+  return PPPERR_NONE;

+}

+#endif /* PPPOE_SUPPORT */

+

+/*

+ * Write n characters to a ppp link.

+ *  RETURN: >= 0 Number of characters written

+ *           -1 Failed to write to device

+ */

+int

+pppWrite(int pd, const u_char *s, int n)

+{

+  PPPControl *pc = &pppControl[pd];

+#if PPPOS_SUPPORT

+  u_char c;

+  u_int fcsOut;

+  struct pbuf *headMB, *tailMB;

+#endif /* PPPOS_SUPPORT */

+

+#if PPPOE_SUPPORT

+  if(pc->ethif) {

+    return pppWriteOverEthernet(pd, s, n);

+  }

+#endif /* PPPOE_SUPPORT */

+

+#if PPPOS_SUPPORT

+  headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);

+  if (headMB == NULL) {

+    LINK_STATS_INC(link.memerr);

+    LINK_STATS_INC(link.proterr);

+    return PPPERR_ALLOC;

+  }

+

+  tailMB = headMB;

+

+  /* If the link has been idle, we'll send a fresh flag character to

+   * flush any noise. */

+  if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {

+    tailMB = pppAppend(PPP_FLAG, tailMB, NULL);

+  }

+  pc->lastXMit = sys_jiffies();

+

+  fcsOut = PPP_INITFCS;

+  /* Load output buffer. */

+  while (n-- > 0) {

+    c = *s++;

+

+    /* Update FCS before checking for special characters. */

+    fcsOut = PPP_FCS(fcsOut, c);

+

+    /* Copy to output buffer escaping special characters. */

+    tailMB = pppAppend(c, tailMB, &pc->outACCM);

+  }

+    

+  /* Add FCS and trailing flag. */

+  c = ~fcsOut & 0xFF;

+  tailMB = pppAppend(c, tailMB, &pc->outACCM);

+  c = (~fcsOut >> 8) & 0xFF;

+  tailMB = pppAppend(c, tailMB, &pc->outACCM);

+  tailMB = pppAppend(PPP_FLAG, tailMB, NULL);

+

+  /* If we failed to complete the packet, throw it away.

+   * Otherwise send it. */

+  if (!tailMB) {

+    PPPDEBUG((LOG_WARNING,

+             "pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len));

+           /*"pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */

+    pbuf_free(headMB);

+    LINK_STATS_INC(link.memerr);

+    LINK_STATS_INC(link.proterr);

+    return PPPERR_ALLOC;

+  }

+

+  PPPDEBUG((LOG_INFO, "pppWrite[%d]: len=%d\n", pd, headMB->len));

+                   /* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */

+  nPut(pc, headMB);

+#endif /* PPPOS_SUPPORT */

+

+  return PPPERR_NONE;

+}

+

+/*

+ * ppp_send_config - configure the transmit characteristics of

+ * the ppp interface.

+ */

+void

+ppp_send_config( int unit, int mtu, u32_t asyncmap, int pcomp, int accomp)

+{

+  PPPControl *pc = &pppControl[unit];

+  int i;

+  

+  pc->mtu = mtu;

+  pc->pcomp = pcomp;

+  pc->accomp = accomp;

+  

+  /* Load the ACCM bits for the 32 control codes. */

+  for (i = 0; i < 32/8; i++) {

+    pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF);

+  }

+  PPPDEBUG((LOG_INFO, "ppp_send_config[%d]: outACCM=%X %X %X %X\n",

+            unit,

+            pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));

+}

+

+

+/*

+ * ppp_set_xaccm - set the extended transmit ACCM for the interface.

+ */

+void

+ppp_set_xaccm(int unit, ext_accm *accm)

+{

+  SMEMCPY(pppControl[unit].outACCM, accm, sizeof(ext_accm));

+  PPPDEBUG((LOG_INFO, "ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n",

+            unit,

+            pppControl[unit].outACCM[0],

+            pppControl[unit].outACCM[1],

+            pppControl[unit].outACCM[2],

+            pppControl[unit].outACCM[3]));

+}

+

+

+/*

+ * ppp_recv_config - configure the receive-side characteristics of

+ * the ppp interface.

+ */

+void

+ppp_recv_config( int unit, int mru, u32_t asyncmap, int pcomp, int accomp)

+{

+  PPPControl *pc = &pppControl[unit];

+  int i;

+

+  LWIP_UNUSED_ARG(accomp);

+  LWIP_UNUSED_ARG(pcomp);

+  LWIP_UNUSED_ARG(mru);

+

+  /* Load the ACCM bits for the 32 control codes. */

+  for (i = 0; i < 32 / 8; i++) {

+    pc->inACCM[i] = (u_char)(asyncmap >> (i * 8));

+  }

+  PPPDEBUG((LOG_INFO, "ppp_recv_config[%d]: inACCM=%X %X %X %X\n",

+            unit,

+            pc->inACCM[0], pc->inACCM[1], pc->inACCM[2], pc->inACCM[3]));

+}

+

+#if 0

+/*

+ * ccp_test - ask kernel whether a given compression method

+ * is acceptable for use.  Returns 1 if the method and parameters

+ * are OK, 0 if the method is known but the parameters are not OK

+ * (e.g. code size should be reduced), or -1 if the method is unknown.

+ */

+int

+ccp_test( int unit, int opt_len,  int for_transmit, u_char *opt_ptr)

+{

+  return 0; /* XXX Currently no compression. */

+}

+

+/*

+ * ccp_flags_set - inform kernel about the current state of CCP.

+ */

+void

+ccp_flags_set(int unit, int isopen, int isup)

+{

+  /* XXX */

+}

+

+/*

+ * ccp_fatal_error - returns 1 if decompression was disabled as a

+ * result of an error detected after decompression of a packet,

+ * 0 otherwise.  This is necessary because of patent nonsense.

+ */

+int

+ccp_fatal_error(int unit)

+{

+  /* XXX */

+  return 0;

+}

+#endif

+

+/*

+ * get_idle_time - return how long the link has been idle.

+ */

+int

+get_idle_time(int u, struct ppp_idle *ip)

+{

+  /* XXX */

+  LWIP_UNUSED_ARG(u);

+  LWIP_UNUSED_ARG(ip);

+

+  return 0;

+}

+

+

+/*

+ * Return user specified netmask, modified by any mask we might determine

+ * for address `addr' (in network byte order).

+ * Here we scan through the system's list of interfaces, looking for

+ * any non-point-to-point interfaces which might appear to be on the same

+ * network as `addr'.  If we find any, we OR in their netmask to the

+ * user-specified netmask.

+ */

+u32_t

+GetMask(u32_t addr)

+{

+  u32_t mask, nmask;

+

+  htonl(addr);

+  if (IN_CLASSA(addr)) { /* determine network mask for address class */

+    nmask = IN_CLASSA_NET;

+  } else if (IN_CLASSB(addr)) {

+    nmask = IN_CLASSB_NET;

+  } else { 

+    nmask = IN_CLASSC_NET;

+  }

+

+  /* class D nets are disallowed by bad_ip_adrs */

+  mask = subnetMask | htonl(nmask);

+  

+  /* XXX

+   * Scan through the system's network interfaces.

+   * Get each netmask and OR them into our mask.

+   */

+

+  return mask;

+}

+

+/*

+ * sifvjcomp - config tcp header compression

+ */

+int

+sifvjcomp( int pd, int vjcomp, int cidcomp, int maxcid)

+{

+#if PPPOS_SUPPORT && VJ_SUPPORT

+  PPPControl *pc = &pppControl[pd];

+  

+  pc->vjEnabled = vjcomp;

+  pc->vjComp.compressSlot = cidcomp;

+  pc->vjComp.maxSlotIndex = maxcid;

+  PPPDEBUG((LOG_INFO, "sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",

+            vjcomp, cidcomp, maxcid));

+#endif /* PPPOS_SUPPORT && VJ_SUPPORT */

+

+  return 0;

+}

+

+/*

+ * pppifNetifInit - netif init callback

+ */

+static err_t

+pppifNetifInit(struct netif *netif)

+{

+  netif->name[0] = 'p';

+  netif->name[1] = 'p';

+  netif->output = pppifOutput;

+  netif->mtu = pppMTU((int)netif->state);

+  return ERR_OK;

+}

+

+

+/*

+ * sifup - Config the interface up and enable IP packets to pass.

+ */

+int

+sifup(int pd)

+{

+  PPPControl *pc = &pppControl[pd];

+  int st = 1;

+  

+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {

+    st = 0;

+    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));

+  } else {

+    netif_remove(&pc->netif);

+    if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input)) {

+      netif_set_up(&pc->netif);

+#if LWIP_DHCP

+      /* ugly workaround for storing a reference to the ppp related info*/

+      pc->netif.dhcp = (struct dhcp *) &pc->addrs;

+#endif /* LWIP_DHCP */

+      pc->if_up = 1;

+      pc->errCode = PPPERR_NONE;

+

+      PPPDEBUG((LOG_DEBUG, "sifup: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));

+      if(pc->linkStatusCB) {

+        pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs);

+      }

+    } else {

+      st = 0;

+      PPPDEBUG((LOG_ERR, "sifup[%d]: netif_add failed\n", pd));

+    }

+  }

+

+  return st;

+}

+

+/*

+ * sifnpmode - Set the mode for handling packets for a given NP.

+ */

+int

+sifnpmode(int u, int proto, enum NPmode mode)

+{

+  LWIP_UNUSED_ARG(u);

+  LWIP_UNUSED_ARG(proto);

+  LWIP_UNUSED_ARG(mode);

+  return 0;

+}

+

+/*

+ * sifdown - Config the interface down and disable IP.

+ */

+int

+sifdown(int pd)

+{

+  PPPControl *pc = &pppControl[pd];

+  int st = 1;

+  

+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {

+    st = 0;

+    PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd));

+  } else {

+    pc->if_up = 0;

+    netif_remove(&pc->netif);

+    PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));

+    if(pc->linkStatusCB) {

+      pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);

+    }

+  }

+  return st;

+}

+

+/**

+ * sifaddr - Config the interface IP addresses and netmask.

+ * @param pd Interface unit ???

+ * @param o Our IP address ???

+ * @param h His IP address ???

+ * @param m IP subnet mask ???

+ * @param ns1 Primary DNS

+ * @param ns2 Secondary DNS

+ */

+int

+sifaddr( int pd, u32_t o, u32_t h, u32_t m, u32_t ns1, u32_t ns2)

+{

+  PPPControl *pc = &pppControl[pd];

+  int st = 1;

+  

+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {

+    st = 0;

+    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));

+  } else {

+    SMEMCPY(&pc->addrs.our_ipaddr, &o, sizeof(o));

+    SMEMCPY(&pc->addrs.his_ipaddr, &h, sizeof(h));

+    SMEMCPY(&pc->addrs.netmask, &m, sizeof(m));

+    SMEMCPY(&pc->addrs.dns1, &ns1, sizeof(ns1));

+    SMEMCPY(&pc->addrs.dns2, &ns2, sizeof(ns2));

+  }

+  return st;

+}

+

+/**

+ * cifaddr - Clear the interface IP addresses, and delete routes

+ * through the interface if possible.

+ * @param pd Interface unit ???

+ * @param o Our IP address ???

+ * @param h IP broadcast address ???

+ */

+int

+cifaddr( int pd, u32_t o, u32_t h)

+{

+  PPPControl *pc = &pppControl[pd];

+  int st = 1;

+  

+  LWIP_UNUSED_ARG(o);

+  LWIP_UNUSED_ARG(h);

+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {

+    st = 0;

+    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));

+  } else {

+    IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0);

+    IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0);

+    IP4_ADDR(&pc->addrs.netmask, 255,255,255,0);

+    IP4_ADDR(&pc->addrs.dns1, 0,0,0,0);

+    IP4_ADDR(&pc->addrs.dns2, 0,0,0,0);

+  }

+  return st;

+}

+

+/*

+ * sifdefaultroute - assign a default route through the address given.

+ */

+int

+sifdefaultroute(int pd, u32_t l, u32_t g)

+{

+  PPPControl *pc = &pppControl[pd];

+  int st = 1;

+

+  LWIP_UNUSED_ARG(l);

+  LWIP_UNUSED_ARG(g);

+

+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {

+    st = 0;

+    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));

+  } else {

+    netif_set_default(&pc->netif);

+  }

+

+  /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */

+

+  return st;

+}

+

+/*

+ * cifdefaultroute - delete a default route through the address given.

+ */

+int

+cifdefaultroute(int pd, u32_t l, u32_t g)

+{

+  PPPControl *pc = &pppControl[pd];

+  int st = 1;

+

+  LWIP_UNUSED_ARG(l);

+  LWIP_UNUSED_ARG(g);

+

+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {

+    st = 0;

+    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));

+  } else {

+    netif_set_default(NULL);

+  }

+

+  return st;

+}

+

+/**********************************/

+/*** LOCAL FUNCTION DEFINITIONS ***/

+/**********************************/

+

+#if PPPOS_SUPPORT

+/* The main PPP process function.  This implements the state machine according

+ * to section 4 of RFC 1661: The Point-To-Point Protocol. */

+static void

+pppMain(void *arg)

+{

+  int pd = (int)arg;

+  struct pbuf *p;

+  PPPControl* pc;

+  int c;

+

+  pc = &pppControl[pd];

+

+  p = pbuf_alloc(PBUF_RAW, PPP_MRU+PPP_HDRLEN, PBUF_RAM);

+  if (!p) {

+    LWIP_ASSERT("p != NULL", p);

+    pc->errCode = PPPERR_ALLOC;

+    goto out;

+  }

+

+  /*

+   * Start the connection and handle incoming events (packet or timeout).

+   */

+  PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd));

+  tcpip_callback(pppStartCB, arg);

+  while (lcp_phase[pd] != PHASE_DEAD) {

+    if (pc->kill_link) {

+      PPPDEBUG((LOG_DEBUG, "pppMain: unit %d kill_link -> pppStopCB\n", pd));

+      pc->errCode = PPPERR_USER;

+      /* This will leave us at PHASE_DEAD. */

+      tcpip_callback(pppStopCB, arg);

+      pc->kill_link = 0;

+    } else if (pc->sig_hup) {

+      PPPDEBUG((LOG_DEBUG, "pppMain: unit %d sig_hup -> pppHupCB\n", pd));

+      pc->sig_hup = 0;

+      tcpip_callback(pppHupCB, arg);

+    } else {

+      c = sio_read(pc->fd, p->payload, p->len);

+      if(c > 0) {

+        pppInProc(pd, p->payload, c);

+      } else {

+        PPPDEBUG((LOG_DEBUG, "pppMain: unit %d sio_read len=%d returned %d\n", pd, p->len, c));

+        sys_msleep(1); /* give other tasks a chance to run */

+      }

+    }

+  }

+  PPPDEBUG((LOG_INFO, "pppMain: unit %d: PHASE_DEAD\n", pd));

+  pppDrop(pc); /* bug fix #17726 */

+  pbuf_free(p);

+

+out:

+  PPPDEBUG((LOG_DEBUG, "pppMain: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));

+  if(pc->linkStatusCB) {

+    pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);

+  }

+

+  pc->openFlag = 0;

+}

+#endif /* PPPOS_SUPPORT */

+

+#if PPPOE_SUPPORT

+

+void

+pppOverEthernetInitFailed(void* arg)

+{

+  PPPControl* pc;

+  int pd = (int)arg;

+

+  pppHupCB(arg);

+  pppStopCB(arg);

+

+  pc = &pppControl[pd];

+  pppoe_destroy(&pc->netif);

+  pc->openFlag = 0;

+

+  if(pc->linkStatusCB) {

+    pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);

+  }

+}

+

+static void

+pppOverEthernetLinkStatusCB(int pd, int up)

+{

+  if(up) {

+    PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd));

+    tcpip_callback(pppStartCB, (void*)pd);

+  } else {

+    PPPControl* pc;

+    pc = &pppControl[pd];

+    tcpip_callback(pppOverEthernetInitFailed, (void*)pd);

+  }

+}

+#endif /* PPPOE_SUPPORT */

+

+struct pbuf *

+pppSingleBuf(struct pbuf *p)

+{

+  struct pbuf *q, *b;

+  u_char *pl;

+

+  if(p->tot_len == p->len) {

+    return p;

+  }

+

+  q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);

+  if(!q) {

+    PPPDEBUG((LOG_ERR,

+             "pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));

+    return p; /* live dangerously */

+  }

+

+  for(b = p, pl = q->payload; b != NULL; b = b->next) {

+    MEMCPY(pl, b->payload, b->len);

+    pl += b->len;

+  }

+

+  pbuf_free(p);

+

+  return q;

+}

+

+struct pppInputHeader {

+  int unit;

+  u16_t proto;

+};

+

+/*

+ * Pass the processed input packet to the appropriate handler.

+ * This function and all handlers run in the context of the tcpip_thread

+ */

+static void

+pppInput(void *arg)

+{

+  struct pbuf *nb = (struct pbuf *)arg;

+  u16_t protocol;

+  int pd;

+

+  pd = ((struct pppInputHeader *)nb->payload)->unit;

+  protocol = ((struct pppInputHeader *)nb->payload)->proto;

+    

+  if(pbuf_header(nb, -(int)sizeof(struct pppInputHeader))) {

+    LWIP_ASSERT("pbuf_header failed\n", 0);

+    goto drop;

+  }

+

+  LINK_STATS_INC(link.recv);

+

+  /*

+   * Toss all non-LCP packets unless LCP is OPEN.

+   * Until we get past the authentication phase, toss all packets

+   * except LCP, LQR and authentication packets.

+   */

+  if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {

+    if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||

+        (lcp_phase[pd] != PHASE_AUTHENTICATE)) {

+      PPPDEBUG((LOG_INFO, "pppInput: discarding proto 0x%04X in phase %d\n", protocol, lcp_phase[pd]));

+      goto drop;

+    }

+  }

+

+  switch(protocol) {

+    case PPP_VJC_COMP:      /* VJ compressed TCP */

+#if VJ_SUPPORT

+      PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));

+      /*

+       * Clip off the VJ header and prepend the rebuilt TCP/IP header and

+       * pass the result to IP.

+       */

+      if ((vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) && (pppControl[pd].netif.input)) {

+        pppControl[pd].netif.input(nb, &pppControl[pd].netif);

+        return;

+      }

+      /* Something's wrong so drop it. */

+      PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ compressed\n", pd));

+#else  /* VJ_SUPPORT */

+      /* No handler for this protocol so drop the packet. */

+      PPPDEBUG((LOG_INFO, "pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));

+#endif /* VJ_SUPPORT */

+      break;

+

+    case PPP_VJC_UNCOMP:    /* VJ uncompressed TCP */

+#if VJ_SUPPORT

+      PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));

+      /*

+       * Process the TCP/IP header for VJ header compression and then pass

+       * the packet to IP.

+       */

+      if ((vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) && pppControl[pd].netif.input) {

+        pppControl[pd].netif.input(nb, &pppControl[pd].netif);

+        return;

+      }

+      /* Something's wrong so drop it. */

+      PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ uncompressed\n", pd));

+#else  /* VJ_SUPPORT */

+      /* No handler for this protocol so drop the packet. */

+      PPPDEBUG((LOG_INFO,

+               "pppInput[%d]: drop VJ UnComp in %d:.*H\n", 

+                pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));

+#endif /* VJ_SUPPORT */

+      break;

+

+    case PPP_IP:            /* Internet Protocol */

+      PPPDEBUG((LOG_INFO, "pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));

+      if (pppControl[pd].netif.input) {

+        pppControl[pd].netif.input(nb, &pppControl[pd].netif);

+        return;

+      }

+      break;

+

+    default: {

+      struct protent *protp;

+      int i;

+

+      /*

+       * Upcall the proper protocol input routine.

+       */

+      for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {

+        if (protp->protocol == protocol && protp->enabled_flag) {

+          PPPDEBUG((LOG_INFO, "pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));

+          nb = pppSingleBuf(nb);

+          (*protp->input)(pd, nb->payload, nb->len);

+          goto out;

+        }

+      }

+

+      /* No handler for this protocol so reject the packet. */

+      PPPDEBUG((LOG_INFO, "pppInput[%d]: rejecting unsupported proto 0x%04X len=%d\n", pd, protocol, nb->len));

+      if (pbuf_header(nb, sizeof(protocol))) {

+        LWIP_ASSERT("pbuf_header failed\n", 0);

+        goto drop;

+      }

+#if BYTE_ORDER == LITTLE_ENDIAN

+      protocol = htons(protocol);

+      SMEMCPY(nb->payload, &protocol, sizeof(protocol));

+#endif /* BYTE_ORDER == LITTLE_ENDIAN */

+      lcp_sprotrej(pd, nb->payload, nb->len);

+    }

+    break;

+  }

+

+drop:

+  LINK_STATS_INC(link.drop);

+

+out:

+  pbuf_free(nb);

+  return;

+}

+

+#if PPPOS_SUPPORT

+/*

+ * Drop the input packet.

+ */

+static void

+pppDrop(PPPControl *pc)

+{

+  if (pc->inHead != NULL) {

+#if 0

+    PPPDEBUG((LOG_INFO, "pppDrop: %d:%.*H\n", pc->inHead->len, min(60, pc->inHead->len * 2), pc->inHead->payload));

+#endif

+    PPPDEBUG((LOG_INFO, "pppDrop: pbuf len=%d\n", pc->inHead->len));

+    if (pc->inTail && (pc->inTail != pc->inHead)) {

+      pbuf_free(pc->inTail);

+    }

+    pbuf_free(pc->inHead);

+    pc->inHead = NULL;

+    pc->inTail = NULL;

+  }

+#if VJ_SUPPORT

+  vj_uncompress_err(&pc->vjComp);

+#endif /* VJ_SUPPORT */

+

+  LINK_STATS_INC(link.drop);

+}

+

+/**

+ * Process a received octet string.

+ */

+static void

+pppInProc(int pd, u_char *s, int l)

+{

+  PPPControl *pc = &pppControl[pd];

+  struct pbuf *nextNBuf;

+  u_char curChar;

+

+  PPPDEBUG((LOG_DEBUG, "pppInProc[%d]: got %d bytes\n", pd, l));

+  while (l-- > 0) {

+    curChar = *s++;

+    

+    /* Handle special characters. */

+    if (ESCAPE_P(pc->inACCM, curChar)) {

+      /* Check for escape sequences. */

+      /* XXX Note that this does not handle an escaped 0x5d character which

+       * would appear as an escape character.  Since this is an ASCII ']'

+       * and there is no reason that I know of to escape it, I won't complicate

+       * the code to handle this case. GLL */

+      if (curChar == PPP_ESCAPE) {

+        pc->inEscaped = 1;

+      /* Check for the flag character. */

+      } else if (curChar == PPP_FLAG) {

+         /* If this is just an extra flag character, ignore it. */

+         if (pc->inState <= PDADDRESS) {

+           /* ignore it */;

+         /* If we haven't received the packet header, drop what has come in. */

+         } else if (pc->inState < PDDATA) {

+           PPPDEBUG((LOG_WARNING,

+                    "pppInProc[%d]: Dropping incomplete packet %d\n", 

+                     pd, pc->inState));

+           LINK_STATS_INC(link.lenerr);

+           pppDrop(pc);

+         /* If the fcs is invalid, drop the packet. */

+         } else if (pc->inFCS != PPP_GOODFCS) {

+           PPPDEBUG((LOG_INFO,

+                    "pppInProc[%d]: Dropping bad fcs 0x%04X proto=0x%04X\n", 

+                     pd, pc->inFCS, pc->inProtocol));

+           LINK_STATS_INC(link.chkerr);

+           pppDrop(pc);

+         /* Otherwise it's a good packet so pass it on. */

+         } else {

+           /* Trim off the checksum. */

+           if(pc->inTail->len >= 2) {

+             pc->inTail->len -= 2;

+

+             pc->inTail->tot_len = pc->inTail->len;

+             if (pc->inTail != pc->inHead) {

+               pbuf_cat(pc->inHead, pc->inTail);

+             }

+           } else {

+             pc->inTail->tot_len = pc->inTail->len;

+             if (pc->inTail != pc->inHead) {

+               pbuf_cat(pc->inHead, pc->inTail);

+             }

+

+             pbuf_realloc(pc->inHead, pc->inHead->tot_len - 2);

+           }

+

+           /* Dispatch the packet thereby consuming it. */

+           if(tcpip_callback(pppInput, pc->inHead) != ERR_OK) {

+             PPPDEBUG((LOG_ERR, "pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pd));

+             pbuf_free(pc->inHead);

+             LINK_STATS_INC(link.drop);

+           }

+           pc->inHead = NULL;

+           pc->inTail = NULL;

+         }

+

+         /* Prepare for a new packet. */

+         pc->inFCS = PPP_INITFCS;

+         pc->inState = PDADDRESS;

+         pc->inEscaped = 0;

+      /* Other characters are usually control characters that may have

+       * been inserted by the physical layer so here we just drop them. */

+      } else {

+        PPPDEBUG((LOG_WARNING,

+                 "pppInProc[%d]: Dropping ACCM char <%d>\n", pd, curChar));

+      }

+    /* Process other characters. */

+    } else {

+      /* Unencode escaped characters. */

+      if (pc->inEscaped) {

+        pc->inEscaped = 0;

+        curChar ^= PPP_TRANS;

+      }

+

+      /* Process character relative to current state. */

+      switch(pc->inState) {

+        case PDIDLE:                    /* Idle state - waiting. */

+          /* Drop the character if it's not 0xff

+           * we would have processed a flag character above. */

+          if (curChar != PPP_ALLSTATIONS) {

+            break;

+          }

+

+        /* Fall through */

+        case PDSTART:                   /* Process start flag. */

+          /* Prepare for a new packet. */

+          pc->inFCS = PPP_INITFCS;

+

+        /* Fall through */

+        case PDADDRESS:                 /* Process address field. */

+          if (curChar == PPP_ALLSTATIONS) {

+            pc->inState = PDCONTROL;

+            break;

+          }

+          /* Else assume compressed address and control fields so

+           * fall through to get the protocol... */

+        case PDCONTROL:                 /* Process control field. */

+          /* If we don't get a valid control code, restart. */

+          if (curChar == PPP_UI) {

+            pc->inState = PDPROTOCOL1;

+            break;

+          }

+#if 0

+          else {

+            PPPDEBUG((LOG_WARNING,

+                     "pppInProc[%d]: Invalid control <%d>\n", pd, curChar));

+                      pc->inState = PDSTART;

+          }

+#endif

+        case PDPROTOCOL1:               /* Process protocol field 1. */

+          /* If the lower bit is set, this is the end of the protocol

+           * field. */

+          if (curChar & 1) {

+            pc->inProtocol = curChar;

+            pc->inState = PDDATA;

+          } else {

+            pc->inProtocol = (u_int)curChar << 8;

+            pc->inState = PDPROTOCOL2;

+          }

+          break;

+        case PDPROTOCOL2:               /* Process protocol field 2. */

+          pc->inProtocol |= curChar;

+          pc->inState = PDDATA;

+          break;

+        case PDDATA:                    /* Process data byte. */

+          /* Make space to receive processed data. */

+          if (pc->inTail == NULL || pc->inTail->len == PBUF_POOL_BUFSIZE) {

+            if(pc->inTail) {

+              pc->inTail->tot_len = pc->inTail->len;

+              if (pc->inTail != pc->inHead) {

+                pbuf_cat(pc->inHead, pc->inTail);

+              }

+            }

+            /* If we haven't started a packet, we need a packet header. */

+            nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);

+            if (nextNBuf == NULL) {

+              /* No free buffers.  Drop the input packet and let the

+               * higher layers deal with it.  Continue processing

+               * the received pbuf chain in case a new packet starts. */

+              PPPDEBUG((LOG_ERR, "pppInProc[%d]: NO FREE MBUFS!\n", pd));

+              LINK_STATS_INC(link.memerr);

+              pppDrop(pc);

+              pc->inState = PDSTART;  /* Wait for flag sequence. */

+              break;

+            }

+            if (pc->inHead == NULL) {

+              struct pppInputHeader *pih = nextNBuf->payload;

+

+              pih->unit = pd;

+              pih->proto = pc->inProtocol;

+

+              nextNBuf->len += sizeof(*pih);

+

+              pc->inHead = nextNBuf;

+            }

+            pc->inTail = nextNBuf;

+          }

+          /* Load character into buffer. */

+          ((u_char*)pc->inTail->payload)[pc->inTail->len++] = curChar;

+          break;

+      }

+

+      /* update the frame check sequence number. */

+      pc->inFCS = PPP_FCS(pc->inFCS, curChar);

+    }

+  }

+

+  avRandomize();

+}

+#endif /* PPPOS_SUPPORT */

+

+#if PPPOE_SUPPORT

+void

+pppInProcOverEthernet(int pd, struct pbuf *pb)

+{

+  struct pppInputHeader *pih;

+  u16_t inProtocol;

+

+  if(pb->len < sizeof(inProtocol)) {

+    PPPDEBUG((LOG_ERR, "pppInProcOverEthernet: too small for protocol field\n"));

+    goto drop;

+  }

+

+  inProtocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1];

+

+  /* make room for pppInputHeader - should not fail */

+  if (pbuf_header(pb, sizeof(*pih) - sizeof(inProtocol)) != 0) {

+    PPPDEBUG((LOG_ERR, "pppInProcOverEthernet: could not allocate room for header\n"));

+    goto drop;

+  }

+

+  pih = pb->payload;

+

+  pih->unit = pd;

+  pih->proto = inProtocol;

+

+  /* Dispatch the packet thereby consuming it. */

+  if(tcpip_callback(pppInput, pb) != ERR_OK) {

+    PPPDEBUG((LOG_ERR, "pppInProcOverEthernet[%d]: tcpip_callback() failed, dropping packet\n", pd));

+    goto drop;

+  }

+

+  return;

+

+drop:

+  LINK_STATS_INC(link.drop);

+  pbuf_free(pb);

+  return;

+}

+#endif /* PPPOE_SUPPORT */

+

+#endif /* PPP_SUPPORT */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp.h
new file mode 100644
index 0000000..d610e4b
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp.h
@@ -0,0 +1,465 @@
+/*****************************************************************************

+* ppp.h - Network Point to Point Protocol header file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1997 Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.

+*   Original derived from BSD codes.

+*****************************************************************************/

+

+#ifndef PPP_H

+#define PPP_H

+

+#include "lwip/opt.h"

+

+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#include "lwip/def.h"

+#include "lwip/sio.h"

+#include "lwip/api.h"

+#include "lwip/sockets.h"

+#include "lwip/stats.h"

+#include "lwip/mem.h"

+#include "lwip/tcpip.h"

+#include "lwip/netif.h"

+

+/*

+ * pppd.h - PPP daemon global declarations.

+ *

+ * Copyright (c) 1989 Carnegie Mellon University.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by Carnegie Mellon University.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ *

+ */

+/*

+ * ppp_defs.h - PPP definitions.

+ *

+ * Copyright (c) 1994 The Australian National University.

+ * All rights reserved.

+ *

+ * Permission to use, copy, modify, and distribute this software and its

+ * documentation is hereby granted, provided that the above copyright

+ * notice appears in all copies.  This software is provided without any

+ * warranty, express or implied. The Australian National University

+ * makes no representations about the suitability of this software for

+ * any purpose.

+ *

+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY

+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES

+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF

+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,

+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY

+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS

+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO

+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,

+ * OR MODIFICATIONS.

+ */

+

+#define TIMEOUT(f, a, t)    sys_untimeout((f), (a)), sys_timeout((t)*1000, (f), (a))

+#define UNTIMEOUT(f, a)     sys_untimeout((f), (a))

+

+

+#ifndef __u_char_defined

+

+/* Type definitions for BSD code. */

+typedef unsigned long  u_long;

+typedef unsigned int   u_int;

+typedef unsigned short u_short;

+typedef unsigned char  u_char;

+

+#endif

+

+/*

+ * Constants and structures defined by the internet system,

+ * Per RFC 790, September 1981, and numerous additions.

+ */

+

+/*

+ * The basic PPP frame.

+ */

+#define PPP_HDRLEN      4       /* octets for standard ppp header */

+#define PPP_FCSLEN      2       /* octets for FCS */

+

+

+/*

+ * Significant octet values.

+ */

+#define PPP_ALLSTATIONS 0xff    /* All-Stations broadcast address */

+#define PPP_UI          0x03    /* Unnumbered Information */

+#define PPP_FLAG        0x7e    /* Flag Sequence */

+#define PPP_ESCAPE      0x7d    /* Asynchronous Control Escape */

+#define PPP_TRANS       0x20    /* Asynchronous transparency modifier */

+

+/*

+ * Protocol field values.

+ */

+#define PPP_IP          0x21    /* Internet Protocol */

+#define PPP_AT          0x29    /* AppleTalk Protocol */

+#define PPP_VJC_COMP    0x2d    /* VJ compressed TCP */

+#define PPP_VJC_UNCOMP  0x2f    /* VJ uncompressed TCP */

+#define PPP_COMP        0xfd    /* compressed packet */

+#define PPP_IPCP        0x8021  /* IP Control Protocol */

+#define PPP_ATCP        0x8029  /* AppleTalk Control Protocol */

+#define PPP_CCP         0x80fd  /* Compression Control Protocol */

+#define PPP_LCP         0xc021  /* Link Control Protocol */

+#define PPP_PAP         0xc023  /* Password Authentication Protocol */

+#define PPP_LQR         0xc025  /* Link Quality Report protocol */

+#define PPP_CHAP        0xc223  /* Cryptographic Handshake Auth. Protocol */

+#define PPP_CBCP        0xc029  /* Callback Control Protocol */

+

+/*

+ * Values for FCS calculations.

+ */

+#define PPP_INITFCS     0xffff  /* Initial FCS value */

+#define PPP_GOODFCS     0xf0b8  /* Good final FCS value */

+#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])

+

+/*

+ * Extended asyncmap - allows any character to be escaped.

+ */

+typedef u_char  ext_accm[32];

+

+/*

+ * What to do with network protocol (NP) packets.

+ */

+enum NPmode {

+  NPMODE_PASS,        /* pass the packet through */

+  NPMODE_DROP,        /* silently drop the packet */

+  NPMODE_ERROR,       /* return an error */

+  NPMODE_QUEUE        /* save it up for later. */

+};

+

+/*

+ * Inline versions of get/put char/short/long.

+ * Pointer is advanced; we assume that both arguments

+ * are lvalues and will already be in registers.

+ * cp MUST be u_char *.

+ */

+#define GETCHAR(c, cp) { \

+    (c) = *(cp)++; \

+}

+#define PUTCHAR(c, cp) { \

+    *(cp)++ = (u_char) (c); \

+}

+

+

+#define GETSHORT(s, cp) { \

+    (s) = *(cp); (cp)++; (s) <<= 8; \

+    (s) |= *(cp); (cp)++; \

+}

+#define PUTSHORT(s, cp) { \

+    *(cp)++ = (u_char) ((s) >> 8); \

+    *(cp)++ = (u_char) (s & 0xff); \

+}

+

+#define GETLONG(l, cp) { \

+    (l) = *(cp); (cp)++; (l) <<= 8; \

+    (l) |= *(cp); (cp)++; (l) <<= 8; \

+    (l) |= *(cp); (cp)++; (l) <<= 8; \

+    (l) |= *(cp); (cp)++; \

+}

+#define PUTLONG(l, cp) { \

+    *(cp)++ = (u_char) ((l) >> 24); \

+    *(cp)++ = (u_char) ((l) >> 16); \

+    *(cp)++ = (u_char) ((l) >> 8); \

+    *(cp)++ = (u_char) (l); \

+}

+

+

+#define INCPTR(n, cp)   ((cp) += (n))

+#define DECPTR(n, cp)   ((cp) -= (n))

+

+#define BCMP(s0, s1, l)     memcmp((u_char *)(s0), (u_char *)(s1), (l))

+#define BCOPY(s, d, l)      MEMCPY((d), (s), (l))

+#define BZERO(s, n)         memset(s, 0, n)

+

+#if PPP_DEBUG

+#define PRINTMSG(m, l)  { m[l] = '\0'; ppp_trace(LOG_INFO, "Remote message: %s\n", m); }

+#else  /* PPP_DEBUG */

+#define PRINTMSG(m, l)

+#endif /* PPP_DEBUG */

+

+/*

+ * MAKEHEADER - Add PPP Header fields to a packet.

+ */

+#define MAKEHEADER(p, t) { \

+    PUTCHAR(PPP_ALLSTATIONS, p); \

+    PUTCHAR(PPP_UI, p); \

+    PUTSHORT(t, p); }

+

+/*************************

+*** PUBLIC DEFINITIONS ***

+*************************/

+

+/* Error codes. */

+#define PPPERR_NONE      0 /* No error. */

+#define PPPERR_PARAM    -1 /* Invalid parameter. */

+#define PPPERR_OPEN     -2 /* Unable to open PPP session. */

+#define PPPERR_DEVICE   -3 /* Invalid I/O device for PPP. */

+#define PPPERR_ALLOC    -4 /* Unable to allocate resources. */

+#define PPPERR_USER     -5 /* User interrupt. */

+#define PPPERR_CONNECT  -6 /* Connection lost. */

+#define PPPERR_AUTHFAIL -7 /* Failed authentication challenge. */

+#define PPPERR_PROTOCOL -8 /* Failed to meet protocol. */

+

+/*

+ * PPP IOCTL commands.

+ */

+/*

+ * Get the up status - 0 for down, non-zero for up.  The argument must

+ * point to an int.

+ */

+#define PPPCTLG_UPSTATUS 100 /* Get the up status - 0 down else up */

+#define PPPCTLS_ERRCODE  101 /* Set the error code */

+#define PPPCTLG_ERRCODE  102 /* Get the error code */

+#define PPPCTLG_FD       103 /* Get the fd associated with the ppp */

+

+/************************

+*** PUBLIC DATA TYPES ***

+************************/

+

+/*

+ * The following struct gives the addresses of procedures to call

+ * for a particular protocol.

+ */

+struct protent {

+    u_short protocol;       /* PPP protocol number */

+    /* Initialization procedure */

+    void (*init) (int unit);

+    /* Process a received packet */

+    void (*input) (int unit, u_char *pkt, int len);

+    /* Process a received protocol-reject */

+    void (*protrej) (int unit);

+    /* Lower layer has come up */

+    void (*lowerup) (int unit);

+    /* Lower layer has gone down */

+    void (*lowerdown) (int unit);

+    /* Open the protocol */

+    void (*open) (int unit);

+    /* Close the protocol */

+    void (*close) (int unit, char *reason);

+#if 0

+    /* Print a packet in readable form */

+    int  (*printpkt) (u_char *pkt, int len,

+              void (*printer) (void *, char *, ...),

+              void *arg);

+    /* Process a received data packet */

+    void (*datainput) (int unit, u_char *pkt, int len);

+#endif

+    int  enabled_flag;      /* 0 iff protocol is disabled */

+    char *name;         /* Text name of protocol */

+#if 0

+    /* Check requested options, assign defaults */

+    void (*check_options) (u_long);

+    /* Configure interface for demand-dial */

+    int  (*demand_conf) (int unit);

+    /* Say whether to bring up link for this pkt */

+    int  (*active_pkt) (u_char *pkt, int len);

+#endif

+};

+

+/*

+ * The following structure records the time in seconds since

+ * the last NP packet was sent or received.

+ */

+struct ppp_idle {

+  u_short xmit_idle;      /* seconds since last NP packet sent */

+  u_short recv_idle;      /* seconds since last NP packet received */

+};

+

+struct ppp_settings {

+

+  u_int  disable_defaultip : 1;       /* Don't use hostname for default IP addrs */

+  u_int  auth_required     : 1;       /* Peer is required to authenticate */

+  u_int  explicit_remote   : 1;       /* remote_name specified with remotename opt */

+  u_int  refuse_pap        : 1;       /* Don't wanna auth. ourselves with PAP */

+  u_int  refuse_chap       : 1;       /* Don't wanna auth. ourselves with CHAP */

+  u_int  usehostname       : 1;       /* Use hostname for our_name */

+  u_int  usepeerdns        : 1;       /* Ask peer for DNS adds */

+

+  u_short idle_time_limit;            /* Shut down link if idle for this long */

+  int  maxconnect;                    /* Maximum connect time (seconds) */

+

+  char user       [MAXNAMELEN   + 1]; /* Username for PAP */

+  char passwd     [MAXSECRETLEN + 1]; /* Password for PAP, secret for CHAP */

+  char our_name   [MAXNAMELEN   + 1]; /* Our name for authentication purposes */

+  char remote_name[MAXNAMELEN   + 1]; /* Peer's name for authentication */

+};

+

+struct ppp_addrs {

+  struct ip_addr our_ipaddr, his_ipaddr, netmask, dns1, dns2;

+};

+

+/*****************************

+*** PUBLIC DATA STRUCTURES ***

+*****************************/

+

+/* Buffers for outgoing packets. */

+extern u_char *outpacket_buf[NUM_PPP];

+

+extern struct ppp_settings ppp_settings;

+

+extern struct protent *ppp_protocols[]; /* Table of pointers to supported protocols */

+

+

+/***********************

+*** PUBLIC FUNCTIONS ***

+***********************/

+

+/* Initialize the PPP subsystem. */

+err_t pppInit(void);

+

+/* Warning: Using PPPAUTHTYPE_ANY might have security consequences.

+ * RFC 1994 says:

+ *

+ * In practice, within or associated with each PPP server, there is a

+ * database which associates "user" names with authentication

+ * information ("secrets").  It is not anticipated that a particular

+ * named user would be authenticated by multiple methods.  This would

+ * make the user vulnerable to attacks which negotiate the least secure

+ * method from among a set (such as PAP rather than CHAP).  If the same

+ * secret was used, PAP would reveal the secret to be used later with

+ * CHAP.

+ *

+ * Instead, for each user name there should be an indication of exactly

+ * one method used to authenticate that user name.  If a user needs to

+ * make use of different authentication methods under different

+ * circumstances, then distinct user names SHOULD be employed, each of

+ * which identifies exactly one authentication method.

+ *

+ */

+enum pppAuthType {

+    PPPAUTHTYPE_NONE,

+    PPPAUTHTYPE_ANY,

+    PPPAUTHTYPE_PAP,

+    PPPAUTHTYPE_CHAP

+};

+

+void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd);

+

+/*

+ * Open a new PPP connection using the given serial I/O device.

+ * This initializes the PPP control block but does not

+ * attempt to negotiate the LCP session.

+ * Return a new PPP connection descriptor on success or

+ * an error code (negative) on failure. 

+ */

+int pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx);

+

+/*

+ * Open a new PPP Over Ethernet (PPPOE) connection.

+ */

+int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx);

+

+/* for source code compatibility */

+#define pppOpen(fd,cb,ls) pppOverSerialOpen(fd,cb,ls)

+

+/*

+ * Close a PPP connection and release the descriptor. 

+ * Any outstanding packets in the queues are dropped.

+ * Return 0 on success, an error code on failure. 

+ */

+int pppClose(int pd);

+

+/*

+ * Indicate to the PPP process that the line has disconnected.

+ */

+void pppSigHUP(int pd);

+

+/*

+ * Get and set parameters for the given connection.

+ * Return 0 on success, an error code on failure. 

+ */

+int  pppIOCtl(int pd, int cmd, void *arg);

+

+/*

+ * Return the Maximum Transmission Unit for the given PPP connection.

+ */

+u_int pppMTU(int pd);

+

+/*

+ * Write n characters to a ppp link.

+ * RETURN: >= 0 Number of characters written, -1 Failed to write to device.

+ */

+int pppWrite(int pd, const u_char *s, int n);

+

+void pppInProcOverEthernet(int pd, struct pbuf *pb);

+

+struct pbuf *pppSingleBuf(struct pbuf *p);

+

+void pppLinkTerminated(int pd);

+

+void pppLinkDown(int pd);

+

+void pppMainWakeup(int pd);

+

+/* Configure i/f transmit parameters */

+void ppp_send_config (int, int, u32_t, int, int);

+/* Set extended transmit ACCM */

+void ppp_set_xaccm (int, ext_accm *);

+/* Configure i/f receive parameters */

+void ppp_recv_config (int, int, u32_t, int, int);

+/* Find out how long link has been idle */

+int  get_idle_time (int, struct ppp_idle *);

+

+/* Configure VJ TCP header compression */

+int  sifvjcomp (int, int, int, int);

+/* Configure i/f down (for IP) */

+int  sifup (int);

+/* Set mode for handling packets for proto */

+int  sifnpmode (int u, int proto, enum NPmode mode);

+/* Configure i/f down (for IP) */

+int  sifdown (int);

+/* Configure IP addresses for i/f */

+int  sifaddr (int, u32_t, u32_t, u32_t, u32_t, u32_t);

+/* Reset i/f IP addresses */

+int  cifaddr (int, u32_t, u32_t);

+/* Create default route through i/f */

+int  sifdefaultroute (int, u32_t, u32_t);

+/* Delete default route through i/f */

+int  cifdefaultroute (int, u32_t, u32_t);

+

+/* Get appropriate netmask for address */

+u32_t GetMask (u32_t); 

+

+#endif /* PPP_SUPPORT */

+

+#endif /* PPP_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp_oe.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp_oe.c
new file mode 100644
index 0000000..2fcffdd
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp_oe.c
@@ -0,0 +1,1227 @@
+/*****************************************************************************

+* ppp_oe.c - PPP Over Ethernet implementation for lwIP.

+*

+* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 06-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+*****************************************************************************/

+

+

+

+/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */

+

+/*-

+ * Copyright (c) 2002 The NetBSD Foundation, Inc.

+ * All rights reserved.

+ *

+ * This code is derived from software contributed to The NetBSD Foundation

+ * by Martin Husemann <martin@NetBSD.org>.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ * 1. Redistributions of source code must retain the above copyright

+ *    notice, this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright

+ *    notice, this list of conditions and the following disclaimer in the

+ *    documentation and/or other materials provided with the distribution.

+ * 3. All advertising materials mentioning features or use of this software

+ *    must display the following acknowledgement:

+ *        This product includes software developed by the NetBSD

+ *        Foundation, Inc. and its contributors.

+ * 4. Neither the name of The NetBSD Foundation nor the names of its

+ *    contributors may be used to endorse or promote products derived

+ *    from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS

+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED

+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR

+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS

+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

+ * POSSIBILITY OF SUCH DAMAGE.

+ */

+

+#include "lwip/opt.h"

+

+#if PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#include "ppp.h"

+#include "pppdebug.h"

+

+#include "lwip/sys.h"

+

+#include "netif/ppp_oe.h"

+#include "netif/etharp.h"

+

+#include <string.h>

+#include <stdio.h>

+

+/** @todo Replace this part with a simple list like other lwIP lists */

+#ifndef _SYS_QUEUE_H_

+#define _SYS_QUEUE_H_

+

+/*

+ * A list is headed by a single forward pointer (or an array of forward

+ * pointers for a hash table header). The elements are doubly linked

+ * so that an arbitrary element can be removed without a need to

+ * traverse the list. New elements can be added to the list before

+ * or after an existing element or at the head of the list. A list

+ * may only be traversed in the forward direction.

+ *

+ * For details on the use of these macros, see the queue(3) manual page.

+ */

+

+/*

+ * List declarations.

+ */

+#define  LIST_HEAD(name, type)                                                 \

+struct name {                                                                  \

+  struct type *lh_first;  /* first element */                                  \

+}

+

+#define  LIST_HEAD_INITIALIZER(head)                                           \

+  { NULL }

+

+#define  LIST_ENTRY(type)                                                      \

+struct {                                                                       \

+  struct type *le_next;  /* next element */                                    \

+  struct type **le_prev; /* address of previous next element */                \

+}

+

+/*

+ * List functions.

+ */

+

+#define  LIST_EMPTY(head)  ((head)->lh_first == NULL)

+

+#define  LIST_FIRST(head)  ((head)->lh_first)

+

+#define  LIST_FOREACH(var, head, field)                                        \

+  for ((var) = LIST_FIRST((head));                                             \

+      (var);                                                                   \

+      (var) = LIST_NEXT((var), field))

+

+#define  LIST_INIT(head) do {                                                  \

+  LIST_FIRST((head)) = NULL;                                                   \

+} while (0)

+

+#define  LIST_INSERT_AFTER(listelm, elm, field) do {                           \

+  if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)         \

+    LIST_NEXT((listelm), field)->field.le_prev =                               \

+        &LIST_NEXT((elm), field);                                              \

+  LIST_NEXT((listelm), field) = (elm);                                         \

+  (elm)->field.le_prev = &LIST_NEXT((listelm), field);                         \

+} while (0)

+

+#define  LIST_INSERT_BEFORE(listelm, elm, field) do {                          \

+  (elm)->field.le_prev = (listelm)->field.le_prev;                             \

+  LIST_NEXT((elm), field) = (listelm);                                         \

+  *(listelm)->field.le_prev = (elm);                                           \

+  (listelm)->field.le_prev = &LIST_NEXT((elm), field);                         \

+} while (0)

+

+#define  LIST_INSERT_HEAD(head, elm, field) do {                               \

+  if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)                  \

+    LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);              \

+  LIST_FIRST((head)) = (elm);                                                  \

+  (elm)->field.le_prev = &LIST_FIRST((head));                                  \

+} while (0)

+

+#define  LIST_NEXT(elm, field)  ((elm)->field.le_next)

+

+#define  LIST_REMOVE(elm, field) do {                                          \

+  if (LIST_NEXT((elm), field) != NULL)                                         \

+    LIST_NEXT((elm), field)->field.le_prev =                                   \

+        (elm)->field.le_prev;                                                  \

+  *(elm)->field.le_prev = LIST_NEXT((elm), field);                             \

+} while (0)

+

+#endif /* !_SYS_QUEUE_H_ */

+

+

+/* Add a 16 bit unsigned value to a buffer pointed to by PTR */

+#define PPPOE_ADD_16(PTR, VAL) \

+    *(PTR)++ = (VAL) / 256;    \

+    *(PTR)++ = (VAL) % 256

+

+/* Add a complete PPPoE header to the buffer pointed to by PTR */

+#define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN)  \

+    *(PTR)++ = PPPOE_VERTYPE;  \

+    *(PTR)++ = (CODE);         \

+    PPPOE_ADD_16(PTR, SESS);   \

+    PPPOE_ADD_16(PTR, LEN)

+

+#define PPPOE_DISC_TIMEOUT (5*1000)  /* base for quick timeout calculation */

+#define PPPOE_SLOW_RETRY   (60*1000) /* persistent retry interval */

+#define PPPOE_DISC_MAXPADI  4        /* retry PADI four times (quickly) */

+#define PPPOE_DISC_MAXPADR  2        /* retry PADR twice */

+

+#ifdef PPPOE_SERVER

+/* from if_spppsubr.c */

+#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */

+#endif

+

+struct pppoe_softc {

+  LIST_ENTRY(pppoe_softc) sc_list;

+  struct netif *sc_ethif;      /* ethernet interface we are using */

+  int sc_pd;                   /* ppp unit number */

+  void (*sc_linkStatusCB)(int pd, int up);

+

+  int sc_state;                /* discovery phase or session connected */

+  struct eth_addr sc_dest;     /* hardware address of concentrator */

+  u16_t sc_session;            /* PPPoE session id */

+

+  char *sc_service_name;       /* if != NULL: requested name of service */

+  char *sc_concentrator_name;  /* if != NULL: requested concentrator id */

+  u8_t *sc_ac_cookie;          /* content of AC cookie we must echo back */

+  size_t sc_ac_cookie_len;     /* length of cookie data */

+#ifdef PPPOE_SERVER

+  u8_t *sc_hunique;            /* content of host unique we must echo back */

+  size_t sc_hunique_len;       /* length of host unique */

+#endif

+  int sc_padi_retried;         /* number of PADI retries already done */

+  int sc_padr_retried;         /* number of PADR retries already done */

+};

+

+/* input routines */

+static void pppoe_dispatch_disc_pkt(struct netif *, struct pbuf *);

+

+/* management routines */

+static int pppoe_do_disconnect(struct pppoe_softc *);

+static void pppoe_abort_connect(struct pppoe_softc *);

+static void pppoe_clear_softc(struct pppoe_softc *, const char *);

+

+/* internal timeout handling */

+static void pppoe_timeout(void *);

+

+/* sending actual protocol controll packets */

+static err_t pppoe_send_padi(struct pppoe_softc *);

+static err_t pppoe_send_padr(struct pppoe_softc *);

+#ifdef PPPOE_SERVER

+static err_t pppoe_send_pado(struct pppoe_softc *);

+static err_t pppoe_send_pads(struct pppoe_softc *);

+#endif

+static err_t pppoe_send_padt(struct netif *, u_int, const u8_t *);

+

+/* internal helper functions */

+static struct pppoe_softc * pppoe_find_softc_by_session(u_int, struct netif *);

+static struct pppoe_softc * pppoe_find_softc_by_hunique(u8_t *, size_t, struct netif *);

+

+static LIST_HEAD(pppoe_softc_head, pppoe_softc) pppoe_softc_list;

+

+int pppoe_hdrlen;

+

+void

+pppoe_init(void)

+{

+  pppoe_hdrlen = sizeof(struct eth_hdr) + PPPOE_HEADERLEN;

+  LIST_INIT(&pppoe_softc_list);

+}

+

+err_t

+pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr)

+{

+  struct pppoe_softc *sc;

+

+  sc = mem_malloc(sizeof(struct pppoe_softc));

+  if(!sc) {

+    *scptr = NULL;

+    return ERR_MEM;

+  }

+  memset(sc, 0, sizeof(struct pppoe_softc));

+

+  /* changed to real address later */

+  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));

+

+  sc->sc_pd = pd;

+  sc->sc_linkStatusCB = linkStatusCB;

+  sc->sc_ethif = ethif;

+

+  LIST_INSERT_HEAD(&pppoe_softc_list, sc, sc_list);

+

+  *scptr = sc;

+

+  return ERR_OK;

+}

+

+err_t

+pppoe_destroy(struct netif *ifp)

+{

+  struct pppoe_softc * sc;

+

+  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {

+    if (sc->sc_ethif == ifp) {

+      break;

+    }

+  }

+

+  if(!(sc && (sc->sc_ethif == ifp))) {

+    return ERR_IF;

+  }

+

+  tcpip_untimeout(pppoe_timeout, sc);

+  LIST_REMOVE(sc, sc_list);

+

+  if (sc->sc_concentrator_name) {

+    mem_free(sc->sc_concentrator_name);

+  }

+  if (sc->sc_service_name) {

+    mem_free(sc->sc_service_name);

+  }

+  if (sc->sc_ac_cookie) {

+    mem_free(sc->sc_ac_cookie);

+  }

+  mem_free(sc);

+

+  return ERR_OK;

+}

+

+/*

+ * Find the interface handling the specified session.

+ * Note: O(number of sessions open), this is a client-side only, mean

+ * and lean implementation, so number of open sessions typically should

+ * be 1.

+ */

+static struct pppoe_softc *

+pppoe_find_softc_by_session(u_int session, struct netif *rcvif)

+{

+  struct pppoe_softc *sc;

+

+  if (session == 0) {

+    return NULL;

+  }

+

+  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {

+    if (sc->sc_state == PPPOE_STATE_SESSION

+        && sc->sc_session == session) {

+      if (sc->sc_ethif == rcvif) {

+        return sc;

+      } else {

+        return NULL;

+      }

+    }

+  }

+  return NULL;

+}

+

+/* Check host unique token passed and return appropriate softc pointer,

+ * or NULL if token is bogus. */

+static struct pppoe_softc *

+pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif)

+{

+  struct pppoe_softc *sc, *t;

+

+  if (LIST_EMPTY(&pppoe_softc_list)) {

+    return NULL;

+  }

+

+  if (len != sizeof sc) {

+    return NULL;

+  }

+  MEMCPY(&t, token, len);

+

+  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {

+    if (sc == t) {

+      break;

+    }

+  }

+

+  if (sc == NULL) {

+    PPPDEBUG((LOG_DEBUG, "pppoe: alien host unique tag, no session found\n"));

+    return NULL;

+  }

+

+  /* should be safe to access *sc now */

+  if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) {

+    printf("%c%c%"U16_F": host unique tag found, but it belongs to a connection in state %d\n",

+      sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_state);

+    return NULL;

+  }

+  if (sc->sc_ethif != rcvif) {

+    printf("%c%c%"U16_F": wrong interface, not accepting host unique\n",

+      sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);

+    return NULL;

+  }

+  return sc;

+}

+

+static void

+pppoe_linkstatus_up(void *arg)

+{

+  struct pppoe_softc *sc = (struct pppoe_softc*)arg;

+

+  sc->sc_linkStatusCB(sc->sc_pd, 1);

+}

+

+/* analyze and handle a single received packet while not in session state */

+static void

+pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb)

+{

+  u16_t tag, len;

+  u16_t session, plen;

+  struct pppoe_softc *sc;

+  const char *err_msg;

+  char devname[6];

+  char *error;

+  u8_t *ac_cookie;

+  size_t ac_cookie_len;

+#ifdef PPPOE_SERVER

+  u8_t *hunique;

+  size_t hunique_len;

+#endif

+  struct pppoehdr *ph;

+  struct pppoetag pt;

+  int off = 0, err, errortag;

+  struct eth_hdr *ethhdr;

+

+  pb = pppSingleBuf(pb);

+

+  strcpy(devname, "pppoe");  /* as long as we don't know which instance */

+  err_msg = NULL;

+  errortag = 0;

+  if (pb->len < sizeof(*ethhdr)) {

+    goto done;

+  }

+  ethhdr = (struct eth_hdr *)pb->payload;

+  off += sizeof(*ethhdr);

+

+  ac_cookie = NULL;

+  ac_cookie_len = 0;

+#ifdef PPPOE_SERVER

+  hunique = NULL;

+  hunique_len = 0;

+#endif

+  session = 0;

+  if (pb->len - off <= PPPOE_HEADERLEN) {

+    printf("pppoe: packet too short: %d\n", pb->len);

+    goto done;

+  }

+

+  ph = (struct pppoehdr *) (ethhdr + 1);

+  if (ph->vertype != PPPOE_VERTYPE) {

+    printf("pppoe: unknown version/type packet: 0x%x\n", ph->vertype);

+    goto done;

+  }

+  session = ntohs(ph->session);

+  plen = ntohs(ph->plen);

+  off += sizeof(*ph);

+

+  if (plen + off > pb->len) {

+    printf("pppoe: packet content does not fit: data available = %d, packet size = %u\n",

+        pb->len - off, plen);

+    goto done;

+  }

+  if(pb->tot_len == pb->len) {

+    pb->tot_len = pb->len = off + plen; /* ignore trailing garbage */

+  }

+  tag = 0;

+  len = 0;

+  sc = NULL;

+  while (off + sizeof(pt) <= pb->len) {

+    MEMCPY(&pt, (u8_t*)pb->payload + off, sizeof(pt));

+    tag = ntohs(pt.tag);

+    len = ntohs(pt.len);

+    if (off + sizeof(pt) + len > pb->len) {

+      printf("pppoe: tag 0x%x len 0x%x is too long\n", tag, len);

+      goto done;

+    }

+    switch (tag) {

+      case PPPOE_TAG_EOL:

+        goto breakbreak;

+      case PPPOE_TAG_SNAME:

+        break;  /* ignored */

+      case PPPOE_TAG_ACNAME:

+        break;  /* ignored */

+      case PPPOE_TAG_HUNIQUE:

+        if (sc != NULL) {

+          break;

+        }

+#ifdef PPPOE_SERVER

+        hunique = (u8_t*)pb->payload + off + sizeof(pt);

+        hunique_len = len;

+#endif

+        sc = pppoe_find_softc_by_hunique((u8_t*)pb->payload + off + sizeof(pt), len, netif);

+        if (sc != NULL) {

+          snprintf(devname, sizeof(devname), "%c%c%"U16_F, sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);

+        }

+        break;

+      case PPPOE_TAG_ACCOOKIE:

+        if (ac_cookie == NULL) {

+          ac_cookie = (u8_t*)pb->payload + off + sizeof(pt);

+          ac_cookie_len = len;

+        }

+        break;

+      case PPPOE_TAG_SNAME_ERR:

+        err_msg = "SERVICE NAME ERROR";

+        errortag = 1;

+        break;

+      case PPPOE_TAG_ACSYS_ERR:

+        err_msg = "AC SYSTEM ERROR";

+        errortag = 1;

+        break;

+      case PPPOE_TAG_GENERIC_ERR:

+        err_msg = "GENERIC ERROR";

+        errortag = 1;

+        break;

+    }

+    if (err_msg) {

+      error = NULL;

+      if (errortag && len) {

+        error = mem_malloc(len+1);

+        if (error) {

+          strncpy(error, (char*)pb->payload + off + sizeof(pt), len);

+          error[len-1] = '\0';

+        }

+      }

+      if (error) {

+        printf("%s: %s: %s\n", devname, err_msg, error);

+        mem_free(error);

+      } else {

+        printf("%s: %s\n", devname, err_msg);

+      }

+      if (errortag) {

+        goto done;

+      }

+    }

+    off += sizeof(pt) + len;

+  }

+

+breakbreak:;

+  switch (ph->code) {

+    case PPPOE_CODE_PADI:

+#ifdef PPPOE_SERVER

+      /*

+       * got service name, concentrator name, and/or host unique.

+       * ignore if we have no interfaces with IFF_PASSIVE|IFF_UP.

+       */

+      if (LIST_EMPTY(&pppoe_softc_list)) {

+        goto done;

+      }

+      LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {

+        if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP)) {

+          continue;

+        }

+        if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) {

+          continue;

+        }

+        if (sc->sc_state == PPPOE_STATE_INITIAL) {

+          break;

+        }

+      }

+      if (sc == NULL) {

+        /* printf("pppoe: free passive interface is not found\n"); */

+        goto done;

+      }

+      if (hunique) {

+        if (sc->sc_hunique) {

+          mem_free(sc->sc_hunique);

+        }

+        sc->sc_hunique = mem_malloc(hunique_len);

+        if (sc->sc_hunique == NULL) {

+          goto done;

+        }

+        sc->sc_hunique_len = hunique_len;

+        MEMCPY(sc->sc_hunique, hunique, hunique_len);

+      }

+      MEMCPY(&sc->sc_dest, eh->ether_shost, sizeof sc->sc_dest);

+      sc->sc_state = PPPOE_STATE_PADO_SENT;

+      pppoe_send_pado(sc);

+      break;

+  #endif /* PPPOE_SERVER */

+    case PPPOE_CODE_PADR:

+  #ifdef PPPOE_SERVER

+      /*

+       * get sc from ac_cookie if IFF_PASSIVE

+       */

+      if (ac_cookie == NULL) {

+        /* be quiet if there is not a single pppoe instance */

+        printf("pppoe: received PADR but not includes ac_cookie\n");

+        goto done;

+      }

+      sc = pppoe_find_softc_by_hunique(ac_cookie, ac_cookie_len, netif);

+      if (sc == NULL) {

+        /* be quiet if there is not a single pppoe instance */

+        if (!LIST_EMPTY(&pppoe_softc_list)) {

+          printf("pppoe: received PADR but could not find request for it\n");

+        }

+        goto done;

+      }

+      if (sc->sc_state != PPPOE_STATE_PADO_SENT) {

+        printf("%c%c%"U16_F": received unexpected PADR\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);

+        goto done;

+      }

+      if (hunique) {

+        if (sc->sc_hunique) {

+          mem_free(sc->sc_hunique);

+        }

+        sc->sc_hunique = mem_malloc(hunique_len);

+        if (sc->sc_hunique == NULL) {

+          goto done;

+        }

+        sc->sc_hunique_len = hunique_len;

+        MEMCPY(sc->sc_hunique, hunique, hunique_len);

+      }

+      pppoe_send_pads(sc);

+      sc->sc_state = PPPOE_STATE_SESSION;

+      tcpip_timeout (100, pppoe_linkstatus_up, sc); /* notify upper layers */

+      break;

+  #else

+      /* ignore, we are no access concentrator */

+      goto done;

+  #endif /* PPPOE_SERVER */

+    case PPPOE_CODE_PADO:

+      if (sc == NULL) {

+        /* be quiet if there is not a single pppoe instance */

+        if (!LIST_EMPTY(&pppoe_softc_list)) {

+          printf("pppoe: received PADO but could not find request for it\n");

+        }

+        goto done;

+      }

+      if (sc->sc_state != PPPOE_STATE_PADI_SENT) {

+        printf("%c%c%"U16_F": received unexpected PADO\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);

+        goto done;

+      }

+      if (ac_cookie) {

+        if (sc->sc_ac_cookie) {

+          mem_free(sc->sc_ac_cookie);

+        }

+        sc->sc_ac_cookie = mem_malloc(ac_cookie_len);

+        if (sc->sc_ac_cookie == NULL) {

+          goto done;

+        }

+        sc->sc_ac_cookie_len = ac_cookie_len;

+        MEMCPY(sc->sc_ac_cookie, ac_cookie, ac_cookie_len);

+      }

+      MEMCPY(&sc->sc_dest, ethhdr->src.addr, sizeof(sc->sc_dest.addr));

+      tcpip_untimeout(pppoe_timeout, sc);

+      sc->sc_padr_retried = 0;

+      sc->sc_state = PPPOE_STATE_PADR_SENT;

+      if ((err = pppoe_send_padr(sc)) != 0) {

+        PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));

+      }

+      tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc);

+      break;

+    case PPPOE_CODE_PADS:

+      if (sc == NULL) {

+        goto done;

+      }

+      sc->sc_session = session;

+      tcpip_untimeout(pppoe_timeout, sc);

+      PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": session 0x%x connected\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, session));

+      sc->sc_state = PPPOE_STATE_SESSION;

+      tcpip_timeout (100, pppoe_linkstatus_up, sc); /* notify upper layers */

+      break;

+    case PPPOE_CODE_PADT:

+      if (sc == NULL) {

+        goto done;

+      }

+      pppoe_clear_softc(sc, "received PADT");

+      break;

+    default:

+      if(sc) {

+        printf("%c%c%"U16_F": unknown code (0x%04x) session = 0x%04x\n",

+            sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num,

+            ph->code, session);

+      } else {

+        printf("pppoe: unknown code (0x%04x) session = 0x%04x\n", ph->code, session);

+      }

+      break;

+  }

+

+done:

+  pbuf_free(pb);

+  return;

+}

+

+void

+pppoe_disc_input(struct netif *netif, struct pbuf *p)

+{

+  /* avoid error messages if there is not a single pppoe instance */

+  if (!LIST_EMPTY(&pppoe_softc_list)) {

+    pppoe_dispatch_disc_pkt(netif, p);

+  } else {

+    pbuf_free(p);

+  }

+}

+

+void

+pppoe_data_input(struct netif *netif, struct pbuf *pb)

+{

+  u16_t session, plen;

+  struct pppoe_softc *sc;

+  struct pppoehdr *ph;

+#ifdef PPPOE_TERM_UNKNOWN_SESSIONS

+  u8_t shost[ETHER_ADDR_LEN];

+#endif

+

+#ifdef PPPOE_TERM_UNKNOWN_SESSIONS

+  MEMCPY(shost, ((struct eth_hdr *)pb->payload)->src.addr, sizeof(shost));

+#endif

+  if (pbuf_header(pb, -(int)sizeof(struct eth_hdr)) != 0) {

+    /* bail out */

+    PPPDEBUG((LOG_ERR, "pppoe_data_input: pbuf_header failed\n"));

+    LINK_STATS_INC(link.lenerr);

+    goto drop;

+  } 

+

+  pb = pppSingleBuf (pb);

+

+  if (pb->len <= PPPOE_HEADERLEN) {

+    printf("pppoe (data): dropping too short packet: %d bytes\n", pb->len);

+    goto drop;

+  }

+

+  if (pb->len < sizeof(*ph)) {

+    printf("pppoe_data_input: could not get PPPoE header\n");

+    goto drop;

+  }

+  ph = (struct pppoehdr *)pb->payload;

+

+  if (ph->vertype != PPPOE_VERTYPE) {

+    printf("pppoe (data): unknown version/type packet: 0x%x\n", ph->vertype);

+    goto drop;

+  }

+  if (ph->code != 0) {

+    goto drop;

+  }

+

+  session = ntohs(ph->session);

+  sc = pppoe_find_softc_by_session(session, netif);

+  if (sc == NULL) {

+#ifdef PPPOE_TERM_UNKNOWN_SESSIONS

+    printf("pppoe: input for unknown session 0x%x, sending PADT\n", session);

+    pppoe_send_padt(netif, session, shost);

+#endif

+    goto drop;

+  }

+

+  plen = ntohs(ph->plen);

+

+  if (pbuf_header(pb, -(int)(PPPOE_HEADERLEN)) != 0) {

+    /* bail out */

+    PPPDEBUG((LOG_ERR, "pppoe_data_input: pbuf_header PPPOE_HEADERLEN failed\n"));

+    LINK_STATS_INC(link.lenerr);

+    goto drop;

+  } 

+

+  PPPDEBUG((LOG_DEBUG, "pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n",

+        sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num,

+        pb->len, plen));

+

+  if (pb->len < plen) {

+    goto drop;

+  }

+

+  pppInProcOverEthernet(sc->sc_pd, pb);

+

+  return;

+

+drop:

+  pbuf_free(pb);

+}

+

+static err_t

+pppoe_output(struct pppoe_softc *sc, struct pbuf *pb)

+{

+  struct eth_hdr *ethhdr;

+  u16_t etype;

+  err_t res;

+

+  if (!sc->sc_ethif) {

+    pbuf_free(pb);

+    return ERR_IF;

+  }

+

+  ethhdr = (struct eth_hdr *)pb->payload;

+  etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHTYPE_PPPOE : ETHTYPE_PPPOEDISC;

+  ethhdr->type = htons(etype);

+  MEMCPY(ethhdr->dest.addr, sc->sc_dest.addr, sizeof(ethhdr->dest.addr));

+  MEMCPY(ethhdr->src.addr, ((struct eth_addr *)sc->sc_ethif->hwaddr)->addr, sizeof(ethhdr->src.addr));

+

+  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F" (%x) state=%d, session=0x%x output -> %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F", len=%d\n",

+      sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype,

+      sc->sc_state, sc->sc_session,

+      sc->sc_dest.addr[0], sc->sc_dest.addr[1], sc->sc_dest.addr[2], sc->sc_dest.addr[3], sc->sc_dest.addr[4], sc->sc_dest.addr[5],

+      pb->tot_len));

+

+  res = sc->sc_ethif->linkoutput(sc->sc_ethif, pb);

+

+  pbuf_free(pb);

+

+  return res;

+}

+

+static err_t

+pppoe_send_padi(struct pppoe_softc *sc)

+{

+  struct pbuf *pb;

+  u8_t *p;

+  int len, l1 = 0, l2 = 0; /* XXX: gcc */

+

+  if (sc->sc_state >PPPOE_STATE_PADI_SENT) {

+    PPPDEBUG((LOG_ERR, "ERROR: pppoe_send_padi in state %d", sc->sc_state));

+  }

+

+  /* calculate length of frame (excluding ethernet header + pppoe header) */

+  len = 2 + 2 + 2 + 2 + sizeof sc;  /* service name tag is required, host unique is send too */

+  if (sc->sc_service_name != NULL) {

+    l1 = strlen(sc->sc_service_name);

+    len += l1;

+  }

+  if (sc->sc_concentrator_name != NULL) {

+    l2 = strlen(sc->sc_concentrator_name);

+    len += 2 + 2 + l2;

+  }

+

+  /* allocate a buffer */

+  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);

+  if (!pb) {

+    return ERR_MEM;

+  }

+

+  p = (u8_t*)pb->payload + sizeof (struct eth_hdr);

+  /* fill in pkt */

+  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, len);

+  PPPOE_ADD_16(p, PPPOE_TAG_SNAME);

+  if (sc->sc_service_name != NULL) {

+    PPPOE_ADD_16(p, l1);

+    MEMCPY(p, sc->sc_service_name, l1);

+    p += l1;

+  } else {

+    PPPOE_ADD_16(p, 0);

+  }

+  if (sc->sc_concentrator_name != NULL) {

+    PPPOE_ADD_16(p, PPPOE_TAG_ACNAME);

+    PPPOE_ADD_16(p, l2);

+    MEMCPY(p, sc->sc_concentrator_name, l2);

+    p += l2;

+  }

+  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);

+  PPPOE_ADD_16(p, sizeof(sc));

+  MEMCPY(p, &sc, sizeof sc);

+

+  /* send pkt */

+  return pppoe_output(sc, pb);

+}

+

+static void

+pppoe_timeout(void *arg)

+{

+  int retry_wait, err;

+  struct pppoe_softc *sc = (struct pppoe_softc*)arg;

+

+  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));

+

+  switch (sc->sc_state) {

+    case PPPOE_STATE_PADI_SENT:

+      /*

+       * We have two basic ways of retrying:

+       *  - Quick retry mode: try a few times in short sequence

+       *  - Slow retry mode: we already had a connection successfully

+       *    established and will try infinitely (without user

+       *    intervention)

+       * We only enter slow retry mode if IFF_LINK1 (aka autodial)

+       * is not set.

+       */

+

+      /* initialize for quick retry mode */

+      retry_wait = PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried);

+

+      sc->sc_padi_retried++;

+      if (sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) {

+#if 0

+        if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) {

+          /* slow retry mode */

+          retry_wait = PPPOE_SLOW_RETRY;

+        } else

+#endif

+        {

+          pppoe_abort_connect(sc);

+          return;

+        }

+      }

+      if ((err = pppoe_send_padi(sc)) != 0) {

+        sc->sc_padi_retried--;

+        PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to transmit PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));

+      }

+      tcpip_timeout(retry_wait, pppoe_timeout, sc);

+      break;

+

+    case PPPOE_STATE_PADR_SENT:

+      sc->sc_padr_retried++;

+      if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) {

+        MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));

+        sc->sc_state = PPPOE_STATE_PADI_SENT;

+        sc->sc_padr_retried = 0;

+        if ((err = pppoe_send_padi(sc)) != 0) {

+          PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));

+        }

+        tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc);

+        return;

+      }

+      if ((err = pppoe_send_padr(sc)) != 0) {

+        sc->sc_padr_retried--;

+        PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));

+      }

+      tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc);

+      break;

+    case PPPOE_STATE_CLOSING:

+      pppoe_do_disconnect(sc);

+      break;

+    default:

+      return;  /* all done, work in peace */

+  }

+}

+

+/* Start a connection (i.e. initiate discovery phase) */

+int

+pppoe_connect(struct pppoe_softc *sc)

+{

+  int err;

+

+  if (sc->sc_state != PPPOE_STATE_INITIAL) {

+    return EBUSY;

+  }

+

+#ifdef PPPOE_SERVER

+  /* wait PADI if IFF_PASSIVE */

+  if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) {

+    return 0;

+  }

+#endif

+  /* save state, in case we fail to send PADI */

+  sc->sc_state = PPPOE_STATE_PADI_SENT;

+  sc->sc_padr_retried = 0;

+  err = pppoe_send_padi(sc);

+  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));

+  tcpip_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc);

+  return err;

+}

+

+/* disconnect */

+void

+pppoe_disconnect(struct pppoe_softc *sc)

+{

+  if (sc->sc_state < PPPOE_STATE_SESSION) {

+    return;

+  }

+  /*

+   * Do not call pppoe_disconnect here, the upper layer state

+   * machine gets confused by this. We must return from this

+   * function and defer disconnecting to the timeout handler.

+   */

+  sc->sc_state = PPPOE_STATE_CLOSING;

+  tcpip_timeout(20, pppoe_timeout, sc);

+}

+

+static int

+pppoe_do_disconnect(struct pppoe_softc *sc)

+{

+  int err;

+

+  if (sc->sc_state < PPPOE_STATE_SESSION) {

+    err = EBUSY;

+  } else {

+    PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));

+    err = pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest);

+  }

+

+  /* cleanup softc */

+  sc->sc_state = PPPOE_STATE_INITIAL;

+  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));

+  if (sc->sc_ac_cookie) {

+    mem_free(sc->sc_ac_cookie);

+    sc->sc_ac_cookie = NULL;

+  }

+  sc->sc_ac_cookie_len = 0;

+#ifdef PPPOE_SERVER

+  if (sc->sc_hunique) {

+    mem_free(sc->sc_hunique);

+    sc->sc_hunique = NULL;

+  }

+  sc->sc_hunique_len = 0;

+#endif

+  sc->sc_session = 0;

+

+  sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */

+

+  return err;

+}

+

+/* Connection attempt aborted */

+static void

+pppoe_abort_connect(struct pppoe_softc *sc)

+{

+  printf("%c%c%"U16_F": could not establish connection\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);

+  sc->sc_state = PPPOE_STATE_CLOSING;

+

+  sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */

+

+  /* clear connection state */

+  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));

+  sc->sc_state = PPPOE_STATE_INITIAL;

+}

+

+/* Send a PADR packet */

+static err_t

+pppoe_send_padr(struct pppoe_softc *sc)

+{

+  struct pbuf *pb;

+  u8_t *p;

+  size_t len, l1 = 0; /* XXX: gcc */

+

+  if (sc->sc_state != PPPOE_STATE_PADR_SENT) {

+    return ERR_CONN;

+  }

+

+  len = 2 + 2 + 2 + 2 + sizeof(sc);    /* service name, host unique */

+  if (sc->sc_service_name != NULL) {    /* service name tag maybe empty */

+    l1 = strlen(sc->sc_service_name);

+    len += l1;

+  }

+  if (sc->sc_ac_cookie_len > 0) {

+    len += 2 + 2 + sc->sc_ac_cookie_len;  /* AC cookie */

+  }

+  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);

+  if (!pb) {

+    return ERR_MEM;

+  }

+  p = (u8_t*)pb->payload + sizeof (struct eth_hdr);

+  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len);

+  PPPOE_ADD_16(p, PPPOE_TAG_SNAME);

+  if (sc->sc_service_name != NULL) {

+    PPPOE_ADD_16(p, l1);

+    MEMCPY(p, sc->sc_service_name, l1);

+    p += l1;

+  } else {

+    PPPOE_ADD_16(p, 0);

+  }

+  if (sc->sc_ac_cookie_len > 0) {

+    PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);

+    PPPOE_ADD_16(p, sc->sc_ac_cookie_len);

+    MEMCPY(p, sc->sc_ac_cookie, sc->sc_ac_cookie_len);

+    p += sc->sc_ac_cookie_len;

+  }

+  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);

+  PPPOE_ADD_16(p, sizeof(sc));

+  MEMCPY(p, &sc, sizeof sc);

+

+  return pppoe_output(sc, pb);

+}

+

+/* send a PADT packet */

+static err_t

+pppoe_send_padt(struct netif *outgoing_if, u_int session, const u8_t *dest)

+{

+  struct pbuf *pb;

+  struct eth_hdr *ethhdr;

+  err_t res;

+  u8_t *p;

+

+  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN, PBUF_RAM);

+  if (!pb) {

+    return ERR_MEM;

+  }

+

+  ethhdr = (struct eth_hdr *)pb->payload;

+  ethhdr->type = htons(ETHTYPE_PPPOEDISC);

+  MEMCPY(ethhdr->dest.addr, dest, sizeof(ethhdr->dest.addr));

+  MEMCPY(ethhdr->src.addr, ((struct eth_addr *)outgoing_if->hwaddr)->addr, sizeof(ethhdr->src.addr));

+

+  p = (u8_t*)(ethhdr + 1);

+  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0);

+

+  res = outgoing_if->linkoutput(outgoing_if, pb);

+

+  pbuf_free(pb);

+

+  return res;

+}

+

+#ifdef PPPOE_SERVER

+static err_t

+pppoe_send_pado(struct pppoe_softc *sc)

+{

+  struct pbuf *pb;

+  u8_t *p;

+  size_t len;

+

+  if (sc->sc_state != PPPOE_STATE_PADO_SENT) {

+    return ERR_CONN;

+  }

+

+  /* calc length */

+  len = 0;

+  /* include ac_cookie */

+  len += 2 + 2 + sizeof(sc);

+  /* include hunique */

+  len += 2 + 2 + sc->sc_hunique_len;

+  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);

+  if (!pb) {

+    return ERR_MEM;

+  }

+  p = (u8_t*)pb->payload + sizeof (struct eth_hdr);

+  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len);

+  PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);

+  PPPOE_ADD_16(p, sizeof(sc));

+  MEMCPY(p, &sc, sizeof(sc));

+  p += sizeof(sc);

+  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);

+  PPPOE_ADD_16(p, sc->sc_hunique_len);

+  MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len);

+  return pppoe_output(sc, pb);

+}

+

+static err_t

+pppoe_send_pads(struct pppoe_softc *sc)

+{

+  struct pbuf *pb;

+  u8_t *p;

+  size_t len, l1 = 0;  /* XXX: gcc */

+

+  if (sc->sc_state != PPPOE_STATE_PADO_SENT) {

+    return ERR_CONN;

+  }

+

+  sc->sc_session = mono_time.tv_sec % 0xff + 1;

+  /* calc length */

+  len = 0;

+  /* include hunique */

+  len += 2 + 2 + 2 + 2 + sc->sc_hunique_len;  /* service name, host unique*/

+  if (sc->sc_service_name != NULL) {    /* service name tag maybe empty */

+    l1 = strlen(sc->sc_service_name);

+    len += l1;

+  }

+  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);

+  if (!pb) {

+    return ERR_MEM;

+  }

+  p = (u8_t*)pb->payload + sizeof (struct eth_hdr);

+  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len);

+  PPPOE_ADD_16(p, PPPOE_TAG_SNAME);

+  if (sc->sc_service_name != NULL) {

+    PPPOE_ADD_16(p, l1);

+    MEMCPY(p, sc->sc_service_name, l1);

+    p += l1;

+  } else {

+    PPPOE_ADD_16(p, 0);

+  }

+  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);

+  PPPOE_ADD_16(p, sc->sc_hunique_len);

+  MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len);

+  return pppoe_output(sc, pb);

+}

+#endif

+

+err_t

+pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb)

+{

+  u8_t *p;

+  size_t len;

+

+  /* are we ready to process data yet? */

+  if (sc->sc_state < PPPOE_STATE_SESSION) {

+    /*sppp_flush(&sc->sc_sppp.pp_if);*/

+    pbuf_free(pb);

+    return ERR_CONN;

+  }

+

+  len = pb->tot_len;

+

+  /* make room for Ethernet header - should not fail */

+  if (pbuf_header(pb, sizeof(struct eth_hdr) + PPPOE_HEADERLEN) != 0) {

+    /* bail out */

+    PPPDEBUG((LOG_ERR, "pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));

+    LINK_STATS_INC(link.lenerr);

+    pbuf_free(pb);

+    return ERR_BUF;

+  } 

+

+  p = (u8_t*)pb->payload + sizeof(struct eth_hdr);

+  PPPOE_ADD_HEADER(p, 0, sc->sc_session, len);

+

+  return pppoe_output(sc, pb);

+}

+

+#if 0 /*def PFIL_HOOKS*/

+static int

+pppoe_ifattach_hook(void *arg, struct pbuf **mp, struct netif *ifp, int dir)

+{

+  struct pppoe_softc *sc;

+  int s;

+

+  if (mp != (struct pbuf **)PFIL_IFNET_DETACH) {

+    return 0;

+  }

+

+  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {

+    if (sc->sc_ethif != ifp) {

+      continue;

+    }

+    if (sc->sc_sppp.pp_if.if_flags & IFF_UP) {

+      sc->sc_sppp.pp_if.if_flags &= ~(IFF_UP|IFF_RUNNING);

+      printf("%c%c%"U16_F": ethernet interface detached, going down\n",

+          sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);

+    }

+    sc->sc_ethif = NULL;

+    pppoe_clear_softc(sc, "ethernet interface detached");

+  }

+

+  return 0;

+}

+#endif

+

+static void

+pppoe_clear_softc(struct pppoe_softc *sc, const char *message)

+{

+  LWIP_UNUSED_ARG(message);

+

+  /* stop timer */

+  tcpip_untimeout(pppoe_timeout, sc);

+  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": session 0x%x terminated, %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_session, message));

+

+  /* fix our state */

+  sc->sc_state = PPPOE_STATE_INITIAL;

+

+  /* notify upper layers */

+  sc->sc_linkStatusCB(sc->sc_pd, 0);

+

+  /* clean up softc */

+  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));

+  if (sc->sc_ac_cookie) {

+    mem_free(sc->sc_ac_cookie);

+    sc->sc_ac_cookie = NULL;

+  }

+  sc->sc_ac_cookie_len = 0;

+  sc->sc_session = 0;

+}

+

+#endif /* PPPOE_SUPPORT */

+

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pppdebug.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pppdebug.h
new file mode 100644
index 0000000..77b8d1f
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pppdebug.h
@@ -0,0 +1,86 @@
+/*****************************************************************************

+* pppdebug.h - System debugging utilities.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* portions Copyright (c) 1998 Global Election Systems Inc.

+* portions Copyright (c) 2001 by Cognizant Pty Ltd.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY (please don't use tabs!)

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 98-07-29 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.

+*   Original.

+*

+*****************************************************************************

+*/

+#ifndef PPPDEBUG_H

+#define PPPDEBUG_H

+

+/************************

+*** PUBLIC DATA TYPES ***

+************************/

+/* Trace levels. */

+typedef enum {

+LOG_CRITICAL = 0,

+LOG_ERR      = 1,

+LOG_NOTICE   = 2,

+LOG_WARNING  = 3,

+LOG_INFO     = 5,

+LOG_DETAIL   = 6,

+LOG_DEBUG    = 7

+} LogCodes;

+

+

+/***********************

+*** PUBLIC FUNCTIONS ***

+***********************/

+/*

+ * ppp_trace - a form of printf to send tracing information to stderr

+ */

+void ppp_trace(int level, const char *format,...);

+

+#define TRACELCP PPP_DEBUG

+

+#if PPP_DEBUG

+

+#define AUTHDEBUG(a) ppp_trace a

+#define IPCPDEBUG(a) ppp_trace a

+#define UPAPDEBUG(a) ppp_trace a

+#define LCPDEBUG(a)  ppp_trace a

+#define FSMDEBUG(a)  ppp_trace a

+#define CHAPDEBUG(a) ppp_trace a

+#define PPPDEBUG(a)  ppp_trace a

+

+#else /* PPP_DEBUG */

+

+#define AUTHDEBUG(a)

+#define IPCPDEBUG(a)

+#define UPAPDEBUG(a)

+#define LCPDEBUG(a)

+#define FSMDEBUG(a)

+#define CHAPDEBUG(a)

+#define PPPDEBUG(a)

+

+#endif /* PPP_DEBUG */

+

+#endif /* PPPDEBUG_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/randm.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/randm.c
new file mode 100644
index 0000000..b6c974c
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/randm.c
@@ -0,0 +1,248 @@
+/*****************************************************************************

+* randm.c - Random number generator program file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* Copyright (c) 1998 by Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 98-06-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.

+*   Extracted from avos.

+*****************************************************************************/

+

+#include "lwip/opt.h"

+

+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#include "md5.h"

+#include "randm.h"

+

+#include "ppp.h"

+#include "pppdebug.h"

+

+

+#if MD5_SUPPORT /* this module depends on MD5 */

+#define RANDPOOLSZ 16   /* Bytes stored in the pool of randomness. */

+

+/*****************************/

+/*** LOCAL DATA STRUCTURES ***/

+/*****************************/

+static char randPool[RANDPOOLSZ];   /* Pool of randomness. */

+static long randCount = 0;      /* Pseudo-random incrementer */

+

+

+/***********************************/

+/*** PUBLIC FUNCTION DEFINITIONS ***/

+/***********************************/

+/*

+ * Initialize the random number generator.

+ *

+ * Since this is to be called on power up, we don't have much

+ *  system randomess to work with.  Here all we use is the

+ *  real-time clock.  We'll accumulate more randomness as soon

+ *  as things start happening.

+ */

+void

+avRandomInit()

+{

+  avChurnRand(NULL, 0);

+}

+

+/*

+ * Churn the randomness pool on a random event.  Call this early and often

+ *  on random and semi-random system events to build randomness in time for

+ *  usage.  For randomly timed events, pass a null pointer and a zero length

+ *  and this will use the system timer and other sources to add randomness.

+ *  If new random data is available, pass a pointer to that and it will be

+ *  included.

+ *

+ * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427

+ */

+void

+avChurnRand(char *randData, u32_t randLen)

+{

+  MD5_CTX md5;

+

+  /* ppp_trace(LOG_INFO, "churnRand: %u@%P\n", randLen, randData); */

+  MD5Init(&md5);

+  MD5Update(&md5, (u_char *)randPool, sizeof(randPool));

+  if (randData) {

+    MD5Update(&md5, (u_char *)randData, randLen);

+  } else {

+    struct {

+      /* INCLUDE fields for any system sources of randomness */

+      char foobar;

+    } sysData;

+

+    /* Load sysData fields here. */

+    MD5Update(&md5, (u_char *)&sysData, sizeof(sysData));

+  }

+  MD5Final((u_char *)randPool, &md5);

+/*  ppp_trace(LOG_INFO, "churnRand: -> 0\n"); */

+}

+

+/*

+ * Use the random pool to generate random data.  This degrades to pseudo

+ *  random when used faster than randomness is supplied using churnRand().

+ * Note: It's important that there be sufficient randomness in randPool

+ *  before this is called for otherwise the range of the result may be

+ *  narrow enough to make a search feasible.

+ *

+ * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427

+ *

+ * XXX Why does he not just call churnRand() for each block?  Probably

+ *  so that you don't ever publish the seed which could possibly help

+ *  predict future values.

+ * XXX Why don't we preserve md5 between blocks and just update it with

+ *  randCount each time?  Probably there is a weakness but I wish that

+ *  it was documented.

+ */

+void

+avGenRand(char *buf, u32_t bufLen)

+{

+  MD5_CTX md5;

+  u_char tmp[16];

+  u32_t n;

+

+  while (bufLen > 0) {

+    n = LWIP_MIN(bufLen, RANDPOOLSZ);

+    MD5Init(&md5);

+    MD5Update(&md5, (u_char *)randPool, sizeof(randPool));

+    MD5Update(&md5, (u_char *)&randCount, sizeof(randCount));

+    MD5Final(tmp, &md5);

+    randCount++;

+    MEMCPY(buf, tmp, n);

+    buf += n;

+    bufLen -= n;

+  }

+}

+

+/*

+ * Return a new random number.

+ */

+u32_t

+avRandom()

+{

+  u32_t newRand;

+

+  avGenRand((char *)&newRand, sizeof(newRand));

+

+  return newRand;

+}

+

+#else /* MD5_SUPPORT */

+

+/*****************************/

+/*** LOCAL DATA STRUCTURES ***/

+/*****************************/

+static int  avRandomized = 0;       /* Set when truely randomized. */

+static u32_t avRandomSeed = 0;      /* Seed used for random number generation. */

+

+

+/***********************************/

+/*** PUBLIC FUNCTION DEFINITIONS ***/

+/***********************************/

+/*

+ * Initialize the random number generator.

+ *

+ * Here we attempt to compute a random number seed but even if

+ * it isn't random, we'll randomize it later.

+ *

+ * The current method uses the fields from the real time clock,

+ * the idle process counter, the millisecond counter, and the

+ * hardware timer tick counter.  When this is invoked

+ * in startup(), then the idle counter and timer values may

+ * repeat after each boot and the real time clock may not be

+ * operational.  Thus we call it again on the first random

+ * event.

+ */

+void

+avRandomInit()

+{

+#if 0

+  /* Get a pointer into the last 4 bytes of clockBuf. */

+  u32_t *lptr1 = (u32_t *)((char *)&clockBuf[3]);

+

+  /*

+   * Initialize our seed using the real-time clock, the idle

+   * counter, the millisecond timer, and the hardware timer

+   * tick counter.  The real-time clock and the hardware

+   * tick counter are the best sources of randomness but

+   * since the tick counter is only 16 bit (and truncated

+   * at that), the idle counter and millisecond timer

+   * (which may be small values) are added to help

+   * randomize the lower 16 bits of the seed.

+   */

+  readClk();

+  avRandomSeed += *(u32_t *)clockBuf + *lptr1 + OSIdleCtr

+           + ppp_mtime() + ((u32_t)TM1 << 16) + TM1;

+#else

+  avRandomSeed += sys_jiffies(); /* XXX */

+#endif

+

+  /* Initialize the Borland random number generator. */

+  srand((unsigned)avRandomSeed);

+}

+

+/*

+ * Randomize our random seed value.  Here we use the fact that

+ * this function is called at *truely random* times by the polling

+ * and network functions.  Here we only get 16 bits of new random

+ * value but we use the previous value to randomize the other 16

+ * bits.

+ */

+void

+avRandomize(void)

+{

+  static u32_t last_jiffies;

+

+  if (!avRandomized) {

+    avRandomized = !0;

+    avRandomInit();

+    /* The initialization function also updates the seed. */

+  } else {

+    /* avRandomSeed += (avRandomSeed << 16) + TM1; */

+    avRandomSeed += (sys_jiffies() - last_jiffies); /* XXX */

+  }

+  last_jiffies = sys_jiffies();

+}

+

+/*

+ * Return a new random number.

+ * Here we use the Borland rand() function to supply a pseudo random

+ * number which we make truely random by combining it with our own

+ * seed which is randomized by truely random events. 

+ * Thus the numbers will be truely random unless there have been no

+ * operator or network events in which case it will be pseudo random

+ * seeded by the real time clock.

+ */

+u32_t

+avRandom()

+{

+  return ((((u32_t)rand() << 16) + rand()) + avRandomSeed);

+}

+

+#endif /* MD5_SUPPORT */

+

+#endif /* PPP_SUPPORT */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/randm.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/randm.h
new file mode 100644
index 0000000..5fb99ef
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/randm.h
@@ -0,0 +1,81 @@
+/*****************************************************************************

+* randm.h - Random number generator header file.

+*

+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.

+* Copyright (c) 1998 Global Election Systems Inc.

+*

+* The authors hereby grant permission to use, copy, modify, distribute,

+* and license this software and its documentation for any purpose, provided

+* that existing copyright notices are retained in all copies and that this

+* notice and the following disclaimer are included verbatim in any 

+* distributions. No written agreement, license, or royalty fee is required

+* for any of the authorized uses.

+*

+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR

+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 

+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+*

+******************************************************************************

+* REVISION HISTORY

+*

+* 03-01-01 Marc Boucher <marc@mbsi.ca>

+*   Ported to lwIP.

+* 98-05-29 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.

+*   Extracted from avos.

+*****************************************************************************/

+

+#ifndef RANDM_H

+#define RANDM_H

+

+/***********************

+*** PUBLIC FUNCTIONS ***

+***********************/

+/*

+ * Initialize the random number generator.

+ */

+void avRandomInit(void);

+

+/*

+ * Churn the randomness pool on a random event.  Call this early and often

+ * on random and semi-random system events to build randomness in time for

+ * usage.  For randomly timed events, pass a null pointer and a zero length

+ * and this will use the system timer and other sources to add randomness.

+ * If new random data is available, pass a pointer to that and it will be

+ * included.

+ */

+void avChurnRand(char *randData, u32_t randLen);

+

+/*

+ * Randomize our random seed value.  To be called for truely random events

+ * such as user operations and network traffic.

+ */

+#if MD5_SUPPORT

+#define avRandomize() avChurnRand(NULL, 0)

+#else  /* MD5_SUPPORT */

+void avRandomize(void);

+#endif /* MD5_SUPPORT */

+

+/*

+ * Use the random pool to generate random data.  This degrades to pseudo

+ * random when used faster than randomness is supplied using churnRand().

+ * Thus it's important to make sure that the results of this are not

+ * published directly because one could predict the next result to at

+ * least some degree.  Also, it's important to get a good seed before

+ * the first use.

+ */

+void avGenRand(char *buf, u32_t bufLen);

+

+/*

+ * Return a new random number.

+ */

+u32_t avRandom(void);

+

+

+#endif /* RANDM_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vj.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vj.c
new file mode 100644
index 0000000..eba7da9
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vj.c
@@ -0,0 +1,660 @@
+/*

+ * Routines to compress and uncompess tcp packets (for transmission

+ * over low speed serial lines.

+ *

+ * Copyright (c) 1989 Regents of the University of California.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by the University of California, Berkeley.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ *

+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:

+ *   Initial distribution.

+ *

+ * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au,

+ * so that the entire packet being decompressed doesn't have

+ * to be in contiguous memory (just the compressed header).

+ *

+ * Modified March 1998 by Guy Lancaster, glanca@gesn.com,

+ * for a 16 bit processor.

+ */

+

+#include "lwip/opt.h"

+

+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */

+

+#include "ppp.h"

+#include "pppdebug.h"

+

+#include "vj.h"

+

+#include <string.h>

+

+#if VJ_SUPPORT

+

+#if LINK_STATS

+#define INCR(counter) ++comp->stats.counter

+#else

+#define INCR(counter)

+#endif

+

+#if defined(NO_CHAR_BITFIELDS)

+#define getip_hl(base)  ((base).ip_hl_v&0xf)

+#define getth_off(base) (((base).th_x2_off&0xf0)>>4)

+#else

+#define getip_hl(base)  ((base).ip_hl)

+#define getth_off(base) ((base).th_off)

+#endif

+

+void

+vj_compress_init(struct vjcompress *comp)

+{

+  register u_int i;

+  register struct cstate *tstate = comp->tstate;

+  

+#if MAX_SLOTS == 0

+  memset((char *)comp, 0, sizeof(*comp));

+#endif

+  comp->maxSlotIndex = MAX_SLOTS - 1;

+  comp->compressSlot = 0;    /* Disable slot ID compression by default. */

+  for (i = MAX_SLOTS - 1; i > 0; --i) {

+    tstate[i].cs_id = i;

+    tstate[i].cs_next = &tstate[i - 1];

+  }

+  tstate[0].cs_next = &tstate[MAX_SLOTS - 1];

+  tstate[0].cs_id = 0;

+  comp->last_cs = &tstate[0];

+  comp->last_recv = 255;

+  comp->last_xmit = 255;

+  comp->flags = VJF_TOSS;

+}

+

+

+/* ENCODE encodes a number that is known to be non-zero.  ENCODEZ

+ * checks for zero (since zero has to be encoded in the long, 3 byte

+ * form).

+ */

+#define ENCODE(n) { \

+  if ((u_short)(n) >= 256) { \

+    *cp++ = 0; \

+    cp[1] = (n); \

+    cp[0] = (n) >> 8; \

+    cp += 2; \

+  } else { \

+    *cp++ = (n); \

+  } \

+}

+#define ENCODEZ(n) { \

+  if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \

+    *cp++ = 0; \

+    cp[1] = (n); \

+    cp[0] = (n) >> 8; \

+    cp += 2; \

+  } else { \

+    *cp++ = (n); \

+  } \

+}

+

+#define DECODEL(f) { \

+  if (*cp == 0) {\

+    u32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]); \

+    (f) = htonl(tmp); \

+    cp += 3; \

+  } else { \

+    u32_t tmp = ntohl(f) + (u32_t)*cp++; \

+    (f) = htonl(tmp); \

+  } \

+}

+

+#define DECODES(f) { \

+  if (*cp == 0) {\

+    u_short tmp = ntohs(f) + (((u_short)cp[1] << 8) | cp[2]); \

+    (f) = htons(tmp); \

+    cp += 3; \

+  } else { \

+    u_short tmp = ntohs(f) + (u_short)*cp++; \

+    (f) = htons(tmp); \

+  } \

+}

+

+#define DECODEU(f) { \

+  if (*cp == 0) {\

+    (f) = htons(((u_short)cp[1] << 8) | cp[2]); \

+    cp += 3; \

+  } else { \

+    (f) = htons((u_short)*cp++); \

+  } \

+}

+

+/*

+ * vj_compress_tcp - Attempt to do Van Jacobsen header compression on a

+ * packet.  This assumes that nb and comp are not null and that the first

+ * buffer of the chain contains a valid IP header.

+ * Return the VJ type code indicating whether or not the packet was

+ * compressed.

+ */

+u_int

+vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb)

+{

+  register struct ip *ip = (struct ip *)pb->payload;

+  register struct cstate *cs = comp->last_cs->cs_next;

+  register u_short hlen = getip_hl(*ip);

+  register struct tcphdr *oth;

+  register struct tcphdr *th;

+  register u_short deltaS, deltaA;

+  register u_long deltaL;

+  register u_int changes = 0;

+  u_char new_seq[16];

+  register u_char *cp = new_seq;

+

+  /*  

+   * Check that the packet is IP proto TCP.

+   */

+  if (ip->ip_p != IPPROTO_TCP) {

+    return (TYPE_IP);

+  }

+

+  /*

+   * Bail if this is an IP fragment or if the TCP packet isn't

+   * `compressible' (i.e., ACK isn't set or some other control bit is

+   * set).  

+   */

+  if ((ip->ip_off & htons(0x3fff)) || pb->tot_len < 40) {

+    return (TYPE_IP);

+  }

+  th = (struct tcphdr *)&((long *)ip)[hlen];

+  if ((th->th_flags & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) {

+    return (TYPE_IP);

+  }

+  /*

+   * Packet is compressible -- we're going to send either a

+   * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need

+   * to locate (or create) the connection state.  Special case the

+   * most recently used connection since it's most likely to be used

+   * again & we don't have to do any reordering if it's used.

+   */

+  INCR(vjs_packets);

+  if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr 

+      || ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr 

+      || *(long *)th != ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) {

+    /*

+     * Wasn't the first -- search for it.

+     *

+     * States are kept in a circularly linked list with

+     * last_cs pointing to the end of the list.  The

+     * list is kept in lru order by moving a state to the

+     * head of the list whenever it is referenced.  Since

+     * the list is short and, empirically, the connection

+     * we want is almost always near the front, we locate

+     * states via linear search.  If we don't find a state

+     * for the datagram, the oldest state is (re-)used.

+     */

+    register struct cstate *lcs;

+    register struct cstate *lastcs = comp->last_cs;

+    

+    do {

+      lcs = cs; cs = cs->cs_next;

+      INCR(vjs_searches);

+      if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr

+          && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr

+          && *(long *)th == ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) {

+        goto found;

+      }

+    } while (cs != lastcs);

+

+    /*

+     * Didn't find it -- re-use oldest cstate.  Send an

+     * uncompressed packet that tells the other side what

+     * connection number we're using for this conversation.

+     * Note that since the state list is circular, the oldest

+     * state points to the newest and we only need to set

+     * last_cs to update the lru linkage.

+     */

+    INCR(vjs_misses);

+    comp->last_cs = lcs;

+    hlen += getth_off(*th);

+    hlen <<= 2;

+    /* Check that the IP/TCP headers are contained in the first buffer. */

+    if (hlen > pb->len) {

+      return (TYPE_IP);

+    }

+    goto uncompressed;

+

+    found:

+    /*

+     * Found it -- move to the front on the connection list.

+     */

+    if (cs == lastcs) {

+      comp->last_cs = lcs;

+    } else {

+      lcs->cs_next = cs->cs_next;

+      cs->cs_next = lastcs->cs_next;

+      lastcs->cs_next = cs;

+    }

+  }

+

+  oth = (struct tcphdr *)&((long *)&cs->cs_ip)[hlen];

+  deltaS = hlen;

+  hlen += getth_off(*th);

+  hlen <<= 2;

+  /* Check that the IP/TCP headers are contained in the first buffer. */

+  if (hlen > pb->len) {

+    PPPDEBUG((LOG_INFO, "vj_compress_tcp: header len %d spans buffers\n", hlen));

+    return (TYPE_IP);

+  }

+

+  /*

+   * Make sure that only what we expect to change changed. The first

+   * line of the `if' checks the IP protocol version, header length &

+   * type of service.  The 2nd line checks the "Don't fragment" bit.

+   * The 3rd line checks the time-to-live and protocol (the protocol

+   * check is unnecessary but costless).  The 4th line checks the TCP

+   * header length.  The 5th line checks IP options, if any.  The 6th

+   * line checks TCP options, if any.  If any of these things are

+   * different between the previous & current datagram, we send the

+   * current datagram `uncompressed'.

+   */

+  if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] 

+      || ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] 

+      || ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] 

+      || getth_off(*th) != getth_off(*oth) 

+      || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) 

+      || (getth_off(*th) > 5 && BCMP(th + 1, oth + 1, (getth_off(*th) - 5) << 2))) {

+    goto uncompressed;

+  }

+

+  /*

+   * Figure out which of the changing fields changed.  The

+   * receiver expects changes in the order: urgent, window,

+   * ack, seq (the order minimizes the number of temporaries

+   * needed in this section of code).

+   */

+  if (th->th_flags & TCP_URG) {

+    deltaS = ntohs(th->th_urp);

+    ENCODEZ(deltaS);

+    changes |= NEW_U;

+  } else if (th->th_urp != oth->th_urp) {

+    /* argh! URG not set but urp changed -- a sensible

+     * implementation should never do this but RFC793

+     * doesn't prohibit the change so we have to deal

+     * with it. */

+    goto uncompressed;

+  }

+

+  if ((deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) != 0) {

+    ENCODE(deltaS);

+    changes |= NEW_W;

+  }

+

+  if ((deltaL = ntohl(th->th_ack) - ntohl(oth->th_ack)) != 0) {

+    if (deltaL > 0xffff) {

+      goto uncompressed;

+    }

+    deltaA = (u_short)deltaL;

+    ENCODE(deltaA);

+    changes |= NEW_A;

+  }

+

+  if ((deltaL = ntohl(th->th_seq) - ntohl(oth->th_seq)) != 0) {

+    if (deltaL > 0xffff) {

+      goto uncompressed;

+    }

+    deltaS = (u_short)deltaL;

+    ENCODE(deltaS);

+    changes |= NEW_S;

+  }

+

+  switch(changes) {

+  case 0:

+    /*

+     * Nothing changed. If this packet contains data and the

+     * last one didn't, this is probably a data packet following

+     * an ack (normal on an interactive connection) and we send

+     * it compressed.  Otherwise it's probably a retransmit,

+     * retransmitted ack or window probe.  Send it uncompressed

+     * in case the other side missed the compressed version.

+     */

+    if (ip->ip_len != cs->cs_ip.ip_len &&

+      ntohs(cs->cs_ip.ip_len) == hlen) {

+      break;

+    }

+

+  /* (fall through) */

+

+  case SPECIAL_I:

+  case SPECIAL_D:

+    /*

+     * actual changes match one of our special case encodings --

+     * send packet uncompressed.

+     */

+    goto uncompressed;

+

+  case NEW_S|NEW_A:

+    if (deltaS == deltaA && deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {

+      /* special case for echoed terminal traffic */

+      changes = SPECIAL_I;

+      cp = new_seq;

+    }

+    break;

+

+  case NEW_S:

+    if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {

+      /* special case for data xfer */

+      changes = SPECIAL_D;

+      cp = new_seq;

+    }

+    break;

+  }

+

+  deltaS = (u_short)(ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id));

+  if (deltaS != 1) {

+    ENCODEZ(deltaS);

+    changes |= NEW_I;

+  }

+  if (th->th_flags & TCP_PSH) {

+    changes |= TCP_PUSH_BIT;

+  }

+  /*

+   * Grab the cksum before we overwrite it below.  Then update our

+   * state with this packet's header.

+   */

+  deltaA = ntohs(th->th_sum);

+  BCOPY(ip, &cs->cs_ip, hlen);

+

+  /*

+   * We want to use the original packet as our compressed packet.

+   * (cp - new_seq) is the number of bytes we need for compressed

+   * sequence numbers.  In addition we need one byte for the change

+   * mask, one for the connection id and two for the tcp checksum.

+   * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how

+   * many bytes of the original packet to toss so subtract the two to

+   * get the new packet size.

+   */

+  deltaS = (u_short)(cp - new_seq);

+  if (!comp->compressSlot || comp->last_xmit != cs->cs_id) {

+    comp->last_xmit = cs->cs_id;

+    hlen -= deltaS + 4;

+    if(pbuf_header(pb, -hlen)){

+      /* Can we cope with this failing?  Just assert for now */

+      LWIP_ASSERT("pbuf_header failed\n", 0);

+    }

+    cp = (u_char *)pb->payload;

+    *cp++ = changes | NEW_C;

+    *cp++ = cs->cs_id;

+  } else {

+    hlen -= deltaS + 3;

+    if(pbuf_header(pb, -hlen)) {

+      /* Can we cope with this failing?  Just assert for now */

+      LWIP_ASSERT("pbuf_header failed\n", 0);

+    }

+    cp = (u_char *)pb->payload;

+    *cp++ = changes;

+  }

+  *cp++ = deltaA >> 8;

+  *cp++ = deltaA;

+  BCOPY(new_seq, cp, deltaS);

+  INCR(vjs_compressed);

+  return (TYPE_COMPRESSED_TCP);

+

+  /*

+   * Update connection state cs & send uncompressed packet (that is,

+   * a regular ip/tcp packet but with the 'conversation id' we hope

+   * to use on future compressed packets in the protocol field).

+   */

+uncompressed:

+  BCOPY(ip, &cs->cs_ip, hlen);

+  ip->ip_p = cs->cs_id;

+  comp->last_xmit = cs->cs_id;

+  return (TYPE_UNCOMPRESSED_TCP);

+}

+

+/*

+ * Called when we may have missed a packet.

+ */

+void

+vj_uncompress_err(struct vjcompress *comp)

+{

+  comp->flags |= VJF_TOSS;

+  INCR(vjs_errorin);

+}

+

+/*

+ * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP.

+ * Return 0 on success, -1 on failure.

+ */

+int

+vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp)

+{

+  register u_int hlen;

+  register struct cstate *cs;

+  register struct ip *ip;

+  

+  ip = (struct ip *)nb->payload;

+  hlen = getip_hl(*ip) << 2;

+  if (ip->ip_p >= MAX_SLOTS

+      || hlen + sizeof(struct tcphdr) > nb->len

+      || (hlen += getth_off(*((struct tcphdr *)&((char *)ip)[hlen])) << 2)

+          > nb->len

+      || hlen > MAX_HDR) {

+    PPPDEBUG((LOG_INFO, "vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n", 

+          ip->ip_p, hlen, nb->len));

+    comp->flags |= VJF_TOSS;

+    INCR(vjs_errorin);

+    return -1;

+  }

+  cs = &comp->rstate[comp->last_recv = ip->ip_p];

+  comp->flags &=~ VJF_TOSS;

+  ip->ip_p = IPPROTO_TCP;

+  BCOPY(ip, &cs->cs_ip, hlen);

+  cs->cs_hlen = hlen;

+  INCR(vjs_uncompressedin);

+  return 0;

+}

+

+/*

+ * Uncompress a packet of type TYPE_COMPRESSED_TCP.

+ * The packet is composed of a buffer chain and the first buffer

+ * must contain an accurate chain length.

+ * The first buffer must include the entire compressed TCP/IP header. 

+ * This procedure replaces the compressed header with the uncompressed

+ * header and returns the length of the VJ header.

+ */

+int

+vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp)

+{

+  u_char *cp;

+  struct tcphdr *th;

+  struct cstate *cs;

+  u_short *bp;

+  struct pbuf *n0 = *nb;

+  u32_t tmp;

+  u_int vjlen, hlen, changes;

+

+  INCR(vjs_compressedin);

+  cp = (u_char *)n0->payload;

+  changes = *cp++;

+  if (changes & NEW_C) {

+    /* 

+     * Make sure the state index is in range, then grab the state.

+     * If we have a good state index, clear the 'discard' flag. 

+     */

+    if (*cp >= MAX_SLOTS) {

+      PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: bad cid=%d\n", *cp));

+      goto bad;

+    }

+

+    comp->flags &=~ VJF_TOSS;

+    comp->last_recv = *cp++;

+  } else {

+    /* 

+     * this packet has an implicit state index.  If we've

+     * had a line error since the last time we got an

+     * explicit state index, we have to toss the packet. 

+     */

+    if (comp->flags & VJF_TOSS) {

+      PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: tossing\n"));

+      INCR(vjs_tossed);

+      return (-1);

+    }

+  }

+  cs = &comp->rstate[comp->last_recv];

+  hlen = getip_hl(cs->cs_ip) << 2;

+  th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];

+  th->th_sum = htons((*cp << 8) | cp[1]);

+  cp += 2;

+  if (changes & TCP_PUSH_BIT) {

+    th->th_flags |= TCP_PSH;

+  } else {

+    th->th_flags &=~ TCP_PSH;

+  }

+

+  switch (changes & SPECIALS_MASK) {

+  case SPECIAL_I:

+    {

+      register u32_t i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;

+      /* some compilers can't nest inline assembler.. */

+      tmp = ntohl(th->th_ack) + i;

+      th->th_ack = htonl(tmp);

+      tmp = ntohl(th->th_seq) + i;

+      th->th_seq = htonl(tmp);

+    }

+    break;

+

+  case SPECIAL_D:

+    /* some compilers can't nest inline assembler.. */

+    tmp = ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;

+    th->th_seq = htonl(tmp);

+    break;

+

+  default:

+    if (changes & NEW_U) {

+      th->th_flags |= TCP_URG;

+      DECODEU(th->th_urp);

+    } else {

+      th->th_flags &=~ TCP_URG;

+    }

+    if (changes & NEW_W) {

+      DECODES(th->th_win);

+    }

+    if (changes & NEW_A) {

+      DECODEL(th->th_ack);

+    }

+    if (changes & NEW_S) {

+      DECODEL(th->th_seq);

+    }

+    break;

+  }

+  if (changes & NEW_I) {

+    DECODES(cs->cs_ip.ip_id);

+  } else {

+    cs->cs_ip.ip_id = ntohs(cs->cs_ip.ip_id) + 1;

+    cs->cs_ip.ip_id = htons(cs->cs_ip.ip_id);

+  }

+

+  /*

+   * At this point, cp points to the first byte of data in the

+   * packet.  Fill in the IP total length and update the IP

+   * header checksum.

+   */

+  vjlen = (u_short)(cp - (u_char*)n0->payload);

+  if (n0->len < vjlen) {

+    /* 

+     * We must have dropped some characters (crc should detect

+     * this but the old slip framing won't) 

+     */

+    PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: head buffer %d too short %d\n", 

+          n0->len, vjlen));

+    goto bad;

+  }

+

+#if BYTE_ORDER == LITTLE_ENDIAN

+  tmp = n0->tot_len - vjlen + cs->cs_hlen;

+  cs->cs_ip.ip_len = htons(tmp);

+#else

+  cs->cs_ip.ip_len = htons(n0->tot_len - vjlen + cs->cs_hlen);

+#endif

+

+  /* recompute the ip header checksum */

+  bp = (u_short *) &cs->cs_ip;

+  cs->cs_ip.ip_sum = 0;

+  for (tmp = 0; hlen > 0; hlen -= 2) {

+    tmp += *bp++;

+  }

+  tmp = (tmp & 0xffff) + (tmp >> 16);

+  tmp = (tmp & 0xffff) + (tmp >> 16);

+  cs->cs_ip.ip_sum = (u_short)(~tmp);

+  

+  /* Remove the compressed header and prepend the uncompressed header. */

+  if(pbuf_header(n0, -((s16_t)(vjlen)))) {

+    /* Can we cope with this failing?  Just assert for now */

+    LWIP_ASSERT("pbuf_header failed\n", 0);

+    goto bad;

+  }

+

+  if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) {

+    struct pbuf *np, *q;

+    u8_t *bufptr;

+

+    np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL);

+    if(!np) {

+      PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: realign failed\n"));

+      goto bad;

+    }

+

+    if(pbuf_header(np, -cs->cs_hlen)) {

+      /* Can we cope with this failing?  Just assert for now */

+      LWIP_ASSERT("pbuf_header failed\n", 0);

+      goto bad;

+    }

+

+    bufptr = n0->payload;

+    for(q = np; q != NULL; q = q->next) {

+      MEMCPY(q->payload, bufptr, q->len);

+      bufptr += q->len;

+    }

+

+    if(n0->next) {

+      pbuf_chain(np, n0->next);

+      pbuf_dechain(n0);

+    }

+    pbuf_free(n0);

+    n0 = np;

+  }

+

+  if(pbuf_header(n0, cs->cs_hlen)) {

+    struct pbuf *np;

+

+    LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE);

+    np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL);

+    if(!np) {

+      PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: prepend failed\n"));

+      goto bad;

+    }

+    pbuf_cat(np, n0);

+    n0 = np;

+  }

+  LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen);

+  MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen);

+

+  *nb = n0;

+

+  return vjlen;

+

+bad:

+  comp->flags |= VJF_TOSS;

+  INCR(vjs_errorin);

+  return (-1);

+}

+

+#endif /* VJ_SUPPORT */

+

+#endif /* PPP_SUPPORT */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vj.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vj.h
new file mode 100644
index 0000000..bc02442
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vj.h
@@ -0,0 +1,155 @@
+/*

+ * Definitions for tcp compression routines.

+ *

+ * $Id: vj.h,v 1.5 2007/12/19 20:47:23 fbernon Exp $

+ *

+ * Copyright (c) 1989 Regents of the University of California.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms are permitted

+ * provided that the above copyright notice and this paragraph are

+ * duplicated in all such forms and that any documentation,

+ * advertising materials, and other materials related to such

+ * distribution and use acknowledge that the software was developed

+ * by the University of California, Berkeley.  The name of the

+ * University may not be used to endorse or promote products derived

+ * from this software without specific prior written permission.

+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR

+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+ *

+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:

+ * - Initial distribution.

+ */

+

+#ifndef VJ_H

+#define VJ_H

+

+#include "vjbsdhdr.h"

+

+#define MAX_SLOTS 16 /* must be > 2 and < 256 */

+#define MAX_HDR   128

+

+/*

+ * Compressed packet format:

+ *

+ * The first octet contains the packet type (top 3 bits), TCP

+ * 'push' bit, and flags that indicate which of the 4 TCP sequence

+ * numbers have changed (bottom 5 bits).  The next octet is a

+ * conversation number that associates a saved IP/TCP header with

+ * the compressed packet.  The next two octets are the TCP checksum

+ * from the original datagram.  The next 0 to 15 octets are

+ * sequence number changes, one change per bit set in the header

+ * (there may be no changes and there are two special cases where

+ * the receiver implicitly knows what changed -- see below).

+ * 

+ * There are 5 numbers which can change (they are always inserted

+ * in the following order): TCP urgent pointer, window,

+ * acknowlegement, sequence number and IP ID.  (The urgent pointer

+ * is different from the others in that its value is sent, not the

+ * change in value.)  Since typical use of SLIP links is biased

+ * toward small packets (see comments on MTU/MSS below), changes

+ * use a variable length coding with one octet for numbers in the

+ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the

+ * range 256 - 65535 or 0.  (If the change in sequence number or

+ * ack is more than 65535, an uncompressed packet is sent.)

+ */

+

+/*

+ * Packet types (must not conflict with IP protocol version)

+ *

+ * The top nibble of the first octet is the packet type.  There are

+ * three possible types: IP (not proto TCP or tcp with one of the

+ * control flags set); uncompressed TCP (a normal IP/TCP packet but

+ * with the 8-bit protocol field replaced by an 8-bit connection id --

+ * this type of packet syncs the sender & receiver); and compressed

+ * TCP (described above).

+ *

+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and

+ * is logically part of the 4-bit "changes" field that follows.  Top

+ * three bits are actual packet type.  For backward compatibility

+ * and in the interest of conserving bits, numbers are chosen so the

+ * IP protocol version number (4) which normally appears in this nibble

+ * means "IP packet".

+ */

+

+/* packet types */

+#define TYPE_IP               0x40

+#define TYPE_UNCOMPRESSED_TCP 0x70

+#define TYPE_COMPRESSED_TCP   0x80

+#define TYPE_ERROR            0x00

+

+/* Bits in first octet of compressed packet */

+#define NEW_C 0x40 /* flag bits for what changed in a packet */

+#define NEW_I 0x20

+#define NEW_S 0x08

+#define NEW_A 0x04

+#define NEW_W 0x02

+#define NEW_U 0x01

+

+/* reserved, special-case values of above */

+#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */

+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */

+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)

+

+#define TCP_PUSH_BIT 0x10

+

+

+/*

+ * "state" data for each active tcp conversation on the wire.  This is

+ * basically a copy of the entire IP/TCP header from the last packet

+ * we saw from the conversation together with a small identifier

+ * the transmit & receive ends of the line use to locate saved header.

+ */

+struct cstate {

+  struct cstate *cs_next; /* next most recently used state (xmit only) */

+  u_short cs_hlen;        /* size of hdr (receive only) */

+  u_char cs_id;           /* connection # associated with this state */

+  u_char cs_filler;

+  union {

+    char csu_hdr[MAX_HDR];

+    struct ip csu_ip;     /* ip/tcp hdr from most recent packet */

+  } vjcs_u;

+};

+#define cs_ip vjcs_u.csu_ip

+#define cs_hdr vjcs_u.csu_hdr

+

+

+struct vjstat {

+  unsigned long vjs_packets;        /* outbound packets */

+  unsigned long vjs_compressed;     /* outbound compressed packets */

+  unsigned long vjs_searches;       /* searches for connection state */

+  unsigned long vjs_misses;         /* times couldn't find conn. state */

+  unsigned long vjs_uncompressedin; /* inbound uncompressed packets */

+  unsigned long vjs_compressedin;   /* inbound compressed packets */

+  unsigned long vjs_errorin;        /* inbound unknown type packets */

+  unsigned long vjs_tossed;         /* inbound packets tossed because of error */

+};

+

+/*

+ * all the state data for one serial line (we need one of these per line).

+ */

+struct vjcompress {

+  struct cstate *last_cs;          /* most recently used tstate */

+  u_char last_recv;                /* last rcvd conn. id */

+  u_char last_xmit;                /* last sent conn. id */

+  u_short flags;

+  u_char maxSlotIndex;

+  u_char compressSlot;             /* Flag indicating OK to compress slot ID. */

+#if LINK_STATS

+  struct vjstat stats;

+#endif

+  struct cstate tstate[MAX_SLOTS]; /* xmit connection states */

+  struct cstate rstate[MAX_SLOTS]; /* receive connection states */

+};

+

+/* flag values */

+#define VJF_TOSS 1U /* tossing rcvd frames because of input err */

+

+extern void  vj_compress_init    (struct vjcompress *comp);

+extern u_int vj_compress_tcp     (struct vjcompress *comp, struct pbuf *pb);

+extern void  vj_uncompress_err   (struct vjcompress *comp);

+extern int   vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp);

+extern int   vj_uncompress_tcp   (struct pbuf **nb, struct vjcompress *comp);

+

+#endif /* VJ_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vjbsdhdr.h b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vjbsdhdr.h
new file mode 100644
index 0000000..6c247c6
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vjbsdhdr.h
@@ -0,0 +1,81 @@
+#ifndef VJBSDHDR_H

+#define VJBSDHDR_H

+

+#include "lwip/tcp.h"

+

+/*

+ * Structure of an internet header, naked of options.

+ *

+ * We declare ip_len and ip_off to be short, rather than u_short

+ * pragmatically since otherwise unsigned comparisons can result

+ * against negative integers quite easily, and fail in subtle ways.

+ */

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct ip

+{

+#if defined(NO_CHAR_BITFIELDS)

+  u_char   ip_hl_v;  /* bug in GCC for mips means the bitfield stuff will sometimes break - so we use a char for both and get round it with macro's instead... */

+#else

+#if BYTE_ORDER == LITTLE_ENDIAN

+  unsigned ip_hl:4,              /* header length */

+           ip_v :4;              /* version */

+#elif BYTE_ORDER == BIG_ENDIAN 

+  unsigned ip_v :4,              /* version */

+           ip_hl:4;              /* header length */

+#else

+  COMPLAIN - NO BYTE ORDER SELECTED!

+#endif

+#endif

+  u_char  ip_tos;                /* type of service */

+  u_short ip_len;                /* total length */

+  u_short ip_id;                 /* identification */

+  u_short ip_off;                /* fragment offset field */

+#define  IP_DF 0x4000            /* dont fragment flag */

+#define  IP_MF 0x2000            /* more fragments flag */

+#define  IP_OFFMASK 0x1fff       /* mask for fragmenting bits */

+  u_char  ip_ttl;                /* time to live */

+  u_char  ip_p;                  /* protocol */

+  u_short ip_sum;                /* checksum */

+  struct  in_addr ip_src,ip_dst; /* source and dest address */

+};

+PACK_STRUCT_END

+

+typedef u32_t tcp_seq;

+

+/*

+ * TCP header.

+ * Per RFC 793, September, 1981.

+ */

+PACK_STRUCT_BEGIN

+#if (defined(__MWERKS__)  || defined(__CWCC__))

+	#pragma options align= packed

+#endif

+struct tcphdr  

+{

+  u_short  th_sport;    /* source port */

+  u_short  th_dport;    /* destination port */

+  tcp_seq  th_seq;      /* sequence number */

+  tcp_seq  th_ack;      /* acknowledgement number */

+#if defined(NO_CHAR_BITFIELDS)

+  u_char   th_x2_off;

+#else

+#if BYTE_ORDER == LITTLE_ENDIAN

+  unsigned th_x2 :4,    /* (unused) */

+           th_off:4;    /* data offset */

+#endif

+#if BYTE_ORDER == BIG_ENDIAN 

+  unsigned th_off:4,    /* data offset */

+           th_x2 :4;    /* (unused) */

+#endif

+#endif

+  u_char   th_flags;

+  u_short  th_win;      /* window */

+  u_short  th_sum;      /* checksum */

+  u_short  th_urp;      /* urgent pointer */

+};

+PACK_STRUCT_END

+

+#endif /* VJBSDHDR_H */

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/slipif.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/slipif.c
new file mode 100644
index 0000000..7839da4
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/slipif.c
@@ -0,0 +1,275 @@
+/**

+ * @file

+ * SLIP Interface

+ *

+ */

+

+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved. 

+ *

+ * Redistribution and use in source and binary forms, with or without 

+ * modification, are permitted provided that the following conditions 

+ * are met: 

+ * 1. Redistributions of source code must retain the above copyright 

+ *    notice, this list of conditions and the following disclaimer. 

+ * 2. Redistributions in binary form must reproduce the above copyright 

+ *    notice, this list of conditions and the following disclaimer in the 

+ *    documentation and/or other materials provided with the distribution. 

+ * 3. Neither the name of the Institute nor the names of its contributors 

+ *    may be used to endorse or promote products derived from this software 

+ *    without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 

+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 

+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 

+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 

+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 

+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 

+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 

+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 

+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 

+ * SUCH DAMAGE. 

+ *

+ * This file is built upon the file: src/arch/rtxc/netif/sioslip.c

+ *

+ * Author: Magnus Ivarsson <magnus.ivarsson(at)volvo.com> 

+ */

+

+/* 

+ * This is an arch independent SLIP netif. The specific serial hooks must be

+ * provided by another file. They are sio_open, sio_recv and sio_send

+ */

+

+#include "netif/slipif.h"

+#include "lwip/opt.h"

+#include "lwip/def.h"

+#include "lwip/pbuf.h"

+#include "lwip/sys.h"

+#include "lwip/stats.h"

+#include "lwip/snmp.h"

+#include "lwip/sio.h"

+

+#define SLIP_END     0300 /* 0xC0 */

+#define SLIP_ESC     0333 /* 0xDB */

+#define SLIP_ESC_END 0334 /* 0xDC */

+#define SLIP_ESC_ESC 0335 /* 0xDD */

+

+#define MAX_SIZE     1500

+

+/**

+ * Send a pbuf doing the necessary SLIP encapsulation

+ *

+ * Uses the serial layer's sio_send()

+ *

+ * @param netif the lwip network interface structure for this slipif

+ * @param p the pbuf chaing packet to send

+ * @param ipaddr the ip address to send the packet to (not used for slipif)

+ * @return always returns ERR_OK since the serial layer does not provide return values

+ */

+err_t

+slipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)

+{

+  struct pbuf *q;

+  u16_t i;

+  u8_t c;

+

+  LWIP_ASSERT("netif != NULL", (netif != NULL));

+  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));

+  LWIP_ASSERT("p != NULL", (p != NULL));

+

+  LWIP_UNUSED_ARG(ipaddr);

+

+  /* Send pbuf out on the serial I/O device. */

+  sio_send(SLIP_END, netif->state);

+

+  for (q = p; q != NULL; q = q->next) {

+    for (i = 0; i < q->len; i++) {

+      c = ((u8_t *)q->payload)[i];

+      switch (c) {

+      case SLIP_END:

+        sio_send(SLIP_ESC, netif->state);

+        sio_send(SLIP_ESC_END, netif->state);

+        break;

+      case SLIP_ESC:

+        sio_send(SLIP_ESC, netif->state);

+        sio_send(SLIP_ESC_ESC, netif->state);

+        break;

+      default:

+        sio_send(c, netif->state);

+        break;

+      }

+    }

+  }

+  sio_send(SLIP_END, netif->state);

+  return ERR_OK;

+}

+

+/**

+ * Handle the incoming SLIP stream character by character

+ *

+ * Poll the serial layer by calling sio_recv()

+ *

+ * @param netif the lwip network interface structure for this slipif

+ * @return The IP packet when SLIP_END is received 

+ */

+static struct pbuf *

+slipif_input(struct netif *netif)

+{

+  u8_t c;

+  /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */

+  struct pbuf *p, *q;

+  u16_t recved;

+  u16_t i;

+

+  LWIP_ASSERT("netif != NULL", (netif != NULL));

+  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));

+

+  q = p = NULL;

+  recved = i = 0;

+  c = 0;

+

+  while (1) {

+    c = sio_recv(netif->state);

+    switch (c) {

+    case SLIP_END:

+      if (recved > 0) {

+        /* Received whole packet. */

+        /* Trim the pbuf to the size of the received packet. */

+        pbuf_realloc(q, recved);

+        

+        LINK_STATS_INC(link.recv);

+        

+        LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n"));

+        return q;

+      }

+      break;

+

+    case SLIP_ESC:

+      c = sio_recv(netif->state);

+      switch (c) {

+      case SLIP_ESC_END:

+        c = SLIP_END;

+        break;

+      case SLIP_ESC_ESC:

+        c = SLIP_ESC;

+        break;

+      }

+      /* FALLTHROUGH */

+

+    default:

+      /* byte received, packet not yet completely received */

+      if (p == NULL) {

+        /* allocate a new pbuf */

+        LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));

+        p = pbuf_alloc(PBUF_LINK, PBUF_POOL_BUFSIZE, PBUF_POOL);

+

+        if (p == NULL) {

+          LINK_STATS_INC(link.drop);

+          LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));

+          /* don't process any further since we got no pbuf to receive to */

+          break;

+        }

+

+        if (q != NULL) {

+          /* 'chain' the pbuf to the existing chain */

+          pbuf_cat(q, p);

+        } else {

+          /* p is the first pbuf in the chain */

+          q = p;

+        }

+      }

+

+      /* this automatically drops bytes if > MAX_SIZE */

+      if ((p != NULL) && (recved <= MAX_SIZE)) {

+        ((u8_t *)p->payload)[i] = c;

+        recved++;

+        i++;

+        if (i >= p->len) {

+          /* on to the next pbuf */

+          i = 0;

+          if (p->next != NULL && p->next->len > 0) {

+            /* p is a chain, on to the next in the chain */

+            p = p->next;

+          } else {

+            /* p is a single pbuf, set it to NULL so next time a new

+             * pbuf is allocated */

+            p = NULL;

+          }

+        }

+      }

+      break;

+    }

+  }

+  return NULL;

+}

+

+#if !NO_SYS

+/**

+ * The SLIP input thread.

+ *

+ * Feed the IP layer with incoming packets

+ *

+ * @param nf the lwip network interface structure for this slipif

+ */

+static void

+slipif_loop(void *nf)

+{

+  struct pbuf *p;

+  struct netif *netif = (struct netif *)nf;

+

+  while (1) {

+    p = slipif_input(netif);

+    if (p != NULL) {

+      if (netif->input(p, netif) != ERR_OK) {

+        pbuf_free(p);

+        p = NULL;

+      }

+    }

+  }

+}

+#endif /* !NO_SYS */

+

+/**

+ * SLIP netif initialization

+ *

+ * Call the arch specific sio_open and remember

+ * the opened device in the state field of the netif.

+ *

+ * @param netif the lwip network interface structure for this slipif

+ * @return ERR_OK if serial line could be opened,

+ *         ERR_IF is serial line couldn't be opened

+ *

+ * @note netif->num must contain the number of the serial port to open

+ *       (0 by default)

+ */

+err_t

+slipif_init(struct netif *netif)

+{

+

+  LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num));

+

+  netif->name[0] = 's';

+  netif->name[1] = 'l';

+  netif->output = slipif_output;

+  netif->mtu = MAX_SIZE;

+  netif->flags = NETIF_FLAG_POINTTOPOINT;

+

+  /* Try to open the serial port (netif->num contains the port number). */

+  netif->state = sio_open(netif->num);

+  if (!netif->state) {

+    /* Opening the serial port failed. */

+    return ERR_IF;

+  }

+

+  /* initialize the snmp variables and counters inside the struct netif

+   * ifSpeed: no assumption can be made without knowing more about the

+   * serial line!

+   */

+  NETIF_INIT_SNMP(netif, snmp_ifType_slip, 0);

+

+  /* Create a thread to poll the serial line. */

+  sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop, netif, SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);

+  return ERR_OK;

+}

diff --git a/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/stf91x_ethernetif.c b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/stf91x_ethernetif.c
new file mode 100644
index 0000000..87042f8
--- /dev/null
+++ b/190725_FreeRTOS_IoT_Libs_Task_Pool_and_MQTT_Preview/FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/stf91x_ethernetif.c
@@ -0,0 +1,416 @@
+/*

+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without modification,

+ * are permitted provided that the following conditions are met:

+ *

+ * 1. Redistributions of source code must retain the above copyright notice,

+ *    this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright notice,

+ *    this list of conditions and the following disclaimer in the documentation

+ *    and/or other materials provided with the distribution.

+ * 3. The name of the author may not be used to endorse or promote products

+ *    derived from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED

+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT

+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT

+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY

+ * OF SUCH DAMAGE.

+ *

+ * This file is part of the lwIP TCP/IP stack.

+ *

+ * Author: Adam Dunkels <adam@sics.se>

+ *

+ */

+

+/*

+ * This file is a skeleton for developing Ethernet network interface

+ * drivers for lwIP. Add code to the low_level functions and do a

+ * search-and-replace for the word "ethernetif" to replace it with

+ * something that better describes your network interface.

+ */

+

+#include "lwip/def.h"

+#include "lwip/mem.h"

+#include "lwip/pbuf.h"

+#include "lwip/sys.h"

+#include <lwip/stats.h>

+#include <lwip/snmp.h>

+#include "netif/etharp.h"

+#include "91x_enet.h"

+

+// Standard library include

+#include <stdio.h>

+#include <string.h>

+

+#define netifMTU													( 1500 )

+#define netifINTERFACE_TASK_STACK_SIZE		( 350 )

+#define netifINTERFACE_TASK_PRIORITY			( configMAX_PRIORITIES - 1 )

+#define netifBUFFER_WAIT_ATTEMPTS					10

+#define netifBUFFER_WAIT_DELAY						(10 / portTICK_PERIOD_MS)

+#define IFNAME0 'e'

+#define IFNAME1 'n'

+

+/* The time to block waiting for input. */

+#define emacBLOCK_TIME_WAITING_FOR_INPUT	( ( TickType_t ) 100 )

+

+/* Interrupt status bit definition. */

+#define DMI_RX_CURRENT_DONE 0x8000

+

+static u8_t s_rxBuff[1520];

+

+/* The semaphore used by the ISR to wake the lwIP task. */

+static SemaphoreHandle_t s_xSemaphore = NULL;

+

+struct ethernetif {

+  struct eth_addr *ethaddr;

+  /* Add whatever per-interface state that is needed here. */

+};

+

+/* Forward declarations. */

+static void ethernetif_input( void *pParams );

+u8 *pcGetNextBuffer( void );

+

+/**

+ * In this function, the hardware should be initialized.

+ * Called from ethernetif_init().

+ *

+ * @param netif the already initialized lwip network interface structure

+ *        for this ethernetif

+ */

+static void low_level_init(struct netif *netif)

+{

+  /* set MAC hardware address length */

+  netif->hwaddr_len = ETHARP_HWADDR_LEN;

+

+  /* set MAC hardware address */

+  netif->hwaddr[0] = MAC_ADDR0;

+  netif->hwaddr[1] = MAC_ADDR1;

+  netif->hwaddr[2] = MAC_ADDR2;

+  netif->hwaddr[3] = MAC_ADDR3;

+  netif->hwaddr[4] = MAC_ADDR4;

+  netif->hwaddr[5] = MAC_ADDR5;

+

+  /* maximum transfer unit */

+  netif->mtu = netifMTU;

+

+  // device capabilities.

+	// don't set NETIF_FLAG_ETHARP if this device is not an ethernet one

+  netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;

+

+  /* Do whatever else is needed to initialize interface. */

+	

+  if( s_xSemaphore == NULL )

+  {

+      vSemaphoreCreateBinary( s_xSemaphore );

+      xSemaphoreTake( s_xSemaphore,  0);

+  }

+

+  /* Initialise the MAC. */

+  ENET_InitClocksGPIO();

+  ENET_Init(PHY_AUTO_NEGOTIATION);

+  ENET_Start();

+	

+  portENTER_CRITICAL();

+  {

+      /*set MAC physical*/

+      ENET_MAC->MAH = (MAC_ADDR5<<8) + MAC_ADDR4;

+      ENET_MAC->MAL = (MAC_ADDR3<<24) + (MAC_ADDR2<<16) + (MAC_ADDR1<<8) + MAC_ADDR0;

+	

+      VIC_Config( ENET_ITLine, VIC_IRQ, 1 );

+      VIC_ITCmd( ENET_ITLine, ENABLE );	

+      ENET_DMA->ISR = DMI_RX_CURRENT_DONE;

+      ENET_DMA->IER = DMI_RX_CURRENT_DONE;

+  }

+  portEXIT_CRITICAL();

+	

+  netif->flags |= NETIF_FLAG_LINK_UP;

+

+  /* Create the task that handles the EMAC. */

+  xTaskCreate( ethernetif_input, "ETH_INT", netifINTERFACE_TASK_STACK_SIZE, (void *)netif, netifINTERFACE_TASK_PRIORITY, NULL );

+}	

+

+

+/**

+ * This function should do the actual transmission of the packet. The packet is

+ * contained in the pbuf that is passed to the function. This pbuf

+ * might be chained.

+ *

+ * @param netif the lwip network interface structure for this ethernetif

+ * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)

+ * @return ERR_OK if the packet could be sent

+ *         an err_t value if the packet couldn't be sent

+ *

+ * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to

+ *       strange results. You might consider waiting for space in the DMA queue

+ *       to become availale since the stack doesn't retry to send a packet

+ *       dropped because of memory failure (except for the TCP timers).

+ */

+static err_t low_level_output(struct netif *netif, struct pbuf *p)

+{

+  struct pbuf *q;

+  u32_t l = 0;

+	unsigned char *pcTxData;

+

+#if ETH_PAD_SIZE

+  pbuf_header(p, -ETH_PAD_SIZE);			/* drop the padding word */

+#endif

+	

+	/* Get a DMA buffer into which we can write the data to send. */

+	for( int i = 0; i < netifBUFFER_WAIT_ATTEMPTS; i++ )

+	{

+		pcTxData = pcGetNextBuffer();

+

+		if( pcTxData ){

+			break;

+		} else {

+			vTaskDelay( netifBUFFER_WAIT_DELAY );

+		}

+	}

+	

+	if (pcTxData == NULL) {

+		portNOP();		

+		

+		return ERR_BUF;

+	}

+	else {

+

+		for(q = p; q != NULL; q = q->next) {

+			/* Send the data from the pbuf to the interface, one pbuf at a

+				 time. The size of the data in each pbuf is kept in the ->len

+				 variable. */

+			

+			vTaskSuspendAll();

+			memcpy(&pcTxData[l], (u8_t*)q->payload, q->len);

+			xTaskResumeAll();

+			l += q->len;

+		}

+	}

+

+	ENET_TxPkt( &pcTxData, l );

+			

+	#if ETH_PAD_SIZE

+		pbuf_header(p, ETH_PAD_SIZE);			/* reclaim the padding word */

+	#endif

+

+		LINK_STATS_INC(link.xmit);

+

+  return ERR_OK;

+}

+

+/**

+ * Should allocate a pbuf and transfer the bytes of the incoming

+ * packet from the interface into the pbuf.

+ *

+ * @param netif the lwip network interface structure for this ethernetif

+ * @return a pbuf filled with the received packet (including MAC header)

+ *         NULL on memory error

+ */

+static struct pbuf *low_level_input(struct netif *netif)

+{

+  struct pbuf *p, *q;

+  u16_t len, l;

+

+  l = 0;

+  p = NULL;

+	

+

+	/* Obtain the size of the packet and put it into the "len"

+		 variable. */

+	len = ENET_HandleRxPkt(s_rxBuff);

+

+	if(len)

+	{

+	#if ETH_PAD_SIZE

+		len += ETH_PAD_SIZE;						/* allow room for Ethernet padding */

+	#endif

+

+		/* We allocate a pbuf chain of pbufs from the pool. */

+		p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);

+

+		if (p != NULL) {

+

+	#if ETH_PAD_SIZE

+			pbuf_header(p, -ETH_PAD_SIZE);			/* drop the padding word */

+	#endif

+

+			/* We iterate over the pbuf chain until we have read the entire

+			 * packet into the pbuf. */

+			for(q = p; q != NULL; q = q->next) {

+				/* Read enough bytes to fill this pbuf in the chain. The

+				 * available data in the pbuf is given by the q->len

+				 * variable. */

+				vTaskSuspendAll();

+				memcpy((u8_t*)q->payload, &s_rxBuff[l], q->len);

+				xTaskResumeAll();

+				l = l + q->len;

+			}

+

+

+	#if ETH_PAD_SIZE

+			pbuf_header(p, ETH_PAD_SIZE);			/* reclaim the padding word */

+	#endif

+

+			LINK_STATS_INC(link.recv);

+

+		} else {

+

+			LINK_STATS_INC(link.memerr);

+			LINK_STATS_INC(link.drop);

+

+		} /* End else */

+	} /* End if */

+			

+  return p;

+}

+

+/**

+ * This function should be called when a packet is ready to be read

+ * from the interface. It uses the function low_level_input() that

+ * should handle the actual reception of bytes from the network

+ * interface.Then the type of the received packet is determined and

+ * the appropriate input function is called.

+ *

+ * @param netif the lwip network interface structure for this ethernetif

+ */

+

+static void ethernetif_input( void *pParams )

+{

+	struct netif *netif;

+  struct ethernetif *ethernetif;

+  struct eth_hdr *ethhdr;

+  struct pbuf *p;

+

+	netif = (struct netif*) pParams;

+	ethernetif = netif->state;

+	

+	for( ;; )

+	{

+		do

+		{

+			

+			/* move received packet into a new pbuf */

+			p = low_level_input( netif );

+			

+			if( p == NULL )

+			{

+				/* No packet could be read.  Wait a for an interrupt to tell us

+				there is more data available. */

+				xSemaphoreTake( s_xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT );

+			}

+		

+		} while( p == NULL );

+

+		/* points to packet payload, which starts with an Ethernet header */

+		ethhdr = p->payload;

+

+		switch (htons(ethhdr->type)) {

+			/* IP or ARP packet? */

+	

+		case ETHTYPE_IP:

+	

+			/* full packet send to tcpip_thread to process */

+			if (netif->input(p, netif) != ERR_OK)

+			{

+				LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));

+				pbuf_free(p);

+				p = NULL;

+			}

+			break;

+				

+		case ETHTYPE_ARP:

+				

+#if ETHARP_TRUST_IP_MAC

+			etharp_ip_input(netif, p);

+#endif

+				

+			etharp_arp_input(netif, ethernetif->ethaddr, p);

+			break;

+		

+		default:

+			pbuf_free(p);

+			p = NULL;

+			break;

+		}

+	}

+}

+

+/**

+ * Should be called at the beginning of the program to set up the

+ * network interface. It calls the function low_level_init() to do the

+ * actual setup of the hardware.

+ *

+ * This function should be passed as a parameter to netif_add().

+ *

+ * @param netif the lwip network interface structure for this ethernetif

+ * @return ERR_OK if the loopif is initialized

+ *         ERR_MEM if private data couldn't be allocated

+ *         any other err_t on error

+ */

+err_t

+ethernetif_init(struct netif *netif)

+{

+  struct ethernetif *ethernetif;

+	

+	LWIP_ASSERT("netif != NULL", (netif != NULL));

+

+  ethernetif = mem_malloc(sizeof(struct ethernetif));

+

+  if (ethernetif == NULL)

+  {

+  	LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));

+  	return ERR_MEM;

+  }

+

+#if LWIP_NETIF_HOSTNAME

+  /* Initialize interface hostname */

+  netif->hostname = "lwip";

+#endif /* LWIP_NETIF_HOSTNAME */

+	

+  /*

+	 * Initialize the snmp variables and counters inside the struct netif.

+	 * The last argument should be replaced with your link speed, in units

+	 * of bits per second.

+	 */

+	NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100);	

+

+  netif->state = ethernetif;

+  netif->name[0] = IFNAME0;

+  netif->name[1] = IFNAME1;

+  /* We directly use etharp_output() here to save a function call.

+	 * You can instead declare your own function an call etharp_output()

+	 * from it if you have to do some checks before sending (e.g. if link

+	 * is available...)

+	 */	

+  netif->output = etharp_output;

+  netif->linkoutput = low_level_output;

+

+  ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);

+

+  low_level_init(netif);

+

+  return ERR_OK;

+}

+/*-----------------------------------------------------------*/

+

+void ENET_IRQHandler(void)

+{

+portBASE_TYPE xSwitchRequired;

+

+	/* Give the semaphore in case the lwIP task needs waking. */

+	xSwitchRequired = xSemaphoreGiveFromISR( s_xSemaphore, &xSwitchRequired );

+	

+	/* Clear the interrupt. */

+	ENET_DMA->ISR = DMI_RX_CURRENT_DONE;

+	

+	/* Switch tasks if necessary. */	

+	portEND_SWITCHING_ISR( xSwitchRequired );

+}

+/*-----------------------------------------------------------*/