rel_1.6.0 init

This commit is contained in:
guocheng.kgc 2020-06-18 20:06:52 +08:00 committed by shengdong.dsd
commit 27b3e2883d
19359 changed files with 8093121 additions and 0 deletions

View file

@ -0,0 +1,24 @@
This directory contains generic network interface device drivers that
do not contain any hardware or architecture specific code. The files
are:
ethernet.c
Shared code for Ethernet based interfaces.
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.
lowpan6.c
A 6LoWPAN implementation as a netif.
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
The lwIP PPP support is based from pppd (http://ppp.samba.org) with
huge changes to match code size and memory requirements for embedded
devices. Please read /doc/ppp.txt and ppp/PPPD_FOLLOWUP for a detailed
explanation.

View file

@ -0,0 +1,310 @@
/**
* @file
* Ethernet common functions
*
* @defgroup ethernet Ethernet
* @ingroup callbackstyle_api
*/
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
* Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include "lwip/opt.h"
#if LWIP_ARP || LWIP_ETHERNET
#include "netif/ethernet.h"
#include "lwip/def.h"
#include "lwip/stats.h"
#include "lwip/etharp.h"
#include "lwip/ip.h"
#include "lwip/snmp.h"
#include <string.h>
#include "netif/ppp/ppp_opts.h"
#if PPPOE_SUPPORT
#include "netif/ppp/pppoe.h"
#endif /* PPPOE_SUPPORT */
const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
const struct eth_addr ethzero = {{0,0,0,0,0,0}};
/**
* @ingroup lwip_nosys
* Process received ethernet frames. Using this function instead of directly
* calling ip_input and passing ARP frames through etharp in ethernetif_input,
* the ARP cache is protected from concurrent access.\n
* Don't call directly, pass to netif_add() and call netif->input().
*
* @param p the received packet, p->payload pointing to the ethernet header
* @param netif the network interface on which the packet was received
*
* @see LWIP_HOOK_UNKNOWN_ETH_PROTOCOL
* @see ETHARP_SUPPORT_VLAN
* @see LWIP_HOOK_VLAN_CHECK
*/
err_t
ethernet_input(struct pbuf *p, struct netif *netif)
{
struct eth_hdr* ethhdr;
u16_t type;
#if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6
s16_t ip_hdr_offset = SIZEOF_ETH_HDR;
#endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */
if (p->len <= SIZEOF_ETH_HDR) {
/* a packet with only an ethernet header (or less) is not valid for us */
ETHARP_STATS_INC(etharp.proterr);
ETHARP_STATS_INC(etharp.drop);
MIB2_STATS_NETIF_INC(netif, ifinerrors);
goto free_and_return;
}
/* points to packet payload, which starts with an Ethernet header */
ethhdr = (struct eth_hdr *)p->payload;
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n",
(unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2],
(unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5],
(unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2],
(unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5],
lwip_htons(ethhdr->type)));
type = ethhdr->type;
#if ETHARP_SUPPORT_VLAN
if (type == PP_HTONS(ETHTYPE_VLAN)) {
struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR);
if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) {
/* a packet with only an ethernet/vlan header (or less) is not valid for us */
ETHARP_STATS_INC(etharp.proterr);
ETHARP_STATS_INC(etharp.drop);
MIB2_STATS_NETIF_INC(netif, ifinerrors);
goto free_and_return;
}
#if defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */
#ifdef LWIP_HOOK_VLAN_CHECK
if (!LWIP_HOOK_VLAN_CHECK(netif, ethhdr, vlan)) {
#elif defined(ETHARP_VLAN_CHECK_FN)
if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) {
#elif defined(ETHARP_VLAN_CHECK)
if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) {
#endif
/* silently ignore this packet: not for our VLAN */
pbuf_free(p);
return ERR_OK;
}
#endif /* defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */
type = vlan->tpid;
ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR;
}
#endif /* ETHARP_SUPPORT_VLAN */
#if LWIP_ARP_FILTER_NETIF
netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, lwip_htons(type));
#endif /* LWIP_ARP_FILTER_NETIF*/
if (ethhdr->dest.addr[0] & 1) {
/* this might be a multicast or broadcast packet */
if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) {
#if LWIP_IPV4
if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) &&
(ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2)) {
/* mark the pbuf as link-layer multicast */
p->flags |= PBUF_FLAG_LLMCAST;
}
#endif /* LWIP_IPV4 */
}
#if LWIP_IPV6
else if ((ethhdr->dest.addr[0] == LL_IP6_MULTICAST_ADDR_0) &&
(ethhdr->dest.addr[1] == LL_IP6_MULTICAST_ADDR_1)) {
/* mark the pbuf as link-layer multicast */
p->flags |= PBUF_FLAG_LLMCAST;
}
#endif /* LWIP_IPV6 */
else if (eth_addr_cmp(&ethhdr->dest, &ethbroadcast)) {
/* mark the pbuf as link-layer broadcast */
p->flags |= PBUF_FLAG_LLBCAST;
}
}
switch (type) {
#if LWIP_IPV4 && LWIP_ARP
/* IP packet? */
case PP_HTONS(ETHTYPE_IP):
if (!(netif->flags & NETIF_FLAG_ETHARP)) {
goto free_and_return;
}
/* skip Ethernet header */
if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
("ethernet_input: IPv4 packet dropped, too short (%"S16_F"/%"S16_F")\n",
p->tot_len, ip_hdr_offset));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet"));
goto free_and_return;
} else {
/* pass to IP layer */
ip4_input(p, netif);
}
break;
case PP_HTONS(ETHTYPE_ARP):
if (!(netif->flags & NETIF_FLAG_ETHARP)) {
goto free_and_return;
}
/* skip Ethernet header */
if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
("ethernet_input: ARP response packet dropped, too short (%"S16_F"/%"S16_F")\n",
p->tot_len, ip_hdr_offset));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet"));
ETHARP_STATS_INC(etharp.lenerr);
ETHARP_STATS_INC(etharp.drop);
goto free_and_return;
} else {
/* pass p to ARP module */
etharp_input(p, netif);
}
break;
#endif /* LWIP_IPV4 && LWIP_ARP */
#if PPPOE_SUPPORT
case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */
pppoe_disc_input(netif, p);
break;
case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */
pppoe_data_input(netif, p);
break;
#endif /* PPPOE_SUPPORT */
#if LWIP_IPV6
case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */
/* skip Ethernet header */
if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
("ethernet_input: IPv6 packet dropped, too short (%"S16_F"/%"S16_F")\n",
p->tot_len, ip_hdr_offset));
goto free_and_return;
} else {
/* pass to IPv6 layer */
ip6_input(p, netif);
}
break;
#endif /* LWIP_IPV6 */
default:
#ifdef LWIP_HOOK_UNKNOWN_ETH_PROTOCOL
if(LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(p, netif) == ERR_OK) {
break;
}
#endif
ETHARP_STATS_INC(etharp.proterr);
ETHARP_STATS_INC(etharp.drop);
MIB2_STATS_NETIF_INC(netif, ifinunknownprotos);
goto free_and_return;
}
/* This means the pbuf is freed or consumed,
so the caller doesn't have to free it again */
return ERR_OK;
free_and_return:
pbuf_free(p);
return ERR_OK;
}
/**
* @ingroup ethernet
* Send an ethernet packet on the network using netif->linkoutput().
* The ethernet header is filled in before sending.
*
* @see LWIP_HOOK_VLAN_SET
*
* @param netif the lwIP network interface on which to send the packet
* @param p the packet to send. pbuf layer must be @ref PBUF_LINK.
* @param src the source MAC address to be copied into the ethernet header
* @param dst the destination MAC address to be copied into the ethernet header
* @param eth_type ethernet type (@ref eth_type)
* @return ERR_OK if the packet was sent, any other err_t on failure
*/
err_t
ethernet_output(struct netif* netif, struct pbuf* p,
const struct eth_addr* src, const struct eth_addr* dst,
u16_t eth_type)
{
struct eth_hdr* ethhdr;
u16_t eth_type_be = lwip_htons(eth_type);
#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET)
s32_t vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type);
if (vlan_prio_vid >= 0) {
struct eth_vlan_hdr* vlanhdr;
LWIP_ASSERT("prio_vid must be <= 0xFFFF", vlan_prio_vid <= 0xFFFF);
if (pbuf_header(p, SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) != 0) {
goto pbuf_header_failed;
}
vlanhdr = (struct eth_vlan_hdr*)(((u8_t*)p->payload) + SIZEOF_ETH_HDR);
vlanhdr->tpid = eth_type_be;
vlanhdr->prio_vid = lwip_htons((u16_t)vlan_prio_vid);
eth_type_be = PP_HTONS(ETHTYPE_VLAN);
} else
#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
{
if (pbuf_header(p, SIZEOF_ETH_HDR) != 0) {
goto pbuf_header_failed;
}
}
ethhdr = (struct eth_hdr*)p->payload;
ethhdr->type = eth_type_be;
ETHADDR32_COPY(&ethhdr->dest, dst);
ETHADDR16_COPY(&ethhdr->src, src);
LWIP_ASSERT("netif->hwaddr_len must be 6 for ethernet_output!",
(netif->hwaddr_len == ETH_HWADDR_LEN));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
("ethernet_output: sending packet %p\n", (void *)p));
/* send the packet */
return netif->linkoutput(netif, p);
pbuf_header_failed:
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
("ethernet_output: could not allocate room for header.\n"));
LINK_STATS_INC(link.lenerr);
return ERR_BUF;
}
#endif /* LWIP_ARP || LWIP_ETHERNET */

View file

@ -0,0 +1,335 @@
/**
* @file
* Ethernet Interface Skeleton
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/*
* This file is a skeleton for developing Ethernet network interface
* drivers for lwIP. Add code to the low_level functions and do a
* search-and-replace for the word "ethernetif" to replace it with
* something that better describes your network interface.
*/
#include "lwip/opt.h"
#if 0 /* don't build, this is only a skeleton, see previous comment */
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/ethip6.h"
#include "lwip/etharp.h"
#include "netif/ppp/pppoe.h"
/* Define those to better describe your network interface. */
#define IFNAME0 'e'
#define IFNAME1 'n'
/**
* Helper struct to hold private data used to operate your ethernet interface.
* Keeping the ethernet address of the MAC in this struct is not necessary
* as it is already kept in the struct netif.
* But this is only an example, anyway...
*/
struct ethernetif {
struct eth_addr *ethaddr;
/* Add whatever per-interface state that is needed here. */
};
/* Forward declarations. */
static void ethernetif_input(struct netif *netif);
/**
* In this function, the hardware should be initialized.
* Called from ethernetif_init().
*
* @param netif the already initialized lwip network interface structure
* for this ethernetif
*/
static void
low_level_init(struct netif *netif)
{
struct ethernetif *ethernetif = netif->state;
/* set MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* set MAC hardware address */
netif->hwaddr[0] = ;
...
netif->hwaddr[5] = ;
/* maximum transfer unit */
netif->mtu = 1500;
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
#if LWIP_IPV6 && LWIP_IPV6_MLD
/*
* For hardware/netifs that implement MAC filtering.
* All-nodes link-local is handled by default, so we must let the hardware know
* to allow multicast packets in.
* Should set mld_mac_filter previously. */
if (netif->mld_mac_filter != NULL) {
ip6_addr_t ip6_allnodes_ll;
ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER);
}
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
/* Do whatever else is needed to initialize interface. */
}
/**
* This function should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*
* @param netif the lwip network interface structure for this ethernetif
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
* @return ERR_OK if the packet could be sent
* an err_t value if the packet couldn't be sent
*
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
* strange results. You might consider waiting for space in the DMA queue
* to become available since the stack doesn't retry to send a packet
* dropped because of memory failure (except for the TCP timers).
*/
static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
struct ethernetif *ethernetif = netif->state;
struct pbuf *q;
initiate transfer();
#if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif
for (q = p; q != NULL; q = q->next) {
/* Send the data from the pbuf to the interface, one pbuf at a
time. The size of the data in each pbuf is kept in the ->len
variable. */
send data from(q->payload, q->len);
}
signal that packet should be sent();
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
if (((u8_t*)p->payload)[0] & 1) {
/* broadcast or multicast packet*/
MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
} else {
/* unicast packet */
MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
}
/* increase ifoutdiscards or ifouterrors on error */
#if ETH_PAD_SIZE
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
LINK_STATS_INC(link.xmit);
return ERR_OK;
}
/**
* Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
* @param netif the lwip network interface structure for this ethernetif
* @return a pbuf filled with the received packet (including MAC header)
* NULL on memory error
*/
static struct pbuf *
low_level_input(struct netif *netif)
{
struct ethernetif *ethernetif = netif->state;
struct pbuf *p, *q;
u16_t len;
/* Obtain the size of the packet and put it into the "len"
variable. */
len = ;
#if ETH_PAD_SIZE
len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
#endif
/* We allocate a pbuf chain of pbufs from the pool. */
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
if (p != NULL) {
#if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif
/* We iterate over the pbuf chain until we have read the entire
* packet into the pbuf. */
for (q = p; q != NULL; q = q->next) {
/* Read enough bytes to fill this pbuf in the chain. The
* available data in the pbuf is given by the q->len
* variable.
* This does not necessarily have to be a memcpy, you can also preallocate
* pbufs for a DMA-enabled MAC and after receiving truncate it to the
* actually received size. In this case, ensure the tot_len member of the
* pbuf is the sum of the chained pbuf len members.
*/
read data into(q->payload, q->len);
}
acknowledge that packet has been read();
MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
if (((u8_t*)p->payload)[0] & 1) {
/* broadcast or multicast packet*/
MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
} else {
/* unicast packet*/
MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
}
#if ETH_PAD_SIZE
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
LINK_STATS_INC(link.recv);
} else {
drop packet();
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
MIB2_STATS_NETIF_INC(netif, ifindiscards);
}
return p;
}
/**
* This function should be called when a packet is ready to be read
* from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network
* interface. Then the type of the received packet is determined and
* the appropriate input function is called.
*
* @param netif the lwip network interface structure for this ethernetif
*/
static void
ethernetif_input(struct netif *netif)
{
struct ethernetif *ethernetif;
struct eth_hdr *ethhdr;
struct pbuf *p;
ethernetif = netif->state;
/* move received packet into a new pbuf */
p = low_level_input(netif);
/* if no packet could be read, silently ignore this */
if (p != NULL) {
/* pass all packets to ethernet_input, which decides what packets it supports */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
p = NULL;
}
}
}
/**
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
* This function should be passed as a parameter to netif_add().
*
* @param netif the lwip network interface structure for this ethernetif
* @return ERR_OK if the loopif is initialized
* ERR_MEM if private data couldn't be allocated
* any other err_t on error
*/
err_t
ethernetif_init(struct netif *netif)
{
struct ethernetif *ethernetif;
LWIP_ASSERT("netif != NULL", (netif != NULL));
ethernetif = mem_malloc(sizeof(struct ethernetif));
if (ethernetif == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
return ERR_MEM;
}
#if LWIP_NETIF_HOSTNAME
/* Initialize interface hostname */
netif->hostname = "lwip";
#endif /* LWIP_NETIF_HOSTNAME */
/*
* Initialize the snmp variables and counters inside the struct netif.
* The last argument should be replaced with your link speed, in units
* of bits per second.
*/
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
netif->state = ethernetif;
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
/* We directly use etharp_output() here to save a function call.
* You can instead declare your own function an call etharp_output()
* from it if you have to do some checks before sending (e.g. if link
* is available...) */
netif->output = etharp_output;
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
#endif /* LWIP_IPV6 */
netif->linkoutput = low_level_output;
ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
/* initialize the hardware */
low_level_init(netif);
return ERR_OK;
}
#endif /* 0 */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,473 @@
The lwIP PPP support is based from pppd 2.4.5 (http://ppp.samba.org) with
huge changes to match code size and memory requirements for embedded devices.
Anyway, pppd has a mature codebase for years and the average commit count
is getting low on their Git repository, meaning that we can follow what
is happening on their side and merge what is relevant for lwIP.
So, here is the pppd follow up, so that we don't get away too far from pppd.
== Patch fetched from from pppd Debian packages ==
This has nothing to do with pppd, but we merged some good patch from
Debian and this is a good place to be.
- LCP adaptive echo, so that we don't send LCP echo request if we
are receiving data from peer, can be enabled by setting PPP_LCP_ADAPTIVE
to true.
- IPCP no/replace default route option, were added in the early stage of
the ppp port, but it wasn't really helpful and was disabled when adding
the new API ppp_set_default() call, which gives the lwIP user control over
which one is the default interface, it was actually a requirement if you
are doing PPP over PPP (i.e. PPPoL2TP, VPN link, over PPPoE, ADSL link).
- using rp-pppoe pppd exits with EXIT_OK after receiving a timeout waiting
for PADO due to no modem attached, bug reported to pppd bug tracker, fixed
in Debian but not in the latest (at the time when the port were started)
pppd release.
== Commits on pppd ==
2010-03-06 - Document +ipv6 and ipv6cp-accept-local
e7537958aee79b3f653c601e903cb31d78fb7dcc
Don't care.
2010-03-06 - Install pppol2tp plugins with sane permissions
406215672cfadc03017341fe03802d1c7294b903
Don't care.
2010-03-07 - pppd: Terminate correctly if lcp_lowerup delayed calling
fsm_lowerup
3eb9e810cfa515543655659b72dde30c54fea0a5
Merged 2012-05-17.
2010-03-07 - rp_pppoe: Copy acName and pppd_pppoe_service after option parsing
cab58617fd9d328029fffabc788020264b4fa91f
Don't care, is a patch for pppd/plugins/rp-pppoe/plugin.c which is not part
of the port.
2010-08-23 - set and reset options to control environment variables
for scripts.
2b6310fd24dba8e0fca8999916a162f0a1842a84
We can't fork processes in embedded, therefore all the pppd process run
feature is disabled in the port, so we don't care about the new
"environment variables" pppd feature.
2010-08-23 - Nit: use _exit when exec fails and restrict values to 0-255
per POSIX.
2b4ea140432eeba5a007c0d4e6236bd0e0c12ba4
Again, we are not running as a heavy process, so all exit() or _exit() calls
were removed.
2010-08-23 - Fix quote handling in configuration files to be more like shell
quoting.
3089132cdf5b58dbdfc2daf08ec5c08eb47f8aca
We are not parsing config file, all the filesystem I/O stuff were disabled
in our port.
2010-08-24 - rp-pppoe: allow MTU to be increased up to 1500
fd1dcdf758418f040da3ed801ab001b5e46854e7
Only concern changes on RP-PPPoE plugin, which we don't use.
2010-09-11 - chat: Allow TIMEOUT value to come from environment variable
ae80bf833e48a6202f44a935a68083ae52ad3824
See 2b6310fd24dba8e0fca8999916a162f0a1842a84.
2011-03-05 - pppdump: Fix printfs with insufficient arguments
7b8db569642c83ba3283745034f2e2c95e459423
pppdump is a ppp tool outside pppd source tree.
2012-05-06 - pppd: Don't unconditionally disable VJ compression under Linux
d8a66adf98a0e525cf38031b42098d539da6eeb6
Patch for sys-linux.c, which we don't use.
2012-05-20 - Remove old version of Linux if_pppol2tp.h
c41092dd4c49267f232f6cba3d31c6c68bfdf68d
Not in the port.
2012-05-20 - pppd: Make MSCHAP-v2 cope better with packet loss
08ef47ca532294eb428238c831616748940e24a2
This is an interesting patch. However it consumes much more memory for
MSCHAP and I am not sure if the benefit worth it. The PPP client can
always start the authentication again if it failed for whatever reason.
2012-05-20 - scripts: Make poff ignore extra arguments to pppd
18f515f32c9f5723a9c2c912601e04335106534b
Again, we are not running scripts.
2012-05-20 - rp-pppoe plugin: Print leading zeros in MAC address
f5dda0cfc220c4b52e26144096d729e27b30f0f7
Again, we are not using the RP-PPPoE plugin.
2012-05-20 - pppd: Notify IPv6 up/down as we do for IPv4
845cda8fa18939cf56e60b073f63a7efa65336fc
This is just a patch that adds plugins hooks for IPv6, the plugin interface
was disabled because we don't have .so plugins in embedded.
2012-05-20 - pppd: Enable IPV6 by default and fix some warnings
0b6118239615e98959f7e0b4e746bdd197533248
Change on Makefile for IPv6, warnings were already cleared during port.
2012-05-20 - contrib: Fix pppgetpass.gtk compilation
80a8e2ce257ca12cce723519a0f20ea1d663b14a
Change on Makefile, don't care.
2012-05-20 - pppd: Don't crash if crypt() returns NULL
04c4348108d847e034dd91066cc6843f60d71731
We are using the PolarSSL DES implementation that does not return NULL.
2012-05-20 - pppd: Eliminate some warnings
c44ae5e6a7338c96eb463881fe709b2dfaffe568
Again, we are handling compilation warnings on our own.
2012-05-20 - rp-pppoe plugin: Import some fixes from rp-pppoe-3.10
1817d83e51a411044e730ba89ebdb0480e1c8cd4
Once more, we are not using the RP-PPPoE plugin.
2013-01-23 - pppd: Clarify circumstances where DNS1/DNS2 environment variables are set
cf2f5c9538b9400ade23446a194729b0a4113b3a
Documentation only.
2013-02-03 - ppp: ignore unrecognised radiusclient configuration directives
7f736dde0da3c19855997d9e67370e351e15e923
Radius plugin, not in the port.
2013-02-03 - pppd: Take out unused %r conversion completely
356d8d558d844412119aa18c8e5a113bc6459c7b
Merged 2014-04-15.
2013-02-03 - pppd: Arrange to use logwtmp from libutil on Linux
9617a7eb137f4fee62799a677a9ecf8d834db3f5
Patch for sys-linux.c, which we don't use.
2013-02-03 - pppdump: Eliminate some compiler warnings
3e3acf1ba2b3046c072a42c19164788a9e419bd1
pppdump is a ppp tool outside pppd source tree.
2013-02-03 - chat: Correct spelling errors in the man page
8dea1b969d266ccbf6f3a8c5474eb6dcd8838e3b
Documentation only.
2013-02-03 - pppd: Fix spelling errors in man page
9e05a25d76b3f83096c661678010320df673df6b
Documentation only.
2013-02-03 - plugins/passprompt: Fix potential out-of-bounds array reference
8edb889b753056a691a3e4b217a110a35f9fdedb
Plugin patch, we do not have plugins.
2013-02-03 - chat: Fix *roff errors in the man page
a7c3489eeaf44e83ce592143c7c8a5b5c29f4c48
Documentation only.
2013-03-02 - pppd: Fix man page description of case when remote IP address isn't known
224841f4799f4f1e2e71bc490c54448d66740f4f
Documentation only.
2013-03-02 - pppd: Add master_detach option
398ed2585640d198c53e736ee5bbd67f7ce8168e
Option for multilink support, we do not support multilink and this option
is about detaching from the terminal, which is out of the embedded scope.
2013-03-11 - pppd: Default exit status to EXIT_CONNECT_FAILED during connection phase
225361d64ae737afdc8cb57579a2f33525461bc9
Commented out in our port, and already fixed by a previously applied Debian patch.
2013-03-11 - pppstats: Fix undefined macro in man page
d16a3985eade5280b8e171f5dd0670a91cba0d39
Documentation only.
2013-05-11 - plugins/radius: Handle bindaddr keyword in radiusclient.conf
d883b2dbafeed3ebd9d7a56ab1469373bd001a3b
Radius plugin, not in the port.
2013-06-09 - pppoatm: Remove explicit loading of pppoatm kernel module
52cd43a84bea524033b918b603698104f221bbb7
PPPoATM plugin, not in the port.
2013-06-09 - pppd: Fix segfault in update_db_entry()
37476164f15a45015310b9d4b197c2d7db1f7f8f
We do not use the samba db.
2013-06-09 - chat: Fix some text that was intended to be literal
cd9683676618adcee8add2c3cfa3382341b5a1f6
Documentation only.
2013-06-09 - README.pppoe: Minor semantic fix
b5b8898af6fd3d44e873cfc66810ace5f1f47e17
Documentation only.
2013-06-10 - radius: Handle additional attributes
2f581cd986a56f2ec4a95abad4f8297a1b10d7e2
Radius plugin, not in the port.
2013-06-10 - chat, pppd: Use \e instead of \\ in man pages
8d6942415d22f6ca4377340ca26e345c3f5fa5db
Documentation only.
2014-01-02 - pppd: Don't crash if NULL pointer passed to vslprintf for %q or %v
906814431bddeb2061825fa1ebad1a967b6d87a9
Merged 2014-04-15.
2014-01-02 - pppd: Accept IPCP ConfAck packets containing MS-WINS options
a243f217f1c6ac1aa7793806bc88590d077f490a
Merged 2014-04-15.
2014-01-02 - config: Update Solaris compiler options and enable CHAPMS and IPV6
99c46caaed01b7edba87962aa52b77fad61bfd7b
Solaris port, don't care.
2014-01-02 - Update README and patchlevel for 2.4.6 release
4043750fca36e7e0eb90d702e048ad1da4929418
Just release stuff.
2014-02-18 - pppd: Add option "stop-bits" to set number of serial port stop bits.
ad993a20ee485f0d0e2ac4105221641b200da6e2
Low level serial port, not in the port.
2014-03-09 - pppd: Separate IPv6 handling for sifup/sifdown
b04d2dc6df5c6b5650fea44250d58757ee3dac4a
Reimplemented.
2014-03-09 - pppol2tp: Connect up/down events to notifiers and add IPv6 ones
fafbe50251efc7d6b4a8be652d085316e112b34f
Not in the port.
2014-03-09 - pppd: Add declarations to eliminate compile warnings
50967962addebe15c7a7e63116ff46a0441dc464
We are handling compilation warnings on our own
2014-03-09 - pppd: Eliminate some unnecessary ifdefs
de8da14d845ee6db9236ccfddabf1d8ebf045ddb
We mostly did that previously. Anyway, merged 2014-12-24.
2014-08-01 - radius: Fix realms-config-file option
880a81be7c8e0fe8567227bc17a1bff3ea035943
Radius plugin, not in the port.
2014-08-01 - pppd: Eliminate potential integer overflow in option parsing
7658e8257183f062dc01f87969c140707c7e52cb
pppd config file parser, not in the port.
2014-08-01 - pppd: Eliminate memory leak with multiple instances of a string option
b94b7fbbaa0589aa6ec5fdc733aeb9ff294d2656
pppd config file parser, not in the port.
2014-08-01 - pppd: Fix a stack variable overflow in MSCHAP-v2
36733a891fb56594fcee580f667b33a64b990981
This fixes a bug introduced in 08ef47ca ("pppd: Make MSCHAP-v2 cope better with packet loss").
We didn't merge 08ef47ca ;-)
2014-08-01 - winbind plugin: Add -DMPPE=1 to eliminate compiler warnings
2b05e22c62095e97dd0a97e4b5588402c2185071
Linux plugin, not in the port.
2014-08-09 - Update README and patchlevel for 2.4.7 release
6e8eaa7a78b31cdab2edf140a9c8afdb02ffaca5
Just release stuff.
2014-08-10 - abort on errors in subdir builds
5e90783d11a59268e05f4cfb29ce2343b13e8ab2
Linux Makefile, not in the port.
2014-06-03 - pppd: add support for defaultroute-metric option
35e5a569c988b1ff865b02a24d9a727a00db4da9
Only necessary for Linux, lwIP does not support route metrics.
2014-12-13 - scripts: Avoid killing wrong pppd
67811a647d399db5d188a242827760615a0f86b5
pppd helper script, not in the port.
2014-12-20 - pppd: Fix sign-extension when displaying bytes in octal
5e8c3cb256a7e86e3572a82a75d51c6850efdbdc
Merged 2016-07-02.
2015-03-01 - Suppress false error message on PPPoE disconnect
219aac3b53d0827549377f1bfe22853ee52d4405
PPPoE plugin, not in the port.
2015-03-01 - Send PADT on PPPoE disconnect
cd2c14f998c57bbe6a01dc5854f2763c0d7f31fb
PPPoE plugin, not in the port. And our PPPoE implementation already does
that: pppoe_disconnect() calls pppoe_send_padt().
2015-08-14 - pppd: ipxcp: Prevent buffer overrun on remote router name
fe149de624f96629a7f46732055d8f718c74b856
We never ported IPX support. lwIP does not support IPX.
2015-03-25 - pppd: Fix ccp_options.mppe type
234edab99a6bb250cc9ecd384cca27b0c8b475ce
We found that while working on MPPE support in lwIP, that's our patch ;-)
2015-03-24 - pppd: Fix ccp_cilen calculated size if both deflate_correct and deflate_draft are enabled
094cb8ae4c61db225e67fedadb4964f846dd0c27
We found that while working on MPPE support in lwIP, that's our patch ;-)
2015-08-14 - Merge branch 'master' of https://github.com/ncopa/ppp
3a5c9a8fbc8970375cd881151d44e4b6fe249c6a
Merge commit, we don't care.
2015-08-14 - Merge branch 'master' of git://github.com/vapier/ppp
912e4fc6665aca188dced7ea7fdc663ce5a2dd24
Merge commit, we don't care.
2015-08-14 - Merge branch 'bug_fix' of git://github.com/radaiming/ppp
dfd33d7f526ecd7b39dd1bba8101260d02af5ebb
Merge commit, we don't care.
2015-08-14 - Merge branch 'master' of git://github.com/pprindeville/ppp
aa4a985f6114d08cf4e47634fb6325da71016473
Merge commit, we don't care.
2015-08-14 - Merge branch 'no-error-on-already-closed' of git://github.com/farnz/ppp
6edf252483b30dbcdcc5059f01831455365d5b6e
Merge commit, we don't care.
2015-08-14 - Merge branch 'send-padt-on-disconnect' of git://github.com/farnz/ppp
84684243d651f55f6df69d2a6707b52fbbe62bb9
Merge commit, we don't care.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,126 @@
/*
* chap-md5.c - New CHAP/MD5 implementation.
*
* Copyright (c) 2003 Paul Mackerras. 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. The name(s) of the authors of this software must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* 3. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Paul Mackerras
* <paulus@samba.org>".
*
* THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
#if 0 /* UNUSED */
#include <stdlib.h>
#include <string.h>
#endif /* UNUSED */
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/chap-new.h"
#include "netif/ppp/chap-md5.h"
#include "netif/ppp/magic.h"
#include "netif/ppp/pppcrypt.h"
#define MD5_HASH_SIZE 16
#define MD5_MIN_CHALLENGE 17
#define MD5_MAX_CHALLENGE 24
#define MD5_MIN_MAX_POWER_OF_TWO_CHALLENGE 3 /* 2^3-1 = 7, 17+7 = 24 */
#if PPP_SERVER
static void chap_md5_generate_challenge(ppp_pcb *pcb, unsigned char *cp) {
int clen;
LWIP_UNUSED_ARG(pcb);
clen = MD5_MIN_CHALLENGE + magic_pow(MD5_MIN_MAX_POWER_OF_TWO_CHALLENGE);
*cp++ = clen;
magic_random_bytes(cp, clen);
}
static int chap_md5_verify_response(ppp_pcb *pcb, int id, const char *name,
const unsigned char *secret, int secret_len,
const unsigned char *challenge, const unsigned char *response,
char *message, int message_space) {
lwip_md5_context ctx;
unsigned char idbyte = id;
unsigned char hash[MD5_HASH_SIZE];
int challenge_len, response_len;
LWIP_UNUSED_ARG(name);
LWIP_UNUSED_ARG(pcb);
challenge_len = *challenge++;
response_len = *response++;
if (response_len == MD5_HASH_SIZE) {
/* Generate hash of ID, secret, challenge */
lwip_md5_init(&ctx);
lwip_md5_starts(&ctx);
lwip_md5_update(&ctx, &idbyte, 1);
lwip_md5_update(&ctx, secret, secret_len);
lwip_md5_update(&ctx, challenge, challenge_len);
lwip_md5_finish(&ctx, hash);
lwip_md5_free(&ctx);
/* Test if our hash matches the peer's response */
if (memcmp(hash, response, MD5_HASH_SIZE) == 0) {
ppp_slprintf(message, message_space, "Access granted");
return 1;
}
}
ppp_slprintf(message, message_space, "Access denied");
return 0;
}
#endif /* PPP_SERVER */
static void chap_md5_make_response(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name,
const unsigned char *challenge, const char *secret, int secret_len,
unsigned char *private_) {
lwip_md5_context ctx;
unsigned char idbyte = id;
int challenge_len = *challenge++;
LWIP_UNUSED_ARG(our_name);
LWIP_UNUSED_ARG(private_);
LWIP_UNUSED_ARG(pcb);
lwip_md5_init(&ctx);
lwip_md5_starts(&ctx);
lwip_md5_update(&ctx, &idbyte, 1);
lwip_md5_update(&ctx, (const u_char *)secret, secret_len);
lwip_md5_update(&ctx, challenge, challenge_len);
lwip_md5_finish(&ctx, &response[1]);
lwip_md5_free(&ctx);
response[0] = MD5_HASH_SIZE;
}
const struct chap_digest_type md5_digest = {
CHAP_MD5, /* code */
#if PPP_SERVER
chap_md5_generate_challenge,
chap_md5_verify_response,
#endif /* PPP_SERVER */
chap_md5_make_response,
NULL, /* check_success */
NULL, /* handle_failure */
};
#endif /* PPP_SUPPORT && CHAP_SUPPORT */

View file

@ -0,0 +1,677 @@
/*
* chap-new.c - New CHAP implementation.
*
* Copyright (c) 2003 Paul Mackerras. 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. The name(s) of the authors of this software must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* 3. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Paul Mackerras
* <paulus@samba.org>".
*
* THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
#if 0 /* UNUSED */
#include <stdlib.h>
#include <string.h>
#endif /* UNUSED */
#include "netif/ppp/ppp_impl.h"
#if 0 /* UNUSED */
#include "session.h"
#endif /* UNUSED */
#include "netif/ppp/chap-new.h"
#include "netif/ppp/chap-md5.h"
#if MSCHAP_SUPPORT
#include "netif/ppp/chap_ms.h"
#endif
#include "netif/ppp/magic.h"
#if 0 /* UNUSED */
/* Hook for a plugin to validate CHAP challenge */
int (*chap_verify_hook)(const char *name, const char *ourname, int id,
const struct chap_digest_type *digest,
const unsigned char *challenge, const unsigned char *response,
char *message, int message_space) = NULL;
#endif /* UNUSED */
#if PPP_OPTIONS
/*
* Command-line options.
*/
static option_t chap_option_list[] = {
{ "chap-restart", o_int, &chap_timeout_time,
"Set timeout for CHAP", OPT_PRIO },
{ "chap-max-challenge", o_int, &pcb->settings.chap_max_transmits,
"Set max #xmits for challenge", OPT_PRIO },
{ "chap-interval", o_int, &pcb->settings.chap_rechallenge_time,
"Set interval for rechallenge", OPT_PRIO },
{ NULL }
};
#endif /* PPP_OPTIONS */
/* Values for flags in chap_client_state and chap_server_state */
#define LOWERUP 1
#define AUTH_STARTED 2
#define AUTH_DONE 4
#define AUTH_FAILED 8
#define TIMEOUT_PENDING 0x10
#define CHALLENGE_VALID 0x20
/*
* Prototypes.
*/
static void chap_init(ppp_pcb *pcb);
static void chap_lowerup(ppp_pcb *pcb);
static void chap_lowerdown(ppp_pcb *pcb);
#if PPP_SERVER
static void chap_timeout(void *arg);
static void chap_generate_challenge(ppp_pcb *pcb);
static void chap_handle_response(ppp_pcb *pcb, int code,
unsigned char *pkt, int len);
static int chap_verify_response(ppp_pcb *pcb, const char *name, const char *ourname, int id,
const struct chap_digest_type *digest,
const unsigned char *challenge, const unsigned char *response,
char *message, int message_space);
#endif /* PPP_SERVER */
static void chap_respond(ppp_pcb *pcb, int id,
unsigned char *pkt, int len);
static void chap_handle_status(ppp_pcb *pcb, int code, int id,
unsigned char *pkt, int len);
static void chap_protrej(ppp_pcb *pcb);
static void chap_input(ppp_pcb *pcb, unsigned char *pkt, int pktlen);
#if PRINTPKT_SUPPORT
static int chap_print_pkt(const unsigned char *p, int plen,
void (*printer) (void *, const char *, ...), void *arg);
#endif /* PRINTPKT_SUPPORT */
/* List of digest types that we know about */
static const struct chap_digest_type* const chap_digests[] = {
&md5_digest,
#if MSCHAP_SUPPORT
&chapms_digest,
&chapms2_digest,
#endif /* MSCHAP_SUPPORT */
NULL
};
/*
* chap_init - reset to initial state.
*/
static void chap_init(ppp_pcb *pcb) {
LWIP_UNUSED_ARG(pcb);
#if 0 /* Not necessary, everything is cleared in ppp_new() */
memset(&pcb->chap_client, 0, sizeof(chap_client_state));
#if PPP_SERVER
memset(&pcb->chap_server, 0, sizeof(chap_server_state));
#endif /* PPP_SERVER */
#endif /* 0 */
}
/*
* chap_lowerup - we can start doing stuff now.
*/
static void chap_lowerup(ppp_pcb *pcb) {
pcb->chap_client.flags |= LOWERUP;
#if PPP_SERVER
pcb->chap_server.flags |= LOWERUP;
if (pcb->chap_server.flags & AUTH_STARTED)
chap_timeout(pcb);
#endif /* PPP_SERVER */
}
static void chap_lowerdown(ppp_pcb *pcb) {
pcb->chap_client.flags = 0;
#if PPP_SERVER
if (pcb->chap_server.flags & TIMEOUT_PENDING)
UNTIMEOUT(chap_timeout, pcb);
pcb->chap_server.flags = 0;
#endif /* PPP_SERVER */
}
#if PPP_SERVER
/*
* chap_auth_peer - Start authenticating the peer.
* If the lower layer is already up, we start sending challenges,
* otherwise we wait for the lower layer to come up.
*/
void chap_auth_peer(ppp_pcb *pcb, const char *our_name, int digest_code) {
const struct chap_digest_type *dp;
int i;
if (pcb->chap_server.flags & AUTH_STARTED) {
ppp_error("CHAP: peer authentication already started!");
return;
}
for (i = 0; (dp = chap_digests[i]) != NULL; ++i)
if (dp->code == digest_code)
break;
if (dp == NULL)
ppp_fatal("CHAP digest 0x%x requested but not available",
digest_code);
pcb->chap_server.digest = dp;
pcb->chap_server.name = our_name;
/* Start with a random ID value */
pcb->chap_server.id = magic();
pcb->chap_server.flags |= AUTH_STARTED;
if (pcb->chap_server.flags & LOWERUP)
chap_timeout(pcb);
}
#endif /* PPP_SERVER */
/*
* chap_auth_with_peer - Prepare to authenticate ourselves to the peer.
* There isn't much to do until we receive a challenge.
*/
void chap_auth_with_peer(ppp_pcb *pcb, const char *our_name, int digest_code) {
const struct chap_digest_type *dp;
int i;
if(NULL == our_name)
return;
if (pcb->chap_client.flags & AUTH_STARTED) {
ppp_error("CHAP: authentication with peer already started!");
return;
}
for (i = 0; (dp = chap_digests[i]) != NULL; ++i)
if (dp->code == digest_code)
break;
if (dp == NULL)
ppp_fatal("CHAP digest 0x%x requested but not available",
digest_code);
pcb->chap_client.digest = dp;
pcb->chap_client.name = our_name;
pcb->chap_client.flags |= AUTH_STARTED;
}
#if PPP_SERVER
/*
* chap_timeout - It's time to send another challenge to the peer.
* This could be either a retransmission of a previous challenge,
* or a new challenge to start re-authentication.
*/
static void chap_timeout(void *arg) {
ppp_pcb *pcb = (ppp_pcb*)arg;
struct pbuf *p;
pcb->chap_server.flags &= ~TIMEOUT_PENDING;
if ((pcb->chap_server.flags & CHALLENGE_VALID) == 0) {
pcb->chap_server.challenge_xmits = 0;
chap_generate_challenge(pcb);
pcb->chap_server.flags |= CHALLENGE_VALID;
} else if (pcb->chap_server.challenge_xmits >= pcb->settings.chap_max_transmits) {
pcb->chap_server.flags &= ~CHALLENGE_VALID;
pcb->chap_server.flags |= AUTH_DONE | AUTH_FAILED;
auth_peer_fail(pcb, PPP_CHAP);
return;
}
p = pbuf_alloc(PBUF_RAW, (u16_t)(pcb->chap_server.challenge_pktlen), PPP_CTRL_PBUF_TYPE);
if(NULL == p)
return;
if(p->tot_len != p->len) {
pbuf_free(p);
return;
}
MEMCPY(p->payload, pcb->chap_server.challenge, pcb->chap_server.challenge_pktlen);
ppp_write(pcb, p);
++pcb->chap_server.challenge_xmits;
pcb->chap_server.flags |= TIMEOUT_PENDING;
TIMEOUT(chap_timeout, arg, pcb->settings.chap_timeout_time);
}
/*
* chap_generate_challenge - generate a challenge string and format
* the challenge packet in pcb->chap_server.challenge_pkt.
*/
static void chap_generate_challenge(ppp_pcb *pcb) {
int clen = 1, nlen, len;
unsigned char *p;
p = pcb->chap_server.challenge;
MAKEHEADER(p, PPP_CHAP);
p += CHAP_HDRLEN;
pcb->chap_server.digest->generate_challenge(pcb, p);
clen = *p;
nlen = strlen(pcb->chap_server.name);
memcpy(p + 1 + clen, pcb->chap_server.name, nlen);
len = CHAP_HDRLEN + 1 + clen + nlen;
pcb->chap_server.challenge_pktlen = PPP_HDRLEN + len;
p = pcb->chap_server.challenge + PPP_HDRLEN;
p[0] = CHAP_CHALLENGE;
p[1] = ++pcb->chap_server.id;
p[2] = len >> 8;
p[3] = len;
}
/*
* chap_handle_response - check the response to our challenge.
*/
static void chap_handle_response(ppp_pcb *pcb, int id,
unsigned char *pkt, int len) {
int response_len, ok, mlen;
const unsigned char *response;
unsigned char *outp;
struct pbuf *p;
const char *name = NULL; /* initialized to shut gcc up */
#if 0 /* UNUSED */
int (*verifier)(const char *, const char *, int, const struct chap_digest_type *,
const unsigned char *, const unsigned char *, char *, int);
#endif /* UNUSED */
char rname[MAXNAMELEN+1];
char message[256];
if ((pcb->chap_server.flags & LOWERUP) == 0)
return;
if (id != pcb->chap_server.challenge[PPP_HDRLEN+1] || len < 2)
return;
if (pcb->chap_server.flags & CHALLENGE_VALID) {
response = pkt;
GETCHAR(response_len, pkt);
len -= response_len + 1; /* length of name */
name = (char *)pkt + response_len;
if (len < 0)
return;
if (pcb->chap_server.flags & TIMEOUT_PENDING) {
pcb->chap_server.flags &= ~TIMEOUT_PENDING;
UNTIMEOUT(chap_timeout, pcb);
}
#if PPP_REMOTENAME
if (pcb->settings.explicit_remote) {
name = pcb->remote_name;
} else
#endif /* PPP_REMOTENAME */
{
/* Null terminate and clean remote name. */
ppp_slprintf(rname, sizeof(rname), "%.*v", len, name);
name = rname;
}
#if 0 /* UNUSED */
if (chap_verify_hook)
verifier = chap_verify_hook;
else
verifier = chap_verify_response;
ok = (*verifier)(name, pcb->chap_server.name, id, pcb->chap_server.digest,
pcb->chap_server.challenge + PPP_HDRLEN + CHAP_HDRLEN,
response, pcb->chap_server.message, sizeof(pcb->chap_server.message));
#endif /* UNUSED */
ok = chap_verify_response(pcb, name, pcb->chap_server.name, id, pcb->chap_server.digest,
pcb->chap_server.challenge + PPP_HDRLEN + CHAP_HDRLEN,
response, message, sizeof(message));
#if 0 /* UNUSED */
if (!ok || !auth_number()) {
#endif /* UNUSED */
if (!ok) {
pcb->chap_server.flags |= AUTH_FAILED;
ppp_warn("Peer %q failed CHAP authentication", name);
}
} else if ((pcb->chap_server.flags & AUTH_DONE) == 0)
return;
/* send the response */
mlen = strlen(message);
len = CHAP_HDRLEN + mlen;
p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +len), PPP_CTRL_PBUF_TYPE);
if(NULL == p)
return;
if(p->tot_len != p->len) {
pbuf_free(p);
return;
}
outp = (unsigned char *)p->payload;
MAKEHEADER(outp, PPP_CHAP);
outp[0] = (pcb->chap_server.flags & AUTH_FAILED)? CHAP_FAILURE: CHAP_SUCCESS;
outp[1] = id;
outp[2] = len >> 8;
outp[3] = len;
if (mlen > 0)
memcpy(outp + CHAP_HDRLEN, message, mlen);
ppp_write(pcb, p);
if (pcb->chap_server.flags & CHALLENGE_VALID) {
pcb->chap_server.flags &= ~CHALLENGE_VALID;
if (!(pcb->chap_server.flags & AUTH_DONE) && !(pcb->chap_server.flags & AUTH_FAILED)) {
#if 0 /* UNUSED */
/*
* Auth is OK, so now we need to check session restrictions
* to ensure everything is OK, but only if we used a
* plugin, and only if we're configured to check. This
* allows us to do PAM checks on PPP servers that
* authenticate against ActiveDirectory, and use AD for
* account info (like when using Winbind integrated with
* PAM).
*/
if (session_mgmt &&
session_check(name, NULL, devnam, NULL) == 0) {
pcb->chap_server.flags |= AUTH_FAILED;
ppp_warn("Peer %q failed CHAP Session verification", name);
}
#endif /* UNUSED */
}
if (pcb->chap_server.flags & AUTH_FAILED) {
auth_peer_fail(pcb, PPP_CHAP);
} else {
if ((pcb->chap_server.flags & AUTH_DONE) == 0)
auth_peer_success(pcb, PPP_CHAP,
pcb->chap_server.digest->code,
name, strlen(name));
if (pcb->settings.chap_rechallenge_time) {
pcb->chap_server.flags |= TIMEOUT_PENDING;
TIMEOUT(chap_timeout, pcb,
pcb->settings.chap_rechallenge_time);
}
}
pcb->chap_server.flags |= AUTH_DONE;
}
}
/*
* chap_verify_response - check whether the peer's response matches
* what we think it should be. Returns 1 if it does (authentication
* succeeded), or 0 if it doesn't.
*/
static int chap_verify_response(ppp_pcb *pcb, const char *name, const char *ourname, int id,
const struct chap_digest_type *digest,
const unsigned char *challenge, const unsigned char *response,
char *message, int message_space) {
int ok;
unsigned char secret[MAXSECRETLEN];
int secret_len;
/* Get the secret that the peer is supposed to know */
if (!get_secret(pcb, name, ourname, (char *)secret, &secret_len, 1)) {
ppp_error("No CHAP secret found for authenticating %q", name);
return 0;
}
ok = digest->verify_response(pcb, id, name, secret, secret_len, challenge,
response, message, message_space);
memset(secret, 0, sizeof(secret));
return ok;
}
#endif /* PPP_SERVER */
/*
* chap_respond - Generate and send a response to a challenge.
*/
static void chap_respond(ppp_pcb *pcb, int id,
unsigned char *pkt, int len) {
int clen, nlen;
int secret_len;
struct pbuf *p;
u_char *outp;
char rname[MAXNAMELEN+1];
char secret[MAXSECRETLEN+1];
p = pbuf_alloc(PBUF_RAW, (u16_t)(RESP_MAX_PKTLEN), PPP_CTRL_PBUF_TYPE);
if(NULL == p)
return;
if(p->tot_len != p->len) {
pbuf_free(p);
return;
}
if ((pcb->chap_client.flags & (LOWERUP | AUTH_STARTED)) != (LOWERUP | AUTH_STARTED))
return; /* not ready */
if (len < 2 || len < pkt[0] + 1)
return; /* too short */
clen = pkt[0];
nlen = len - (clen + 1);
/* Null terminate and clean remote name. */
ppp_slprintf(rname, sizeof(rname), "%.*v", nlen, pkt + clen + 1);
#if PPP_REMOTENAME
/* Microsoft doesn't send their name back in the PPP packet */
if (pcb->settings.explicit_remote || (pcb->settings.remote_name[0] != 0 && rname[0] == 0))
strlcpy(rname, pcb->settings.remote_name, sizeof(rname));
#endif /* PPP_REMOTENAME */
/* get secret for authenticating ourselves with the specified host */
if (!get_secret(pcb, pcb->chap_client.name, rname, secret, &secret_len, 0)) {
secret_len = 0; /* assume null secret if can't find one */
ppp_warn("No CHAP secret found for authenticating us to %q", rname);
}
outp = (u_char*)p->payload;
MAKEHEADER(outp, PPP_CHAP);
outp += CHAP_HDRLEN;
pcb->chap_client.digest->make_response(pcb, outp, id, pcb->chap_client.name, pkt,
secret, secret_len, pcb->chap_client.priv);
memset(secret, 0, secret_len);
clen = *outp;
nlen = strlen(pcb->chap_client.name);
memcpy(outp + clen + 1, pcb->chap_client.name, nlen);
outp = (u_char*)p->payload + PPP_HDRLEN;
len = CHAP_HDRLEN + clen + 1 + nlen;
outp[0] = CHAP_RESPONSE;
outp[1] = id;
outp[2] = len >> 8;
outp[3] = len;
pbuf_realloc(p, PPP_HDRLEN + len);
ppp_write(pcb, p);
}
static void chap_handle_status(ppp_pcb *pcb, int code, int id,
unsigned char *pkt, int len) {
const char *msg = NULL;
LWIP_UNUSED_ARG(id);
if ((pcb->chap_client.flags & (AUTH_DONE|AUTH_STARTED|LOWERUP))
!= (AUTH_STARTED|LOWERUP))
return;
pcb->chap_client.flags |= AUTH_DONE;
if (code == CHAP_SUCCESS) {
/* used for MS-CHAP v2 mutual auth, yuck */
if (pcb->chap_client.digest->check_success != NULL) {
if (!(*pcb->chap_client.digest->check_success)(pcb, pkt, len, pcb->chap_client.priv))
code = CHAP_FAILURE;
} else
msg = "CHAP authentication succeeded";
} else {
if (pcb->chap_client.digest->handle_failure != NULL)
(*pcb->chap_client.digest->handle_failure)(pcb, pkt, len);
else
msg = "CHAP authentication failed";
}
if (msg) {
if (len > 0)
ppp_info("%s: %.*v", msg, len, pkt);
else
ppp_info("%s", msg);
}
if (code == CHAP_SUCCESS)
auth_withpeer_success(pcb, PPP_CHAP, pcb->chap_client.digest->code);
else {
pcb->chap_client.flags |= AUTH_FAILED;
ppp_error("CHAP authentication failed");
auth_withpeer_fail(pcb, PPP_CHAP);
}
}
static void chap_input(ppp_pcb *pcb, unsigned char *pkt, int pktlen) {
unsigned char code, id;
int len;
if (pktlen < CHAP_HDRLEN)
return;
GETCHAR(code, pkt);
GETCHAR(id, pkt);
GETSHORT(len, pkt);
if (len < CHAP_HDRLEN || len > pktlen)
return;
len -= CHAP_HDRLEN;
switch (code) {
case CHAP_CHALLENGE:
chap_respond(pcb, id, pkt, len);
break;
#if PPP_SERVER
case CHAP_RESPONSE:
chap_handle_response(pcb, id, pkt, len);
break;
#endif /* PPP_SERVER */
case CHAP_FAILURE:
case CHAP_SUCCESS:
chap_handle_status(pcb, code, id, pkt, len);
break;
default:
break;
}
}
static void chap_protrej(ppp_pcb *pcb) {
#if PPP_SERVER
if (pcb->chap_server.flags & TIMEOUT_PENDING) {
pcb->chap_server.flags &= ~TIMEOUT_PENDING;
UNTIMEOUT(chap_timeout, pcb);
}
if (pcb->chap_server.flags & AUTH_STARTED) {
pcb->chap_server.flags = 0;
auth_peer_fail(pcb, PPP_CHAP);
}
#endif /* PPP_SERVER */
if ((pcb->chap_client.flags & (AUTH_STARTED|AUTH_DONE)) == AUTH_STARTED) {
pcb->chap_client.flags &= ~AUTH_STARTED;
ppp_error("CHAP authentication failed due to protocol-reject");
auth_withpeer_fail(pcb, PPP_CHAP);
}
}
#if PRINTPKT_SUPPORT
/*
* chap_print_pkt - print the contents of a CHAP packet.
*/
static const char* const chap_code_names[] = {
"Challenge", "Response", "Success", "Failure"
};
static int chap_print_pkt(const unsigned char *p, int plen,
void (*printer) (void *, const char *, ...), void *arg) {
int code, id, len;
int clen, nlen;
unsigned char x;
if (plen < CHAP_HDRLEN)
return 0;
GETCHAR(code, p);
GETCHAR(id, p);
GETSHORT(len, p);
if (len < CHAP_HDRLEN || len > plen)
return 0;
if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(chap_code_names))
printer(arg, " %s", chap_code_names[code-1]);
else
printer(arg, " code=0x%x", code);
printer(arg, " id=0x%x", id);
len -= CHAP_HDRLEN;
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 = ");
ppp_print_string(p, nlen, printer, arg);
break;
case CHAP_FAILURE:
case CHAP_SUCCESS:
printer(arg, " ");
ppp_print_string(p, len, printer, arg);
break;
default:
for (clen = len; clen > 0; --clen) {
GETCHAR(x, p);
printer(arg, " %.2x", x);
}
/* no break */
}
return len + CHAP_HDRLEN;
}
#endif /* PRINTPKT_SUPPORT */
const struct protent chap_protent = {
PPP_CHAP,
chap_init,
chap_input,
chap_protrej,
chap_lowerup,
chap_lowerdown,
NULL, /* open */
NULL, /* close */
#if PRINTPKT_SUPPORT
chap_print_pkt,
#endif /* PRINTPKT_SUPPORT */
#if PPP_DATAINPUT
NULL, /* datainput */
#endif /* PPP_DATAINPUT */
#if PRINTPKT_SUPPORT
"CHAP", /* name */
NULL, /* data_name */
#endif /* PRINTPKT_SUPPORT */
#if PPP_OPTIONS
chap_option_list,
NULL, /* check_options */
#endif /* PPP_OPTIONS */
#if DEMAND_SUPPORT
NULL,
NULL
#endif /* DEMAND_SUPPORT */
};
#endif /* PPP_SUPPORT && CHAP_SUPPORT */

