added support for lwip

This commit is contained in:
John Cobb
2015-02-15 16:35:01 -06:00
parent 86eb8f94ef
commit 0c07499e54
106 changed files with 41425 additions and 0 deletions

27
lwip/netif/FILES Normal file
View File

@ -0,0 +1,27 @@
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
An example network interface that shows how a "loopback"
interface would work. This is not really intended for actual
use, but as a very basic example of how initialization and
output functions work.
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

895
lwip/netif/exclude/etharp.c Normal file
View File

@ -0,0 +1,895 @@
/**
* @file
* Address Resolution Protocol module for IP over Ethernet
*
* Functionally, ARP is divided into two parts. The first maps an IP address
* to a physical address when sending a packet, and the second part answers
* requests from other machines for our physical address.
*
* This implementation complies with RFC 826 (Ethernet ARP). It supports
* Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6
* if an interface calls etharp_query(our_netif, its_ip_addr, NULL) upon
* address change.
*/
#ifdef EXCLUDE
/*
* 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 <string.h>
#include "lwip/opt.h"
#include "lwip/inet.h"
#include "netif/etharp.h"
#include "lwip/ip.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
/* ARP needs to inform DHCP of any ARP replies? */
#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
# include "lwip/dhcp.h"
#endif
/** the time an ARP entry stays valid after its last update,
* (240 * 5) seconds = 20 minutes.
*/
#define ARP_MAXAGE 240
/** the time an ARP entry stays pending after first request,
* (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
/** ARP message types */
#define ARP_REQUEST 1
#define ARP_REPLY 2
#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,
ETHARP_STATE_PENDING,
ETHARP_STATE_STABLE,
/** @internal transitional state used in etharp_tmr() for convenience*/
ETHARP_STATE_EXPIRED
};
struct etharp_entry {
#if ARP_QUEUEING
/**
* Pointer to queue of pending outgoing packets on this ARP entry.
*/
struct pbuf *p;
#endif
struct ip_addr ipaddr;
struct eth_addr ethaddr;
enum etharp_state state;
u8_t ctime;
struct netif *netif;
};
static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
static struct etharp_entry arp_table[ARP_TABLE_SIZE];
/**
* 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
static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags);
static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);
/**
* Initializes ARP module.
*/
void
etharp_init(void)
{
u8_t i;
/* clear ARP entries */
for(i = 0; i < ARP_TABLE_SIZE; ++i) {
arp_table[i].state = ETHARP_STATE_EMPTY;
#if ARP_QUEUEING
arp_table[i].p = NULL;
#endif
arp_table[i].ctime = 0;
arp_table[i].netif = NULL;
}
}
/**
* 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++;
/* stable entry? */
if ((arp_table[i].state == ETHARP_STATE_STABLE) &&
/* entry has become old? */
(arp_table[i].ctime >= ARP_MAXAGE)) {
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %"U16_F".\n", (u16_t)i));
arp_table[i].state = ETHARP_STATE_EXPIRED;
/* pending entry? */
} else if (arp_table[i].state == ETHARP_STATE_PENDING) {
/* entry unresolved/pending for too long? */
if (arp_table[i].ctime >= ARP_MAXPENDING) {
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %"U16_F".\n", (u16_t)i));
arp_table[i].state = ETHARP_STATE_EXPIRED;
#if ARP_QUEUEING
} else if (arp_table[i].p != NULL) {
/* resend an ARP query here */
#endif
}
}
/* clean up entries that have just been expired */
if (arp_table[i].state == ETHARP_STATE_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].p != 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].p)));
pbuf_free(arp_table[i].p);
arp_table[i].p = NULL;
}
#endif
/* recycle entry for re-use */
arp_table[i].state = ETHARP_STATE_EMPTY;
}
}
}
/**
* 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 find_entry(struct ip_addr *ipaddr, u8_t flags)
{
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
/**
* 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 | DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i));
/* found exact IP address match, simply bail out */
return i;
#if ARP_QUEUEING
/* pending with queued packets? */
} else if (arp_table[i].p != 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 | DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i));
/* found exact IP address match, simply bail out */
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))
{
return (s8_t)ERR_MEM;
}
/* b) choose the least destructive entry to recycle:
* 1) empty entry
* 2) oldest stable entry
* 3) oldest pending entry without queued packets
* 4) oldest pending entry without queued packets
*
* { ETHARP_TRY_HARD is set at this point }
*/
/* 1) empty entry available? */
if (empty < ARP_TABLE_SIZE) {
i = empty;
LWIP_DEBUGF(ETHARP_DEBUG | 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 | 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].p == NULL", arp_table[i].p == 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 | 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 | DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].p)));
pbuf_free(arp_table[i].p);
arp_table[i].p = 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;
return (err_t)i;
}
/**
* 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 | DBG_TRACE | 3, ("update_arp_entry()\n"));
LWIP_ASSERT("netif->hwaddr_len != 0", netif->hwaddr_len != 0);
LWIP_DEBUGF(ETHARP_DEBUG | 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 | DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
return ERR_ARG;
}
/* find or create ARP entry */
i = find_entry(ipaddr, flags);
/* 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 | DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
/* update address */
k = netif->hwaddr_len;
while (k > 0) {
k--;
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
}
/* reset time stamp */
arp_table[i].ctime = 0;
/* this is where we will send out queued packets! */
#if ARP_QUEUEING
while (arp_table[i].p != NULL) {
/* get the first packet on the queue */
struct pbuf *p = arp_table[i].p;
/* Ethernet header */
struct eth_hdr *ethhdr = p->payload;
/* remember (and reference) remainder of queue */
/* note: this will also terminate the p pbuf chain */
arp_table[i].p = pbuf_dequeue(p);
/* fill-in Ethernet header */
k = netif->hwaddr_len;
while(k > 0) {
k--;
ethhdr->dest.addr[k] = ethaddr->addr[k];
ethhdr->src.addr[k] = netif->hwaddr[k];
}
ethhdr->type = htons(ETHTYPE_IP);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n", (void *)p));
/* send the queued IP packet */
netif->linkoutput(netif, p);
/* 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;
i = 0;
while (i < ARP_TABLE_SIZE)
{
if ((arp_table[i].state == ETHARP_STATE_STABLE) &&
(arp_table[i].netif == netif) &&
ip_addr_cmp(ipaddr, &arp_table[i].ipaddr) )
{
*eth_ret = &arp_table[i].ethaddr;
*ip_ret = &arp_table[i].ipaddr;
return i;
}
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 pbuf 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_ASSERT("netif != NULL", netif != NULL);
/* 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 | 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 pbuf The ARP packet that arrived on netif. Is freed by this function.
* @param ethaddr Ethernet address of netif.
*
* @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;
LWIP_ASSERT("netif != NULL", netif != NULL);
/* drop short ARP packets */
if (p->tot_len < sizeof(struct etharp_hdr)) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 1, ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, (s16_t)sizeof(struct etharp_hdr)));
pbuf_free(p);
return;
}
hdr = p->payload;
/* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
* structure packing (not using structure copy which breaks strict-aliasing rules). */
memcpy(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));
memcpy(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));
/* 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 | DBG_TRACE, ("etharp_arp_input: incoming ARP request\n"));
/* ARP request for our address? */
if (for_us) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n"));
/* re-use pbuf to send ARP reply */
hdr->opcode = htons(ARP_REPLY);
hdr->dipaddr = hdr->sipaddr;
hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;
i = netif->hwaddr_len;
while(i > 0) {
i--;
hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];
hdr->shwaddr.addr[i] = ethaddr->addr[i];
hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i];
hdr->ethhdr.src.addr[i] = ethaddr->addr[i];
}
hdr->hwtype = htons(HWTYPE_ETHERNET);
ARPH_HWLEN_SET(hdr, netif->hwaddr_len);
hdr->proto = htons(ETHTYPE_IP);
ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
hdr->ethhdr.type = htons(ETHTYPE_ARP);
/* 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 | 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 | 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 | 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 | DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode)));
break;
}
/* free ARP packet */
pbuf_free(p);
}
/**
* Resolve and fill-in Ethernet address header for outgoing 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 ipaddr The IP address of the packet destination.
* @param pbuf The pbuf(s) containing the IP packet to be sent.
*
* @return
* - ERR_RTE No route to destination (no gateway to external networks),
* or the return type of either etharp_query() or netif->linkoutput().
*/
err_t
etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
{
struct eth_addr *dest, *srcaddr, mcastaddr;
struct eth_hdr *ethhdr;
u8_t i;
/* make room for Ethernet header - should not fail */
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
/* bail out */
LWIP_DEBUGF(ETHARP_DEBUG | 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 */
srcaddr = (struct eth_addr *)netif->hwaddr;
ethhdr = q->payload;
i = netif->hwaddr_len;
while(i > 0) {
i--;
ethhdr->dest.addr[i] = dest->addr[i];
ethhdr->src.addr[i] = srcaddr->addr[i];
}
ethhdr->type = htons(ETHTYPE_IP);
/* send packet directly on the link */
return netif->linkoutput(netif, q);
}
/**
* 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.
*
* @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 */
u8_t k; /* Ethernet address octet index */
/* non-unicast address? */
if (ip_addr_isbroadcast(ipaddr, netif) ||
ip_addr_ismulticast(ipaddr) ||
ip_addr_isany(ipaddr)) {
LWIP_DEBUGF(ETHARP_DEBUG | 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 */
i = find_entry(ipaddr, ETHARP_TRY_HARD);
/* could not find or create entry? */
if (i < 0)
{
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not create ARP entry\n"));
if (q) LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: packet dropped\n"));
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);
}
/* packet given? */
if (q != NULL) {
/* stable entry? */
if (arp_table[i].state == ETHARP_STATE_STABLE) {
/* we have a valid IP->Ethernet address mapping,
* fill in the Ethernet header for the outgoing packet */
struct eth_hdr *ethhdr = q->payload;
k = netif->hwaddr_len;
while(k > 0) {
k--;
ethhdr->dest.addr[k] = arp_table[i].ethaddr.addr[k];
ethhdr->src.addr[k] = srcaddr->addr[k];
}
ethhdr->type = htons(ETHTYPE_IP);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending packet %p\n", (void *)q));
/* send the packet */
result = netif->linkoutput(netif, q);
/* 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;
/* copy any PBUF_REF referenced payloads into PBUF_RAM */
/* (the caller of lwIP assumes the referenced payload can be
* freed after it returns from the lwIP call that brought us here) */
p = pbuf_take(q);
/* packet could be taken over? */
if (p != NULL) {
/* queue packet ... */
if (arp_table[i].p == NULL) {
/* ... in the empty queue */
pbuf_ref(p);
arp_table[i].p = p;
#if 0 /* multi-packet-queueing disabled, see bug #11400 */
} else {
/* ... at tail of non-empty queue */
pbuf_queue(arp_table[i].p, p);
#endif
}
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
result = ERR_OK;
} else {
LWIP_DEBUGF(ETHARP_DEBUG | 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 | DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));
#endif
}
}
return result;
}
err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr)
{
struct pbuf *p;
struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
err_t result = ERR_OK;
u8_t k; /* ARP entry index */
/* allocate a pbuf for the outgoing ARP request packet */
p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);
/* could allocate a pbuf for an ARP request? */
if (p != NULL) {
struct etharp_hdr *hdr = p->payload;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_request: sending ARP request.\n"));
hdr->opcode = htons(ARP_REQUEST);
k = netif->hwaddr_len;
while(k > 0) {
k--;
hdr->shwaddr.addr[k] = srcaddr->addr[k];
/* the hardware address is what we ask for, in
* a request it is a don't-care value, we use zeroes */
hdr->dhwaddr.addr[k] = 0x00;
}
hdr->dipaddr = *(struct ip_addr2 *)ipaddr;
hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;
hdr->hwtype = htons(HWTYPE_ETHERNET);
ARPH_HWLEN_SET(hdr, netif->hwaddr_len);
hdr->proto = htons(ETHTYPE_IP);
ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
k = netif->hwaddr_len;
while(k > 0) {
k--;
/* broadcast to all network interfaces on the local network */
hdr->ethhdr.dest.addr[k] = 0xff;
hdr->ethhdr.src.addr[k] = srcaddr->addr[k];
}
hdr->ethhdr.type = htons(ETHTYPE_ARP);
/* send ARP query */
result = netif->linkoutput(netif, p);
/* free ARP query packet */
pbuf_free(p);
p = NULL;
/* could not allocate pbuf for ARP request */
} else {
result = ERR_MEM;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_request: could not allocate pbuf for ARP request.\n"));
}
return result;
}
#endif

