aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/zpu/lwip/lwip-1.3.1/src/netif
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/zpu/lwip/lwip-1.3.1/src/netif')
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/FILES25
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/etharp.c1185
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ethernetif.c313
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/loopif.c66
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/auth.c988
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/auth.h111
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/chap.c902
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/chap.h166
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/chpms.c396
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/chpms.h64
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/fsm.c906
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/fsm.h169
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ipcp.c1440
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ipcp.h124
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/lcp.c2035
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/lcp.h167
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/magic.c82
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/magic.h67
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/md5.c318
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/md5.h55
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/pap.c619
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/pap.h131
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ppp.c1999
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ppp.h465
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ppp_oe.c1227
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/pppdebug.h86
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/randm.c248
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/randm.h81
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/vj.c660
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/vj.h155
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/vjbsdhdr.h75
-rw-r--r--firmware/zpu/lwip/lwip-1.3.1/src/netif/slipif.c279
32 files changed, 15604 insertions, 0 deletions
diff --git a/firmware/zpu/lwip/lwip-1.3.1/src/netif/FILES b/firmware/zpu/lwip/lwip-1.3.1/src/netif/FILES
new file mode 100644
index 000000000..1c4f5928d
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/etharp.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/etharp.c
new file mode 100644
index 000000000..73ea21173
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/src/netif/etharp.c
@@ -0,0 +1,1185 @@
+/**
+ * @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_gratuitous(our_netif) 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 with 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;
+ SMEMCPY(&hdr->sipaddr, &netif->ip_addr, sizeof(hdr->sipaddr));
+
+ 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_RAW, 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;
+ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
+ ("ethernet_input: dest:%02x:%02x:%02x:%02x:%02x:%02x, src:%02x:%02x:%02x:%02x:%02x:%02x, type:%2hx\n",
+ (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2],
+ (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5],
+ (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2],
+ (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5],
+ (unsigned)htons(ethhdr->type)));
+
+ 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:
+ ETHARP_STATS_INC(etharp.proterr);
+ ETHARP_STATS_INC(etharp.drop);
+ 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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ethernetif.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ethernetif.c
new file mode 100644
index 000000000..ccd7bd67f
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
+
+ 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/firmware/zpu/lwip/lwip-1.3.1/src/netif/loopif.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/loopif.c
new file mode 100644
index 000000000..1e1f28cf1
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/src/netif/loopif.c
@@ -0,0 +1,66 @@
+/**
+ * @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/snmp.h"
+
+/**
+ * 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)
+{
+ /* 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 = netif_loop_output;
+ return ERR_OK;
+}
+
+#endif /* LWIP_HAVE_LOOPIF */
diff --git a/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/auth.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/auth.c
new file mode 100644
index 000000000..4c0ee6a8e
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/auth.h b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/auth.h
new file mode 100644
index 000000000..86ff04945
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/chap.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/chap.c
new file mode 100644
index 000000000..6d9c3c3ce
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/chap.h b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/chap.h
new file mode 100644
index 000000000..83dafd734
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/chpms.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/chpms.c
new file mode 100644
index 000000000..0c7521f20
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/chpms.h b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/chpms.h
new file mode 100644
index 000000000..df070fb35
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/fsm.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/fsm.c
new file mode 100644
index 000000000..c073f1e36
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/fsm.h b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/fsm.h
new file mode 100644
index 000000000..14034ec7f
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ipcp.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ipcp.c
new file mode 100644
index 000000000..3a403a0a6
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ipcp.h b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ipcp.h
new file mode 100644
index 000000000..dfcf4fba6
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/lcp.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/lcp.c
new file mode 100644
index 000000000..85a0add95
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/lcp.h b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/lcp.h
new file mode 100644
index 000000000..1a5e5a4c0
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/magic.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/magic.c
new file mode 100644
index 000000000..d3922bb56
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/magic.h b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/magic.h
new file mode 100644
index 000000000..bc5174993
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/md5.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/md5.c
new file mode 100644
index 000000000..d65ecedbf
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/md5.h b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/md5.h
new file mode 100644
index 000000000..e129533f3
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/pap.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/pap.c
new file mode 100644
index 000000000..7c3fd7e4c
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/pap.c
@@ -0,0 +1,619 @@
+/*****************************************************************************
+* 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"));
+ } else {
+ GETCHAR(msglen, inp);
+ if(msglen > 0) {
+ 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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/pap.h b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/pap.h
new file mode 100644
index 000000000..0a09fc841
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ppp.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ppp.c
new file mode 100644
index 000000000..8720c3368
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ppp.c
@@ -0,0 +1,1999 @@
+/*****************************************************************************
+* 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();
+
+ MEMCPY(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);
+ 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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ppp.h b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ppp.h
new file mode 100644
index 000000000..d5caa0a7e
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ppp_oe.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/ppp_oe.c
new file mode 100644
index 000000000..c34c529b6
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/pppdebug.h b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/pppdebug.h
new file mode 100644
index 000000000..6253863c9
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/randm.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/randm.c
new file mode 100644
index 000000000..0c622a0b0
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/randm.h b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/randm.h
new file mode 100644
index 000000000..a0984b020
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/vj.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/vj.c
new file mode 100644
index 000000000..814ea72c5
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/vj.h b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/vj.h
new file mode 100644
index 000000000..b9617da4d
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/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/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/vjbsdhdr.h b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/vjbsdhdr.h
new file mode 100644
index 000000000..f46267614
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/src/netif/ppp/vjbsdhdr.h
@@ -0,0 +1,75 @@
+#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
+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
+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/firmware/zpu/lwip/lwip-1.3.1/src/netif/slipif.c b/firmware/zpu/lwip/lwip-1.3.1/src/netif/slipif.c
new file mode 100644
index 000000000..6cb2db442
--- /dev/null
+++ b/firmware/zpu/lwip/lwip-1.3.1/src/netif/slipif.c
@@ -0,0 +1,279 @@
+/**
+ * @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"
+
+#if LWIP_HAVE_SLIPIF
+
+#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;
+}
+#endif /* LWIP_HAVE_SLIPIF */