View file

@ -0,0 +1,962 @@
/*
* chap_ms.c - Microsoft MS-CHAP compatible implementation.
*
* Copyright (c) 1995 Eric Rosenquist. 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(s) of the authors of this software must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* 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
*/
/*
* Modifications by Frank Cusack, frank@google.com, March 2002.
*
* Implemented MS-CHAPv2 functionality, heavily based on sample
* implementation in RFC 2759. Implemented MPPE functionality,
* heavily based on sample implementation in RFC 3079.
*
* Copyright (c) 2002 Google, Inc. 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(s) of the authors of this software must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
#if 0 /* UNUSED */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#endif /* UNUSED */
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/chap-new.h"
#include "netif/ppp/chap_ms.h"
#include "netif/ppp/pppcrypt.h"
#include "netif/ppp/magic.h"
#if MPPE_SUPPORT
#include "netif/ppp/mppe.h" /* For mppe_sha1_pad*, mppe_set_key() */
#endif /* MPPE_SUPPORT */
#define SHA1_SIGNATURE_SIZE 20
#define MD4_SIGNATURE_SIZE 16 /* 16 bytes in a MD4 message digest */
#define MAX_NT_PASSWORD 256 /* Max (Unicode) chars in an NT pass */
#define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */
#define MS_CHAP2_RESPONSE_LEN 49 /* Response length for MS-CHAPv2 */
#define MS_AUTH_RESPONSE_LENGTH 40 /* MS-CHAPv2 authenticator response, */
/* as ASCII */
/* Error codes for MS-CHAP failure messages. */
#define MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS 646
#define MS_CHAP_ERROR_ACCT_DISABLED 647
#define MS_CHAP_ERROR_PASSWD_EXPIRED 648
#define MS_CHAP_ERROR_NO_DIALIN_PERMISSION 649
#define MS_CHAP_ERROR_AUTHENTICATION_FAILURE 691
#define MS_CHAP_ERROR_CHANGING_PASSWORD 709
/*
* Offsets within the response field for MS-CHAP
*/
#define MS_CHAP_LANMANRESP 0
#define MS_CHAP_LANMANRESP_LEN 24
#define MS_CHAP_NTRESP 24
#define MS_CHAP_NTRESP_LEN 24
#define MS_CHAP_USENT 48
/*
* Offsets within the response field for MS-CHAP2
*/
#define MS_CHAP2_PEER_CHALLENGE 0
#define MS_CHAP2_PEER_CHAL_LEN 16
#define MS_CHAP2_RESERVED_LEN 8
#define MS_CHAP2_NTRESP 24
#define MS_CHAP2_NTRESP_LEN 24
#define MS_CHAP2_FLAGS 48
#if MPPE_SUPPORT
#if 0 /* UNUSED */
/* These values are the RADIUS attribute values--see RFC 2548. */
#define MPPE_ENC_POL_ENC_ALLOWED 1
#define MPPE_ENC_POL_ENC_REQUIRED 2
#define MPPE_ENC_TYPES_RC4_40 2
#define MPPE_ENC_TYPES_RC4_128 4
/* used by plugins (using above values) */
extern void set_mppe_enc_types(int, int);
#endif /* UNUSED */
#endif /* MPPE_SUPPORT */
/* Are we the authenticator or authenticatee? For MS-CHAPv2 key derivation. */
#define MS_CHAP2_AUTHENTICATEE 0
#define MS_CHAP2_AUTHENTICATOR 1
static void ascii2unicode (const char[], int, u_char[]);
static void NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]);
static void ChallengeResponse (const u_char *, const u_char *, u_char[24]);
static void ChallengeHash (const u_char[16], const u_char *, const char *, u_char[8]);
static void ChapMS_NT (const u_char *, const char *, int, u_char[24]);
static void ChapMS2_NT (const u_char *, const u_char[16], const char *, const char *, int,
u_char[24]);
static void GenerateAuthenticatorResponsePlain
(const char*, int, u_char[24], const u_char[16], const u_char *,
const char *, u_char[41]);
#ifdef MSLANMAN
static void ChapMS_LANMan (u_char *, char *, int, u_char *);
#endif
static void GenerateAuthenticatorResponse(const u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
u_char NTResponse[24], const u_char PeerChallenge[16],
const u_char *rchallenge, const char *username,
u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]);
#if MPPE_SUPPORT
static void Set_Start_Key (ppp_pcb *pcb, const u_char *, const char *, int);
static void SetMasterKeys (ppp_pcb *pcb, const char *, int, u_char[24], int);
#endif /* MPPE_SUPPORT */
static void ChapMS (ppp_pcb *pcb, const u_char *, const char *, int, u_char *);
static void ChapMS2 (ppp_pcb *pcb, const u_char *, const u_char *, const char *, const char *, int,
u_char *, u_char[MS_AUTH_RESPONSE_LENGTH+1], int);
#ifdef MSLANMAN
bool ms_lanman = 0; /* Use LanMan password instead of NT */
/* Has meaning only with MS-CHAP challenges */
#endif
#if MPPE_SUPPORT
#ifdef DEBUGMPPEKEY
/* For MPPE debug */
/* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
static char *mschap_challenge = NULL;
/* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
static char *mschap2_peer_challenge = NULL;
#endif
#include "netif/ppp/fsm.h" /* Need to poke MPPE options */
#include "netif/ppp/ccp.h"
#endif /* MPPE_SUPPORT */
#if PPP_OPTIONS
/*
* Command-line options.
*/
static option_t chapms_option_list[] = {
#ifdef MSLANMAN
{ "ms-lanman", o_bool, &ms_lanman,
"Use LanMan passwd when using MS-CHAP", 1 },
#endif
#ifdef DEBUGMPPEKEY
{ "mschap-challenge", o_string, &mschap_challenge,
"specify CHAP challenge" },
{ "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,
"specify CHAP peer challenge" },
#endif
{ NULL }
};
#endif /* PPP_OPTIONS */
#if PPP_SERVER
/*
* chapms_generate_challenge - generate a challenge for MS-CHAP.
* For MS-CHAP the challenge length is fixed at 8 bytes.
* The length goes in challenge[0] and the actual challenge starts
* at challenge[1].
*/
static void chapms_generate_challenge(ppp_pcb *pcb, unsigned char *challenge) {
LWIP_UNUSED_ARG(pcb);
*challenge++ = 8;
#ifdef DEBUGMPPEKEY
if (mschap_challenge && strlen(mschap_challenge) == 8)
memcpy(challenge, mschap_challenge, 8);
else
#endif
magic_random_bytes(challenge, 8);
}
static void chapms2_generate_challenge(ppp_pcb *pcb, unsigned char *challenge) {
LWIP_UNUSED_ARG(pcb);
*challenge++ = 16;
#ifdef DEBUGMPPEKEY
if (mschap_challenge && strlen(mschap_challenge) == 16)
memcpy(challenge, mschap_challenge, 16);
else
#endif
magic_random_bytes(challenge, 16);
}
static int chapms_verify_response(ppp_pcb *pcb, int id, const char *name,
const unsigned char *secret, int secret_len,
const unsigned char *challenge, const unsigned char *response,
char *message, int message_space) {
unsigned char md[MS_CHAP_RESPONSE_LEN];
int diff;
int challenge_len, response_len;
LWIP_UNUSED_ARG(id);
LWIP_UNUSED_ARG(name);
challenge_len = *challenge++; /* skip length, is 8 */
response_len = *response++;
if (response_len != MS_CHAP_RESPONSE_LEN)
goto bad;
#ifndef MSLANMAN
if (!response[MS_CHAP_USENT]) {
/* Should really propagate this into the error packet. */
ppp_notice("Peer request for LANMAN auth not supported");
goto bad;
}
#endif
/* Generate the expected response. */
ChapMS(pcb, (const u_char *)challenge, (const char *)secret, secret_len, md);
#ifdef MSLANMAN
/* Determine which part of response to verify against */
if (!response[MS_CHAP_USENT])
diff = memcmp(&response[MS_CHAP_LANMANRESP],
&md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN);
else
#endif
diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP],
MS_CHAP_NTRESP_LEN);
if (diff == 0) {
ppp_slprintf(message, message_space, "Access granted");
return 1;
}
bad:
/* See comments below for MS-CHAP V2 */
ppp_slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
challenge_len, challenge);
return 0;
}
static int chapms2_verify_response(ppp_pcb *pcb, int id, const char *name,
const unsigned char *secret, int secret_len,
const unsigned char *challenge, const unsigned char *response,
char *message, int message_space) {
unsigned char md[MS_CHAP2_RESPONSE_LEN];
char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
int challenge_len, response_len;
LWIP_UNUSED_ARG(id);
challenge_len = *challenge++; /* skip length, is 16 */
response_len = *response++;
if (response_len != MS_CHAP2_RESPONSE_LEN)
goto bad; /* not even the right length */
/* Generate the expected response and our mutual auth. */
ChapMS2(pcb, (const u_char*)challenge, (const u_char*)&response[MS_CHAP2_PEER_CHALLENGE], name,
(const char *)secret, secret_len, md,
(unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
/* compare MDs and send the appropriate status */
/*
* Per RFC 2759, success message must be formatted as
* "S=<auth_string> M=<message>"
* where
* <auth_string> is the Authenticator Response (mutual auth)
* <message> is a text message
*
* However, some versions of Windows (win98 tested) do not know
* about the M=<message> part (required per RFC 2759) and flag
* it as an error (reported incorrectly as an encryption error
* to the user). Since the RFC requires it, and it can be
* useful information, we supply it if the peer is a conforming
* system. Luckily (?), win98 sets the Flags field to 0x04
* (contrary to RFC requirements) so we can use that to
* distinguish between conforming and non-conforming systems.
*
* Special thanks to Alex Swiridov <say@real.kharkov.ua> for
* help debugging this.
*/
if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP],
MS_CHAP2_NTRESP_LEN) == 0) {
if (response[MS_CHAP2_FLAGS])
ppp_slprintf(message, message_space, "S=%s", saresponse);
else
ppp_slprintf(message, message_space, "S=%s M=%s",
saresponse, "Access granted");
return 1;
}
bad:
/*
* Failure message must be formatted as
* "E=e R=r C=c V=v M=m"
* where
* e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
* r = retry (we use 1, ok to retry)
* c = challenge to use for next response, we reuse previous
* v = Change Password version supported, we use 0
* m = text message
*
* The M=m part is only for MS-CHAPv2. Neither win2k nor
* win98 (others untested) display the message to the user anyway.
* They also both ignore the E=e code.
*
* Note that it's safe to reuse the same challenge as we don't
* actually accept another response based on the error message
* (and no clients try to resend a response anyway).
*
* Basically, this whole bit is useless code, even the small
* implementation here is only because of overspecification.
*/
ppp_slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
challenge_len, challenge, "Access denied");
return 0;
}
#endif /* PPP_SERVER */
static void chapms_make_response(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name,
const unsigned char *challenge, const char *secret, int secret_len,
unsigned char *private_) {
LWIP_UNUSED_ARG(id);
LWIP_UNUSED_ARG(our_name);
LWIP_UNUSED_ARG(private_);
challenge++; /* skip length, should be 8 */
*response++ = MS_CHAP_RESPONSE_LEN;
ChapMS(pcb, challenge, secret, secret_len, response);
}
static void chapms2_make_response(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name,
const unsigned char *challenge, const char *secret, int secret_len,
unsigned char *private_) {
LWIP_UNUSED_ARG(id);
challenge++; /* skip length, should be 16 */
*response++ = MS_CHAP2_RESPONSE_LEN;
ChapMS2(pcb, challenge,
#ifdef DEBUGMPPEKEY
mschap2_peer_challenge,
#else
NULL,
#endif
our_name, secret, secret_len, response, private_,
MS_CHAP2_AUTHENTICATEE);
}
static int chapms2_check_success(ppp_pcb *pcb, unsigned char *msg, int len, unsigned char *private_) {
LWIP_UNUSED_ARG(pcb);
if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
strncmp((char *)msg, "S=", 2) != 0) {
/* Packet does not start with "S=" */
ppp_error("MS-CHAPv2 Success packet is badly formed.");
return 0;
}
msg += 2;
len -= 2;
if (len < MS_AUTH_RESPONSE_LENGTH
|| memcmp(msg, private_, MS_AUTH_RESPONSE_LENGTH)) {
/* Authenticator Response did not match expected. */
ppp_error("MS-CHAPv2 mutual authentication failed.");
return 0;
}
/* Authenticator Response matches. */
msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
len -= MS_AUTH_RESPONSE_LENGTH;
if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
msg += 3; /* Eat the delimiter */
} else if (len) {
/* Packet has extra text which does not begin " M=" */
ppp_error("MS-CHAPv2 Success packet is badly formed.");
return 0;
}
return 1;
}
static void chapms_handle_failure(ppp_pcb *pcb, unsigned char *inp, int len) {
int err;
const char *p;
char msg[64];
LWIP_UNUSED_ARG(pcb);
/* We want a null-terminated string for strxxx(). */
len = LWIP_MIN(len, 63);
MEMCPY(msg, inp, len);
msg[len] = 0;
p = msg;
/*
* Deal with MS-CHAP formatted failure messages; just print the
* M=<message> part (if any). For MS-CHAP we're not really supposed
* to use M=<message>, but it shouldn't hurt. See
* chapms[2]_verify_response.
*/
if (!strncmp(p, "E=", 2))
err = strtol(p+2, NULL, 10); /* Remember the error code. */
else
goto print_msg; /* Message is badly formatted. */
if (len && ((p = strstr(p, " M=")) != NULL)) {
/* M=<message> field found. */
p += 3;
} else {
/* No M=<message>; use the error code. */
switch (err) {
case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
p = "E=646 Restricted logon hours";
break;
case MS_CHAP_ERROR_ACCT_DISABLED:
p = "E=647 Account disabled";
break;
case MS_CHAP_ERROR_PASSWD_EXPIRED:
p = "E=648 Password expired";
break;
case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
p = "E=649 No dialin permission";
break;
case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
p = "E=691 Authentication failure";
break;
case MS_CHAP_ERROR_CHANGING_PASSWORD:
/* Should never see this, we don't support Change Password. */
p = "E=709 Error changing password";
break;
default:
ppp_error("Unknown MS-CHAP authentication failure: %.*v",
len, inp);
return;
}
}
print_msg:
if (p != NULL)
ppp_error("MS-CHAP authentication failed: %v", p);
}
static void ChallengeResponse(const u_char *challenge,
const u_char PasswordHash[MD4_SIGNATURE_SIZE],
u_char response[24]) {
u_char ZPasswordHash[21];
lwip_des_context des;
u_char des_key[8];
BZERO(ZPasswordHash, sizeof(ZPasswordHash));
MEMCPY(ZPasswordHash, PasswordHash, MD4_SIGNATURE_SIZE);
#if 0
dbglog("ChallengeResponse - ZPasswordHash %.*B",
sizeof(ZPasswordHash), ZPasswordHash);
#endif
pppcrypt_56_to_64_bit_key(ZPasswordHash + 0, des_key);
lwip_des_init(&des);
lwip_des_setkey_enc(&des, des_key);
lwip_des_crypt_ecb(&des, challenge, response +0);
lwip_des_free(&des);
pppcrypt_56_to_64_bit_key(ZPasswordHash + 7, des_key);
lwip_des_init(&des);
lwip_des_setkey_enc(&des, des_key);
lwip_des_crypt_ecb(&des, challenge, response +8);
lwip_des_free(&des);
pppcrypt_56_to_64_bit_key(ZPasswordHash + 14, des_key);
lwip_des_init(&des);
lwip_des_setkey_enc(&des, des_key);
lwip_des_crypt_ecb(&des, challenge, response +16);
lwip_des_free(&des);
#if 0
dbglog("ChallengeResponse - response %.24B", response);
#endif
}
static void ChallengeHash(const u_char PeerChallenge[16], const u_char *rchallenge,
const char *username, u_char Challenge[8]) {
lwip_sha1_context sha1Context;
u_char sha1Hash[SHA1_SIGNATURE_SIZE];
const char *user;
/* remove domain from "domain\username" */
if ((user = strrchr(username, '\\')) != NULL)
++user;
else
user = username;
lwip_sha1_init(&sha1Context);
lwip_sha1_starts(&sha1Context);
lwip_sha1_update(&sha1Context, PeerChallenge, 16);
lwip_sha1_update(&sha1Context, rchallenge, 16);
lwip_sha1_update(&sha1Context, (const unsigned char*)user, strlen(user));
lwip_sha1_finish(&sha1Context, sha1Hash);
lwip_sha1_free(&sha1Context);
MEMCPY(Challenge, sha1Hash, 8);
}
/*
* Convert the ASCII version of the password to Unicode.
* This implicitly supports 8-bit ISO8859/1 characters.
* This gives us the little-endian representation, which
* is assumed by all M$ CHAP RFCs. (Unicode byte ordering
* is machine-dependent.)
*/
static void ascii2unicode(const char ascii[], int ascii_len, u_char unicode[]) {
int i;
BZERO(unicode, ascii_len * 2);
for (i = 0; i < ascii_len; i++)
unicode[i * 2] = (u_char) ascii[i];
}
static void NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE]) {
lwip_md4_context md4Context;
lwip_md4_init(&md4Context);
lwip_md4_starts(&md4Context);
lwip_md4_update(&md4Context, secret, secret_len);
lwip_md4_finish(&md4Context, hash);
lwip_md4_free(&md4Context);
}
static void ChapMS_NT(const u_char *rchallenge, const char *secret, int secret_len,
u_char NTResponse[24]) {
u_char unicodePassword[MAX_NT_PASSWORD * 2];
u_char PasswordHash[MD4_SIGNATURE_SIZE];
/* Hash the Unicode version of the secret (== password). */
ascii2unicode(secret, secret_len, unicodePassword);
NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
ChallengeResponse(rchallenge, PasswordHash, NTResponse);
}
static void ChapMS2_NT(const u_char *rchallenge, const u_char PeerChallenge[16], const char *username,
const char *secret, int secret_len, u_char NTResponse[24]) {
u_char unicodePassword[MAX_NT_PASSWORD * 2];
u_char PasswordHash[MD4_SIGNATURE_SIZE];
u_char Challenge[8];
ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
/* Hash the Unicode version of the secret (== password). */
ascii2unicode(secret, secret_len, unicodePassword);
NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
ChallengeResponse(Challenge, PasswordHash, NTResponse);
}
#ifdef MSLANMAN
static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
static void ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
unsigned char *response) {
int i;
u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
u_char PasswordHash[MD4_SIGNATURE_SIZE];
lwip_des_context des;
u_char des_key[8];
/* LANMan password is case insensitive */
BZERO(UcasePassword, sizeof(UcasePassword));
for (i = 0; i < secret_len; i++)
UcasePassword[i] = (u_char)toupper(secret[i]);
pppcrypt_56_to_64_bit_key(UcasePassword +0, des_key);
lwip_des_init(&des);
lwip_des_setkey_enc(&des, des_key);
lwip_des_crypt_ecb(&des, StdText, PasswordHash +0);
lwip_des_free(&des);
pppcrypt_56_to_64_bit_key(UcasePassword +7, des_key);
lwip_des_init(&des);
lwip_des_setkey_enc(&des, des_key);
lwip_des_crypt_ecb(&des, StdText, PasswordHash +8);
lwip_des_free(&des);
ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]);
}
#endif
static void GenerateAuthenticatorResponse(const u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
u_char NTResponse[24], const u_char PeerChallenge[16],
const u_char *rchallenge, const char *username,
u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) {
/*
* "Magic" constants used in response generation, from RFC 2759.
*/
static const u_char Magic1[39] = /* "Magic server to client signing constant" */
{ 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
static const u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
{ 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
0x6E };
int i;
lwip_sha1_context sha1Context;
u_char Digest[SHA1_SIGNATURE_SIZE];
u_char Challenge[8];
lwip_sha1_init(&sha1Context);
lwip_sha1_starts(&sha1Context);
lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
lwip_sha1_update(&sha1Context, NTResponse, 24);
lwip_sha1_update(&sha1Context, Magic1, sizeof(Magic1));
lwip_sha1_finish(&sha1Context, Digest);
lwip_sha1_free(&sha1Context);
ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
lwip_sha1_init(&sha1Context);
lwip_sha1_starts(&sha1Context);
lwip_sha1_update(&sha1Context, Digest, sizeof(Digest));
lwip_sha1_update(&sha1Context, Challenge, sizeof(Challenge));
lwip_sha1_update(&sha1Context, Magic2, sizeof(Magic2));
lwip_sha1_finish(&sha1Context, Digest);
lwip_sha1_free(&sha1Context);
/* Convert to ASCII hex string. */
for (i = 0; i < LWIP_MAX((MS_AUTH_RESPONSE_LENGTH / 2), (int)sizeof(Digest)); i++)
sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
}
static void GenerateAuthenticatorResponsePlain(
const char *secret, int secret_len,
u_char NTResponse[24], const u_char PeerChallenge[16],
const u_char *rchallenge, const char *username,
u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) {
u_char unicodePassword[MAX_NT_PASSWORD * 2];
u_char PasswordHash[MD4_SIGNATURE_SIZE];
u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
/* Hash (x2) the Unicode version of the secret (== password). */
ascii2unicode(secret, secret_len, unicodePassword);
NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
NTPasswordHash(PasswordHash, sizeof(PasswordHash),
PasswordHashHash);
GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
rchallenge, username, authResponse);
}
#if MPPE_SUPPORT
/*
* Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
*/
static void Set_Start_Key(ppp_pcb *pcb, const u_char *rchallenge, const char *secret, int secret_len) {
u_char unicodePassword[MAX_NT_PASSWORD * 2];
u_char PasswordHash[MD4_SIGNATURE_SIZE];
u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
lwip_sha1_context sha1Context;
u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
/* Hash (x2) the Unicode version of the secret (== password). */
ascii2unicode(secret, secret_len, unicodePassword);
NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
lwip_sha1_init(&sha1Context);
lwip_sha1_starts(&sha1Context);
lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
lwip_sha1_update(&sha1Context, rchallenge, 8);
lwip_sha1_finish(&sha1Context, Digest);
lwip_sha1_free(&sha1Context);
/* Same key in both directions. */
mppe_set_key(pcb, &pcb->mppe_comp, Digest);
mppe_set_key(pcb, &pcb->mppe_decomp, Digest);
pcb->mppe_keys_set = 1;
}
/*
* Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
*/
static void SetMasterKeys(ppp_pcb *pcb, const char *secret, int secret_len, u_char NTResponse[24], int IsServer) {
u_char unicodePassword[MAX_NT_PASSWORD * 2];
u_char PasswordHash[MD4_SIGNATURE_SIZE];
u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
lwip_sha1_context sha1Context;
u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
const u_char *s;
/* "This is the MPPE Master Key" */
static const u_char Magic1[27] =
{ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
/* "On the client side, this is the send key; "
"on the server side, it is the receive key." */
static const u_char Magic2[84] =
{ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
0x6b, 0x65, 0x79, 0x2e };
/* "On the client side, this is the receive key; "
"on the server side, it is the send key." */
static const u_char Magic3[84] =
{ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
0x6b, 0x65, 0x79, 0x2e };
/* Hash (x2) the Unicode version of the secret (== password). */
ascii2unicode(secret, secret_len, unicodePassword);
NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
lwip_sha1_init(&sha1Context);
lwip_sha1_starts(&sha1Context);
lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
lwip_sha1_update(&sha1Context, NTResponse, 24);
lwip_sha1_update(&sha1Context, Magic1, sizeof(Magic1));
lwip_sha1_finish(&sha1Context, MasterKey);
lwip_sha1_free(&sha1Context);
/*
* generate send key
*/
if (IsServer)
s = Magic3;
else
s = Magic2;
lwip_sha1_init(&sha1Context);
lwip_sha1_starts(&sha1Context);
lwip_sha1_update(&sha1Context, MasterKey, 16);
lwip_sha1_update(&sha1Context, mppe_sha1_pad1, SHA1_PAD_SIZE);
lwip_sha1_update(&sha1Context, s, 84);
lwip_sha1_update(&sha1Context, mppe_sha1_pad2, SHA1_PAD_SIZE);
lwip_sha1_finish(&sha1Context, Digest);
lwip_sha1_free(&sha1Context);
mppe_set_key(pcb, &pcb->mppe_comp, Digest);
/*
* generate recv key
*/
if (IsServer)
s = Magic2;
else
s = Magic3;
lwip_sha1_init(&sha1Context);
lwip_sha1_starts(&sha1Context);
lwip_sha1_update(&sha1Context, MasterKey, 16);
lwip_sha1_update(&sha1Context, mppe_sha1_pad1, SHA1_PAD_SIZE);
lwip_sha1_update(&sha1Context, s, 84);
lwip_sha1_update(&sha1Context, mppe_sha1_pad2, SHA1_PAD_SIZE);
lwip_sha1_finish(&sha1Context, Digest);
lwip_sha1_free(&sha1Context);
mppe_set_key(pcb, &pcb->mppe_decomp, Digest);
pcb->mppe_keys_set = 1;
}
#endif /* MPPE_SUPPORT */
static void ChapMS(ppp_pcb *pcb, const u_char *rchallenge, const char *secret, int secret_len,
unsigned char *response) {
#if !MPPE_SUPPORT
LWIP_UNUSED_ARG(pcb);
#endif /* !MPPE_SUPPORT */
BZERO(response, MS_CHAP_RESPONSE_LEN);
ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
#ifdef MSLANMAN
ChapMS_LANMan(rchallenge, secret, secret_len,
&response[MS_CHAP_LANMANRESP]);
/* preferred method is set by option */
response[MS_CHAP_USENT] = !ms_lanman;
#else
response[MS_CHAP_USENT] = 1;
#endif
#if MPPE_SUPPORT
Set_Start_Key(pcb, rchallenge, secret, secret_len);
#endif /* MPPE_SUPPORT */
}
/*
* If PeerChallenge is NULL, one is generated and the PeerChallenge
* field of response is filled in. Call this way when generating a response.
* If PeerChallenge is supplied, it is copied into the PeerChallenge field.
* Call this way when verifying a response (or debugging).
* Do not call with PeerChallenge = response.
*
* The PeerChallenge field of response is then used for calculation of the
* Authenticator Response.
*/
static void ChapMS2(ppp_pcb *pcb, const u_char *rchallenge, const u_char *PeerChallenge,
const char *user, const char *secret, int secret_len, unsigned char *response,
u_char authResponse[], int authenticator) {
/* ARGSUSED */
LWIP_UNUSED_ARG(authenticator);
#if !MPPE_SUPPORT
LWIP_UNUSED_ARG(pcb);
#endif /* !MPPE_SUPPORT */
BZERO(response, MS_CHAP2_RESPONSE_LEN);
/* Generate the Peer-Challenge if requested, or copy it if supplied. */
if (!PeerChallenge)
magic_random_bytes(&response[MS_CHAP2_PEER_CHALLENGE], MS_CHAP2_PEER_CHAL_LEN);
else
MEMCPY(&response[MS_CHAP2_PEER_CHALLENGE], PeerChallenge,
MS_CHAP2_PEER_CHAL_LEN);
/* Generate the NT-Response */
ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user,
secret, secret_len, &response[MS_CHAP2_NTRESP]);
/* Generate the Authenticator Response. */
GenerateAuthenticatorResponsePlain(secret, secret_len,
&response[MS_CHAP2_NTRESP],
&response[MS_CHAP2_PEER_CHALLENGE],
rchallenge, user, authResponse);
#if MPPE_SUPPORT
SetMasterKeys(pcb, secret, secret_len,
&response[MS_CHAP2_NTRESP], authenticator);
#endif /* MPPE_SUPPORT */
}
#if 0 /* UNUSED */
#if MPPE_SUPPORT
/*
* Set MPPE options from plugins.
*/
void set_mppe_enc_types(int policy, int types) {
/* Early exit for unknown policies. */
if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
policy != MPPE_ENC_POL_ENC_REQUIRED)
return;
/* Don't modify MPPE if it's optional and wasn't already configured. */
if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
return;
/*
* Disable undesirable encryption types. Note that we don't ENABLE
* any encryption types, to avoid overriding manual configuration.
*/
switch(types) {
case MPPE_ENC_TYPES_RC4_40:
ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
break;
case MPPE_ENC_TYPES_RC4_128:
ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */
break;
default:
break;
}
}
#endif /* MPPE_SUPPORT */
#endif /* UNUSED */
const struct chap_digest_type chapms_digest = {
CHAP_MICROSOFT, /* code */
#if PPP_SERVER
chapms_generate_challenge,
chapms_verify_response,
#endif /* PPP_SERVER */
chapms_make_response,
NULL, /* check_success */
chapms_handle_failure,
};
const struct chap_digest_type chapms2_digest = {
CHAP_MICROSOFT_V2, /* code */
#if PPP_SERVER
chapms2_generate_challenge,
chapms2_verify_response,
#endif /* PPP_SERVER */
chapms2_make_response,
chapms2_check_success,
chapms_handle_failure,
};
#endif /* PPP_SUPPORT && MSCHAP_SUPPORT */