View File

@ -0,0 +1,332 @@
/*
* 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>
*
*/
#ifdef EXCLUDE
/*
* 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"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include <lwip/stats.h>
#include "netif/etharp.h"
u8_t U8t_DUMMY_VARIABLE = 0;
u16_t U16t_DUMMY_VARIABLE = 0;
/* Define those to better describe your network interface. */
#define IFNAME0 'e'
#define IFNAME1 'n'
struct ethernetif {
struct eth_addr *ethaddr;
/* Add whatever per-interface state that is needed here. */
};
static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
/* Forward declarations. */
static void ethernetif_input(struct netif *netif);
static err_t ethernetif_output(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr);
static void low_level_init(struct netif *netif)
{
struct ethernetif *ethernetif = netif->state;
/* set MAC hardware address length */
netif->hwaddr_len = 6;
/* set MAC hardware address */
netif->hwaddr[0] = U8t_DUMMY_VARIABLE;
netif->hwaddr[5] = U8t_DUMMY_VARIABLE;
/* maximum transfer unit */
netif->mtu = 1500;
/* broadcast capability */
netif->flags = NETIF_FLAG_BROADCAST;
/* Do whatever else is needed to initialize interface. */
}
/*
* low_level_output():
*
* 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.
*
*/
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
#if LINK_STATS
lwip_stats.link.xmit++;
#endif /* LINK_STATS */
return ERR_OK;
}
/*
* low_level_input():
*
* Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
*/
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 = U16t_DUMMY_VARIABLE;
#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
#if LINK_STATS
lwip_stats.link.recv++;
#endif /* LINK_STATS */
} else {
//drop packet();
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif /* LINK_STATS */
}
return p;
}
/*
* ethernetif_output():
*
* This function is called by the TCP/IP stack when an IP packet
* should be sent. It calls the function called low_level_output() to
* do the actual transmission of the packet.
*
*/
static err_t
ethernetif_output(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr)
{
/* resolve hardware address, then send (or queue) packet */
return etharp_output(netif, ipaddr, p);
}
/*
* ethernetif_input():
*
* 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.
*
*/
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;
#if LINK_STATS
lwip_stats.link.recv++;
#endif /* LINK_STATS */
ethhdr = p->payload;
switch (htons(ethhdr->type)) {
/* IP packet? */
case ETHTYPE_IP:
#if 0
/* CSi disabled ARP table update on ingress IP packets.
This seems to work but needs thorough testing. */
/* update ARP table */
etharp_ip_input(netif, p);
#endif
/* skip Ethernet header */
pbuf_header(p, -sizeof(struct eth_hdr));
/* pass to network layer */
netif->input(p, netif);
break;
case ETHTYPE_ARP:
/* pass p to ARP module */
etharp_arp_input(netif, ethernetif->ethaddr, p);
break;
default:
pbuf_free(p);
p = NULL;
break;
}
}
static void
arp_timer(void *arg)
{
etharp_tmr();
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
}
/*
* ethernetif_init():
*
* 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.
*
*/
err_t
ethernetif_init(struct netif *netif)
{
struct ethernetif *ethernetif;
ethernetif = mem_malloc(sizeof(struct ethernetif));
if (ethernetif == NULL)
{
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
return ERR_MEM;
}
#if LWIP_SNMP
/* ifType ethernetCsmacd(6) @see RFC1213 */
netif->link_type = 6;
/* your link speed here */
netif->link_speed = ;
netif->ts = 0;
netif->ifinoctets = 0;
netif->ifinucastpkts = 0;
netif->ifinnucastpkts = 0;
netif->ifindiscards = 0;
netif->ifoutoctets = 0;
netif->ifoutucastpkts = 0;
netif->ifoutnucastpkts = 0;
netif->ifoutdiscards = 0;
#endif
netif->state = ethernetif;
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->output = ethernetif_output;
netif->linkoutput = low_level_output;
ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
low_level_init(netif);
etharp_init();
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
return ERR_OK;
}
#endif

