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 );

+}

+/*-----------------------------------------------------------*/