View file

@ -0,0 +1,465 @@
/*
* demand.c - Support routines for demand-dialling.
*
* Copyright (c) 1996-2002 Paul Mackerras. 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. The name(s) of the authors of this software must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* 3. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Paul Mackerras
* <paulus@samba.org>".
*
* THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && DEMAND_SUPPORT /* don't build if not configured for use in lwipopts.h */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef PPP_FILTER
#include <pcap-bpf.h>
#endif
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/fsm.h"
#include "netif/ppp/ipcp.h"
#include "netif/ppp/lcp.h"
char *frame;
int framelen;
int framemax;
int escape_flag;
int flush_flag;
int fcs;
struct packet {
int length;
struct packet *next;
unsigned char data[1];
};
struct packet *pend_q;
struct packet *pend_qtail;
static int active_packet (unsigned char *, int);
/*
* demand_conf - configure the interface for doing dial-on-demand.
*/
void
demand_conf()
{
int i;
const struct protent *protp;
/* framemax = lcp_allowoptions[0].mru;
if (framemax < PPP_MRU) */
framemax = PPP_MRU;
framemax += PPP_HDRLEN + PPP_FCSLEN;
frame = malloc(framemax);
if (frame == NULL)
novm("demand frame");
framelen = 0;
pend_q = NULL;
escape_flag = 0;
flush_flag = 0;
fcs = PPP_INITFCS;
netif_set_mtu(pcb, LWIP_MIN(lcp_allowoptions[0].mru, PPP_MRU));
if (ppp_send_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0
|| ppp_recv_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0)
fatal("Couldn't set up demand-dialled PPP interface: %m");
#ifdef PPP_FILTER
set_filters(&pass_filter, &active_filter);
#endif
/*
* Call the demand_conf procedure for each protocol that's got one.
*/
for (i = 0; (protp = protocols[i]) != NULL; ++i)
if (protp->demand_conf != NULL)
((*protp->demand_conf)(pcb));
/* FIXME: find a way to die() here */
#if 0
if (!((*protp->demand_conf)(pcb)))
die(1);
#endif
}
/*
* demand_block - set each network protocol to block further packets.
*/
void
demand_block()
{
int i;
const struct protent *protp;
for (i = 0; (protp = protocols[i]) != NULL; ++i)
if (protp->demand_conf != NULL)
sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_QUEUE);
get_loop_output();
}
/*
* demand_discard - set each network protocol to discard packets
* with an error.
*/
void
demand_discard()
{
struct packet *pkt, *nextpkt;
int i;
const struct protent *protp;
for (i = 0; (protp = protocols[i]) != NULL; ++i)
if (protp->demand_conf != NULL)
sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_ERROR);
get_loop_output();
/* discard all saved packets */
for (pkt = pend_q; pkt != NULL; pkt = nextpkt) {
nextpkt = pkt->next;
free(pkt);
}
pend_q = NULL;
framelen = 0;
flush_flag = 0;
escape_flag = 0;
fcs = PPP_INITFCS;
}
/*
* demand_unblock - set each enabled network protocol to pass packets.
*/
void
demand_unblock()
{
int i;
const struct protent *protp;
for (i = 0; (protp = protocols[i]) != NULL; ++i)
if (protp->demand_conf != NULL)
sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_PASS);
}
/*
* FCS lookup table as calculated by genfcstab.
*/
static u_short fcstab[256] = {
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
/*
* loop_chars - process characters received from the loopback.
* Calls loop_frame when a complete frame has been accumulated.
* Return value is 1 if we need to bring up the link, 0 otherwise.
*/
int
loop_chars(p, n)
unsigned char *p;
int n;
{
int c, rv;
rv = 0;
/* check for synchronous connection... */
if ( (p[0] == 0xFF) && (p[1] == 0x03) ) {
rv = loop_frame(p,n);
return rv;
}
for (; n > 0; --n) {
c = *p++;
if (c == PPP_FLAG) {
if (!escape_flag && !flush_flag
&& framelen > 2 && fcs == PPP_GOODFCS) {
framelen -= 2;
if (loop_frame((unsigned char *)frame, framelen))
rv = 1;
}
framelen = 0;
flush_flag = 0;
escape_flag = 0;
fcs = PPP_INITFCS;
continue;
}
if (flush_flag)
continue;
if (escape_flag) {
c ^= PPP_TRANS;
escape_flag = 0;
} else if (c == PPP_ESCAPE) {
escape_flag = 1;
continue;
}
if (framelen >= framemax) {
flush_flag = 1;
continue;
}
frame[framelen++] = c;
fcs = PPP_FCS(fcs, c);
}
return rv;
}
/*
* loop_frame - given a frame obtained from the loopback,
* decide whether to bring up the link or not, and, if we want
* to transmit this frame later, put it on the pending queue.
* Return value is 1 if we need to bring up the link, 0 otherwise.
* We assume that the kernel driver has already applied the
* pass_filter, so we won't get packets it rejected.
* We apply the active_filter to see if we want this packet to
* bring up the link.
*/
int
loop_frame(frame, len)
unsigned char *frame;
int len;
{
struct packet *pkt;
/* dbglog("from loop: %P", frame, len); */
if (len < PPP_HDRLEN)
return 0;
if ((PPP_PROTOCOL(frame) & 0x8000) != 0)
return 0; /* shouldn't get any of these anyway */
if (!active_packet(frame, len))
return 0;
pkt = (struct packet *) malloc(sizeof(struct packet) + len);
if (pkt != NULL) {
pkt->length = len;
pkt->next = NULL;
memcpy(pkt->data, frame, len);
if (pend_q == NULL)
pend_q = pkt;
else
pend_qtail->next = pkt;
pend_qtail = pkt;
}
return 1;
}
/*
* demand_rexmit - Resend all those frames which we got via the
* loopback, now that the real serial link is up.
*/
void
demand_rexmit(proto, newip)
int proto;
u32_t newip;
{
struct packet *pkt, *prev, *nextpkt;
unsigned short checksum;
unsigned short pkt_checksum = 0;
unsigned iphdr;
struct timeval tv;
char cv = 0;
char ipstr[16];
prev = NULL;
pkt = pend_q;
pend_q = NULL;
tv.tv_sec = 1;
tv.tv_usec = 0;
select(0,NULL,NULL,NULL,&tv); /* Sleep for 1 Seconds */
for (; pkt != NULL; pkt = nextpkt) {
nextpkt = pkt->next;
if (PPP_PROTOCOL(pkt->data) == proto) {
if ( (proto == PPP_IP) && newip ) {
/* Get old checksum */
iphdr = (pkt->data[4] & 15) << 2;
checksum = *((unsigned short *) (pkt->data+14));
if (checksum == 0xFFFF) {
checksum = 0;
}
if (pkt->data[13] == 17) {
pkt_checksum = *((unsigned short *) (pkt->data+10+iphdr));
if (pkt_checksum) {
cv = 1;
if (pkt_checksum == 0xFFFF) {
pkt_checksum = 0;
}
}
else {
cv = 0;
}
}
if (pkt->data[13] == 6) {
pkt_checksum = *((unsigned short *) (pkt->data+20+iphdr));
cv = 1;
if (pkt_checksum == 0xFFFF) {
pkt_checksum = 0;
}
}
/* Delete old Source-IP-Address */
checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
pkt_checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
pkt_checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
/* Change Source-IP-Address */
* ((u32_t *) (pkt->data + 16)) = newip;
/* Add new Source-IP-Address */
checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
pkt_checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
pkt_checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
/* Write new checksum */
if (!checksum) {
checksum = 0xFFFF;
}
*((unsigned short *) (pkt->data+14)) = checksum;
if (pkt->data[13] == 6) {
*((unsigned short *) (pkt->data+20+iphdr)) = pkt_checksum;
}
if (cv && (pkt->data[13] == 17) ) {
*((unsigned short *) (pkt->data+10+iphdr)) = pkt_checksum;
}
/* Log Packet */
strcpy(ipstr,inet_ntoa(*( (struct in_addr *) (pkt->data+16))));
if (pkt->data[13] == 1) {
syslog(LOG_INFO,"Open ICMP %s -> %s\n",
ipstr,
inet_ntoa(*( (struct in_addr *) (pkt->data+20))));
} else {
syslog(LOG_INFO,"Open %s %s:%d -> %s:%d\n",
pkt->data[13] == 6 ? "TCP" : "UDP",
ipstr,
ntohs(*( (short *) (pkt->data+iphdr+4))),
inet_ntoa(*( (struct in_addr *) (pkt->data+20))),
ntohs(*( (short *) (pkt->data+iphdr+6))));
}
}
output(pcb, pkt->data, pkt->length);
free(pkt);
} else {
if (prev == NULL)
pend_q = pkt;
else
prev->next = pkt;
prev = pkt;
}
}
pend_qtail = prev;
if (prev != NULL)
prev->next = NULL;
}
/*
* Scan a packet to decide whether it is an "active" packet,
* that is, whether it is worth bringing up the link for.
*/
static int
active_packet(p, len)
unsigned char *p;
int len;
{
int proto, i;
const struct protent *protp;
if (len < PPP_HDRLEN)
return 0;
proto = PPP_PROTOCOL(p);
#ifdef PPP_FILTER
p[0] = 1; /* outbound packet indicator */
if ((pass_filter.bf_len != 0
&& bpf_filter(pass_filter.bf_insns, p, len, len) == 0)
|| (active_filter.bf_len != 0
&& bpf_filter(active_filter.bf_insns, p, len, len) == 0)) {
p[0] = 0xff;
return 0;
}
p[0] = 0xff;
#endif
for (i = 0; (protp = protocols[i]) != NULL; ++i) {
if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) {
if (protp->active_pkt == NULL)
return 1;
return (*protp->active_pkt)(p, len);
}
}
return 0; /* not a supported protocol !!?? */
}
#endif /* PPP_SUPPORT && DEMAND_SUPPORT */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,191 @@
/*
* ecp.c - PPP Encryption Control Protocol.
*
* Copyright (c) 2002 Google, Inc.
* 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(s) of the authors of this software must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Derived from ccp.c, which is:
*
* Copyright (c) 1994-2002 Paul Mackerras. 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. The name(s) of the authors of this software must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* 3. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Paul Mackerras
* <paulus@samba.org>".
*
* THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && ECP_SUPPORT /* don't build if not configured for use in lwipopts.h */
#include <string.h>
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/fsm.h"
#include "netif/ppp/ecp.h"
#if PPP_OPTIONS
static option_t ecp_option_list[] = {
{ "noecp", o_bool, &ecp_protent.enabled_flag,
"Disable ECP negotiation" },
{ "-ecp", o_bool, &ecp_protent.enabled_flag,
"Disable ECP negotiation", OPT_ALIAS },
{ NULL }
};
#endif /* PPP_OPTIONS */
/*
* Protocol entry points from main code.
*/
static void ecp_init (int unit);
/*
static void ecp_open (int unit);
static void ecp_close (int unit, char *);
static void ecp_lowerup (int unit);
static void ecp_lowerdown (int);
static void ecp_input (int unit, u_char *pkt, int len);
static void ecp_protrej (int unit);
*/
#if PRINTPKT_SUPPORT
static int ecp_printpkt (const u_char *pkt, int len,
void (*printer) (void *, char *, ...),
void *arg);
#endif /* PRINTPKT_SUPPORT */
/*
static void ecp_datainput (int unit, u_char *pkt, int len);
*/
const struct protent ecp_protent = {
PPP_ECP,
ecp_init,
NULL, /* ecp_input, */
NULL, /* ecp_protrej, */
NULL, /* ecp_lowerup, */
NULL, /* ecp_lowerdown, */
NULL, /* ecp_open, */
NULL, /* ecp_close, */
#if PRINTPKT_SUPPORT
ecp_printpkt,
#endif /* PRINTPKT_SUPPORT */
#if PPP_DATAINPUT
NULL, /* ecp_datainput, */
#endif /* PPP_DATAINPUT */
#if PRINTPKT_SUPPORT
"ECP",
"Encrypted",
#endif /* PRINTPKT_SUPPORT */
#if PPP_OPTIONS
ecp_option_list,
NULL,
#endif /* PPP_OPTIONS */
#if DEMAND_SUPPORT
NULL,
NULL
#endif /* DEMAND_SUPPORT */
};
fsm ecp_fsm[NUM_PPP];
ecp_options ecp_wantoptions[NUM_PPP]; /* what to request the peer to use */
ecp_options ecp_gotoptions[NUM_PPP]; /* what the peer agreed to do */
ecp_options ecp_allowoptions[NUM_PPP]; /* what we'll agree to do */
ecp_options ecp_hisoptions[NUM_PPP]; /* what we agreed to do */
static const fsm_callbacks ecp_callbacks = {
NULL, /* ecp_resetci, */
NULL, /* ecp_cilen, */
NULL, /* ecp_addci, */
NULL, /* ecp_ackci, */
NULL, /* ecp_nakci, */
NULL, /* ecp_rejci, */
NULL, /* ecp_reqci, */
NULL, /* ecp_up, */
NULL, /* ecp_down, */
NULL,
NULL,
NULL,
NULL,
NULL, /* ecp_extcode, */
"ECP"
};
/*
* ecp_init - initialize ECP.
*/
static void
ecp_init(unit)
int unit;
{
fsm *f = &ecp_fsm[unit];
f->unit = unit;
f->protocol = PPP_ECP;
f->callbacks = &ecp_callbacks;
fsm_init(f);
#if 0 /* Not necessary, everything is cleared in ppp_new() */
memset(&ecp_wantoptions[unit], 0, sizeof(ecp_options));
memset(&ecp_gotoptions[unit], 0, sizeof(ecp_options));
memset(&ecp_allowoptions[unit], 0, sizeof(ecp_options));
memset(&ecp_hisoptions[unit], 0, sizeof(ecp_options));
#endif /* 0 */
}
#if PRINTPKT_SUPPORT
static int
ecp_printpkt(p, plen, printer, arg)
const u_char *p;
int plen;
void (*printer) (void *, char *, ...);
void *arg;
{
return 0;
}
#endif /* PRINTPKT_SUPPORT */
#endif /* PPP_SUPPORT && ECP_SUPPORT */

View file

@ -0,0 +1,56 @@
/*
* eui64.c - EUI64 routines for IPv6CP.
*
* Copyright (c) 1999 Tommi Komulainen. 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(s) of the authors of this software must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Tommi Komulainen
* <Tommi.Komulainen@iki.fi>".
*
* THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: eui64.c,v 1.6 2002/12/04 23:03:32 paulus Exp $
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/eui64.h"
/*
* eui64_ntoa - Make an ascii representation of an interface identifier
*/
char *eui64_ntoa(eui64_t e) {
static char buf[20];
sprintf(buf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x",
e.e8[0], e.e8[1], e.e8[2], e.e8[3],
e.e8[4], e.e8[5], e.e8[6], e.e8[7]);
return buf;
}
#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */

View file

@ -0,0 +1,799 @@
/*
* fsm.c - {Link, IP} Control Protocol Finite State Machine.
*
* Copyright (c) 1984-2000 Carnegie Mellon University. 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 "Carnegie Mellon University" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For permission or any legal
* details, please contact
* Office of Technology Transfer
* Carnegie Mellon University
* 5000 Forbes Avenue
* Pittsburgh, PA 15213-3890
* (412) 268-4387, fax: (412) 268-7395
* tech-transfer@andrew.cmu.edu
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Computing Services
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
/*
* @todo:
* Randomize fsm id on link/init.
* Deal with variable outgoing MTU.
*/
#if 0 /* UNUSED */
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#endif /* UNUSED */
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/fsm.h"
static void fsm_timeout (void *);
static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len);
static void fsm_rconfack(fsm *f, int id, u_char *inp, int len);
static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len);
static void fsm_rtermreq(fsm *f, int id, u_char *p, int len);
static void fsm_rtermack(fsm *f);
static void fsm_rcoderej(fsm *f, u_char *inp, int len);
static void fsm_sconfreq(fsm *f, int retransmit);
#define PROTO_NAME(f) ((f)->callbacks->proto_name)
/*
* fsm_init - Initialize fsm.
*
* Initialize fsm state.
*/
void fsm_init(fsm *f) {
ppp_pcb *pcb = f->pcb;
f->state = PPP_FSM_INITIAL;
f->flags = 0;
f->id = 0; /* XXX Start with random id? */
f->maxnakloops = pcb->settings.fsm_max_nak_loops;
f->term_reason_len = 0;
}
/*
* fsm_lowerup - The lower layer is up.
*/
void fsm_lowerup(fsm *f) {
switch( f->state ){
case PPP_FSM_INITIAL:
f->state = PPP_FSM_CLOSED;
break;
case PPP_FSM_STARTING:
if( f->flags & OPT_SILENT )
f->state = PPP_FSM_STOPPED;
else {
/* Send an initial configure-request */
fsm_sconfreq(f, 0);
f->state = PPP_FSM_REQSENT;
}
break;
default:
FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state));
/* no break */
}
}
/*
* fsm_lowerdown - The lower layer is down.
*
* Cancel all timeouts and inform upper layers.
*/
void fsm_lowerdown(fsm *f) {
switch( f->state ){
case PPP_FSM_CLOSED:
f->state = PPP_FSM_INITIAL;
break;
case PPP_FSM_STOPPED:
f->state = PPP_FSM_STARTING;
if( f->callbacks->starting )
(*f->callbacks->starting)(f);
break;
case PPP_FSM_CLOSING:
f->state = PPP_FSM_INITIAL;
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
break;
case PPP_FSM_STOPPING:
case PPP_FSM_REQSENT:
case PPP_FSM_ACKRCVD:
case PPP_FSM_ACKSENT:
f->state = PPP_FSM_STARTING;
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
break;
case PPP_FSM_OPENED:
if( f->callbacks->down )
(*f->callbacks->down)(f);
f->state = PPP_FSM_STARTING;
break;
default:
FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state));
/* no break */
}
}
/*
* fsm_open - Link is allowed to come up.
*/
void fsm_open(fsm *f) {
switch( f->state ){
case PPP_FSM_INITIAL:
f->state = PPP_FSM_STARTING;
if( f->callbacks->starting )
(*f->callbacks->starting)(f);
break;
case PPP_FSM_CLOSED:
if( f->flags & OPT_SILENT )
f->state = PPP_FSM_STOPPED;
else {
/* Send an initial configure-request */
fsm_sconfreq(f, 0);
f->state = PPP_FSM_REQSENT;
}
break;
case PPP_FSM_CLOSING:
f->state = PPP_FSM_STOPPING;
/* fall through */
/* no break */
case PPP_FSM_STOPPED:
case PPP_FSM_OPENED:
if( f->flags & OPT_RESTART ){
fsm_lowerdown(f);
fsm_lowerup(f);
}
break;
default:
break;
}
}
/*
* terminate_layer - Start process of shutting down the FSM
*
* Cancel any timeout running, notify upper layers we're done, and
* send a terminate-request message as configured.
*/
static void terminate_layer(fsm *f, int nextstate) {
ppp_pcb *pcb = f->pcb;
if( f->state != PPP_FSM_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 and send Terminate-Request */
f->retransmits = pcb->settings.fsm_max_term_transmits;
fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
(const u_char *) f->term_reason, f->term_reason_len);
if (f->retransmits == 0) {
/*
* User asked for no terminate requests at all; just close it.
* We've already fired off one Terminate-Request just to be nice
* to the peer, but we're not going to wait for a reply.
*/
f->state = nextstate == PPP_FSM_CLOSING ? PPP_FSM_CLOSED : PPP_FSM_STOPPED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
return;
}
TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time);
--f->retransmits;
f->state = nextstate;
}
/*
* fsm_close - Start closing connection.
*
* Cancel timeouts and either initiate close or possibly go directly to
* the PPP_FSM_CLOSED state.
*/
void fsm_close(fsm *f, const char *reason) {
f->term_reason = reason;
f->term_reason_len = (reason == NULL? 0: LWIP_MIN(strlen(reason), 0xFF) );
switch( f->state ){
case PPP_FSM_STARTING:
f->state = PPP_FSM_INITIAL;
break;
case PPP_FSM_STOPPED:
f->state = PPP_FSM_CLOSED;
break;
case PPP_FSM_STOPPING:
f->state = PPP_FSM_CLOSING;
break;
case PPP_FSM_REQSENT:
case PPP_FSM_ACKRCVD:
case PPP_FSM_ACKSENT:
case PPP_FSM_OPENED:
terminate_layer(f, PPP_FSM_CLOSING);
break;
default:
break;
}
}
/*
* fsm_timeout - Timeout expired.
*/
static void fsm_timeout(void *arg) {
fsm *f = (fsm *) arg;
ppp_pcb *pcb = f->pcb;
switch (f->state) {
case PPP_FSM_CLOSING:
case PPP_FSM_STOPPING:
if( f->retransmits <= 0 ){
/*
* We've waited for an ack long enough. Peer probably heard us.
*/
f->state = (f->state == PPP_FSM_CLOSING)? PPP_FSM_CLOSED: PPP_FSM_STOPPED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
} else {
/* Send Terminate-Request */
fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
(const u_char *) f->term_reason, f->term_reason_len);
TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time);
--f->retransmits;
}
break;
case PPP_FSM_REQSENT:
case PPP_FSM_ACKRCVD:
case PPP_FSM_ACKSENT:
if (f->retransmits <= 0) {
ppp_warn("%s: timeout sending Config-Requests", PROTO_NAME(f));
f->state = PPP_FSM_STOPPED;
if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
(*f->callbacks->finished)(f);
} else {
/* Retransmit the configure-request */
if (f->callbacks->retransmit)
(*f->callbacks->retransmit)(f);
fsm_sconfreq(f, 1); /* Re-send Configure-Request */
if( f->state == PPP_FSM_ACKRCVD )
f->state = PPP_FSM_REQSENT;
}
break;
default:
FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->state));
/* no break */
}
}
/*
* fsm_input - Input packet.
*/
void fsm_input(fsm *f, u_char *inpacket, int l) {
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 < HEADERLEN) {
FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol));
return;
}
GETCHAR(code, inp);
GETCHAR(id, inp);
GETSHORT(len, inp);
if (len < HEADERLEN) {
FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol));
return;
}
if (len > l) {
FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol));
return;
}
len -= HEADERLEN; /* subtract header length */
if( f->state == PPP_FSM_INITIAL || f->state == PPP_FSM_STARTING ){
FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.",
f->protocol, f->state));
return;
}
/*
* 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_rconfreq - Receive Configure-Request.
*/
static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len) {
int code, reject_if_disagree;
switch( f->state ){
case PPP_FSM_CLOSED:
/* Go away, we're closed */
fsm_sdata(f, TERMACK, id, NULL, 0);
return;
case PPP_FSM_CLOSING:
case PPP_FSM_STOPPING:
return;
case PPP_FSM_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 = PPP_FSM_REQSENT;
break;
case PPP_FSM_STOPPED:
/* Negotiation started by our peer */
fsm_sconfreq(f, 0); /* Send initial Configure-Request */
f->state = PPP_FSM_REQSENT;
break;
default:
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, code, id, inp, len);
if (code == CONFACK) {
if (f->state == PPP_FSM_ACKRCVD) {
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
f->state = PPP_FSM_OPENED;
if (f->callbacks->up)
(*f->callbacks->up)(f); /* Inform upper layers */
} else
f->state = PPP_FSM_ACKSENT;
f->nakloops = 0;
} else {
/* we sent CONFACK or CONFREJ */
if (f->state != PPP_FSM_ACKRCVD)
f->state = PPP_FSM_REQSENT;
if( code == CONFNAK )
++f->nakloops;
}
}
/*
* fsm_rconfack - Receive Configure-Ack.
*/
static void fsm_rconfack(fsm *f, int id, u_char *inp, int len) {
ppp_pcb *pcb = f->pcb;
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 */
ppp_error("Received bad configure-ack: %P", inp, len);
return;
}
f->seen_ack = 1;
f->rnakloops = 0;
switch (f->state) {
case PPP_FSM_CLOSED:
case PPP_FSM_STOPPED:
fsm_sdata(f, TERMACK, id, NULL, 0);
break;
case PPP_FSM_REQSENT:
f->state = PPP_FSM_ACKRCVD;
f->retransmits = pcb->settings.fsm_max_conf_req_transmits;
break;
case PPP_FSM_ACKRCVD:
/* Huh? an extra valid Ack? oh well... */
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
fsm_sconfreq(f, 0);
f->state = PPP_FSM_REQSENT;
break;
case PPP_FSM_ACKSENT:
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
f->state = PPP_FSM_OPENED;
f->retransmits = pcb->settings.fsm_max_conf_req_transmits;
if (f->callbacks->up)
(*f->callbacks->up)(f); /* Inform upper layers */
break;
case PPP_FSM_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 = PPP_FSM_REQSENT;
break;
default:
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 ret;
int treat_as_reject;
if (id != f->reqid || f->seen_ack) /* Expected id? */
return; /* Nope, toss... */
if (code == CONFNAK) {
++f->rnakloops;
treat_as_reject = (f->rnakloops >= f->maxnakloops);
if (f->callbacks->nakci == NULL
|| !(ret = f->callbacks->nakci(f, inp, len, treat_as_reject))) {
ppp_error("Received bad configure-nak: %P", inp, len);
return;
}
} else {
f->rnakloops = 0;
if (f->callbacks->rejci == NULL
|| !(ret = f->callbacks->rejci(f, inp, len))) {
ppp_error("Received bad configure-rej: %P", inp, len);
return;
}
}
f->seen_ack = 1;
switch (f->state) {
case PPP_FSM_CLOSED:
case PPP_FSM_STOPPED:
fsm_sdata(f, TERMACK, id, NULL, 0);
break;
case PPP_FSM_REQSENT:
case PPP_FSM_ACKSENT:
/* They didn't agree to what we wanted - try another request */
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
if (ret < 0)
f->state = PPP_FSM_STOPPED; /* kludge for stopping CCP */
else
fsm_sconfreq(f, 0); /* Send Configure-Request */
break;
case PPP_FSM_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 = PPP_FSM_REQSENT;
break;
case PPP_FSM_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 = PPP_FSM_REQSENT;
break;
default:
break;
}
}
/*
* fsm_rtermreq - Receive Terminate-Req.
*/
static void fsm_rtermreq(fsm *f, int id, u_char *p, int len) {
ppp_pcb *pcb = f->pcb;
switch (f->state) {
case PPP_FSM_ACKRCVD:
case PPP_FSM_ACKSENT:
f->state = PPP_FSM_REQSENT; /* Start over but keep trying */
break;
case PPP_FSM_OPENED:
if (len > 0) {
ppp_info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p);
} else
ppp_info("%s terminated by peer", PROTO_NAME(f));
f->retransmits = 0;
f->state = PPP_FSM_STOPPING;
if (f->callbacks->down)
(*f->callbacks->down)(f); /* Inform upper layers */
TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time);
break;
default:
break;
}
fsm_sdata(f, TERMACK, id, NULL, 0);
}
/*
* fsm_rtermack - Receive Terminate-Ack.
*/
static void fsm_rtermack(fsm *f) {
switch (f->state) {
case PPP_FSM_CLOSING:
UNTIMEOUT(fsm_timeout, f);
f->state = PPP_FSM_CLOSED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case PPP_FSM_STOPPING:
UNTIMEOUT(fsm_timeout, f);
f->state = PPP_FSM_STOPPED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case PPP_FSM_ACKRCVD:
f->state = PPP_FSM_REQSENT;
break;
case PPP_FSM_OPENED:
if (f->callbacks->down)
(*f->callbacks->down)(f); /* Inform upper layers */
fsm_sconfreq(f, 0);
f->state = PPP_FSM_REQSENT;
break;
default:
break;
}
}
/*
* fsm_rcoderej - Receive an Code-Reject.
*/
static void fsm_rcoderej(fsm *f, u_char *inp, int len) {
u_char code, id;
if (len < HEADERLEN) {
FSMDEBUG(("fsm_rcoderej: Rcvd short Code-Reject packet!"));
return;
}
GETCHAR(code, inp);
GETCHAR(id, inp);
ppp_warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id);
if( f->state == PPP_FSM_ACKRCVD )
f->state = PPP_FSM_REQSENT;
}
/*
* fsm_protreject - Peer doesn't speak this protocol.
*
* Treat this as a catastrophic error (RXJ-).
*/
void fsm_protreject(fsm *f) {
switch( f->state ){
case PPP_FSM_CLOSING:
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
/* fall through */
/* no break */
case PPP_FSM_CLOSED:
f->state = PPP_FSM_CLOSED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case PPP_FSM_STOPPING:
case PPP_FSM_REQSENT:
case PPP_FSM_ACKRCVD:
case PPP_FSM_ACKSENT:
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
/* fall through */
/* no break */
case PPP_FSM_STOPPED:
f->state = PPP_FSM_STOPPED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case PPP_FSM_OPENED:
terminate_layer(f, PPP_FSM_STOPPING);
break;
default:
FSMDEBUG(("%s: Protocol-reject event in state %d!",
PROTO_NAME(f), f->state));
/* no break */
}
}
/*
* fsm_sconfreq - Send a Configure-Request.
*/
static void fsm_sconfreq(fsm *f, int retransmit) {
ppp_pcb *pcb = f->pcb;
struct pbuf *p;
u_char *outp;
int cilen;
if( f->state != PPP_FSM_REQSENT && f->state != PPP_FSM_ACKRCVD && f->state != PPP_FSM_ACKSENT ){
/* Not currently negotiating - reset options */
if( f->callbacks->resetci )
(*f->callbacks->resetci)(f);
f->nakloops = 0;
f->rnakloops = 0;
}
if( !retransmit ){
/* New request - reset retransmission counter, use new ID */
f->retransmits = pcb->settings.fsm_max_conf_req_transmits;
f->reqid = ++f->id;
}
f->seen_ack = 0;
/*
* Make up the request packet
*/
if( f->callbacks->cilen && f->callbacks->addci ){
cilen = (*f->callbacks->cilen)(f);
if( cilen > pcb->peer_mru - HEADERLEN )
cilen = pcb->peer_mru - HEADERLEN;
} else
cilen = 0;
p = pbuf_alloc(PBUF_RAW, (u16_t)(cilen + HEADERLEN + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE);
if(NULL == p)
return;
if(p->tot_len != p->len) {
pbuf_free(p);
return;
}
/* send the request to our peer */
outp = (u_char*)p->payload;
MAKEHEADER(outp, f->protocol);
PUTCHAR(CONFREQ, outp);
PUTCHAR(f->reqid, outp);
PUTSHORT(cilen + HEADERLEN, outp);
if (cilen != 0) {
(*f->callbacks->addci)(f, outp, &cilen);
LWIP_ASSERT("cilen == p->len - HEADERLEN - PPP_HDRLEN", cilen == p->len - HEADERLEN - PPP_HDRLEN);
}
ppp_write(pcb, p);
/* start the retransmit timer */
--f->retransmits;
TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time);
}
/*
* 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, const u_char *data, int datalen) {
ppp_pcb *pcb = f->pcb;
struct pbuf *p;
u_char *outp;
int outlen;
/* Adjust length to be smaller than MTU */
if (datalen > pcb->peer_mru - HEADERLEN)
datalen = pcb->peer_mru - HEADERLEN;
outlen = datalen + HEADERLEN;
p = pbuf_alloc(PBUF_RAW, (u16_t)(outlen + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE);
if(NULL == p)
return;
if(p->tot_len != p->len) {
pbuf_free(p);
return;
}
outp = (u_char*)p->payload;
if (datalen) /* && data != outp + PPP_HDRLEN + HEADERLEN) -- was only for fsm_sconfreq() */
MEMCPY(outp + PPP_HDRLEN + HEADERLEN, data, datalen);
MAKEHEADER(outp, f->protocol);
PUTCHAR(code, outp);
PUTCHAR(id, outp);
PUTSHORT(outlen, outp);
ppp_write(pcb, p);
}
#endif /* PPP_SUPPORT */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,294 @@
/*
* magic.c - PPP Magic Number routines.
*
* Copyright (c) 1984-2000 Carnegie Mellon University. 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 "Carnegie Mellon University" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For permission or any legal
* details, please contact
* Office of Technology Transfer
* Carnegie Mellon University
* 5000 Forbes Avenue
* Pittsburgh, PA 15213-3890
* (412) 268-4387, fax: (412) 268-7395
* tech-transfer@andrew.cmu.edu
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Computing Services
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*****************************************************************************
* 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 "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/magic.h"
#if PPP_MD5_RANDM /* Using MD5 for better randomness if enabled */
#include "netif/ppp/pppcrypt.h"
#define MD5_HASH_SIZE 16
static char magic_randpool[MD5_HASH_SIZE]; /* Pool of randomness. */
static long magic_randcount; /* Pseudo-random incrementer */
static u32_t magic_randomseed; /* Seed used for random number generation. */
/*
* 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
*/
static void magic_churnrand(char *rand_data, u32_t rand_len) {
lwip_md5_context md5_ctx;
/* LWIP_DEBUGF(LOG_INFO, ("magic_churnrand: %u@%P\n", rand_len, rand_data)); */
lwip_md5_init(&md5_ctx);
lwip_md5_starts(&md5_ctx);
lwip_md5_update(&md5_ctx, (u_char *)magic_randpool, sizeof(magic_randpool));
if (rand_data) {
lwip_md5_update(&md5_ctx, (u_char *)rand_data, rand_len);
} else {
struct {
/* INCLUDE fields for any system sources of randomness */
u32_t jiffies;
#ifdef LWIP_RAND
u32_t rand;
#endif /* LWIP_RAND */
} sys_data;
magic_randomseed += sys_jiffies();
sys_data.jiffies = magic_randomseed;
#ifdef LWIP_RAND
sys_data.rand = LWIP_RAND();
#endif /* LWIP_RAND */
/* Load sys_data fields here. */
lwip_md5_update(&md5_ctx, (u_char *)&sys_data, sizeof(sys_data));
}
lwip_md5_finish(&md5_ctx, (u_char *)magic_randpool);
lwip_md5_free(&md5_ctx);
/* LWIP_DEBUGF(LOG_INFO, ("magic_churnrand: -> 0\n")); */
}
/*
* Initialize the random number generator.
*/
void magic_init(void) {
magic_churnrand(NULL, 0);
}
/*
* Randomize our random seed value.
*/
void magic_randomize(void) {
magic_churnrand(NULL, 0);
}
/*
* magic_random_bytes - Fill a buffer with random bytes.
*
* Use the random pool to generate random data. This degrades to pseudo
* random when used faster than randomness is supplied using magic_churnrand().
* Note: It's important that there be sufficient randomness in magic_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 magic_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
* magic_randcount each time? Probably there is a weakness but I wish that
* it was documented.
*/
void magic_random_bytes(unsigned char *buf, u32_t buf_len) {
lwip_md5_context md5_ctx;
u_char tmp[MD5_HASH_SIZE];
u32_t n;
while (buf_len > 0) {
lwip_md5_init(&md5_ctx);
lwip_md5_starts(&md5_ctx);
lwip_md5_update(&md5_ctx, (u_char *)magic_randpool, sizeof(magic_randpool));
lwip_md5_update(&md5_ctx, (u_char *)&magic_randcount, sizeof(magic_randcount));
lwip_md5_finish(&md5_ctx, tmp);
lwip_md5_free(&md5_ctx);
magic_randcount++;
n = LWIP_MIN(buf_len, MD5_HASH_SIZE);
MEMCPY(buf, tmp, n);
buf += n;
buf_len -= n;
}
}
/*
* Return a new random number.
*/
u32_t magic(void) {
u32_t new_rand;
magic_random_bytes((unsigned char *)&new_rand, sizeof(new_rand));
return new_rand;
}
#else /* PPP_MD5_RANDM */
/*****************************/
/*** LOCAL DATA STRUCTURES ***/
/*****************************/
#ifndef LWIP_RAND
static int magic_randomized; /* Set when truely randomized. */
#endif /* LWIP_RAND */
static u32_t magic_randomseed; /* 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 magic_init(void) {
magic_randomseed += sys_jiffies();
#ifndef LWIP_RAND
/* Initialize the Borland random number generator. */
srand((unsigned)magic_randomseed);
#endif /* LWIP_RAND */
}
/*
* magic_init - Initialize the magic number generator.
*
* 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 magic_randomize(void) {
#ifndef LWIP_RAND
if (!magic_randomized) {
magic_randomized = !0;
magic_init();
/* The initialization function also updates the seed. */
} else {
#endif /* LWIP_RAND */
magic_randomseed += sys_jiffies();
#ifndef LWIP_RAND
}
#endif /* LWIP_RAND */
}
/*
* 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 magic(void) {
#ifdef LWIP_RAND
return LWIP_RAND() + magic_randomseed;
#else /* LWIP_RAND */
return ((u32_t)rand() << 16) + (u32_t)rand() + magic_randomseed;
#endif /* LWIP_RAND */
}
/*
* magic_random_bytes - Fill a buffer with random bytes.
*/
void magic_random_bytes(unsigned char *buf, u32_t buf_len) {
u32_t new_rand, n;
while (buf_len > 0) {
new_rand = magic();
n = LWIP_MIN(buf_len, sizeof(new_rand));
MEMCPY(buf, &new_rand, n);
buf += n;
buf_len -= n;
}
}
#endif /* PPP_MD5_RANDM */
/*
* Return a new random number between 0 and (2^pow)-1 included.
*/
u32_t magic_pow(u8_t pow) {
return magic() & ~(~0UL<<pow);
}
#endif /* PPP_SUPPORT */