119
lwip/netif/loopif.c Normal file
View File

@ -0,0 +1,119 @@
/*
* 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/mem.h"
#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)
#include "netif/tcpdump.h"
#endif /* LWIP_DEBUG && LWIP_TCPDUMP */
#include "lwip/tcp.h"
#include "lwip/ip.h"
static void
loopif_input( void * arg )
{
struct netif *netif = (struct netif *)( ((void **)arg)[ 0 ] );
struct pbuf *r = (struct pbuf *)( ((void **)arg)[ 1 ] );
mem_free( arg );
netif -> input( r, netif );
}
static err_t
loopif_output(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr)
{
struct pbuf *q, *r;
u8_t *ptr;
void **arg;
#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)
tcpdump(p);
#endif /* LWIP_DEBUG && LWIP_TCPDUMP */
r = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
if (r != NULL) {
ptr = r->payload;
for(q = p; q != NULL; q = q->next) {
memcpy(ptr, q->payload, q->len);
ptr += q->len;
}
arg = mem_malloc( sizeof( void *[2]));
if( NULL == arg ) {
return ERR_MEM;
}
arg[0] = netif;
arg[1] = r;
/**
* workaround (patch #1779) to try to prevent bug #2595:
* When connecting to "localhost" with the loopif interface,
* tcp_output doesn't get the opportunity to finnish sending the
* segment before tcp_process gets it, resulting in tcp_process
* referencing pcb->unacked-> which still is NULL.
*
* TODO: Is there still a race condition here? Leon
*/
sys_timeout( 1, loopif_input, arg );
return ERR_OK;
}
return ERR_MEM;
}
err_t
loopif_init(struct netif *netif)
{
netif->name[0] = 'l';
netif->name[1] = 'o';
#if 0 /** TODO: I think this should be enabled, or not? Leon */
netif->input = loopif_input;
#endif
netif->output = loopif_output;
return ERR_OK;
}
#endif /* LWIP_HAVE_LOOPIF */