View file

@ -0,0 +1,412 @@
/*
* mppe.c - interface MPPE to the PPP code.
*
* By Frank Cusack <fcusack@fcusack.com>.
* Copyright (c) 2002,2003,2004 Google, Inc.
* All rights reserved.
*
* License:
* 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.
*
* Changelog:
* 08/12/05 - Matt Domsch <Matt_Domsch@dell.com>
* Only need extra skb padding on transmit, not receive.
* 06/18/04 - Matt Domsch <Matt_Domsch@dell.com>, Oleg Makarenko <mole@quadra.ru>
* Use Linux kernel 2.6 arc4 and sha1 routines rather than
* providing our own.
* 2/15/04 - TS: added #include <version.h> and testing for Kernel
* version before using
* MOD_DEC_USAGE_COUNT/MOD_INC_USAGE_COUNT which are
* deprecated in 2.6
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && MPPE_SUPPORT /* don't build if not configured for use in lwipopts.h */
#include <string.h>
#include "lwip/err.h"
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/ccp.h"
#include "netif/ppp/mppe.h"
#include "netif/ppp/pppdebug.h"
#include "netif/ppp/pppcrypt.h"
#define SHA1_SIGNATURE_SIZE 20
/* ppp_mppe_state.bits definitions */
#define MPPE_BIT_A 0x80 /* Encryption table were (re)inititalized */
#define MPPE_BIT_B 0x40 /* MPPC only (not implemented) */
#define MPPE_BIT_C 0x20 /* MPPC only (not implemented) */
#define MPPE_BIT_D 0x10 /* This is an encrypted frame */
#define MPPE_BIT_FLUSHED MPPE_BIT_A
#define MPPE_BIT_ENCRYPTED MPPE_BIT_D
#define MPPE_BITS(p) ((p)[0] & 0xf0)
#define MPPE_CCOUNT(p) ((((p)[0] & 0x0f) << 8) + (p)[1])
#define MPPE_CCOUNT_SPACE 0x1000 /* The size of the ccount space */
#define MPPE_OVHD 2 /* MPPE overhead/packet */
#define SANITY_MAX 1600 /* Max bogon factor we will tolerate */
/*
* Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3.
* Well, not what's written there, but rather what they meant.
*/
static void mppe_rekey(ppp_mppe_state * state, int initial_key)
{
lwip_sha1_context sha1_ctx;
u8_t sha1_digest[SHA1_SIGNATURE_SIZE];
/*
* Key Derivation, from RFC 3078, RFC 3079.
* Equivalent to Get_Key() for MS-CHAP as described in RFC 3079.
*/
lwip_sha1_init(&sha1_ctx);
lwip_sha1_starts(&sha1_ctx);
lwip_sha1_update(&sha1_ctx, state->master_key, state->keylen);
lwip_sha1_update(&sha1_ctx, mppe_sha1_pad1, SHA1_PAD_SIZE);
lwip_sha1_update(&sha1_ctx, state->session_key, state->keylen);
lwip_sha1_update(&sha1_ctx, mppe_sha1_pad2, SHA1_PAD_SIZE);
lwip_sha1_finish(&sha1_ctx, sha1_digest);
lwip_sha1_free(&sha1_ctx);
MEMCPY(state->session_key, sha1_digest, state->keylen);
if (!initial_key) {
lwip_arc4_init(&state->arc4);
lwip_arc4_setup(&state->arc4, sha1_digest, state->keylen);
lwip_arc4_crypt(&state->arc4, state->session_key, state->keylen);
lwip_arc4_free(&state->arc4);
}
if (state->keylen == 8) {
/* See RFC 3078 */
state->session_key[0] = 0xd1;
state->session_key[1] = 0x26;
state->session_key[2] = 0x9e;
}
lwip_arc4_init(&state->arc4);
lwip_arc4_setup(&state->arc4, state->session_key, state->keylen);
}
/*
* Set key, used by MSCHAP before mppe_init() is actually called by CCP so we
* don't have to keep multiple copies of keys.
*/
void mppe_set_key(ppp_pcb *pcb, ppp_mppe_state *state, u8_t *key) {
LWIP_UNUSED_ARG(pcb);
MEMCPY(state->master_key, key, MPPE_MAX_KEY_LEN);
}
/*
* Initialize (de)compressor state.
*/
void
mppe_init(ppp_pcb *pcb, ppp_mppe_state *state, u8_t options)
{
#if PPP_DEBUG
const u8_t *debugstr = (const u8_t*)"mppe_comp_init";
if (&pcb->mppe_decomp == state) {
debugstr = (const u8_t*)"mppe_decomp_init";
}
#endif /* PPP_DEBUG */
/* Save keys. */
MEMCPY(state->session_key, state->master_key, sizeof(state->master_key));
if (options & MPPE_OPT_128)
state->keylen = 16;
else if (options & MPPE_OPT_40)
state->keylen = 8;
else {
PPPDEBUG(LOG_DEBUG, ("%s[%d]: unknown key length\n", debugstr,
pcb->netif->num));
lcp_close(pcb, "MPPE required but peer negotiation failed");
return;
}
if (options & MPPE_OPT_STATEFUL)
state->stateful = 1;
/* Generate the initial session key. */
mppe_rekey(state, 1);
#if PPP_DEBUG
{
int i;
char mkey[sizeof(state->master_key) * 2 + 1];
char skey[sizeof(state->session_key) * 2 + 1];
PPPDEBUG(LOG_DEBUG, ("%s[%d]: initialized with %d-bit %s mode\n",
debugstr, pcb->netif->num, (state->keylen == 16) ? 128 : 40,
(state->stateful) ? "stateful" : "stateless"));
for (i = 0; i < (int)sizeof(state->master_key); i++)
sprintf(mkey + i * 2, "%02x", state->master_key[i]);
for (i = 0; i < (int)sizeof(state->session_key); i++)
sprintf(skey + i * 2, "%02x", state->session_key[i]);
PPPDEBUG(LOG_DEBUG,
("%s[%d]: keys: master: %s initial session: %s\n",
debugstr, pcb->netif->num, mkey, skey));
}
#endif /* PPP_DEBUG */
/*
* Initialize the coherency count. The initial value is not specified
* in RFC 3078, but we can make a reasonable assumption that it will
* start at 0. Setting it to the max here makes the comp/decomp code
* do the right thing (determined through experiment).
*/
state->ccount = MPPE_CCOUNT_SPACE - 1;
/*
* Note that even though we have initialized the key table, we don't
* set the FLUSHED bit. This is contrary to RFC 3078, sec. 3.1.
*/
state->bits = MPPE_BIT_ENCRYPTED;
}
/*
* We received a CCP Reset-Request (actually, we are sending a Reset-Ack),
* tell the compressor to rekey. Note that we MUST NOT rekey for
* every CCP Reset-Request; we only rekey on the next xmit packet.
* We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost.
* So, rekeying for every CCP Reset-Request is broken as the peer will not
* know how many times we've rekeyed. (If we rekey and THEN get another
* CCP Reset-Request, we must rekey again.)
*/
void mppe_comp_reset(ppp_pcb *pcb, ppp_mppe_state *state)
{
LWIP_UNUSED_ARG(pcb);
state->bits |= MPPE_BIT_FLUSHED;
}
/*
* Compress (encrypt) a packet.
* It's strange to call this a compressor, since the output is always
* MPPE_OVHD + 2 bytes larger than the input.
*/
err_t
mppe_compress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb, u16_t protocol)
{
struct pbuf *n, *np;
u8_t *pl;
err_t err;
LWIP_UNUSED_ARG(pcb);
/* TCP stack requires that we don't change the packet payload, therefore we copy
* the whole packet before encryption.
*/
np = pbuf_alloc(PBUF_RAW, MPPE_OVHD + sizeof(protocol) + (*pb)->tot_len, PBUF_POOL);
if (!np) {
return ERR_MEM;
}
/* Hide MPPE header + protocol */
pbuf_header(np, -(s16_t)(MPPE_OVHD + sizeof(protocol)));
if ((err = pbuf_copy(np, *pb)) != ERR_OK) {
pbuf_free(np);
return err;
}
/* Reveal MPPE header + protocol */
pbuf_header(np, (s16_t)(MPPE_OVHD + sizeof(protocol)));
*pb = np;
pl = (u8_t*)np->payload;
state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
PPPDEBUG(LOG_DEBUG, ("mppe_compress[%d]: ccount %d\n", pcb->netif->num, state->ccount));
/* FIXME: use PUT* macros */
pl[0] = state->ccount>>8;
pl[1] = state->ccount;
if (!state->stateful || /* stateless mode */
((state->ccount & 0xff) == 0xff) || /* "flag" packet */
(state->bits & MPPE_BIT_FLUSHED)) { /* CCP Reset-Request */
/* We must rekey */
if (state->stateful) {
PPPDEBUG(LOG_DEBUG, ("mppe_compress[%d]: rekeying\n", pcb->netif->num));
}
mppe_rekey(state, 0);
state->bits |= MPPE_BIT_FLUSHED;
}
pl[0] |= state->bits;
state->bits &= ~MPPE_BIT_FLUSHED; /* reset for next xmit */
pl += MPPE_OVHD;
/* Add protocol */
/* FIXME: add PFC support */
pl[0] = protocol >> 8;
pl[1] = protocol;
/* Hide MPPE header */
pbuf_header(np, -(s16_t)MPPE_OVHD);
/* Encrypt packet */
for (n = np; n != NULL; n = n->next) {
lwip_arc4_crypt(&state->arc4, (u8_t*)n->payload, n->len);
if (n->tot_len == n->len) {
break;
}
}
/* Reveal MPPE header */
pbuf_header(np, (s16_t)MPPE_OVHD);
return ERR_OK;
}
/*
* We received a CCP Reset-Ack. Just ignore it.
*/
void mppe_decomp_reset(ppp_pcb *pcb, ppp_mppe_state *state)
{
LWIP_UNUSED_ARG(pcb);
LWIP_UNUSED_ARG(state);
return;
}
/*
* Decompress (decrypt) an MPPE packet.
*/
err_t
mppe_decompress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb)
{
struct pbuf *n0 = *pb, *n;
u8_t *pl;
u16_t ccount;
u8_t flushed;
/* MPPE Header */
if (n0->len < MPPE_OVHD) {
PPPDEBUG(LOG_DEBUG,
("mppe_decompress[%d]: short pkt (%d)\n",
pcb->netif->num, n0->len));
state->sanity_errors += 100;
goto sanity_error;
}
pl = (u8_t*)n0->payload;
flushed = MPPE_BITS(pl) & MPPE_BIT_FLUSHED;
ccount = MPPE_CCOUNT(pl);
PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: ccount %d\n",
pcb->netif->num, ccount));
/* sanity checks -- terminate with extreme prejudice */
if (!(MPPE_BITS(pl) & MPPE_BIT_ENCRYPTED)) {
PPPDEBUG(LOG_DEBUG,
("mppe_decompress[%d]: ENCRYPTED bit not set!\n",
pcb->netif->num));
state->sanity_errors += 100;
goto sanity_error;
}
if (!state->stateful && !flushed) {
PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: FLUSHED bit not set in "
"stateless mode!\n", pcb->netif->num));
state->sanity_errors += 100;
goto sanity_error;
}
if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) {
PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: FLUSHED bit not set on "
"flag packet!\n", pcb->netif->num));
state->sanity_errors += 100;
goto sanity_error;
}
/*
* Check the coherency count.
*/
if (!state->stateful) {
/* Discard late packet */
if ((ccount - state->ccount) % MPPE_CCOUNT_SPACE > MPPE_CCOUNT_SPACE / 2) {
state->sanity_errors++;
goto sanity_error;
}
/* RFC 3078, sec 8.1. Rekey for every packet. */
while (state->ccount != ccount) {
mppe_rekey(state, 0);
state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
}
} else {
/* RFC 3078, sec 8.2. */
if (!state->discard) {
/* normal state */
state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
if (ccount != state->ccount) {
/*
* (ccount > state->ccount)
* Packet loss detected, enter the discard state.
* Signal the peer to rekey (by sending a CCP Reset-Request).
*/
state->discard = 1;
ccp_resetrequest(pcb);
return ERR_BUF;
}
} else {
/* discard state */
if (!flushed) {
/* ccp.c will be silent (no additional CCP Reset-Requests). */
return ERR_BUF;
} else {
/* Rekey for every missed "flag" packet. */
while ((ccount & ~0xff) !=
(state->ccount & ~0xff)) {
mppe_rekey(state, 0);
state->ccount =
(state->ccount +
256) % MPPE_CCOUNT_SPACE;
}
/* reset */
state->discard = 0;
state->ccount = ccount;
/*
* Another problem with RFC 3078 here. It implies that the
* peer need not send a Reset-Ack packet. But RFC 1962
* requires it. Hopefully, M$ does send a Reset-Ack; even
* though it isn't required for MPPE synchronization, it is
* required to reset CCP state.
*/
}
}
if (flushed)
mppe_rekey(state, 0);
}
/* Hide MPPE header */
pbuf_header(n0, -(s16_t)(MPPE_OVHD));
/* Decrypt the packet. */
for (n = n0; n != NULL; n = n->next) {
lwip_arc4_crypt(&state->arc4, (u8_t*)n->payload, n->len);
if (n->tot_len == n->len) {
break;
}
}
/* good packet credit */
state->sanity_errors >>= 1;
return ERR_OK;
sanity_error:
if (state->sanity_errors >= SANITY_MAX) {
/*
* Take LCP down if the peer is sending too many bogons.
* We don't want to do this for a single or just a few
* instances since it could just be due to packet corruption.
*/
lcp_close(pcb, "Too many MPPE errors");
}
return ERR_BUF;
}
#endif /* PPP_SUPPORT && MPPE_SUPPORT */

View file

@ -0,0 +1,609 @@
/*
* multilink.c - support routines for multilink.
*
* Copyright (c) 2000-2002 Paul Mackerras. 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. The name(s) of the authors of this software must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* 3. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Paul Mackerras
* <paulus@samba.org>".
*
* THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && defined(HAVE_MULTILINK) /* don't build if not configured for use in lwipopts.h */
/* Multilink support
*
* Multilink uses Samba TDB (Trivial Database Library), which
* we cannot port, because it needs a filesystem.
*
* We have to choose between doing a memory-shared TDB-clone,
* or dropping multilink support at all.
*/
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <netinet/in.h>
#include <unistd.h>
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/fsm.h"
#include "netif/ppp/lcp.h"
#include "netif/ppp/tdb.h"
bool endpoint_specified; /* user gave explicit endpoint discriminator */
char *bundle_id; /* identifier for our bundle */
char *blinks_id; /* key for the list of links */
bool doing_multilink; /* multilink was enabled and agreed to */
bool multilink_master; /* we own the multilink bundle */
extern TDB_CONTEXT *pppdb;
extern char db_key[];
static void make_bundle_links (int append);
static void remove_bundle_link (void);
static void iterate_bundle_links (void (*func) (char *));
static int get_default_epdisc (struct epdisc *);
static int parse_num (char *str, const char *key, int *valp);
static int owns_unit (TDB_DATA pid, int unit);
#define set_ip_epdisc(ep, addr) do { \
ep->length = 4; \
ep->value[0] = addr >> 24; \
ep->value[1] = addr >> 16; \
ep->value[2] = addr >> 8; \
ep->value[3] = addr; \
} while (0)
#define LOCAL_IP_ADDR(addr) \
(((addr) & 0xff000000) == 0x0a000000 /* 10.x.x.x */ \
|| ((addr) & 0xfff00000) == 0xac100000 /* 172.16.x.x */ \
|| ((addr) & 0xffff0000) == 0xc0a80000) /* 192.168.x.x */
#define process_exists(n) (kill((n), 0) == 0 || errno != ESRCH)
void
mp_check_options()
{
lcp_options *wo = &lcp_wantoptions[0];
lcp_options *ao = &lcp_allowoptions[0];
doing_multilink = 0;
if (!multilink)
return;
/* if we're doing multilink, we have to negotiate MRRU */
if (!wo->neg_mrru) {
/* mrru not specified, default to mru */
wo->mrru = wo->mru;
wo->neg_mrru = 1;
}
ao->mrru = ao->mru;
ao->neg_mrru = 1;
if (!wo->neg_endpoint && !noendpoint) {
/* get a default endpoint value */
wo->neg_endpoint = get_default_epdisc(&wo->endpoint);
}
}
/*
* Make a new bundle or join us to an existing bundle
* if we are doing multilink.
*/
int
mp_join_bundle()
{
lcp_options *go = &lcp_gotoptions[0];
lcp_options *ho = &lcp_hisoptions[0];
lcp_options *ao = &lcp_allowoptions[0];
int unit, pppd_pid;
int l, mtu;
char *p;
TDB_DATA key, pid, rec;
if (doing_multilink) {
/* have previously joined a bundle */
if (!go->neg_mrru || !ho->neg_mrru) {
notice("oops, didn't get multilink on renegotiation");
lcp_close(pcb, "multilink required");
return 0;
}
/* XXX should check the peer_authname and ho->endpoint
are the same as previously */
return 0;
}
if (!go->neg_mrru || !ho->neg_mrru) {
/* not doing multilink */
if (go->neg_mrru)
notice("oops, multilink negotiated only for receive");
mtu = ho->neg_mru? ho->mru: PPP_MRU;
if (mtu > ao->mru)
mtu = ao->mru;
if (demand) {
/* already have a bundle */
cfg_bundle(0, 0, 0, 0);
netif_set_mtu(pcb, mtu);
return 0;
}
make_new_bundle(0, 0, 0, 0);
set_ifunit(1);
netif_set_mtu(pcb, mtu);
return 0;
}
doing_multilink = 1;
/*
* Find the appropriate bundle or join a new one.
* First we make up a name for the bundle.
* The length estimate is worst-case assuming every
* character has to be quoted.
*/
l = 4 * strlen(peer_authname) + 10;
if (ho->neg_endpoint)
l += 3 * ho->endpoint.length + 8;
if (bundle_name)
l += 3 * strlen(bundle_name) + 2;
bundle_id = malloc(l);
if (bundle_id == 0)
novm("bundle identifier");
p = bundle_id;
p += slprintf(p, l-1, "BUNDLE=\"%q\"", peer_authname);
if (ho->neg_endpoint || bundle_name)
*p++ = '/';
if (ho->neg_endpoint)
p += slprintf(p, bundle_id+l-p, "%s",
epdisc_to_str(&ho->endpoint));
if (bundle_name)
p += slprintf(p, bundle_id+l-p, "/%v", bundle_name);
/* Make the key for the list of links belonging to the bundle */
l = p - bundle_id;
blinks_id = malloc(l + 7);
if (blinks_id == NULL)
novm("bundle links key");
slprintf(blinks_id, l + 7, "BUNDLE_LINKS=%s", bundle_id + 7);
/*
* For demand mode, we only need to configure the bundle
* and attach the link.
*/
mtu = LWIP_MIN(ho->mrru, ao->mru);
if (demand) {
cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
netif_set_mtu(pcb, mtu);
script_setenv("BUNDLE", bundle_id + 7, 1);
return 0;
}
/*
* Check if the bundle ID is already in the database.
*/
unit = -1;
lock_db();
key.dptr = bundle_id;
key.dsize = p - bundle_id;
pid = tdb_fetch(pppdb, key);
if (pid.dptr != NULL) {
/* bundle ID exists, see if the pppd record exists */
rec = tdb_fetch(pppdb, pid);
if (rec.dptr != NULL && rec.dsize > 0) {
/* make sure the string is null-terminated */
rec.dptr[rec.dsize-1] = 0;
/* parse the interface number */
parse_num(rec.dptr, "IFNAME=ppp", &unit);
/* check the pid value */
if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid)
|| !process_exists(pppd_pid)
|| !owns_unit(pid, unit))
unit = -1;
free(rec.dptr);
}
free(pid.dptr);
}
if (unit >= 0) {
/* attach to existing unit */
if (bundle_attach(unit)) {
set_ifunit(0);
script_setenv("BUNDLE", bundle_id + 7, 0);
make_bundle_links(1);
unlock_db();
info("Link attached to %s", ifname);
return 1;
}
/* attach failed because bundle doesn't exist */
}
/* we have to make a new bundle */
make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
set_ifunit(1);
netif_set_mtu(pcb, mtu);
script_setenv("BUNDLE", bundle_id + 7, 1);
make_bundle_links(pcb);
unlock_db();
info("New bundle %s created", ifname);
multilink_master = 1;
return 0;
}
void mp_exit_bundle()
{
lock_db();
remove_bundle_link();
unlock_db();
}
static void sendhup(char *str)
{
int pid;
if (parse_num(str, "PPPD_PID=", &pid) && pid != getpid()) {
if (debug)
dbglog("sending SIGHUP to process %d", pid);
kill(pid, SIGHUP);
}
}
void mp_bundle_terminated()
{
TDB_DATA key;
bundle_terminating = 1;
upper_layers_down(pcb);
notice("Connection terminated.");
#if PPP_STATS_SUPPORT
print_link_stats();
#endif /* PPP_STATS_SUPPORT */
if (!demand) {
remove_pidfiles();
script_unsetenv("IFNAME");
}
lock_db();
destroy_bundle();
iterate_bundle_links(sendhup);
key.dptr = blinks_id;
key.dsize = strlen(blinks_id);
tdb_delete(pppdb, key);
unlock_db();
new_phase(PPP_PHASE_DEAD);
doing_multilink = 0;
multilink_master = 0;
}
static void make_bundle_links(int append)
{
TDB_DATA key, rec;
char *p;
char entry[32];
int l;
key.dptr = blinks_id;
key.dsize = strlen(blinks_id);
slprintf(entry, sizeof(entry), "%s;", db_key);
p = entry;
if (append) {
rec = tdb_fetch(pppdb, key);
if (rec.dptr != NULL && rec.dsize > 0) {
rec.dptr[rec.dsize-1] = 0;
if (strstr(rec.dptr, db_key) != NULL) {
/* already in there? strange */
warn("link entry already exists in tdb");
return;
}
l = rec.dsize + strlen(entry);
p = malloc(l);
if (p == NULL)
novm("bundle link list");
slprintf(p, l, "%s%s", rec.dptr, entry);
} else {
warn("bundle link list not found");
}
if (rec.dptr != NULL)
free(rec.dptr);
}
rec.dptr = p;
rec.dsize = strlen(p) + 1;
if (tdb_store(pppdb, key, rec, TDB_REPLACE))
error("couldn't %s bundle link list",
append? "update": "create");
if (p != entry)
free(p);
}
static void remove_bundle_link()
{
TDB_DATA key, rec;
char entry[32];
char *p, *q;
int l;
key.dptr = blinks_id;
key.dsize = strlen(blinks_id);
slprintf(entry, sizeof(entry), "%s;", db_key);
rec = tdb_fetch(pppdb, key);
if (rec.dptr == NULL || rec.dsize <= 0) {
if (rec.dptr != NULL)
free(rec.dptr);
return;
}
rec.dptr[rec.dsize-1] = 0;
p = strstr(rec.dptr, entry);
if (p != NULL) {
q = p + strlen(entry);
l = strlen(q) + 1;
memmove(p, q, l);
rec.dsize = p - rec.dptr + l;
if (tdb_store(pppdb, key, rec, TDB_REPLACE))
error("couldn't update bundle link list (removal)");
}
free(rec.dptr);
}
static void iterate_bundle_links(void (*func)(char *))
{
TDB_DATA key, rec, pp;
char *p, *q;
key.dptr = blinks_id;
key.dsize = strlen(blinks_id);
rec = tdb_fetch(pppdb, key);
if (rec.dptr == NULL || rec.dsize <= 0) {
error("bundle link list not found (iterating list)");
if (rec.dptr != NULL)
free(rec.dptr);
return;
}
p = rec.dptr;
p[rec.dsize-1] = 0;
while ((q = strchr(p, ';')) != NULL) {
*q = 0;
key.dptr = p;
key.dsize = q - p;
pp = tdb_fetch(pppdb, key);
if (pp.dptr != NULL && pp.dsize > 0) {
pp.dptr[pp.dsize-1] = 0;
func(pp.dptr);
}
if (pp.dptr != NULL)
free(pp.dptr);
p = q + 1;
}
free(rec.dptr);
}
static int
parse_num(str, key, valp)
char *str;
const char *key;
int *valp;
{
char *p, *endp;
int i;
p = strstr(str, key);
if (p != 0) {
p += strlen(key);
i = strtol(p, &endp, 10);
if (endp != p && (*endp == 0 || *endp == ';')) {
*valp = i;
return 1;
}
}
return 0;
}
/*
* Check whether the pppd identified by `key' still owns ppp unit `unit'.
*/
static int
owns_unit(key, unit)
TDB_DATA key;
int unit;
{
char ifkey[32];
TDB_DATA kd, vd;
int ret = 0;
slprintf(ifkey, sizeof(ifkey), "IFNAME=ppp%d", unit);
kd.dptr = ifkey;
kd.dsize = strlen(ifkey);
vd = tdb_fetch(pppdb, kd);
if (vd.dptr != NULL) {
ret = vd.dsize == key.dsize
&& memcmp(vd.dptr, key.dptr, vd.dsize) == 0;
free(vd.dptr);
}
return ret;
}
static int
get_default_epdisc(ep)
struct epdisc *ep;
{
char *p;
struct hostent *hp;
u32_t addr;
/* First try for an ethernet MAC address */
p = get_first_ethernet();
if (p != 0 && get_if_hwaddr(ep->value, p) >= 0) {
ep->class = EPD_MAC;
ep->length = 6;
return 1;
}
/* see if our hostname corresponds to a reasonable IP address */
hp = gethostbyname(hostname);
if (hp != NULL) {
addr = *(u32_t *)hp->h_addr;
if (!bad_ip_adrs(addr)) {
addr = lwip_ntohl(addr);
if (!LOCAL_IP_ADDR(addr)) {
ep->class = EPD_IP;
set_ip_epdisc(ep, addr);
return 1;
}
}
}
return 0;
}
/*
* epdisc_to_str - make a printable string from an endpoint discriminator.
*/
static char *endp_class_names[] = {
"null", "local", "IP", "MAC", "magic", "phone"
};
char *
epdisc_to_str(ep)
struct epdisc *ep;
{
static char str[MAX_ENDP_LEN*3+8];
u_char *p = ep->value;
int i, mask = 0;
char *q, c, c2;
if (ep->class == EPD_NULL && ep->length == 0)
return "null";
if (ep->class == EPD_IP && ep->length == 4) {
u32_t addr;
GETLONG(addr, p);
slprintf(str, sizeof(str), "IP:%I", lwip_htonl(addr));
return str;
}
c = ':';
c2 = '.';
if (ep->class == EPD_MAC && ep->length == 6)
c2 = ':';
else if (ep->class == EPD_MAGIC && (ep->length % 4) == 0)
mask = 3;
q = str;
if (ep->class <= EPD_PHONENUM)
q += slprintf(q, sizeof(str)-1, "%s",
endp_class_names[ep->class]);
else
q += slprintf(q, sizeof(str)-1, "%d", ep->class);
c = ':';
for (i = 0; i < ep->length && i < MAX_ENDP_LEN; ++i) {
if ((i & mask) == 0) {
*q++ = c;
c = c2;
}
q += slprintf(q, str + sizeof(str) - q, "%.2x", ep->value[i]);
}
return str;
}
static int hexc_val(int c)
{
if (c >= 'a')
return c - 'a' + 10;
if (c >= 'A')
return c - 'A' + 10;
return c - '0';
}
int
str_to_epdisc(ep, str)
struct epdisc *ep;
char *str;
{
int i, l;
char *p, *endp;
for (i = EPD_NULL; i <= EPD_PHONENUM; ++i) {
int sl = strlen(endp_class_names[i]);
if (strncasecmp(str, endp_class_names[i], sl) == 0) {
str += sl;
break;
}
}
if (i > EPD_PHONENUM) {
/* not a class name, try a decimal class number */
i = strtol(str, &endp, 10);
if (endp == str)
return 0; /* can't parse class number */
str = endp;
}
ep->class = i;
if (*str == 0) {
ep->length = 0;
return 1;
}
if (*str != ':' && *str != '.')
return 0;
++str;
if (i == EPD_IP) {
u32_t addr;
i = parse_dotted_ip(str, &addr);
if (i == 0 || str[i] != 0)
return 0;
set_ip_epdisc(ep, addr);
return 1;
}
if (i == EPD_MAC && get_if_hwaddr(ep->value, str) >= 0) {
ep->length = 6;
return 1;
}
p = str;
for (l = 0; l < MAX_ENDP_LEN; ++l) {
if (*str == 0)
break;
if (p <= str)
for (p = str; isxdigit(*p); ++p)
;
i = p - str;
if (i == 0)
return 0;
ep->value[l] = hexc_val(*str++);
if ((i & 1) == 0)
ep->value[l] = (ep->value[l] << 4) + hexc_val(*str++);
if (*str == ':' || *str == '.')
++str;
}
if (*str != 0 || (ep->class == EPD_MAC && l != 6))
return 0;
ep->length = l;
return 1;
}
#endif /* PPP_SUPPORT && HAVE_MULTILINK */

View file

@ -0,0 +1,22 @@
About PolarSSL files into lwIP PPP support
------------------------------------------
This folder contains some files fetched from the latest BSD release of
the PolarSSL project (PolarSSL 0.10.1-bsd) for ciphers and encryption
methods we need for lwIP PPP support.
The PolarSSL files were cleaned to contain only the necessary struct
fields and functions needed for lwIP.
The PolarSSL API was not changed at all, so if you are already using
PolarSSL you can choose to skip the compilation of the included PolarSSL
library into lwIP.
If you are not using the embedded copy you must include external
libraries into your arch/cc.h port file.
Beware of the stack requirements which can be a lot larger if you are not
using our cleaned PolarSSL library.
PolarSSL project website: http://polarssl.org/

View file

@ -0,0 +1,101 @@
/*
* An implementation of the ARCFOUR algorithm
*
* Based on XySSL: Copyright (C) 2006-2008 Christophe Devine
*
* Copyright (C) 2009 Paul Bakker <polarssl_maintainer at polarssl dot org>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the names of PolarSSL or XySSL 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 COPYRIGHT HOLDERS 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 COPYRIGHT
* OWNER 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.
*/
/*
* The ARCFOUR algorithm was publicly disclosed on 94/09.
*
* http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_ARC4
#include "netif/ppp/polarssl/arc4.h"
/*
* ARC4 key schedule
*/
void arc4_setup( arc4_context *ctx, unsigned char *key, int keylen )
{
int i, j, k, a;
unsigned char *m;
ctx->x = 0;
ctx->y = 0;
m = ctx->m;
for( i = 0; i < 256; i++ )
m[i] = (unsigned char) i;
j = k = 0;
for( i = 0; i < 256; i++, k++ )
{
if( k >= keylen ) k = 0;
a = m[i];
j = ( j + a + key[k] ) & 0xFF;
m[i] = m[j];
m[j] = (unsigned char) a;
}
}
/*
* ARC4 cipher function
*/
void arc4_crypt( arc4_context *ctx, unsigned char *buf, int buflen )
{
int i, x, y, a, b;
unsigned char *m;
x = ctx->x;
y = ctx->y;
m = ctx->m;
for( i = 0; i < buflen; i++ )
{
x = ( x + 1 ) & 0xFF; a = m[x];
y = ( y + a ) & 0xFF; b = m[y];
m[x] = (unsigned char) b;
m[y] = (unsigned char) a;
buf[i] = (unsigned char)
( buf[i] ^ m[(unsigned char)( a + b )] );
}
ctx->x = x;
ctx->y = y;
}
#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_DES */

View file

@ -0,0 +1,422 @@
/*
* FIPS-46-3 compliant Triple-DES implementation
*
* Based on XySSL: Copyright (C) 2006-2008 Christophe Devine
*
* Copyright (C) 2009 Paul Bakker <polarssl_maintainer at polarssl dot org>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the names of PolarSSL or XySSL 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 COPYRIGHT HOLDERS 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 COPYRIGHT
* OWNER 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.
*/
/*
* DES, on which TDES is based, was originally designed by Horst Feistel
* at IBM in 1974, and was adopted as a standard by NIST (formerly NBS).
*
* http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_DES
#include "netif/ppp/polarssl/des.h"
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_ULONG_BE
#define GET_ULONG_BE(n,b,i) \
{ \
(n) = ( (unsigned long) (b)[(i) ] << 24 ) \
| ( (unsigned long) (b)[(i) + 1] << 16 ) \
| ( (unsigned long) (b)[(i) + 2] << 8 ) \
| ( (unsigned long) (b)[(i) + 3] ); \
}
#endif
#ifndef PUT_ULONG_BE
#define PUT_ULONG_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
/*
* Expanded DES S-boxes
*/
static const unsigned long SB1[64] =
{
0x01010400, 0x00000000, 0x00010000, 0x01010404,
0x01010004, 0x00010404, 0x00000004, 0x00010000,
0x00000400, 0x01010400, 0x01010404, 0x00000400,
0x01000404, 0x01010004, 0x01000000, 0x00000004,
0x00000404, 0x01000400, 0x01000400, 0x00010400,
0x00010400, 0x01010000, 0x01010000, 0x01000404,
0x00010004, 0x01000004, 0x01000004, 0x00010004,
0x00000000, 0x00000404, 0x00010404, 0x01000000,
0x00010000, 0x01010404, 0x00000004, 0x01010000,
0x01010400, 0x01000000, 0x01000000, 0x00000400,
0x01010004, 0x00010000, 0x00010400, 0x01000004,
0x00000400, 0x00000004, 0x01000404, 0x00010404,
0x01010404, 0x00010004, 0x01010000, 0x01000404,
0x01000004, 0x00000404, 0x00010404, 0x01010400,
0x00000404, 0x01000400, 0x01000400, 0x00000000,
0x00010004, 0x00010400, 0x00000000, 0x01010004
};
static const unsigned long SB2[64] =
{
0x80108020, 0x80008000, 0x00008000, 0x00108020,
0x00100000, 0x00000020, 0x80100020, 0x80008020,
0x80000020, 0x80108020, 0x80108000, 0x80000000,
0x80008000, 0x00100000, 0x00000020, 0x80100020,
0x00108000, 0x00100020, 0x80008020, 0x00000000,
0x80000000, 0x00008000, 0x00108020, 0x80100000,
0x00100020, 0x80000020, 0x00000000, 0x00108000,
0x00008020, 0x80108000, 0x80100000, 0x00008020,
0x00000000, 0x00108020, 0x80100020, 0x00100000,
0x80008020, 0x80100000, 0x80108000, 0x00008000,
0x80100000, 0x80008000, 0x00000020, 0x80108020,
0x00108020, 0x00000020, 0x00008000, 0x80000000,
0x00008020, 0x80108000, 0x00100000, 0x80000020,
0x00100020, 0x80008020, 0x80000020, 0x00100020,
0x00108000, 0x00000000, 0x80008000, 0x00008020,
0x80000000, 0x80100020, 0x80108020, 0x00108000
};
static const unsigned long SB3[64] =
{
0x00000208, 0x08020200, 0x00000000, 0x08020008,
0x08000200, 0x00000000, 0x00020208, 0x08000200,
0x00020008, 0x08000008, 0x08000008, 0x00020000,
0x08020208, 0x00020008, 0x08020000, 0x00000208,
0x08000000, 0x00000008, 0x08020200, 0x00000200,
0x00020200, 0x08020000, 0x08020008, 0x00020208,
0x08000208, 0x00020200, 0x00020000, 0x08000208,
0x00000008, 0x08020208, 0x00000200, 0x08000000,
0x08020200, 0x08000000, 0x00020008, 0x00000208,
0x00020000, 0x08020200, 0x08000200, 0x00000000,
0x00000200, 0x00020008, 0x08020208, 0x08000200,
0x08000008, 0x00000200, 0x00000000, 0x08020008,
0x08000208, 0x00020000, 0x08000000, 0x08020208,
0x00000008, 0x00020208, 0x00020200, 0x08000008,
0x08020000, 0x08000208, 0x00000208, 0x08020000,
0x00020208, 0x00000008, 0x08020008, 0x00020200
};
static const unsigned long SB4[64] =
{
0x00802001, 0x00002081, 0x00002081, 0x00000080,
0x00802080, 0x00800081, 0x00800001, 0x00002001,
0x00000000, 0x00802000, 0x00802000, 0x00802081,
0x00000081, 0x00000000, 0x00800080, 0x00800001,
0x00000001, 0x00002000, 0x00800000, 0x00802001,
0x00000080, 0x00800000, 0x00002001, 0x00002080,
0x00800081, 0x00000001, 0x00002080, 0x00800080,
0x00002000, 0x00802080, 0x00802081, 0x00000081,
0x00800080, 0x00800001, 0x00802000, 0x00802081,
0x00000081, 0x00000000, 0x00000000, 0x00802000,
0x00002080, 0x00800080, 0x00800081, 0x00000001,
0x00802001, 0x00002081, 0x00002081, 0x00000080,
0x00802081, 0x00000081, 0x00000001, 0x00002000,
0x00800001, 0x00002001, 0x00802080, 0x00800081,
0x00002001, 0x00002080, 0x00800000, 0x00802001,
0x00000080, 0x00800000, 0x00002000, 0x00802080
};
static const unsigned long SB5[64] =
{
0x00000100, 0x02080100, 0x02080000, 0x42000100,
0x00080000, 0x00000100, 0x40000000, 0x02080000,
0x40080100, 0x00080000, 0x02000100, 0x40080100,
0x42000100, 0x42080000, 0x00080100, 0x40000000,
0x02000000, 0x40080000, 0x40080000, 0x00000000,
0x40000100, 0x42080100, 0x42080100, 0x02000100,
0x42080000, 0x40000100, 0x00000000, 0x42000000,
0x02080100, 0x02000000, 0x42000000, 0x00080100,
0x00080000, 0x42000100, 0x00000100, 0x02000000,
0x40000000, 0x02080000, 0x42000100, 0x40080100,
0x02000100, 0x40000000, 0x42080000, 0x02080100,
0x40080100, 0x00000100, 0x02000000, 0x42080000,
0x42080100, 0x00080100, 0x42000000, 0x42080100,
0x02080000, 0x00000000, 0x40080000, 0x42000000,
0x00080100, 0x02000100, 0x40000100, 0x00080000,
0x00000000, 0x40080000, 0x02080100, 0x40000100
};
static const unsigned long SB6[64] =
{
0x20000010, 0x20400000, 0x00004000, 0x20404010,
0x20400000, 0x00000010, 0x20404010, 0x00400000,
0x20004000, 0x00404010, 0x00400000, 0x20000010,
0x00400010, 0x20004000, 0x20000000, 0x00004010,
0x00000000, 0x00400010, 0x20004010, 0x00004000,
0x00404000, 0x20004010, 0x00000010, 0x20400010,
0x20400010, 0x00000000, 0x00404010, 0x20404000,
0x00004010, 0x00404000, 0x20404000, 0x20000000,
0x20004000, 0x00000010, 0x20400010, 0x00404000,
0x20404010, 0x00400000, 0x00004010, 0x20000010,
0x00400000, 0x20004000, 0x20000000, 0x00004010,
0x20000010, 0x20404010, 0x00404000, 0x20400000,
0x00404010, 0x20404000, 0x00000000, 0x20400010,
0x00000010, 0x00004000, 0x20400000, 0x00404010,
0x00004000, 0x00400010, 0x20004010, 0x00000000,
0x20404000, 0x20000000, 0x00400010, 0x20004010
};
static const unsigned long SB7[64] =
{
0x00200000, 0x04200002, 0x04000802, 0x00000000,
0x00000800, 0x04000802, 0x00200802, 0x04200800,
0x04200802, 0x00200000, 0x00000000, 0x04000002,
0x00000002, 0x04000000, 0x04200002, 0x00000802,
0x04000800, 0x00200802, 0x00200002, 0x04000800,
0x04000002, 0x04200000, 0x04200800, 0x00200002,
0x04200000, 0x00000800, 0x00000802, 0x04200802,
0x00200800, 0x00000002, 0x04000000, 0x00200800,
0x04000000, 0x00200800, 0x00200000, 0x04000802,
0x04000802, 0x04200002, 0x04200002, 0x00000002,
0x00200002, 0x04000000, 0x04000800, 0x00200000,
0x04200800, 0x00000802, 0x00200802, 0x04200800,
0x00000802, 0x04000002, 0x04200802, 0x04200000,
0x00200800, 0x00000000, 0x00000002, 0x04200802,
0x00000000, 0x00200802, 0x04200000, 0x00000800,
0x04000002, 0x04000800, 0x00000800, 0x00200002
};
static const unsigned long SB8[64] =
{
0x10001040, 0x00001000, 0x00040000, 0x10041040,
0x10000000, 0x10001040, 0x00000040, 0x10000000,
0x00040040, 0x10040000, 0x10041040, 0x00041000,
0x10041000, 0x00041040, 0x00001000, 0x00000040,
0x10040000, 0x10000040, 0x10001000, 0x00001040,
0x00041000, 0x00040040, 0x10040040, 0x10041000,
0x00001040, 0x00000000, 0x00000000, 0x10040040,
0x10000040, 0x10001000, 0x00041040, 0x00040000,
0x00041040, 0x00040000, 0x10041000, 0x00001000,
0x00000040, 0x10040040, 0x00001000, 0x00041040,
0x10001000, 0x00000040, 0x10000040, 0x10040000,
0x10040040, 0x10000000, 0x00040000, 0x10001040,
0x00000000, 0x10041040, 0x00040040, 0x10000040,
0x10040000, 0x10001000, 0x10001040, 0x00000000,
0x10041040, 0x00041000, 0x00041000, 0x00001040,
0x00001040, 0x00040040, 0x10000000, 0x10041000
};
/*
* PC1: left and right halves bit-swap
*/
static const unsigned long LHs[16] =
{
0x00000000, 0x00000001, 0x00000100, 0x00000101,
0x00010000, 0x00010001, 0x00010100, 0x00010101,
0x01000000, 0x01000001, 0x01000100, 0x01000101,
0x01010000, 0x01010001, 0x01010100, 0x01010101
};
static const unsigned long RHs[16] =
{
0x00000000, 0x01000000, 0x00010000, 0x01010000,
0x00000100, 0x01000100, 0x00010100, 0x01010100,
0x00000001, 0x01000001, 0x00010001, 0x01010001,
0x00000101, 0x01000101, 0x00010101, 0x01010101,
};
/*
* Initial Permutation macro
*/
#define DES_IP(X,Y) \
{ \
T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \
T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \
T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \
T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \
Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \
T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \
X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \
}
/*
* Final Permutation macro
*/
#define DES_FP(X,Y) \
{ \
X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \
T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \
Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \
T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \
T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \
T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \
T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \
}
/*
* DES round macro
*/
#define DES_ROUND(X,Y) \
{ \
T = *SK++ ^ X; \
Y ^= SB8[ (T ) & 0x3F ] ^ \
SB6[ (T >> 8) & 0x3F ] ^ \
SB4[ (T >> 16) & 0x3F ] ^ \
SB2[ (T >> 24) & 0x3F ]; \
\
T = *SK++ ^ ((X << 28) | (X >> 4)); \
Y ^= SB7[ (T ) & 0x3F ] ^ \
SB5[ (T >> 8) & 0x3F ] ^ \
SB3[ (T >> 16) & 0x3F ] ^ \
SB1[ (T >> 24) & 0x3F ]; \
}
#define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; }
static void des_setkey( unsigned long SK[32], unsigned char key[8] )
{
int i;
unsigned long X, Y, T;
GET_ULONG_BE( X, key, 0 );
GET_ULONG_BE( Y, key, 4 );
/*
* Permuted Choice 1
*/
T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4);
T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T );
X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2)
| (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] )
| (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6)
| (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4);
Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2)
| (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] )
| (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6)
| (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4);
X &= 0x0FFFFFFF;
Y &= 0x0FFFFFFF;
/*
* calculate subkeys
*/
for( i = 0; i < 16; i++ )
{
if( i < 2 || i == 8 || i == 15 )
{
X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF;
Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF;
}
else
{
X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF;
Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF;
}
*SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000)
| ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000)
| ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000)
| ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000)
| ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000)
| ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000)
| ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400)
| ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100)
| ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010)
| ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004)
| ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001);
*SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000)
| ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000)
| ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000)
| ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000)
| ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000)
| ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000)
| ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000)
| ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400)
| ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100)
| ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011)
| ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002);
}
}
/*
* DES key schedule (56-bit, encryption)
*/
void des_setkey_enc( des_context *ctx, unsigned char key[8] )
{
des_setkey( ctx->sk, key );
}
/*
* DES key schedule (56-bit, decryption)
*/
void des_setkey_dec( des_context *ctx, unsigned char key[8] )
{
int i;
des_setkey( ctx->sk, key );
for( i = 0; i < 16; i += 2 )
{
SWAP( ctx->sk[i ], ctx->sk[30 - i] );
SWAP( ctx->sk[i + 1], ctx->sk[31 - i] );
}
}
/*
* DES-ECB block encryption/decryption
*/
void des_crypt_ecb( des_context *ctx,
const unsigned char input[8],
unsigned char output[8] )
{
int i;
unsigned long X, Y, T, *SK;
SK = ctx->sk;
GET_ULONG_BE( X, input, 0 );
GET_ULONG_BE( Y, input, 4 );
DES_IP( X, Y );
for( i = 0; i < 8; i++ )
{
DES_ROUND( Y, X );
DES_ROUND( X, Y );
}
DES_FP( Y, X );
PUT_ULONG_BE( Y, output, 0 );
PUT_ULONG_BE( X, output, 4 );
}
#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_DES */

View file