927
lwip/netif/ppp/auth.c Normal file
View File

@ -0,0 +1,927 @@
/*****************************************************************************
* 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 "ppp.h"
#if PPP_SUPPORT > 0
#include "fsm.h"
#include "lcp.h"
#include "pap.h"
#include "chap.h"
#include "auth.h"
#include "ipcp.h"
#if CBCP_SUPPORT > 0
#include "cbcp.h"
#endif
#include "pppdebug.h"
/*************************/
/*** 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 > 0 || CHAP_SUPPORT > 0 */
static void set_allowed_addrs(int unit, struct wordlist *addrs);
static void free_wordlist (struct wordlist *);
#endif
#if CBCP_SUPPORT > 0
static void callback_phase (int);
#endif
/******************************/
/*** PUBLIC DATA STRUCTURES ***/
/******************************/
/*****************************/
/*** LOCAL DATA STRUCTURES ***/
/*****************************/
#if PAP_SUPPORT > 0 || CHAP_SUPPORT > 0
/* The name by which the peer authenticated itself to us. */
static char peer_authname[MAXNAMELEN];
#endif
/* 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 > 0 || CHAP_SUPPORT > 0
/* Set if we got the contents of passwd[] from the pap-secrets file. */
static int passwd_from_file;
#endif
/***********************************/
/*** 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)
{
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"));
pppMainWakeup(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;
pppMainWakeup(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 > 0 || CHAP_SUPPORT > 0
lcp_options *ho = &lcp_hisoptions[unit];
#endif
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 > 0
if (go->neg_chap) {
ChapAuthPeer(unit, ppp_settings.our_name, go->chap_mdtype);
auth |= CHAP_PEER;
}
#endif
#if PAP_SUPPORT > 0 && CHAP_SUPPORT > 0
else
#endif
#if PAP_SUPPORT > 0
if (go->neg_upap) {
upap_authpeer(unit);
auth |= PAP_PEER;
}
#endif
#if CHAP_SUPPORT > 0
if (ho->neg_chap) {
ChapAuthWithPeer(unit, ppp_settings.user, ho->chap_mdtype);
auth |= CHAP_WITHPEER;
}
#endif
#if PAP_SUPPORT > 0 && CHAP_SUPPORT > 0
else
#endif
#if PAP_SUPPORT > 0
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
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)
{
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 > 0 || CHAP_SUPPORT > 0
/*
* 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;
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
/*
* np_up - a network protocol has come up.
*/
void np_up(int unit, u16_t 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)
{
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)
{
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 > 0
/*
* 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
*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
/*
* 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 > 0
/*
* 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;
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
#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 > 0
/*
* If we negotiated callback, do it now.
*/
if (go->neg_cbcp) {
lcp_phase[unit] = PHASE_CALLBACK;
(*cbcp_protent.open)(unit);
return;
}
#endif
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;
(void)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)
{
(void)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)
{
(void)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)
{
/* 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)
{
(void)client;
(void)server;
(void)remote;
/* XXX Fail until we set up our passwords. */
return 0;
}
#if 0 /* PAP_SUPPORT > 0 || CHAP_SUPPORT > 0 */
/*
* 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
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 > 0 || 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
#endif /* PPP_SUPPORT */