@ -0,0 +1,281 @@
/*
* RFC 1186/1320 compliant MD4 implementation
*
* Based on XySSL: Copyright (C) 2006-2008 Christophe Devine
*
* Copyright (C) 2009 Paul Bakker <polarssl_maintainer at polarssl dot org>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the names of PolarSSL or XySSL 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 COPYRIGHT HOLDERS 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 COPYRIGHT
* OWNER 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.
*/
/*
* The MD4 algorithm was designed by Ron Rivest in 1990.
*
* http://www.ietf.org/rfc/rfc1186.txt
* http://www.ietf.org/rfc/rfc1320.txt
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD4
#include "netif/ppp/polarssl/md4.h"
#include <string.h>
/*
* 32-bit integer manipulation macros (little endian)
*/
#ifndef GET_ULONG_LE
#define GET_ULONG_LE(n,b,i) \
{ \
(n) = ( (unsigned long) (b)[(i) ] ) \
| ( (unsigned long) (b)[(i) + 1] << 8 ) \
| ( (unsigned long) (b)[(i) + 2] << 16 ) \
| ( (unsigned long) (b)[(i) + 3] << 24 ); \
}
#endif
#ifndef PUT_ULONG_LE
#define PUT_ULONG_LE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \
}
#endif
/*
* MD4 context setup
*/
void md4_starts( md4_context *ctx )
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
}
static void md4_process( md4_context *ctx, const unsigned char data[64] )
{
unsigned long X[16], A, B, C, D;
GET_ULONG_LE( X[ 0], data, 0 );
GET_ULONG_LE( X[ 1], data, 4 );
GET_ULONG_LE( X[ 2], data, 8 );
GET_ULONG_LE( X[ 3], data, 12 );
GET_ULONG_LE( X[ 4], data, 16 );
GET_ULONG_LE( X[ 5], data, 20 );
GET_ULONG_LE( X[ 6], data, 24 );
GET_ULONG_LE( X[ 7], data, 28 );
GET_ULONG_LE( X[ 8], data, 32 );
GET_ULONG_LE( X[ 9], data, 36 );
GET_ULONG_LE( X[10], data, 40 );
GET_ULONG_LE( X[11], data, 44 );
GET_ULONG_LE( X[12], data, 48 );
GET_ULONG_LE( X[13], data, 52 );
GET_ULONG_LE( X[14], data, 56 );
GET_ULONG_LE( X[15], data, 60 );
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
#define F(x, y, z) ((x & y) | ((~x) & z))
#define P(a,b,c,d,x,s) { a += F(b,c,d) + x; a = S(a,s); }
P( A, B, C, D, X[ 0], 3 );
P( D, A, B, C, X[ 1], 7 );
P( C, D, A, B, X[ 2], 11 );
P( B, C, D, A, X[ 3], 19 );
P( A, B, C, D, X[ 4], 3 );
P( D, A, B, C, X[ 5], 7 );
P( C, D, A, B, X[ 6], 11 );
P( B, C, D, A, X[ 7], 19 );
P( A, B, C, D, X[ 8], 3 );
P( D, A, B, C, X[ 9], 7 );
P( C, D, A, B, X[10], 11 );
P( B, C, D, A, X[11], 19 );
P( A, B, C, D, X[12], 3 );
P( D, A, B, C, X[13], 7 );
P( C, D, A, B, X[14], 11 );
P( B, C, D, A, X[15], 19 );
#undef P
#undef F
#define F(x,y,z) ((x & y) | (x & z) | (y & z))
#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); }
P( A, B, C, D, X[ 0], 3 );
P( D, A, B, C, X[ 4], 5 );
P( C, D, A, B, X[ 8], 9 );
P( B, C, D, A, X[12], 13 );
P( A, B, C, D, X[ 1], 3 );
P( D, A, B, C, X[ 5], 5 );
P( C, D, A, B, X[ 9], 9 );
P( B, C, D, A, X[13], 13 );
P( A, B, C, D, X[ 2], 3 );
P( D, A, B, C, X[ 6], 5 );
P( C, D, A, B, X[10], 9 );
P( B, C, D, A, X[14], 13 );
P( A, B, C, D, X[ 3], 3 );
P( D, A, B, C, X[ 7], 5 );
P( C, D, A, B, X[11], 9 );
P( B, C, D, A, X[15], 13 );
#undef P
#undef F
#define F(x,y,z) (x ^ y ^ z)
#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); }
P( A, B, C, D, X[ 0], 3 );
P( D, A, B, C, X[ 8], 9 );
P( C, D, A, B, X[ 4], 11 );
P( B, C, D, A, X[12], 15 );
P( A, B, C, D, X[ 2], 3 );
P( D, A, B, C, X[10], 9 );
P( C, D, A, B, X[ 6], 11 );
P( B, C, D, A, X[14], 15 );
P( A, B, C, D, X[ 1], 3 );
P( D, A, B, C, X[ 9], 9 );
P( C, D, A, B, X[ 5], 11 );
P( B, C, D, A, X[13], 15 );
P( A, B, C, D, X[ 3], 3 );
P( D, A, B, C, X[11], 9 );
P( C, D, A, B, X[ 7], 11 );
P( B, C, D, A, X[15], 15 );
#undef F
#undef P
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
}
/*
* MD4 process buffer
*/
void md4_update( md4_context *ctx, const unsigned char *input, int ilen )
{
int fill;
unsigned long left;
if( ilen <= 0 )
return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += ilen;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < (unsigned long) ilen )
ctx->total[1]++;
if( left && ilen >= fill )
{
MEMCPY( (void *) (ctx->buffer + left),
input, fill );
md4_process( ctx, ctx->buffer );
input += fill;
ilen -= fill;
left = 0;
}
while( ilen >= 64 )
{
md4_process( ctx, input );
input += 64;
ilen -= 64;
}
if( ilen > 0 )
{
MEMCPY( (void *) (ctx->buffer + left),
input, ilen );
}
}
static const unsigned char md4_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* MD4 final digest
*/
void md4_finish( md4_context *ctx, unsigned char output[16] )
{
unsigned long last, padn;
unsigned long high, low;
unsigned char msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_ULONG_LE( low, msglen, 0 );
PUT_ULONG_LE( high, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
md4_update( ctx, md4_padding, padn );
md4_update( ctx, msglen, 8 );
PUT_ULONG_LE( ctx->state[0], output, 0 );
PUT_ULONG_LE( ctx->state[1], output, 4 );
PUT_ULONG_LE( ctx->state[2], output, 8 );
PUT_ULONG_LE( ctx->state[3], output, 12 );
}
/*
* output = MD4( input buffer )
*/
void md4( unsigned char *input, int ilen, unsigned char output[16] )
{
md4_context ctx;
md4_starts( &ctx );
md4_update( &ctx, input, ilen );
md4_finish( &ctx, output );
}
#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD4 */

View file

@ -0,0 +1,300 @@
/*
* RFC 1321 compliant MD5 implementation
*
* Based on XySSL: Copyright (C) 2006-2008 Christophe Devine
*
* Copyright (C) 2009 Paul Bakker <polarssl_maintainer at polarssl dot org>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the names of PolarSSL or XySSL 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 COPYRIGHT HOLDERS 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 COPYRIGHT
* OWNER 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.
*/
/*
* The MD5 algorithm was designed by Ron Rivest in 1991.
*
* http://www.ietf.org/rfc/rfc1321.txt
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD5
#include "netif/ppp/polarssl/md5.h"
#include <string.h>
/*
* 32-bit integer manipulation macros (little endian)
*/
#ifndef GET_ULONG_LE
#define GET_ULONG_LE(n,b,i) \
{ \
(n) = ( (unsigned long) (b)[(i) ] ) \
| ( (unsigned long) (b)[(i) + 1] << 8 ) \
| ( (unsigned long) (b)[(i) + 2] << 16 ) \
| ( (unsigned long) (b)[(i) + 3] << 24 ); \
}
#endif
#ifndef PUT_ULONG_LE
#define PUT_ULONG_LE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \
}
#endif
/*
* MD5 context setup
*/
void md5_starts( md5_context *ctx )
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
}
static void md5_process( md5_context *ctx, const unsigned char data[64] )
{
unsigned long X[16], A, B, C, D;
GET_ULONG_LE( X[ 0], data, 0 );
GET_ULONG_LE( X[ 1], data, 4 );
GET_ULONG_LE( X[ 2], data, 8 );
GET_ULONG_LE( X[ 3], data, 12 );
GET_ULONG_LE( X[ 4], data, 16 );
GET_ULONG_LE( X[ 5], data, 20 );
GET_ULONG_LE( X[ 6], data, 24 );
GET_ULONG_LE( X[ 7], data, 28 );
GET_ULONG_LE( X[ 8], data, 32 );
GET_ULONG_LE( X[ 9], data, 36 );
GET_ULONG_LE( X[10], data, 40 );
GET_ULONG_LE( X[11], data, 44 );
GET_ULONG_LE( X[12], data, 48 );
GET_ULONG_LE( X[13], data, 52 );
GET_ULONG_LE( X[14], data, 56 );
GET_ULONG_LE( X[15], data, 60 );
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
#define P(a,b,c,d,k,s,t) \
{ \
a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
#define F(x,y,z) (z ^ (x & (y ^ z)))
P( A, B, C, D, 0, 7, 0xD76AA478 );
P( D, A, B, C, 1, 12, 0xE8C7B756 );
P( C, D, A, B, 2, 17, 0x242070DB );
P( B, C, D, A, 3, 22, 0xC1BDCEEE );
P( A, B, C, D, 4, 7, 0xF57C0FAF );
P( D, A, B, C, 5, 12, 0x4787C62A );
P( C, D, A, B, 6, 17, 0xA8304613 );
P( B, C, D, A, 7, 22, 0xFD469501 );
P( A, B, C, D, 8, 7, 0x698098D8 );
P( D, A, B, C, 9, 12, 0x8B44F7AF );
P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
P( B, C, D, A, 11, 22, 0x895CD7BE );
P( A, B, C, D, 12, 7, 0x6B901122 );
P( D, A, B, C, 13, 12, 0xFD987193 );
P( C, D, A, B, 14, 17, 0xA679438E );
P( B, C, D, A, 15, 22, 0x49B40821 );
#undef F
#define F(x,y,z) (y ^ (z & (x ^ y)))
P( A, B, C, D, 1, 5, 0xF61E2562 );
P( D, A, B, C, 6, 9, 0xC040B340 );
P( C, D, A, B, 11, 14, 0x265E5A51 );
P( B, C, D, A, 0, 20, 0xE9B6C7AA );
P( A, B, C, D, 5, 5, 0xD62F105D );
P( D, A, B, C, 10, 9, 0x02441453 );
P( C, D, A, B, 15, 14, 0xD8A1E681 );
P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
P( A, B, C, D, 9, 5, 0x21E1CDE6 );
P( D, A, B, C, 14, 9, 0xC33707D6 );
P( C, D, A, B, 3, 14, 0xF4D50D87 );
P( B, C, D, A, 8, 20, 0x455A14ED );
P( A, B, C, D, 13, 5, 0xA9E3E905 );
P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
P( C, D, A, B, 7, 14, 0x676F02D9 );
P( B, C, D, A, 12, 20, 0x8D2A4C8A );
#undef F
#define F(x,y,z) (x ^ y ^ z)
P( A, B, C, D, 5, 4, 0xFFFA3942 );
P( D, A, B, C, 8, 11, 0x8771F681 );
P( C, D, A, B, 11, 16, 0x6D9D6122 );
P( B, C, D, A, 14, 23, 0xFDE5380C );
P( A, B, C, D, 1, 4, 0xA4BEEA44 );
P( D, A, B, C, 4, 11, 0x4BDECFA9 );
P( C, D, A, B, 7, 16, 0xF6BB4B60 );
P( B, C, D, A, 10, 23, 0xBEBFBC70 );
P( A, B, C, D, 13, 4, 0x289B7EC6 );
P( D, A, B, C, 0, 11, 0xEAA127FA );
P( C, D, A, B, 3, 16, 0xD4EF3085 );
P( B, C, D, A, 6, 23, 0x04881D05 );
P( A, B, C, D, 9, 4, 0xD9D4D039 );
P( D, A, B, C, 12, 11, 0xE6DB99E5 );
P( C, D, A, B, 15, 16, 0x1FA27CF8 );
P( B, C, D, A, 2, 23, 0xC4AC5665 );
#undef F
#define F(x,y,z) (y ^ (x | ~z))
P( A, B, C, D, 0, 6, 0xF4292244 );
P( D, A, B, C, 7, 10, 0x432AFF97 );
P( C, D, A, B, 14, 15, 0xAB9423A7 );
P( B, C, D, A, 5, 21, 0xFC93A039 );
P( A, B, C, D, 12, 6, 0x655B59C3 );
P( D, A, B, C, 3, 10, 0x8F0CCC92 );
P( C, D, A, B, 10, 15, 0xFFEFF47D );
P( B, C, D, A, 1, 21, 0x85845DD1 );
P( A, B, C, D, 8, 6, 0x6FA87E4F );
P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
P( C, D, A, B, 6, 15, 0xA3014314 );
P( B, C, D, A, 13, 21, 0x4E0811A1 );
P( A, B, C, D, 4, 6, 0xF7537E82 );
P( D, A, B, C, 11, 10, 0xBD3AF235 );
P( C, D, A, B, 2, 15, 0x2AD7D2BB );
P( B, C, D, A, 9, 21, 0xEB86D391 );
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
}
/*
* MD5 process buffer
*/
void md5_update( md5_context *ctx, const unsigned char *input, int ilen )
{
int fill;
unsigned long left;
if( ilen <= 0 )
return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += ilen;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < (unsigned long) ilen )
ctx->total[1]++;
if( left && ilen >= fill )
{
MEMCPY( (void *) (ctx->buffer + left),
input, fill );
md5_process( ctx, ctx->buffer );
input += fill;
ilen -= fill;
left = 0;
}
while( ilen >= 64 )
{
md5_process( ctx, input );
input += 64;
ilen -= 64;
}
if( ilen > 0 )
{
MEMCPY( (void *) (ctx->buffer + left),
input, ilen );
}
}
static const unsigned char md5_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* MD5 final digest
*/
void md5_finish( md5_context *ctx, unsigned char output[16] )
{
unsigned long last, padn;
unsigned long high, low;
unsigned char msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_ULONG_LE( low, msglen, 0 );
PUT_ULONG_LE( high, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
md5_update( ctx, md5_padding, padn );
md5_update( ctx, msglen, 8 );
PUT_ULONG_LE( ctx->state[0], output, 0 );
PUT_ULONG_LE( ctx->state[1], output, 4 );
PUT_ULONG_LE( ctx->state[2], output, 8 );
PUT_ULONG_LE( ctx->state[3], output, 12 );
}
/*
* output = MD5( input buffer )
*/
void md5( unsigned char *input, int ilen, unsigned char output[16] )
{
md5_context ctx;
md5_starts( &ctx );
md5_update( &ctx, input, ilen );
md5_finish( &ctx, output );
}
#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD5 */

View file

@ -0,0 +1,335 @@
/*
* FIPS-180-1 compliant SHA-1 implementation
*
* Based on XySSL: Copyright (C) 2006-2008 Christophe Devine
*
* Copyright (C) 2009 Paul Bakker <polarssl_maintainer at polarssl dot org>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the names of PolarSSL or XySSL 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 COPYRIGHT HOLDERS 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 COPYRIGHT
* OWNER 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.
*/
/*
* The SHA-1 standard was published by NIST in 1993.
*
* http://www.itl.nist.gov/fipspubs/fip180-1.htm
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_SHA1
#include "netif/ppp/polarssl/sha1.h"
#include <string.h>
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_ULONG_BE
#define GET_ULONG_BE(n,b,i) \
{ \
(n) = ( (unsigned long) (b)[(i) ] << 24 ) \
| ( (unsigned long) (b)[(i) + 1] << 16 ) \
| ( (unsigned long) (b)[(i) + 2] << 8 ) \
| ( (unsigned long) (b)[(i) + 3] ); \
}
#endif
#ifndef PUT_ULONG_BE
#define PUT_ULONG_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
/*
* SHA-1 context setup
*/
void sha1_starts( sha1_context *ctx )
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xC3D2E1F0;
}
static void sha1_process( sha1_context *ctx, const unsigned char data[64] )
{
unsigned long temp, W[16], A, B, C, D, E;
GET_ULONG_BE( W[ 0], data, 0 );
GET_ULONG_BE( W[ 1], data, 4 );
GET_ULONG_BE( W[ 2], data, 8 );
GET_ULONG_BE( W[ 3], data, 12 );
GET_ULONG_BE( W[ 4], data, 16 );
GET_ULONG_BE( W[ 5], data, 20 );
GET_ULONG_BE( W[ 6], data, 24 );
GET_ULONG_BE( W[ 7], data, 28 );
GET_ULONG_BE( W[ 8], data, 32 );
GET_ULONG_BE( W[ 9], data, 36 );
GET_ULONG_BE( W[10], data, 40 );
GET_ULONG_BE( W[11], data, 44 );
GET_ULONG_BE( W[12], data, 48 );
GET_ULONG_BE( W[13], data, 52 );
GET_ULONG_BE( W[14], data, 56 );
GET_ULONG_BE( W[15], data, 60 );
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
#define R(t) \
( \
temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \
W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \
( W[t & 0x0F] = S(temp,1) ) \
)
#define P(a,b,c,d,e,x) \
{ \
e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];
#define F(x,y,z) (z ^ (x & (y ^ z)))
#define K 0x5A827999
P( A, B, C, D, E, W[0] );
P( E, A, B, C, D, W[1] );
P( D, E, A, B, C, W[2] );
P( C, D, E, A, B, W[3] );
P( B, C, D, E, A, W[4] );
P( A, B, C, D, E, W[5] );
P( E, A, B, C, D, W[6] );
P( D, E, A, B, C, W[7] );
P( C, D, E, A, B, W[8] );
P( B, C, D, E, A, W[9] );
P( A, B, C, D, E, W[10] );
P( E, A, B, C, D, W[11] );
P( D, E, A, B, C, W[12] );
P( C, D, E, A, B, W[13] );
P( B, C, D, E, A, W[14] );
P( A, B, C, D, E, W[15] );
P( E, A, B, C, D, R(16) );
P( D, E, A, B, C, R(17) );
P( C, D, E, A, B, R(18) );
P( B, C, D, E, A, R(19) );
#undef K
#undef F
#define F(x,y,z) (x ^ y ^ z)
#define K 0x6ED9EBA1
P( A, B, C, D, E, R(20) );
P( E, A, B, C, D, R(21) );
P( D, E, A, B, C, R(22) );
P( C, D, E, A, B, R(23) );
P( B, C, D, E, A, R(24) );
P( A, B, C, D, E, R(25) );
P( E, A, B, C, D, R(26) );
P( D, E, A, B, C, R(27) );
P( C, D, E, A, B, R(28) );
P( B, C, D, E, A, R(29) );
P( A, B, C, D, E, R(30) );
P( E, A, B, C, D, R(31) );
P( D, E, A, B, C, R(32) );
P( C, D, E, A, B, R(33) );
P( B, C, D, E, A, R(34) );
P( A, B, C, D, E, R(35) );
P( E, A, B, C, D, R(36) );
P( D, E, A, B, C, R(37) );
P( C, D, E, A, B, R(38) );
P( B, C, D, E, A, R(39) );
#undef K
#undef F
#define F(x,y,z) ((x & y) | (z & (x | y)))
#define K 0x8F1BBCDC
P( A, B, C, D, E, R(40) );
P( E, A, B, C, D, R(41) );
P( D, E, A, B, C, R(42) );
P( C, D, E, A, B, R(43) );
P( B, C, D, E, A, R(44) );
P( A, B, C, D, E, R(45) );
P( E, A, B, C, D, R(46) );
P( D, E, A, B, C, R(47) );
P( C, D, E, A, B, R(48) );
P( B, C, D, E, A, R(49) );
P( A, B, C, D, E, R(50) );
P( E, A, B, C, D, R(51) );
P( D, E, A, B, C, R(52) );
P( C, D, E, A, B, R(53) );
P( B, C, D, E, A, R(54) );
P( A, B, C, D, E, R(55) );
P( E, A, B, C, D, R(56) );
P( D, E, A, B, C, R(57) );
P( C, D, E, A, B, R(58) );
P( B, C, D, E, A, R(59) );
#undef K
#undef F
#define F(x,y,z) (x ^ y ^ z)
#define K 0xCA62C1D6
P( A, B, C, D, E, R(60) );
P( E, A, B, C, D, R(61) );
P( D, E, A, B, C, R(62) );
P( C, D, E, A, B, R(63) );
P( B, C, D, E, A, R(64) );
P( A, B, C, D, E, R(65) );
P( E, A, B, C, D, R(66) );
P( D, E, A, B, C, R(67) );
P( C, D, E, A, B, R(68) );
P( B, C, D, E, A, R(69) );
P( A, B, C, D, E, R(70) );
P( E, A, B, C, D, R(71) );
P( D, E, A, B, C, R(72) );
P( C, D, E, A, B, R(73) );
P( B, C, D, E, A, R(74) );
P( A, B, C, D, E, R(75) );
P( E, A, B, C, D, R(76) );
P( D, E, A, B, C, R(77) );
P( C, D, E, A, B, R(78) );
P( B, C, D, E, A, R(79) );
#undef K
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
ctx->state[4] += E;
}
/*
* SHA-1 process buffer
*/
void sha1_update( sha1_context *ctx, const unsigned char *input, int ilen )
{
int fill;
unsigned long left;
if( ilen <= 0 )
return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += ilen;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < (unsigned long) ilen )
ctx->total[1]++;
if( left && ilen >= fill )
{
MEMCPY( (void *) (ctx->buffer + left),
input, fill );
sha1_process( ctx, ctx->buffer );
input += fill;
ilen -= fill;
left = 0;
}
while( ilen >= 64 )
{
sha1_process( ctx, input );
input += 64;
ilen -= 64;
}
if( ilen > 0 )
{
MEMCPY( (void *) (ctx->buffer + left),
input, ilen );
}
}
static const unsigned char sha1_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* SHA-1 final digest
*/
void sha1_finish( sha1_context *ctx, unsigned char output[20] )
{
unsigned long last, padn;
unsigned long high, low;
unsigned char msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_ULONG_BE( high, msglen, 0 );
PUT_ULONG_BE( low, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
sha1_update( ctx, sha1_padding, padn );
sha1_update( ctx, msglen, 8 );
PUT_ULONG_BE( ctx->state[0], output, 0 );
PUT_ULONG_BE( ctx->state[1], output, 4 );
PUT_ULONG_BE( ctx->state[2], output, 8 );
PUT_ULONG_BE( ctx->state[3], output, 12 );
PUT_ULONG_BE( ctx->state[4], output, 16 );
}
/*
* output = SHA-1( input buffer )
*/
void sha1( unsigned char *input, int ilen, unsigned char output[20] )
{
sha1_context ctx;
sha1_starts( &ctx );
sha1_update( &ctx, input, ilen );
sha1_finish( &ctx, output );
}
#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_SHA1 */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,422 @@
/**
* @file
* Point To Point Protocol Sequential API module
*
*/
/*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include "netif/ppp/ppp_opts.h"
#if LWIP_PPP_API /* don't build if not configured for use in lwipopts.h */
#include "netif/ppp/pppapi.h"
#include "lwip/priv/tcpip_priv.h"
#include "netif/ppp/pppoe.h"
#include "netif/ppp/pppol2tp.h"
#include "netif/ppp/pppos.h"
#if LWIP_MPU_COMPATIBLE
LWIP_MEMPOOL_DECLARE(PPPAPI_MSG, MEMP_NUM_PPP_API_MSG, sizeof(struct pppapi_msg), "PPPAPI_MSG")
#endif
#define PPPAPI_VAR_REF(name) API_VAR_REF(name)
#define PPPAPI_VAR_DECLARE(name) API_VAR_DECLARE(struct pppapi_msg, name)
#define PPPAPI_VAR_ALLOC(name) API_VAR_ALLOC_POOL(struct pppapi_msg, PPPAPI_MSG, name, ERR_MEM)
#define PPPAPI_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC_POOL(struct pppapi_msg, PPPAPI_MSG, name, NULL)
#define PPPAPI_VAR_FREE(name) API_VAR_FREE_POOL(PPPAPI_MSG, name)
/**
* Call ppp_set_default() inside the tcpip_thread context.
*/
static err_t
pppapi_do_ppp_set_default(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct pppapi_msg */
struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m;
ppp_set_default(msg->msg.ppp);
return ERR_OK;
}
/**
* Call ppp_set_default() in a thread-safe way by running that function inside the
* tcpip_thread context.
*/
err_t
pppapi_set_default(ppp_pcb *pcb)
{
err_t err;
PPPAPI_VAR_DECLARE(msg);
PPPAPI_VAR_ALLOC(msg);
PPPAPI_VAR_REF(msg).msg.ppp = pcb;
err = tcpip_api_call(pppapi_do_ppp_set_default, &PPPAPI_VAR_REF(msg).call);
PPPAPI_VAR_FREE(msg);
return err;
}
#if PPP_NOTIFY_PHASE
/**
* Call ppp_set_notify_phase_callback() inside the tcpip_thread context.
*/
static err_t
pppapi_do_ppp_set_notify_phase_callback(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct pppapi_msg */
struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m;
ppp_set_notify_phase_callback(msg->msg.ppp, msg->msg.msg.setnotifyphasecb.notify_phase_cb);
return ERR_OK;
}
/**
* Call ppp_set_notify_phase_callback() in a thread-safe way by running that function inside the
* tcpip_thread context.
*/
err_t
pppapi_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb)
{
err_t err;
PPPAPI_VAR_DECLARE(msg);
PPPAPI_VAR_ALLOC(msg);
PPPAPI_VAR_REF(msg).msg.ppp = pcb;
PPPAPI_VAR_REF(msg).msg.msg.setnotifyphasecb.notify_phase_cb = notify_phase_cb;
err = tcpip_api_call(pppapi_do_ppp_set_notify_phase_callback, &PPPAPI_VAR_REF(msg).call);
PPPAPI_VAR_FREE(msg);
return err;
}
#endif /* PPP_NOTIFY_PHASE */
#if PPPOS_SUPPORT
/**
* Call pppos_create() inside the tcpip_thread context.
*/
static err_t
pppapi_do_pppos_create(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct pppapi_msg */
struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m;
msg->msg.ppp = pppos_create(msg->msg.msg.serialcreate.pppif, msg->msg.msg.serialcreate.output_cb,
msg->msg.msg.serialcreate.link_status_cb, msg->msg.msg.serialcreate.ctx_cb);
return ERR_OK;
}
/**
* Call pppos_create() in a thread-safe way by running that function inside the
* tcpip_thread context.
*/
ppp_pcb*
pppapi_pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb,
ppp_link_status_cb_fn link_status_cb, void *ctx_cb)
{
ppp_pcb* result;
PPPAPI_VAR_DECLARE(msg);
PPPAPI_VAR_ALLOC_RETURN_NULL(msg);
PPPAPI_VAR_REF(msg).msg.ppp = NULL;
PPPAPI_VAR_REF(msg).msg.msg.serialcreate.pppif = pppif;
PPPAPI_VAR_REF(msg).msg.msg.serialcreate.output_cb = output_cb;
PPPAPI_VAR_REF(msg).msg.msg.serialcreate.link_status_cb = link_status_cb;
PPPAPI_VAR_REF(msg).msg.msg.serialcreate.ctx_cb = ctx_cb;
tcpip_api_call(pppapi_do_pppos_create, &PPPAPI_VAR_REF(msg).call);
result = PPPAPI_VAR_REF(msg).msg.ppp;
PPPAPI_VAR_FREE(msg);
return result;
}
#endif /* PPPOS_SUPPORT */
#if PPPOE_SUPPORT
/**
* Call pppoe_create() inside the tcpip_thread context.
*/
static err_t
pppapi_do_pppoe_create(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct pppapi_msg */
struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m;
msg->msg.ppp = pppoe_create(msg->msg.msg.ethernetcreate.pppif, msg->msg.msg.ethernetcreate.ethif,
msg->msg.msg.ethernetcreate.service_name, msg->msg.msg.ethernetcreate.concentrator_name,
msg->msg.msg.ethernetcreate.link_status_cb, msg->msg.msg.ethernetcreate.ctx_cb);
return ERR_OK;
}
/**
* Call pppoe_create() in a thread-safe way by running that function inside the
* tcpip_thread context.
*/
ppp_pcb*
pppapi_pppoe_create(struct netif *pppif, struct netif *ethif, const char *service_name,
const char *concentrator_name, ppp_link_status_cb_fn link_status_cb,
void *ctx_cb)
{
ppp_pcb* result;
PPPAPI_VAR_DECLARE(msg);
PPPAPI_VAR_ALLOC_RETURN_NULL(msg);
PPPAPI_VAR_REF(msg).msg.ppp = NULL;
PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.pppif = pppif;
PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.ethif = ethif;
PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.service_name = service_name;
PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.concentrator_name = concentrator_name;
PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.link_status_cb = link_status_cb;
PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.ctx_cb = ctx_cb;
tcpip_api_call(pppapi_do_pppoe_create, &PPPAPI_VAR_REF(msg).call);
result = PPPAPI_VAR_REF(msg).msg.ppp;
PPPAPI_VAR_FREE(msg);
return result;
}
#endif /* PPPOE_SUPPORT */
#if PPPOL2TP_SUPPORT
/**
* Call pppol2tp_create() inside the tcpip_thread context.
*/
static err_t
pppapi_do_pppol2tp_create(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct pppapi_msg */
struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m;
msg->msg.ppp = pppol2tp_create(msg->msg.msg.l2tpcreate.pppif,
msg->msg.msg.l2tpcreate.netif, API_EXPR_REF(msg->msg.msg.l2tpcreate.ipaddr), msg->msg.msg.l2tpcreate.port,
#if PPPOL2TP_AUTH_SUPPORT
msg->msg.msg.l2tpcreate.secret,
msg->msg.msg.l2tpcreate.secret_len,
#else /* PPPOL2TP_AUTH_SUPPORT */
NULL,
#endif /* PPPOL2TP_AUTH_SUPPORT */
msg->msg.msg.l2tpcreate.link_status_cb, msg->msg.msg.l2tpcreate.ctx_cb);
return ERR_OK;
}
/**
* Call pppol2tp_create() in a thread-safe way by running that function inside the
* tcpip_thread context.
*/
ppp_pcb*
pppapi_pppol2tp_create(struct netif *pppif, struct netif *netif, ip_addr_t *ipaddr, u16_t port,
const u8_t *secret, u8_t secret_len,
ppp_link_status_cb_fn link_status_cb, void *ctx_cb)
{
ppp_pcb* result;
PPPAPI_VAR_DECLARE(msg);
PPPAPI_VAR_ALLOC_RETURN_NULL(msg);
PPPAPI_VAR_REF(msg).msg.ppp = NULL;
PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.pppif = pppif;
PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.netif = netif;
PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.ipaddr = PPPAPI_VAR_REF(ipaddr);
PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.port = port;
#if PPPOL2TP_AUTH_SUPPORT
PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.secret = secret;
PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.secret_len = secret_len;
#endif /* PPPOL2TP_AUTH_SUPPORT */
PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.link_status_cb = link_status_cb;
PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.ctx_cb = ctx_cb;
tcpip_api_call(pppapi_do_pppol2tp_create, &PPPAPI_VAR_REF(msg).call);
result = PPPAPI_VAR_REF(msg).msg.ppp;
PPPAPI_VAR_FREE(msg);
return result;
}
#endif /* PPPOL2TP_SUPPORT */
/**
* Call ppp_connect() inside the tcpip_thread context.
*/
static err_t
pppapi_do_ppp_connect(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct pppapi_msg */
struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m;
return ppp_connect(msg->msg.ppp, msg->msg.msg.connect.holdoff);
}
/**
* Call ppp_connect() in a thread-safe way by running that function inside the
* tcpip_thread context.
*/
err_t
pppapi_connect(ppp_pcb *pcb, u16_t holdoff)
{
err_t err;
PPPAPI_VAR_DECLARE(msg);
PPPAPI_VAR_ALLOC(msg);
PPPAPI_VAR_REF(msg).msg.ppp = pcb;
PPPAPI_VAR_REF(msg).msg.msg.connect.holdoff = holdoff;
err = tcpip_api_call(pppapi_do_ppp_connect, &PPPAPI_VAR_REF(msg).call);
PPPAPI_VAR_FREE(msg);
return err;
}
#if PPP_SERVER
/**
* Call ppp_listen() inside the tcpip_thread context.
*/
static err_t
pppapi_do_ppp_listen(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct pppapi_msg */
struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m;
return ppp_listen(msg->msg.ppp);
}
/**
* Call ppp_listen() in a thread-safe way by running that function inside the
* tcpip_thread context.
*/
err_t
pppapi_listen(ppp_pcb *pcb)
{
err_t err;
PPPAPI_VAR_DECLARE(msg);
PPPAPI_VAR_ALLOC(msg);
PPPAPI_VAR_REF(msg).msg.ppp = pcb;
err = tcpip_api_call(pppapi_do_ppp_listen, &PPPAPI_VAR_REF(msg).call);
PPPAPI_VAR_FREE(msg);
return err;
}
#endif /* PPP_SERVER */
/**
* Call ppp_close() inside the tcpip_thread context.
*/
static err_t
pppapi_do_ppp_close(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct pppapi_msg */
struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m;
return ppp_close(msg->msg.ppp, msg->msg.msg.close.nocarrier);
}
/**
* Call ppp_close() in a thread-safe way by running that function inside the
* tcpip_thread context.
*/
err_t
pppapi_close(ppp_pcb *pcb, u8_t nocarrier)
{
err_t err;
PPPAPI_VAR_DECLARE(msg);
PPPAPI_VAR_ALLOC(msg);
PPPAPI_VAR_REF(msg).msg.ppp = pcb;
PPPAPI_VAR_REF(msg).msg.msg.close.nocarrier = nocarrier;
err = tcpip_api_call(pppapi_do_ppp_close, &PPPAPI_VAR_REF(msg).call);
PPPAPI_VAR_FREE(msg);
return err;
}
/**
* Call ppp_free() inside the tcpip_thread context.
*/
static err_t
pppapi_do_ppp_free(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct pppapi_msg */
struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m;
return ppp_free(msg->msg.ppp);
}
/**
* Call ppp_free() in a thread-safe way by running that function inside the
* tcpip_thread context.
*/
err_t
pppapi_free(ppp_pcb *pcb)
{
err_t err;
PPPAPI_VAR_DECLARE(msg);
PPPAPI_VAR_ALLOC(msg);
PPPAPI_VAR_REF(msg).msg.ppp = pcb;
err = tcpip_api_call(pppapi_do_ppp_free, &PPPAPI_VAR_REF(msg).call);
PPPAPI_VAR_FREE(msg);
return err;
}
/**
* Call ppp_ioctl() inside the tcpip_thread context.
*/
static err_t
pppapi_do_ppp_ioctl(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct pppapi_msg */
struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m;
return ppp_ioctl(msg->msg.ppp, msg->msg.msg.ioctl.cmd, msg->msg.msg.ioctl.arg);
}
/**
* Call ppp_ioctl() in a thread-safe way by running that function inside the
* tcpip_thread context.
*/
err_t
pppapi_ioctl(ppp_pcb *pcb, u8_t cmd, void *arg)
{
err_t err;
PPPAPI_VAR_DECLARE(msg);
PPPAPI_VAR_ALLOC(msg);
PPPAPI_VAR_REF(msg).msg.ppp = pcb;
PPPAPI_VAR_REF(msg).msg.msg.ioctl.cmd = cmd;
PPPAPI_VAR_REF(msg).msg.msg.ioctl.arg = arg;
err = tcpip_api_call(pppapi_do_ppp_ioctl, &PPPAPI_VAR_REF(msg).call);
PPPAPI_VAR_FREE(msg);
return err;
}
#endif /* LWIP_PPP_API */

View file

@ -0,0 +1,66 @@
/*
* pppcrypt.c - PPP/DES linkage for MS-CHAP and EAP SRP-SHA1
*
* Extracted from chap_ms.c by James Carlson.
*
* Copyright (c) 1995 Eric Rosenquist. 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(s) of the authors of this software must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not necessary */
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/pppcrypt.h"
static u_char pppcrypt_get_7bits(u_char *input, int startBit) {
unsigned int word;
word = (unsigned)input[startBit / 8] << 8;
word |= (unsigned)input[startBit / 8 + 1];
word >>= 15 - (startBit % 8 + 7);
return word & 0xFE;
}
/* IN 56 bit DES key missing parity bits
* OUT 64 bit DES key with parity bits added
*/
void pppcrypt_56_to_64_bit_key(u_char *key, u_char * des_key) {
des_key[0] = pppcrypt_get_7bits(key, 0);
des_key[1] = pppcrypt_get_7bits(key, 7);
des_key[2] = pppcrypt_get_7bits(key, 14);
des_key[3] = pppcrypt_get_7bits(key, 21);
des_key[4] = pppcrypt_get_7bits(key, 28);
des_key[5] = pppcrypt_get_7bits(key, 35);
des_key[6] = pppcrypt_get_7bits(key, 42);
des_key[7] = pppcrypt_get_7bits(key, 49);
}
#endif /* PPP_SUPPORT && MSCHAP_SUPPORT */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,875 @@
/**
* @file
* Network Point to Point Protocol over Serial file.
*
*/
/*
* 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 "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && PPPOS_SUPPORT /* don't build if not configured for use in lwipopts.h */
#include <string.h>
#include <stddef.h>
#include "lwip/err.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "lwip/memp.h"
#include "lwip/netif.h"
#include "lwip/snmp.h"
#include "lwip/priv/tcpip_priv.h"
#include "lwip/api.h"
#include "lwip/ip4.h" /* for ip4_input() */
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/pppos.h"
#include "netif/ppp/vj.h"
/* Memory pool */
LWIP_MEMPOOL_DECLARE(PPPOS_PCB, MEMP_NUM_PPPOS_INTERFACES, sizeof(pppos_pcb), "PPPOS_PCB")
/* callbacks called from PPP core */
static err_t pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p);
static err_t pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol);
static err_t pppos_connect(ppp_pcb *ppp, void *ctx);
#if PPP_SERVER
static err_t pppos_listen(ppp_pcb *ppp, void *ctx);
#endif /* PPP_SERVER */
static void pppos_disconnect(ppp_pcb *ppp, void *ctx);
static err_t pppos_destroy(ppp_pcb *ppp, void *ctx);
static void pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp);
static void pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp);
/* Prototypes for procedures local to this file. */
#if PPP_INPROC_IRQ_SAFE
static void pppos_input_callback(void *arg);
#endif /* PPP_INPROC_IRQ_SAFE */
static void pppos_input_free_current_packet(pppos_pcb *pppos);
static void pppos_input_drop(pppos_pcb *pppos);
static err_t pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs);
static err_t pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs);
/* Callbacks structure for PPP core */
static const struct link_callbacks pppos_callbacks = {
pppos_connect,
#if PPP_SERVER
pppos_listen,
#endif /* PPP_SERVER */
pppos_disconnect,
pppos_destroy,
pppos_write,
pppos_netif_output,
pppos_send_config,
pppos_recv_config
};
/* PPP's Asynchronous-Control-Character-Map. The mask array is used
* to select the specific bit for a character. */
#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & 1 << (c & 0x07))
#if PPP_FCS_TABLE
/*
* FCS lookup table as calculated by genfcstab.
*/
static const u16_t fcstab[256] = {
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
#else /* PPP_FCS_TABLE */
/* The HDLC polynomial: X**0 + X**5 + X**12 + X**16 (0x8408) */
#define PPP_FCS_POLYNOMIAL 0x8408
static u16_t
ppp_get_fcs(u8_t byte)
{
unsigned int octet;
int bit;
octet = byte;
for (bit = 8; bit-- > 0; ) {
octet = (octet & 0x01) ? ((octet >> 1) ^ PPP_FCS_POLYNOMIAL) : (octet >> 1);
}
return octet & 0xffff;
}
#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ ppp_get_fcs(((fcs) ^ (c)) & 0xff))
#endif /* PPP_FCS_TABLE */
/*
* Values for FCS calculations.
*/
#define PPP_INITFCS 0xffff /* Initial FCS value */
#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
#if PPP_INPROC_IRQ_SAFE
#define PPPOS_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev)
#define PPPOS_PROTECT(lev) SYS_ARCH_PROTECT(lev)
#define PPPOS_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev)
#else
#define PPPOS_DECL_PROTECT(lev)
#define PPPOS_PROTECT(lev)
#define PPPOS_UNPROTECT(lev)
#endif /* PPP_INPROC_IRQ_SAFE */
/*
* Create a new PPP connection using the given serial I/O device.
*
* Return 0 on success, an error code on failure.
*/
ppp_pcb *pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb,
ppp_link_status_cb_fn link_status_cb, void *ctx_cb)
{
pppos_pcb *pppos;
ppp_pcb *ppp;
pppos = (pppos_pcb *)LWIP_MEMPOOL_ALLOC(PPPOS_PCB);
if (pppos == NULL) {
return NULL;
}
ppp = ppp_new(pppif, &pppos_callbacks, pppos, link_status_cb, ctx_cb);
if (ppp == NULL) {
LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos);
return NULL;
}
memset(pppos, 0, sizeof(pppos_pcb));
pppos->ppp = ppp;
pppos->output_cb = output_cb;
return ppp;
}
/* Called by PPP core */
static err_t
pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p)
{
pppos_pcb *pppos = (pppos_pcb *)ctx;
u8_t *s;
struct pbuf *nb;
u16_t n;
u16_t fcs_out;
err_t err;
LWIP_UNUSED_ARG(ppp);
/* Grab an output buffer. */
nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
if (nb == NULL) {
PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: alloc fail\n", ppp->netif->num));
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
pbuf_free(p);
return ERR_MEM;
}
/* If the link has been idle, we'll send a fresh flag character to
* flush any noise. */
err = ERR_OK;
if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) {
err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL);
}
/* Load output buffer. */
fcs_out = PPP_INITFCS;
s = (u8_t*)p->payload;
n = p->len;
while (n-- > 0) {
err = pppos_output_append(pppos, err, nb, *s++, 1, &fcs_out);
}
err = pppos_output_last(pppos, err, nb, &fcs_out);
if (err == ERR_OK) {
PPPDEBUG(LOG_INFO, ("pppos_write[%d]: len=%d\n", ppp->netif->num, p->len));
} else {
PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: output failed len=%d\n", ppp->netif->num, p->len));
}
pbuf_free(p);
return err;
}
/* Called by PPP core */
static err_t
pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol)
{
pppos_pcb *pppos = (pppos_pcb *)ctx;
struct pbuf *nb, *p;
u16_t fcs_out;
err_t err;
LWIP_UNUSED_ARG(ppp);
/* Grab an output buffer. */
nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
if (nb == NULL) {
PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: alloc fail\n", ppp->netif->num));
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
return ERR_MEM;
}
/* If the link has been idle, we'll send a fresh flag character to
* flush any noise. */
err = ERR_OK;
if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) {
err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL);
}
fcs_out = PPP_INITFCS;
if (!pppos->accomp) {
err = pppos_output_append(pppos, err, nb, PPP_ALLSTATIONS, 1, &fcs_out);
err = pppos_output_append(pppos, err, nb, PPP_UI, 1, &fcs_out);
}
if (!pppos->pcomp || protocol > 0xFF) {
err = pppos_output_append(pppos, err, nb, (protocol >> 8) & 0xFF, 1, &fcs_out);
}
err = pppos_output_append(pppos, err, nb, protocol & 0xFF, 1, &fcs_out);
/* Load packet. */
for(p = pb; p; p = p->next) {
u16_t n = p->len;
u8_t *s = (u8_t*)p->payload;
while (n-- > 0) {
err = pppos_output_append(pppos, err, nb, *s++, 1, &fcs_out);
}
}
err = pppos_output_last(pppos, err, nb, &fcs_out);
if (err == ERR_OK) {
PPPDEBUG(LOG_INFO, ("pppos_netif_output[%d]: proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len));
} else {
PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: output failed proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len));
}
return err;
}
static err_t
pppos_connect(ppp_pcb *ppp, void *ctx)
{
pppos_pcb *pppos = (pppos_pcb *)ctx;
PPPOS_DECL_PROTECT(lev);
#if PPP_INPROC_IRQ_SAFE
/* input pbuf left over from last session? */
pppos_input_free_current_packet(pppos);
#endif /* PPP_INPROC_IRQ_SAFE */
/* reset PPPoS control block to its initial state */
memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit));
/*
* Default the in and out accm so that escape and flag characters
* are always escaped.
*/
pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
pppos->out_accm[15] = 0x60;
PPPOS_PROTECT(lev);
pppos->open = 1;
PPPOS_UNPROTECT(lev);
/*
* Start the connection and handle incoming events (packet or timeout).
*/
PPPDEBUG(LOG_INFO, ("pppos_connect: unit %d: connecting\n", ppp->netif->num));
ppp_start(ppp); /* notify upper layers */
return ERR_OK;
}
#if PPP_SERVER
static err_t
pppos_listen(ppp_pcb *ppp, void *ctx)
{
pppos_pcb *pppos = (pppos_pcb *)ctx;
PPPOS_DECL_PROTECT(lev);
#if PPP_INPROC_IRQ_SAFE
/* input pbuf left over from last session? */
pppos_input_free_current_packet(pppos);
#endif /* PPP_INPROC_IRQ_SAFE */
/* reset PPPoS control block to its initial state */
memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit));
/*
* Default the in and out accm so that escape and flag characters
* are always escaped.
*/
pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
pppos->out_accm[15] = 0x60;
PPPOS_PROTECT(lev);
pppos->open = 1;
PPPOS_UNPROTECT(lev);
/*
* Wait for something to happen.
*/
PPPDEBUG(LOG_INFO, ("pppos_listen: unit %d: listening\n", ppp->netif->num));
ppp_start(ppp); /* notify upper layers */
return ERR_OK;
}
#endif /* PPP_SERVER */
static void
pppos_disconnect(ppp_pcb *ppp, void *ctx)
{
pppos_pcb *pppos = (pppos_pcb *)ctx;
PPPOS_DECL_PROTECT(lev);
PPPOS_PROTECT(lev);
pppos->open = 0;
PPPOS_UNPROTECT(lev);
/* If PPP_INPROC_IRQ_SAFE is used we cannot call
* pppos_input_free_current_packet() here because
* rx IRQ might still call pppos_input().
*/
#if !PPP_INPROC_IRQ_SAFE
/* input pbuf left ? */
pppos_input_free_current_packet(pppos);
#endif /* !PPP_INPROC_IRQ_SAFE */
ppp_link_end(ppp); /* notify upper layers */
}
static err_t
pppos_destroy(ppp_pcb *ppp, void *ctx)
{
pppos_pcb *pppos = (pppos_pcb *)ctx;
LWIP_UNUSED_ARG(ppp);
#if PPP_INPROC_IRQ_SAFE
/* input pbuf left ? */
pppos_input_free_current_packet(pppos);
#endif /* PPP_INPROC_IRQ_SAFE */
LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos);
return ERR_OK;
}
#if !NO_SYS && !PPP_INPROC_IRQ_SAFE
/** Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread.
*
* @param ppp PPP descriptor index, returned by pppos_create()
* @param s received data
* @param l length of received data
*/
err_t
pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l)
{
struct pbuf *p;
err_t err;
p = pbuf_alloc(PBUF_RAW, l, PBUF_POOL);
if (!p) {
return ERR_MEM;
}
pbuf_take(p, s, l);
err = tcpip_inpkt(p, ppp_netif(ppp), pppos_input_sys);
if (err != ERR_OK) {
pbuf_free(p);
}
return err;
}
/* called from TCPIP thread */
err_t pppos_input_sys(struct pbuf *p, struct netif *inp) {
ppp_pcb *ppp = (ppp_pcb*)inp->state;
struct pbuf *n;
for (n = p; n; n = n->next) {
pppos_input(ppp, (u8_t*)n->payload, n->len);
}
pbuf_free(p);
return ERR_OK;
}
#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */
/** PPPoS input helper struct, must be packed since it is stored
* to pbuf->payload, which might be unaligned. */
#if PPP_INPROC_IRQ_SAFE
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct pppos_input_header {
PACK_STRUCT_FIELD(ppp_pcb *ppp);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#endif /* PPP_INPROC_IRQ_SAFE */
/** Pass received raw characters to PPPoS to be decoded.
*
* @param ppp PPP descriptor index, returned by pppos_create()
* @param s received data
* @param l length of received data
*/
void
pppos_input(ppp_pcb *ppp, u8_t *s, int l)
{
pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb;
struct pbuf *next_pbuf;
u8_t cur_char;
u8_t escaped;
PPPOS_DECL_PROTECT(lev);
PPPOS_PROTECT(lev);
if (!pppos->open) {
PPPOS_UNPROTECT(lev);
return;
}
PPPOS_UNPROTECT(lev);
PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l));
while (l-- > 0) {
cur_char = *s++;
PPPOS_PROTECT(lev);
escaped = ESCAPE_P(pppos->in_accm, cur_char);
PPPOS_UNPROTECT(lev);
/* Handle special characters. */
if (escaped) {
/* Check for escape sequences. */
/* XXX Note that this does not handle an escaped 0x5d character which
* would appear as an escape character. Since this is an ASCII ']'
* and there is no reason that I know of to escape it, I won't complicate
* the code to handle this case. GLL */
if (cur_char == PPP_ESCAPE) {
pppos->in_escaped = 1;
/* Check for the flag character. */
} else if (cur_char == PPP_FLAG) {
/* If this is just an extra flag character, ignore it. */
if (pppos->in_state <= PDADDRESS) {
/* ignore it */;
/* If we haven't received the packet header, drop what has come in. */
} else if (pppos->in_state < PDDATA) {
PPPDEBUG(LOG_WARNING,
("pppos_input[%d]: Dropping incomplete packet %d\n",
ppp->netif->num, pppos->in_state));
LINK_STATS_INC(link.lenerr);
pppos_input_drop(pppos);
/* If the fcs is invalid, drop the packet. */
} else if (pppos->in_fcs != PPP_GOODFCS) {
PPPDEBUG(LOG_INFO,
("pppos_input[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n",
ppp->netif->num, pppos->in_fcs, pppos->in_protocol));
/* Note: If you get lots of these, check for UART frame errors or try different baud rate */
LINK_STATS_INC(link.chkerr);
pppos_input_drop(pppos);
/* Otherwise it's a good packet so pass it on. */
} else {
struct pbuf *inp;
/* Trim off the checksum. */
if(pppos->in_tail->len > 2) {
pppos->in_tail->len -= 2;
pppos->in_tail->tot_len = pppos->in_tail->len;
if (pppos->in_tail != pppos->in_head) {
pbuf_cat(pppos->in_head, pppos->in_tail);
}
} else {
pppos->in_tail->tot_len = pppos->in_tail->len;
if (pppos->in_tail != pppos->in_head) {
pbuf_cat(pppos->in_head, pppos->in_tail);
}
pbuf_realloc(pppos->in_head, pppos->in_head->tot_len - 2);
}
/* Dispatch the packet thereby consuming it. */
inp = pppos->in_head;
/* Packet consumed, release our references. */
pppos->in_head = NULL;
pppos->in_tail = NULL;
#if IP_FORWARD || LWIP_IPV6_FORWARD
/* hide the room for Ethernet forwarding header */
pbuf_header(inp, -(s16_t)(PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN));
#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
#if PPP_INPROC_IRQ_SAFE
if(tcpip_callback_with_block(pppos_input_callback, inp, 0) != ERR_OK) {
PPPDEBUG(LOG_ERR, ("pppos_input[%d]: tcpip_callback() failed, dropping packet\n", ppp->netif->num));
pbuf_free(inp);
LINK_STATS_INC(link.drop);
MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);
}
#else /* PPP_INPROC_IRQ_SAFE */
ppp_input(ppp, inp);
#endif /* PPP_INPROC_IRQ_SAFE */
}
/* Prepare for a new packet. */
pppos->in_fcs = PPP_INITFCS;
pppos->in_state = PDADDRESS;
pppos->in_escaped = 0;
/* Other characters are usually control characters that may have
* been inserted by the physical layer so here we just drop them. */
} else {
PPPDEBUG(LOG_WARNING,
("pppos_input[%d]: Dropping ACCM char <%d>\n", ppp->netif->num, cur_char));
}
/* Process other characters. */
} else {
/* Unencode escaped characters. */
if (pppos->in_escaped) {
pppos->in_escaped = 0;
cur_char ^= PPP_TRANS;
}
/* Process character relative to current state. */
switch(pppos->in_state) {
case PDIDLE: /* Idle state - waiting. */
/* Drop the character if it's not 0xff
* we would have processed a flag character above. */
if (cur_char != PPP_ALLSTATIONS) {
break;
}
/* no break */
/* Fall through */
case PDSTART: /* Process start flag. */
/* Prepare for a new packet. */
pppos->in_fcs = PPP_INITFCS;
/* no break */
/* Fall through */
case PDADDRESS: /* Process address field. */
if (cur_char == PPP_ALLSTATIONS) {
pppos->in_state = PDCONTROL;
break;
}
/* no break */
/* Else assume compressed address and control fields so
* fall through to get the protocol... */
case PDCONTROL: /* Process control field. */
/* If we don't get a valid control code, restart. */
if (cur_char == PPP_UI) {
pppos->in_state = PDPROTOCOL1;
break;
}
/* no break */
#if 0
else {
PPPDEBUG(LOG_WARNING,
("pppos_input[%d]: Invalid control <%d>\n", ppp->netif->num, cur_char));
pppos->in_state = PDSTART;
}
#endif
case PDPROTOCOL1: /* Process protocol field 1. */
/* If the lower bit is set, this is the end of the protocol
* field. */
if (cur_char & 1) {
pppos->in_protocol = cur_char;
pppos->in_state = PDDATA;
} else {
pppos->in_protocol = (u16_t)cur_char << 8;
pppos->in_state = PDPROTOCOL2;
}
break;
case PDPROTOCOL2: /* Process protocol field 2. */
pppos->in_protocol |= cur_char;
pppos->in_state = PDDATA;
break;
case PDDATA: /* Process data byte. */
/* Make space to receive processed data. */
if (pppos->in_tail == NULL || pppos->in_tail->len == PBUF_POOL_BUFSIZE) {
u16_t pbuf_alloc_len;
if (pppos->in_tail != NULL) {
pppos->in_tail->tot_len = pppos->in_tail->len;
if (pppos->in_tail != pppos->in_head) {
pbuf_cat(pppos->in_head, pppos->in_tail);
/* give up the in_tail reference now */
pppos->in_tail = NULL;
}
}
/* If we haven't started a packet, we need a packet header. */
pbuf_alloc_len = 0;
#if IP_FORWARD || LWIP_IPV6_FORWARD
/* If IP forwarding is enabled we are reserving PBUF_LINK_ENCAPSULATION_HLEN
* + PBUF_LINK_HLEN bytes so the packet is being allocated with enough header
* space to be forwarded (to Ethernet for example).
*/
if (pppos->in_head == NULL) {
pbuf_alloc_len = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN;
}
#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
next_pbuf = pbuf_alloc(PBUF_RAW, pbuf_alloc_len, PBUF_POOL);
if (next_pbuf == NULL) {
/* No free buffers. Drop the input packet and let the
* higher layers deal with it. Continue processing
* the received pbuf chain in case a new packet starts. */
PPPDEBUG(LOG_ERR, ("pppos_input[%d]: NO FREE PBUFS!\n", ppp->netif->num));
LINK_STATS_INC(link.memerr);
pppos_input_drop(pppos);
pppos->in_state = PDSTART; /* Wait for flag sequence. */
break;
}
if (pppos->in_head == NULL) {
u8_t *payload = ((u8_t*)next_pbuf->payload) + pbuf_alloc_len;
#if PPP_INPROC_IRQ_SAFE
((struct pppos_input_header*)payload)->ppp = ppp;
payload += sizeof(struct pppos_input_header);
next_pbuf->len += sizeof(struct pppos_input_header);
#endif /* PPP_INPROC_IRQ_SAFE */
next_pbuf->len += sizeof(pppos->in_protocol);
*(payload++) = pppos->in_protocol >> 8;
*(payload) = pppos->in_protocol & 0xFF;
pppos->in_head = next_pbuf;
}
pppos->in_tail = next_pbuf;
}
/* Load character into buffer. */
((u8_t*)pppos->in_tail->payload)[pppos->in_tail->len++] = cur_char;
break;
default:
break;
}
/* update the frame check sequence number. */
pppos->in_fcs = PPP_FCS(pppos->in_fcs, cur_char);
}
} /* while (l-- > 0), all bytes processed */
}
#if PPP_INPROC_IRQ_SAFE
/* PPPoS input callback using one input pointer
*/
static void pppos_input_callback(void *arg) {
struct pbuf *pb = (struct pbuf*)arg;
ppp_pcb *ppp;
ppp = ((struct pppos_input_header*)pb->payload)->ppp;
if(pbuf_header(pb, -(s16_t)sizeof(struct pppos_input_header))) {
LWIP_ASSERT("pbuf_header failed\n", 0);
goto drop;
}
/* Dispatch the packet thereby consuming it. */
ppp_input(ppp, pb);
return;
drop:
LINK_STATS_INC(link.drop);
MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);
pbuf_free(pb);
}
#endif /* PPP_INPROC_IRQ_SAFE */
static void
pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp)
{
int i;
pppos_pcb *pppos = (pppos_pcb *)ctx;
LWIP_UNUSED_ARG(ppp);
pppos->pcomp = pcomp;
pppos->accomp = accomp;
/* Load the ACCM bits for the 32 control codes. */
for (i = 0; i < 32/8; i++) {
pppos->out_accm[i] = (u8_t)((accm >> (8 * i)) & 0xFF);
}
PPPDEBUG(LOG_INFO, ("pppos_send_config[%d]: out_accm=%X %X %X %X\n",
pppos->ppp->netif->num,
pppos->out_accm[0], pppos->out_accm[1], pppos->out_accm[2], pppos->out_accm[3]));
}
static void
pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp)
{
int i;
pppos_pcb *pppos = (pppos_pcb *)ctx;
PPPOS_DECL_PROTECT(lev);
LWIP_UNUSED_ARG(ppp);
LWIP_UNUSED_ARG(pcomp);
LWIP_UNUSED_ARG(accomp);
/* Load the ACCM bits for the 32 control codes. */
PPPOS_PROTECT(lev);
for (i = 0; i < 32 / 8; i++) {
pppos->in_accm[i] = (u8_t)(accm >> (i * 8));
}
PPPOS_UNPROTECT(lev);
PPPDEBUG(LOG_INFO, ("pppos_recv_config[%d]: in_accm=%X %X %X %X\n",
pppos->ppp->netif->num,
pppos->in_accm[0], pppos->in_accm[1], pppos->in_accm[2], pppos->in_accm[3]));
}
/*
* Drop the input packet.
*/
static void
pppos_input_free_current_packet(pppos_pcb *pppos)
{
if (pppos->in_head != NULL) {
if (pppos->in_tail && (pppos->in_tail != pppos->in_head)) {
pbuf_free(pppos->in_tail);
}
pbuf_free(pppos->in_head);
pppos->in_head = NULL;
}
pppos->in_tail = NULL;
}
/*
* Drop the input packet and increase error counters.
*/
static void
pppos_input_drop(pppos_pcb *pppos)
{
if (pppos->in_head != NULL) {
#if 0
PPPDEBUG(LOG_INFO, ("pppos_input_drop: %d:%.*H\n", pppos->in_head->len, min(60, pppos->in_head->len * 2), pppos->in_head->payload));
#endif
PPPDEBUG(LOG_INFO, ("pppos_input_drop: pbuf len=%d, addr %p\n", pppos->in_head->len, (void*)pppos->in_head));
}
pppos_input_free_current_packet(pppos);
#if VJ_SUPPORT
vj_uncompress_err(&pppos->ppp->vj_comp);
#endif /* VJ_SUPPORT */
LINK_STATS_INC(link.drop);
MIB2_STATS_NETIF_INC(pppos->ppp->netif, ifindiscards);
}
/*
* pppos_output_append - append given character to end of given pbuf.
* If out_accm is not 0 and the character needs to be escaped, do so.
* If pbuf is full, send the pbuf and reuse it.
* Return the current pbuf.
*/
static err_t
pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs)
{
if (err != ERR_OK) {
return err;
}
/* Make sure there is room for the character and an escape code.
* Sure we don't quite fill the buffer if the character doesn't
* get escaped but is one character worth complicating this? */
if ((PBUF_POOL_BUFSIZE - nb->len) < 2) {
u32_t l = pppos->output_cb(pppos->ppp, (u8_t*)nb->payload, nb->len, pppos->ppp->ctx_cb);
if (l != nb->len) {
return ERR_IF;
}
nb->len = 0;
}
/* Update FCS before checking for special characters. */
if (fcs) {
*fcs = PPP_FCS(*fcs, c);
}
/* Copy to output buffer escaping special characters. */
if (accm && ESCAPE_P(pppos->out_accm, c)) {
*((u8_t*)nb->payload + nb->len++) = PPP_ESCAPE;
*((u8_t*)nb->payload + nb->len++) = c ^ PPP_TRANS;
} else {
*((u8_t*)nb->payload + nb->len++) = c;
}
return ERR_OK;
}
static err_t
pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs)
{
ppp_pcb *ppp = pppos->ppp;
/* Add FCS and trailing flag. */
err = pppos_output_append(pppos, err, nb, ~(*fcs) & 0xFF, 1, NULL);
err = pppos_output_append(pppos, err, nb, (~(*fcs) >> 8) & 0xFF, 1, NULL);
err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL);
if (err != ERR_OK) {
goto failed;
}
/* Send remaining buffer if not empty */
if (nb->len > 0) {
u32_t l = pppos->output_cb(ppp, (u8_t*)nb->payload, nb->len, ppp->ctx_cb);
if (l != nb->len) {
err = ERR_IF;
goto failed;
}
}
pppos->last_xmit = sys_now();
MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, nb->tot_len);
MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts);
LINK_STATS_INC(link.xmit);
pbuf_free(nb);
return ERR_OK;
failed:
pppos->last_xmit = 0; /* prepend PPP_FLAG to next packet */
LINK_STATS_INC(link.err);
LINK_STATS_INC(link.drop);
MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
pbuf_free(nb);
return err;
}
#endif /* PPP_SUPPORT && PPPOS_SUPPORT */