94
lwip/netif/ppp/auth.h Normal file
View File

@ -0,0 +1,94 @@
/*****************************************************************************
* 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 ***
***********************/
void link_required (int); /* we are starting to use the link */
void link_terminated (int); /* we are finished with the link */
void link_down (int); /* the LCP layer has left the Opened state */
void link_established (int); /* the link is up; authenticate now */
void np_up (int, u16_t); /* a network protocol has come up */
void np_down (int, u16_t); /* a network protocol has gone down */
void np_finished (int, u16_t); /* a network protocol no longer needs link */
void auth_peer_fail (int, u16_t);/* peer failed to authenticate itself */
/* 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);
void auth_reset (int); /* check what secrets we have */
/* 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 */

872
lwip/netif/ppp/chap.c Normal file
View File

@ -0,0 +1,872 @@
/*** 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 "ppp.h"
#if PPP_SUPPORT > 0
#include "magic.h"
#if CHAP_SUPPORT > 0
#include "randm.h"
#include "auth.h"
#include "md5.h"
#include "chap.h"
#include "chpms.h"
#include "pppdebug.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);
static int ChapPrintPkt (u_char *, int,
void (*) (void *, char *, ...), void *);
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
};
/*****************************/
/*** LOCAL DATA STRUCTURES ***/
/*****************************/
static char *ChapCodenames[] = {
"Challenge", "Response", "Success", "Failure"
};
/***********************************/
/*** 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)
{
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)
{
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;
}
/*
* 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 /* PPP_SUPPORT */

167
lwip/netif/ppp/chap.h Normal file
View File

@ -0,0 +1,167 @@
/*****************************************************************************
* 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.1 2003/05/27 14:37:56 jani 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 */

398
lwip/netif/ppp/chpms.c Normal file
View File

@ -0,0 +1,398 @@
/*** 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 "ppp.h"
#if MSCHAP_SUPPORT > 0
#include "md4.h"
#ifndef USE_CRYPT
#include "des.h"
#endif
#include "chap.h"
#include "chpms.h"
#include "pppdebug.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 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 */

64
lwip/netif/ppp/chpms.h Normal file
View File

@ -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.3 2004/02/07 00:30:03 likewise 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 */

838
lwip/netif/ppp/fsm.c Normal file
View File

@ -0,0 +1,838 @@
/*****************************************************************************
* 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 "ppp.h"
#if PPP_SUPPORT > 0
#include "fsm.h"
#include "pppdebug.h"
/*************************/
/*** LOCAL DEFINITIONS ***/
/*************************/
/************************/
/*** 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 = 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;
switch( f->state ){
case INITIAL:
f->state = CLOSED;
break;
case STARTING:
if( f->flags & OPT_SILENT )
f->state = STOPPED;
else {
/* Send an initial configure-request */
fsm_sconfreq(f, 0);
f->state = REQSENT;
}
break;
default:
FSMDEBUG((LOG_INFO, "%s: Up event in state %d!\n",
PROTO_NAME(f), f->state));
}
FSMDEBUG((LOG_INFO, "%s: lowerup state %d -> %d\n",
PROTO_NAME(f), oldState, 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;
switch( f->state ){
case CLOSED:
f->state = INITIAL;
break;
case STOPPED:
f->state = STARTING;
if( f->callbacks->starting )
(*f->callbacks->starting)(f);
break;
case CLOSING:
f->state = INITIAL;
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
break;
case STOPPING:
case REQSENT:
case ACKRCVD:
case ACKSENT:
f->state = STARTING;
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
break;
case OPENED:
if( f->callbacks->down )
(*f->callbacks->down)(f);
f->state = STARTING;
break;
default:
FSMDEBUG((LOG_INFO, "%s: Down event in state %d!\n",
PROTO_NAME(f), f->state));
}
FSMDEBUG((LOG_INFO, "%s: lowerdown state %d -> %d\n",
PROTO_NAME(f), oldState, f->state));
}
/*
* fsm_open - Link is allowed to come up.
*/
void fsm_open(fsm *f)
{
int oldState = f->state;
switch( f->state ){
case INITIAL:
f->state = STARTING;
if( f->callbacks->starting )
(*f->callbacks->starting)(f);
break;
case CLOSED:
if( f->flags & OPT_SILENT )
f->state = STOPPED;
else {
/* Send an initial configure-request */
fsm_sconfreq(f, 0);
f->state = REQSENT;
}
break;
case CLOSING:
f->state = STOPPING;
/* fall through */
case STOPPED:
case OPENED:
if( f->flags & OPT_RESTART ){
fsm_lowerdown(f);
fsm_lowerup(f);
}
break;
}
FSMDEBUG((LOG_INFO, "%s: open state %d -> %d\n",
PROTO_NAME(f), oldState, f->state));
}
/*
* fsm_close - Start closing connection.
*
* Cancel timeouts and either initiate close or possibly go directly to
* the CLOSED state.
*/
void fsm_close(fsm *f, char *reason)
{
int oldState = f->state;
f->term_reason = reason;
f->term_reason_len = (reason == NULL? 0: strlen(reason));
switch( f->state ){
case STARTING:
f->state = INITIAL;
break;
case STOPPED:
f->state = CLOSED;
break;
case STOPPING:
f->state = CLOSING;
break;
case REQSENT:
case ACKRCVD:
case ACKSENT:
case OPENED:
if( f->state != 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 = CLOSING;
break;
}
FSMDEBUG((LOG_INFO, "%s: close reason=%s state %d -> %d\n",
PROTO_NAME(f), reason, oldState, 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 == INITIAL || f->state == STARTING ){
FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.\n",
f->protocol, 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 CLOSING:
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
/* fall through */
case CLOSED:
f->state = CLOSED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case STOPPING:
case REQSENT:
case ACKRCVD:
case ACKSENT:
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
/* fall through */
case STOPPED:
f->state = STOPPED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case 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 = STOPPING;
break;
default:
FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!\n",
PROTO_NAME(f), f->state));
}
}
/**********************************/
/*** LOCAL FUNCTION DEFINITIONS ***/
/**********************************/
/*
* fsm_timeout - Timeout expired.
*/
static void fsm_timeout(void *arg)
{
fsm *f = (fsm *) arg;
switch (f->state) {
case CLOSING:
case STOPPING:
if( f->retransmits <= 0 ){
FSMDEBUG((LOG_WARNING, "%s: timeout sending Terminate-Request state=%d\n",
PROTO_NAME(f), f->state));
/*
* We've waited for an ack long enough. Peer probably heard us.
*/
f->state = (f->state == CLOSING)? CLOSED: STOPPED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
} else {
FSMDEBUG((LOG_WARNING, "%s: timeout resending Terminate-Requests state=%d\n",
PROTO_NAME(f), 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 REQSENT:
case ACKRCVD:
case ACKSENT:
if (f->retransmits <= 0) {
FSMDEBUG((LOG_WARNING, "%s: timeout sending Config-Requests state=%d\n",
PROTO_NAME(f), f->state));
f->state = 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\n",
PROTO_NAME(f), 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 == ACKRCVD )
f->state = REQSENT;
}
break;
default:
FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!\n",
PROTO_NAME(f), 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\n",
PROTO_NAME(f), id, f->state));
switch( f->state ){
case CLOSED:
/* Go away, we're closed */
fsm_sdata(f, TERMACK, id, NULL, 0);
return;
case CLOSING:
case STOPPING:
return;
case 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 STOPPED:
/* Negotiation started by our peer */
fsm_sconfreq(f, 0); /* Send initial Configure-Request */
f->state = 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 == ACKRCVD) {
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
f->state = OPENED;
if (f->callbacks->up)
(*f->callbacks->up)(f); /* Inform upper layers */
}
else
f->state = ACKSENT;
f->nakloops = 0;
}
else {
/* we sent CONFACK or CONFREJ */
if (f->state != ACKRCVD)
f->state = 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\n",
PROTO_NAME(f), id, 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 CLOSED:
case STOPPED:
fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
break;
case REQSENT:
f->state = ACKRCVD;
f->retransmits = f->maxconfreqtransmits;
break;
case ACKRCVD:
/* Huh? an extra valid Ack? oh well... */
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
fsm_sconfreq(f, 0);
f->state = REQSENT;
break;
case ACKSENT:
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
f->state = OPENED;
f->retransmits = f->maxconfreqtransmits;
if (f->callbacks->up)
(*f->callbacks->up)(f); /* Inform upper layers */
break;
case 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 = 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\n",
PROTO_NAME(f), id, 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 CLOSED:
case STOPPED:
fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
break;
case REQSENT:
case ACKSENT:
/* They didn't agree to what we wanted - try another request */
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
if (ret < 0)
f->state = STOPPED; /* kludge for stopping CCP */
else
fsm_sconfreq(f, 0); /* Send Configure-Request */
break;
case 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 = REQSENT;
break;
case 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 = REQSENT;
break;
}
}
/*
* fsm_rtermreq - Receive Terminate-Req.
*/
static void fsm_rtermreq(fsm *f, int id, u_char *p, int len)
{
FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d state=%d\n",
PROTO_NAME(f), id, f->state));
switch (f->state) {
case ACKRCVD:
case ACKSENT:
f->state = REQSENT; /* Start over but keep trying */
break;
case 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 = 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\n",
PROTO_NAME(f), f->state));
switch (f->state) {
case CLOSING:
UNTIMEOUT(fsm_timeout, f);
f->state = CLOSED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case STOPPING:
UNTIMEOUT(fsm_timeout, f);
f->state = STOPPED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case ACKRCVD:
f->state = REQSENT;
break;
case 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\n",
PROTO_NAME(f), 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 == ACKRCVD )
f->state = REQSENT;
}
/*
* fsm_sconfreq - Send a Configure-Request.
*/
static void fsm_sconfreq(fsm *f, int retransmit)
{
u_char *outp;
int cilen;
if( f->state != REQSENT && f->state != ACKRCVD && f->state != 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 */

187
lwip/netif/ppp/fsm.h Normal file
View File

@ -0,0 +1,187 @@
/*****************************************************************************
* 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.1 2003/05/27 14:37:56 jani 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 INITIAL 0 /* Down, hasn't been opened */
#define STARTING 1 /* Down, been opened */
#define CLOSED 2 /* Up, hasn't been opened */
#define STOPPED 3 /* Open, waiting for down event */
#define CLOSING 4 /* Terminating the connection, not open */
#define STOPPING 5 /* Terminating, but open */
#define REQSENT 6 /* We've sent a Config Request */
#define ACKRCVD 7 /* We've received a Config Ack */
#define ACKSENT 8 /* We've sent a Config Ack */
#define 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) /* Reset our Configuration Information */
(fsm*);
int (*cilen) /* Length of our Configuration Information */
(fsm*);
void (*addci) /* Add our Configuration Information */
(fsm*, u_char*, int*);
int (*ackci) /* ACK our Configuration Information */
(fsm*, u_char*, int);
int (*nakci) /* NAK our Configuration Information */
(fsm*, u_char*, int);
int (*rejci) /* Reject our Configuration Information */
(fsm*, u_char*, int);
int (*reqci) /* Request peer's Configuration Information */
(fsm*, u_char*, int*, int);
void (*up) /* Called when fsm reaches OPENED state */
(fsm*);
void (*down) /* Called when fsm leaves OPENED state */
(fsm*);
void (*starting) /* Called when we want the lower layer */
(fsm*);
void (*finished) /* Called when we don't want the lower layer */
(fsm*);
void (*protreject) /* Called when Protocol-Reject received */
(int);
void (*retransmit) /* Retransmission is necessary */
(fsm*);
int (*extcode) /* Called when unknown code received */
(fsm*, int, u_char, u_char*, int);
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 */

1377
lwip/netif/ppp/ipcp.c Normal file

File diff suppressed because it is too large Load Diff

126
lwip/netif/ppp/ipcp.h Normal file
View File

@ -0,0 +1,126 @@
/*****************************************************************************
* 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.1 2003/05/27 14:37:56 jani 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 */

1991
lwip/netif/ppp/lcp.c Normal file

File diff suppressed because it is too large Load Diff

169
lwip/netif/ppp/lcp.h Normal file
View File

@ -0,0 +1,169 @@
/*****************************************************************************
* 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.1 2003/05/27 14:37:56 jani 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 */

79
lwip/netif/ppp/magic.c Normal file
View File

@ -0,0 +1,79 @@
/*****************************************************************************
* 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 "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();
}

64
lwip/netif/ppp/magic.h Normal file
View File

@ -0,0 +1,64 @@
/*****************************************************************************
* 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.1 2003/05/27 14:37:56 jani Exp $
*/
#ifndef MAGIC_H
#define MAGIC_H
/*****************************************************************************
************************** PUBLIC FUNCTIONS **********************************
*****************************************************************************/
void magicInit(void); /* Initialize the magic number generator */
u32_t magic(void); /* Returns the next magic number */
#endif /* MAGIC_H */

306
lwip/netif/ppp/md5.c Normal file
View File

@ -0,0 +1,306 @@
/*
***********************************************************************
** 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 "ppp.h"
#include "md5.h"
#include "pppdebug.h"
#if CHAP_SUPPORT > 0 || MD5_SUPPORT > 0
/*
***********************************************************************
** 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);
}
memcpy(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

55
lwip/netif/ppp/md5.h Normal file
View File

@ -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 */

608
lwip/netif/ppp/pap.c Normal file
View File

@ -0,0 +1,608 @@
/*****************************************************************************
* 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 "ppp.h"
#include "auth.h"
#include "pap.h"
#include "pppdebug.h"
#if PAP_SUPPORT > 0
/***********************************/
/*** 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;
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;
UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d s=%d\n", id, u->us_clientstate));
if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
return;
/*
* Parse message.
*/
if (len < sizeof (u_char)) {
UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));
return;
}
GETCHAR(msglen, inp);
len -= sizeof (u_char);
if (len < msglen) {
UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));
return;
}
msg = (char *) inp;
PRINTMSG(msg, msglen);
u->us_clientstate = UPAPCS_BADAUTH;
UPAPDEBUG((LOG_ERR, "PAP authentication failed\n"));
auth_withpeer_fail(u->us_unit, PPP_PAP);
}
/*
* upap_sauthreq - Send an Authenticate-Request.
*/
static void upap_sauthreq(upap_state *u)
{
u_char *outp;
int outlen;
outlen = UPAP_HEADERLEN + 2 * sizeof (u_char)
+ u->us_userlen + u->us_passwdlen;
outp = outpacket_buf[u->us_unit];
MAKEHEADER(outp, PPP_PAP);
PUTCHAR(UPAP_AUTHREQ, outp);
PUTCHAR(++u->us_id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(u->us_userlen, outp);
BCOPY(u->us_user, outp, u->us_userlen);
INCPTR(u->us_userlen, outp);
PUTCHAR(u->us_passwdlen, outp);
BCOPY(u->us_passwd, outp, u->us_passwdlen);
pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);
UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d\n", u->us_id));
TIMEOUT(upap_timeout, u, u->us_timeouttime);
++u->us_transmits;
u->us_clientstate = UPAPCS_AUTHREQ;
}
/*
* upap_sresp - Send a response (ack or nak).
*/
static void upap_sresp(
upap_state *u,
u_char code,
u_char id,
char *msg,
int msglen
)
{
u_char *outp;
int outlen;
outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
outp = outpacket_buf[u->us_unit];
MAKEHEADER(outp, PPP_PAP);
PUTCHAR(code, outp);
PUTCHAR(id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(msglen, outp);
BCOPY(msg, outp, msglen);
pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);
UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d s=%d\n",
code, id, u->us_clientstate));
}
#if 0
/*
* upap_printpkt - print the contents of a PAP packet.
*/
static int upap_printpkt(
u_char *p,
int plen,
void (*printer) (void *, char *, ...),
void *arg
)
{
(void)p;
(void)plen;
(void)printer;
(void)arg;
return 0;
}
#endif
#endif /* PAP_SUPPORT */