View file

@ -0,0 +1,677 @@
/*
* upap.c - User/Password Authentication Protocol.
*
* Copyright (c) 1984-2000 Carnegie Mellon University. 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 "Carnegie Mellon University" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For permission or any legal
* details, please contact
* Office of Technology Transfer
* Carnegie Mellon University
* 5000 Forbes Avenue
* Pittsburgh, PA 15213-3890
* (412) 268-4387, fax: (412) 268-7395
* tech-transfer@andrew.cmu.edu
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Computing Services
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
/*
* @todo:
*/
#if 0 /* UNUSED */
#include <stdio.h>
#include <string.h>
#endif /* UNUSED */
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/upap.h"
#if PPP_OPTIONS
/*
* Command-line options.
*/
static option_t pap_option_list[] = {
{ "hide-password", o_bool, &hide_password,
"Don't output passwords to log", OPT_PRIO | 1 },
{ "show-password", o_bool, &hide_password,
"Show password string in debug log messages", OPT_PRIOSUB | 0 },
{ "pap-restart", o_int, &upap[0].us_timeouttime,
"Set retransmit timeout for PAP", OPT_PRIO },
{ "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
"Set max number of transmissions for auth-reqs", OPT_PRIO },
{ "pap-timeout", o_int, &upap[0].us_reqtimeout,
"Set time limit for peer PAP authentication", OPT_PRIO },
{ NULL }
};
#endif /* PPP_OPTIONS */
/*
* Protocol entry points.
*/
static void upap_init(ppp_pcb *pcb);
static void upap_lowerup(ppp_pcb *pcb);
static void upap_lowerdown(ppp_pcb *pcb);
static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l);
static void upap_protrej(ppp_pcb *pcb);
#if PRINTPKT_SUPPORT
static int upap_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg);
#endif /* PRINTPKT_SUPPORT */
const struct protent pap_protent = {
PPP_PAP,
upap_init,
upap_input,
upap_protrej,
upap_lowerup,
upap_lowerdown,
NULL,
NULL,
#if PRINTPKT_SUPPORT
upap_printpkt,
#endif /* PRINTPKT_SUPPORT */
#if PPP_DATAINPUT
NULL,
#endif /* PPP_DATAINPUT */
#if PRINTPKT_SUPPORT
"PAP",
NULL,
#endif /* PRINTPKT_SUPPORT */
#if PPP_OPTIONS
pap_option_list,
NULL,
#endif /* PPP_OPTIONS */
#if DEMAND_SUPPORT
NULL,
NULL
#endif /* DEMAND_SUPPORT */
};
static void upap_timeout(void *arg);
#if PPP_SERVER
static void upap_reqtimeout(void *arg);
static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len);
#endif /* PPP_SERVER */
static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len);
static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len);
static void upap_sauthreq(ppp_pcb *pcb);
#if PPP_SERVER
static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, int msglen);
#endif /* PPP_SERVER */
/*
* upap_init - Initialize a UPAP unit.
*/
static void upap_init(ppp_pcb *pcb) {
pcb->upap.us_user = NULL;
pcb->upap.us_userlen = 0;
pcb->upap.us_passwd = NULL;
pcb->upap.us_passwdlen = 0;
pcb->upap.us_clientstate = UPAPCS_INITIAL;
#if PPP_SERVER
pcb->upap.us_serverstate = UPAPSS_INITIAL;
#endif /* PPP_SERVER */
pcb->upap.us_id = 0;
}
/*
* upap_authwithpeer - Authenticate us with our peer (start client).
*
* Set new state and send authenticate's.
*/
void upap_authwithpeer(ppp_pcb *pcb, const char *user, const char *password) {
if(!user || !password)
return;
/* Save the username and password we're given */
pcb->upap.us_user = user;
pcb->upap.us_userlen = LWIP_MIN(strlen(user), 0xff);
pcb->upap.us_passwd = password;
pcb->upap.us_passwdlen = LWIP_MIN(strlen(password), 0xff);
pcb->upap.us_transmits = 0;
/* Lower layer up yet? */
if (pcb->upap.us_clientstate == UPAPCS_INITIAL ||
pcb->upap.us_clientstate == UPAPCS_PENDING) {
pcb->upap.us_clientstate = UPAPCS_PENDING;
return;
}
upap_sauthreq(pcb); /* Start protocol */
}
#if PPP_SERVER
/*
* upap_authpeer - Authenticate our peer (start server).
*
* Set new state.
*/
void upap_authpeer(ppp_pcb *pcb) {
/* Lower layer up yet? */
if (pcb->upap.us_serverstate == UPAPSS_INITIAL ||
pcb->upap.us_serverstate == UPAPSS_PENDING) {
pcb->upap.us_serverstate = UPAPSS_PENDING;
return;
}
pcb->upap.us_serverstate = UPAPSS_LISTEN;
if (pcb->settings.pap_req_timeout > 0)
TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout);
}
#endif /* PPP_SERVER */
/*
* upap_timeout - Retransmission timer for sending auth-reqs expired.
*/
static void upap_timeout(void *arg) {
ppp_pcb *pcb = (ppp_pcb*)arg;
if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ)
return;
if (pcb->upap.us_transmits >= pcb->settings.pap_max_transmits) {
/* give up in disgust */
ppp_error("No response to PAP authenticate-requests");
pcb->upap.us_clientstate = UPAPCS_BADAUTH;
auth_withpeer_fail(pcb, PPP_PAP);
return;
}
upap_sauthreq(pcb); /* Send Authenticate-Request */
}
#if PPP_SERVER
/*
* upap_reqtimeout - Give up waiting for the peer to send an auth-req.
*/
static void upap_reqtimeout(void *arg) {
ppp_pcb *pcb = (ppp_pcb*)arg;
if (pcb->upap.us_serverstate != UPAPSS_LISTEN)
return; /* huh?? */
auth_peer_fail(pcb, PPP_PAP);
pcb->upap.us_serverstate = UPAPSS_BADAUTH;
}
#endif /* PPP_SERVER */
/*
* upap_lowerup - The lower layer is up.
*
* Start authenticating if pending.
*/
static void upap_lowerup(ppp_pcb *pcb) {
if (pcb->upap.us_clientstate == UPAPCS_INITIAL)
pcb->upap.us_clientstate = UPAPCS_CLOSED;
else if (pcb->upap.us_clientstate == UPAPCS_PENDING) {
upap_sauthreq(pcb); /* send an auth-request */
}
#if PPP_SERVER
if (pcb->upap.us_serverstate == UPAPSS_INITIAL)
pcb->upap.us_serverstate = UPAPSS_CLOSED;
else if (pcb->upap.us_serverstate == UPAPSS_PENDING) {
pcb->upap.us_serverstate = UPAPSS_LISTEN;
if (pcb->settings.pap_req_timeout > 0)
TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout);
}
#endif /* PPP_SERVER */
}
/*
* upap_lowerdown - The lower layer is down.
*
* Cancel all timeouts.
*/
static void upap_lowerdown(ppp_pcb *pcb) {
if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
UNTIMEOUT(upap_timeout, pcb); /* Cancel timeout */
#if PPP_SERVER
if (pcb->upap.us_serverstate == UPAPSS_LISTEN && pcb->settings.pap_req_timeout > 0)
UNTIMEOUT(upap_reqtimeout, pcb);
#endif /* PPP_SERVER */
pcb->upap.us_clientstate = UPAPCS_INITIAL;
#if PPP_SERVER
pcb->upap.us_serverstate = UPAPSS_INITIAL;
#endif /* PPP_SERVER */
}
/*
* upap_protrej - Peer doesn't speak this protocol.
*
* This shouldn't happen. In any case, pretend lower layer went down.
*/
static void upap_protrej(ppp_pcb *pcb) {
if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) {
ppp_error("PAP authentication failed due to protocol-reject");
auth_withpeer_fail(pcb, PPP_PAP);
}
#if PPP_SERVER
if (pcb->upap.us_serverstate == UPAPSS_LISTEN) {
ppp_error("PAP authentication of peer failed (protocol-reject)");
auth_peer_fail(pcb, PPP_PAP);
}
#endif /* PPP_SERVER */
upap_lowerdown(pcb);
}
/*
* upap_input - Input UPAP packet.
*/
static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l) {
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(("pap_input: rcvd short header."));
return;
}
GETCHAR(code, inp);
GETCHAR(id, inp);
GETSHORT(len, inp);
if (len < UPAP_HEADERLEN) {
UPAPDEBUG(("pap_input: rcvd illegal length."));
return;
}
if (len > l) {
UPAPDEBUG(("pap_input: rcvd short packet."));
return;
}
len -= UPAP_HEADERLEN;
/*
* Action depends on code.
*/
switch (code) {
case UPAP_AUTHREQ:
#if PPP_SERVER
upap_rauthreq(pcb, inp, id, len);
#endif /* PPP_SERVER */
break;
case UPAP_AUTHACK:
upap_rauthack(pcb, inp, id, len);
break;
case UPAP_AUTHNAK:
upap_rauthnak(pcb, inp, id, len);
break;
default: /* XXX Need code reject */
break;
}
}
#if PPP_SERVER
/*
* upap_rauth - Receive Authenticate.
*/
static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len) {
u_char ruserlen, rpasswdlen;
char *ruser;
char *rpasswd;
char rhostname[256];
int retcode;
const char *msg;
int msglen;
if (pcb->upap.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 (pcb->upap.us_serverstate == UPAPSS_OPEN) {
upap_sresp(pcb, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
return;
}
if (pcb->upap.us_serverstate == UPAPSS_BADAUTH) {
upap_sresp(pcb, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
return;
}
/*
* Parse user/passwd.
*/
if (len < 1) {
UPAPDEBUG(("pap_rauth: rcvd short packet."));
return;
}
GETCHAR(ruserlen, inp);
len -= sizeof (u_char) + ruserlen + sizeof (u_char);
if (len < 0) {
UPAPDEBUG(("pap_rauth: rcvd short packet."));
return;
}
ruser = (char *) inp;
INCPTR(ruserlen, inp);
GETCHAR(rpasswdlen, inp);
if (len < rpasswdlen) {
UPAPDEBUG(("pap_rauth: rcvd short packet."));
return;
}
rpasswd = (char *) inp;
/*
* Check the username and password given.
*/
retcode = UPAP_AUTHNAK;
if (auth_check_passwd(pcb, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen)) {
retcode = UPAP_AUTHACK;
}
BZERO(rpasswd, rpasswdlen);
#if 0 /* UNUSED */
/*
* Check remote number authorization. A plugin may have filled in
* the remote number or added an allowed number, and rather than
* return an authenticate failure, is leaving it for us to verify.
*/
if (retcode == UPAP_AUTHACK) {
if (!auth_number()) {
/* We do not want to leak info about the pap result. */
retcode = UPAP_AUTHNAK; /* XXX exit value will be "wrong" */
warn("calling number %q is not authorized", remote_number);
}
}
msglen = strlen(msg);
if (msglen > 255)
msglen = 255;
#endif /* UNUSED */
upap_sresp(pcb, retcode, id, msg, msglen);
/* Null terminate and clean remote name. */
ppp_slprintf(rhostname, sizeof(rhostname), "%.*v", ruserlen, ruser);
if (retcode == UPAP_AUTHACK) {
pcb->upap.us_serverstate = UPAPSS_OPEN;
ppp_notice("PAP peer authentication succeeded for %q", rhostname);
auth_peer_success(pcb, PPP_PAP, 0, ruser, ruserlen);
} else {
pcb->upap.us_serverstate = UPAPSS_BADAUTH;
ppp_warn("PAP peer authentication failed for %q", rhostname);
auth_peer_fail(pcb, PPP_PAP);
}
if (pcb->settings.pap_req_timeout > 0)
UNTIMEOUT(upap_reqtimeout, pcb);
}
#endif /* PPP_SERVER */
/*
* upap_rauthack - Receive Authenticate-Ack.
*/
static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len) {
u_char msglen;
char *msg;
LWIP_UNUSED_ARG(id);
if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) /* XXX */
return;
/*
* Parse message.
*/
if (len < 1) {
UPAPDEBUG(("pap_rauthack: ignoring missing msg-length."));
} else {
GETCHAR(msglen, inp);
if (msglen > 0) {
len -= sizeof (u_char);
if (len < msglen) {
UPAPDEBUG(("pap_rauthack: rcvd short packet."));
return;
}
msg = (char *) inp;
PRINTMSG(msg, msglen);
}
}
pcb->upap.us_clientstate = UPAPCS_OPEN;
auth_withpeer_success(pcb, PPP_PAP, 0);
}
/*
* upap_rauthnak - Receive Authenticate-Nak.
*/
static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len) {
u_char msglen;
char *msg;
LWIP_UNUSED_ARG(id);
if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) /* XXX */
return;
/*
* Parse message.
*/
if (len < 1) {
UPAPDEBUG(("pap_rauthnak: ignoring missing msg-length."));
} else {
GETCHAR(msglen, inp);
if (msglen > 0) {
len -= sizeof (u_char);
if (len < msglen) {
UPAPDEBUG(("pap_rauthnak: rcvd short packet."));
return;
}
msg = (char *) inp;
PRINTMSG(msg, msglen);
}
}
pcb->upap.us_clientstate = UPAPCS_BADAUTH;
ppp_error("PAP authentication failed");
auth_withpeer_fail(pcb, PPP_PAP);
}
/*
* upap_sauthreq - Send an Authenticate-Request.
*/
static void upap_sauthreq(ppp_pcb *pcb) {
struct pbuf *p;
u_char *outp;
int outlen;
outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
pcb->upap.us_userlen + pcb->upap.us_passwdlen;
p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE);
if(NULL == p)
return;
if(p->tot_len != p->len) {
pbuf_free(p);
return;
}
outp = (u_char*)p->payload;
MAKEHEADER(outp, PPP_PAP);
PUTCHAR(UPAP_AUTHREQ, outp);
PUTCHAR(++pcb->upap.us_id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(pcb->upap.us_userlen, outp);
MEMCPY(outp, pcb->upap.us_user, pcb->upap.us_userlen);
INCPTR(pcb->upap.us_userlen, outp);
PUTCHAR(pcb->upap.us_passwdlen, outp);
MEMCPY(outp, pcb->upap.us_passwd, pcb->upap.us_passwdlen);
ppp_write(pcb, p);
TIMEOUT(upap_timeout, pcb, pcb->settings.pap_timeout_time);
++pcb->upap.us_transmits;
pcb->upap.us_clientstate = UPAPCS_AUTHREQ;
}
#if PPP_SERVER
/*
* upap_sresp - Send a response (ack or nak).
*/
static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, int msglen) {
struct pbuf *p;
u_char *outp;
int outlen;
outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE);
if(NULL == p)
return;
if(p->tot_len != p->len) {
pbuf_free(p);
return;
}
outp = (u_char*)p->payload;
MAKEHEADER(outp, PPP_PAP);
PUTCHAR(code, outp);
PUTCHAR(id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(msglen, outp);
MEMCPY(outp, msg, msglen);
ppp_write(pcb, p);
}
#endif /* PPP_SERVER */
#if PRINTPKT_SUPPORT
/*
* upap_printpkt - print the contents of a PAP packet.
*/
static const char* const upap_codenames[] = {
"AuthReq", "AuthAck", "AuthNak"
};
static int upap_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg) {
int code, id, len;
int mlen, ulen, wlen;
const u_char *user, *pwd, *msg;
const u_char *pstart;
if (plen < UPAP_HEADERLEN)
return 0;
pstart = p;
GETCHAR(code, p);
GETCHAR(id, p);
GETSHORT(len, p);
if (len < UPAP_HEADERLEN || len > plen)
return 0;
if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(upap_codenames))
printer(arg, " %s", upap_codenames[code-1]);
else
printer(arg, " code=0x%x", code);
printer(arg, " id=0x%x", id);
len -= UPAP_HEADERLEN;
switch (code) {
case UPAP_AUTHREQ:
if (len < 1)
break;
ulen = p[0];
if (len < ulen + 2)
break;
wlen = p[ulen + 1];
if (len < ulen + wlen + 2)
break;
user = (const u_char *) (p + 1);
pwd = (const u_char *) (p + ulen + 2);
p += ulen + wlen + 2;
len -= ulen + wlen + 2;
printer(arg, " user=");
ppp_print_string(user, ulen, printer, arg);
printer(arg, " password=");
/* FIXME: require ppp_pcb struct as printpkt() argument */
#if 0
if (!pcb->settings.hide_password)
#endif
ppp_print_string(pwd, wlen, printer, arg);
#if 0
else
printer(arg, "<hidden>");
#endif
break;
case UPAP_AUTHACK:
case UPAP_AUTHNAK:
if (len < 1)
break;
mlen = p[0];
if (len < mlen + 1)
break;
msg = (const u_char *) (p + 1);
p += mlen + 1;
len -= mlen + 1;
printer(arg, " ");
ppp_print_string(msg, mlen, printer, arg);
break;
default:
break;
}
/* print the rest of the bytes in the packet */
for (; len > 0; --len) {
GETCHAR(code, p);
printer(arg, " %.2x", code);
}
return p - pstart;
}
#endif /* PRINTPKT_SUPPORT */
#endif /* PPP_SUPPORT && PAP_SUPPORT */

View file

@ -0,0 +1,957 @@
/*
* utils.c - various utility functions used in pppd.
*
* Copyright (c) 1999-2002 Paul Mackerras. 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. The name(s) of the authors of this software must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* 3. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Paul Mackerras
* <paulus@samba.org>".
*
* THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
#if 0 /* UNUSED */
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <syslog.h>
#include <netdb.h>
#include <time.h>
#include <utmp.h>
#include <pwd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifdef SVR4
#include <sys/mkdev.h>
#endif
#endif /* UNUSED */
#include <ctype.h> /* isdigit() */
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/fsm.h"
#include "netif/ppp/lcp.h"
#if defined(SUNOS4)
extern char *strerror();
#endif
static void ppp_logit(int level, const char *fmt, va_list args);
static void ppp_log_write(int level, char *buf);
#if PRINTPKT_SUPPORT
static void ppp_vslp_printer(void *arg, const char *fmt, ...);
static void ppp_format_packet(const u_char *p, int len,
void (*printer) (void *, const char *, ...), void *arg);
struct buffer_info {
char *ptr;
int len;
};
#endif /* PRINTPKT_SUPPORT */
/*
* ppp_strlcpy - like strcpy/strncpy, doesn't overflow destination buffer,
* always leaves destination null-terminated (for len > 0).
*/
size_t ppp_strlcpy(char *dest, const char *src, size_t len) {
size_t ret = strlen(src);
if (len != 0) {
if (ret < len)
strcpy(dest, src);
else {
strncpy(dest, src, len - 1);
dest[len-1] = 0;
}
}
return ret;
}
/*
* ppp_strlcat - like strcat/strncat, doesn't overflow destination buffer,
* always leaves destination null-terminated (for len > 0).
*/
size_t ppp_strlcat(char *dest, const char *src, size_t len) {
size_t dlen = strlen(dest);
return dlen + ppp_strlcpy(dest + dlen, src, (len > dlen? len - dlen: 0));
}
/*
* ppp_slprintf - format a message into a buffer. Like sprintf except we
* also specify the length of the output buffer, and we handle
* %m (error message), %v (visible string),
* %q (quoted string), %t (current time) and %I (IP address) formats.
* Doesn't do floating-point formats.
* Returns the number of chars put into buf.
*/
int ppp_slprintf(char *buf, int buflen, const char *fmt, ...) {
va_list args;
int n;
va_start(args, fmt);
n = ppp_vslprintf(buf, buflen, fmt, args);
va_end(args);
return n;
}
/*
* ppp_vslprintf - like ppp_slprintf, takes a va_list instead of a list of args.
*/
#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0)
int ppp_vslprintf(char *buf, int buflen, const char *fmt, va_list args) {
int c, i, n;
int width, prec, fillch;
int base, len, neg, quoted;
unsigned long val = 0;
const char *f;
char *str, *buf0;
const unsigned char *p;
char num[32];
#if 0 /* need port */
time_t t;
#endif /* need port */
u32_t ip;
static char hexchars[] = "0123456789abcdef";
#if PRINTPKT_SUPPORT
struct buffer_info bufinfo;
#endif /* PRINTPKT_SUPPORT */
buf0 = buf;
--buflen;
while (buflen > 0) {
for (f = fmt; *f != '%' && *f != 0; ++f)
;
if (f > fmt) {
len = f - fmt;
if (len > buflen)
len = buflen;
memcpy(buf, fmt, len);
buf += len;
buflen -= len;
fmt = f;
}
if (*fmt == 0)
break;
c = *++fmt;
width = 0;
prec = -1;
fillch = ' ';
if (c == '0') {
fillch = '0';
c = *++fmt;
}
if (c == '*') {
width = va_arg(args, int);
c = *++fmt;
} else {
while (isdigit(c)) {
width = width * 10 + c - '0';
c = *++fmt;
}
}
if (c == '.') {
c = *++fmt;
if (c == '*') {
prec = va_arg(args, int);
c = *++fmt;
} else {
prec = 0;
while (isdigit(c)) {
prec = prec * 10 + c - '0';
c = *++fmt;
}
}
}
str = 0;
base = 0;
neg = 0;
++fmt;
switch (c) {
case 'l':
c = *fmt++;
switch (c) {
case 'd':
val = va_arg(args, long);
if ((long)val < 0) {
neg = 1;
val = (unsigned long)-(long)val;
}
base = 10;
break;
case 'u':
val = va_arg(args, unsigned long);
base = 10;
break;
default:
OUTCHAR('%');
OUTCHAR('l');
--fmt; /* so %lz outputs %lz etc. */
continue;
}
break;
case 'd':
i = va_arg(args, int);
if (i < 0) {
neg = 1;
val = -i;
} else
val = i;
base = 10;
break;
case 'u':
val = va_arg(args, unsigned int);
base = 10;
break;
case 'o':
val = va_arg(args, unsigned int);
base = 8;
break;
case 'x':
case 'X':
val = va_arg(args, unsigned int);
base = 16;
break;
case 'p':
val = (unsigned long) va_arg(args, void *);
base = 16;
neg = 2;
break;
case 's':
str = va_arg(args, char *);
break;
case 'c':
num[0] = va_arg(args, int);
num[1] = 0;
str = num;
break;
#if 0 /* do we always have strerror() in embedded ? */
case 'm':
str = strerror(errno);
break;
#endif /* do we always have strerror() in embedded ? */
case 'I':
ip = va_arg(args, u32_t);
ip = lwip_ntohl(ip);
ppp_slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff,
(ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
str = num;
break;
#if 0 /* need port */
case 't':
time(&t);
str = ctime(&t);
str += 4; /* chop off the day name */
str[15] = 0; /* chop off year and newline */
break;
#endif /* need port */
case 'v': /* "visible" string */
case 'q': /* quoted string */
quoted = c == 'q';
p = va_arg(args, unsigned char *);
if (p == NULL)
p = (const unsigned char *)"<NULL>";
if (fillch == '0' && prec >= 0) {
n = prec;
} else {
n = strlen((const char *)p);
if (prec >= 0 && n > prec)
n = prec;
}
while (n > 0 && buflen > 0) {
c = *p++;
--n;
if (!quoted && c >= 0x80) {
OUTCHAR('M');
OUTCHAR('-');
c -= 0x80;
}
if (quoted && (c == '"' || c == '\\'))
OUTCHAR('\\');
if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
if (quoted) {
OUTCHAR('\\');
switch (c) {
case '\t': OUTCHAR('t'); break;
case '\n': OUTCHAR('n'); break;
case '\b': OUTCHAR('b'); break;
case '\f': OUTCHAR('f'); break;
default:
OUTCHAR('x');
OUTCHAR(hexchars[c >> 4]);
OUTCHAR(hexchars[c & 0xf]);
}
} else {
if (c == '\t')
OUTCHAR(c);
else {
OUTCHAR('^');
OUTCHAR(c ^ 0x40);
}
}
} else
OUTCHAR(c);
}
continue;
#if PRINTPKT_SUPPORT
case 'P': /* print PPP packet */
bufinfo.ptr = buf;
bufinfo.len = buflen + 1;
p = va_arg(args, unsigned char *);
n = va_arg(args, int);
ppp_format_packet(p, n, ppp_vslp_printer, &bufinfo);
buf = bufinfo.ptr;
buflen = bufinfo.len - 1;
continue;
#endif /* PRINTPKT_SUPPORT */
case 'B':
p = va_arg(args, unsigned char *);
for (n = prec; n > 0; --n) {
c = *p++;
if (fillch == ' ')
OUTCHAR(' ');
OUTCHAR(hexchars[(c >> 4) & 0xf]);
OUTCHAR(hexchars[c & 0xf]);
}
continue;
default:
*buf++ = '%';
if (c != '%')
--fmt; /* so %z outputs %z etc. */
--buflen;
continue;
}
if (base != 0) {
str = num + sizeof(num);
*--str = 0;
while (str > num + neg) {
*--str = hexchars[val % base];
val = val / base;
if (--prec <= 0 && val == 0)
break;
}
switch (neg) {
case 1:
*--str = '-';
break;
case 2:
*--str = 'x';
*--str = '0';
break;
default:
break;
}
len = num + sizeof(num) - 1 - str;
} else {
len = strlen(str);
if (prec >= 0 && len > prec)
len = prec;
}
if (width > 0) {
if (width > buflen)
width = buflen;
if ((n = width - len) > 0) {
buflen -= n;
for (; n > 0; --n)
*buf++ = fillch;
}
}
if (len > buflen)
len = buflen;
memcpy(buf, str, len);
buf += len;
buflen -= len;
}
*buf = 0;
return buf - buf0;
}
#if PRINTPKT_SUPPORT
/*
* vslp_printer - used in processing a %P format
*/
static void ppp_vslp_printer(void *arg, const char *fmt, ...) {
int n;
va_list pvar;
struct buffer_info *bi;
va_start(pvar, fmt);
bi = (struct buffer_info *) arg;
n = ppp_vslprintf(bi->ptr, bi->len, fmt, pvar);
va_end(pvar);
bi->ptr += n;
bi->len -= n;
}
#endif /* PRINTPKT_SUPPORT */
#if 0 /* UNUSED */
/*
* log_packet - format a packet and log it.
*/
void
log_packet(p, len, prefix, level)
u_char *p;
int len;
char *prefix;
int level;
{
init_pr_log(prefix, level);
ppp_format_packet(p, len, pr_log, &level);
end_pr_log();
}
#endif /* UNUSED */
#if PRINTPKT_SUPPORT
/*
* ppp_format_packet - make a readable representation of a packet,
* calling `printer(arg, format, ...)' to output it.
*/
static void ppp_format_packet(const u_char *p, int len,
void (*printer) (void *, const char *, ...), void *arg) {
int i, n;
u_short proto;
const struct protent *protp;
if (len >= 2) {
GETSHORT(proto, p);
len -= 2;
for (i = 0; (protp = protocols[i]) != NULL; ++i)
if (proto == protp->protocol)
break;
if (protp != NULL) {
printer(arg, "[%s", protp->name);
n = (*protp->printpkt)(p, len, printer, arg);
printer(arg, "]");
p += n;
len -= n;
} else {
for (i = 0; (protp = protocols[i]) != NULL; ++i)
if (proto == (protp->protocol & ~0x8000))
break;
if (protp != 0 && protp->data_name != 0) {
printer(arg, "[%s data]", protp->data_name);
if (len > 8)
printer(arg, "%.8B ...", p);
else
printer(arg, "%.*B", len, p);
len = 0;
} else
printer(arg, "[proto=0x%x]", proto);
}
}
if (len > 32)
printer(arg, "%.32B ...", p);
else
printer(arg, "%.*B", len, p);
}
#endif /* PRINTPKT_SUPPORT */
#if 0 /* UNUSED */
/*
* init_pr_log, end_pr_log - initialize and finish use of pr_log.
*/
static char line[256]; /* line to be logged accumulated here */
static char *linep; /* current pointer within line */
static int llevel; /* level for logging */
void
init_pr_log(prefix, level)
const char *prefix;
int level;
{
linep = line;
if (prefix != NULL) {
ppp_strlcpy(line, prefix, sizeof(line));
linep = line + strlen(line);
}
llevel = level;
}
void
end_pr_log()
{
if (linep != line) {
*linep = 0;
ppp_log_write(llevel, line);
}
}
/*
* pr_log - printer routine for outputting to log
*/
void
pr_log (void *arg, const char *fmt, ...)
{
int l, n;
va_list pvar;
char *p, *eol;
char buf[256];
va_start(pvar, fmt);
n = ppp_vslprintf(buf, sizeof(buf), fmt, pvar);
va_end(pvar);
p = buf;
eol = strchr(buf, '\n');
if (linep != line) {
l = (eol == NULL)? n: eol - buf;
if (linep + l < line + sizeof(line)) {
if (l > 0) {
memcpy(linep, buf, l);
linep += l;
}
if (eol == NULL)
return;
p = eol + 1;
eol = strchr(p, '\n');
}
*linep = 0;
ppp_log_write(llevel, line);
linep = line;
}
while (eol != NULL) {
*eol = 0;
ppp_log_write(llevel, p);
p = eol + 1;
eol = strchr(p, '\n');
}
/* assumes sizeof(buf) <= sizeof(line) */
l = buf + n - p;
if (l > 0) {
memcpy(line, p, n);
linep = line + l;
}
}
#endif /* UNUSED */
/*
* ppp_print_string - print a readable representation of a string using
* printer.
*/
void ppp_print_string(const u_char *p, int len, void (*printer) (void *, const char *, ...), void *arg) {
int c;
printer(arg, "\"");
for (; len > 0; --len) {
c = *p++;
if (' ' <= c && c <= '~') {
if (c == '\\' || c == '"')
printer(arg, "\\");
printer(arg, "%c", c);
} else {
switch (c) {
case '\n':
printer(arg, "\\n");
break;
case '\r':
printer(arg, "\\r");
break;
case '\t':
printer(arg, "\\t");
break;
default:
printer(arg, "\\%.3o", (u8_t)c);
/* no break */
}
}
}
printer(arg, "\"");
}
/*
* ppp_logit - does the hard work for fatal et al.
*/
static void ppp_logit(int level, const char *fmt, va_list args) {
char buf[1024];
ppp_vslprintf(buf, sizeof(buf), fmt, args);
ppp_log_write(level, buf);
}
static void ppp_log_write(int level, char *buf) {
LWIP_UNUSED_ARG(level); /* necessary if PPPDEBUG is defined to an empty function */
LWIP_UNUSED_ARG(buf);
PPPDEBUG(level, ("%s\n", buf) );
#if 0
if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) {
int n = strlen(buf);
if (n > 0 && buf[n-1] == '\n')
--n;
if (write(log_to_fd, buf, n) != n
|| write(log_to_fd, "\n", 1) != 1)
log_to_fd = -1;
}
#endif
}
/*
* ppp_fatal - log an error message and die horribly.
*/
void ppp_fatal(const char *fmt, ...) {
va_list pvar;
va_start(pvar, fmt);
ppp_logit(LOG_ERR, fmt, pvar);
va_end(pvar);
LWIP_ASSERT("ppp_fatal", 0); /* as promised */
}
/*
* ppp_error - log an error message.
*/
void ppp_error(const char *fmt, ...) {
va_list pvar;
va_start(pvar, fmt);
ppp_logit(LOG_ERR, fmt, pvar);
va_end(pvar);
#if 0 /* UNUSED */
++error_count;
#endif /* UNUSED */
}
/*
* ppp_warn - log a warning message.
*/
void ppp_warn(const char *fmt, ...) {
va_list pvar;
va_start(pvar, fmt);
ppp_logit(LOG_WARNING, fmt, pvar);
va_end(pvar);
}
/*
* ppp_notice - log a notice-level message.
*/
void ppp_notice(const char *fmt, ...) {
va_list pvar;
va_start(pvar, fmt);
ppp_logit(LOG_NOTICE, fmt, pvar);
va_end(pvar);
}
/*
* ppp_info - log an informational message.
*/
void ppp_info(const char *fmt, ...) {
va_list pvar;
va_start(pvar, fmt);
ppp_logit(LOG_INFO, fmt, pvar);
va_end(pvar);
}
/*
* ppp_dbglog - log a debug message.
*/
void ppp_dbglog(const char *fmt, ...) {
va_list pvar;
va_start(pvar, fmt);
ppp_logit(LOG_DEBUG, fmt, pvar);
va_end(pvar);
}
#if PRINTPKT_SUPPORT
/*
* ppp_dump_packet - print out a packet in readable form if it is interesting.
* Assumes len >= PPP_HDRLEN.
*/
void ppp_dump_packet(ppp_pcb *pcb, const char *tag, unsigned char *p, int len) {
int proto;
/*
* don't print data packets, i.e. IPv4, IPv6, VJ, and compressed packets.
*/
proto = (p[0] << 8) + p[1];
if (proto < 0xC000 && (proto & ~0x8000) == proto)
return;
/*
* don't print valid LCP echo request/reply packets if the link is up.
*/
if (proto == PPP_LCP && pcb->phase == PPP_PHASE_RUNNING && len >= 2 + HEADERLEN) {
unsigned char *lcp = p + 2;
int l = (lcp[2] << 8) + lcp[3];
if ((lcp[0] == ECHOREQ || lcp[0] == ECHOREP)
&& l >= HEADERLEN && l <= len - 2)
return;
}
ppp_dbglog("%s %P", tag, p, len);
}
#endif /* PRINTPKT_SUPPORT */
#if 0 /* Unused */
/*
* complete_read - read a full `count' bytes from fd,
* unless end-of-file or an error other than EINTR is encountered.
*/
ssize_t
complete_read(int fd, void *buf, size_t count)
{
size_t done;
ssize_t nb;
char *ptr = buf;
for (done = 0; done < count; ) {
nb = read(fd, ptr, count - done);
if (nb < 0) {
if (errno == EINTR)
continue;
return -1;
}
if (nb == 0)
break;
done += nb;
ptr += nb;
}
return done;
}
/* Procedures for locking the serial device using a lock file. */
#ifndef LOCK_DIR
#ifdef __linux__
#define LOCK_DIR "/var/lock"
#else
#ifdef SVR4
#define LOCK_DIR "/var/spool/locks"
#else
#define LOCK_DIR "/var/spool/lock"
#endif
#endif
#endif /* LOCK_DIR */
static char lock_file[MAXPATHLEN];
/*
* lock - create a lock file for the named device
*/
int
lock(dev)
char *dev;
{
#ifdef LOCKLIB
int result;
result = mklock (dev, (void *) 0);
if (result == 0) {
ppp_strlcpy(lock_file, dev, sizeof(lock_file));
return 0;
}
if (result > 0)
ppp_notice("Device %s is locked by pid %d", dev, result);
else
ppp_error("Can't create lock file %s", lock_file);
return -1;
#else /* LOCKLIB */
char lock_buffer[12];
int fd, pid, n;
#ifdef SVR4
struct stat sbuf;
if (stat(dev, &sbuf) < 0) {
ppp_error("Can't get device number for %s: %m", dev);
return -1;
}
if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
ppp_error("Can't lock %s: not a character device", dev);
return -1;
}
ppp_slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d",
LOCK_DIR, major(sbuf.st_dev),
major(sbuf.st_rdev), minor(sbuf.st_rdev));
#else
char *p;
char lockdev[MAXPATHLEN];
if ((p = strstr(dev, "dev/")) != NULL) {
dev = p + 4;
strncpy(lockdev, dev, MAXPATHLEN-1);
lockdev[MAXPATHLEN-1] = 0;
while ((p = strrchr(lockdev, '/')) != NULL) {
*p = '_';
}
dev = lockdev;
} else
if ((p = strrchr(dev, '/')) != NULL)
dev = p + 1;
ppp_slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev);
#endif
while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
if (errno != EEXIST) {
ppp_error("Can't create lock file %s: %m", lock_file);
break;
}
/* Read the lock file to find out who has the device locked. */
fd = open(lock_file, O_RDONLY, 0);
if (fd < 0) {
if (errno == ENOENT) /* This is just a timing problem. */
continue;
ppp_error("Can't open existing lock file %s: %m", lock_file);
break;
}
#ifndef LOCK_BINARY
n = read(fd, lock_buffer, 11);
#else
n = read(fd, &pid, sizeof(pid));
#endif /* LOCK_BINARY */
close(fd);
fd = -1;
if (n <= 0) {
ppp_error("Can't read pid from lock file %s", lock_file);
break;
}
/* See if the process still exists. */
#ifndef LOCK_BINARY
lock_buffer[n] = 0;
pid = atoi(lock_buffer);
#endif /* LOCK_BINARY */
if (pid == getpid())
return 1; /* somebody else locked it for us */
if (pid == 0
|| (kill(pid, 0) == -1 && errno == ESRCH)) {
if (unlink (lock_file) == 0) {
ppp_notice("Removed stale lock on %s (pid %d)", dev, pid);
continue;
}
ppp_warn("Couldn't remove stale lock on %s", dev);
} else
ppp_notice("Device %s is locked by pid %d", dev, pid);
break;
}
if (fd < 0) {
lock_file[0] = 0;
return -1;
}
pid = getpid();
#ifndef LOCK_BINARY
ppp_slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
write (fd, lock_buffer, 11);
#else
write(fd, &pid, sizeof (pid));
#endif
close(fd);
return 0;
#endif
}
/*
* relock - called to update our lockfile when we are about to detach,
* thus changing our pid (we fork, the child carries on, and the parent dies).
* Note that this is called by the parent, with pid equal to the pid
* of the child. This avoids a potential race which would exist if
* we had the child rewrite the lockfile (the parent might die first,
* and another process could think the lock was stale if it checked
* between when the parent died and the child rewrote the lockfile).
*/
int
relock(pid)
int pid;
{
#ifdef LOCKLIB
/* XXX is there a way to do this? */
return -1;
#else /* LOCKLIB */
int fd;
char lock_buffer[12];
if (lock_file[0] == 0)
return -1;
fd = open(lock_file, O_WRONLY, 0);
if (fd < 0) {
ppp_error("Couldn't reopen lock file %s: %m", lock_file);
lock_file[0] = 0;
return -1;
}
#ifndef LOCK_BINARY
ppp_slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
write (fd, lock_buffer, 11);
#else
write(fd, &pid, sizeof(pid));
#endif /* LOCK_BINARY */
close(fd);
return 0;
#endif /* LOCKLIB */
}
/*
* unlock - remove our lockfile
*/
void
unlock()
{
if (lock_file[0]) {
#ifdef LOCKLIB
(void) rmlock(lock_file, (void *) 0);
#else
unlink(lock_file);
#endif
lock_file[0] = 0;
}
}
#endif /* Unused */
#endif /* PPP_SUPPORT */