129
lwip/netif/ppp/pap.h Normal file
View File

@ -0,0 +1,129 @@
/*****************************************************************************
* 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
/*************************
*** 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_H */

1631
lwip/netif/ppp/ppp.c Normal file

File diff suppressed because it is too large Load Diff

447
lwip/netif/ppp/ppp.h Normal file
View File

@ -0,0 +1,447 @@
/*****************************************************************************
* 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"
//#include "lwipopts.h"
#if PPP_SUPPORT > 0
#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); \
}
#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
#define PRINTMSG(m, l)
#endif
/*
* 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][PPP_MRU+PPP_HDRLEN];
extern struct ppp_settings ppp_settings;
extern struct protent *ppp_protocols[];/* Table of pointers to supported protocols */
/***********************
*** PUBLIC FUNCTIONS ***
***********************/
/* Initialize the PPP subsystem. */
void 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 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 pppOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx);
/*
* 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 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 */

89
lwip/netif/ppp/pppdebug.h Normal file
View File

@ -0,0 +1,89 @@
/*****************************************************************************
* 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,...);
#if PPP_DEBUG > 0
#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
#define TRACELCP 1
#else
#define AUTHDEBUG(a)
#define IPCPDEBUG(a)
#define UPAPDEBUG(a)
#define LCPDEBUG(a)
#define FSMDEBUG(a)
#define CHAPDEBUG(a)
#define PPPDEBUG(a)
#define TRACELCP 0
#endif
#endif /* PPPDEBUG_H */