View file

@ -0,0 +1,695 @@
/*
* 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 "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && VJ_SUPPORT /* don't build if not configured for use in lwipopts.h */
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/pppdebug.h"
#include "netif/ppp/vj.h"
#include <string.h>
#if LINK_STATS
#define INCR(counter) ++comp->stats.counter
#else
#define INCR(counter)
#endif
void
vj_compress_init(struct vjcompress *comp)
{
u8_t i;
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 ((u16_t)(n) >= 256) { \
*cp++ = 0; \
cp[1] = (u8_t)(n); \
cp[0] = (u8_t)((n) >> 8); \
cp += 2; \
} else { \
*cp++ = (u8_t)(n); \
} \
}
#define ENCODEZ(n) { \
if ((u16_t)(n) >= 256 || (u16_t)(n) == 0) { \
*cp++ = 0; \
cp[1] = (u8_t)(n); \
cp[0] = (u8_t)((n) >> 8); \
cp += 2; \
} else { \
*cp++ = (u8_t)(n); \
} \
}
#define DECODEL(f) { \
if (*cp == 0) {\
u32_t tmp_ = lwip_ntohl(f) + ((cp[1] << 8) | cp[2]); \
(f) = lwip_htonl(tmp_); \
cp += 3; \
} else { \
u32_t tmp_ = lwip_ntohl(f) + (u32_t)*cp++; \
(f) = lwip_htonl(tmp_); \
} \
}
#define DECODES(f) { \
if (*cp == 0) {\
u16_t tmp_ = lwip_ntohs(f) + (((u16_t)cp[1] << 8) | cp[2]); \
(f) = lwip_htons(tmp_); \
cp += 3; \
} else { \
u16_t tmp_ = lwip_ntohs(f) + (u16_t)*cp++; \
(f) = lwip_htons(tmp_); \
} \
}
#define DECODEU(f) { \
if (*cp == 0) {\
(f) = lwip_htons(((u16_t)cp[1] << 8) | cp[2]); \
cp += 3; \
} else { \
(f) = lwip_htons((u16_t)*cp++); \
} \
}
/* Helper structures for unaligned *u32_t and *u16_t accesses */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct vj_u32_t {
PACK_STRUCT_FIELD(u32_t v);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct vj_u16_t {
PACK_STRUCT_FIELD(u16_t v);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/*
* vj_compress_tcp - Attempt to do Van Jacobson 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.
*/
u8_t
vj_compress_tcp(struct vjcompress *comp, struct pbuf **pb)
{
struct pbuf *np = *pb;
struct ip_hdr *ip = (struct ip_hdr *)np->payload;
struct cstate *cs = comp->last_cs->cs_next;
u16_t ilen = IPH_HL(ip);
u16_t hlen;
struct tcp_hdr *oth;
struct tcp_hdr *th;
u16_t deltaS, deltaA = 0;
u32_t deltaL;
u32_t changes = 0;
u8_t new_seq[16];
u8_t *cp = new_seq;
/*
* Check that the packet is IP proto TCP.
*/
if (IPH_PROTO(ip) != IP_PROTO_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 ((IPH_OFFSET(ip) & PP_HTONS(0x3fff)) || np->tot_len < 40) {
return (TYPE_IP);
}
th = (struct tcp_hdr *)&((struct vj_u32_t*)ip)[ilen];
if ((TCPH_FLAGS(th) & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) {
return (TYPE_IP);
}
/* Check that the TCP/IP headers are contained in the first buffer. */
hlen = ilen + TCPH_HDRLEN(th);
hlen <<= 2;
if (np->len < hlen) {
PPPDEBUG(LOG_INFO, ("vj_compress_tcp: header len %d spans buffers\n", hlen));
return (TYPE_IP);
}
/* TCP stack requires that we don't change the packet payload, therefore we copy
* the whole packet before compression. */
np = pbuf_alloc(PBUF_RAW, np->tot_len, PBUF_POOL);
if (!np) {
return (TYPE_IP);
}
if (pbuf_copy(np, *pb) != ERR_OK) {
pbuf_free(np);
return (TYPE_IP);
}
*pb = np;
ip = (struct ip_hdr *)np->payload;
/*
* 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 (!ip4_addr_cmp(&ip->src, &cs->cs_ip.src)
|| !ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest)
|| (*(struct vj_u32_t*)th).v != (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) {
/*
* 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.
*/
struct cstate *lcs;
struct cstate *lastcs = comp->last_cs;
do {
lcs = cs; cs = cs->cs_next;
INCR(vjs_searches);
if (ip4_addr_cmp(&ip->src, &cs->cs_ip.src)
&& ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest)
&& (*(struct vj_u32_t*)th).v == (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) {
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;
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 tcp_hdr *)&((struct vj_u32_t*)&cs->cs_ip)[ilen];
deltaS = ilen;
/*
* 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 ((((struct vj_u16_t*)ip)[0]).v != (((struct vj_u16_t*)&cs->cs_ip)[0]).v
|| (((struct vj_u16_t*)ip)[3]).v != (((struct vj_u16_t*)&cs->cs_ip)[3]).v
|| (((struct vj_u16_t*)ip)[4]).v != (((struct vj_u16_t*)&cs->cs_ip)[4]).v
|| TCPH_HDRLEN(th) != TCPH_HDRLEN(oth)
|| (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2))
|| (TCPH_HDRLEN(th) > 5 && BCMP(th + 1, oth + 1, (TCPH_HDRLEN(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 (TCPH_FLAGS(th) & TCP_URG) {
deltaS = lwip_ntohs(th->urgp);
ENCODEZ(deltaS);
changes |= NEW_U;
} else if (th->urgp != oth->urgp) {
/* 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 = (u16_t)(lwip_ntohs(th->wnd) - lwip_ntohs(oth->wnd))) != 0) {
ENCODE(deltaS);
changes |= NEW_W;
}
if ((deltaL = lwip_ntohl(th->ackno) - lwip_ntohl(oth->ackno)) != 0) {
if (deltaL > 0xffff) {
goto uncompressed;
}
deltaA = (u16_t)deltaL;
ENCODE(deltaA);
changes |= NEW_A;
}
if ((deltaL = lwip_ntohl(th->seqno) - lwip_ntohl(oth->seqno)) != 0) {
if (deltaL > 0xffff) {
goto uncompressed;
}
deltaS = (u16_t)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 (IPH_LEN(ip) != IPH_LEN(&cs->cs_ip) &&
lwip_ntohs(IPH_LEN(&cs->cs_ip)) == hlen) {
break;
}
/* no 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 == lwip_ntohs(IPH_LEN(&cs->cs_ip)) - hlen) {
/* special case for echoed terminal traffic */
changes = SPECIAL_I;
cp = new_seq;
}
break;
case NEW_S:
if (deltaS == lwip_ntohs(IPH_LEN(&cs->cs_ip)) - hlen) {
/* special case for data xfer */
changes = SPECIAL_D;
cp = new_seq;
}
break;
default:
break;
}
deltaS = (u16_t)(lwip_ntohs(IPH_ID(ip)) - lwip_ntohs(IPH_ID(&cs->cs_ip)));
if (deltaS != 1) {
ENCODEZ(deltaS);
changes |= NEW_I;
}
if (TCPH_FLAGS(th) & TCP_PSH) {
changes |= TCP_PUSH_BIT;
}
/*
* Grab the cksum before we overwrite it below. Then update our
* state with this packet's header.
*/
deltaA = lwip_ntohs(th->chksum);
MEMCPY(&cs->cs_ip, 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 = (u16_t)(cp - new_seq);
if (!comp->compressSlot || comp->last_xmit != cs->cs_id) {
comp->last_xmit = cs->cs_id;
hlen -= deltaS + 4;
if (pbuf_header(np, -(s16_t)hlen)){
/* Can we cope with this failing? Just assert for now */
LWIP_ASSERT("pbuf_header failed\n", 0);
}
cp = (u8_t*)np->payload;
*cp++ = (u8_t)(changes | NEW_C);
*cp++ = cs->cs_id;
} else {
hlen -= deltaS + 3;
if (pbuf_header(np, -(s16_t)hlen)) {
/* Can we cope with this failing? Just assert for now */
LWIP_ASSERT("pbuf_header failed\n", 0);
}
cp = (u8_t*)np->payload;
*cp++ = (u8_t)changes;
}
*cp++ = (u8_t)(deltaA >> 8);
*cp++ = (u8_t)deltaA;
MEMCPY(cp, new_seq, 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:
MEMCPY(&cs->cs_ip, ip, hlen);
IPH_PROTO_SET(ip, 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)
{
u32_t hlen;
struct cstate *cs;
struct ip_hdr *ip;
ip = (struct ip_hdr *)nb->payload;
hlen = IPH_HL(ip) << 2;
if (IPH_PROTO(ip) >= MAX_SLOTS
|| hlen + sizeof(struct tcp_hdr) > nb->len
|| (hlen += TCPH_HDRLEN(((struct tcp_hdr *)&((char *)ip)[hlen])) << 2)
> nb->len
|| hlen > MAX_HDR) {
PPPDEBUG(LOG_INFO, ("vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n",
IPH_PROTO(ip), hlen, nb->len));
comp->flags |= VJF_TOSS;
INCR(vjs_errorin);
return -1;
}
cs = &comp->rstate[comp->last_recv = IPH_PROTO(ip)];
comp->flags &=~ VJF_TOSS;
IPH_PROTO_SET(ip, IP_PROTO_TCP);
MEMCPY(&cs->cs_ip, ip, hlen);
cs->cs_hlen = (u16_t)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)
{
u8_t *cp;
struct tcp_hdr *th;
struct cstate *cs;
struct vj_u16_t *bp;
struct pbuf *n0 = *nb;
u32_t tmp;
u32_t vjlen, hlen, changes;
INCR(vjs_compressedin);
cp = (u8_t*)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 = IPH_HL(&cs->cs_ip) << 2;
th = (struct tcp_hdr *)&((u8_t*)&cs->cs_ip)[hlen];
th->chksum = lwip_htons((*cp << 8) | cp[1]);
cp += 2;
if (changes & TCP_PUSH_BIT) {
TCPH_SET_FLAG(th, TCP_PSH);
} else {
TCPH_UNSET_FLAG(th, TCP_PSH);
}
switch (changes & SPECIALS_MASK) {
case SPECIAL_I:
{
u32_t i = lwip_ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen;
/* some compilers can't nest inline assembler.. */
tmp = lwip_ntohl(th->ackno) + i;
th->ackno = lwip_htonl(tmp);
tmp = lwip_ntohl(th->seqno) + i;
th->seqno = lwip_htonl(tmp);
}
break;
case SPECIAL_D:
/* some compilers can't nest inline assembler.. */
tmp = lwip_ntohl(th->seqno) + lwip_ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen;
th->seqno = lwip_htonl(tmp);
break;
default:
if (changes & NEW_U) {
TCPH_SET_FLAG(th, TCP_URG);
DECODEU(th->urgp);
} else {
TCPH_UNSET_FLAG(th, TCP_URG);
}
if (changes & NEW_W) {
DECODES(th->wnd);
}
if (changes & NEW_A) {
DECODEL(th->ackno);
}
if (changes & NEW_S) {
DECODEL(th->seqno);
}
break;
}
if (changes & NEW_I) {
DECODES(cs->cs_ip._id);
} else {
IPH_ID_SET(&cs->cs_ip, lwip_ntohs(IPH_ID(&cs->cs_ip)) + 1);
IPH_ID_SET(&cs->cs_ip, lwip_htons(IPH_ID(&cs->cs_ip)));
}
/*
* 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 = (u16_t)(cp - (u8_t*)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;
IPH_LEN_SET(&cs->cs_ip, lwip_htons((u16_t)tmp));
#else
IPH_LEN_SET(&cs->cs_ip, lwip_htons(n0->tot_len - vjlen + cs->cs_hlen));
#endif
/* recompute the ip header checksum */
bp = (struct vj_u16_t*) &cs->cs_ip;
IPH_CHKSUM_SET(&cs->cs_ip, 0);
for (tmp = 0; hlen > 0; hlen -= 2) {
tmp += (*bp++).v;
}
tmp = (tmp & 0xffff) + (tmp >> 16);
tmp = (tmp & 0xffff) + (tmp >> 16);
IPH_CHKSUM_SET(&cs->cs_ip, (u16_t)(~tmp));
/* Remove the compressed header and prepend the uncompressed header. */
if (pbuf_header(n0, -(s16_t)vjlen)) {
/* Can we cope with this failing? Just assert for now */
LWIP_ASSERT("pbuf_header failed\n", 0);
goto bad;
}
if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) {
struct pbuf *np, *q;
u8_t *bufptr;
#if IP_FORWARD
/* If IP forwarding is enabled we are using a PBUF_LINK packet type so
* the packet is being allocated with enough header space to be
* forwarded (to Ethernet for example).
*/
np = pbuf_alloc(PBUF_LINK, n0->len + cs->cs_hlen, PBUF_POOL);
#else /* IP_FORWARD */
np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL);
#endif /* IP_FORWARD */
if(!np) {
PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: realign failed\n"));
goto bad;
}
if (pbuf_header(np, -(s16_t)cs->cs_hlen)) {
/* Can we cope with this failing? Just assert for now */
LWIP_ASSERT("pbuf_header failed\n", 0);
goto bad;
}
bufptr = (u8_t*)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, (s16_t)cs->cs_hlen)) {
struct pbuf *np;
LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE);
np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL);
if(!np) {
PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: prepend failed\n"));
goto bad;
}
pbuf_cat(np, n0);
n0 = np;
}
LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen);
MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen);
*nb = n0;
return vjlen;
bad:
comp->flags |= VJF_TOSS;
INCR(vjs_errorin);
return (-1);
}
#endif /* PPP_SUPPORT && VJ_SUPPORT */

View file

@ -0,0 +1,555 @@
/**
* @file
* SLIP Interface
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is built upon the file: src/arch/rtxc/netif/sioslip.c
*
* Author: Magnus Ivarsson <magnus.ivarsson(at)volvo.com>
* Simon Goldschmidt
*/
/**
* @defgroup slipif SLIP netif
* @ingroup addons
*
* This is an arch independent SLIP netif. The specific serial hooks must be
* provided by another file. They are sio_open, sio_read/sio_tryread and sio_send
*
* Usage: This netif can be used in three ways:\n
* 1) For NO_SYS==0, an RX thread can be used which blocks on sio_read()
* until data is received.\n
* 2) In your main loop, call slipif_poll() to check for new RX bytes,
* completed packets are fed into netif->input().\n
* 3) Call slipif_received_byte[s]() from your serial RX ISR and
* slipif_process_rxqueue() from your main loop. ISR level decodes
* packets and puts completed packets on a queue which is fed into
* the stack from the main loop (needs SYS_LIGHTWEIGHT_PROT for
* pbuf_alloc to work on ISR level!).
*
*/
#include "netif/slipif.h"
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/sys.h"
#include "lwip/sio.h"
#define SLIP_END 0xC0 /* 0300: start and end of every packet */
#define SLIP_ESC 0xDB /* 0333: escape start (one byte escaped data follows) */
#define SLIP_ESC_END 0xDC /* 0334: following escape: original byte is 0xC0 (END) */
#define SLIP_ESC_ESC 0xDD /* 0335: following escape: original byte is 0xDB (ESC) */
/** Maximum packet size that is received by this netif */
#ifndef SLIP_MAX_SIZE
#define SLIP_MAX_SIZE 1500
#endif
/** Define this to the interface speed for SNMP
* (sio_fd is the sio_fd_t returned by sio_open).
* The default value of zero means 'unknown'.
*/
#ifndef SLIP_SIO_SPEED
#define SLIP_SIO_SPEED(sio_fd) 0
#endif
enum slipif_recv_state {
SLIP_RECV_NORMAL,
SLIP_RECV_ESCAPE
};
struct slipif_priv {
sio_fd_t sd;
/* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */
struct pbuf *p, *q;
u8_t state;
u16_t i, recved;
#if SLIP_RX_FROM_ISR
struct pbuf *rxpackets;
#endif
};
/**
* Send a pbuf doing the necessary SLIP encapsulation
*
* Uses the serial layer's sio_send()
*
* @param netif the lwip network interface structure for this slipif
* @param p the pbuf chain packet to send
* @return always returns ERR_OK since the serial layer does not provide return values
*/
static err_t
slipif_output(struct netif *netif, struct pbuf *p)
{
struct slipif_priv *priv;
struct pbuf *q;
u16_t i;
u8_t c;
LWIP_ASSERT("netif != NULL", (netif != NULL));
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
LWIP_ASSERT("p != NULL", (p != NULL));
LWIP_DEBUGF(SLIP_DEBUG, ("slipif_output(%"U16_F"): sending %"U16_F" bytes\n", (u16_t)netif->num, p->tot_len));
priv = (struct slipif_priv *)netif->state;
/* Send pbuf out on the serial I/O device. */
/* Start with packet delimiter. */
sio_send(SLIP_END, priv->sd);
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:
/* need to escape this byte (0xC0 -> 0xDB, 0xDC) */
sio_send(SLIP_ESC, priv->sd);
sio_send(SLIP_ESC_END, priv->sd);
break;
case SLIP_ESC:
/* need to escape this byte (0xDB -> 0xDB, 0xDD) */
sio_send(SLIP_ESC, priv->sd);
sio_send(SLIP_ESC_ESC, priv->sd);
break;
default:
/* normal byte - no need for escaping */
sio_send(c, priv->sd);
break;
}
}
}
/* End with packet delimiter. */
sio_send(SLIP_END, priv->sd);
return ERR_OK;
}
#if LWIP_IPV4
/**
* Send a pbuf doing the necessary SLIP encapsulation
*
* Uses the serial layer's sio_send()
*
* @param netif the lwip network interface structure for this slipif
* @param p the pbuf chain packet to send
* @param ipaddr the ip address to send the packet to (not used for slipif)
* @return always returns ERR_OK since the serial layer does not provide return values
*/
static err_t
slipif_output_v4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr)
{
LWIP_UNUSED_ARG(ipaddr);
return slipif_output(netif, p);
}
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
/**
* Send a pbuf doing the necessary SLIP encapsulation
*
* Uses the serial layer's sio_send()
*
* @param netif the lwip network interface structure for this slipif
* @param p the pbuf chain packet to send
* @param ipaddr the ip address to send the packet to (not used for slipif)
* @return always returns ERR_OK since the serial layer does not provide return values
*/
static err_t
slipif_output_v6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr)
{
LWIP_UNUSED_ARG(ipaddr);
return slipif_output(netif, p);
}
#endif /* LWIP_IPV6 */
/**
* Handle the incoming SLIP stream character by character
*
* @param netif the lwip network interface structure for this slipif
* @param c received character (multiple calls to this function will
* return a complete packet, NULL is returned before - used for polling)
* @return The IP packet when SLIP_END is received
*/
static struct pbuf*
slipif_rxbyte(struct netif *netif, u8_t c)
{
struct slipif_priv *priv;
struct pbuf *t;
LWIP_ASSERT("netif != NULL", (netif != NULL));
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
priv = (struct slipif_priv *)netif->state;
switch (priv->state) {
case SLIP_RECV_NORMAL:
switch (c) {
case SLIP_END:
if (priv->recved > 0) {
/* Received whole packet. */
/* Trim the pbuf to the size of the received packet. */
pbuf_realloc(priv->q, priv->recved);
LINK_STATS_INC(link.recv);
LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet (%"U16_F" bytes)\n", priv->recved));
t = priv->q;
priv->p = priv->q = NULL;
priv->i = priv->recved = 0;
return t;
}
return NULL;
case SLIP_ESC:
priv->state = SLIP_RECV_ESCAPE;
return NULL;
default:
break;
} /* end switch (c) */
break;
case SLIP_RECV_ESCAPE:
/* un-escape END or ESC bytes, leave other bytes
(although that would be a protocol error) */
switch (c) {
case SLIP_ESC_END:
c = SLIP_END;
break;
case SLIP_ESC_ESC:
c = SLIP_ESC;
break;
default:
break;
}
priv->state = SLIP_RECV_NORMAL;
break;
default:
break;
} /* end switch (priv->state) */
/* byte received, packet not yet completely received */
if (priv->p == NULL) {
/* allocate a new pbuf */
LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));
priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - PBUF_LINK_ENCAPSULATION_HLEN), PBUF_POOL);
if (priv->p == NULL) {
LINK_STATS_INC(link.drop);
LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));
/* don't process any further since we got no pbuf to receive to */
return NULL;
}
if (priv->q != NULL) {
/* 'chain' the pbuf to the existing chain */
pbuf_cat(priv->q, priv->p);
} else {
/* p is the first pbuf in the chain */
priv->q = priv->p;
}
}
/* this automatically drops bytes if > SLIP_MAX_SIZE */
if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) {
((u8_t *)priv->p->payload)[priv->i] = c;
priv->recved++;
priv->i++;
if (priv->i >= priv->p->len) {
/* on to the next pbuf */
priv->i = 0;
if (priv->p->next != NULL && priv->p->next->len > 0) {
/* p is a chain, on to the next in the chain */
priv->p = priv->p->next;
} else {
/* p is a single pbuf, set it to NULL so next time a new
* pbuf is allocated */
priv->p = NULL;
}
}
}
return NULL;
}
/** Like slipif_rxbyte, but passes completed packets to netif->input
*
* @param netif The lwip network interface structure for this slipif
* @param c received character
*/
static void
slipif_rxbyte_input(struct netif *netif, u8_t c)
{
struct pbuf *p;
p = slipif_rxbyte(netif, c);
if (p != NULL) {
if (netif->input(p, netif) != ERR_OK) {
pbuf_free(p);
}
}
}
#if SLIP_USE_RX_THREAD
/**
* The SLIP input thread.
*
* Feed the IP layer with incoming packets
*
* @param nf the lwip network interface structure for this slipif
*/
static void
slipif_loop_thread(void *nf)
{
u8_t c;
struct netif *netif = (struct netif *)nf;
struct slipif_priv *priv = (struct slipif_priv *)netif->state;
while (1) {
if (sio_read(priv->sd, &c, 1) > 0) {
slipif_rxbyte_input(netif, c);
}
}
}
#endif /* SLIP_USE_RX_THREAD */
/**
* SLIP netif initialization
*
* Call the arch specific sio_open and remember
* the opened device in the state field of the netif.
*
* @param netif the lwip network interface structure for this slipif
* @return ERR_OK if serial line could be opened,
* ERR_MEM if no memory could be allocated,
* ERR_IF is serial line couldn't be opened
*
* @note netif->num must contain the number of the serial port to open
* (0 by default). If netif->state is != NULL, it is interpreted as an
* u8_t pointer pointing to the serial port number instead of netif->num.
*
*/
err_t
slipif_init(struct netif *netif)
{
struct slipif_priv *priv;
u8_t sio_num;
LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num));
/* Allocate private data */
priv = (struct slipif_priv *)mem_malloc(sizeof(struct slipif_priv));
if (!priv) {
return ERR_MEM;
}
netif->name[0] = 's';
netif->name[1] = 'l';
#if LWIP_IPV4
netif->output = slipif_output_v4;
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
netif->output_ip6 = slipif_output_v6;
#endif /* LWIP_IPV6 */
netif->mtu = SLIP_MAX_SIZE;
/* netif->state or netif->num contain the port number */
if (netif->state != NULL) {
sio_num = *(u8_t*)netif->state;
} else {
sio_num = netif->num;
}
/* Try to open the serial port. */
priv->sd = sio_open(sio_num);
if (!priv->sd) {
/* Opening the serial port failed. */
mem_free(priv);
return ERR_IF;
}
/* Initialize private data */
priv->p = NULL;
priv->q = NULL;
priv->state = SLIP_RECV_NORMAL;
priv->i = 0;
priv->recved = 0;
#if SLIP_RX_FROM_ISR
priv->rxpackets = NULL;
#endif
netif->state = priv;
/* initialize the snmp variables and counters inside the struct netif */
MIB2_INIT_NETIF(netif, snmp_ifType_slip, SLIP_SIO_SPEED(priv->sd));
#if SLIP_USE_RX_THREAD
/* Create a thread to poll the serial line. */
sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif,
SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);
#endif /* SLIP_USE_RX_THREAD */
return ERR_OK;
}
/**
* Polls the serial device and feeds the IP layer with incoming packets.
*
* @param netif The lwip network interface structure for this slipif
*/
void
slipif_poll(struct netif *netif)
{
u8_t c;
struct slipif_priv *priv;
LWIP_ASSERT("netif != NULL", (netif != NULL));
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
priv = (struct slipif_priv *)netif->state;
while (sio_tryread(priv->sd, &c, 1) > 0) {
slipif_rxbyte_input(netif, c);
}
}
#if SLIP_RX_FROM_ISR
/**
* Feeds the IP layer with incoming packets that were receive
*
* @param netif The lwip network interface structure for this slipif
*/
void
slipif_process_rxqueue(struct netif *netif)
{
struct slipif_priv *priv;
SYS_ARCH_DECL_PROTECT(old_level);
LWIP_ASSERT("netif != NULL", (netif != NULL));
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
priv = (struct slipif_priv *)netif->state;
SYS_ARCH_PROTECT(old_level);
while (priv->rxpackets != NULL) {
struct pbuf *p = priv->rxpackets;
#if SLIP_RX_QUEUE
/* dequeue packet */
struct pbuf *q = p;
while ((q->len != q->tot_len) && (q->next != NULL)) {
q = q->next;
}
priv->rxpackets = q->next;
q->next = NULL;
#else /* SLIP_RX_QUEUE */
priv->rxpackets = NULL;
#endif /* SLIP_RX_QUEUE */
SYS_ARCH_UNPROTECT(old_level);
if (netif->input(p, netif) != ERR_OK) {
pbuf_free(p);
}
SYS_ARCH_PROTECT(old_level);
}
}
/** Like slipif_rxbyte, but queues completed packets.
*
* @param netif The lwip network interface structure for this slipif
* @param data Received serial byte
*/
static void
slipif_rxbyte_enqueue(struct netif *netif, u8_t data)
{
struct pbuf *p;
struct slipif_priv *priv = (struct slipif_priv *)netif->state;
SYS_ARCH_DECL_PROTECT(old_level);
p = slipif_rxbyte(netif, data);
if (p != NULL) {
SYS_ARCH_PROTECT(old_level);
if (priv->rxpackets != NULL) {
#if SLIP_RX_QUEUE
/* queue multiple pbufs */
struct pbuf *q = p;
while (q->next != NULL) {
q = q->next;
}
q->next = p;
} else {
#else /* SLIP_RX_QUEUE */
pbuf_free(priv->rxpackets);
}
{
#endif /* SLIP_RX_QUEUE */
priv->rxpackets = p;
}
SYS_ARCH_UNPROTECT(old_level);
}
}
/**
* Process a received byte, completed packets are put on a queue that is
* fed into IP through slipif_process_rxqueue().
*
* This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled.
*
* @param netif The lwip network interface structure for this slipif
* @param data received character
*/
void
slipif_received_byte(struct netif *netif, u8_t data)
{
LWIP_ASSERT("netif != NULL", (netif != NULL));
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
slipif_rxbyte_enqueue(netif, data);
}
/**
* Process multiple received byte, completed packets are put on a queue that is
* fed into IP through slipif_process_rxqueue().
*
* This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled.
*
* @param netif The lwip network interface structure for this slipif
* @param data received character
* @param len Number of received characters
*/
void
slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len)
{
u8_t i;
u8_t *rxdata = data;
LWIP_ASSERT("netif != NULL", (netif != NULL));
LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
for (i = 0; i < len; i++, rxdata++) {
slipif_rxbyte_enqueue(netif, *rxdata);
}
}
#endif /* SLIP_RX_FROM_ISR */