242
lwip/netif/ppp/randm.c Normal file
View File

@ -0,0 +1,242 @@
/*****************************************************************************
* 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 "ppp.h"
#if PPP_SUPPORT > 0
#include "md5.h"
#include "randm.h"
#include "pppdebug.h"
#if MD5_SUPPORT>0 /* 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 */

81
lwip/netif/ppp/randm.h Normal file
View File

@ -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
void avRandomize(void);
#endif
/*
* 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 */

633
lwip/netif/ppp/vj.c Normal file
View File

@ -0,0 +1,633 @@
/*
* 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 <string.h>
#include "ppp.h"
#include "vj.h"
#include "pppdebug.h"
#if VJ_SUPPORT > 0
#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;
pbuf_header(pb, -hlen);
cp = (u_char *)pb->payload;
*cp++ = changes | NEW_C;
*cp++ = cs->cs_id;
} else {
hlen -= deltaS + 3;
pbuf_header(pb, -hlen);
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. */
pbuf_header(n0, -vjlen);
if(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"));
*nb = NULL;
goto bad;
}
pbuf_header(np, -cs->cs_hlen);
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"));
*nb = NULL;
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

155
lwip/netif/ppp/vj.h Normal file
View File

@ -0,0 +1,155 @@
/*
* Definitions for tcp compression routines.
*
* $Id: vj.h,v 1.4 2004/02/07 00:30:03 likewise 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 */

76
lwip/netif/ppp/vjbsdhdr.h Normal file
View File

@ -0,0 +1,76 @@
#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 */

213
lwip/netif/slipif.c Normal file
View File

@ -0,0 +1,213 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is built upon the file: src/arch/rtxc/netif/sioslip.c
*
* Author: Magnus Ivarsson <magnus.ivarsson(at)volvo.com>
*/
/*
* This is an arch independent SLIP netif. The specific serial hooks must be
* provided by another file. They are sio_open, sio_recv and sio_send
*/
#include "netif/slipif.h"
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "lwip/stats.h"
#include "lwip/sio.h"
#define SLIP_END 0300
#define SLIP_ESC 0333
#define SLIP_ESC_END 0334
#define SLIP_ESC_ESC 0335
#define MAX_SIZE 1500
/**
* Send a pbuf doing the necessary SLIP encapsulation
*
* Uses the serial layer's sio_send()
*/
err_t
slipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
{
struct pbuf *q;
u16_t i;
u8_t c;
/* 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 0;
}
/**
* Handle the incoming SLIP stream character by character
*
* Poll the serial layer by calling sio_recv()
*
* @return The IP packet when SLIP_END is received
*/
static struct pbuf *
slipif_input(struct netif *netif)
{
u8_t c;
struct pbuf *p, *q;
u16_t recved;
u16_t i;
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. */
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:
if (p == NULL) {
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"));
}
if (q != NULL) {
pbuf_cat(q, p);
} else {
q = p;
}
}
if (p != NULL && recved < MAX_SIZE) {
((u8_t *)p->payload)[i] = c;
recved++;
i++;
if (i >= p->len) {
i = 0;
if (p->next != NULL && p->next->len > 0)
p = p->next;
else
p = NULL;
}
}
break;
}
}
return NULL;
}
/**
* The SLIP input thread.
*
* Feed the IP layer with incoming packets
*/
static void
slipif_loop(void *nf)
{
struct pbuf *p;
struct netif *netif = (struct netif *)nf;
while (1) {
p = slipif_input(netif);
netif->input(p, netif);
}
}
/**
* SLIP netif initialization
*
* Call the arch specific sio_open and remember
* the opened device in the state field of the netif.
*/
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 = 1500;
netif->flags = NETIF_FLAG_POINTTOPOINT;
netif->state = sio_open(netif->num);
if (!netif->state)
return ERR_IF;
sys_thread_new(slipif_loop, netif, SLIPIF_THREAD_PRIO);
return ERR_OK;
}