Add FreeRTOS-Plus directory.

This commit is contained in:
Richard Barry 2012-08-11 21:34:11 +00:00
parent 7bd5f21ad5
commit f508a5f653
6798 changed files with 134949 additions and 19 deletions

View file

@ -0,0 +1,536 @@
FUTURE
* TODO: The lwIP source code makes some invalid assumptions on processor
word-length, storage sizes and alignment. See the mailing lists for
problems with exoteric (/DSP) architectures showing these problems.
We still have to fix some of these issues neatly.
* TODO: the ARP layer is not protected against concurrent access. If
you run from a multitasking OS, serialize access to ARP (called from
your network device driver and from a timeout thread.)
HISTORY
(HEAD)
2004-12-28 Leon Woestenberg <leon.woestenberg@gmx.net>
* etharp.*: Disabled multiple packets on the ARP queue.
This clashes with TCP queueing.
2004-11-28 Leon Woestenberg <leon.woestenberg@gmx.net>
* etharp.*: Fixed race condition from ARP request to ARP timeout.
Halved the ARP period, doubled the period counts.
ETHARP_MAX_PENDING now should be at least 2. This prevents
the counter from reaching 0 right away (which would allow
too little time for ARP responses to be received).
2004-11-25 Leon Woestenberg <leon.woestenberg@gmx.net>
* dhcp.c: Decline messages were not multicast but unicast.
* etharp.c: ETHARP_CREATE is renamed to ETHARP_TRY_HARD.
Do not try hard to insert arbitrary packet's source address,
etharp_ip_input() now calls etharp_update() without ETHARP_TRY_HARD.
etharp_query() now always DOES call ETHARP_TRY_HARD so that users
querying an address will see it appear in the cache (DHCP could
suffer from this when a server invalidly gave an in-use address.)
* ipv4/ip_addr.h: Renamed ip_addr_maskcmp() to _netcmp() as we are
comparing network addresses (identifiers), not the network masks
themselves.
* ipv4/ip_addr.c: ip_addr_isbroadcast() now checks that the given
IP address actually belongs to the network of the given interface.
2004-11-24 Kieran Mansley <kjm25@cam.ac.uk>
* tcp.c: Increment pcb->snd_buf when ACK is received in SYN_SENT state.
(STABLE-1_1_0-RC1)
2004-10-16 Kieran Mansley <kjm25@cam.ac.uk>
* tcp.c: Add code to tcp_recved() to send an ACK (window update) immediately,
even if one is already pending, if the rcv_wnd is above a threshold
(currently TCP_WND/2). This avoids waiting for a timer to expire to send a
delayed ACK in order to open the window if the stack is only receiving data.
2004-09-12 Kieran Mansley <kjm25@cam.ac.uk>
* tcp*.*: Retransmit time-out handling improvement by Sam Jansen.
2004-08-20 Tony Mountifield <tony@softins.co.uk>
* etharp.c: Make sure the first pbuf queued on an ARP entry
is properly ref counted.
2004-07-27 Tony Mountifield <tony@softins.co.uk>
* debug.h: Added (int) cast in LWIP_DEBUGF() to avoid compiler
warnings about comparison.
* pbuf.c: Stopped compiler complaining of empty if statement
when LWIP_DEBUGF() empty. Closed an unclosed comment.
* tcp.c: Stopped compiler complaining of empty if statement
when LWIP_DEBUGF() empty.
* ip.h Corrected IPH_TOS() macro: returns a byte, so doesn't need htons().
* inet.c: Added a couple of casts to quiet the compiler.
No need to test isascii(c) before isdigit(c) or isxdigit(c).
2004-07-22 Tony Mountifield <tony@softins.co.uk>
* inet.c: Made data types consistent in inet_ntoa().
Added casts for return values of checksum routines, to pacify compiler.
* ip_frag.c, tcp_out.c, sockets.c, pbuf.c
Small corrections to some debugging statements, to pacify compiler.
2004-07-21 Tony Mountifield <tony@softins.co.uk>
* etharp.c: Removed spurious semicolon and added missing end-of-comment.
* ethernetif.c Updated low_level_output() to match prototype for
netif->linkoutput and changed low_level_input() similarly for consistency.
* api_msg.c: Changed recv_raw() from int to u8_t, to match prototype
of raw_recv() in raw.h and so avoid compiler error.
* sockets.c: Added trivial (int) cast to keep compiler happier.
* ip.c, netif.c Changed debug statements to use the tidier ip4_addrN() macros.
(STABLE-1_0_0)
++ Changes:
2004-07-05 Leon Woestenberg <leon.woestenberg@gmx.net>
* sockets.*: Restructured LWIP_PRIVATE_TIMEVAL. Make sure
your cc.h file defines this either 1 or 0. If non-defined,
defaults to 1.
* .c: Added <string.h> and <errno.h> includes where used.
* etharp.c: Made some array indices unsigned.
2004-06-27 Leon Woestenberg <leon.woestenberg@gmx.net>
* netif.*: Added netif_set_up()/down().
* dhcp.c: Changes to restart program flow.
2004-05-07 Leon Woestenberg <leon.woestenberg@gmx.net>
* etharp.c: In find_entry(), instead of a list traversal per candidate, do a
single-pass lookup for different candidates. Should exploit locality.
2004-04-29 Leon Woestenberg <leon.woestenberg@gmx.net>
* tcp*.c: Cleaned up source comment documentation for Doxygen processing.
* opt.h: ETHARP_ALWAYS_INSERT option removed to comply with ARP RFC.
* etharp.c: update_arp_entry() only adds new ARP entries when adviced to by
the caller. This deprecates the ETHARP_ALWAYS_INSERT overrule option.
++ Bug fixes:
2004-04-27 Leon Woestenberg <leon.woestenberg@gmx.net>
* etharp.c: Applied patch of bug #8708 by Toni Mountifield with a solution
suggested by Timmy Brolin. Fix for 32-bit processors that cannot access
non-aligned 32-bit words, such as soms 32-bit TCP/IP header fields. Fix
is to prefix the 14-bit Ethernet headers with two padding bytes.
2004-04-23 Leon Woestenberg <leon.woestenberg@gmx.net>
* ip_addr.c: Fix in the ip_addr_isbroadcast() check.
* etharp.c: Fixed the case where the packet that initiates the ARP request
is not queued, and gets lost. Fixed the case where the packets destination
address is already known; we now always queue the packet and perform an ARP
request.
(STABLE-0_7_0)
++ Bug fixes:
* Fixed TCP bug for SYN_SENT to ESTABLISHED state transition.
* Fixed TCP bug in dequeueing of FIN from out of order segment queue.
* Fixed two possible NULL references in rare cases.
(STABLE-0_6_6)
++ Bug fixes:
* Fixed DHCP which did not include the IP address in DECLINE messages.
++ Changes:
* etharp.c has been hauled over a bit.
(STABLE-0_6_5)
++ Bug fixes:
* Fixed TCP bug induced by bad window resizing with unidirectional TCP traffic.
* Packets sent from ARP queue had invalid source hardware address.
++ Changes:
* Pass-by ARP requests do now update the cache.
++ New features:
* No longer dependent on ctype.h.
* New socket options.
* Raw IP pcb support.
(STABLE-0_6_4)
++ Bug fixes:
* Some debug formatters and casts fixed.
* Numereous fixes in PPP.
++ Changes:
* DEBUGF now is LWIP_DEBUGF
* pbuf_dechain() has been re-enabled.
* Mentioned the changed use of CVS branches in README.
(STABLE-0_6_3)
++ Bug fixes:
* Fixed pool pbuf memory leak in pbuf_alloc().
Occured if not enough PBUF_POOL pbufs for a packet pbuf chain.
Reported by Savin Zlobec.
* PBUF_POOL chains had their tot_len field not set for non-first
pbufs. Fixed in pbuf_alloc().
++ New features:
* Added PPP stack contributed by Marc Boucher
++ Changes:
* Now drops short packets for ICMP/UDP/TCP protocols. More robust.
* ARP queueuing now queues the latest packet instead of the first.
This is the RFC recommended behaviour, but can be overridden in
lwipopts.h.
(0.6.2)
++ Bugfixes:
* TCP has been fixed to deal with the new use of the pbuf->ref
counter.
* DHCP dhcp_inform() crash bug fixed.
++ Changes:
* Removed pbuf_pool_free_cache and pbuf_pool_alloc_cache. Also removed
pbuf_refresh(). This has sped up pbuf pool operations considerably.
Implemented by David Haas.
(0.6.1)
++ New features:
* The packet buffer implementation has been enhanced to support
zero-copy and copy-on-demand for packet buffers which have their
payloads in application-managed memory.
Implemented by David Haas.
Use PBUF_REF to make a pbuf refer to RAM. lwIP will use zero-copy
if an outgoing packet can be directly sent on the link, or perform
a copy-on-demand when necessary.
The application can safely assume the packet is sent, and the RAM
is available to the application directly after calling udp_send()
or similar function.
++ Bugfixes:
* ARP_QUEUEING should now correctly work for all cases, including
PBUF_REF.
Implemented by Leon Woestenberg.
++ Changes:
* IP_ADDR_ANY is no longer a NULL pointer. Instead, it is a pointer
to a '0.0.0.0' IP address.
* The packet buffer implementation is changed. The pbuf->ref counter
meaning has changed, and several pbuf functions have been
adapted accordingly.
* netif drivers have to be changed to set the hardware address length field
that must be initialized correctly by the driver (hint: 6 for Ethernet MAC).
See the contrib/ports/c16x cs8900 driver as a driver example.
* netif's have a dhcp field that must be initialized to NULL by the driver.
See the contrib/ports/c16x cs8900 driver as a driver example.
(0.5.x) This file has been unmaintained up to 0.6.1. All changes are
logged in CVS but have not been explained here.
(0.5.3) Changes since version 0.5.2
++ Bugfixes:
* memp_malloc(MEMP_API_MSG) could fail with multiple application
threads because it wasn't protected by semaphores.
++ Other changes:
* struct ip_addr now packed.
* The name of the time variable in arp.c has been changed to ctime
to avoid conflicts with the time() function.
(0.5.2) Changes since version 0.5.1
++ New features:
* A new TCP function, tcp_tmr(), now handles both TCP timers.
++ Bugfixes:
* A bug in tcp_parseopt() could cause the stack to hang because of a
malformed TCP option.
* The address of new connections in the accept() function in the BSD
socket library was not handled correctly.
* pbuf_dechain() did not update the ->tot_len field of the tail.
* Aborted TCP connections were not handled correctly in all
situations.
++ Other changes:
* All protocol header structs are now packed.
* The ->len field in the tcp_seg structure now counts the actual
amount of data, and does not add one for SYN and FIN segments.
(0.5.1) Changes since version 0.5.0
++ New features:
* Possible to run as a user process under Linux.
* Preliminary support for cross platform packed structs.
* ARP timer now implemented.
++ Bugfixes:
* TCP output queue length was badly initialized when opening
connections.
* TCP delayed ACKs were not sent correctly.
* Explicit initialization of BSS segment variables.
* read() in BSD socket library could drop data.
* Problems with memory alignment.
* Situations when all TCP buffers were used could lead to
starvation.
* TCP MSS option wasn't parsed correctly.
* Problems with UDP checksum calculation.
* IP multicast address tests had endianess problems.
* ARP requests had wrong destination hardware address.
++ Other changes:
* struct eth_addr changed from u16_t[3] array to u8_t[6].
* A ->linkoutput() member was added to struct netif.
* TCP and UDP ->dest_* struct members where changed to ->remote_*.
* ntoh* macros are now null definitions for big endian CPUs.
(0.5.0) Changes since version 0.4.2
++ New features:
* Redesigned operating system emulation layer to make porting easier.
* Better control over TCP output buffers.
* Documenation added.
++ Bugfixes:
* Locking issues in buffer management.
* Bugfixes in the sequential API.
* IP forwarding could cause memory leakage. This has been fixed.
++ Other changes:
* Directory structure somewhat changed; the core/ tree has been
collapsed.
(0.4.2) Changes since version 0.4.1
++ New features:
* Experimental ARP implementation added.
* Skeleton Ethernet driver added.
* Experimental BSD socket API library added.
++ Bugfixes:
* In very intense situations, memory leakage could occur. This has
been fixed.
++ Other changes:
* Variables named "data" and "code" have been renamed in order to
avoid name conflicts in certain compilers.
* Variable++ have in appliciable cases been translated to ++variable
since some compilers generate better code in the latter case.
(0.4.1) Changes since version 0.4
++ New features:
* TCP: Connection attempts time out earlier than data
transmissions. Nagle algorithm implemented. Push flag set on the
last segment in a burst.
* UDP: experimental support for UDP-Lite extensions.
++ Bugfixes:
* TCP: out of order segments were in some cases handled incorrectly,
and this has now been fixed. Delayed acknowledgements was broken
in 0.4, has now been fixed. Binding to an address that is in use
now results in an error. Reset connections sometimes hung an
application; this has been fixed.
* Checksum calculation sometimes failed for chained pbufs with odd
lengths. This has been fixed.
* API: a lot of bug fixes in the API. The UDP API has been improved
and tested. Error reporting and handling has been
improved. Logical flaws and race conditions for incoming TCP
connections has been found and removed.
* Memory manager: alignment issues. Reallocating memory sometimes
failed, this has been fixed.
* Generic library: bcopy was flawed and has been fixed.
++ Other changes:
* API: all datatypes has been changed from generic ones such as
ints, to specified ones such as u16_t. Functions that return
errors now have the correct type (err_t).
* General: A lot of code cleaned up and debugging code removed. Many
portability issues have been fixed.
* The license was changed; the advertising clause was removed.
* C64 port added.
* Thanks: Huge thanks go to Dagan Galarneau, Horst Garnetzke, Petri
Kosunen, Mikael Caleres, and Frits Wilmink for reporting and
fixing bugs!
(0.4) Changes since version 0.3.1
* Memory management has been radically changed; instead of
allocating memory from a shared heap, memory for objects that are
rapidly allocated and deallocated is now kept in pools. Allocation
and deallocation from those memory pools is very fast. The shared
heap is still present but is used less frequently.
* The memory, memory pool, and packet buffer subsystems now support
4-, 2-, or 1-byte alignment.
* "Out of memory" situations are handled in a more robust way.
* Stack usage has been reduced.
* Easier configuration of lwIP parameters such as memory usage,
TTLs, statistics gathering, etc. All configuration parameters are
now kept in a single header file "lwipopts.h".
* The directory structure has been changed slightly so that all
architecture specific files are kept under the src/arch
hierarchy.
* Error propagation has been improved, both in the protocol modules
and in the API.
* The code for the RTXC architecture has been implemented, tested
and put to use.
* Bugs have been found and corrected in the TCP, UDP, IP, API, and
the Internet checksum modules.
* Bugs related to porting between a 32-bit and a 16-bit architecture
have been found and corrected.
* The license has been changed slightly to conform more with the
original BSD license, including the advertisement clause.
(0.3.1) Changes since version 0.3
* Fix of a fatal bug in the buffer management. Pbufs with allocated
RAM never returned the RAM when the pbuf was deallocated.
* TCP congestion control, window updates and retransmissions did not
work correctly. This has now been fixed.
* Bugfixes in the API.
(0.3) Changes since version 0.2
* New and improved directory structure. All include files are now
kept in a dedicated include/ directory.
* The API now has proper error handling. A new function,
netconn_err(), now returns an error code for the connection in
case of errors.
* Improvements in the memory management subsystem. The system now
keeps a pointer to the lowest free memory block. A new function,
mem_malloc2() tries to allocate memory once, and if it fails tries
to free some memory and retry the allocation.
* Much testing has been done with limited memory
configurations. lwIP now does a better job when overloaded.
* Some bugfixes and improvements to the buffer (pbuf) subsystem.
* Many bugfixes in the TCP code:
- Fixed a bug in tcp_close().
- The TCP receive window was incorrectly closed when out of
sequence segments was received. This has been fixed.
- Connections are now timed-out of the FIN-WAIT-2 state.
- The initial congestion window could in some cases be too
large. This has been fixed.
- The retransmission queue could in some cases be screwed up. This
has been fixed.
- TCP RST flag now handled correctly.
- Out of sequence data was in some cases never delivered to the
application. This has been fixed.
- Retransmitted segments now contain the correct acknowledgment
number and advertised window.
- TCP retransmission timeout backoffs are not correctly computed
(ala BSD). After a number of retransmissions, TCP now gives up
the connection.
* TCP connections now are kept on three lists, one for active
connections, one for listening connections, and one for
connections that are in TIME-WAIT. This greatly speeds up the fast
timeout processing for sending delayed ACKs.
* TCP now provides proper feedback to the application when a
connection has been successfully set up.
* More comments have been added to the code. The code has also been
somewhat cleaned up.
(0.2) Initial public release.

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2001, 2002 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>
*
*/

View file

@ -0,0 +1,4 @@
src/ - The source code for the lwIP TCP/IP stack.
doc/ - The documentation for lwIP.
See also the FILES file in each subdirectory.

View file

@ -0,0 +1,92 @@
INTRODUCTION
lwIP is a small independent implementation of the TCP/IP protocol
suite that has been developed by Adam Dunkels at the Computer and
Networks Architectures (CNA) lab at the Swedish Institute of Computer
Science (SICS).
The focus of the lwIP TCP/IP implementation is to reduce the RAM usage
while still having a full scale TCP. This making lwIP suitable for use
in embedded systems with tenths of kilobytes of free RAM and room for
around 40 kilobytes of code ROM.
FEATURES
* IP (Internet Protocol) including packet forwarding over multiple
network interfaces
* ICMP (Internet Control Message Protocol) for network maintenance
and debugging
* UDP (User Datagram Protocol) including experimental UDP-lite
extensions
* TCP (Transmission Control Protocol) with congestion control, RTT
estimation and fast recovery/fast retransmit
* Specialized API for enhanced performance
* Optional Berkeley socket API
LICENSE
lwIP is freely available under a BSD license.
DEVELOPMENT
lwIP has grown into an excellent TCP/IP stack for embedded devices,
and developers using the stack often submit bug fixes, improvements,
and additions to the stack to further increase its usefulness.
Development of lwIP is hosted on Savannah, a central point for
software development, maintenance and distribution. Everyone can
help improve lwIP by use of Savannah's interface, CVS and the
mailing list. A core team of developers will commit changes to the
CVS source tree.
The lwIP TCP/IP stack is maintained in the 'lwip' CVS module and
contributions (such as platform ports) are in the 'contrib' module.
The CVS main trunk is the stable branch, which contains bug fixes and
tested features. The latest stable branch can be checked out by doing:
cvs -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip login
cvs -z3 -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip co lwip
The 'STABLE' tag in the stable branch will represent the most stable
revision (which may be somewhat older to protect us from errors
introduced by merges). This 'STABLE' tagged version can be checked out
by doing:
cvs -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip login
cvs -z3 -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip co -r STABLE lwip
The 'DEVEL' branch is the active development branch, which contains
bleeding edge changes, and may be instable. It can be checkout by doing:
cvs -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip login
cvs -z3 -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip co -r DEVEL lwip
The current contrib CVS tree can be checked out by doing:
cvs -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip login
cvs -z3 -d:pserver:anoncvs@subversions.gnu.org:/cvsroot/lwip co contrib
Last night's CVS tar ball can be downloaded from:
http://savannah.gnu.org/cvs.backups/lwip.tar.gz
The current CVS trees are web-browsable:
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/lwip/
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/contrib/
Submit patches and bugs via the lwIP project page:
http://savannah.nongnu.org/projects/lwip/
DOCUMENTATION
The original out-dated homepage of lwIP and Adam Dunkels' papers on
lwIP are at the official lwIP home page:
http://www.sics.se/~adam/lwip/
Self documentation of the source code is regularly extracted from the
current CVS sources and is available from this web page:
http://www.nongnu.org/lwip/
Reading Adam's papers, the files in docs/, browsing the source code
documentation and browsing the mailing list archives is a good way to
become familiar with the design of lwIP.
Adam Dunkels <adam@sics.se>
Leon Woestenberg <leon.woestenberg@gmx.net>

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __CC_H__
#define __CC_H__
#include "cpu.h"
typedef unsigned char u8_t;
typedef signed char s8_t;
typedef unsigned short u16_t;
typedef signed short s16_t;
typedef unsigned long u32_t;
typedef signed long s32_t;
typedef u32_t mem_ptr_t;
typedef int sys_prot_t;
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#endif /* __CC_H__ */

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __CPU_H__
#define __CPU_H__
#define BYTE_ORDER LITTLE_ENDIAN
#endif /* __CPU_H__ */

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __ARCH_INIT_H__
#define __ARCH_INIT_H__
#define TCPIP_INIT_DONE(arg) tcpip_init_done(arg)
void tcpip_init_done(void *);
int wait_for_tcpip_init(void);
#endif /* __ARCH_INIT_H__ */

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LIB_H__
#define __LIB_H__
#include <string.h>
#endif /* __LIB_H__ */

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __PERF_H__
#define __PERF_H__
#define PERF_START /* null definition */
#define PERF_STOP(x) /* null definition */
#endif /* __PERF_H__ */

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __SYS_RTXC_H__
#define __SYS_RTXC_H__
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#define SYS_MBOX_NULL (xQueueHandle)0
#define SYS_SEM_NULL (xSemaphoreHandle)0
typedef xSemaphoreHandle sys_sem_t;
typedef xQueueHandle sys_mbox_t;
typedef xTaskHandle sys_thread_t;
#endif /* __SYS_RTXC_H__ */

View file

@ -0,0 +1,385 @@
/*
* Copyright (c) 2001-2003 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>
*
*/
/* lwIP includes. */
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/mem.h"
/* Message queue constants. */
#define archMESG_QUEUE_LENGTH ( 6 )
#define archPOST_BLOCK_TIME_MS ( ( unsigned long ) 10000 )
struct timeoutlist
{
struct sys_timeouts timeouts;
xTaskHandle pid;
};
/* This is the number of threads that can be started with sys_thread_new() */
#define SYS_THREAD_MAX 4
#define lwipTCP_STACK_SIZE 600
#define lwipBASIC_SERVER_STACK_SIZE 250
static struct timeoutlist timeoutlist[SYS_THREAD_MAX];
static u16_t nextthread = 0;
int intlevel = 0;
/*-----------------------------------------------------------------------------------*/
// Creates an empty mailbox.
sys_mbox_t
sys_mbox_new(void)
{
xQueueHandle mbox;
mbox = xQueueCreate( archMESG_QUEUE_LENGTH, sizeof( void * ) );
return mbox;
}
/*-----------------------------------------------------------------------------------*/
/*
Deallocates a mailbox. If there are messages still present in the
mailbox when the mailbox is deallocated, it is an indication of a
programming error in lwIP and the developer should be notified.
*/
void
sys_mbox_free(sys_mbox_t mbox)
{
if( uxQueueMessagesWaiting( mbox ) )
{
/* Line for breakpoint. Should never break here! */
__asm volatile ( "NOP" );
}
vQueueDelete( mbox );
}
/*-----------------------------------------------------------------------------------*/
// Posts the "msg" to the mailbox.
void
sys_mbox_post(sys_mbox_t mbox, void *data)
{
xQueueSend( mbox, &data, ( portTickType ) ( archPOST_BLOCK_TIME_MS / portTICK_RATE_MS ) );
}
/*-----------------------------------------------------------------------------------*/
/*
Blocks the thread until a message arrives in the mailbox, but does
not block the thread longer than "timeout" milliseconds (similar to
the sys_arch_sem_wait() function). The "msg" argument is a result
parameter that is set by the function (i.e., by doing "*msg =
ptr"). The "msg" parameter maybe NULL to indicate that the message
should be dropped.
The return values are the same as for the sys_arch_sem_wait() function:
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
timeout.
Note that a function with a similar name, sys_mbox_fetch(), is
implemented by lwIP.
*/
u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
{
void *dummyptr;
portTickType StartTime, EndTime, Elapsed;
StartTime = xTaskGetTickCount();
if( msg == NULL )
{
msg = &dummyptr;
}
if( timeout != 0 )
{
if(pdTRUE == xQueueReceive( mbox, &(*msg), timeout ) )
{
EndTime = xTaskGetTickCount();
Elapsed = EndTime - StartTime;
if( Elapsed == 0 )
{
Elapsed = 1;
}
return ( Elapsed );
}
else // timed out blocking for message
{
*msg = NULL;
return SYS_ARCH_TIMEOUT;
}
}
else // block forever for a message.
{
while( pdTRUE != xQueueReceive( mbox, &(*msg), 10000 ) ) // time is arbitrary
{
;
}
EndTime = xTaskGetTickCount();
Elapsed = EndTime - StartTime;
if( Elapsed == 0 )
{
Elapsed = 1;
}
return ( Elapsed ); // return time blocked TBD test
}
}
/*-----------------------------------------------------------------------------------*/
// Creates and returns a new semaphore. The "count" argument specifies
// the initial state of the semaphore. TBD finish and test
sys_sem_t
sys_sem_new(u8_t count)
{
xSemaphoreHandle xSemaphore;
portENTER_CRITICAL();
vSemaphoreCreateBinary( xSemaphore );
if(count == 0) // Means it can't be taken
{
xSemaphoreTake(xSemaphore,1);
}
portEXIT_CRITICAL();
if( xSemaphore == NULL )
{
return NULL; // TBD need assert
}
else
{
return xSemaphore;
}
}
/*-----------------------------------------------------------------------------------*/
/*
Blocks the thread while waiting for the semaphore to be
signaled. If the "timeout" argument is non-zero, the thread should
only be blocked for the specified time (measured in
milliseconds).
If the timeout argument is non-zero, the return value is the number of
milliseconds spent waiting for the semaphore to be signaled. If the
semaphore wasn't signaled within the specified time, the return value is
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
(i.e., it was already signaled), the function may return zero.
Notice that lwIP implements a function with a similar name,
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
*/
u32_t
sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
{
portTickType StartTime, EndTime, Elapsed;
StartTime = xTaskGetTickCount();
if( timeout != 0)
{
if( xSemaphoreTake( sem, timeout ) == pdTRUE )
{
EndTime = xTaskGetTickCount();
Elapsed = EndTime - StartTime;
if( Elapsed == 0 )
{
Elapsed = 1;
}
return (Elapsed); // return time blocked TBD test
}
else
{
return SYS_ARCH_TIMEOUT;
}
}
else // must block without a timeout
{
while( xSemaphoreTake( sem, 10000 ) != pdTRUE )
{
;
}
EndTime = xTaskGetTickCount();
Elapsed = EndTime - StartTime;
if( Elapsed == 0 )
{
Elapsed = 1;
}
return ( Elapsed ); // return time blocked
}
}
/*-----------------------------------------------------------------------------------*/
// Signals a semaphore
void
sys_sem_signal(sys_sem_t sem)
{
xSemaphoreGive( sem );
}
/*-----------------------------------------------------------------------------------*/
// Deallocates a semaphore
void
sys_sem_free(sys_sem_t sem)
{
vQueueDelete( sem );
}
/*-----------------------------------------------------------------------------------*/
// Initialize sys arch
void
sys_init(void)
{
int i;
// Initialize the the per-thread sys_timeouts structures
// make sure there are no valid pids in the list
for(i = 0; i < SYS_THREAD_MAX; i++)
{
timeoutlist[i].pid = 0;
}
// keep track of how many threads have been created
nextthread = 0;
}
/*-----------------------------------------------------------------------------------*/
/*
Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
each thread has a list of timeouts which is represented as a linked
list of sys_timeout structures. The sys_timeouts structure holds a
pointer to a linked list of timeouts. This function is called by
the lwIP timeout scheduler and must not return a NULL value.
In a single threaded sys_arch implementation, this function will
simply return a pointer to a global sys_timeouts variable stored in
the sys_arch module.
*/
struct sys_timeouts *
sys_arch_timeouts(void)
{
int i;
xTaskHandle pid;
struct timeoutlist *tl;
pid = xTaskGetCurrentTaskHandle( );
for(i = 0; i < nextthread; i++)
{
tl = &timeoutlist[i];
if(tl->pid == pid)
{
return &(tl->timeouts);
}
}
// Error
return NULL;
}
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
// TBD
/*-----------------------------------------------------------------------------------*/
/*
Starts a new thread with priority "prio" that will begin its execution in the
function "thread()". The "arg" argument will be passed as an argument to the
thread() function. The id of the new thread is returned. Both the id and
the priority are system dependent.
*/
sys_thread_t sys_thread_new(void (* thread)(void *arg), void *arg, int prio)
{
xTaskHandle CreatedTask;
int result;
static int iCall = 0;
if( iCall == 0 )
{
/* The first time this is called we are creating the lwIP handler. */
result = xTaskCreate( thread, ( signed char * ) "lwIP", lwipTCP_STACK_SIZE, arg, prio, &CreatedTask );
iCall++;
}
else
{
result = xTaskCreate( thread, ( signed char * ) "WEBSvr", lwipBASIC_SERVER_STACK_SIZE, arg, prio, &CreatedTask );
}
// For each task created, store the task handle (pid) in the timers array.
// This scheme doesn't allow for threads to be deleted
timeoutlist[nextthread++].pid = CreatedTask;
if(result == pdPASS)
{
return CreatedTask;
}
else
{
return NULL;
}
}
/*
This optional function does a "fast" critical region protection and returns
the previous protection level. This function is only called during very short
critical regions. An embedded system which supports ISR-based drivers might
want to implement this function by disabling interrupts. Task-based systems
might want to implement this by using a mutex or disabling tasking. This
function should support recursive calls from the same task or interrupt. In
other words, sys_arch_protect() could be called while already protected. In
that case the return value indicates that it is already protected.
sys_arch_protect() is only required if your port is supporting an operating
system.
*/
sys_prot_t sys_arch_protect(void)
{
vPortEnterCritical();
return 1;
}
/*
This optional function does a "fast" set of critical region protection to the
value specified by pval. See the documentation for sys_arch_protect() for
more information. This function is only required if your port is supporting
an operating system.
*/
void sys_arch_unprotect(sys_prot_t pval)
{
( void ) pval;
vPortExitCritical();
}

View file

@ -0,0 +1,62 @@
1 Introduction
This document describes some guidelines for people participating
in lwIP development.
2 How to contribute to lwIP
Here is a short list of suggestions to anybody working with lwIP and
trying to contribute bug reports, fixes, enhancements, platform ports etc.
First of all as you may already know lwIP is a volunteer project so feedback
to fixes or questions might often come late. Hopefully the bug and patch tracking
features of Savannah help us not lose users' input.
2.1 Source code style:
1. do not use tabs.
2. indentation is two spaces per level (i.e. per tab).
3. end debug messages with a trailing newline (\n).
4. one space between keyword and opening bracket.
5. no space between function and opening bracket.
6. one space and no newline before opening curly braces of a block.
7. closing curly brace on a single line.
8. spaces surrounding assignment and comparisons.
9. use current source code style as further reference.
2.2 Source code documentation style:
1. JavaDoc compliant and Doxygen compatible.
2. Function documentation above functions in .c files, not .h files.
(This forces you to synchronize documentation and implementation.)
3. Use current documentation style as further reference.
2.3 Bug reports and patches:
1. Make sure you are reporting bugs or send patches against the latest
sources. (From the latest release and/or the current CVS sources.)
2. If you think you found a bug make sure it's not already filed in the
bugtracker at Savannah.
3. If you have a fix put the patch on Savannah. If it is a patch that affects
both core and arch specific stuff please separate them so that the core can
be applied separately while leaving the other patch 'open'. The prefered way
is to NOT touch archs you can't test and let maintainers take care of them.
This is a good way to see if they are used at all - the same goes for unix
netifs except tapif.
4. Do not file a bug and post a fix to it to the patch area. Either a bug report
or a patch will be enough.
If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area.
5. Trivial patches (compiler warning, indentation and spelling fixes or anything obvious which takes a line or two)
can go to the lwip-users list. This is still the fastest way of interaction and the list is not so crowded
as to allow for loss of fixes. Putting bugs on Savannah and subsequently closing them is too much an overhead
for reporting a compiler warning fix.
6. Patches should be specific to a single change or to related changes.Do not mix bugfixes with spelling and other
trivial fixes unless the bugfix is trivial too.Do not reorganize code and rename identifiers in the same patch you
change behaviour if not necessary.A patch is easier to read and understand if it's to the point and short than
if it's not to the point and long :) so the chances for it to be applied are greater.
2.4 Platform porters:
1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and
you think it could benefit others[1] you might want discuss this on the mailing list. You
can also ask for CVS access to submit and maintain your port in the contrib CVS module.

View file

@ -0,0 +1,292 @@
Raw TCP/IP interface for lwIP
Authors: Adam Dunkels, Leon Woestenberg
lwIP provides two Application Program's Interfaces (APIs) for programs
to use for communication with the TCP/IP code:
* low-level "core" / "callback" or "raw" API.
* higher-level "sequential" API.
The sequential API provides a way for ordinary, sequential, programs
to use the lwIP stack. It is quite similar to the BSD socket API. The
model of execution is based on the blocking open-read-write-close
paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
code and the application program must reside in different execution
contexts (threads).
** The remainder of this document discusses the "raw" API. **
The raw TCP/IP interface allows the application program to integrate
better with the TCP/IP code. Program execution is event based by
having callback functions being called from within the TCP/IP
code. The TCP/IP code and the application program both run in the same
thread. The sequential API has a much higher overhead and is not very
well suited for small systems since it forces a multithreaded paradigm
on the application.
The raw TCP/IP interface is not only faster in terms of code execution
time but is also less memory intensive. The drawback is that program
development is somewhat harder and application programs written for
the raw TCP/IP interface are more difficult to understand. Still, this
is the preferred way of writing applications that should be small in
code size and memory usage.
Both APIs can be used simultaneously by different application
programs. In fact, the sequential API is implemented as an application
program using the raw TCP/IP interface.
--- Callbacks
Program execution is driven by callbacks. Each callback is an ordinary
C function that is called from within the TCP/IP code. Every callback
function is passed the current TCP or UDP connection state as an
argument. Also, in order to be able to keep program specific state,
the callback functions are called with a program specified argument
that is independent of the TCP/IP state.
The function for setting the application connection state is:
- void tcp_arg(struct tcp_pcb *pcb, void *arg)
Specifies the program specific state that should be passed to all
other callback functions. The "pcb" argument is the current TCP
connection control block, and the "arg" argument is the argument
that will be passed to the callbacks.
--- TCP connection setup
The functions used for setting up connections is similar to that of
the sequential API and of the BSD socket API. A new TCP connection
identifier (i.e., a protocol control block - PCB) is created with the
tcp_new() function. This PCB can then be either set to listen for new
incoming connections or be explicitly connected to another host.
- struct tcp_pcb *tcp_new(void)
Creates a new connection identifier (PCB). If memory is not
available for creating the new pcb, NULL is returned.
- err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port)
Binds the pcb to a local IP address and port number. The IP address
can be specified as IP_ADDR_ANY in order to bind the connection to
all local IP addresses.
If another connection is bound to the same port, the function will
return ERR_USE, otherwise ERR_OK is returned.
- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb)
Commands a pcb to start listening for incoming connections. When an
incoming connection is accepted, the function specified with the
tcp_accept() function will be called. The pcb will have to be bound
to a local port with the tcp_bind() function.
The tcp_listen() function returns a new connection identifier, and
the one passed as an argument to the function will be
deallocated. The reason for this behavior is that less memory is
needed for a connection that is listening, so tcp_listen() will
reclaim the memory needed for the original connection and allocate a
new smaller memory block for the listening connection.
tcp_listen() may return NULL if no memory was available for the
listening connection. If so, the memory associated with the pcb
passed as an argument to tcp_listen() will not be deallocated.
- void tcp_accept(struct tcp_pcb *pcb,
err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
err_t err))
Specified the callback function that should be called when a new
connection arrives on a listening connection.
- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port, err_t (* connected)(void *arg,
struct tcp_pcb *tpcb,
err_t err));
Sets up the pcb to connect to the remote host and sends the
initial SYN segment which opens the connection.
The tcp_connect() function returns immediately; it does not wait for
the connection to be properly setup. Instead, it will call the
function specified as the fourth argument (the "connected" argument)
when the connection is established. If the connection could not be
properly established, either because the other host refused the
connection or because the other host didn't answer, the "connected"
function will be called with an the "err" argument set accordingly.
The tcp_connect() function can return ERR_MEM if no memory is
available for enqueueing the SYN segment. If the SYN indeed was
enqueued successfully, the tcp_connect() function returns ERR_OK.
--- Sending TCP data
TCP data is sent by enqueueing the data with a call to
tcp_write(). When the data is successfully transmitted to the remote
host, the application will be notified with a call to a specified
callback function.
- err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len,
u8_t copy)
Enqueues the data pointed to by the argument dataptr. The length of
the data is passed as the len parameter. The copy argument is either
0 or 1 and indicates whether the new memory should be allocated for
the data to be copied into. If the argument is 0, no new memory
should be allocated and the data should only be referenced by
pointer.
The tcp_write() function will fail and return ERR_MEM if the length
of the data exceeds the current send buffer size or if the length of
the queue of outgoing segment is larger than the upper limit defined
in lwipopts.h. The number of bytes available in the output queue can
be retrieved with the tcp_sndbuf() function.
The proper way to use this function is to call the function with at
most tcp_sndbuf() bytes of data. If the function returns ERR_MEM,
the application should wait until some of the currently enqueued
data has been successfully received by the other host and try again.
- void tcp_sent(struct tcp_pcb *pcb,
err_t (* sent)(void *arg, struct tcp_pcb *tpcb,
u16_t len))
Specifies the callback function that should be called when data has
successfully been received (i.e., acknowledged) by the remote
host. The len argument passed to the callback function gives the
amount bytes that was acknowledged by the last acknowledgment.
--- Receiving TCP data
TCP data reception is callback based - an application specified
callback function is called when new data arrives. When the
application has taken the data, it has to call the tcp_recved()
function to indicate that TCP can advertise increase the receive
window.
- void tcp_recv(struct tcp_pcb *pcb,
err_t (* recv)(void *arg, struct tcp_pcb *tpcb,
struct pbuf *p, err_t err))
Sets the callback function that will be called when new data
arrives. The callback function will be passed a NULL pbuf to
indicate that the remote host has closed the connection.
- void tcp_recved(struct tcp_pcb *pcb, u16_t len)
Must be called when the application has received the data. The len
argument indicates the length of the received data.
--- Application polling
When a connection is idle (i.e., no data is either transmitted or
received), lwIP will repeatedly poll the application by calling a
specified callback function. This can be used either as a watchdog
timer for killing connections that have stayed idle for too long, or
as a method of waiting for memory to become available. For instance,
if a call to tcp_write() has failed because memory wasn't available,
the application may use the polling functionality to call tcp_write()
again when the connection has been idle for a while.
- void tcp_poll(struct tcp_pcb *pcb, u8_t interval,
err_t (* poll)(void *arg, struct tcp_pcb *tpcb))
Specifies the polling interval and the callback function that should
be called to poll the application. The interval is specified in
number of TCP coarse grained timer shots, which typically occurs
twice a second. An interval of 10 means that the application would
be polled every 5 seconds.
--- Closing and aborting connections
- err_t tcp_close(struct tcp_pcb *pcb)
Closes the connection. The function may return ERR_MEM if no memory
was available for closing the connection. If so, the application
should wait and try again either by using the acknowledgment
callback or the polling functionality. If the close succeeds, the
function returns ERR_OK.
The pcb is deallocated by the TCP code after a call to tcp_close().
- void tcp_abort(struct tcp_pcb *pcb)
Aborts the connection by sending a RST (reset) segment to the remote
host. The pcb is deallocated. This function never fails.
If a connection is aborted because of an error, the application is
alerted of this event by the err callback. Errors that might abort a
connection are when there is a shortage of memory. The callback
function to be called is set using the tcp_err() function.
- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg,
err_t err))
The error callback function does not get the pcb passed to it as a
parameter since the pcb may already have been deallocated.
--- Lower layer TCP interface
TCP provides a simple interface to the lower layers of the
system. During system initialization, the function tcp_init() has
to be called before any other TCP function is called. When the system
is running, the two timer functions tcp_fasttmr() and tcp_slowtmr()
must be called with regular intervals. The tcp_fasttmr() should be
called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and
tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds.
--- UDP interface
The UDP interface is similar to that of TCP, but due to the lower
level of complexity of UDP, the interface is significantly simpler.
- struct udp_pcb *udp_new(void)
Creates a new UDP pcb which can be used for UDP communication. The
pcb is not active until it has either been bound to a local address
or connected to a remote address.
- void udp_remove(struct udp_pcb *pcb)
Removes and deallocates the pcb.
- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port)
Binds the pcb to a local address. The IP-address argument "ipaddr"
can be IP_ADDR_ANY to indicate that it should listen to any local IP
address. The function currently always return ERR_OK.
- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port)
Sets the remote end of the pcb. This function does not generate any
network traffic, but only set the remote address of the pcb.
- err_t udp_disconnect(struct udp_pcb *pcb)
Remove the remote end of the pcb. This function does not generate
any network traffic, but only removes the remote address of the pcb.
- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)
Sends the pbuf p. The pbuf is not deallocated.
- void udp_recv(struct udp_pcb *pcb,
void (* recv)(void *arg, struct udp_pcb *upcb,
struct pbuf *p,
struct ip_addr *addr,
u16_t port),
void *recv_arg)
Specifies a callback function that should be called when a UDP
datagram is received.

View file

@ -0,0 +1,135 @@
Daily Use Guide for using Savannah for lwIP
Table of Contents:
1 - Obtaining lwIP from the CVS repository
2 - Committers/developers CVS access using SSH (to be written)
3 - Merging from DEVEL branch to main trunk (stable branch)
4 - How to release lwIP
1 Obtaining lwIP from the CVS repository
----------------------------------------
To perform an anonymous CVS checkout of the main trunk (this is where
bug fixes and incremental enhancements occur), do this:
export CVS_RSH=ssh
cvs -d:ext:anoncvs@subversions.gnu.org:/cvsroot/lwip checkout lwip
(If SSH asks about authenticity of the host, you can check the key
fingerprint against http://savannah.nongnu.org/cvs/?group=lwip)
Or, obtain a stable branch (updated with bug fixes only) as follows:
cvs -d:ext:anoncvs@subversions.gnu.org:/cvsroot/lwip checkout -r STABLE-0_7 -d lwip-0.7 lwip
Or, obtain a specific (fixed) release as follows:
cvs -d:ext:anoncvs@subversions.gnu.org:/cvsroot/lwip checkout -r STABLE-0_7_0 -d lwip-0.7.0 lwip
Or, obtain a development branch (considered unstable!) as follows:
cvs -d:ext:anoncvs@subversions.gnu.org:/cvsroot/lwip checkout -r DEVEL -d lwip-DEVEL lwip
3 Committers/developers CVS access using SSH
--------------------------------------------
The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption.
As such, CVS commits to the server occur through a SSH tunnel for project members.
To create a SSH2 key pair in UNIX-like environments, do this:
ssh-keygen -t dsa
Under Windows, a recommended SSH client is "PuTTY", freely available with good
documentation and a graphic user interface. Use its key generator.
Now paste the id_dsa.pub contents into your Savannah account public key list. Wait
a while so that Savannah can update its configuration (This can take minutes).
Try to login using SSH:
ssh -v your_login@subversions.gnu.org
If it tells you:
Authenticating with public key "your_key_name"...
Server refused to allocate pty
then you could login; Savannah refuses to give you a shell - which is OK, as we
are allowed to use SSH for CVS only. Now, you should be able to do this:
export CVS_RSH=ssh
cvs -d:ext:your_login@subversions.gnu.org:/cvsroot/lwip checkout lwip
after which you can edit your local files with bug fixes or new features and
commit them. Make sure you know what you are doing when using CVS to make
changes on the repository. If in doubt, ask on the lwip-members mailing list.
3 Merging from DEVEL branch to main trunk (stable)
--------------------------------------------------
Merging is a delicate process in CVS and requires the
following disciplined steps in order to prevent conflicts
in the future. Conflicts can be hard to solve!
Merging from branch A to branch B requires that the A branch
has a tag indicating the previous merger. This tag is called
'merged_from_A_to_B'. After merging, the tag is moved in the
A branch to remember this merger for future merge actions.
IMPORTANT: AFTER COMMITTING A SUCCESFUL MERGE IN THE
REPOSITORY, THE TAG MUST BE SET ON THE SOURCE BRANCH OF THE
MERGE ACTION (REPLACING EXISTING TAGS WITH THE SAME NAME).
Merge all changes in DEVEL since our last merge to main:
In the working copy of the main trunk:
cvs update -P -jmerged_from_DEVEL_to_main -jDEVEL
(This will apply the changes between 'merged_from_DEVEL_to_main'
and 'DEVEL' to your work set of files)
We can now commit the merge result.
cvs commit -R -m "Merged from DEVEL to main."
If this worked out OK, we now move the tag in the DEVEL branch
to this merge point, so we can use this point for future merges:
cvs rtag -F -r DEVEL merged_from_DEVEL_to_main lwip
4 How to release lwIP
---------------------
First, checkout a clean copy of the branch to be released. Tag this set with
tag name "STABLE-0_6_3". (I use release number 0.6.3 throughout this example).
Login CVS using pserver authentication, then export a clean copy of the
tagged tree. Export is similar to a checkout, except that the CVS metadata
is not created locally.
export CVS_RSH=ssh
cvs -d:ext:anoncvs@subversions.gnu.org:/cvsroot/lwip export -r STABLE-0_6_3 -d lwip-0.6.3 lwip
Archive this directory using tar, gzip'd, bzip2'd and zip'd.
tar czvf lwip-0.6.3.tar.gz lwip-0.6.3
tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3
zip -r lwip-0.6.3.zip lwip-0.6.3
Now, sign the archives with a detached GPG binary signature as follows:
gpg -b lwip-0.6.3.tar.gz
gpg -b lwip-0.6.3.tar.bz2
gpg -b lwip-0.6.3.zip
Upload these files using anonymous FTP:
ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
ncftp>mput *0.6.3.*
Additionally, you may post a news item on Savannah, like this:
A new 0.6.3 release is now available here:
http://savannah.nongnu.org/files/?group=lwip&highlight=0.6.3
You will have to submit this via the user News interface, then approve
this via the Administrator News interface.

View file

@ -0,0 +1,194 @@
sys_arch interface for lwIP 0.6++
Author: Adam Dunkels
The operating system emulation layer provides a common interface
between the lwIP code and the underlying operating system kernel. The
general idea is that porting lwIP to new architectures requires only
small changes to a few header files and a new sys_arch
implementation. It is also possible to do a sys_arch implementation
that does not rely on any underlying operating system.
The sys_arch provides semaphores and mailboxes to lwIP. For the full
lwIP functionality, multiple threads support can be implemented in the
sys_arch, but this is not required for the basic lwIP
functionality. Previous versions of lwIP required the sys_arch to
implement timer scheduling as well but as of lwIP 0.5 this is
implemented in a higher layer.
In addition to the source file providing the functionality of sys_arch,
the OS emulation layer must provide several header files defining
macros used throughout lwip. The files required and the macros they
must define are listed below the sys_arch description.
Semaphores can be either counting or binary - lwIP works with both
kinds. Mailboxes are used for message passing and can be implemented
either as a queue which allows multiple messages to be posted to a
mailbox, or as a rendez-vous point where only one message can be
posted at a time. lwIP works with both kinds, but the former type will
be more efficient. A message in a mailbox is just a pointer, nothing
more.
Semaphores are represented by the type "sys_sem_t" which is typedef'd
in the sys_arch.h file. Mailboxes are equivalently represented by the
type "sys_mbox_t". lwIP does not place any restrictions on how
sys_sem_t or sys_mbox_t are represented internally.
The following functions must be implemented by the sys_arch:
- void sys_init(void)
Is called to initialize the sys_arch layer.
- sys_sem_t sys_sem_new(u8_t count)
Creates and returns a new semaphore. The "count" argument specifies
the initial state of the semaphore.
- void sys_sem_free(sys_sem_t sem)
Deallocates a semaphore.
- void sys_sem_signal(sys_sem_t sem)
Signals a semaphore.
- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
Blocks the thread while waiting for the semaphore to be
signaled. If the "timeout" argument is non-zero, the thread should
only be blocked for the specified time (measured in
milliseconds).
If the timeout argument is non-zero, the return value is the number of
milliseconds spent waiting for the semaphore to be signaled. If the
semaphore wasn't signaled within the specified time, the return value is
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
(i.e., it was already signaled), the function may return zero.
Notice that lwIP implements a function with a similar name,
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
- sys_mbox_t sys_mbox_new(void)
Creates an empty mailbox.
- void sys_mbox_free(sys_mbox_t mbox)
Deallocates a mailbox. If there are messages still present in the
mailbox when the mailbox is deallocated, it is an indication of a
programming error in lwIP and the developer should be notified.
- void sys_mbox_post(sys_mbox_t mbox, void *msg)
Posts the "msg" to the mailbox.
- u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
Blocks the thread until a message arrives in the mailbox, but does
not block the thread longer than "timeout" milliseconds (similar to
the sys_arch_sem_wait() function). The "msg" argument is a result
parameter that is set by the function (i.e., by doing "*msg =
ptr"). The "msg" parameter maybe NULL to indicate that the message
should be dropped.
The return values are the same as for the sys_arch_sem_wait() function:
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
timeout.
Note that a function with a similar name, sys_mbox_fetch(), is
implemented by lwIP.
- struct sys_timeouts *sys_arch_timeouts(void)
Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
each thread has a list of timeouts which is repressented as a linked
list of sys_timeout structures. The sys_timeouts structure holds a
pointer to a linked list of timeouts. This function is called by
the lwIP timeout scheduler and must not return a NULL value.
In a single threadd sys_arch implementation, this function will
simply return a pointer to a global sys_timeouts variable stored in
the sys_arch module.
If threads are supported by the underlying operating system and if
such functionality is needed in lwIP, the following function will have
to be implemented as well:
- sys_thread_t sys_thread_new(void (* thread)(void *arg), void *arg, int prio)
Starts a new thread with priority "prio" that will begin its execution in the
function "thread()". The "arg" argument will be passed as an argument to the
thread() function. The id of the new thread is returned. Both the id and
the priority are system dependent.
- sys_prot_t sys_arch_protect(void)
This optional function does a "fast" critical region protection and returns
the previous protection level. This function is only called during very short
critical regions. An embedded system which supports ISR-based drivers might
want to implement this function by disabling interrupts. Task-based systems
might want to implement this by using a mutex or disabling tasking. This
function should support recursive calls from the same task or interrupt. In
other words, sys_arch_protect() could be called while already protected. In
that case the return value indicates that it is already protected.
sys_arch_protect() is only required if your port is supporting an operating
system.
- void sys_arch_unprotect(sys_prot_t pval)
This optional function does a "fast" set of critical region protection to the
value specified by pval. See the documentation for sys_arch_protect() for
more information. This function is only required if your port is supporting
an operating system.
-------------------------------------------------------------------------------
Additional files required for the "OS support" emulation layer:
-------------------------------------------------------------------------------
cc.h - Architecture environment, some compiler specific, some
environment specific (probably should move env stuff
to sys_arch.h.)
Typedefs for the types used by lwip -
u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t
Compiler hints for packing lwip's structures -
PACK_STRUCT_FIELD(x)
PACK_STRUCT_STRUCT
PACK_STRUCT_BEGIN
PACK_STRUCT_END
Platform specific diagnostic output -
LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.
"lightweight" synchronization mechanisms -
SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.
SYS_ARCH_PROTECT(x) - enter protection mode.
SYS_ARCH_UNPROTECT(x) - leave protection mode.
If the compiler does not provide memset() this file must include a
definition of it, or include a file which defines it.
This file must either include a system-local <errno.h> which defines
the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO
to make lwip/arch.h define the codes which are used throughout.
perf.h - Architecture specific performance measurement.
Measurement calls made throughout lwip, these can be defined to nothing.
PERF_START - start measuring something.
PERF_STOP(x) - stop measuring something, and record the result.
sys_arch.h - Tied to sys_arch.c
Arch dependent types for the following objects:
sys_sem_t, sys_mbox_t, sys_thread_t,
And, optionally:
sys_prot_t
Defines to set vars of sys_mbox_t and sys_sem_t to NULL.
SYS_MBOX_NULL NULL
SYS_SEM_NULL NULL

View file

@ -0,0 +1,13 @@
api/ - The code for the high-level wrapper API. Not needed if
you use the lowel-level call-back/raw API.
core/ - The core of the TPC/IP stack; protocol implementations,
memory and buffer management, and the low-level raw API.
include/ - lwIP include files.
netif/ - Generic network interface device drivers are kept here,
as well as the ARP module.
For more information on the various subdirectories, check the FILES
file in each directory.

View file

@ -0,0 +1,729 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/* This is the part of the API that is linked with
the application */
#include "lwip/opt.h"
#include "lwip/api.h"
#include "lwip/api_msg.h"
#include "lwip/memp.h"
struct
netbuf *netbuf_new(void)
{
struct netbuf *buf;
buf = memp_malloc(MEMP_NETBUF);
if (buf != NULL) {
buf->p = NULL;
buf->ptr = NULL;
return buf;
} else {
return NULL;
}
}
void
netbuf_delete(struct netbuf *buf)
{
if (buf != NULL) {
if (buf->p != NULL) {
pbuf_free(buf->p);
buf->p = buf->ptr = NULL;
}
memp_free(MEMP_NETBUF, buf);
}
}
void *
netbuf_alloc(struct netbuf *buf, u16_t size)
{
/* Deallocate any previously allocated memory. */
if (buf->p != NULL) {
pbuf_free(buf->p);
}
buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
if (buf->p == NULL) {
return NULL;
}
buf->ptr = buf->p;
return buf->p->payload;
}
void
netbuf_free(struct netbuf *buf)
{
if (buf->p != NULL) {
pbuf_free(buf->p);
}
buf->p = buf->ptr = NULL;
}
void
netbuf_ref(struct netbuf *buf, void *dataptr, u16_t size)
{
if (buf->p != NULL) {
pbuf_free(buf->p);
}
buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
buf->p->payload = dataptr;
buf->p->len = buf->p->tot_len = size;
buf->ptr = buf->p;
}
void
netbuf_chain(struct netbuf *head, struct netbuf *tail)
{
pbuf_chain(head->p, tail->p);
head->ptr = head->p;
memp_free(MEMP_NETBUF, tail);
}
u16_t
netbuf_len(struct netbuf *buf)
{
return buf->p->tot_len;
}
err_t
netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
{
if (buf->ptr == NULL) {
return ERR_BUF;
}
*dataptr = buf->ptr->payload;
*len = buf->ptr->len;
return ERR_OK;
}
s8_t
netbuf_next(struct netbuf *buf)
{
if (buf->ptr->next == NULL) {
return -1;
}
buf->ptr = buf->ptr->next;
if (buf->ptr->next == NULL) {
return 1;
}
return 0;
}
void
netbuf_first(struct netbuf *buf)
{
buf->ptr = buf->p;
}
void
netbuf_copy_partial(struct netbuf *buf, void *dataptr, u16_t len, u16_t offset)
{
struct pbuf *p;
u16_t i, left;
left = 0;
if(buf == NULL || dataptr == NULL) {
return;
}
/* This implementation is bad. It should use bcopy
instead. */
for(p = buf->p; left < len && p != NULL; p = p->next) {
if (offset != 0 && offset >= p->len) {
offset -= p->len;
} else {
for(i = offset; i < p->len; ++i) {
((char *)dataptr)[left] = ((char *)p->payload)[i];
if (++left >= len) {
return;
}
}
offset = 0;
}
}
}
void
netbuf_copy(struct netbuf *buf, void *dataptr, u16_t len)
{
netbuf_copy_partial(buf, dataptr, len, 0);
}
struct ip_addr *
netbuf_fromaddr(struct netbuf *buf)
{
return buf->fromaddr;
}
u16_t
netbuf_fromport(struct netbuf *buf)
{
return buf->fromport;
}
struct
netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u16_t proto,
void (*callback)(struct netconn *, enum netconn_evt, u16_t len))
{
struct netconn *conn;
struct api_msg *msg;
conn = memp_malloc(MEMP_NETCONN);
if (conn == NULL) {
return NULL;
}
conn->err = ERR_OK;
conn->type = t;
conn->pcb.tcp = NULL;
if ((conn->mbox = sys_mbox_new()) == SYS_MBOX_NULL) {
memp_free(MEMP_NETCONN, conn);
return NULL;
}
conn->recvmbox = SYS_MBOX_NULL;
conn->acceptmbox = SYS_MBOX_NULL;
conn->sem = SYS_SEM_NULL;
conn->state = NETCONN_NONE;
conn->socket = 0;
conn->callback = callback;
conn->recv_avail = 0;
if((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
memp_free(MEMP_NETCONN, conn);
return NULL;
}
msg->type = API_MSG_NEWCONN;
msg->msg.msg.bc.port = proto; /* misusing the port field */
msg->msg.conn = conn;
api_msg_post(msg);
sys_mbox_fetch(conn->mbox, NULL);
memp_free(MEMP_API_MSG, msg);
if ( conn->err != ERR_OK ) {
memp_free(MEMP_NETCONN, conn);
return NULL;
}
return conn;
}
struct
netconn *netconn_new(enum netconn_type t)
{
return netconn_new_with_proto_and_callback(t,0,NULL);
}
struct
netconn *netconn_new_with_callback(enum netconn_type t,
void (*callback)(struct netconn *, enum netconn_evt, u16_t len))
{
return netconn_new_with_proto_and_callback(t,0,callback);
}
err_t
netconn_delete(struct netconn *conn)
{
struct api_msg *msg;
void *mem;
if (conn == NULL) {
return ERR_OK;
}
if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
return ERR_MEM;
}
msg->type = API_MSG_DELCONN;
msg->msg.conn = conn;
api_msg_post(msg);
sys_mbox_fetch(conn->mbox, NULL);
memp_free(MEMP_API_MSG, msg);
/* Drain the recvmbox. */
if (conn->recvmbox != SYS_MBOX_NULL) {
while (sys_arch_mbox_fetch(conn->recvmbox, &mem, 1) != SYS_ARCH_TIMEOUT) {
if (conn->type == NETCONN_TCP) {
if(mem != NULL)
pbuf_free((struct pbuf *)mem);
} else {
netbuf_delete((struct netbuf *)mem);
}
}
sys_mbox_free(conn->recvmbox);
conn->recvmbox = SYS_MBOX_NULL;
}
/* Drain the acceptmbox. */
if (conn->acceptmbox != SYS_MBOX_NULL) {
while (sys_arch_mbox_fetch(conn->acceptmbox, &mem, 1) != SYS_ARCH_TIMEOUT) {
netconn_delete((struct netconn *)mem);
}
sys_mbox_free(conn->acceptmbox);
conn->acceptmbox = SYS_MBOX_NULL;
}
sys_mbox_free(conn->mbox);
conn->mbox = SYS_MBOX_NULL;
if (conn->sem != SYS_SEM_NULL) {
sys_sem_free(conn->sem);
}
/* conn->sem = SYS_SEM_NULL;*/
memp_free(MEMP_NETCONN, conn);
return ERR_OK;
}
enum netconn_type
netconn_type(struct netconn *conn)
{
return conn->type;
}
err_t
netconn_peer(struct netconn *conn, struct ip_addr *addr,
u16_t *port)
{
switch (conn->type) {
case NETCONN_RAW:
/* return an error as connecting is only a helper for upper layers */
return ERR_CONN;
case NETCONN_UDPLITE:
case NETCONN_UDPNOCHKSUM:
case NETCONN_UDP:
if (conn->pcb.udp == NULL ||
((conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0))
return ERR_CONN;
*addr = (conn->pcb.udp->remote_ip);
*port = conn->pcb.udp->remote_port;
break;
case NETCONN_TCP:
if (conn->pcb.tcp == NULL)
return ERR_CONN;
*addr = (conn->pcb.tcp->remote_ip);
*port = conn->pcb.tcp->remote_port;
break;
}
return (conn->err = ERR_OK);
}
err_t
netconn_addr(struct netconn *conn, struct ip_addr **addr,
u16_t *port)
{
switch (conn->type) {
case NETCONN_RAW:
*addr = &(conn->pcb.raw->local_ip);
*port = conn->pcb.raw->protocol;
break;
case NETCONN_UDPLITE:
case NETCONN_UDPNOCHKSUM:
case NETCONN_UDP:
*addr = &(conn->pcb.udp->local_ip);
*port = conn->pcb.udp->local_port;
break;
case NETCONN_TCP:
*addr = &(conn->pcb.tcp->local_ip);
*port = conn->pcb.tcp->local_port;
break;
}
return (conn->err = ERR_OK);
}
err_t
netconn_bind(struct netconn *conn, struct ip_addr *addr,
u16_t port)
{
struct api_msg *msg;
if (conn == NULL) {
return ERR_VAL;
}
if (conn->type != NETCONN_TCP &&
conn->recvmbox == SYS_MBOX_NULL) {
if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {
return ERR_MEM;
}
}
if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
return (conn->err = ERR_MEM);
}
msg->type = API_MSG_BIND;
msg->msg.conn = conn;
msg->msg.msg.bc.ipaddr = addr;
msg->msg.msg.bc.port = port;
api_msg_post(msg);
sys_mbox_fetch(conn->mbox, NULL);
memp_free(MEMP_API_MSG, msg);
return conn->err;
}
err_t
netconn_connect(struct netconn *conn, struct ip_addr *addr,
u16_t port)
{
struct api_msg *msg;
if (conn == NULL) {
return ERR_VAL;
}
if (conn->recvmbox == SYS_MBOX_NULL) {
if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {
return ERR_MEM;
}
}
if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
return ERR_MEM;
}
msg->type = API_MSG_CONNECT;
msg->msg.conn = conn;
msg->msg.msg.bc.ipaddr = addr;
msg->msg.msg.bc.port = port;
api_msg_post(msg);
sys_mbox_fetch(conn->mbox, NULL);
memp_free(MEMP_API_MSG, msg);
return conn->err;
}
err_t
netconn_disconnect(struct netconn *conn)
{
struct api_msg *msg;
if (conn == NULL) {
return ERR_VAL;
}
if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
return ERR_MEM;
}
msg->type = API_MSG_DISCONNECT;
msg->msg.conn = conn;
api_msg_post(msg);
sys_mbox_fetch(conn->mbox, NULL);
memp_free(MEMP_API_MSG, msg);
return conn->err;
}
err_t
netconn_listen(struct netconn *conn)
{
struct api_msg *msg;
if (conn == NULL) {
return ERR_VAL;
}
if (conn->acceptmbox == SYS_MBOX_NULL) {
conn->acceptmbox = sys_mbox_new();
if (conn->acceptmbox == SYS_MBOX_NULL) {
return ERR_MEM;
}
}
if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
return (conn->err = ERR_MEM);
}
msg->type = API_MSG_LISTEN;
msg->msg.conn = conn;
api_msg_post(msg);
sys_mbox_fetch(conn->mbox, NULL);
memp_free(MEMP_API_MSG, msg);
return conn->err;
}
struct netconn *
netconn_accept(struct netconn *conn)
{
struct netconn *newconn;
if (conn == NULL) {
return NULL;
}
sys_mbox_fetch(conn->acceptmbox, (void **)&newconn);
/* Register event with callback */
if (conn->callback)
(*conn->callback)(conn, NETCONN_EVT_RCVMINUS, 0);
return newconn;
}
struct netbuf *
netconn_recv(struct netconn *conn)
{
struct api_msg *msg;
struct netbuf *buf;
struct pbuf *p;
u16_t len;
if (conn == NULL) {
return NULL;
}
if (conn->recvmbox == SYS_MBOX_NULL) {
conn->err = ERR_CONN;
return NULL;
}
if (conn->err != ERR_OK) {
return NULL;
}
if (conn->type == NETCONN_TCP) {
if (conn->pcb.tcp->state == LISTEN) {
conn->err = ERR_CONN;
return NULL;
}
buf = memp_malloc(MEMP_NETBUF);
if (buf == NULL) {
conn->err = ERR_MEM;
return NULL;
}
sys_mbox_fetch(conn->recvmbox, (void **)&p);
if (p != NULL)
{
len = p->tot_len;
conn->recv_avail -= len;
}
else
len = 0;
/* Register event with callback */
if (conn->callback)
(*conn->callback)(conn, NETCONN_EVT_RCVMINUS, len);
/* If we are closed, we indicate that we no longer wish to receive
data by setting conn->recvmbox to SYS_MBOX_NULL. */
if (p == NULL) {
memp_free(MEMP_NETBUF, buf);
sys_mbox_free(conn->recvmbox);
conn->recvmbox = SYS_MBOX_NULL;
return NULL;
}
buf->p = p;
buf->ptr = p;
buf->fromport = 0;
buf->fromaddr = NULL;
/* Let the stack know that we have taken the data. */
if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
conn->err = ERR_MEM;
return buf;
}
msg->type = API_MSG_RECV;
msg->msg.conn = conn;
if (buf != NULL) {
msg->msg.msg.len = buf->p->tot_len;
} else {
msg->msg.msg.len = 1;
}
api_msg_post(msg);
sys_mbox_fetch(conn->mbox, NULL);
memp_free(MEMP_API_MSG, msg);
} else {
sys_mbox_fetch(conn->recvmbox, (void **)&buf);
conn->recv_avail -= buf->p->tot_len;
/* Register event with callback */
if (conn->callback)
(*conn->callback)(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);
}
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));
return buf;
}
err_t
netconn_send(struct netconn *conn, struct netbuf *buf)
{
struct api_msg *msg;
if (conn == NULL) {
return ERR_VAL;
}
if (conn->err != ERR_OK) {
return conn->err;
}
if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
return (conn->err = ERR_MEM);
}
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len));
msg->type = API_MSG_SEND;
msg->msg.conn = conn;
msg->msg.msg.p = buf->p;
api_msg_post(msg);
sys_mbox_fetch(conn->mbox, NULL);
memp_free(MEMP_API_MSG, msg);
return conn->err;
}
err_t
netconn_write(struct netconn *conn, void *dataptr, u16_t size, u8_t copy)
{
struct api_msg *msg;
u16_t len;
if (conn == NULL) {
return ERR_VAL;
}
if (conn->err != ERR_OK) {
return conn->err;
}
if (conn->sem == SYS_SEM_NULL) {
conn->sem = sys_sem_new(0);
if (conn->sem == SYS_SEM_NULL) {
return ERR_MEM;
}
}
if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
return (conn->err = ERR_MEM);
}
msg->type = API_MSG_WRITE;
msg->msg.conn = conn;
conn->state = NETCONN_WRITE;
while (conn->err == ERR_OK && size > 0) {
msg->msg.msg.w.dataptr = dataptr;
msg->msg.msg.w.copy = copy;
if (conn->type == NETCONN_TCP) {
if (tcp_sndbuf(conn->pcb.tcp) == 0) {
sys_sem_wait(conn->sem);
if (conn->err != ERR_OK) {
goto ret;
}
}
if (size > tcp_sndbuf(conn->pcb.tcp)) {
/* We cannot send more than one send buffer's worth of data at a
time. */
len = tcp_sndbuf(conn->pcb.tcp);
} else {
len = size;
}
} else {
len = size;
}
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_write: writing %d bytes (%d)\n", len, copy));
msg->msg.msg.w.len = len;
api_msg_post(msg);
sys_mbox_fetch(conn->mbox, NULL);
if (conn->err == ERR_OK) {
dataptr = (void *)((char *)dataptr + len);
size -= len;
} else if (conn->err == ERR_MEM) {
conn->err = ERR_OK;
sys_sem_wait(conn->sem);
} else {
goto ret;
}
}
ret:
memp_free(MEMP_API_MSG, msg);
conn->state = NETCONN_NONE;
if (conn->sem != SYS_SEM_NULL) {
sys_sem_free(conn->sem);
conn->sem = SYS_SEM_NULL;
}
return conn->err;
}
err_t
netconn_close(struct netconn *conn)
{
struct api_msg *msg;
if (conn == NULL) {
return ERR_VAL;
}
if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
return (conn->err = ERR_MEM);
}
conn->state = NETCONN_CLOSE;
again:
msg->type = API_MSG_CLOSE;
msg->msg.conn = conn;
api_msg_post(msg);
sys_mbox_fetch(conn->mbox, NULL);
if (conn->err == ERR_MEM &&
conn->sem != SYS_SEM_NULL) {
sys_sem_wait(conn->sem);
goto again;
}
conn->state = NETCONN_NONE;
memp_free(MEMP_API_MSG, msg);
return conn->err;
}
err_t
netconn_err(struct netconn *conn)
{
return conn->err;
}

View file

@ -0,0 +1,810 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/arch.h"
#include "lwip/api_msg.h"
#include "lwip/memp.h"
#include "lwip/sys.h"
#include "lwip/tcpip.h"
#if LWIP_RAW
static u8_t
recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
struct ip_addr *addr)
{
struct netbuf *buf;
struct netconn *conn;
conn = arg;
if (!conn) return 0;
if (conn->recvmbox != SYS_MBOX_NULL) {
if (!(buf = memp_malloc(MEMP_NETBUF))) {
return 0;
}
pbuf_ref(p);
buf->p = p;
buf->ptr = p;
buf->fromaddr = addr;
buf->fromport = pcb->protocol;
conn->recv_avail += p->tot_len;
/* Register event with callback */
if (conn->callback)
(*conn->callback)(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
sys_mbox_post(conn->recvmbox, buf);
}
return 0; /* do not eat the packet */
}
#endif
#if LWIP_UDP
static void
recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
struct ip_addr *addr, u16_t port)
{
struct netbuf *buf;
struct netconn *conn;
(void)pcb;
conn = arg;
if (conn == NULL) {
pbuf_free(p);
return;
}
if (conn->recvmbox != SYS_MBOX_NULL) {
buf = memp_malloc(MEMP_NETBUF);
if (buf == NULL) {
pbuf_free(p);
return;
} else {
buf->p = p;
buf->ptr = p;
buf->fromaddr = addr;
buf->fromport = port;
}
conn->recv_avail += p->tot_len;
/* Register event with callback */
if (conn->callback)
(*conn->callback)(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
sys_mbox_post(conn->recvmbox, buf);
}
}
#endif /* LWIP_UDP */
#if LWIP_TCP
static err_t
recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
struct netconn *conn;
u16_t len;
(void)pcb;
conn = arg;
if (conn == NULL) {
pbuf_free(p);
return ERR_VAL;
}
if (conn->recvmbox != SYS_MBOX_NULL) {
conn->err = err;
if (p != NULL) {
len = p->tot_len;
conn->recv_avail += len;
}
else
len = 0;
/* Register event with callback */
if (conn->callback)
(*conn->callback)(conn, NETCONN_EVT_RCVPLUS, len);
sys_mbox_post(conn->recvmbox, p);
}
return ERR_OK;
}
static err_t
poll_tcp(void *arg, struct tcp_pcb *pcb)
{
struct netconn *conn;
(void)pcb;
conn = arg;
if (conn != NULL &&
(conn->state == NETCONN_WRITE || conn->state == NETCONN_CLOSE) &&
conn->sem != SYS_SEM_NULL) {
sys_sem_signal(conn->sem);
}
return ERR_OK;
}
static err_t
sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
{
struct netconn *conn;
(void)pcb;
conn = arg;
if (conn != NULL && conn->sem != SYS_SEM_NULL) {
sys_sem_signal(conn->sem);
}
if (conn && conn->callback)
if (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)
(*conn->callback)(conn, NETCONN_EVT_SENDPLUS, len);
return ERR_OK;
}
static void
err_tcp(void *arg, err_t err)
{
struct netconn *conn;
conn = arg;
conn->pcb.tcp = NULL;
conn->err = err;
if (conn->recvmbox != SYS_MBOX_NULL) {
/* Register event with callback */
if (conn->callback)
(*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
sys_mbox_post(conn->recvmbox, NULL);
}
if (conn->mbox != SYS_MBOX_NULL) {
sys_mbox_post(conn->mbox, NULL);
}
if (conn->acceptmbox != SYS_MBOX_NULL) {
/* Register event with callback */
if (conn->callback)
(*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
sys_mbox_post(conn->acceptmbox, NULL);
}
if (conn->sem != SYS_SEM_NULL) {
sys_sem_signal(conn->sem);
}
}
static void
setup_tcp(struct netconn *conn)
{
struct tcp_pcb *pcb;
pcb = conn->pcb.tcp;
tcp_arg(pcb, conn);
tcp_recv(pcb, recv_tcp);
tcp_sent(pcb, sent_tcp);
tcp_poll(pcb, poll_tcp, 4);
tcp_err(pcb, err_tcp);
}
static err_t
accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
{
sys_mbox_t mbox;
struct netconn *newconn;
struct netconn *conn;
#if API_MSG_DEBUG
#if TCP_DEBUG
tcp_debug_print_state(newpcb->state);
#endif /* TCP_DEBUG */
#endif /* API_MSG_DEBUG */
conn = (struct netconn *)arg;
mbox = conn->acceptmbox;
newconn = memp_malloc(MEMP_NETCONN);
if (newconn == NULL) {
return ERR_MEM;
}
newconn->type = NETCONN_TCP;
newconn->pcb.tcp = newpcb;
setup_tcp(newconn);
newconn->recvmbox = sys_mbox_new();
if (newconn->recvmbox == SYS_MBOX_NULL) {
memp_free(MEMP_NETCONN, newconn);
return ERR_MEM;
}
newconn->mbox = sys_mbox_new();
if (newconn->mbox == SYS_MBOX_NULL) {
sys_mbox_free(newconn->recvmbox);
memp_free(MEMP_NETCONN, newconn);
return ERR_MEM;
}
newconn->sem = sys_sem_new(0);
if (newconn->sem == SYS_SEM_NULL) {
sys_mbox_free(newconn->recvmbox);
sys_mbox_free(newconn->mbox);
memp_free(MEMP_NETCONN, newconn);
return ERR_MEM;
}
newconn->acceptmbox = SYS_MBOX_NULL;
newconn->err = err;
/* Register event with callback */
if (conn->callback)
{
(*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
/* We have to set the callback here even though
* the new socket is unknown. Mark the socket as -1. */
newconn->callback = conn->callback;
newconn->socket = -1;
}
sys_mbox_post(mbox, newconn);
return ERR_OK;
}
#endif /* LWIP_TCP */
static void
do_newconn(struct api_msg_msg *msg)
{
if(msg->conn->pcb.tcp != NULL) {
/* This "new" connection already has a PCB allocated. */
/* Is this an error condition? Should it be deleted?
We currently just are happy and return. */
sys_mbox_post(msg->conn->mbox, NULL);
return;
}
msg->conn->err = ERR_OK;
/* Allocate a PCB for this connection */
switch(msg->conn->type) {
#if LWIP_RAW
case NETCONN_RAW:
msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field */
raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
break;
#endif
#if LWIP_UDP
case NETCONN_UDPLITE:
msg->conn->pcb.udp = udp_new();
if(msg->conn->pcb.udp == NULL) {
msg->conn->err = ERR_MEM;
break;
}
udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
break;
case NETCONN_UDPNOCHKSUM:
msg->conn->pcb.udp = udp_new();
if(msg->conn->pcb.udp == NULL) {
msg->conn->err = ERR_MEM;
break;
}
udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
break;
case NETCONN_UDP:
msg->conn->pcb.udp = udp_new();
if(msg->conn->pcb.udp == NULL) {
msg->conn->err = ERR_MEM;
break;
}
udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
msg->conn->pcb.tcp = tcp_new();
if(msg->conn->pcb.tcp == NULL) {
msg->conn->err = ERR_MEM;
break;
}
setup_tcp(msg->conn);
break;
#endif
}
sys_mbox_post(msg->conn->mbox, NULL);
}
static void
do_delconn(struct api_msg_msg *msg)
{
if (msg->conn->pcb.tcp != NULL) {
switch (msg->conn->type) {
#if LWIP_RAW
case NETCONN_RAW:
raw_remove(msg->conn->pcb.raw);
break;
#endif
#if LWIP_UDP
case NETCONN_UDPLITE:
/* FALLTHROUGH */
case NETCONN_UDPNOCHKSUM:
/* FALLTHROUGH */
case NETCONN_UDP:
msg->conn->pcb.udp->recv_arg = NULL;
udp_remove(msg->conn->pcb.udp);
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
if (msg->conn->pcb.tcp->state == LISTEN) {
tcp_arg(msg->conn->pcb.tcp, NULL);
tcp_accept(msg->conn->pcb.tcp, NULL);
tcp_close(msg->conn->pcb.tcp);
} else {
tcp_arg(msg->conn->pcb.tcp, NULL);
tcp_sent(msg->conn->pcb.tcp, NULL);
tcp_recv(msg->conn->pcb.tcp, NULL);
tcp_poll(msg->conn->pcb.tcp, NULL, 0);
tcp_err(msg->conn->pcb.tcp, NULL);
if (tcp_close(msg->conn->pcb.tcp) != ERR_OK) {
tcp_abort(msg->conn->pcb.tcp);
}
}
#endif
default:
break;
}
}
/* Trigger select() in socket layer */
if (msg->conn->callback)
{
(*msg->conn->callback)(msg->conn, NETCONN_EVT_RCVPLUS, 0);
(*msg->conn->callback)(msg->conn, NETCONN_EVT_SENDPLUS, 0);
}
if (msg->conn->mbox != SYS_MBOX_NULL) {
sys_mbox_post(msg->conn->mbox, NULL);
}
}
static void
do_bind(struct api_msg_msg *msg)
{
if (msg->conn->pcb.tcp == NULL) {
switch (msg->conn->type) {
#if LWIP_RAW
case NETCONN_RAW:
msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */
raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
break;
#endif
#if LWIP_UDP
case NETCONN_UDPLITE:
msg->conn->pcb.udp = udp_new();
udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
break;
case NETCONN_UDPNOCHKSUM:
msg->conn->pcb.udp = udp_new();
udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
break;
case NETCONN_UDP:
msg->conn->pcb.udp = udp_new();
udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
msg->conn->pcb.tcp = tcp_new();
setup_tcp(msg->conn);
#endif /* LWIP_TCP */
default:
break;
}
}
switch (msg->conn->type) {
#if LWIP_RAW
case NETCONN_RAW:
msg->conn->err = raw_bind(msg->conn->pcb.raw,msg->msg.bc.ipaddr);
break;
#endif
#if LWIP_UDP
case NETCONN_UDPLITE:
/* FALLTHROUGH */
case NETCONN_UDPNOCHKSUM:
/* FALLTHROUGH */
case NETCONN_UDP:
msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
msg->conn->err = tcp_bind(msg->conn->pcb.tcp,
msg->msg.bc.ipaddr, msg->msg.bc.port);
#endif /* LWIP_TCP */
default:
break;
}
sys_mbox_post(msg->conn->mbox, NULL);
}
#if LWIP_TCP
static err_t
do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
{
struct netconn *conn;
(void)pcb;
conn = arg;
if (conn == NULL) {
return ERR_VAL;
}
conn->err = err;
if (conn->type == NETCONN_TCP && err == ERR_OK) {
setup_tcp(conn);
}
sys_mbox_post(conn->mbox, NULL);
return ERR_OK;
}
#endif
static void
do_connect(struct api_msg_msg *msg)
{
if (msg->conn->pcb.tcp == NULL) {
switch (msg->conn->type) {
#if LWIP_RAW
case NETCONN_RAW:
msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */
raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
break;
#endif
#if LWIP_UDP
case NETCONN_UDPLITE:
msg->conn->pcb.udp = udp_new();
if (msg->conn->pcb.udp == NULL) {
msg->conn->err = ERR_MEM;
sys_mbox_post(msg->conn->mbox, NULL);
return;
}
udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
break;
case NETCONN_UDPNOCHKSUM:
msg->conn->pcb.udp = udp_new();
if (msg->conn->pcb.udp == NULL) {
msg->conn->err = ERR_MEM;
sys_mbox_post(msg->conn->mbox, NULL);
return;
}
udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
break;
case NETCONN_UDP:
msg->conn->pcb.udp = udp_new();
if (msg->conn->pcb.udp == NULL) {
msg->conn->err = ERR_MEM;
sys_mbox_post(msg->conn->mbox, NULL);
return;
}
udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
msg->conn->pcb.tcp = tcp_new();
if (msg->conn->pcb.tcp == NULL) {
msg->conn->err = ERR_MEM;
sys_mbox_post(msg->conn->mbox, NULL);
return;
}
#endif
default:
break;
}
}
switch (msg->conn->type) {
#if LWIP_RAW
case NETCONN_RAW:
raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
sys_mbox_post(msg->conn->mbox, NULL);
break;
#endif
#if LWIP_UDP
case NETCONN_UDPLITE:
/* FALLTHROUGH */
case NETCONN_UDPNOCHKSUM:
/* FALLTHROUGH */
case NETCONN_UDP:
udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
sys_mbox_post(msg->conn->mbox, NULL);
break;
#endif
#if LWIP_TCP
case NETCONN_TCP:
/* tcp_arg(msg->conn->pcb.tcp, msg->conn);*/
setup_tcp(msg->conn);
tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,
do_connected);
/*tcp_output(msg->conn->pcb.tcp);*/
#endif
default:
break;
}
}
static void
do_disconnect(struct api_msg_msg *msg)
{
switch (msg->conn->type) {
#if LWIP_RAW
case NETCONN_RAW:
/* Do nothing as connecting is only a helper for upper lwip layers */
break;
#endif
#if LWIP_UDP
case NETCONN_UDPLITE:
/* FALLTHROUGH */
case NETCONN_UDPNOCHKSUM:
/* FALLTHROUGH */
case NETCONN_UDP:
udp_disconnect(msg->conn->pcb.udp);
break;
#endif
case NETCONN_TCP:
break;
}
sys_mbox_post(msg->conn->mbox, NULL);
}
static void
do_listen(struct api_msg_msg *msg)
{
if (msg->conn->pcb.tcp != NULL) {
switch (msg->conn->type) {
#if LWIP_RAW
case NETCONN_RAW:
LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen RAW: cannot listen for RAW.\n"));
break;
#endif
#if LWIP_UDP
case NETCONN_UDPLITE:
/* FALLTHROUGH */
case NETCONN_UDPNOCHKSUM:
/* FALLTHROUGH */
case NETCONN_UDP:
LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen UDP: cannot listen for UDP.\n"));
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
msg->conn->pcb.tcp = tcp_listen(msg->conn->pcb.tcp);
if (msg->conn->pcb.tcp == NULL) {
msg->conn->err = ERR_MEM;
} else {
if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
msg->conn->acceptmbox = sys_mbox_new();
if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
msg->conn->err = ERR_MEM;
break;
}
}
tcp_arg(msg->conn->pcb.tcp, msg->conn);
tcp_accept(msg->conn->pcb.tcp, accept_function);
}
#endif
default:
break;
}
}
sys_mbox_post(msg->conn->mbox, NULL);
}
static void
do_accept(struct api_msg_msg *msg)
{
if (msg->conn->pcb.tcp != NULL) {
switch (msg->conn->type) {
#if LWIP_RAW
case NETCONN_RAW:
LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept RAW: cannot accept for RAW.\n"));
break;
#endif
#if LWIP_UDP
case NETCONN_UDPLITE:
/* FALLTHROUGH */
case NETCONN_UDPNOCHKSUM:
/* FALLTHROUGH */
case NETCONN_UDP:
LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept UDP: cannot accept for UDP.\n"));
break;
#endif /* LWIP_UDP */
case NETCONN_TCP:
break;
}
}
}
static void
do_send(struct api_msg_msg *msg)
{
if (msg->conn->pcb.tcp != NULL) {
switch (msg->conn->type) {
#if LWIP_RAW
case NETCONN_RAW:
raw_send(msg->conn->pcb.raw, msg->msg.p);
break;
#endif
#if LWIP_UDP
case NETCONN_UDPLITE:
/* FALLTHROUGH */
case NETCONN_UDPNOCHKSUM:
/* FALLTHROUGH */
case NETCONN_UDP:
udp_send(msg->conn->pcb.udp, msg->msg.p);
break;
#endif /* LWIP_UDP */
case NETCONN_TCP:
break;
}
}
sys_mbox_post(msg->conn->mbox, NULL);
}
static void
do_recv(struct api_msg_msg *msg)
{
#if LWIP_TCP
if (msg->conn->pcb.tcp != NULL) {
if (msg->conn->type == NETCONN_TCP) {
tcp_recved(msg->conn->pcb.tcp, msg->msg.len);
}
}
#endif
sys_mbox_post(msg->conn->mbox, NULL);
}
static void
do_write(struct api_msg_msg *msg)
{
#if LWIP_TCP
err_t err;
#endif
if (msg->conn->pcb.tcp != NULL) {
switch (msg->conn->type) {
#if LWIP_RAW
case NETCONN_RAW:
msg->conn->err = ERR_VAL;
break;
#endif
#if LWIP_UDP
case NETCONN_UDPLITE:
/* FALLTHROUGH */
case NETCONN_UDPNOCHKSUM:
/* FALLTHROUGH */
case NETCONN_UDP:
msg->conn->err = ERR_VAL;
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
err = tcp_write(msg->conn->pcb.tcp, msg->msg.w.dataptr,
msg->msg.w.len, msg->msg.w.copy);
/* This is the Nagle algorithm: inhibit the sending of new TCP
segments when new outgoing data arrives from the user if any
previously transmitted data on the connection remains
unacknowledged. */
if(err == ERR_OK && (msg->conn->pcb.tcp->unacked == NULL || (msg->conn->pcb.tcp->flags & TF_NODELAY)) ) {
tcp_output(msg->conn->pcb.tcp);
}
msg->conn->err = err;
if (msg->conn->callback)
if (err == ERR_OK)
{
if (tcp_sndbuf(msg->conn->pcb.tcp) <= TCP_SNDLOWAT)
(*msg->conn->callback)(msg->conn, NETCONN_EVT_SENDMINUS, msg->msg.w.len);
}
#endif
default:
break;
}
}
sys_mbox_post(msg->conn->mbox, NULL);
}
static void
do_close(struct api_msg_msg *msg)
{
err_t err;
err = ERR_OK;
if (msg->conn->pcb.tcp != NULL) {
switch (msg->conn->type) {
#if LWIP_RAW
case NETCONN_RAW:
break;
#endif
#if LWIP_UDP
case NETCONN_UDPLITE:
/* FALLTHROUGH */
case NETCONN_UDPNOCHKSUM:
/* FALLTHROUGH */
case NETCONN_UDP:
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
if (msg->conn->pcb.tcp->state == LISTEN) {
err = tcp_close(msg->conn->pcb.tcp);
}
msg->conn->err = err;
#endif
default:
break;
}
}
sys_mbox_post(msg->conn->mbox, NULL);
}
typedef void (* api_msg_decode)(struct api_msg_msg *msg);
static api_msg_decode decode[API_MSG_MAX] = {
do_newconn,
do_delconn,
do_bind,
do_connect,
do_disconnect,
do_listen,
do_accept,
do_send,
do_recv,
do_write,
do_close
};
void
api_msg_input(struct api_msg *msg)
{
decode[msg->type](&(msg->msg));
}
void
api_msg_post(struct api_msg *msg)
{
tcpip_apimsg(msg);
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/err.h"
#ifdef LWIP_DEBUG
static char *err_strerr[] = {"Ok.",
"Out of memory error.",
"Buffer error.",
"Connection aborted.",
"Connection reset.",
"Connection closed.",
"Not connected.",
"Illegal value.",
"Illegal argument.",
"Routing problem.",
"Address in use."
};
char *
lwip_strerr(err_t err)
{
return err_strerr[-err];
}
#endif /* LWIP_DEBUG */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,184 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/sys.h"
#include "lwip/memp.h"
#include "lwip/pbuf.h"
#include "lwip/ip.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/tcpip.h"
static void (* tcpip_init_done)(void *arg) = NULL;
static void *tcpip_init_done_arg;
static sys_mbox_t mbox;
#if LWIP_TCP
static int tcpip_tcp_timer_active = 0;
static void
tcpip_tcp_timer(void *arg)
{
(void)arg;
/* call TCP timer handler */
tcp_tmr();
/* timer still needed? */
if (tcp_active_pcbs || tcp_tw_pcbs) {
/* restart timer */
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
} else {
/* disable timer */
tcpip_tcp_timer_active = 0;
}
}
#if !NO_SYS
void
tcp_timer_needed(void)
{
/* timer is off but needed again? */
if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
/* enable and start timer */
tcpip_tcp_timer_active = 1;
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
}
}
#endif /* !NO_SYS */
#endif /* LWIP_TCP */
static void
tcpip_thread(void *arg)
{
struct tcpip_msg *msg;
(void)arg;
ip_init();
#if LWIP_UDP
udp_init();
#endif
#if LWIP_TCP
tcp_init();
#endif
if (tcpip_init_done != NULL) {
tcpip_init_done(tcpip_init_done_arg);
}
while (1) { /* MAIN Loop */
sys_mbox_fetch(mbox, (void *)&msg);
switch (msg->type) {
case TCPIP_MSG_API:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
api_msg_input(msg->msg.apimsg);
break;
case TCPIP_MSG_INPUT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: IP packet %p\n", (void *)msg));
ip_input(msg->msg.inp.p, msg->msg.inp.netif);
break;
case TCPIP_MSG_CALLBACK:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
msg->msg.cb.f(msg->msg.cb.ctx);
break;
default:
break;
}
memp_free(MEMP_TCPIP_MSG, msg);
}
}
err_t
tcpip_input(struct pbuf *p, struct netif *inp)
{
struct tcpip_msg *msg;
msg = memp_malloc(MEMP_TCPIP_MSG);
if (msg == NULL) {
pbuf_free(p);
return ERR_MEM;
}
msg->type = TCPIP_MSG_INPUT;
msg->msg.inp.p = p;
msg->msg.inp.netif = inp;
sys_mbox_post(mbox, msg);
return ERR_OK;
}
err_t
tcpip_callback(void (*f)(void *ctx), void *ctx)
{
struct tcpip_msg *msg;
msg = memp_malloc(MEMP_TCPIP_MSG);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_CALLBACK;
msg->msg.cb.f = f;
msg->msg.cb.ctx = ctx;
sys_mbox_post(mbox, msg);
return ERR_OK;
}
void
tcpip_apimsg(struct api_msg *apimsg)
{
struct tcpip_msg *msg;
msg = memp_malloc(MEMP_TCPIP_MSG);
if (msg == NULL) {
memp_free(MEMP_API_MSG, apimsg);
return;
}
msg->type = TCPIP_MSG_API;
msg->msg.apimsg = apimsg;
sys_mbox_post(mbox, msg);
}
void
tcpip_init(void (* initfunc)(void *), void *arg)
{
tcpip_init_done = initfunc;
tcpip_init_done_arg = arg;
mbox = sys_mbox_new();
sys_thread_new(tcpip_thread, NULL, TCPIP_THREAD_PRIO);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,377 @@
/*
* 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>
*
*/
/* inet.c
*
* Functions common to all TCP/IP modules, such as the Internet checksum and the
* byte order functions.
*
*/
#include "lwip/opt.h"
#include "lwip/arch.h"
#include "lwip/def.h"
#include "lwip/inet.h"
#include "lwip/sys.h"
/* This is a reference implementation of the checksum algorithm
- it may not work on all architectures, and all processors, particularly
if they have issues with alignment and 16 bit access.
- in this case you will need to port it to your architecture and
#define LWIP_CHKSUM <your_checksum_routine>
in your sys_arch.h
*/
#ifndef LWIP_CHKSUM
#define LWIP_CHKSUM lwip_standard_chksum
static u16_t
lwip_standard_chksum(void *dataptr, int len)
{
u32_t acc;
LWIP_DEBUGF(INET_DEBUG, ("lwip_chksum(%p, %d)\n", (void *)dataptr, len));
for(acc = 0; len > 1; len -= 2) {
/* acc = acc + *((u16_t *)dataptr)++;*/
acc += *(u16_t *)dataptr;
dataptr = (void *)((u16_t *)dataptr + 1);
}
/* add up any odd byte */
if (len == 1) {
acc += htons((u16_t)((*(u8_t *)dataptr) & 0xff) << 8);
LWIP_DEBUGF(INET_DEBUG, ("inet: chksum: odd byte %d\n", (unsigned int)(*(u8_t *)dataptr)));
} else {
LWIP_DEBUGF(INET_DEBUG, ("inet: chksum: no odd byte\n"));
}
acc = (acc >> 16) + (acc & 0xffffUL);
if ((acc & 0xffff0000) != 0) {
acc = (acc >> 16) + (acc & 0xffffUL);
}
return (u16_t)acc;
}
#endif
/* inet_chksum_pseudo:
*
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
*/
u16_t
inet_chksum_pseudo(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
u8_t proto, u16_t proto_len)
{
u32_t acc;
struct pbuf *q;
u8_t swapped;
acc = 0;
swapped = 0;
/* iterate through all pbuf in chain */
for(q = p; q != NULL; q = q->next) {
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
(void *)q, (void *)q->next));
acc += LWIP_CHKSUM(q->payload, q->len);
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%lx \n", acc));*/
while (acc >> 16) {
acc = (acc & 0xffffUL) + (acc >> 16);
}
if (q->len % 2 != 0) {
swapped = 1 - swapped;
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
}
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%lx \n", acc));*/
}
if (swapped) {
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
}
acc += (src->addr & 0xffffUL);
acc += ((src->addr >> 16) & 0xffffUL);
acc += (dest->addr & 0xffffUL);
acc += ((dest->addr >> 16) & 0xffffUL);
acc += (u32_t)htons((u16_t)proto);
acc += (u32_t)htons(proto_len);
while (acc >> 16) {
acc = (acc & 0xffffUL) + (acc >> 16);
}
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%lx\n", acc));
return (u16_t)~(acc & 0xffffUL);
}
/* inet_chksum:
*
* Calculates the Internet checksum over a portion of memory. Used primarely for IP
* and ICMP.
*/
u16_t
inet_chksum(void *dataptr, u16_t len)
{
u32_t acc;
acc = LWIP_CHKSUM(dataptr, len);
while (acc >> 16) {
acc = (acc & 0xffff) + (acc >> 16);
}
return (u16_t)~(acc & 0xffff);
}
u16_t
inet_chksum_pbuf(struct pbuf *p)
{
u32_t acc;
struct pbuf *q;
u8_t swapped;
acc = 0;
swapped = 0;
for(q = p; q != NULL; q = q->next) {
acc += LWIP_CHKSUM(q->payload, q->len);
while (acc >> 16) {
acc = (acc & 0xffffUL) + (acc >> 16);
}
if (q->len % 2 != 0) {
swapped = 1 - swapped;
acc = (acc & 0x00ffUL << 8) | (acc & 0xff00UL >> 8);
}
}
if (swapped) {
acc = ((acc & 0x00ffUL) << 8) | ((acc & 0xff00UL) >> 8);
}
return (u16_t)~(acc & 0xffffUL);
}
/* Here for now until needed in other places in lwIP */
#ifndef isascii
#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up)
#define isascii(c) in_range(c, 0x20, 0x7f)
#define isdigit(c) in_range(c, '0', '9')
#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
#define islower(c) in_range(c, 'a', 'z')
#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
#endif
/*
* Ascii internet address interpretation routine.
* The value returned is in network order.
*/
/* */
/* inet_addr */
u32_t inet_addr(const char *cp)
{
struct in_addr val;
if (inet_aton(cp, &val)) {
return (val.s_addr);
}
return (INADDR_NONE);
}
/*
* Check whether "cp" is a valid ascii representation
* of an Internet address and convert to a binary address.
* Returns 1 if the address is valid, 0 if not.
* This replaces inet_addr, the return value from which
* cannot distinguish between failure and a local broadcast address.
*/
/* */
/* inet_aton */
int inet_aton(const char *cp, struct in_addr *addr)
{
u32_t val;
int base, n;
char c;
u32_t parts[4];
u32_t* pp = parts;
c = *cp;
for (;;) {
/*
* Collect number up to ``.''.
* Values are specified as for C:
* 0x=hex, 0=octal, isdigit=decimal.
*/
if (!isdigit(c))
return (0);
val = 0; base = 10;
if (c == '0') {
c = *++cp;
if (c == 'x' || c == 'X')
base = 16, c = *++cp;
else
base = 8;
}
for (;;) {
if (isdigit(c)) {
val = (val * base) + (int)(c - '0');
c = *++cp;
} else if (base == 16 && isxdigit(c)) {
val = (val << 4) |
(int)(c + 10 - (islower(c) ? 'a' : 'A'));
c = *++cp;
} else
break;
}
if (c == '.') {
/*
* Internet format:
* a.b.c.d
* a.b.c (with c treated as 16 bits)
* a.b (with b treated as 24 bits)
*/
if (pp >= parts + 3)
return (0);
*pp++ = val;
c = *++cp;
} else
break;
}
/*
* Check for trailing characters.
*/
if (c != '\0' && (!isascii(c) || !isspace(c)))
return (0);
/*
* Concoct the address according to
* the number of parts specified.
*/
n = pp - parts + 1;
switch (n) {
case 0:
return (0); /* initial nondigit */
case 1: /* a -- 32 bits */
break;
case 2: /* a.b -- 8.24 bits */
if (val > 0xffffff)
return (0);
val |= parts[0] << 24;
break;
case 3: /* a.b.c -- 8.8.16 bits */
if (val > 0xffff)
return (0);
val |= (parts[0] << 24) | (parts[1] << 16);
break;
case 4: /* a.b.c.d -- 8.8.8.8 bits */
if (val > 0xff)
return (0);
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
break;
}
if (addr)
addr->s_addr = htonl(val);
return (1);
}
/* Convert numeric IP address into decimal dotted ASCII representation.
* returns ptr to static buffer; not reentrant!
*/
char *inet_ntoa(struct in_addr addr)
{
static char str[16];
u32_t s_addr = addr.s_addr;
char inv[3];
char *rp;
u8_t *ap;
u8_t rem;
u8_t n;
u8_t i;
rp = str;
ap = (u8_t *)&s_addr;
for(n = 0; n < 4; n++) {
i = 0;
do {
rem = *ap % (u8_t)10;
*ap /= (u8_t)10;
inv[i++] = '0' + rem;
} while(*ap);
while(i--)
*rp++ = inv[i];
*rp++ = '.';
ap++;
}
*--rp = 0;
return str;
}
#ifndef BYTE_ORDER
#error BYTE_ORDER is not defined
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
u16_t
htons(u16_t n)
{
return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
}
u16_t
ntohs(u16_t n)
{
return htons(n);
}
u32_t
htonl(u32_t n)
{
return ((n & 0xff) << 24) |
((n & 0xff00) << 8) |
((n & 0xff0000) >> 8) |
((n & 0xff000000) >> 24);
}
u32_t
ntohl(u32_t n)
{
return htonl(n);
}
#endif /* BYTE_ORDER == LITTLE_ENDIAN */

View file

@ -0,0 +1,168 @@
/*
* 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>
*
*/
/* inet6.c
*
* Functions common to all TCP/IP modules, such as the Internet checksum and the
* byte order functions.
*
*/
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/inet.h"
/* chksum:
*
* Sums up all 16 bit words in a memory portion. Also includes any odd byte.
* This function is used by the other checksum functions.
*
* For now, this is not optimized. Must be optimized for the particular processor
* arcitecture on which it is to run. Preferebly coded in assembler.
*/
static u32_t
chksum(void *dataptr, u16_t len)
{
u16_t *sdataptr = dataptr;
u32_t acc;
for(acc = 0; len > 1; len -= 2) {
acc += *sdataptr++;
}
/* add up any odd byte */
if (len == 1) {
acc += htons((u16_t)(*(u8_t *)dataptr) << 8);
}
return acc;
}
/* inet_chksum_pseudo:
*
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
*/
u16_t
inet_chksum_pseudo(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
u8_t proto, u32_t proto_len)
{
u32_t acc;
struct pbuf *q;
u8_t swapped, i;
acc = 0;
swapped = 0;
for(q = p; q != NULL; q = q->next) {
acc += chksum(q->payload, q->len);
while (acc >> 16) {
acc = (acc & 0xffff) + (acc >> 16);
}
if (q->len % 2 != 0) {
swapped = 1 - swapped;
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
}
}
if (swapped) {
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
}
for(i = 0; i < 8; i++) {
acc += ((u16_t *)src->addr)[i] & 0xffff;
acc += ((u16_t *)dest->addr)[i] & 0xffff;
while (acc >> 16) {
acc = (acc & 0xffff) + (acc >> 16);
}
}
acc += (u16_t)htons((u16_t)proto);
acc += ((u16_t *)&proto_len)[0] & 0xffff;
acc += ((u16_t *)&proto_len)[1] & 0xffff;
while (acc >> 16) {
acc = (acc & 0xffff) + (acc >> 16);
}
return ~(acc & 0xffff);
}
/* inet_chksum:
*
* Calculates the Internet checksum over a portion of memory. Used primarely for IP
* and ICMP.
*/
u16_t
inet_chksum(void *dataptr, u16_t len)
{
u32_t acc, sum;
acc = chksum(dataptr, len);
sum = (acc & 0xffff) + (acc >> 16);
sum += (sum >> 16);
return ~(sum & 0xffff);
}
u16_t
inet_chksum_pbuf(struct pbuf *p)
{
u32_t acc;
struct pbuf *q;
u8_t swapped;
acc = 0;
swapped = 0;
for(q = p; q != NULL; q = q->next) {
acc += chksum(q->payload, q->len);
while (acc >> 16) {
acc = (acc & 0xffff) + (acc >> 16);
}
if (q->len % 2 != 0) {
swapped = 1 - swapped;
acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8);
}
}
if (swapped) {
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
}
return ~(acc & 0xffff);
}

View file

@ -0,0 +1,205 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/* Some ICMP messages should be passed to the transport protocols. This
is not implemented. */
#include "lwip/opt.h"
#include "lwip/icmp.h"
#include "lwip/inet.h"
#include "lwip/ip.h"
#include "lwip/def.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include <string.h>
void
icmp_input(struct pbuf *p, struct netif *inp)
{
unsigned char type;
unsigned char code;
struct icmp_echo_hdr *iecho;
struct ip_hdr *iphdr;
struct ip_addr tmpaddr;
u16_t hlen;
ICMP_STATS_INC(icmp.recv);
snmp_inc_icmpinmsgs();
iphdr = p->payload;
hlen = IPH_HL(iphdr) * 4;
if (pbuf_header(p, -((s16_t)hlen)) || (p->tot_len < sizeof(u16_t)*2)) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%u bytes) received\n", p->tot_len));
pbuf_free(p);
ICMP_STATS_INC(icmp.lenerr);
snmp_inc_icmpinerrors();
return;
}
type = *((u8_t *)p->payload);
code = *(((u8_t *)p->payload)+1);
switch (type) {
case ICMP_ECHO:
/* broadcast or multicast destination address? */
if (ip_addr_isbroadcast(&iphdr->dest, inp) || ip_addr_ismulticast(&iphdr->dest)) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
ICMP_STATS_INC(icmp.err);
pbuf_free(p);
return;
}
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
pbuf_free(p);
ICMP_STATS_INC(icmp.lenerr);
snmp_inc_icmpinerrors();
return;
}
iecho = p->payload;
if (inet_chksum_pbuf(p) != 0) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
pbuf_free(p);
ICMP_STATS_INC(icmp.chkerr);
snmp_inc_icmpinerrors();
return;
}
tmpaddr.addr = iphdr->src.addr;
iphdr->src.addr = iphdr->dest.addr;
iphdr->dest.addr = tmpaddr.addr;
ICMPH_TYPE_SET(iecho, ICMP_ER);
/* adjust the checksum */
if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) {
iecho->chksum += htons(ICMP_ECHO << 8) + 1;
} else {
iecho->chksum += htons(ICMP_ECHO << 8);
}
ICMP_STATS_INC(icmp.xmit);
/* increase number of messages attempted to send */
snmp_inc_icmpoutmsgs();
/* increase number of echo replies attempted to send */
snmp_inc_icmpoutechoreps();
pbuf_header(p, hlen);
ip_output_if(p, &(iphdr->src), IP_HDRINCL,
IPH_TTL(iphdr), 0, IP_PROTO_ICMP, inp);
break;
default:
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %d code %d not supported.\n", (int)type, (int)code));
ICMP_STATS_INC(icmp.proterr);
ICMP_STATS_INC(icmp.drop);
}
pbuf_free(p);
}
void
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
{
struct pbuf *q;
struct ip_hdr *iphdr;
struct icmp_dur_hdr *idur;
q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
/* ICMP header + IP header + 8 bytes of data */
iphdr = p->payload;
idur = q->payload;
ICMPH_TYPE_SET(idur, ICMP_DUR);
ICMPH_CODE_SET(idur, t);
memcpy((char *)q->payload + 8, p->payload, IP_HLEN + 8);
/* calculate checksum */
idur->chksum = 0;
idur->chksum = inet_chksum(idur, q->len);
ICMP_STATS_INC(icmp.xmit);
/* increase number of messages attempted to send */
snmp_inc_icmpoutmsgs();
/* increase number of destination unreachable messages attempted to send */
snmp_inc_icmpoutdestunreachs();
ip_output(q, NULL, &(iphdr->src),
ICMP_TTL, 0, IP_PROTO_ICMP);
pbuf_free(q);
}
#if IP_FORWARD
void
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
{
struct pbuf *q;
struct ip_hdr *iphdr;
struct icmp_te_hdr *tehdr;
q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
iphdr = p->payload;
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
LWIP_DEBUGF(ICMP_DEBUG, (" to "));
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
tehdr = q->payload;
ICMPH_TYPE_SET(tehdr, ICMP_TE);
ICMPH_CODE_SET(tehdr, t);
/* copy fields from original packet */
memcpy((char *)q->payload + 8, (char *)p->payload, IP_HLEN + 8);
/* calculate checksum */
tehdr->chksum = 0;
tehdr->chksum = inet_chksum(tehdr, q->len);
ICMP_STATS_INC(icmp.xmit);
/* increase number of messages attempted to send */
snmp_inc_icmpoutmsgs();
/* increase number of destination unreachable messages attempted to send */
snmp_inc_icmpouttimeexcds();
ip_output(q, NULL, &(iphdr->src),
ICMP_TTL, 0, IP_PROTO_ICMP);
pbuf_free(q);
}
#endif /* IP_FORWARD */

View file

@ -0,0 +1,508 @@
/* @file
*
* This is the IP layer implementation for incoming and outgoing IP traffic.
*
* @see ip_frag.c
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/ip.h"
#include "lwip/ip_frag.h"
#include "lwip/inet.h"
#include "lwip/netif.h"
#include "lwip/icmp.h"
#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/stats.h"
#include "arch/perf.h"
#include "lwip/snmp.h"
#if LWIP_DHCP
# include "lwip/dhcp.h"
#endif /* LWIP_DHCP */
/**
* Initializes the IP layer.
*/
void
ip_init(void)
{
/* no initializations as of yet */
}
/**
* Finds the appropriate network interface for a given IP address. It
* searches the list of network interfaces linearly. A match is found
* if the masked IP address of the network interface equals the masked
* IP address given to the function.
*/
struct netif *
ip_route(struct ip_addr *dest)
{
struct netif *netif;
/* iterate through netifs */
for(netif = netif_list; netif != NULL; netif = netif->next) {
/* network mask matches? */
if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
/* return netif on which to forward IP packet */
return netif;
}
}
/* no matching netif found, use default netif */
return netif_default;
}
#if IP_FORWARD
/**
* Forwards an IP packet. It finds an appropriate route for the
* packet, decrements the TTL value of the packet, adjusts the
* checksum and outputs the packet on the appropriate interface.
*/
static struct netif *
ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
{
struct netif *netif;
PERF_START;
/* Find network interface where to forward this IP packet to. */
netif = ip_route((struct ip_addr *)&(iphdr->dest));
if (netif == NULL) {
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%lx found\n",
iphdr->dest.addr));
snmp_inc_ipnoroutes();
return (struct netif *)NULL;
}
/* Do not forward packets onto the same network interface on which
* they arrived. */
if (netif == inp) {
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
snmp_inc_ipnoroutes();
return (struct netif *)NULL;
}
/* decrement TTL */
IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
/* send ICMP if TTL == 0 */
if (IPH_TTL(iphdr) == 0) {
/* Don't send ICMP messages in response to ICMP messages */
if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
icmp_time_exceeded(p, ICMP_TE_TTL);
snmp_inc_icmpouttimeexcds();
}
return (struct netif *)NULL;
}
/* Incrementally update the IP checksum. */
if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) {
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1);
} else {
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100));
}
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%lx\n",
iphdr->dest.addr));
IP_STATS_INC(ip.fw);
IP_STATS_INC(ip.xmit);
snmp_inc_ipforwdatagrams();
PERF_STOP("ip_forward");
/* transmit pbuf on chosen interface */
netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));
return netif;
}
#endif /* IP_FORWARD */
/**
* This function is called by the network interface device driver when
* an IP packet is received. The function does the basic checks of the
* IP header such as packet size being at least larger than the header
* size etc. If the packet was not destined for us, the packet is
* forwarded (using ip_forward). The IP checksum is always checked.
*
* Finally, the packet is sent to the upper layer protocol input function.
*
*
*
*/
err_t
ip_input(struct pbuf *p, struct netif *inp) {
struct ip_hdr *iphdr;
struct netif *netif;
u16_t iphdrlen;
IP_STATS_INC(ip.recv);
snmp_inc_ipinreceives();
/* identify the IP header */
iphdr = p->payload;
if (IPH_V(iphdr) != 4) {
LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %u\n", IPH_V(iphdr)));
ip_debug_print(p);
pbuf_free(p);
IP_STATS_INC(ip.err);
IP_STATS_INC(ip.drop);
snmp_inc_ipunknownprotos();
return ERR_OK;
}
/* obtain IP header length in number of 32-bit words */
iphdrlen = IPH_HL(iphdr);
/* calculate IP header length in bytes */
iphdrlen *= 4;
/* header length exceeds first pbuf length? */
if (iphdrlen > p->len) {
LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %u) does not fit in first pbuf (len %u), IP packet droppped.\n",
iphdrlen, p->len));
/* free (drop) packet pbufs */
pbuf_free(p);
IP_STATS_INC(ip.lenerr);
IP_STATS_INC(ip.drop);
snmp_inc_ipindiscards();
return ERR_OK;
}
/* verify checksum */
#if CHECKSUM_CHECK_IP
if (inet_chksum(iphdr, iphdrlen) != 0) {
LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%x) failed, IP packet dropped.\n", inet_chksum(iphdr, iphdrlen)));
ip_debug_print(p);
pbuf_free(p);
IP_STATS_INC(ip.chkerr);
IP_STATS_INC(ip.drop);
snmp_inc_ipindiscards();
return ERR_OK;
}
#endif
/* Trim pbuf. This should have been done at the netif layer,
* but we'll do it anyway just to be sure that its done. */
pbuf_realloc(p, ntohs(IPH_LEN(iphdr)));
/* match packet against an interface, i.e. is this packet for us? */
for (netif = netif_list; netif != NULL; netif = netif->next) {
LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%lx netif->ip_addr 0x%lx (0x%lx, 0x%lx, 0x%lx)\n",
iphdr->dest.addr, netif->ip_addr.addr,
iphdr->dest.addr & netif->netmask.addr,
netif->ip_addr.addr & netif->netmask.addr,
iphdr->dest.addr & ~(netif->netmask.addr)));
/* interface is up and configured? */
if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr))))
{
/* unicast to this interface address? */
if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
/* or broadcast on this interface network address? */
ip_addr_isbroadcast(&(iphdr->dest), netif)) {
LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
netif->name[0], netif->name[1]));
/* break out of for loop */
break;
}
}
}
#if LWIP_DHCP
/* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
* using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
* According to RFC 1542 section 3.1.1, referred by RFC 2131).
*/
if (netif == NULL) {
/* remote port is DHCP server? */
if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %u\n",
ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest)));
if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest) == DHCP_CLIENT_PORT) {
LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));
netif = inp;
}
}
}
#endif /* LWIP_DHCP */
/* packet not for us? */
if (netif == NULL) {
/* packet not for us, route or discard */
LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: packet not for us.\n"));
#if IP_FORWARD
/* non-broadcast packet? */
if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {
/* try to forward IP packet on (other) interfaces */
ip_forward(p, iphdr, inp);
}
else
#endif /* IP_FORWARD */
{
snmp_inc_ipindiscards();
}
pbuf_free(p);
return ERR_OK;
}
/* packet consists of multiple fragments? */
if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
#if IP_REASSEMBLY /* packet fragment reassembly code present? */
LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04x tot_len=%u len=%u MF=%u offset=%u), calling ip_reass()\n",
ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
/* reassemble the packet*/
p = ip_reass(p);
/* packet not fully reassembled yet? */
if (p == NULL) {
return ERR_OK;
}
iphdr = p->payload;
#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
pbuf_free(p);
LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%x) (while IP_REASSEMBLY == 0).\n",
ntohs(IPH_OFFSET(iphdr))));
IP_STATS_INC(ip.opterr);
IP_STATS_INC(ip.drop);
snmp_inc_ipunknownprotos();
return ERR_OK;
#endif /* IP_REASSEMBLY */
}
#if IP_OPTIONS == 0 /* no support for IP options in the IP header? */
if (iphdrlen > IP_HLEN) {
LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS == 0).\n"));
pbuf_free(p);
IP_STATS_INC(ip.opterr);
IP_STATS_INC(ip.drop);
snmp_inc_ipunknownprotos();
return ERR_OK;
}
#endif /* IP_OPTIONS == 0 */
/* send to upper layers */
LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
ip_debug_print(p);
LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %d p->tot_len %d\n", p->len, p->tot_len));
#if LWIP_RAW
/* raw input did not eat the packet? */
if (raw_input(p, inp) == 0) {
#endif /* LWIP_RAW */
switch (IPH_PROTO(iphdr)) {
#if LWIP_UDP
case IP_PROTO_UDP:
case IP_PROTO_UDPLITE:
snmp_inc_ipindelivers();
udp_input(p, inp);
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case IP_PROTO_TCP:
snmp_inc_ipindelivers();
tcp_input(p, inp);
break;
#endif /* LWIP_TCP */
case IP_PROTO_ICMP:
snmp_inc_ipindelivers();
icmp_input(p, inp);
break;
default:
/* send ICMP destination protocol unreachable unless is was a broadcast */
if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&
!ip_addr_ismulticast(&(iphdr->dest))) {
p->payload = iphdr;
icmp_dest_unreach(p, ICMP_DUR_PROTO);
}
pbuf_free(p);
LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %d\n", IPH_PROTO(iphdr)));
IP_STATS_INC(ip.proterr);
IP_STATS_INC(ip.drop);
snmp_inc_ipunknownprotos();
}
#if LWIP_RAW
} /* LWIP_RAW */
#endif
return ERR_OK;
}
/**
* Sends an IP packet on a network interface. This function constructs
* the IP header and calculates the IP header checksum. If the source
* IP address is NULL, the IP address of the outgoing network
* interface is filled in as source address.
*/
err_t
ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
u8_t ttl, u8_t tos,
u8_t proto, struct netif *netif)
{
struct ip_hdr *iphdr;
u16_t ip_id = 0;
snmp_inc_ipoutrequests();
if (dest != IP_HDRINCL) {
if (pbuf_header(p, IP_HLEN)) {
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));
IP_STATS_INC(ip.err);
snmp_inc_ipoutdiscards();
return ERR_BUF;
}
iphdr = p->payload;
IPH_TTL_SET(iphdr, ttl);
IPH_PROTO_SET(iphdr, proto);
ip_addr_set(&(iphdr->dest), dest);
IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos);
IPH_LEN_SET(iphdr, htons(p->tot_len));
IPH_OFFSET_SET(iphdr, htons(IP_DF));
IPH_ID_SET(iphdr, htons(ip_id));
++ip_id;
if (ip_addr_isany(src)) {
ip_addr_set(&(iphdr->src), &(netif->ip_addr));
} else {
ip_addr_set(&(iphdr->src), src);
}
IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
#endif
} else {
iphdr = p->payload;
dest = &(iphdr->dest);
}
#if IP_FRAG
/* don't fragment if interface has mtu set to 0 [loopif] */
if (netif->mtu && (p->tot_len > netif->mtu))
return ip_frag(p,netif,dest);
#endif
IP_STATS_INC(ip.xmit);
LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%u\n", netif->name[0], netif->name[1], netif->num));
ip_debug_print(p);
LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
return netif->output(netif, p, dest);
}
/**
* Simple interface to ip_output_if. It finds the outgoing network
* interface and calls upon ip_output_if to do the actual work.
*/
err_t
ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
u8_t ttl, u8_t tos, u8_t proto)
{
struct netif *netif;
if ((netif = ip_route(dest)) == NULL) {
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: No route to 0x%lx\n", dest->addr));
IP_STATS_INC(ip.rterr);
snmp_inc_ipoutdiscards();
return ERR_RTE;
}
return ip_output_if(p, src, dest, ttl, tos, proto, netif);
}
#if IP_DEBUG
void
ip_debug_print(struct pbuf *p)
{
struct ip_hdr *iphdr = p->payload;
u8_t *payload;
payload = (u8_t *)iphdr + IP_HLEN;
LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("|%2d |%2d | 0x%02x | %5u | (v, hl, tos, len)\n",
IPH_V(iphdr),
IPH_HL(iphdr),
IPH_TOS(iphdr),
ntohs(IPH_LEN(iphdr))));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %5u |%u%u%u| %4u | (id, flags, offset)\n",
ntohs(IPH_ID(iphdr)),
ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,
ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,
ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,
ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %3u | %3u | 0x%04x | (ttl, proto, chksum)\n",
IPH_TTL(iphdr),
IPH_PROTO(iphdr),
ntohs(IPH_CHKSUM(iphdr))));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %3u | %3u | %3u | %3u | (src)\n",
ip4_addr1(&iphdr->src),
ip4_addr2(&iphdr->src),
ip4_addr3(&iphdr->src),
ip4_addr4(&iphdr->src)));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %3u | %3u | %3u | %3u | (dest)\n",
ip4_addr1(&iphdr->dest),
ip4_addr2(&iphdr->dest),
ip4_addr3(&iphdr->dest),
ip4_addr4(&iphdr->dest)));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
}
#endif /* IP_DEBUG */

View file

@ -0,0 +1,72 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/ip_addr.h"
#include "lwip/inet.h"
#include "lwip/netif.h"
/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
const struct ip_addr ip_addr_any = { 0x00000000UL };
const struct ip_addr ip_addr_broadcast = { 0xffffffffUL };
/* Determine if an address is a broadcast address on a network interface
*
* @param addr address to be checked
* @param netif the network interface against which the address is checked
* @return returns non-zero if the address is a broadcast address
*
*/
u8_t ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif)
{
/* all ones (broadcast) or all zeroes (old skool broadcast) */
if ((addr->addr == ip_addr_broadcast.addr) ||
(addr->addr == ip_addr_any.addr))
return 1;
/* no broadcast support on this network interface? */
else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0)
/* the given address cannot be a broadcast address
* nor can we check against any broadcast addresses */
return 0;
/* address matches network interface address exactly? => no broadcast */
else if (addr->addr == netif->ip_addr.addr)
return 0;
/* on the same (sub) network... */
else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask))
/* ...and host identifier bits are all ones? =>... */
&& ((addr->addr & ~netif->netmask.addr) ==
(ip_addr_broadcast.addr & ~netif->netmask.addr)))
/* => network broadcast address */
return 1;
else
return 0;
}

View file

@ -0,0 +1,345 @@
/* @file
*
* This is the IP packet segmentation and reassembly implementation.
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Jani Monoses <jani@iv.ro>
* original reassembly code by Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/sys.h"
#include "lwip/ip.h"
#include "lwip/ip_frag.h"
#include "lwip/netif.h"
#include "lwip/stats.h"
#include <string.h>
/*
* Copy len bytes from offset in pbuf to buffer
*
* helper used by both ip_reass and ip_frag
*/
static struct pbuf *
copy_from_pbuf(struct pbuf *p, u16_t * offset,
u8_t * buffer, u16_t len)
{
u16_t l;
p->payload = (u8_t *)p->payload + *offset;
p->len -= *offset;
while (len) {
l = len < p->len ? len : p->len;
memcpy(buffer, p->payload, l);
buffer += l;
len -= l;
if (len)
p = p->next;
else
*offset = l;
}
return p;
}
#define IP_REASS_BUFSIZE 5760
#define IP_REASS_MAXAGE 30
#define IP_REASS_TMO 1000
static u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE];
static u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8)];
static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f,
0x0f, 0x07, 0x03, 0x01
};
static u16_t ip_reasslen;
static u8_t ip_reassflags;
#define IP_REASS_FLAG_LASTFRAG 0x01
static u8_t ip_reasstmr;
/* Reassembly timer */
static void
ip_reass_timer(void *arg)
{
(void)arg;
if (ip_reasstmr > 1) {
ip_reasstmr--;
sys_timeout(IP_REASS_TMO, ip_reass_timer, NULL);
} else if (ip_reasstmr == 1)
ip_reasstmr = 0;
}
struct pbuf *
ip_reass(struct pbuf *p)
{
struct pbuf *q;
struct ip_hdr *fraghdr, *iphdr;
u16_t offset, len;
u16_t i;
IPFRAG_STATS_INC(ip_frag.recv);
iphdr = (struct ip_hdr *) ip_reassbuf;
fraghdr = (struct ip_hdr *) p->payload;
/* If ip_reasstmr is zero, no packet is present in the buffer, so we
write the IP header of the fragment into the reassembly
buffer. The timer is updated with the maximum age. */
if (ip_reasstmr == 0) {
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: new packet\n"));
memcpy(iphdr, fraghdr, IP_HLEN);
ip_reasstmr = IP_REASS_MAXAGE;
sys_timeout(IP_REASS_TMO, ip_reass_timer, NULL);
ip_reassflags = 0;
/* Clear the bitmap. */
memset(ip_reassbitmap, 0, sizeof(ip_reassbitmap));
}
/* Check if the incoming fragment matches the one currently present
in the reasembly buffer. If so, we proceed with copying the
fragment into the buffer. */
if (ip_addr_cmp(&iphdr->src, &fraghdr->src) &&
ip_addr_cmp(&iphdr->dest, &fraghdr->dest) &&
IPH_ID(iphdr) == IPH_ID(fraghdr)) {
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching old packet\n"));
IPFRAG_STATS_INC(ip_frag.cachehit);
/* Find out the offset in the reassembly buffer where we should
copy the fragment. */
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
/* If the offset or the offset + fragment length overflows the
reassembly buffer, we discard the entire packet. */
if (offset > IP_REASS_BUFSIZE || offset + len > IP_REASS_BUFSIZE) {
LWIP_DEBUGF(IP_REASS_DEBUG,
("ip_reass: fragment outside of buffer (%d:%d/%d).\n", offset,
offset + len, IP_REASS_BUFSIZE));
sys_untimeout(ip_reass_timer, NULL);
ip_reasstmr = 0;
goto nullreturn;
}
/* Copy the fragment into the reassembly buffer, at the right
offset. */
LWIP_DEBUGF(IP_REASS_DEBUG,
("ip_reass: copying with offset %d into %d:%d\n", offset,
IP_HLEN + offset, IP_HLEN + offset + len));
i = IPH_HL(fraghdr) * 4;
copy_from_pbuf(p, &i, &ip_reassbuf[IP_HLEN + offset], len);
/* Update the bitmap. */
if (offset / (8 * 8) == (offset + len) / (8 * 8)) {
LWIP_DEBUGF(IP_REASS_DEBUG,
("ip_reass: updating single byte in bitmap.\n"));
/* If the two endpoints are in the same byte, we only update
that byte. */
ip_reassbitmap[offset / (8 * 8)] |=
bitmap_bits[(offset / 8) & 7] &
~bitmap_bits[((offset + len) / 8) & 7];
} else {
/* If the two endpoints are in different bytes, we update the
bytes in the endpoints and fill the stuff inbetween with
0xff. */
ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7];
LWIP_DEBUGF(IP_REASS_DEBUG,
("ip_reass: updating many bytes in bitmap (%d:%d).\n",
1 + offset / (8 * 8), (offset + len) / (8 * 8)));
for (i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
ip_reassbitmap[i] = 0xff;
}
ip_reassbitmap[(offset + len) / (8 * 8)] |=
~bitmap_bits[((offset + len) / 8) & 7];
}
/* If this fragment has the More Fragments flag set to zero, we
know that this is the last fragment, so we can calculate the
size of the entire packet. We also set the
IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
the final fragment. */
if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {
ip_reassflags |= IP_REASS_FLAG_LASTFRAG;
ip_reasslen = offset + len;
LWIP_DEBUGF(IP_REASS_DEBUG,
("ip_reass: last fragment seen, total len %d\n",
ip_reasslen));
}
/* Finally, we check if we have a full packet in the buffer. We do
this by checking if we have the last fragment and if all bits
in the bitmap are set. */
if (ip_reassflags & IP_REASS_FLAG_LASTFRAG) {
/* Check all bytes up to and including all but the last byte in
the bitmap. */
for (i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) {
if (ip_reassbitmap[i] != 0xff) {
LWIP_DEBUGF(IP_REASS_DEBUG,
("ip_reass: last fragment seen, bitmap %d/%d failed (%x)\n",
i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i]));
goto nullreturn;
}
}
/* Check the last byte in the bitmap. It should contain just the
right amount of bits. */
if (ip_reassbitmap[ip_reasslen / (8 * 8)] !=
(u8_t) ~ bitmap_bits[ip_reasslen / 8 & 7]) {
LWIP_DEBUGF(IP_REASS_DEBUG,
("ip_reass: last fragment seen, bitmap %d didn't contain %x (%x)\n",
ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7],
ip_reassbitmap[ip_reasslen / (8 * 8)]));
goto nullreturn;
}
/* Pretend to be a "normal" (i.e., not fragmented) IP packet
from now on. */
ip_reasslen += IP_HLEN;
IPH_LEN_SET(iphdr, htons(ip_reasslen));
IPH_OFFSET_SET(iphdr, 0);
IPH_CHKSUM_SET(iphdr, 0);
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
/* If we have come this far, we have a full packet in the
buffer, so we allocate a pbuf and copy the packet into it. We
also reset the timer. */
sys_untimeout(ip_reass_timer, NULL);
ip_reasstmr = 0;
pbuf_free(p);
p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL);
if (p != NULL) {
i = 0;
for (q = p; q != NULL; q = q->next) {
/* Copy enough bytes to fill this pbuf in the chain. The
available data in the pbuf is given by the q->len
variable. */
LWIP_DEBUGF(IP_REASS_DEBUG,
("ip_reass: memcpy from %p (%d) to %p, %d bytes\n",
(void *)&ip_reassbuf[i], i, q->payload,
q->len > ip_reasslen - i ? ip_reasslen - i : q->len));
memcpy(q->payload, &ip_reassbuf[i],
q->len > ip_reasslen - i ? ip_reasslen - i : q->len);
i += q->len;
}
IPFRAG_STATS_INC(ip_frag.fw);
} else {
IPFRAG_STATS_INC(ip_frag.memerr);
}
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", (void*)p));
return p;
}
}
nullreturn:
IPFRAG_STATS_INC(ip_frag.drop);
pbuf_free(p);
return NULL;
}
#define MAX_MTU 1500
static u8_t buf[MEM_ALIGN_SIZE(MAX_MTU)];
/**
* Fragment an IP packet if too large
*
* Chop the packet in mtu sized chunks and send them in order
* by using a fixed size static memory buffer (PBUF_ROM)
*/
err_t
ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
{
struct pbuf *rambuf;
struct pbuf *header;
struct ip_hdr *iphdr;
u16_t nfb = 0;
u16_t left, cop;
u16_t mtu = netif->mtu;
u16_t ofo, omf;
u16_t last;
u16_t poff = IP_HLEN;
u16_t tmp;
/* Get a RAM based MTU sized pbuf */
rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
rambuf->tot_len = rambuf->len = mtu;
rambuf->payload = MEM_ALIGN((void *)buf);
/* Copy the IP header in it */
iphdr = rambuf->payload;
memcpy(iphdr, p->payload, IP_HLEN);
/* Save original offset */
tmp = ntohs(IPH_OFFSET(iphdr));
ofo = tmp & IP_OFFMASK;
omf = tmp & IP_MF;
left = p->tot_len - IP_HLEN;
while (left) {
last = (left <= mtu - IP_HLEN);
/* Set new offset and MF flag */
ofo += nfb;
tmp = omf | (IP_OFFMASK & (ofo));
if (!last)
tmp = tmp | IP_MF;
IPH_OFFSET_SET(iphdr, htons(tmp));
/* Fill this fragment */
nfb = (mtu - IP_HLEN) / 8;
cop = last ? left : nfb * 8;
p = copy_from_pbuf(p, &poff, (u8_t *) iphdr + IP_HLEN, cop);
/* Correct header */
IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
IPH_CHKSUM_SET(iphdr, 0);
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
if (last)
pbuf_realloc(rambuf, left + IP_HLEN);
/* This part is ugly: we alloc a RAM based pbuf for
* the link level header for each chunk and then
* free it.A PBUF_ROM style pbuf for which pbuf_header
* worked would make things simpler.
*/
header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
pbuf_chain(header, rambuf);
netif->output(netif, header, dest);
IPFRAG_STATS_INC(ip_frag.xmit);
pbuf_free(header);
left -= cop;
}
pbuf_free(rambuf);
return ERR_OK;
}

View file

@ -0,0 +1 @@
IPv6 support in lwIP is very experimental.

View file

@ -0,0 +1,184 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/* Some ICMP messages should be passed to the transport protocols. This
is not implemented. */
#include "lwip/opt.h"
#include "lwip/icmp.h"
#include "lwip/inet.h"
#include "lwip/ip.h"
#include "lwip/def.h"
#include "lwip/stats.h"
void
icmp_input(struct pbuf *p, struct netif *inp)
{
unsigned char type;
struct icmp_echo_hdr *iecho;
struct ip_hdr *iphdr;
struct ip_addr tmpaddr;
#ifdef ICMP_STATS
++lwip_stats.icmp.recv;
#endif /* ICMP_STATS */
/* TODO: check length before accessing payload! */
type = ((char *)p->payload)[0];
switch (type) {
case ICMP6_ECHO:
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
pbuf_free(p);
#ifdef ICMP_STATS
++lwip_stats.icmp.lenerr;
#endif /* ICMP_STATS */
return;
}
iecho = p->payload;
iphdr = (struct ip_hdr *)((char *)p->payload - IP_HLEN);
if (inet_chksum_pbuf(p) != 0) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%x)\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
#ifdef ICMP_STATS
++lwip_stats.icmp.chkerr;
#endif /* ICMP_STATS */
/* return;*/
}
LWIP_DEBUGF(ICMP_DEBUG, ("icmp: p->len %d p->tot_len %d\n", p->len, p->tot_len));
ip_addr_set(&tmpaddr, &(iphdr->src));
ip_addr_set(&(iphdr->src), &(iphdr->dest));
ip_addr_set(&(iphdr->dest), &tmpaddr);
iecho->type = ICMP6_ER;
/* adjust the checksum */
if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) {
iecho->chksum += htons(ICMP6_ECHO << 8) + 1;
} else {
iecho->chksum += htons(ICMP6_ECHO << 8);
}
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%x)\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
#ifdef ICMP_STATS
++lwip_stats.icmp.xmit;
#endif /* ICMP_STATS */
/* LWIP_DEBUGF("icmp: p->len %u p->tot_len %u\n", p->len, p->tot_len);*/
ip_output_if (p, &(iphdr->src), IP_HDRINCL,
iphdr->hoplim, IP_PROTO_ICMP, inp);
break;
default:
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %d not supported.\n", (int)type));
#ifdef ICMP_STATS
++lwip_stats.icmp.proterr;
++lwip_stats.icmp.drop;
#endif /* ICMP_STATS */
}
pbuf_free(p);
}
void
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
{
struct pbuf *q;
struct ip_hdr *iphdr;
struct icmp_dur_hdr *idur;
q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
/* ICMP header + IP header + 8 bytes of data */
iphdr = p->payload;
idur = q->payload;
idur->type = (char)ICMP6_DUR;
idur->icode = (char)t;
memcpy((char *)q->payload + 8, p->payload, IP_HLEN + 8);
/* calculate checksum */
idur->chksum = 0;
idur->chksum = inet_chksum(idur, q->len);
#ifdef ICMP_STATS
++lwip_stats.icmp.xmit;
#endif /* ICMP_STATS */
ip_output(q, NULL,
(struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
pbuf_free(q);
}
void
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
{
struct pbuf *q;
struct ip_hdr *iphdr;
struct icmp_te_hdr *tehdr;
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n"));
q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
iphdr = p->payload;
tehdr = q->payload;
tehdr->type = (char)ICMP6_TE;
tehdr->icode = (char)t;
/* copy fields from original packet */
memcpy((char *)q->payload + 8, (char *)p->payload, IP_HLEN + 8);
/* calculate checksum */
tehdr->chksum = 0;
tehdr->chksum = inet_chksum(tehdr, q->len);
#ifdef ICMP_STATS
++lwip_stats.icmp.xmit;
#endif /* ICMP_STATS */
ip_output(q, NULL,
(struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
pbuf_free(q);
}

View file

@ -0,0 +1,386 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/* ip.c
*
* This is the code for the IP layer for IPv6.
*
*/
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/ip.h"
#include "lwip/inet.h"
#include "lwip/netif.h"
#include "lwip/icmp.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/stats.h"
#include "arch/perf.h"
/* ip_init:
*
* Initializes the IP layer.
*/
void
ip_init(void)
{
}
/* ip_route:
*
* Finds the appropriate network interface for a given IP address. It searches the
* list of network interfaces linearly. A match is found if the masked IP address of
* the network interface equals the masked IP address given to the function.
*/
struct netif *
ip_route(struct ip_addr *dest)
{
struct netif *netif;
for(netif = netif_list; netif != NULL; netif = netif->next) {
if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
return netif;
}
}
return netif_default;
}
/* ip_forward:
*
* Forwards an IP packet. It finds an appropriate route for the packet, decrements
* the TTL value of the packet, adjusts the checksum and outputs the packet on the
* appropriate interface.
*/
static void
ip_forward(struct pbuf *p, struct ip_hdr *iphdr)
{
struct netif *netif;
PERF_START;
if ((netif = ip_route((struct ip_addr *)&(iphdr->dest))) == NULL) {
LWIP_DEBUGF(IP_DEBUG, ("ip_input: no forwarding route found for "));
#if IP_DEBUG
ip_addr_debug_print(IP_DEBUG, &(iphdr->dest));
#endif /* IP_DEBUG */
LWIP_DEBUGF(IP_DEBUG, ("\n"));
pbuf_free(p);
return;
}
/* Decrement TTL and send ICMP if ttl == 0. */
if (--iphdr->hoplim == 0) {
/* Don't send ICMP messages in response to ICMP messages */
if (iphdr->nexthdr != IP_PROTO_ICMP) {
icmp_time_exceeded(p, ICMP_TE_TTL);
}
pbuf_free(p);
return;
}
/* Incremental update of the IP checksum. */
/* if (iphdr->chksum >= htons(0xffff - 0x100)) {
iphdr->chksum += htons(0x100) + 1;
} else {
iphdr->chksum += htons(0x100);
}*/
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to "));
#if IP_DEBUG
ip_addr_debug_print(IP_DEBUG, &(iphdr->dest));
#endif /* IP_DEBUG */
LWIP_DEBUGF(IP_DEBUG, ("\n"));
#ifdef IP_STATS
++lwip_stats.ip.fw;
++lwip_stats.ip.xmit;
#endif /* IP_STATS */
PERF_STOP("ip_forward");
netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));
}
/* ip_input:
*
* This function is called by the network interface device driver when an IP packet is
* received. The function does the basic checks of the IP header such as packet size
* being at least larger than the header size etc. If the packet was not destined for
* us, the packet is forwarded (using ip_forward). The IP checksum is always checked.
*
* Finally, the packet is sent to the upper layer protocol input function.
*/
void
ip_input(struct pbuf *p, struct netif *inp) {
struct ip_hdr *iphdr;
struct netif *netif;
PERF_START;
#if IP_DEBUG
ip_debug_print(p);
#endif /* IP_DEBUG */
#ifdef IP_STATS
++lwip_stats.ip.recv;
#endif /* IP_STATS */
/* identify the IP header */
iphdr = p->payload;
if (iphdr->v != 6) {
LWIP_DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number\n"));
#if IP_DEBUG
ip_debug_print(p);
#endif /* IP_DEBUG */
pbuf_free(p);
#ifdef IP_STATS
++lwip_stats.ip.err;
++lwip_stats.ip.drop;
#endif /* IP_STATS */
return;
}
/* is this packet for us? */
for(netif = netif_list; netif != NULL; netif = netif->next) {
#if IP_DEBUG
LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest "));
ip_addr_debug_print(IP_DEBUG, &(iphdr->dest));
LWIP_DEBUGF(IP_DEBUG, ("netif->ip_addr "));
ip_addr_debug_print(IP_DEBUG, &(netif->ip_addr));
LWIP_DEBUGF(IP_DEBUG, ("\n"));
#endif /* IP_DEBUG */
if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr))) {
break;
}
}
if (netif == NULL) {
/* packet not for us, route or discard */
#ifdef IP_FORWARD
ip_forward(p, iphdr);
#endif
pbuf_free(p);
return;
}
pbuf_realloc(p, IP_HLEN + ntohs(iphdr->len));
/* send to upper layers */
#if IP_DEBUG
/* LWIP_DEBUGF("ip_input: \n");
ip_debug_print(p);
LWIP_DEBUGF("ip_input: p->len %u p->tot_len %u\n", p->len, p->tot_len);*/
#endif /* IP_DEBUG */
pbuf_header(p, -IP_HLEN);
switch (iphdr->nexthdr) {
case IP_PROTO_UDP:
udp_input(p);
break;
case IP_PROTO_TCP:
tcp_input(p);
break;
case IP_PROTO_ICMP:
icmp_input(p, inp);
break;
default:
/* send ICMP destination protocol unreachable */
icmp_dest_unreach(p, ICMP_DUR_PROTO);
pbuf_free(p);
LWIP_DEBUGF(IP_DEBUG, ("Unsupported transport protocol %u\n",
iphdr->nexthdr));
#ifdef IP_STATS
++lwip_stats.ip.proterr;
++lwip_stats.ip.drop;
#endif /* IP_STATS */
}
PERF_STOP("ip_input");
}
/* ip_output_if:
*
* Sends an IP packet on a network interface. This function constructs the IP header
* and calculates the IP header checksum. If the source IP address is NULL,
* the IP address of the outgoing network interface is filled in as source address.
*/
err_t
ip_output_if (struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
u8_t ttl,
u8_t proto, struct netif *netif)
{
struct ip_hdr *iphdr;
PERF_START;
printf("len %u tot_len %u\n", p->len, p->tot_len);
if (pbuf_header(p, IP_HLEN)) {
LWIP_DEBUGF(IP_DEBUG, ("ip_output: not enough room for IP header in pbuf\n"));
#ifdef IP_STATS
++lwip_stats.ip.err;
#endif /* IP_STATS */
return ERR_BUF;
}
printf("len %u tot_len %u\n", p->len, p->tot_len);
iphdr = p->payload;
if (dest != IP_HDRINCL) {
printf("!IP_HDRLINCL\n");
iphdr->hoplim = ttl;
iphdr->nexthdr = proto;
iphdr->len = htons(p->tot_len - IP_HLEN);
ip_addr_set(&(iphdr->dest), dest);
iphdr->v = 6;
if (ip_addr_isany(src)) {
ip_addr_set(&(iphdr->src), &(netif->ip_addr));
} else {
ip_addr_set(&(iphdr->src), src);
}
} else {
dest = &(iphdr->dest);
}
#ifdef IP_STATS
++lwip_stats.ip.xmit;
#endif /* IP_STATS */
LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c (len %u)\n", netif->name[0], netif->name[1], p->tot_len));
#if IP_DEBUG
ip_debug_print(p);
#endif /* IP_DEBUG */
PERF_STOP("ip_output_if");
return netif->output(netif, p, dest);
}
/* ip_output:
*
* Simple interface to ip_output_if. It finds the outgoing network interface and
* calls upon ip_output_if to do the actual work.
*/
err_t
ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
u8_t ttl, u8_t proto)
{
struct netif *netif;
if ((netif = ip_route(dest)) == NULL) {
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%lx\n", dest->addr));
#ifdef IP_STATS
++lwip_stats.ip.rterr;
#endif /* IP_STATS */
return ERR_RTE;
}
return ip_output_if (p, src, dest, ttl, proto, netif);
}
#if IP_DEBUG
void
ip_debug_print(struct pbuf *p)
{
struct ip_hdr *iphdr = p->payload;
char *payload;
payload = (char *)iphdr + IP_HLEN;
LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("|%2d | %x%x | %x%x | (v, traffic class, flow label)\n",
iphdr->v,
iphdr->tclass1, iphdr->tclass2,
iphdr->flow1, iphdr->flow2));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %5u | %2u | %2u | (len, nexthdr, hoplim)\n",
ntohs(iphdr->len),
iphdr->nexthdr,
iphdr->hoplim));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (src)\n",
ntohl(iphdr->src.addr[0]) >> 16 & 0xffff,
ntohl(iphdr->src.addr[0]) & 0xffff));
LWIP_DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (src)\n",
ntohl(iphdr->src.addr[1]) >> 16 & 0xffff,
ntohl(iphdr->src.addr[1]) & 0xffff));
LWIP_DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (src)\n",
ntohl(iphdr->src.addr[2]) >> 16 & 0xffff,
ntohl(iphdr->src.addr[2]) & 0xffff));
LWIP_DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (src)\n",
ntohl(iphdr->src.addr[3]) >> 16 & 0xffff,
ntohl(iphdr->src.addr[3]) & 0xffff));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (dest)\n",
ntohl(iphdr->dest.addr[0]) >> 16 & 0xffff,
ntohl(iphdr->dest.addr[0]) & 0xffff));
LWIP_DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (dest)\n",
ntohl(iphdr->dest.addr[1]) >> 16 & 0xffff,
ntohl(iphdr->dest.addr[1]) & 0xffff));
LWIP_DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (dest)\n",
ntohl(iphdr->dest.addr[2]) >> 16 & 0xffff,
ntohl(iphdr->dest.addr[2]) & 0xffff));
LWIP_DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (dest)\n",
ntohl(iphdr->dest.addr[3]) >> 16 & 0xffff,
ntohl(iphdr->dest.addr[3]) & 0xffff));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
}
#endif /* IP_DEBUG */

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/ip_addr.h"
#include "lwip/inet.h"
int
ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
struct ip_addr *mask)
{
return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) &&
(addr1->addr[1] & mask->addr[1]) == (addr2->addr[1] & mask->addr[1]) &&
(addr1->addr[2] & mask->addr[2]) == (addr2->addr[2] & mask->addr[2]) &&
(addr1->addr[3] & mask->addr[3]) == (addr2->addr[3] & mask->addr[3]));
}
int
ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2)
{
return(addr1->addr[0] == addr2->addr[0] &&
addr1->addr[1] == addr2->addr[1] &&
addr1->addr[2] == addr2->addr[2] &&
addr1->addr[3] == addr2->addr[3]);
}
void
ip_addr_set(struct ip_addr *dest, struct ip_addr *src)
{
memcpy(dest, src, sizeof(struct ip_addr));
/* dest->addr[0] = src->addr[0];
dest->addr[1] = src->addr[1];
dest->addr[2] = src->addr[2];
dest->addr[3] = src->addr[3];*/
}
int
ip_addr_isany(struct ip_addr *addr)
{
if (addr == NULL) return 1;
return((addr->addr[0] | addr->addr[1] | addr->addr[2] | addr->addr[3]) == 0);
}
/*#if IP_DEBUG*/
void
ip_addr_debug_print(struct ip_addr *addr)
{
printf("%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx",
ntohl(addr->addr[0]) >> 16 & 0xffff,
ntohl(addr->addr[0]) & 0xffff,
ntohl(addr->addr[1]) >> 16 & 0xffff,
ntohl(addr->addr[1]) & 0xffff,
ntohl(addr->addr[2]) >> 16 & 0xffff,
ntohl(addr->addr[2]) & 0xffff,
ntohl(addr->addr[3]) >> 16 & 0xffff,
ntohl(addr->addr[3]) & 0xffff);
}
/*#endif*/ /* IP_DEBUG */

View file

@ -0,0 +1,310 @@
/** @file
*
* Dynamic memory manager
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include <string.h>
#include "lwip/arch.h"
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/sys.h"
#include "lwip/stats.h"
struct mem {
mem_size_t next, prev;
#if MEM_ALIGNMENT == 1
u8_t used;
#elif MEM_ALIGNMENT == 2
u16_t used;
#elif MEM_ALIGNMENT == 4
u32_t used;
#elif MEM_ALIGNMENT == 8
u64_t used;
#else
#error "unhandled MEM_ALIGNMENT size"
#endif /* MEM_ALIGNMENT */
};
static struct mem *ram_end;
static u8_t ram[MEM_SIZE + sizeof(struct mem) + MEM_ALIGNMENT];
#define MIN_SIZE 12
#if 0 /* this one does not align correctly for some, resulting in crashes */
#define SIZEOF_STRUCT_MEM (unsigned int)MEM_ALIGN_SIZE(sizeof(struct mem))
#else
#define SIZEOF_STRUCT_MEM (sizeof(struct mem) + \
(((sizeof(struct mem) % MEM_ALIGNMENT) == 0)? 0 : \
(4 - (sizeof(struct mem) % MEM_ALIGNMENT))))
#endif
static struct mem *lfree; /* pointer to the lowest free block */
static sys_sem_t mem_sem;
static void
plug_holes(struct mem *mem)
{
struct mem *nmem;
struct mem *pmem;
LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);
/* plug hole forward */
LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE", mem->next <= MEM_SIZE);
nmem = (struct mem *)&ram[mem->next];
if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
if (lfree == nmem) {
lfree = mem;
}
mem->next = nmem->next;
((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;
}
/* plug hole backward */
pmem = (struct mem *)&ram[mem->prev];
if (pmem != mem && pmem->used == 0) {
if (lfree == mem) {
lfree = pmem;
}
pmem->next = mem->next;
((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;
}
}
void
mem_init(void)
{
struct mem *mem;
memset(ram, 0, MEM_SIZE);
mem = (struct mem *)ram;
mem->next = MEM_SIZE;
mem->prev = 0;
mem->used = 0;
ram_end = (struct mem *)&ram[MEM_SIZE];
ram_end->used = 1;
ram_end->next = MEM_SIZE;
ram_end->prev = MEM_SIZE;
mem_sem = sys_sem_new(1);
lfree = (struct mem *)ram;
#if MEM_STATS
lwip_stats.mem.avail = MEM_SIZE;
#endif /* MEM_STATS */
}
void
mem_free(void *rmem)
{
struct mem *mem;
if (rmem == NULL) {
LWIP_DEBUGF(MEM_DEBUG | DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n"));
return;
}
sys_sem_wait(mem_sem);
LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
(u8_t *)rmem < (u8_t *)ram_end);
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n"));
#if MEM_STATS
++lwip_stats.mem.err;
#endif /* MEM_STATS */
sys_sem_signal(mem_sem);
return;
}
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
LWIP_ASSERT("mem_free: mem->used", mem->used);
mem->used = 0;
if (mem < lfree) {
lfree = mem;
}
#if MEM_STATS
lwip_stats.mem.used -= mem->next - ((u8_t *)mem - ram);
#endif /* MEM_STATS */
plug_holes(mem);
sys_sem_signal(mem_sem);
}
void *
mem_reallocm(void *rmem, mem_size_t newsize)
{
void *nmem;
nmem = mem_malloc(newsize);
if (nmem == NULL) {
return mem_realloc(rmem, newsize);
}
memcpy(nmem, rmem, newsize);
mem_free(rmem);
return nmem;
}
void *
mem_realloc(void *rmem, mem_size_t newsize)
{
mem_size_t size;
mem_size_t ptr, ptr2;
struct mem *mem, *mem2;
/* Expand the size of the allocated memory region so that we can
adjust for alignment. */
if ((newsize % MEM_ALIGNMENT) != 0) {
newsize += MEM_ALIGNMENT - ((newsize + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);
}
if (newsize > MEM_SIZE) {
return NULL;
}
sys_sem_wait(mem_sem);
LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
(u8_t *)rmem < (u8_t *)ram_end);
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n"));
return rmem;
}
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
ptr = (u8_t *)mem - ram;
size = mem->next - ptr - SIZEOF_STRUCT_MEM;
#if MEM_STATS
lwip_stats.mem.used -= (size - newsize);
#endif /* MEM_STATS */
if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size) {
ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
mem2 = (struct mem *)&ram[ptr2];
mem2->used = 0;
mem2->next = mem->next;
mem2->prev = ptr;
mem->next = ptr2;
if (mem2->next != MEM_SIZE) {
((struct mem *)&ram[mem2->next])->prev = ptr2;
}
plug_holes(mem2);
}
sys_sem_signal(mem_sem);
return rmem;
}
void *
mem_malloc(mem_size_t size)
{
mem_size_t ptr, ptr2;
struct mem *mem, *mem2;
if (size == 0) {
return NULL;
}
/* Expand the size of the allocated memory region so that we can
adjust for alignment. */
if ((size % MEM_ALIGNMENT) != 0) {
size += MEM_ALIGNMENT - ((size + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);
}
if (size > MEM_SIZE) {
return NULL;
}
sys_sem_wait(mem_sem);
for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE; ptr = ((struct mem *)&ram[ptr])->next) {
mem = (struct mem *)&ram[ptr];
if (!mem->used &&
mem->next - (ptr + SIZEOF_STRUCT_MEM) >= size + SIZEOF_STRUCT_MEM) {
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
mem2 = (struct mem *)&ram[ptr2];
mem2->prev = ptr;
mem2->next = mem->next;
mem->next = ptr2;
if (mem2->next != MEM_SIZE) {
((struct mem *)&ram[mem2->next])->prev = ptr2;
}
mem2->used = 0;
mem->used = 1;
#if MEM_STATS
lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM);
/* if (lwip_stats.mem.max < lwip_stats.mem.used) {
lwip_stats.mem.max = lwip_stats.mem.used;
} */
if (lwip_stats.mem.max < ptr2) {
lwip_stats.mem.max = ptr2;
}
#endif /* MEM_STATS */
if (mem == lfree) {
/* Find next free block after mem */
while (lfree->used && lfree != ram_end) {
lfree = (struct mem *)&ram[lfree->next];
}
LWIP_ASSERT("mem_malloc: !lfree->used", !lfree->used);
}
sys_sem_signal(mem_sem);
LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
(mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
(unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
return (u8_t *)mem + SIZEOF_STRUCT_MEM;
}
}
LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %d bytes\n", (int)size));
#if MEM_STATS
++lwip_stats.mem.err;
#endif /* MEM_STATS */
sys_sem_signal(mem_sem);
return NULL;
}

View file

@ -0,0 +1,274 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/memp.h"
#include "lwip/pbuf.h"
#include "lwip/udp.h"
#include "lwip/raw.h"
#include "lwip/tcp.h"
#include "lwip/api.h"
#include "lwip/api_msg.h"
#include "lwip/tcpip.h"
#include "lwip/sys.h"
#include "lwip/stats.h"
struct memp {
struct memp *next;
};
static struct memp *memp_tab[MEMP_MAX];
static const u16_t memp_sizes[MEMP_MAX] = {
sizeof(struct pbuf),
sizeof(struct raw_pcb),
sizeof(struct udp_pcb),
sizeof(struct tcp_pcb),
sizeof(struct tcp_pcb_listen),
sizeof(struct tcp_seg),
sizeof(struct netbuf),
sizeof(struct netconn),
sizeof(struct api_msg),
sizeof(struct tcpip_msg),
sizeof(struct sys_timeout)
};
static const u16_t memp_num[MEMP_MAX] = {
MEMP_NUM_PBUF,
MEMP_NUM_RAW_PCB,
MEMP_NUM_UDP_PCB,
MEMP_NUM_TCP_PCB,
MEMP_NUM_TCP_PCB_LISTEN,
MEMP_NUM_TCP_SEG,
MEMP_NUM_NETBUF,
MEMP_NUM_NETCONN,
MEMP_NUM_API_MSG,
MEMP_NUM_TCPIP_MSG,
MEMP_NUM_SYS_TIMEOUT
};
static u8_t memp_memory[(MEMP_NUM_PBUF *
MEM_ALIGN_SIZE(sizeof(struct pbuf) +
sizeof(struct memp)) +
MEMP_NUM_RAW_PCB *
MEM_ALIGN_SIZE(sizeof(struct raw_pcb) +
sizeof(struct memp)) +
MEMP_NUM_UDP_PCB *
MEM_ALIGN_SIZE(sizeof(struct udp_pcb) +
sizeof(struct memp)) +
MEMP_NUM_TCP_PCB *
MEM_ALIGN_SIZE(sizeof(struct tcp_pcb) +
sizeof(struct memp)) +
MEMP_NUM_TCP_PCB_LISTEN *
MEM_ALIGN_SIZE(sizeof(struct tcp_pcb_listen) +
sizeof(struct memp)) +
MEMP_NUM_TCP_SEG *
MEM_ALIGN_SIZE(sizeof(struct tcp_seg) +
sizeof(struct memp)) +
MEMP_NUM_NETBUF *
MEM_ALIGN_SIZE(sizeof(struct netbuf) +
sizeof(struct memp)) +
MEMP_NUM_NETCONN *
MEM_ALIGN_SIZE(sizeof(struct netconn) +
sizeof(struct memp)) +
MEMP_NUM_API_MSG *
MEM_ALIGN_SIZE(sizeof(struct api_msg) +
sizeof(struct memp)) +
MEMP_NUM_TCPIP_MSG *
MEM_ALIGN_SIZE(sizeof(struct tcpip_msg) +
sizeof(struct memp)) +
MEMP_NUM_SYS_TIMEOUT *
MEM_ALIGN_SIZE(sizeof(struct sys_timeout) +
sizeof(struct memp)))];
#if !SYS_LIGHTWEIGHT_PROT
static sys_sem_t mutex;
#endif
#if MEMP_SANITY_CHECK
static int
memp_sanity(void)
{
int i, c;
struct memp *m, *n;
for(i = 0; i < MEMP_MAX; i++) {
for(m = memp_tab[i]; m != NULL; m = m->next) {
c = 1;
for(n = memp_tab[i]; n != NULL; n = n->next) {
if (n == m) {
--c;
}
if (c < 0) return 0; /* LW was: abort(); */
}
}
}
return 1;
}
#endif /* MEMP_SANITY_CHECK*/
void
memp_init(void)
{
struct memp *m, *memp;
u16_t i, j;
u16_t size;
#if MEMP_STATS
for(i = 0; i < MEMP_MAX; ++i) {
lwip_stats.memp[i].used = lwip_stats.memp[i].max =
lwip_stats.memp[i].err = 0;
lwip_stats.memp[i].avail = memp_num[i];
}
#endif /* MEMP_STATS */
memp = (struct memp *)&memp_memory[0];
for(i = 0; i < MEMP_MAX; ++i) {
size = MEM_ALIGN_SIZE(memp_sizes[i] + sizeof(struct memp));
if (memp_num[i] > 0) {
memp_tab[i] = memp;
m = memp;
for(j = 0; j < memp_num[i]; ++j) {
m->next = (struct memp *)MEM_ALIGN((u8_t *)m + size);
memp = m;
m = m->next;
}
memp->next = NULL;
memp = m;
} else {
memp_tab[i] = NULL;
}
}
#if !SYS_LIGHTWEIGHT_PROT
mutex = sys_sem_new(1);
#endif
}
void *
memp_malloc(memp_t type)
{
struct memp *memp;
void *mem;
#if SYS_LIGHTWEIGHT_PROT
SYS_ARCH_DECL_PROTECT(old_level);
#endif
LWIP_ASSERT("memp_malloc: type < MEMP_MAX", type < MEMP_MAX);
#if SYS_LIGHTWEIGHT_PROT
SYS_ARCH_PROTECT(old_level);
#else /* SYS_LIGHTWEIGHT_PROT */
sys_sem_wait(mutex);
#endif /* SYS_LIGHTWEIGHT_PROT */
memp = memp_tab[type];
if (memp != NULL) {
memp_tab[type] = memp->next;
memp->next = NULL;
#if MEMP_STATS
++lwip_stats.memp[type].used;
if (lwip_stats.memp[type].used > lwip_stats.memp[type].max) {
lwip_stats.memp[type].max = lwip_stats.memp[type].used;
}
#endif /* MEMP_STATS */
#if SYS_LIGHTWEIGHT_PROT
SYS_ARCH_UNPROTECT(old_level);
#else /* SYS_LIGHTWEIGHT_PROT */
sys_sem_signal(mutex);
#endif /* SYS_LIGHTWEIGHT_PROT */
LWIP_ASSERT("memp_malloc: memp properly aligned",
((mem_ptr_t)MEM_ALIGN((u8_t *)memp + sizeof(struct memp)) % MEM_ALIGNMENT) == 0);
mem = MEM_ALIGN((u8_t *)memp + sizeof(struct memp));
return mem;
} else {
LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %d\n", type));
#if MEMP_STATS
++lwip_stats.memp[type].err;
#endif /* MEMP_STATS */
#if SYS_LIGHTWEIGHT_PROT
SYS_ARCH_UNPROTECT(old_level);
#else /* SYS_LIGHTWEIGHT_PROT */
sys_sem_signal(mutex);
#endif /* SYS_LIGHTWEIGHT_PROT */
return NULL;
}
}
void
memp_free(memp_t type, void *mem)
{
struct memp *memp;
#if SYS_LIGHTWEIGHT_PROT
SYS_ARCH_DECL_PROTECT(old_level);
#endif /* SYS_LIGHTWEIGHT_PROT */
if (mem == NULL) {
return;
}
memp = (struct memp *)((u8_t *)mem - sizeof(struct memp));
#if SYS_LIGHTWEIGHT_PROT
SYS_ARCH_PROTECT(old_level);
#else /* SYS_LIGHTWEIGHT_PROT */
sys_sem_wait(mutex);
#endif /* SYS_LIGHTWEIGHT_PROT */
#if MEMP_STATS
lwip_stats.memp[type].used--;
#endif /* MEMP_STATS */
memp->next = memp_tab[type];
memp_tab[type] = memp;
#if MEMP_SANITY_CHECK
LWIP_ASSERT("memp sanity", memp_sanity());
#endif
#if SYS_LIGHTWEIGHT_PROT
SYS_ARCH_UNPROTECT(old_level);
#else /* SYS_LIGHTWEIGHT_PROT */
sys_sem_signal(mutex);
#endif /* SYS_LIGHTWEIGHT_PROT */
}

View file

@ -0,0 +1,288 @@
/**
* @file
*
* lwIP network interface abstraction
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/tcp.h"
struct netif *netif_list = NULL;
struct netif *netif_default = NULL;
/**
* Add a network interface to the list of lwIP netifs.
*
* @param netif a pre-allocated netif structure
* @param ipaddr IP address for the new netif
* @param netmask network mask for the new netif
* @param gw default gateway IP address for the new netif
* @param state opaque data passed to the new netif
* @param init callback function that initializes the interface
* @param input callback function that is called to pass
* ingress packets up in the protocol layer stack.
*
* @return netif, or NULL if failed.
*/
struct netif *
netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
struct ip_addr *gw,
void *state,
err_t (* init)(struct netif *netif),
err_t (* input)(struct pbuf *p, struct netif *netif))
{
static int netifnum = 0;
#if LWIP_DHCP
/* netif not under DHCP control by default */
netif->dhcp = NULL;
#endif
/* remember netif specific state information data */
netif->state = state;
netif->num = netifnum++;
netif->input = input;
netif_set_addr(netif, ipaddr, netmask, gw);
/* call user specified initialization function for netif */
if (init(netif) != ERR_OK) {
return NULL;
}
/* add this netif to the list */
netif->next = netif_list;
netif_list = netif;
LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ",
netif->name[0], netif->name[1]));
ip_addr_debug_print(NETIF_DEBUG, ipaddr);
LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));
ip_addr_debug_print(NETIF_DEBUG, netmask);
LWIP_DEBUGF(NETIF_DEBUG, (" gw "));
ip_addr_debug_print(NETIF_DEBUG, gw);
LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
return netif;
}
void
netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask,
struct ip_addr *gw)
{
netif_set_ipaddr(netif, ipaddr);
netif_set_netmask(netif, netmask);
netif_set_gw(netif, gw);
}
void netif_remove(struct netif * netif)
{
if ( netif == NULL ) return;
/* is it the first netif? */
if (netif_list == netif) {
netif_list = netif->next;
}
else {
/* look for netif further down the list */
struct netif * tmpNetif;
for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {
if (tmpNetif->next == netif) {
tmpNetif->next = netif->next;
break;
}
}
if (tmpNetif == NULL)
return; /* we didn't find any netif today */
}
/* this netif is default? */
if (netif_default == netif)
/* reset default netif */
netif_default = NULL;
LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
}
struct netif *
netif_find(char *name)
{
struct netif *netif;
u8_t num;
if (name == NULL) {
return NULL;
}
num = name[2] - '0';
for(netif = netif_list; netif != NULL; netif = netif->next) {
if (num == netif->num &&
name[0] == netif->name[0] &&
name[1] == netif->name[1]) {
LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1]));
return netif;
}
}
LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1]));
return NULL;
}
void
netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
{
/* TODO: Handling of obsolete pcbs */
/* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */
#if LWIP_TCP
struct tcp_pcb *pcb;
struct tcp_pcb_listen *lpcb;
/* address is actually being changed? */
if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0)
{
/* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: netif address being changed\n"));
pcb = tcp_active_pcbs;
while (pcb != NULL) {
/* PCB bound to current local interface address? */
if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
/* this connection must be aborted */
struct tcp_pcb *next = pcb->next;
LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
tcp_abort(pcb);
pcb = next;
} else {
pcb = pcb->next;
}
}
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
/* PCB bound to current local interface address? */
if (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr))) {
/* The PCB is listening to the old ipaddr and
* is set to listen to the new one instead */
ip_addr_set(&(lpcb->local_ip), ipaddr);
}
}
}
#endif
ip_addr_set(&(netif->ip_addr), ipaddr);
#if 0 /* only allowed for Ethernet interfaces TODO: how can we check? */
/** For Ethernet network interfaces, we would like to send a
* "gratuitous ARP"; this is an ARP packet sent by a node in order
* to spontaneously cause other nodes to update an entry in their
* ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.
*/
etharp_query(netif, ipaddr, NULL);
#endif
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: IP address of interface %c%c set to %u.%u.%u.%u\n",
netif->name[0], netif->name[1],
ip4_addr1(&netif->ip_addr),
ip4_addr2(&netif->ip_addr),
ip4_addr3(&netif->ip_addr),
ip4_addr4(&netif->ip_addr)));
}
void
netif_set_gw(struct netif *netif, struct ip_addr *gw)
{
ip_addr_set(&(netif->gw), gw);
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: GW address of interface %c%c set to %u.%u.%u.%u\n",
netif->name[0], netif->name[1],
ip4_addr1(&netif->gw),
ip4_addr2(&netif->gw),
ip4_addr3(&netif->gw),
ip4_addr4(&netif->gw)));
}
void
netif_set_netmask(struct netif *netif, struct ip_addr *netmask)
{
ip_addr_set(&(netif->netmask), netmask);
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE | DBG_STATE | 3, ("netif: netmask of interface %c%c set to %u.%u.%u.%u\n",
netif->name[0], netif->name[1],
ip4_addr1(&netif->netmask),
ip4_addr2(&netif->netmask),
ip4_addr3(&netif->netmask),
ip4_addr4(&netif->netmask)));
}
void
netif_set_default(struct netif *netif)
{
netif_default = netif;
LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",
netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));
}
/**
* Bring an interface up, available for processing
* traffic.
*
* @note: Enabling DHCP on a down interface will make it come
* up once configured.
*
* @see dhcp_start()
*/
void netif_set_up(struct netif *netif)
{
netif->flags |= NETIF_FLAG_UP;
}
/**
* Ask if an interface is up
*/
u8_t netif_is_up(struct netif *netif)
{
return (netif->flags & NETIF_FLAG_UP)?1:0;
}
/**
* Bring an interface down, disabling any traffic processing.
*
* @note: Enabling DHCP on a down interface will make it come
* up once configured.
*
* @see dhcp_start()
*/
void netif_set_down(struct netif *netif)
{
netif->flags &= ~NETIF_FLAG_UP;
}
void
netif_init(void)
{
netif_list = netif_default = NULL;
}

View file

@ -0,0 +1,962 @@
/**
* @file
* Packet buffer management
*
* Packets are built from the pbuf data structure. It supports dynamic
* memory allocation for packet contents or can reference externally
* managed packet contents both in RAM and ROM. Quick allocation for
* incoming packets is provided through pools with fixed sized pbufs.
*
* A packet may span over multiple pbufs, chained as a singly linked
* list. This is called a "pbuf chain".
*
* Multiple packets may be queued, also using this singly linked list.
* This is called a "packet queue".
*
* So, a packet queue consists of one or more pbuf chains, each of
* which consist of one or more pbufs. Currently, queues are only
* supported in a limited section of lwIP, this is the etharp queueing
* code. Outside of this section no packet queues are supported yet.
*
* The differences between a pbuf chain and a packet queue are very
* precise but subtle.
*
* The last pbuf of a packet has a ->tot_len field that equals the
* ->len field. It can be found by traversing the list. If the last
* pbuf of a packet has a ->next field other than NULL, more packets
* are on the queue.
*
* Therefore, looping through a pbuf of a single packet, has an
* loop end condition (tot_len == p->len), NOT (next == NULL).
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/stats.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "arch/perf.h"
#include <string.h>
static u8_t pbuf_pool_memory[(PBUF_POOL_SIZE * MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE + sizeof(struct pbuf)))];
#if !SYS_LIGHTWEIGHT_PROT
static volatile u8_t pbuf_pool_free_lock, pbuf_pool_alloc_lock;
static sys_sem_t pbuf_pool_free_sem;
#endif
static struct pbuf *pbuf_pool = NULL;
/**
* Initializes the pbuf module.
*
* A large part of memory is allocated for holding the pool of pbufs.
* The size of the individual pbufs in the pool is given by the size
* parameter, and the number of pbufs in the pool by the num parameter.
*
* After the memory has been allocated, the pbufs are set up. The
* ->next pointer in each pbuf is set up to point to the next pbuf in
* the pool.
*
*/
void
pbuf_init(void)
{
struct pbuf *p, *q = NULL;
u16_t i;
pbuf_pool = (struct pbuf *)&pbuf_pool_memory[0];
LWIP_ASSERT("pbuf_init: pool aligned", (mem_ptr_t)pbuf_pool % MEM_ALIGNMENT == 0);
#if PBUF_STATS
lwip_stats.pbuf.avail = PBUF_POOL_SIZE;
#endif /* PBUF_STATS */
/* Set up ->next pointers to link the pbufs of the pool together */
p = pbuf_pool;
for(i = 0; i < PBUF_POOL_SIZE; ++i) {
p->next = (struct pbuf *)((u8_t *)p + PBUF_POOL_BUFSIZE + sizeof(struct pbuf));
p->len = p->tot_len = PBUF_POOL_BUFSIZE;
p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf)));
p->flags = PBUF_FLAG_POOL;
q = p;
p = p->next;
}
/* The ->next pointer of last pbuf is NULL to indicate that there
are no more pbufs in the pool */
q->next = NULL;
#if !SYS_LIGHTWEIGHT_PROT
pbuf_pool_alloc_lock = 0;
pbuf_pool_free_lock = 0;
pbuf_pool_free_sem = sys_sem_new(1);
#endif
}
/**
* @internal only called from pbuf_alloc()
*/
static struct pbuf *
pbuf_pool_alloc(void)
{
struct pbuf *p = NULL;
SYS_ARCH_DECL_PROTECT(old_level);
SYS_ARCH_PROTECT(old_level);
#if !SYS_LIGHTWEIGHT_PROT
/* Next, check the actual pbuf pool, but if the pool is locked, we
pretend to be out of buffers and return NULL. */
if (pbuf_pool_free_lock) {
#if PBUF_STATS
++lwip_stats.pbuf.alloc_locked;
#endif /* PBUF_STATS */
return NULL;
}
pbuf_pool_alloc_lock = 1;
if (!pbuf_pool_free_lock) {
#endif /* SYS_LIGHTWEIGHT_PROT */
p = pbuf_pool;
if (p) {
pbuf_pool = p->next;
}
#if !SYS_LIGHTWEIGHT_PROT
#if PBUF_STATS
} else {
++lwip_stats.pbuf.alloc_locked;
#endif /* PBUF_STATS */
}
pbuf_pool_alloc_lock = 0;
#endif /* SYS_LIGHTWEIGHT_PROT */
#if PBUF_STATS
if (p != NULL) {
++lwip_stats.pbuf.used;
if (lwip_stats.pbuf.used > lwip_stats.pbuf.max) {
lwip_stats.pbuf.max = lwip_stats.pbuf.used;
}
}
#endif /* PBUF_STATS */
SYS_ARCH_UNPROTECT(old_level);
return p;
}
/**
* Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
*
* The actual memory allocated for the pbuf is determined by the
* layer at which the pbuf is allocated and the requested size
* (from the size parameter).
*
* @param flag this parameter decides how and where the pbuf
* should be allocated as follows:
*
* - PBUF_RAM: buffer memory for pbuf is allocated as one large
* chunk. This includes protocol headers as well.
* - PBUF_ROM: no buffer memory is allocated for the pbuf, even for
* protocol headers. Additional headers must be prepended
* by allocating another pbuf and chain in to the front of
* the ROM pbuf. It is assumed that the memory used is really
* similar to ROM in that it is immutable and will not be
* changed. Memory which is dynamic should generally not
* be attached to PBUF_ROM pbufs. Use PBUF_REF instead.
* - PBUF_REF: no buffer memory is allocated for the pbuf, even for
* protocol headers. It is assumed that the pbuf is only
* being used in a single thread. If the pbuf gets queued,
* then pbuf_take should be called to copy the buffer.
* - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from
* the pbuf pool that is allocated during pbuf_init().
*
* @return the allocated pbuf. If multiple pbufs where allocated, this
* is the first pbuf of a pbuf chain.
*/
struct pbuf *
pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag)
{
struct pbuf *p, *q, *r;
u16_t offset;
s32_t rem_len; /* remaining length */
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%u)\n", length));
/* determine header offset */
offset = 0;
switch (l) {
case PBUF_TRANSPORT:
/* add room for transport (often TCP) layer header */
offset += PBUF_TRANSPORT_HLEN;
/* FALLTHROUGH */
case PBUF_IP:
/* add room for IP layer header */
offset += PBUF_IP_HLEN;
/* FALLTHROUGH */
case PBUF_LINK:
/* add room for link layer header */
offset += PBUF_LINK_HLEN;
break;
case PBUF_RAW:
break;
default:
LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
return NULL;
}
switch (flag) {
case PBUF_POOL:
/* allocate head of pbuf chain into p */
p = pbuf_pool_alloc();
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
if (p == NULL) {
#if PBUF_STATS
++lwip_stats.pbuf.err;
#endif /* PBUF_STATS */
return NULL;
}
p->next = NULL;
/* make the payload pointer point 'offset' bytes into pbuf data memory */
p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset)));
LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
/* the total length of the pbuf chain is the requested size */
p->tot_len = length;
/* set the length of the first pbuf in the chain */
p->len = length > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: length;
/* set reference count (needed here in case we fail) */
p->ref = 1;
/* now allocate the tail of the pbuf chain */
/* remember first pbuf for linkage in next iteration */
r = p;
/* remaining length to be allocated */
rem_len = length - p->len;
/* any remaining pbufs to be allocated? */
while (rem_len > 0) {
q = pbuf_pool_alloc();
if (q == NULL) {
LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_alloc: Out of pbufs in pool.\n"));
#if PBUF_STATS
++lwip_stats.pbuf.err;
#endif /* PBUF_STATS */
/* free chain so far allocated */
pbuf_free(p);
/* bail out unsuccesfully */
return NULL;
}
q->next = NULL;
/* make previous pbuf point to this pbuf */
r->next = q;
/* set total length of this pbuf and next in chain */
q->tot_len = rem_len;
/* this pbuf length is pool size, unless smaller sized tail */
q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len;
q->payload = (void *)((u8_t *)q + sizeof(struct pbuf));
LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);
q->ref = 1;
/* calculate remaining length to be allocated */
rem_len -= q->len;
/* remember this pbuf for linkage in next iteration */
r = q;
}
/* end of chain */
/*r->next = NULL;*/
break;
case PBUF_RAM:
/* If pbuf is to be allocated in RAM, allocate memory for it. */
p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + offset) + MEM_ALIGN_SIZE(length));
if (p == NULL) {
return NULL;
}
/* Set up internal structure of the pbuf. */
p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + offset));
p->len = p->tot_len = length;
p->next = NULL;
p->flags = PBUF_FLAG_RAM;
LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
break;
/* pbuf references existing (non-volatile static constant) ROM payload? */
case PBUF_ROM:
/* pbuf references existing (externally allocated) RAM payload? */
case PBUF_REF:
/* only allocate memory for the pbuf structure */
p = memp_malloc(MEMP_PBUF);
if (p == NULL) {
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", flag == PBUF_ROM?"ROM":"REF"));
return NULL;
}
/* caller must set this field properly, afterwards */
p->payload = NULL;
p->len = p->tot_len = length;
p->next = NULL;
p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF);
break;
default:
LWIP_ASSERT("pbuf_alloc: erroneous flag", 0);
return NULL;
}
/* set reference count */
p->ref = 1;
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%u) == %p\n", length, (void *)p));
return p;
}
#if PBUF_STATS
#define DEC_PBUF_STATS do { --lwip_stats.pbuf.used; } while (0)
#else /* PBUF_STATS */
#define DEC_PBUF_STATS
#endif /* PBUF_STATS */
#define PBUF_POOL_FAST_FREE(p) do { \
p->next = pbuf_pool; \
pbuf_pool = p; \
DEC_PBUF_STATS; \
} while (0)
#if SYS_LIGHTWEIGHT_PROT
#define PBUF_POOL_FREE(p) do { \
SYS_ARCH_DECL_PROTECT(old_level); \
SYS_ARCH_PROTECT(old_level); \
PBUF_POOL_FAST_FREE(p); \
SYS_ARCH_UNPROTECT(old_level); \
} while (0)
#else /* SYS_LIGHTWEIGHT_PROT */
#define PBUF_POOL_FREE(p) do { \
sys_sem_wait(pbuf_pool_free_sem); \
PBUF_POOL_FAST_FREE(p); \
sys_sem_signal(pbuf_pool_free_sem); \
} while (0)
#endif /* SYS_LIGHTWEIGHT_PROT */
/**
* Shrink a pbuf chain to a desired length.
*
* @param p pbuf to shrink.
* @param new_len desired new length of pbuf chain
*
* Depending on the desired length, the first few pbufs in a chain might
* be skipped and left unchanged. The new last pbuf in the chain will be
* resized, and any remaining pbufs will be freed.
*
* @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.
* @note May not be called on a packet queue.
*
* @bug Cannot grow the size of a pbuf (chain) (yet).
*/
void
pbuf_realloc(struct pbuf *p, u16_t new_len)
{
struct pbuf *q;
u16_t rem_len; /* remaining length */
s16_t grow;
LWIP_ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL ||
p->flags == PBUF_FLAG_ROM ||
p->flags == PBUF_FLAG_RAM ||
p->flags == PBUF_FLAG_REF);
/* desired length larger than current length? */
if (new_len >= p->tot_len) {
/* enlarging not yet supported */
return;
}
/* the pbuf chain grows by (new_len - p->tot_len) bytes
* (which may be negative in case of shrinking) */
grow = new_len - p->tot_len;
/* first, step over any pbufs that should remain in the chain */
rem_len = new_len;
q = p;
/* should this pbuf be kept? */
while (rem_len > q->len) {
/* decrease remaining length by pbuf length */
rem_len -= q->len;
/* decrease total length indicator */
q->tot_len += grow;
/* proceed to next pbuf in chain */
q = q->next;
}
/* we have now reached the new last pbuf (in q) */
/* rem_len == desired length for pbuf q */
/* shrink allocated memory for PBUF_RAM */
/* (other types merely adjust their length fields */
if ((q->flags == PBUF_FLAG_RAM) && (rem_len != q->len)) {
/* reallocate and adjust the length of the pbuf that will be split */
mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);
}
/* adjust length fields for new last pbuf */
q->len = rem_len;
q->tot_len = q->len;
/* any remaining pbufs in chain? */
if (q->next != NULL) {
/* free remaining pbufs in chain */
pbuf_free(q->next);
}
/* q is last packet in chain */
q->next = NULL;
}
/**
* Adjusts the payload pointer to hide or reveal headers in the payload.
*
* Adjusts the ->payload pointer so that space for a header
* (dis)appears in the pbuf payload.
*
* The ->payload, ->tot_len and ->len fields are adjusted.
*
* @param hdr_size_inc Number of bytes to increment header size which
* increases the size of the pbuf. New space is on the front.
* (Using a negative value decreases the header size.)
* If hdr_size_inc is 0, this function does nothing and returns succesful.
*
* PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so
* the call will fail. A check is made that the increase in header size does
* not move the payload pointer in front of the start of the buffer.
* @return non-zero on failure, zero on success.
*
*/
u8_t
pbuf_header(struct pbuf *p, s16_t header_size_increment)
{
void *payload;
LWIP_ASSERT("p != NULL", p != NULL);
if ((header_size_increment == 0) || (p == NULL)) return 0;
/* remember current payload pointer */
payload = p->payload;
/* pbuf types containing payloads? */
if (p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_POOL) {
/* set new payload pointer */
p->payload = (u8_t *)p->payload - header_size_increment;
/* boundary check fails? */
if ((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) {
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
(void *)p->payload,
(void *)(p + 1)));\
/* restore old payload pointer */
p->payload = payload;
/* bail out unsuccesfully */
return 1;
}
/* pbuf types refering to external payloads? */
} else if (p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_ROM) {
/* hide a header in the payload? */
if ((header_size_increment < 0) && (header_size_increment - p->len <= 0)) {
/* increase payload pointer */
p->payload = (u8_t *)p->payload - header_size_increment;
} else {
/* cannot expand payload to front (yet!)
* bail out unsuccesfully */
return 1;
}
}
/* modify pbuf length fields */
p->len += header_size_increment;
p->tot_len += header_size_increment;
LWIP_DEBUGF( PBUF_DEBUG, ("pbuf_header: old %p new %p (%d)\n",
(void *)payload, (void *)p->payload, header_size_increment));
return 0;
}
/**
* Dereference a pbuf chain or queue and deallocate any no-longer-used
* pbufs at the head of this chain or queue.
*
* Decrements the pbuf reference count. If it reaches zero, the pbuf is
* deallocated.
*
* For a pbuf chain, this is repeated for each pbuf in the chain,
* up to the first pbuf which has a non-zero reference count after
* decrementing. So, when all reference counts are one, the whole
* chain is free'd.
*
* @param pbuf The pbuf (chain) to be dereferenced.
*
* @return the number of pbufs that were de-allocated
* from the head of the chain.
*
* @note MUST NOT be called on a packet queue (Not verified to work yet).
* @note the reference counter of a pbuf equals the number of pointers
* that refer to the pbuf (or into the pbuf).
*
* @internal examples:
*
* Assuming existing chains a->b->c with the following reference
* counts, calling pbuf_free(a) results in:
*
* 1->2->3 becomes ...1->3
* 3->3->3 becomes 2->3->3
* 1->1->2 becomes ......1
* 2->1->1 becomes 1->1->1
* 1->1->1 becomes .......
*
*/
u8_t
pbuf_free(struct pbuf *p)
{
struct pbuf *q;
u8_t count;
SYS_ARCH_DECL_PROTECT(old_level);
LWIP_ASSERT("p != NULL", p != NULL);
/* if assertions are disabled, proceed with debug output */
if (p == NULL) {
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));
return 0;
}
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p));
PERF_START;
LWIP_ASSERT("pbuf_free: sane flags",
p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_ROM ||
p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_POOL);
count = 0;
/* Since decrementing ref cannot be guaranteed to be a single machine operation
* we must protect it. Also, the later test of ref must be protected.
*/
SYS_ARCH_PROTECT(old_level);
/* de-allocate all consecutive pbufs from the head of the chain that
* obtain a zero reference count after decrementing*/
while (p != NULL) {
/* all pbufs in a chain are referenced at least once */
LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
/* decrease reference count (number of pointers to pbuf) */
p->ref--;
/* this pbuf is no longer referenced to? */
if (p->ref == 0) {
/* remember next pbuf in chain for next iteration */
q = p->next;
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p));
/* is this a pbuf from the pool? */
if (p->flags == PBUF_FLAG_POOL) {
p->len = p->tot_len = PBUF_POOL_BUFSIZE;
p->payload = (void *)((u8_t *)p + sizeof(struct pbuf));
PBUF_POOL_FREE(p);
/* is this a ROM or RAM referencing pbuf? */
} else if (p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) {
memp_free(MEMP_PBUF, p);
/* p->flags == PBUF_FLAG_RAM */
} else {
mem_free(p);
}
count++;
/* proceed to next pbuf */
p = q;
/* p->ref > 0, this pbuf is still referenced to */
/* (and so the remaining pbufs in chain as well) */
} else {
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %u, ending here.\n", (void *)p, (unsigned int)p->ref));
/* stop walking through the chain */
p = NULL;
}
}
SYS_ARCH_UNPROTECT(old_level);
PERF_STOP("pbuf_free");
/* return number of de-allocated pbufs */
return count;
}
/**
* Count number of pbufs in a chain
*
* @param p first pbuf of chain
* @return the number of pbufs in a chain
*/
u8_t
pbuf_clen(struct pbuf *p)
{
u8_t len;
len = 0;
while (p != NULL) {
++len;
p = p->next;
}
return len;
}
/**
* Increment the reference count of the pbuf.
*
* @param p pbuf to increase reference counter of
*
*/
void
pbuf_ref(struct pbuf *p)
{
SYS_ARCH_DECL_PROTECT(old_level);
/* pbuf given? */
if (p != NULL) {
SYS_ARCH_PROTECT(old_level);
++(p->ref);
SYS_ARCH_UNPROTECT(old_level);
}
}
/**
* Concatenate two pbufs (each may be a pbuf chain) and take over
* the caller's reference of the tail pbuf.
*
* @note The caller MAY NOT reference the tail pbuf afterwards.
* Use pbuf_chain() for that purpose.
*
* @see pbuf_chain()
*/
void
pbuf_cat(struct pbuf *h, struct pbuf *t)
{
struct pbuf *p;
LWIP_ASSERT("h != NULL (programmer violates API)", h != NULL);
LWIP_ASSERT("t != NULL (programmer violates API)", t != NULL);
if ((h == NULL) || (t == NULL)) return;
/* proceed to last pbuf of chain */
for (p = h; p->next != NULL; p = p->next) {
/* add total length of second chain to all totals of first chain */
p->tot_len += t->tot_len;
}
/* { p is last pbuf of first h chain, p->next == NULL } */
LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
LWIP_ASSERT("p->next == NULL", p->next == NULL);
/* add total length of second chain to last pbuf total of first chain */
p->tot_len += t->tot_len;
/* chain last pbuf of head (p) with first of tail (t) */
p->next = t;
/* p->next now references t, but the caller will drop its reference to t,
* so netto there is no change to the reference count of t.
*/
}
/**
* Chain two pbufs (or pbuf chains) together.
*
* The caller MUST call pbuf_free(t) once it has stopped
* using it. Use pbuf_cat() instead if you no longer use t.
*
* @param h head pbuf (chain)
* @param t tail pbuf (chain)
* @note The pbufs MUST belong to the same packet.
* @note MAY NOT be called on a packet queue.
*
* The ->tot_len fields of all pbufs of the head chain are adjusted.
* The ->next field of the last pbuf of the head chain is adjusted.
* The ->ref field of the first pbuf of the tail chain is adjusted.
*
*/
void
pbuf_chain(struct pbuf *h, struct pbuf *t)
{
pbuf_cat(h, t);
/* t is now referenced by h */
pbuf_ref(t);
LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
}
/* For packet queueing. Note that queued packets MUST be dequeued first
* using pbuf_dequeue() before calling other pbuf_() functions. */
#if ARP_QUEUEING
/**
* Add a packet to the end of a queue.
*
* @param q pointer to first packet on the queue
* @param n packet to be queued
*
* Both packets MUST be given, and must be different.
*/
void
pbuf_queue(struct pbuf *p, struct pbuf *n)
{
#if PBUF_DEBUG /* remember head of queue */
struct pbuf *q = p;
#endif
/* programmer stupidity checks */
LWIP_ASSERT("p == NULL in pbuf_queue: this indicates a programmer error\n", p != NULL);
LWIP_ASSERT("n == NULL in pbuf_queue: this indicates a programmer error\n", n != NULL);
LWIP_ASSERT("p == n in pbuf_queue: this indicates a programmer error\n", p != n);
if ((p == NULL) || (n == NULL) || (p == n)){
LWIP_DEBUGF(PBUF_DEBUG | DBG_HALT | 3, ("pbuf_queue: programmer argument error\n"))
return;
}
/* iterate through all packets on queue */
while (p->next != NULL) {
/* be very picky about pbuf chain correctness */
#if PBUF_DEBUG
/* iterate through all pbufs in packet */
while (p->tot_len != p->len) {
/* make sure invariant condition holds */
LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);
/* make sure each packet is complete */
LWIP_ASSERT("p->next != NULL", p->next != NULL);
p = p->next;
/* { p->tot_len == p->len => p is last pbuf of a packet } */
}
/* { p is last pbuf of a packet } */
/* proceed to next packet on queue */
#endif
/* proceed to next pbuf */
if (p->next != NULL) p = p->next;
}
/* { p->tot_len == p->len and p->next == NULL } ==>
* { p is last pbuf of last packet on queue } */
/* chain last pbuf of queue with n */
p->next = n;
/* n is now referenced to by the (packet p in the) queue */
pbuf_ref(n);
#if PBUF_DEBUG
LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2,
("pbuf_queue: newly queued packet %p sits after packet %p in queue %p\n",
(void *)n, (void *)p, (void *)q));
#endif
}
/**
* Remove a packet from the head of a queue.
*
* The caller MUST reference the remainder of the queue (as returned). The
* caller MUST NOT call pbuf_ref() as it implicitly takes over the reference
* from p.
*
* @param p pointer to first packet on the queue which will be dequeued.
* @return first packet on the remaining queue (NULL if no further packets).
*
*/
struct pbuf *
pbuf_dequeue(struct pbuf *p)
{
struct pbuf *q;
LWIP_ASSERT("p != NULL", p != NULL);
/* iterate through all pbufs in packet p */
while (p->tot_len != p->len) {
/* make sure invariant condition holds */
LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);
/* make sure each packet is complete */
LWIP_ASSERT("p->next != NULL", p->next != NULL);
p = p->next;
}
/* { p->tot_len == p->len } => p is the last pbuf of the first packet */
/* remember next packet on queue in q */
q = p->next;
/* dequeue packet p from queue */
p->next = NULL;
/* any next packet on queue? */
if (q != NULL) {
/* although q is no longer referenced by p, it MUST be referenced by
* the caller, who is maintaining this packet queue. So, we do not call
* pbuf_free(q) here, resulting in an implicit pbuf_ref(q) for the caller. */
LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: first remaining packet on queue is %p\n", (void *)q));
} else {
LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: no further packets on queue\n"));
}
return q;
}
#endif
/**
*
* Create PBUF_POOL (or PBUF_RAM) copies of PBUF_REF pbufs.
*
* Used to queue packets on behalf of the lwIP stack, such as
* ARP based queueing.
*
* Go through a pbuf chain and replace any PBUF_REF buffers
* with PBUF_POOL (or PBUF_RAM) pbufs, each taking a copy of
* the referenced data.
*
* @note You MUST explicitly use p = pbuf_take(p);
* The pbuf you give as argument, may have been replaced
* by a (differently located) copy through pbuf_take()!
*
* @note Any replaced pbufs will be freed through pbuf_free().
* This may deallocate them if they become no longer referenced.
*
* @param p Head of pbuf chain to process
*
* @return Pointer to head of pbuf chain
*/
struct pbuf *
pbuf_take(struct pbuf *p)
{
struct pbuf *q , *prev, *head;
LWIP_ASSERT("pbuf_take: p != NULL\n", p != NULL);
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)\n", (void*)p));
prev = NULL;
head = p;
/* iterate through pbuf chain */
do
{
/* pbuf is of type PBUF_REF? */
if (p->flags == PBUF_FLAG_REF) {
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p\n", (void *)p));
/* allocate a pbuf (w/ payload) fully in RAM */
/* PBUF_POOL buffers are faster if we can use them */
if (p->len <= PBUF_POOL_BUFSIZE) {
q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);
if (q == NULL) {
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n"));
}
} else {
/* no replacement pbuf yet */
q = NULL;
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n"));
}
/* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */
if (q == NULL) {
q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);
if (q == NULL) {
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM\n"));
}
}
/* replacement pbuf could be allocated? */
if (q != NULL)
{
/* copy p to q */
/* copy successor */
q->next = p->next;
/* remove linkage from original pbuf */
p->next = NULL;
/* remove linkage to original pbuf */
if (prev != NULL) {
/* prev->next == p at this point */
LWIP_ASSERT("prev->next == p", prev->next == p);
/* break chain and insert new pbuf instead */
prev->next = q;
/* prev == NULL, so we replaced the head pbuf of the chain */
} else {
head = q;
}
/* copy pbuf payload */
memcpy(q->payload, p->payload, p->len);
q->tot_len = p->tot_len;
q->len = p->len;
/* in case p was the first pbuf, it is no longer refered to by
* our caller, as the caller MUST do p = pbuf_take(p);
* in case p was not the first pbuf, it is no longer refered to
* by prev. we can safely free the pbuf here.
* (note that we have set p->next to NULL already so that
* we will not free the rest of the chain by accident.)
*/
pbuf_free(p);
/* do not copy ref, since someone else might be using the old buffer */
LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_take: replaced PBUF_REF %p with %p\n", (void *)p, (void *)q));
p = q;
} else {
/* deallocate chain */
pbuf_free(head);
LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_take: failed to allocate replacement pbuf for %p\n", (void *)p));
return NULL;
}
/* p->flags != PBUF_FLAG_REF */
} else {
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: skipping pbuf not of type PBUF_REF\n"));
}
/* remember this pbuf */
prev = p;
/* proceed to next pbuf in original chain */
p = p->next;
} while (p);
LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: end of chain reached.\n"));
return head;
}
/**
* Dechains the first pbuf from its succeeding pbufs in the chain.
*
* Makes p->tot_len field equal to p->len.
* @param p pbuf to dechain
* @return remainder of the pbuf chain, or NULL if it was de-allocated.
* @note May not be called on a packet queue.
*/
struct pbuf *
pbuf_dechain(struct pbuf *p)
{
struct pbuf *q;
u8_t tail_gone = 1;
/* tail */
q = p->next;
/* pbuf has successor in chain? */
if (q != NULL) {
/* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
/* enforce invariant if assertion is disabled */
q->tot_len = p->tot_len - p->len;
/* decouple pbuf from remainder */
p->next = NULL;
/* total length of pbuf p is its own length only */
p->tot_len = p->len;
/* q is no longer referenced by p, free it */
LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
tail_gone = pbuf_free(q);
if (tail_gone > 0) {
LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE,
("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
}
/* return remaining tail or NULL if deallocated */
}
/* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
return (tail_gone > 0? NULL: q);
}

View file

@ -0,0 +1,328 @@
/**
* @file
*
* Implementation of raw protocol PCBs for low-level handling of
* different types of protocols besides (or overriding) those
* already available in lwIP.
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include <string.h>
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/memp.h"
#include "lwip/inet.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/raw.h"
#include "lwip/stats.h"
#include "arch/perf.h"
#include "lwip/snmp.h"
#if LWIP_RAW
/** The list of RAW PCBs */
static struct raw_pcb *raw_pcbs = NULL;
void
raw_init(void)
{
raw_pcbs = NULL;
}
/**
* Determine if in incoming IP packet is covered by a RAW PCB
* and if so, pass it to a user-provided receive callback function.
*
* Given an incoming IP datagram (as a chain of pbufs) this function
* finds a corresponding RAW PCB and calls the corresponding receive
* callback function.
*
* @param pbuf pbuf to be demultiplexed to a RAW PCB.
* @param netif network interface on which the datagram was received.
* @Return - 1 if the packet has been eaten by a RAW PCB receive
* callback function. The caller MAY NOT not reference the
* packet any longer, and MAY NOT call pbuf_free().
* @return - 0 if packet is not eaten (pbuf is still referenced by the
* caller).
*
*/
u8_t
raw_input(struct pbuf *p, struct netif *inp)
{
struct raw_pcb *pcb;
struct ip_hdr *iphdr;
int proto;
u8_t eaten = 0;
( void ) inp;
iphdr = p->payload;
proto = IPH_PROTO(iphdr);
pcb = raw_pcbs;
/* loop through all raw pcbs until the packet is eaten by one */
/* this allows multiple pcbs to match against the packet by design */
while ((eaten == 0) && (pcb != NULL)) {
if (pcb->protocol == proto) {
/* receive callback function available? */
if (pcb->recv != NULL) {
/* the receive callback function did not eat the packet? */
if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0)
{
/* receive function ate the packet */
p = NULL;
eaten = 1;
}
}
/* no receive callback function was set for this raw PCB */
/* drop the packet */
}
pcb = pcb->next;
}
return eaten;
}
/**
* Bind a RAW PCB.
*
* @param pcb RAW PCB to be bound with a local address ipaddr.
* @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
* bind to all local interfaces.
*
* @return lwIP error code.
* - ERR_OK. Successful. No error occured.
* - ERR_USE. The specified IP address is already bound to by
* another RAW PCB.
*
* @see raw_disconnect()
*/
err_t
raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr)
{
ip_addr_set(&pcb->local_ip, ipaddr);
return ERR_OK;
}
/**
* Connect an RAW PCB. This function is required by upper layers
* of lwip. Using the raw api you could use raw_sendto() instead
*
* This will associate the RAW PCB with the remote address.
*
* @param pcb RAW PCB to be connected with remote address ipaddr and port.
* @param ipaddr remote IP address to connect with.
*
* @return lwIP error code
*
* @see raw_disconnect() and raw_sendto()
*/
err_t
raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr)
{
ip_addr_set(&pcb->remote_ip, ipaddr);
return ERR_OK;
}
/**
* Set the callback function for received packets that match the
* raw PCB's protocol and binding.
*
* The callback function MUST either
* - eat the packet by calling pbuf_free() and returning non-zero. The
* packet will not be passed to other raw PCBs or other protocol layers.
* - not free the packet, and return zero. The packet will be matched
* against further PCBs and/or forwarded to another protocol layers.
*
* @return non-zero if the packet was free()d, zero if the packet remains
* available for others.
*/
void
raw_recv(struct raw_pcb *pcb,
u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p,
struct ip_addr *addr),
void *recv_arg)
{
/* remember recv() callback and user data */
pcb->recv = recv;
pcb->recv_arg = recv_arg;
}
/**
* Send the raw IP packet to the given address. Note that actually you cannot
* modify the IP headers (this is inconsistent with the receive callback where
* you actually get the IP headers), you can only specify the IP payload here.
* It requires some more changes in lwIP. (there will be a raw_send() function
* then.)
*
* @param pcb the raw pcb which to send
* @param p the IP payload to send
* @param ipaddr the destination address of the IP packet
*
*/
err_t
raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
{
err_t err;
struct netif *netif;
struct ip_addr *src_ip;
struct pbuf *q; /* q will be sent down the stack */
LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 3, ("raw_sendto\n"));
/* not enough space to add an IP header to first pbuf in given p chain? */
if (pbuf_header(p, IP_HLEN)) {
/* allocate header in new pbuf */
q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
/* new header pbuf could not be allocated? */
if (q == NULL) {
LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 2, ("raw_sendto: could not allocate header\n"));
return ERR_MEM;
}
/* chain header q in front of given pbuf p */
pbuf_chain(q, p);
/* { first pbuf q points to header pbuf } */
LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
} else {
/* first pbuf q equals given pbuf */
q = p;
pbuf_header(q, -IP_HLEN);
}
if ((netif = ip_route(ipaddr)) == NULL) {
LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%lx\n", ipaddr->addr));
#if RAW_STATS
/* ++lwip_stats.raw.rterr;*/
#endif /* RAW_STATS */
/* free any temporary header pbuf allocated by pbuf_header() */
if (q != p) {
pbuf_free(q);
}
return ERR_RTE;
}
if (ip_addr_isany(&pcb->local_ip)) {
/* use outgoing network interface IP address as source address */
src_ip = &(netif->ip_addr);
} else {
/* use RAW PCB local IP address as source address */
src_ip = &(pcb->local_ip);
}
err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
/* did we chain a header earlier? */
if (q != p) {
/* free the header */
pbuf_free(q);
}
return err;
}
/**
* Send the raw IP packet to the address given by raw_connect()
*
* @param pcb the raw pcb which to send
* @param p the IP payload to send
* @param ipaddr the destination address of the IP packet
*
*/
err_t
raw_send(struct raw_pcb *pcb, struct pbuf *p)
{
return raw_sendto(pcb, p, &pcb->remote_ip);
}
/**
* Remove an RAW PCB.
*
* @param pcb RAW PCB to be removed. The PCB is removed from the list of
* RAW PCB's and the data structure is freed from memory.
*
* @see raw_new()
*/
void
raw_remove(struct raw_pcb *pcb)
{
struct raw_pcb *pcb2;
/* pcb to be removed is first in list? */
if (raw_pcbs == pcb) {
/* make list start at 2nd pcb */
raw_pcbs = raw_pcbs->next;
/* pcb not 1st in list */
} else for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
/* find pcb in raw_pcbs list */
if (pcb2->next != NULL && pcb2->next == pcb) {
/* remove pcb from list */
pcb2->next = pcb->next;
}
}
memp_free(MEMP_RAW_PCB, pcb);
}
/**
* Create a RAW PCB.
*
* @return The RAW PCB which was created. NULL if the PCB data structure
* could not be allocated.
*
* @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)
*
* @see raw_remove()
*/
struct raw_pcb *
raw_new(u16_t proto) {
struct raw_pcb *pcb;
LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 3, ("raw_new\n"));
pcb = memp_malloc(MEMP_RAW_PCB);
/* could allocate RAW PCB? */
if (pcb != NULL) {
/* initialize PCB to all zeroes */
memset(pcb, 0, sizeof(struct raw_pcb));
pcb->protocol = proto;
pcb->ttl = RAW_TTL;
pcb->next = raw_pcbs;
raw_pcbs = pcb;
}
return pcb;
}
#endif /* LWIP_RAW */

View file

@ -0,0 +1,115 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include <string.h>
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/stats.h"
#include "lwip/mem.h"
#if LWIP_STATS
struct stats_ lwip_stats;
void
stats_init(void)
{
memset(&lwip_stats, 0, sizeof(struct stats_));
}
#if LWIP_STATS_DISPLAY
void
stats_display_proto(struct stats_proto *proto, char *name)
{
LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
LWIP_PLATFORM_DIAG(("xmit: %d\n\t", proto->xmit));
LWIP_PLATFORM_DIAG(("rexmit: %d\n\t", proto->rexmit));
LWIP_PLATFORM_DIAG(("recv: %d\n\t", proto->recv));
LWIP_PLATFORM_DIAG(("fw: %d\n\t", proto->fw));
LWIP_PLATFORM_DIAG(("drop: %d\n\t", proto->drop));
LWIP_PLATFORM_DIAG(("chkerr: %d\n\t", proto->chkerr));
LWIP_PLATFORM_DIAG(("lenerr: %d\n\t", proto->lenerr));
LWIP_PLATFORM_DIAG(("memerr: %d\n\t", proto->memerr));
LWIP_PLATFORM_DIAG(("rterr: %d\n\t", proto->rterr));
LWIP_PLATFORM_DIAG(("proterr: %d\n\t", proto->proterr));
LWIP_PLATFORM_DIAG(("opterr: %d\n\t", proto->opterr));
LWIP_PLATFORM_DIAG(("err: %d\n\t", proto->err));
LWIP_PLATFORM_DIAG(("cachehit: %d\n", proto->cachehit));
}
void
stats_display_pbuf(struct stats_pbuf *pbuf)
{
LWIP_PLATFORM_DIAG(("\nPBUF\n\t"));
LWIP_PLATFORM_DIAG(("avail: %d\n\t", pbuf->avail));
LWIP_PLATFORM_DIAG(("used: %d\n\t", pbuf->used));
LWIP_PLATFORM_DIAG(("max: %d\n\t", pbuf->max));
LWIP_PLATFORM_DIAG(("err: %d\n\t", pbuf->err));
LWIP_PLATFORM_DIAG(("alloc_locked: %d\n\t", pbuf->alloc_locked));
LWIP_PLATFORM_DIAG(("refresh_locked: %d\n", pbuf->refresh_locked));
}
void
stats_display_mem(struct stats_mem *mem, char *name)
{
LWIP_PLATFORM_DIAG(("\n MEM %s\n\t", name));
LWIP_PLATFORM_DIAG(("avail: %d\n\t", mem->avail));
LWIP_PLATFORM_DIAG(("used: %d\n\t", mem->used));
LWIP_PLATFORM_DIAG(("max: %d\n\t", mem->max));
LWIP_PLATFORM_DIAG(("err: %d\n", mem->err));
}
void
stats_display(void)
{
int i;
char * memp_names[] = {"PBUF", "RAW_PCB", "UDP_PCB", "TCP_PCB", "TCP_PCB_LISTEN",
"TCP_SEG", "NETBUF", "NETCONN", "API_MSG", "TCP_MSG", "TIMEOUT"};
stats_display_proto(&lwip_stats.link, "LINK");
stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG");
stats_display_proto(&lwip_stats.ip, "IP");
stats_display_proto(&lwip_stats.icmp, "ICMP");
stats_display_proto(&lwip_stats.udp, "UDP");
stats_display_proto(&lwip_stats.tcp, "TCP");
stats_display_pbuf(&lwip_stats.pbuf);
stats_display_mem(&lwip_stats.mem, "HEAP");
for (i = 0; i < MEMP_MAX; i++) {
stats_display_mem(&lwip_stats.memp[i], memp_names[i]);
}
}
#endif /* LWIP_STATS_DISPLAY */
#endif /* LWIP_STATS */

View file

@ -0,0 +1,294 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/sys.h"
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/memp.h"
#if (NO_SYS == 0)
struct sswt_cb
{
int timeflag;
sys_sem_t *psem;
};
void
sys_mbox_fetch(sys_mbox_t mbox, void **msg)
{
u32_t time;
struct sys_timeouts *timeouts;
struct sys_timeout *tmptimeout;
sys_timeout_handler h;
void *arg;
again:
timeouts = sys_arch_timeouts();
if (!timeouts || !timeouts->next) {
sys_arch_mbox_fetch(mbox, msg, 0);
} else {
if (timeouts->next->time > 0) {
time = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);
} else {
time = SYS_ARCH_TIMEOUT;
}
if (time == SYS_ARCH_TIMEOUT) {
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
could be fetched. We should now call the timeout handler and
deallocate the memory allocated for the timeout. */
tmptimeout = timeouts->next;
timeouts->next = tmptimeout->next;
h = tmptimeout->h;
arg = tmptimeout->arg;
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
if (h != NULL) {
LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", (void *)h, (void *)arg));
h(arg);
}
/* We try again to fetch a message from the mbox. */
goto again;
} else {
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
occured. The time variable is set to the number of
milliseconds we waited for the message. */
if (time <= timeouts->next->time) {
timeouts->next->time -= time;
} else {
timeouts->next->time = 0;
}
}
}
}
void
sys_sem_wait(sys_sem_t sem)
{
u32_t time;
struct sys_timeouts *timeouts;
struct sys_timeout *tmptimeout;
sys_timeout_handler h;
void *arg;
/* while (sys_arch_sem_wait(sem, 1000) == 0);
return;*/
again:
timeouts = sys_arch_timeouts();
if (!timeouts || !timeouts->next) {
sys_arch_sem_wait(sem, 0);
} else {
if (timeouts->next->time > 0) {
time = sys_arch_sem_wait(sem, timeouts->next->time);
} else {
time = SYS_ARCH_TIMEOUT;
}
if (time == SYS_ARCH_TIMEOUT) {
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
could be fetched. We should now call the timeout handler and
deallocate the memory allocated for the timeout. */
tmptimeout = timeouts->next;
timeouts->next = tmptimeout->next;
h = tmptimeout->h;
arg = tmptimeout->arg;
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
if (h != NULL) {
LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", (void *)h, (void *)arg));
h(arg);
}
/* We try again to fetch a message from the mbox. */
goto again;
} else {
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
occured. The time variable is set to the number of
milliseconds we waited for the message. */
if (time <= timeouts->next->time) {
timeouts->next->time -= time;
} else {
timeouts->next->time = 0;
}
}
}
}
void
sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
{
struct sys_timeouts *timeouts;
struct sys_timeout *timeout, *t;
timeout = memp_malloc(MEMP_SYS_TIMEOUT);
if (timeout == NULL) {
return;
}
timeout->next = NULL;
timeout->h = h;
timeout->arg = arg;
timeout->time = msecs;
timeouts = sys_arch_timeouts();
LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%lu h=%p arg=%p\n",
(void *)timeout, msecs, (void *)h, (void *)arg));
LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);
if (timeouts->next == NULL) {
timeouts->next = timeout;
return;
}
if (timeouts->next->time > msecs) {
timeouts->next->time -= msecs;
timeout->next = timeouts->next;
timeouts->next = timeout;
} else {
for(t = timeouts->next; t != NULL; t = t->next) {
timeout->time -= t->time;
if (t->next == NULL || t->next->time > timeout->time) {
if (t->next != NULL) {
t->next->time -= timeout->time;
}
timeout->next = t->next;
t->next = timeout;
break;
}
}
}
}
/* Go through timeout list (for this task only) and remove the first matching entry,
even though the timeout has not triggered yet.
*/
void
sys_untimeout(sys_timeout_handler h, void *arg)
{
struct sys_timeouts *timeouts;
struct sys_timeout *prev_t, *t;
timeouts = sys_arch_timeouts();
if (timeouts->next == NULL)
return;
for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next)
{
if ((t->h == h) && (t->arg == arg))
{
/* We have a match */
/* Unlink from previous in list */
if (prev_t == NULL)
timeouts->next = t->next;
else
prev_t->next = t->next;
/* If not the last one, add time of this one back to next */
if (t->next != NULL)
t->next->time += t->time;
memp_free(MEMP_SYS_TIMEOUT, t);
return;
}
}
return;
}
static void
sswt_handler(void *arg)
{
struct sswt_cb *sswt_cb = (struct sswt_cb *) arg;
/* Timeout. Set flag to TRUE and signal semaphore */
sswt_cb->timeflag = 1;
sys_sem_signal(*(sswt_cb->psem));
}
/* Wait for a semaphore with timeout (specified in ms) */
/* timeout = 0: wait forever */
/* Returns 0 on timeout. 1 otherwise */
int
sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout)
{
struct sswt_cb sswt_cb;
sswt_cb.psem = &sem;
sswt_cb.timeflag = 0;
/* If timeout is zero, then just wait forever */
if (timeout > 0)
/* Create a timer and pass it the address of our flag */
sys_timeout(timeout, sswt_handler, &sswt_cb);
sys_sem_wait(sem);
/* Was it a timeout? */
if (sswt_cb.timeflag)
{
/* timeout */
return 0;
} else {
/* Not a timeout. Remove timeout entry */
sys_untimeout(sswt_handler, &sswt_cb);
return 1;
}
}
void
sys_msleep(u32_t ms)
{
sys_sem_t delaysem = sys_sem_new(0);
sys_sem_wait_timeout(delaysem, ms);
sys_sem_free(delaysem);
}
#endif /* NO_SYS */

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,724 @@
/**
* @file
*
* Transmission Control Protocol, outgoing traffic
*
* The output functions of TCP.
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/def.h"
#include "lwip/opt.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/sys.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/inet.h"
#include "lwip/tcp.h"
#include "lwip/stats.h"
#include <string.h>
#if LWIP_TCP
/* Forward declarations.*/
static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
err_t
tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)
{
/* no data, no length, flags, copy=1, no optdata, no optdatalen */
return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0);
}
/**
* Write data for sending (but does not send it immediately).
*
* It waits in the expectation of more data being sent soon (as
* it can send them more efficiently by combining them together).
* To prompt the system to send data now, call tcp_output() after
* calling tcp_write().
*
* @arg pcb Protocol control block of the TCP connection to enqueue data for.
*
* @see tcp_write()
*/
err_t
tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)
{
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%u, copy=%d)\n", (void *)pcb,
arg, len, (unsigned int)copy));
/* connection is in valid state for data transmission? */
if (pcb->state == ESTABLISHED ||
pcb->state == CLOSE_WAIT ||
pcb->state == SYN_SENT ||
pcb->state == SYN_RCVD) {
if (len > 0) {
return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0);
}
return ERR_OK;
} else {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_STATE | 3, ("tcp_write() called in invalid state\n"));
return ERR_CONN;
}
}
/**
* Enqueue either data or TCP options (but not both) for tranmission
*
*
*
* @arg pcb Protocol control block for the TCP connection to enqueue data for.
* @arg arg Pointer to the data to be enqueued for sending.
* @arg len Data length in bytes
* @arg flags
* @arg copy 1 if data must be copied, 0 if data is non-volatile and can be
* referenced.
* @arg optdata
* @arg optlen
*/
err_t
tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
u8_t flags, u8_t copy,
u8_t *optdata, u8_t optlen)
{
struct pbuf *p;
struct tcp_seg *seg, *useg, *queue=NULL;
u32_t left, seqno;
u16_t seglen;
void *ptr;
u8_t queuelen;
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%u, flags=%x, copy=%u)\n",
(void *)pcb, arg, len, (unsigned int)flags, (unsigned int)copy));
LWIP_ASSERT("tcp_enqueue: len == 0 || optlen == 0 (programmer violates API)",
len == 0 || optlen == 0);
LWIP_ASSERT("tcp_enqueue: arg == NULL || optdata == NULL (programmer violates API)",
arg == NULL || optdata == NULL);
/* fail on too much data */
if (len > pcb->snd_buf) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%u > snd_buf=%u)\n", len, pcb->snd_buf));
return ERR_MEM;
}
left = len;
ptr = arg;
/* seqno will be the sequence number of the first segment enqueued
* by the call to this function. */
seqno = pcb->snd_lbb;
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %u\n", (unsigned int)pcb->snd_queuelen));
/* If total number of pbufs on the unsent/unacked queues exceeds the
* configured maximum, return an error */
queuelen = pcb->snd_queuelen;
if (queuelen >= TCP_SND_QUEUELEN) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %u (max %u)\n", queuelen, TCP_SND_QUEUELEN));
goto memerr;
}
if (queuelen != 0) {
LWIP_ASSERT("tcp_enqueue: pbufs on queue => at least one queue non-empty",
pcb->unacked != NULL || pcb->unsent != NULL);
} else {
LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty",
pcb->unacked == NULL && pcb->unsent == NULL);
}
/* First, break up the data into segments and tuck them together in
* the local "queue" variable. */
useg = NULL;
queue = NULL;
seg = NULL;
seglen = 0;
while (queue == NULL || left > 0) {
/* The segment length should be the MSS if the data to be enqueued
* is larger than the MSS. */
seglen = left > pcb->mss? pcb->mss: left;
/* Allocate memory for tcp_seg, and fill in fields. */
seg = memp_malloc(MEMP_TCP_SEG);
if (seg == NULL) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for tcp_seg\n"));
goto memerr;
}
seg->next = NULL;
seg->p = NULL;
/* first segment of to-be-queued data? */
if (queue == NULL) {
queue = seg;
}
/* subsequent segments of to-be-queued data */
else {
/* Attach the segment to the end of the queued segments */
LWIP_ASSERT("useg != NULL", useg != NULL);
useg->next = seg;
}
/* remember last segment of to-be-queued data for next iteration */
useg = seg;
/* If copy is set, memory should be allocated
* and data copied into pbuf, otherwise data comes from
* ROM or other static memory, and need not be copied. If
* optdata is != NULL, we have options instead of data. */
/* options? */
if (optdata != NULL) {
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
goto memerr;
}
++queuelen;
seg->dataptr = seg->p->payload;
}
/* copy from volatile memory? */
else if (copy) {
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue : could not allocate memory for pbuf copy size %u\n", seglen));
goto memerr;
}
++queuelen;
if (arg != NULL) {
memcpy(seg->p->payload, ptr, seglen);
}
seg->dataptr = seg->p->payload;
}
/* do not copy data */
else {
/* First, allocate a pbuf for holding the data.
* since the referenced data is available at least until it is sent out on the
* link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM
* instead of PBUF_REF here.
*/
if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n"));
goto memerr;
}
++queuelen;
/* reference the non-volatile payload data */
p->payload = ptr;
seg->dataptr = ptr;
/* Second, allocate a pbuf for the headers. */
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) {
/* If allocation fails, we have to deallocate the data pbuf as
* well. */
pbuf_free(p);
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for header pbuf\n"));
goto memerr;
}
++queuelen;
/* Concatenate the headers and data pbufs together. */
pbuf_cat(seg->p/*header*/, p/*data*/);
p = NULL;
}
/* Now that there are more segments queued, we check again if the
length of the queue exceeds the configured maximum. */
if (queuelen > TCP_SND_QUEUELEN) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %u (%u)\n", queuelen, TCP_SND_QUEUELEN));
goto memerr;
}
seg->len = seglen;
/* build TCP header */
if (pbuf_header(seg->p, TCP_HLEN)) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n"));
TCP_STATS_INC(tcp.err);
goto memerr;
}
seg->tcphdr = seg->p->payload;
seg->tcphdr->src = htons(pcb->local_port);
seg->tcphdr->dest = htons(pcb->remote_port);
seg->tcphdr->seqno = htonl(seqno);
seg->tcphdr->urgp = 0;
TCPH_FLAGS_SET(seg->tcphdr, flags);
/* don't fill in tcphdr->ackno and tcphdr->wnd until later */
/* Copy the options into the header, if they are present. */
if (optdata == NULL) {
TCPH_HDRLEN_SET(seg->tcphdr, 5);
}
else {
TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4));
/* Copy options into data portion of segment.
Options can thus only be sent in non data carrying
segments such as SYN|ACK. */
memcpy(seg->dataptr, optdata, optlen);
}
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE, ("tcp_enqueue: queueing %lu:%lu (0x%x)\n",
ntohl(seg->tcphdr->seqno),
ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
flags));
left -= seglen;
seqno += seglen;
ptr = (void *)((char *)ptr + seglen);
}
/* Now that the data to be enqueued has been broken up into TCP
segments in the queue variable, we add them to the end of the
pcb->unsent queue. */
if (pcb->unsent == NULL) {
useg = NULL;
}
else {
for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
}
/* { useg is last segment on the unsent queue, NULL if list is empty } */
/* If there is room in the last pbuf on the unsent queue,
chain the first pbuf on the queue together with that. */
if (useg != NULL &&
TCP_TCPLEN(useg) != 0 &&
!(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&
!(flags & (TCP_SYN | TCP_FIN)) &&
/* fit within max seg size */
useg->len + queue->len <= pcb->mss) {
/* Remove TCP header from first segment of our to-be-queued list */
pbuf_header(queue->p, -TCP_HLEN);
pbuf_cat(useg->p, queue->p);
useg->len += queue->len;
useg->next = queue->next;
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE | DBG_STATE, ("tcp_enqueue: chaining segments, new len %u\n", useg->len));
if (seg == queue) {
seg = NULL;
}
memp_free(MEMP_TCP_SEG, queue);
}
else {
/* empty list */
if (useg == NULL) {
/* initialize list with this segment */
pcb->unsent = queue;
}
/* enqueue segment */
else {
useg->next = queue;
}
}
if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
++len;
}
pcb->snd_lbb += len;
pcb->snd_buf -= len;
/* update number of segments on the queues */
pcb->snd_queuelen = queuelen;
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (after enqueued)\n", pcb->snd_queuelen));
if (pcb->snd_queuelen != 0) {
LWIP_ASSERT("tcp_enqueue: valid queue length",
pcb->unacked != NULL || pcb->unsent != NULL);
}
/* Set the PSH flag in the last segment that we enqueued, but only
if the segment has data (indicated by seglen > 0). */
if (seg != NULL && seglen > 0 && seg->tcphdr != NULL) {
TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);
}
return ERR_OK;
memerr:
TCP_STATS_INC(tcp.memerr);
if (queue != NULL) {
tcp_segs_free(queue);
}
if (pcb->snd_queuelen != 0) {
LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
pcb->unsent != NULL);
}
LWIP_DEBUGF(TCP_QLEN_DEBUG | DBG_STATE, ("tcp_enqueue: %d (with mem err)\n", pcb->snd_queuelen));
return ERR_MEM;
}
/* find out what we can send and send it */
err_t
tcp_output(struct tcp_pcb *pcb)
{
struct pbuf *p;
struct tcp_hdr *tcphdr;
struct tcp_seg *seg, *useg;
u32_t wnd;
#if TCP_CWND_DEBUG
int i = 0;
#endif /* TCP_CWND_DEBUG */
/* First, check if we are invoked by the TCP input processing
code. If so, we do not output anything. Instead, we rely on the
input processing code to call us when input processing is done
with. */
if (tcp_input_pcb == pcb) {
return ERR_OK;
}
wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
seg = pcb->unsent;
/* useg should point to last segment on unacked queue */
useg = pcb->unacked;
if (useg != NULL) {
for (; useg->next != NULL; useg = useg->next);
}
/* If the TF_ACK_NOW flag is set and no data will be sent (either
* because the ->unsent queue is empty or because the window does
* not allow it), construct an empty ACK segment and send it.
*
* If data is to be sent, we will just piggyback the ACK (see below).
*/
if (pcb->flags & TF_ACK_NOW &&
(seg == NULL ||
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
if (p == NULL) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
return ERR_BUF;
}
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %lu\n", pcb->rcv_nxt));
/* remove ACK flags from the PCB, as we send an empty ACK now */
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
tcphdr = p->payload;
tcphdr->src = htons(pcb->local_port);
tcphdr->dest = htons(pcb->remote_port);
tcphdr->seqno = htonl(pcb->snd_nxt);
tcphdr->ackno = htonl(pcb->rcv_nxt);
TCPH_FLAGS_SET(tcphdr, TCP_ACK);
tcphdr->wnd = htons(pcb->rcv_wnd);
tcphdr->urgp = 0;
TCPH_HDRLEN_SET(tcphdr, 5);
tcphdr->chksum = 0;
#if CHECKSUM_GEN_TCP
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
IP_PROTO_TCP, p->tot_len);
#endif
ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
IP_PROTO_TCP);
pbuf_free(p);
return ERR_OK;
}
#if TCP_OUTPUT_DEBUG
if (seg == NULL) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", pcb->unsent));
}
#endif /* TCP_OUTPUT_DEBUG */
#if TCP_CWND_DEBUG
if (seg == NULL) {
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, seg == NULL, ack %lu\n",
pcb->snd_wnd, pcb->cwnd, wnd,
pcb->lastack));
} else {
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, effwnd %lu, seq %lu, ack %lu\n",
pcb->snd_wnd, pcb->cwnd, wnd,
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
ntohl(seg->tcphdr->seqno), pcb->lastack));
}
#endif /* TCP_CWND_DEBUG */
/* data available and window allows it to be sent? */
while (seg != NULL &&
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
#if TCP_CWND_DEBUG
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, effwnd %lu, seq %lu, ack %lu, i%d\n",
pcb->snd_wnd, pcb->cwnd, wnd,
ntohl(seg->tcphdr->seqno) + seg->len -
pcb->lastack,
ntohl(seg->tcphdr->seqno), pcb->lastack, i));
++i;
#endif /* TCP_CWND_DEBUG */
pcb->unsent = seg->next;
if (pcb->state != SYN_SENT) {
TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
}
tcp_output_segment(seg, pcb);
pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) {
pcb->snd_max = pcb->snd_nxt;
}
/* put segment on unacknowledged list if length > 0 */
if (TCP_TCPLEN(seg) > 0) {
seg->next = NULL;
/* unacked list is empty? */
if (pcb->unacked == NULL) {
pcb->unacked = seg;
useg = seg;
/* unacked list is not empty? */
} else {
/* In the case of fast retransmit, the packet should not go to the tail
* of the unacked queue, but rather at the head. We need to check for
* this case. -STJ Jul 27, 2004 */
if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){
/* add segment to head of unacked list */
seg->next = pcb->unacked;
pcb->unacked = seg;
} else {
/* add segment to tail of unacked list */
useg->next = seg;
useg = useg->next;
}
}
/* do not queue empty segments on the unacked list */
} else {
tcp_seg_free(seg);
}
seg = pcb->unsent;
}
return ERR_OK;
}
/**
* Actually send a TCP segment over IP
*/
static void
tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
{
u16_t len;
struct netif *netif;
/* The TCP header has already been constructed, but the ackno and
wnd fields remain. */
seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
/* silly window avoidance */
if (pcb->rcv_wnd < pcb->mss) {
seg->tcphdr->wnd = 0;
} else {
/* advertise our receive window size in this TCP segment */
seg->tcphdr->wnd = htons(pcb->rcv_wnd);
}
/* If we don't have a local IP address, we get one by
calling ip_route(). */
if (ip_addr_isany(&(pcb->local_ip))) {
netif = ip_route(&(pcb->remote_ip));
if (netif == NULL) {
return;
}
ip_addr_set(&(pcb->local_ip), &(netif->ip_addr));
}
pcb->rtime = 0;
if (pcb->rttest == 0) {
pcb->rttest = tcp_ticks;
pcb->rtseq = ntohl(seg->tcphdr->seqno);
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %lu\n", pcb->rtseq));
}
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %lu:%lu\n",
htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
seg->len));
len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
seg->p->len -= len;
seg->p->tot_len -= len;
seg->p->payload = seg->tcphdr;
seg->tcphdr->chksum = 0;
#if CHECKSUM_GEN_TCP
seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,
&(pcb->local_ip),
&(pcb->remote_ip),
IP_PROTO_TCP, seg->p->tot_len);
#endif
TCP_STATS_INC(tcp.xmit);
ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
IP_PROTO_TCP);
}
void
tcp_rst(u32_t seqno, u32_t ackno,
struct ip_addr *local_ip, struct ip_addr *remote_ip,
u16_t local_port, u16_t remote_port)
{
struct pbuf *p;
struct tcp_hdr *tcphdr;
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
if (p == NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
return;
}
tcphdr = p->payload;
tcphdr->src = htons(local_port);
tcphdr->dest = htons(remote_port);
tcphdr->seqno = htonl(seqno);
tcphdr->ackno = htonl(ackno);
TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK);
tcphdr->wnd = htons(TCP_WND);
tcphdr->urgp = 0;
TCPH_HDRLEN_SET(tcphdr, 5);
tcphdr->chksum = 0;
#if CHECKSUM_GEN_TCP
tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
IP_PROTO_TCP, p->tot_len);
#endif
TCP_STATS_INC(tcp.xmit);
/* Send output with hardcoded TTL since we have no access to the pcb */
ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
pbuf_free(p);
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %lu ackno %lu.\n", seqno, ackno));
}
/* requeue all unacked segments for retransmission */
void
tcp_rexmit_rto(struct tcp_pcb *pcb)
{
struct tcp_seg *seg;
if (pcb->unacked == NULL) {
return;
}
/* Move all unacked segments to the head of the unsent queue */
for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
/* concatenate unsent queue after unacked queue */
seg->next = pcb->unsent;
/* unsent queue is the concatenated queue (of unacked, unsent) */
pcb->unsent = pcb->unacked;
/* unacked queue is now empty */
pcb->unacked = NULL;
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
/* increment number of retransmissions */
++pcb->nrtx;
/* Don't take any RTT measurements after retransmitting. */
pcb->rttest = 0;
/* Do the actual retransmission */
tcp_output(pcb);
}
void
tcp_rexmit(struct tcp_pcb *pcb)
{
struct tcp_seg *seg;
if (pcb->unacked == NULL) {
return;
}
/* Move the first unacked segment to the unsent queue */
seg = pcb->unacked->next;
pcb->unacked->next = pcb->unsent;
pcb->unsent = pcb->unacked;
pcb->unacked = seg;
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
++pcb->nrtx;
/* Don't take any rtt measurements after retransmitting. */
pcb->rttest = 0;
/* Do the actual retransmission. */
tcp_output(pcb);
}
void
tcp_keepalive(struct tcp_pcb *pcb)
{
struct pbuf *p;
struct tcp_hdr *tcphdr;
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %u.%u.%u.%u\n",
ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %lu pcb->tmr %lu pcb->keep_cnt %u\n", tcp_ticks, pcb->tmr, pcb->keep_cnt));
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
if(p == NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: could not allocate memory for pbuf\n"));
return;
}
tcphdr = p->payload;
tcphdr->src = htons(pcb->local_port);
tcphdr->dest = htons(pcb->remote_port);
tcphdr->seqno = htonl(pcb->snd_nxt - 1);
tcphdr->ackno = htonl(pcb->rcv_nxt);
tcphdr->wnd = htons(pcb->rcv_wnd);
tcphdr->urgp = 0;
TCPH_HDRLEN_SET(tcphdr, 5);
tcphdr->chksum = 0;
#if CHECKSUM_GEN_TCP
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, IP_PROTO_TCP, p->tot_len);
#endif
TCP_STATS_INC(tcp.xmit);
/* Send output to IP */
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
pbuf_free(p);
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_keepalive: seqno %lu ackno %lu.\n", pcb->snd_nxt - 1, pcb->rcv_nxt));
}
#endif /* LWIP_TCP */

View file

@ -0,0 +1,801 @@
/**
* @file
* User Datagram Protocol module
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/* udp.c
*
* The code for the User Datagram Protocol UDP.
*
*/
#include <string.h>
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/memp.h"
#include "lwip/inet.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/udp.h"
#include "lwip/icmp.h"
#include "lwip/stats.h"
#include "arch/perf.h"
#include "lwip/snmp.h"
/* The list of UDP PCBs */
#if LWIP_UDP
/* was static, but we may want to access this from a socket layer */
struct udp_pcb *udp_pcbs = NULL;
static struct udp_pcb *pcb_cache = NULL;
void
udp_init(void)
{
udp_pcbs = pcb_cache = NULL;
}
/**
* Process an incoming UDP datagram.
*
* Given an incoming UDP datagram (as a chain of pbufs) this function
* finds a corresponding UDP PCB and
*
* @param pbuf pbuf to be demultiplexed to a UDP PCB.
* @param netif network interface on which the datagram was received.
*
*/
void
udp_input(struct pbuf *p, struct netif *inp)
{
struct udp_hdr *udphdr;
struct udp_pcb *pcb;
struct ip_hdr *iphdr;
u16_t src, dest;
#if SO_REUSE
struct udp_pcb *pcb_temp;
int reuse = 0;
int reuse_port_1 = 0;
int reuse_port_2 = 0;
#endif /* SO_REUSE */
PERF_START;
UDP_STATS_INC(udp.recv);
iphdr = p->payload;
if (pbuf_header(p, -((s16_t)(UDP_HLEN + IPH_HL(iphdr) * 4)))) {
/* drop short packets */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: short UDP datagram (%u bytes) discarded\n", p->tot_len));
UDP_STATS_INC(udp.lenerr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpinerrors();
pbuf_free(p);
goto end;
}
udphdr = (struct udp_hdr *)((u8_t *)p->payload - UDP_HLEN);
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %u\n", p->tot_len));
src = ntohs(udphdr->src);
dest = ntohs(udphdr->dest);
udp_debug_print(udphdr);
/* print the UDP source and destination */
LWIP_DEBUGF(UDP_DEBUG, ("udp (%u.%u.%u.%u, %u) <-- (%u.%u.%u.%u, %u)\n",
ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest),
ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest),
ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),
ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src)));
#if SO_REUSE
pcb_temp = udp_pcbs;
again_1:
/* Iterate through the UDP pcb list for a fully matching pcb */
for (pcb = pcb_temp; pcb != NULL; pcb = pcb->next) {
#else /* SO_REUSE */
/* Iterate through the UDP pcb list for a fully matching pcb */
for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
#endif /* SO_REUSE */
/* print the PCB local and remote address */
LWIP_DEBUGF(UDP_DEBUG, ("pcb (%u.%u.%u.%u, %u) --- (%u.%u.%u.%u, %u)\n",
ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),
ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,
ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port));
/* PCB remote port matches UDP source port? */
if ((pcb->remote_port == src) &&
/* PCB local port matches UDP destination port? */
(pcb->local_port == dest) &&
/* accepting from any remote (source) IP address? or... */
(ip_addr_isany(&pcb->remote_ip) ||
/* PCB remote IP address matches UDP source IP address? */
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) &&
/* accepting on any local (netif) IP address? or... */
(ip_addr_isany(&pcb->local_ip) ||
/* PCB local IP address matches UDP destination IP address? */
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
#if SO_REUSE
if (pcb->so_options & SOF_REUSEPORT) {
if(reuse) {
/* We processed one PCB already */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB and SOF_REUSEPORT set.\n"));
} else {
/* First PCB with this address */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: first PCB and SOF_REUSEPORT set.\n"));
reuse = 1;
}
reuse_port_1 = 1;
p->ref++;
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: reference counter on PBUF set to %i\n", p->ref));
} else {
if (reuse) {
/* We processed one PCB already */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB but SOF_REUSEPORT not set !\n"));
}
}
#endif /* SO_REUSE */
break;
}
}
/* no fully matching pcb found? then look for an unconnected pcb */
if (pcb == NULL) {
/* Iterate through the UDP PCB list for a pcb that matches
the local address. */
#if SO_REUSE
pcb_temp = udp_pcbs;
again_2:
for (pcb = pcb_temp; pcb != NULL; pcb = pcb->next) {
#else /* SO_REUSE */
for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
#endif /* SO_REUSE */
LWIP_DEBUGF(UDP_DEBUG, ("pcb (%u.%u.%u.%u, %u) --- (%u.%u.%u.%u, %u)\n",
ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),
ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,
ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port));
/* unconnected? */
if (((pcb->flags & UDP_FLAGS_CONNECTED) == 0) &&
/* destination port matches? */
(pcb->local_port == dest) &&
/* not bound to a specific (local) interface address? or... */
(ip_addr_isany(&pcb->local_ip) ||
/* ...matching interface address? */
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
#if SO_REUSE
if (pcb->so_options & SOF_REUSEPORT) {
if (reuse) {
/* We processed one PCB already */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB and SOF_REUSEPORT set.\n"));
} else {
/* First PCB with this address */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: first PCB and SOF_REUSEPORT set.\n"));
reuse = 1;
}
reuse_port_2 = 1;
p->ref++;
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: reference counter on PBUF set to %i\n", p->ref));
} else {
if (reuse) {
/* We processed one PCB already */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB but SOF_REUSEPORT not set !\n"));
}
}
#endif /* SO_REUSE */
break;
}
}
}
/* Check checksum if this is a match or if it was directed at us. */
if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest))
{
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: calculating checksum\n"));
pbuf_header(p, UDP_HLEN);
#ifdef IPv6
if (iphdr->nexthdr == IP_PROTO_UDPLITE) {
#else
if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
#endif /* IPv4 */
/* Do the UDP Lite checksum */
#if CHECKSUM_CHECK_UDP
if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
(struct ip_addr *)&(iphdr->dest),
IP_PROTO_UDPLITE, ntohs(udphdr->len)) != 0) {
LWIP_DEBUGF(UDP_DEBUG | 2, ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
UDP_STATS_INC(udp.chkerr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpinerrors();
pbuf_free(p);
goto end;
}
#endif
} else {
#if CHECKSUM_CHECK_UDP
if (udphdr->chksum != 0) {
if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
(struct ip_addr *)&(iphdr->dest),
IP_PROTO_UDP, p->tot_len) != 0) {
LWIP_DEBUGF(UDP_DEBUG | 2, ("udp_input: UDP datagram discarded due to failing checksum\n"));
UDP_STATS_INC(udp.chkerr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpinerrors();
pbuf_free(p);
goto end;
}
}
#endif
}
pbuf_header(p, -UDP_HLEN);
if (pcb != NULL) {
snmp_inc_udpindatagrams();
pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);
#if SO_REUSE
/* First socket should receive now */
if(reuse_port_1 || reuse_port_2) {
/* We want to search on next socket after receiving */
pcb_temp = pcb->next;
if(reuse_port_1) {
/* We are searching connected sockets */
reuse_port_1 = 0;
reuse_port_2 = 0;
goto again_1;
} else {
/* We are searching unconnected sockets */
reuse_port_1 = 0;
reuse_port_2 = 0;
goto again_2;
}
}
#endif /* SO_REUSE */
} else {
#if SO_REUSE
if(reuse) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: freeing PBUF with reference counter set to %i\n", p->ref));
pbuf_free(p);
goto end;
}
#endif /* SO_REUSE */
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: not for us.\n"));
/* No match was found, send ICMP destination port unreachable unless
destination address was broadcast/multicast. */
if (!ip_addr_isbroadcast(&iphdr->dest, inp) &&
!ip_addr_ismulticast(&iphdr->dest)) {
/* adjust pbuf pointer */
p->payload = iphdr;
icmp_dest_unreach(p, ICMP_DUR_PORT);
}
UDP_STATS_INC(udp.proterr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpnoports();
pbuf_free(p);
}
} else {
pbuf_free(p);
}
end:
PERF_STOP("udp_input");
}
/**
* Send data to a specified address using UDP.
*
* @param pcb UDP PCB used to send the data.
* @param pbuf chain of pbuf's to be sent.
* @param dst_ip Destination IP address.
* @param dst_port Destination UDP port.
*
* If the PCB already has a remote address association, it will
* be restored after the data is sent.
*
* @return lwIP error code.
* - ERR_OK. Successful. No error occured.
* - ERR_MEM. Out of memory.
* - ERR_RTE. Could not find route to destination address.
*
* @see udp_disconnect() udp_send()
*/
err_t
udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
struct ip_addr *dst_ip, u16_t dst_port)
{
err_t err;
/* temporary space for current PCB remote address */
struct ip_addr pcb_remote_ip;
u16_t pcb_remote_port;
/* remember current remote peer address of PCB */
pcb_remote_ip.addr = pcb->remote_ip.addr;
pcb_remote_port = pcb->remote_port;
/* copy packet destination address to PCB remote peer address */
pcb->remote_ip.addr = dst_ip->addr;
pcb->remote_port = dst_port;
/* send to the packet destination address */
err = udp_send(pcb, p);
/* restore PCB remote peer address */
pcb->remote_ip.addr = pcb_remote_ip.addr;
pcb->remote_port = pcb_remote_port;
return err;
}
/**
* Send data using UDP.
*
* @param pcb UDP PCB used to send the data.
* @param pbuf chain of pbuf's to be sent.
*
* @return lwIP error code.
* - ERR_OK. Successful. No error occured.
* - ERR_MEM. Out of memory.
* - ERR_RTE. Could not find route to destination address.
*
* @see udp_disconnect() udp_sendto()
*/
err_t
udp_send(struct udp_pcb *pcb, struct pbuf *p)
{
struct udp_hdr *udphdr;
struct netif *netif;
struct ip_addr *src_ip;
err_t err;
struct pbuf *q; /* q will be sent down the stack */
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_send\n"));
/* if the PCB is not yet bound to a port, bind it here */
if (pcb->local_port == 0) {
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));
err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
if (err != ERR_OK) {
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: forced port bind failed\n"));
return err;
}
}
/* not enough space to add an UDP header to first pbuf in given p chain? */
if (pbuf_header(p, UDP_HLEN)) {
/* allocate header in a seperate new pbuf */
q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
/* new header pbuf could not be allocated? */
if (q == NULL) {
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 2, ("udp_send: could not allocate header\n"));
return ERR_MEM;
}
/* chain header q in front of given pbuf p */
pbuf_chain(q, p);
/* { first pbuf q points to header pbuf } */
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
/* adding a header within p succeeded */
} else {
/* first pbuf q equals given pbuf */
q = p;
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p));
}
/* { q now represents the packet to be sent } */
udphdr = q->payload;
udphdr->src = htons(pcb->local_port);
udphdr->dest = htons(pcb->remote_port);
/* in UDP, 0 checksum means 'no checksum' */
udphdr->chksum = 0x0000;
/* find the outgoing network interface for this packet */
netif = ip_route(&(pcb->remote_ip));
/* no outgoing network interface could be found? */
if (netif == NULL) {
LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%lx\n", pcb->remote_ip.addr));
UDP_STATS_INC(udp.rterr);
return ERR_RTE;
}
/* PCB local address is IP_ANY_ADDR? */
if (ip_addr_isany(&pcb->local_ip)) {
/* use outgoing network interface IP address as source address */
src_ip = &(netif->ip_addr);
} else {
/* use UDP PCB local IP address as source address */
src_ip = &(pcb->local_ip);
}
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %u\n", q->tot_len));
/* UDP Lite protocol? */
if (pcb->flags & UDP_FLAGS_UDPLITE) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %u\n", q->tot_len));
/* set UDP message length in UDP header */
udphdr->len = htons(pcb->chksum_len);
/* calculate checksum */
#if CHECKSUM_GEN_UDP
udphdr->chksum = inet_chksum_pseudo(q, src_ip, &(pcb->remote_ip),
IP_PROTO_UDP, pcb->chksum_len);
/* chksum zero must become 0xffff, as zero means 'no checksum' */
if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;
#else
udphdr->chksum = 0x0000;
#endif
/* output to IP */
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));
err = ip_output_if (q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);
/* UDP */
} else {
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %u\n", q->tot_len));
udphdr->len = htons(q->tot_len);
/* calculate checksum */
#if CHECKSUM_GEN_UDP
if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
udphdr->chksum = inet_chksum_pseudo(q, src_ip, &pcb->remote_ip, IP_PROTO_UDP, q->tot_len);
/* chksum zero must become 0xffff, as zero means 'no checksum' */
if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;
}
#else
udphdr->chksum = 0x0000;
#endif
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04x\n", udphdr->chksum));
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
/* output to IP */
err = ip_output_if(q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
}
/* TODO: must this be increased even if error occured? */
snmp_inc_udpoutdatagrams();
/* did we chain a seperate header pbuf earlier? */
if (q != p) {
/* free the header pbuf */
pbuf_free(q); q = NULL;
/* { p is still referenced by the caller, and will live on } */
}
UDP_STATS_INC(udp.xmit);
return err;
}
/**
* Bind an UDP PCB.
*
* @param pcb UDP PCB to be bound with a local address ipaddr and port.
* @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
* bind to all local interfaces.
* @param port local UDP port to bind with.
*
* @return lwIP error code.
* - ERR_OK. Successful. No error occured.
* - ERR_USE. The specified ipaddr and port are already bound to by
* another UDP PCB.
*
* @see udp_disconnect()
*/
err_t
udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
{
struct udp_pcb *ipcb;
u8_t rebind;
#if SO_REUSE
int reuse_port_all_set = 1;
#endif /* SO_REUSE */
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_bind(ipaddr = "));
ip_addr_debug_print(UDP_DEBUG, ipaddr);
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, (", port = %u)\n", port));
rebind = 0;
/* Check for double bind and rebind of the same pcb */
for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
/* is this UDP PCB already on active list? */
if (pcb == ipcb) {
/* pcb may occur at most once in active list */
LWIP_ASSERT("rebind == 0", rebind == 0);
/* pcb already in list, just rebind */
rebind = 1;
}
#if SO_REUSE == 0
/* this code does not allow upper layer to share a UDP port for
listening to broadcast or multicast traffic (See SO_REUSE_ADDR and
SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR
combine with implementation of UDP PCB flags. Leon Woestenberg. */
#ifdef LWIP_UDP_TODO
/* port matches that of PCB in list? */
else if ((ipcb->local_port == port) &&
/* IP address matches, or one is IP_ADDR_ANY? */
(ip_addr_isany(&(ipcb->local_ip)) ||
ip_addr_isany(ipaddr) ||
ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {
/* other PCB already binds to this local IP and port */
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: local port %u already bound by another pcb\n", port));
return ERR_USE;
}
#endif
#else /* SO_REUSE */
/* Search through list of PCB's.
If there is a PCB bound to specified port and IP_ADDR_ANY another PCB can be bound to the interface IP
or to the loopback address on the same port if SOF_REUSEADDR is set. Any combination of PCB's bound to
the same local port, but to one address out of {IP_ADDR_ANY, 127.0.0.1, interface IP} at a time is valid.
But no two PCB's bound to same local port and same local address is valid.
If SOF_REUSEPORT is set several PCB's can be bound to same local port and same local address also. But then
all PCB's must have the SOF_REUSEPORT option set.
When the two options aren't set and specified port is already bound, ERR_USE is returned saying that
address is already in use. */
else if (ipcb->local_port == port) {
if(ip_addr_cmp(&(ipcb->local_ip), ipaddr)) {
if(pcb->so_options & SOF_REUSEPORT) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: in UDP PCB's SO_REUSEPORT set and same address.\n"));
reuse_port_all_set = (reuse_port_all_set && (ipcb->so_options & SOF_REUSEPORT));
}
else {
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: in UDP PCB's SO_REUSEPORT not set and same address.\n"));
return ERR_USE;
}
}
else if((ip_addr_isany(ipaddr) && !ip_addr_isany(&(ipcb->local_ip))) ||
(!ip_addr_isany(ipaddr) && ip_addr_isany(&(ipcb->local_ip)))) {
if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: in UDP PCB's SO_REUSEPORT or SO_REUSEADDR not set and not the same address.\n"));
return ERR_USE;
}
}
}
#endif /* SO_REUSE */
}
#if SO_REUSE
/* If SOF_REUSEPORT isn't set in all PCB's bound to specified port and local address specified then
{IP, port} can't be reused. */
if(!reuse_port_all_set) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: not all sockets have SO_REUSEPORT set.\n"));
return ERR_USE;
}
#endif /* SO_REUSE */
ip_addr_set(&pcb->local_ip, ipaddr);
/* no port specified? */
if (port == 0) {
#ifndef UDP_LOCAL_PORT_RANGE_START
#define UDP_LOCAL_PORT_RANGE_START 4096
#define UDP_LOCAL_PORT_RANGE_END 0x7fff
#endif
port = UDP_LOCAL_PORT_RANGE_START;
ipcb = udp_pcbs;
while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {
if (ipcb->local_port == port) {
port++;
ipcb = udp_pcbs;
} else
ipcb = ipcb->next;
}
if (ipcb != NULL) {
/* no more ports available in local range */
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));
return ERR_USE;
}
}
pcb->local_port = port;
/* pcb not active yet? */
if (rebind == 0) {
/* place the PCB on the active list if not already there */
pcb->next = udp_pcbs;
udp_pcbs = pcb;
}
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | DBG_STATE, ("udp_bind: bound to %u.%u.%u.%u, port %u\n",
(unsigned int)(ntohl(pcb->local_ip.addr) >> 24 & 0xff),
(unsigned int)(ntohl(pcb->local_ip.addr) >> 16 & 0xff),
(unsigned int)(ntohl(pcb->local_ip.addr) >> 8 & 0xff),
(unsigned int)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));
return ERR_OK;
}
/**
* Connect an UDP PCB.
*
* This will associate the UDP PCB with the remote address.
*
* @param pcb UDP PCB to be connected with remote address ipaddr and port.
* @param ipaddr remote IP address to connect with.
* @param port remote UDP port to connect with.
*
* @return lwIP error code
*
* @see udp_disconnect()
*/
err_t
udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
{
struct udp_pcb *ipcb;
if (pcb->local_port == 0) {
err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
if (err != ERR_OK)
return err;
}
ip_addr_set(&pcb->remote_ip, ipaddr);
pcb->remote_port = port;
pcb->flags |= UDP_FLAGS_CONNECTED;
/** TODO: this functionality belongs in upper layers */
#ifdef LWIP_UDP_TODO
/* Nail down local IP for netconn_addr()/getsockname() */
if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {
struct netif *netif;
if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));
UDP_STATS_INC(udp.rterr);
return ERR_RTE;
}
/** TODO: this will bind the udp pcb locally, to the interface which
is used to route output packets to the remote address. However, we
might want to accept incoming packets on any interface! */
pcb->local_ip = netif->ip_addr;
} else if (ip_addr_isany(&pcb->remote_ip)) {
pcb->local_ip.addr = 0;
}
#endif
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | DBG_STATE, ("udp_connect: connected to %u.%u.%u.%u, port %u\n",
(unsigned int)(ntohl(pcb->remote_ip.addr) >> 24 & 0xff),
(unsigned int)(ntohl(pcb->remote_ip.addr) >> 16 & 0xff),
(unsigned int)(ntohl(pcb->remote_ip.addr) >> 8 & 0xff),
(unsigned int)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));
/* Insert UDP PCB into the list of active UDP PCBs. */
for(ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
if (pcb == ipcb) {
/* already on the list, just return */
return ERR_OK;
}
}
/* PCB not yet on the list, add PCB now */
pcb->next = udp_pcbs;
udp_pcbs = pcb;
return ERR_OK;
}
void
udp_disconnect(struct udp_pcb *pcb)
{
/* reset remote address association */
ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY);
pcb->remote_port = 0;
/* mark PCB as unconnected */
pcb->flags &= ~UDP_FLAGS_CONNECTED;
}
void
udp_recv(struct udp_pcb *pcb,
void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p,
struct ip_addr *addr, u16_t port),
void *recv_arg)
{
/* remember recv() callback and user data */
pcb->recv = recv;
pcb->recv_arg = recv_arg;
}
/**
* Remove an UDP PCB.
*
* @param pcb UDP PCB to be removed. The PCB is removed from the list of
* UDP PCB's and the data structure is freed from memory.
*
* @see udp_new()
*/
void
udp_remove(struct udp_pcb *pcb)
{
struct udp_pcb *pcb2;
/* pcb to be removed is first in list? */
if (udp_pcbs == pcb) {
/* make list start at 2nd pcb */
udp_pcbs = udp_pcbs->next;
/* pcb not 1st in list */
} else for(pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
/* find pcb in udp_pcbs list */
if (pcb2->next != NULL && pcb2->next == pcb) {
/* remove pcb from list */
pcb2->next = pcb->next;
}
}
memp_free(MEMP_UDP_PCB, pcb);
}
/**
* Create a UDP PCB.
*
* @return The UDP PCB which was created. NULL if the PCB data structure
* could not be allocated.
*
* @see udp_remove()
*/
struct udp_pcb *
udp_new(void) {
struct udp_pcb *pcb;
pcb = memp_malloc(MEMP_UDP_PCB);
/* could allocate UDP PCB? */
if (pcb != NULL) {
/* initialize PCB to all zeroes */
memset(pcb, 0, sizeof(struct udp_pcb));
pcb->ttl = UDP_TTL;
}
return pcb;
}
#if UDP_DEBUG
int
udp_debug_print(struct udp_hdr *udphdr)
{
LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n"));
LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(UDP_DEBUG, ("| %5u | %5u | (src port, dest port)\n",
ntohs(udphdr->src), ntohs(udphdr->dest)));
LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(UDP_DEBUG, ("| %5u | 0x%04x | (len, chksum)\n",
ntohs(udphdr->len), ntohs(udphdr->chksum)));
LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
return 0;
}
#endif /* UDP_DEBUG */
#endif /* LWIP_UDP */

View file

@ -0,0 +1,112 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_ICMP_H__
#define __LWIP_ICMP_H__
#include "lwip/arch.h"
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#define ICMP_ER 0 /* echo reply */
#define ICMP_DUR 3 /* destination unreachable */
#define ICMP_SQ 4 /* source quench */
#define ICMP_RD 5 /* redirect */
#define ICMP_ECHO 8 /* echo */
#define ICMP_TE 11 /* time exceeded */
#define ICMP_PP 12 /* parameter problem */
#define ICMP_TS 13 /* timestamp */
#define ICMP_TSR 14 /* timestamp reply */
#define ICMP_IRQ 15 /* information request */
#define ICMP_IR 16 /* information reply */
enum icmp_dur_type {
ICMP_DUR_NET = 0, /* net unreachable */
ICMP_DUR_HOST = 1, /* host unreachable */
ICMP_DUR_PROTO = 2, /* protocol unreachable */
ICMP_DUR_PORT = 3, /* port unreachable */
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
ICMP_DUR_SR = 5 /* source route failed */
};
enum icmp_te_type {
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */
};
void icmp_input(struct pbuf *p, struct netif *inp);
void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct icmp_echo_hdr {
PACK_STRUCT_FIELD(u16_t _type_code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u16_t id);
PACK_STRUCT_FIELD(u16_t seqno);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
PACK_STRUCT_BEGIN
struct icmp_dur_hdr {
PACK_STRUCT_FIELD(u16_t _type_code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t unused);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
PACK_STRUCT_BEGIN
struct icmp_te_hdr {
PACK_STRUCT_FIELD(u16_t _type_code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t unused);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define ICMPH_TYPE(hdr) (ntohs((hdr)->_type_code) >> 8)
#define ICMPH_CODE(hdr) (ntohs((hdr)->_type_code) & 0xff)
#define ICMPH_TYPE_SET(hdr, type) ((hdr)->_type_code = htons(ICMPH_CODE(hdr) | ((type) << 8)))
#define ICMPH_CODE_SET(hdr, code) ((hdr)->_type_code = htons((code) | (ICMPH_TYPE(hdr) << 8)))
#endif /* __LWIP_ICMP_H__ */

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_INET_H__
#define __LWIP_INET_H__
#include "lwip/arch.h"
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
u16_t inet_chksum(void *dataptr, u16_t len);
u16_t inet_chksum_pbuf(struct pbuf *p);
u16_t inet_chksum_pseudo(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
u8_t proto, u16_t proto_len);
u32_t inet_addr(const char *cp);
int inet_aton(const char *cp, struct in_addr *addr);
char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */
#ifdef htons
#undef htons
#endif /* htons */
#ifdef htonl
#undef htonl
#endif /* htonl */
#ifdef ntohs
#undef ntohs
#endif /* ntohs */
#ifdef ntohl
#undef ntohl
#endif /* ntohl */
#if BYTE_ORDER == BIG_ENDIAN
#define htons(x) (x)
#define ntohs(x) (x)
#define htonl(x) (x)
#define ntohl(x) (x)
#else
#ifdef LWIP_PREFIX_BYTEORDER_FUNCS
/* workaround for naming collisions on some platforms */
#define htons lwip_htons
#define ntohs lwip_ntohs
#define htonl lwip_htonl
#define ntohl lwip_ntohl
#endif
u16_t htons(u16_t x);
u16_t ntohs(u16_t x);
u32_t htonl(u32_t x);
u32_t ntohl(u32_t x);
#endif
#endif /* __LWIP_INET_H__ */

View file

@ -0,0 +1,154 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_H__
#define __LWIP_IP_H__
#include "lwip/arch.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
void ip_init(void);
struct netif *ip_route(struct ip_addr *dest);
err_t ip_input(struct pbuf *p, struct netif *inp);
err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
u8_t ttl, u8_t tos, u8_t proto);
err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
u8_t ttl, u8_t tos, u8_t proto,
struct netif *netif);
#define IP_HLEN 20
#define IP_PROTO_ICMP 1
#define IP_PROTO_UDP 17
#define IP_PROTO_UDPLITE 170
#define IP_PROTO_TCP 6
/* This is passed as the destination address to ip_output_if (not
to ip_output), meaning that an IP header already is constructed
in the pbuf. This is used when TCP retransmits. */
#ifdef IP_HDRINCL
#undef IP_HDRINCL
#endif /* IP_HDRINCL */
#define IP_HDRINCL NULL
/* This is the common part of all PCB types. It needs to be at the
beginning of a PCB type definition. It is located here so that
changes to this common part are made in one location instead of
having to change all PCB structs. */
#define IP_PCB struct ip_addr local_ip; \
struct ip_addr remote_ip; \
/* Socket options */ \
u16_t so_options; \
/* Type Of Service */ \
u8_t tos; \
/* Time To Live */ \
u8_t ttl
/*
* Option flags per-socket. These are the same like SO_XXX.
*/
#define SOF_DEBUG (u16_t)0x0001U /* turn on debugging info recording */
#define SOF_ACCEPTCONN (u16_t)0x0002U /* socket has had listen() */
#define SOF_REUSEADDR (u16_t)0x0004U /* allow local address reuse */
#define SOF_KEEPALIVE (u16_t)0x0008U /* keep connections alive */
#define SOF_DONTROUTE (u16_t)0x0010U /* just use interface addresses */
#define SOF_BROADCAST (u16_t)0x0020U /* permit sending of broadcast msgs */
#define SOF_USELOOPBACK (u16_t)0x0040U /* bypass hardware when possible */
#define SOF_LINGER (u16_t)0x0080U /* linger on close if data present */
#define SOF_OOBINLINE (u16_t)0x0100U /* leave received OOB data in line */
#define SOF_REUSEPORT (u16_t)0x0200U /* allow local address & port reuse */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_hdr {
/* version / header length / type of service */
PACK_STRUCT_FIELD(u16_t _v_hl_tos);
/* total length */
PACK_STRUCT_FIELD(u16_t _len);
/* identification */
PACK_STRUCT_FIELD(u16_t _id);
/* fragment offset field */
PACK_STRUCT_FIELD(u16_t _offset);
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
/* time to live / protocol*/
PACK_STRUCT_FIELD(u16_t _ttl_proto);
/* checksum */
PACK_STRUCT_FIELD(u16_t _chksum);
/* source and destination IP addresses */
PACK_STRUCT_FIELD(struct ip_addr src);
PACK_STRUCT_FIELD(struct ip_addr dest);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12)
#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f)
#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff)
#define IPH_LEN(hdr) ((hdr)->_len)
#define IPH_ID(hdr) ((hdr)->_id)
#define IPH_OFFSET(hdr) ((hdr)->_offset)
#define IPH_TTL(hdr) (ntohs((hdr)->_ttl_proto) >> 8)
#define IPH_PROTO(hdr) (ntohs((hdr)->_ttl_proto) & 0xff)
#define IPH_CHKSUM(hdr) ((hdr)->_chksum)
#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos)))
#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)
#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)
#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)
#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl_proto = (htons(IPH_PROTO(hdr) | ((ttl) << 8)))
#define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8)))
#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
#if IP_DEBUG
void ip_debug_print(struct pbuf *p);
#else
#define ip_debug_print(p)
#endif /* IP_DEBUG */
#endif /* __LWIP_IP_H__ */

View file

@ -0,0 +1,159 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_ADDR_H__
#define __LWIP_IP_ADDR_H__
#include "lwip/arch.h"
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_addr {
PACK_STRUCT_FIELD(u32_t addr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_addr2 {
PACK_STRUCT_FIELD(u16_t addrw[2]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* For compatibility with BSD code */
struct in_addr {
u32_t s_addr;
};
struct netif;
extern const struct ip_addr ip_addr_any;
extern const struct ip_addr ip_addr_broadcast;
/** IP_ADDR_ can be used as a fixed IP address
* for the wildcard and the broadcast address
*/
#define IP_ADDR_ANY ((struct ip_addr *)&ip_addr_any)
#define IP_ADDR_BROADCAST ((struct ip_addr *)&ip_addr_broadcast)
#define INADDR_NONE ((u32_t) 0xffffffff) /* 255.255.255.255 */
#define INADDR_LOOPBACK ((u32_t) 0x7f000001) /* 127.0.0.1 */
/* Definitions of the bits in an Internet address integer.
On subnets, host and network parts are found according to
the subnet mask, not these masks. */
#define IN_CLASSA(a) ((((u32_t)(a)) & 0x80000000) == 0)
#define IN_CLASSA_NET 0xff000000
#define IN_CLASSA_NSHIFT 24
#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET)
#define IN_CLASSA_MAX 128
#define IN_CLASSB(a) ((((u32_t)(a)) & 0xc0000000) == 0x80000000)
#define IN_CLASSB_NET 0xffff0000
#define IN_CLASSB_NSHIFT 16
#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET)
#define IN_CLASSB_MAX 65536
#define IN_CLASSC(a) ((((u32_t)(a)) & 0xe0000000) == 0xc0000000)
#define IN_CLASSC_NET 0xffffff00
#define IN_CLASSC_NSHIFT 8
#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET)
#define IN_CLASSD(a) (((u32_t)(a) & 0xf0000000) == 0xe0000000)
#define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */
#define IN_CLASSD_NSHIFT 28 /* net and host fields, but */
#define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */
#define IN_MULTICAST(a) IN_CLASSD(a)
#define IN_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000) == 0xf0000000)
#define IN_BADCLASS(a) (((u32_t)(a) & 0xf0000000) == 0xf0000000)
#define IN_LOOPBACKNET 127 /* official! */
#define IP4_ADDR(ipaddr, a,b,c,d) (ipaddr)->addr = htonl(((u32_t)(a & 0xff) << 24) | ((u32_t)(b & 0xff) << 16) | \
((u32_t)(c & 0xff) << 8) | (u32_t)(d & 0xff))
#define ip_addr_set(dest, src) (dest)->addr = \
((src) == NULL? 0:\
(src)->addr)
/**
* Determine if two address are on the same network.
*
* @arg addr1 IP address 1
* @arg addr2 IP address 2
* @arg mask network identifier mask
* @return !0 if the network identifiers of both address match
*/
#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \
(mask)->addr) == \
((addr2)->addr & \
(mask)->addr))
#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)
#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0)
u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *);
#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000)) == ntohl(0xe0000000))
#define ip_addr_debug_print(debug, ipaddr) LWIP_DEBUGF(debug, ("%u.%u.%u.%u", \
ipaddr?(unsigned int)(ntohl((ipaddr)->addr) >> 24) & 0xff:0, \
ipaddr?(unsigned int)(ntohl((ipaddr)->addr) >> 16) & 0xff:0, \
ipaddr?(unsigned int)(ntohl((ipaddr)->addr) >> 8) & 0xff:0, \
ipaddr?(unsigned int)ntohl((ipaddr)->addr) & 0xff:0U))
/* cast to unsigned int, as it is used as argument to printf functions
* which expect integer arguments */
#define ip4_addr1(ipaddr) ((unsigned int)(ntohl((ipaddr)->addr) >> 24) & 0xff)
#define ip4_addr2(ipaddr) ((unsigned int)(ntohl((ipaddr)->addr) >> 16) & 0xff)
#define ip4_addr3(ipaddr) ((unsigned int)(ntohl((ipaddr)->addr) >> 8) & 0xff)
#define ip4_addr4(ipaddr) ((unsigned int)(ntohl((ipaddr)->addr)) & 0xff)
#endif /* __LWIP_IP_ADDR_H__ */

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Jani Monoses <jani@iv.ro>
*
*/
#ifndef __LWIP_IP_FRAG_H__
#define __LWIP_IP_FRAG_H__
#include "lwip/err.h"
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#include "lwip/ip_addr.h"
struct pbuf * ip_reass(struct pbuf *);
err_t ip_frag(struct pbuf *, struct netif *, struct ip_addr *);
#endif /* __LWIP_IP_FRAG_H__ */

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_ICMP_H__
#define __LWIP_ICMP_H__
#include "lwip/arch.h"
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#define ICMP6_DUR 1
#define ICMP6_TE 3
#define ICMP6_ECHO 128 /* echo */
#define ICMP6_ER 129 /* echo reply */
enum icmp_dur_type {
ICMP_DUR_NET = 0, /* net unreachable */
ICMP_DUR_HOST = 1, /* host unreachable */
ICMP_DUR_PROTO = 2, /* protocol unreachable */
ICMP_DUR_PORT = 3, /* port unreachable */
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
ICMP_DUR_SR = 5 /* source route failed */
};
enum icmp_te_type {
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */
};
void icmp_input(struct pbuf *p, struct netif *inp);
void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
struct icmp_echo_hdr {
u8_t type;
u8_t icode;
u16_t chksum;
u16_t id;
u16_t seqno;
};
struct icmp_dur_hdr {
u8_t type;
u8_t icode;
u16_t chksum;
u32_t unused;
};
struct icmp_te_hdr {
u8_t type;
u8_t icode;
u16_t chksum;
u32_t unused;
};
#endif /* __LWIP_ICMP_H__ */

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_INET_H__
#define __LWIP_INET_H__
#include "lwip/arch.h"
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
u16_t inet_chksum(void *data, u16_t len);
u16_t inet_chksum_pbuf(struct pbuf *p);
u16_t inet_chksum_pseudo(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
u8_t proto, u32_t proto_len);
u32_t inet_addr(const char *cp);
int inet_aton(const char *cp, struct in_addr *addr);
#ifndef _MACHINE_ENDIAN_H_
#ifndef _NETINET_IN_H
#ifndef _LINUX_BYTEORDER_GENERIC_H
u16_t htons(u16_t n);
u16_t ntohs(u16_t n);
u32_t htonl(u32_t n);
u32_t ntohl(u32_t n);
#endif /* _LINUX_BYTEORDER_GENERIC_H */
#endif /* _NETINET_IN_H */
#endif /* _MACHINE_ENDIAN_H_ */
#endif /* __LWIP_INET_H__ */

View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_H__
#define __LWIP_IP_H__
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#define IP_HLEN 40
#define IP_PROTO_ICMP 58
#define IP_PROTO_UDP 17
#define IP_PROTO_UDPLITE 170
#define IP_PROTO_TCP 6
/* This is passed as the destination address to ip_output_if (not
to ip_output), meaning that an IP header already is constructed
in the pbuf. This is used when TCP retransmits. */
#ifdef IP_HDRINCL
#undef IP_HDRINCL
#endif /* IP_HDRINCL */
#define IP_HDRINCL NULL
/* The IPv6 header. */
struct ip_hdr {
#if BYTE_ORDER == LITTLE_ENDIAN
u8_t tclass1:4, v:4;
u8_t flow1:4, tclass2:4;
#else
u8_t v:4, tclass1:4;
u8_t tclass2:8, flow1:4;
#endif
u16_t flow2;
u16_t len; /* payload length */
u8_t nexthdr; /* next header */
u8_t hoplim; /* hop limit (TTL) */
struct ip_addr src, dest; /* source and destination IP addresses */
};
void ip_init(void);
#include "lwip/netif.h"
struct netif *ip_route(struct ip_addr *dest);
void ip_input(struct pbuf *p, struct netif *inp);
/* source and destination addresses in network byte order, please */
err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
unsigned char ttl, unsigned char proto);
err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
unsigned char ttl, unsigned char proto,
struct netif *netif);
#if IP_DEBUG
void ip_debug_print(struct pbuf *p);
#endif /* IP_DEBUG */
#endif /* __LWIP_IP_H__ */

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_ADDR_H__
#define __LWIP_IP_ADDR_H__
#include "lwip/arch.h"
#define IP_ADDR_ANY 0
struct ip_addr {
u32_t addr[4];
};
#define IP6_ADDR(ipaddr, a,b,c,d,e,f,g,h) do { (ipaddr)->addr[0] = htonl((u32_t)((a & 0xffff) << 16) | (b & 0xffff)); \
(ipaddr)->addr[1] = htonl(((c & 0xffff) << 16) | (d & 0xffff)); \
(ipaddr)->addr[2] = htonl(((e & 0xffff) << 16) | (f & 0xffff)); \
(ipaddr)->addr[3] = htonl(((g & 0xffff) << 16) | (h & 0xffff)); } while(0)
int ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
struct ip_addr *mask);
int ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2);
void ip_addr_set(struct ip_addr *dest, struct ip_addr *src);
int ip_addr_isany(struct ip_addr *addr);
#if IP_DEBUG
void ip_addr_debug_print(struct ip_addr *addr);
#endif /* IP_DEBUG */
#endif /* __LWIP_IP_ADDR_H__ */

View file

@ -0,0 +1,159 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_API_H__
#define __LWIP_API_H__
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "lwip/ip.h"
#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/err.h"
#define NETCONN_NOCOPY 0x00
#define NETCONN_COPY 0x01
enum netconn_type {
NETCONN_TCP,
NETCONN_UDP,
NETCONN_UDPLITE,
NETCONN_UDPNOCHKSUM,
NETCONN_RAW
};
enum netconn_state {
NETCONN_NONE,
NETCONN_WRITE,
NETCONN_ACCEPT,
NETCONN_RECV,
NETCONN_CONNECT,
NETCONN_CLOSE
};
enum netconn_evt {
NETCONN_EVT_RCVPLUS,
NETCONN_EVT_RCVMINUS,
NETCONN_EVT_SENDPLUS,
NETCONN_EVT_SENDMINUS
};
struct netbuf {
struct pbuf *p, *ptr;
struct ip_addr *fromaddr;
u16_t fromport;
err_t err;
};
struct netconn {
enum netconn_type type;
enum netconn_state state;
union {
struct tcp_pcb *tcp;
struct udp_pcb *udp;
struct raw_pcb *raw;
} pcb;
err_t err;
sys_mbox_t mbox;
sys_mbox_t recvmbox;
sys_mbox_t acceptmbox;
sys_sem_t sem;
int socket;
u16_t recv_avail;
void (* callback)(struct netconn *, enum netconn_evt, u16_t len);
};
/* Network buffer functions: */
struct netbuf * netbuf_new (void);
void netbuf_delete (struct netbuf *buf);
void * netbuf_alloc (struct netbuf *buf, u16_t size);
void netbuf_free (struct netbuf *buf);
void netbuf_ref (struct netbuf *buf,
void *dataptr, u16_t size);
void netbuf_chain (struct netbuf *head,
struct netbuf *tail);
u16_t netbuf_len (struct netbuf *buf);
err_t netbuf_data (struct netbuf *buf,
void **dataptr, u16_t *len);
s8_t netbuf_next (struct netbuf *buf);
void netbuf_first (struct netbuf *buf);
void netbuf_copy (struct netbuf *buf,
void *dataptr, u16_t len);
void netbuf_copy_partial(struct netbuf *buf, void *dataptr,
u16_t len, u16_t offset);
struct ip_addr * netbuf_fromaddr (struct netbuf *buf);
u16_t netbuf_fromport (struct netbuf *buf);
/* Network connection functions: */
struct netconn * netconn_new (enum netconn_type type);
struct
netconn *netconn_new_with_callback(enum netconn_type t,
void (*callback)(struct netconn *, enum netconn_evt, u16_t len));
struct
netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u16_t proto,
void (*callback)(struct netconn *, enum netconn_evt, u16_t len));
err_t netconn_delete (struct netconn *conn);
enum netconn_type netconn_type (struct netconn *conn);
err_t netconn_peer (struct netconn *conn,
struct ip_addr *addr,
u16_t *port);
err_t netconn_addr (struct netconn *conn,
struct ip_addr **addr,
u16_t *port);
err_t netconn_bind (struct netconn *conn,
struct ip_addr *addr,
u16_t port);
err_t netconn_connect (struct netconn *conn,
struct ip_addr *addr,
u16_t port);
err_t netconn_disconnect (struct netconn *conn);
err_t netconn_listen (struct netconn *conn);
struct netconn * netconn_accept (struct netconn *conn);
struct netbuf * netconn_recv (struct netconn *conn);
err_t netconn_send (struct netconn *conn,
struct netbuf *buf);
err_t netconn_write (struct netconn *conn,
void *dataptr, u16_t size,
u8_t copy);
err_t netconn_close (struct netconn *conn);
err_t netconn_err (struct netconn *conn);
#endif /* __LWIP_API_H__ */

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_API_MSG_H__
#define __LWIP_API_MSG_H__
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "lwip/ip.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/api.h"
enum api_msg_type {
API_MSG_NEWCONN,
API_MSG_DELCONN,
API_MSG_BIND,
API_MSG_CONNECT,
API_MSG_DISCONNECT,
API_MSG_LISTEN,
API_MSG_ACCEPT,
API_MSG_SEND,
API_MSG_RECV,
API_MSG_WRITE,
API_MSG_CLOSE,
API_MSG_MAX
};
struct api_msg_msg {
struct netconn *conn;
enum netconn_type conntype;
union {
struct pbuf *p;
struct {
struct ip_addr *ipaddr;
u16_t port;
} bc;
struct {
void *dataptr;
u16_t len;
unsigned char copy;
} w;
sys_mbox_t mbox;
u16_t len;
} msg;
};
struct api_msg {
enum api_msg_type type;
struct api_msg_msg msg;
};
void api_msg_input(struct api_msg *msg);
void api_msg_post(struct api_msg *msg);
#endif /* __LWIP_API_MSG_H__ */

View file

@ -0,0 +1,216 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_ARCH_H__
#define __LWIP_ARCH_H__
#ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN 1234
#endif
#ifndef BIG_ENDIAN
#define BIG_ENDIAN 4321
#endif
#include "arch/cc.h"
#ifndef PACK_STRUCT_BEGIN
#define PACK_STRUCT_BEGIN
#endif /* PACK_STRUCT_BEGIN */
#ifndef PACK_STRUCT_END
#define PACK_STRUCT_END
#endif /* PACK_STRUCT_END */
#ifndef PACK_STRUCT_FIELD
#define PACK_STRUCT_FIELD(x) x
#endif /* PACK_STRUCT_FIELD */
#ifdef LWIP_PROVIDE_ERRNO
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Arg list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale NFS file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#define ENSROK 0 /* DNS server returned answer with no data */
#define ENSRNODATA 160 /* DNS server returned answer with no data */
#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
#define ENSRSERVFAIL 162 /* DNS server returned general failure */
#define ENSRNOTFOUND 163 /* Domain name not found */
#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
#define ENSRREFUSED 165 /* DNS server refused query */
#define ENSRBADQUERY 166 /* Misformatted DNS query */
#define ENSRBADNAME 167 /* Misformatted domain name */
#define ENSRBADFAMILY 168 /* Unsupported address family */
#define ENSRBADRESP 169 /* Misformatted DNS reply */
#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
#define ENSROF 172 /* End of file */
#define ENSRFILE 173 /* Error reading file */
#define ENSRNOMEM 174 /* Out of memory */
#define ENSRDESTRUCTION 175 /* Application terminated lookup */
#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */
#define ENSRCNAMELOOP 177 /* Domain name is too long */
#ifndef errno
extern int errno;
#endif
#endif /* LWIP_PROVIDE_ERRNO */
#endif /* __LWIP_ARCH_H__ */

View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_DEBUG_H__
#define __LWIP_DEBUG_H__
#include "arch/cc.h"
/** lower two bits indicate debug level
* - 0 off
* - 1 warning
* - 2 serious
* - 3 severe
*/
#define DBG_LEVEL_OFF 0
#define DBG_LEVEL_WARNING 1 /* bad checksums, dropped packets, ... */
#define DBG_LEVEL_SERIOUS 2 /* memory allocation failures, ... */
#define DBG_LEVEL_SEVERE 3 /* */
#define DBG_MASK_LEVEL 3
/** flag for LWIP_DEBUGF to enable that debug message */
#define DBG_ON 0x80U
/** flag for LWIP_DEBUGF to disable that debug message */
#define DBG_OFF 0x00U
/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */
#define DBG_TRACE 0x40U
/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */
#define DBG_STATE 0x20U
/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */
#define DBG_FRESH 0x10U
/** flag for LWIP_DEBUGF to halt after printing this debug message */
#define DBG_HALT 0x08U
#ifndef LWIP_NOASSERT
# define LWIP_ASSERT(x,y) do { if(!(y)) LWIP_PLATFORM_ASSERT(x); } while(0)
#else
# define LWIP_ASSERT(x,y)
#endif
#ifdef LWIP_DEBUG
/** print debug message only if debug message type is enabled...
* AND is of correct type AND is at least DBG_LEVEL
*/
# define LWIP_DEBUGF(debug,x) do { if (((debug) & DBG_ON) && ((debug) & DBG_TYPES_ON) && ((int)((debug) & DBG_MASK_LEVEL) >= DBG_MIN_LEVEL)) { LWIP_PLATFORM_DIAG(x); if ((debug) & DBG_HALT) while(1); } } while(0)
# define LWIP_ERROR(x) do { LWIP_PLATFORM_DIAG(x); } while(0)
#else /* LWIP_DEBUG */
# define LWIP_DEBUGF(debug,x)
# define LWIP_ERROR(x)
#endif /* LWIP_DEBUG */
#endif /* __LWIP_DEBUG_H__ */

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_DEF_H__
#define __LWIP_DEF_H__
/* this might define NULL already */
#include "arch/cc.h"
#define LWIP_MAX(x , y) (x) > (y) ? (x) : (y)
#define LWIP_MIN(x , y) (x) < (y) ? (x) : (y)
#ifndef NULL
#define NULL ((void *)0)
#endif
#endif /* __LWIP_DEF_H__ */

View file

@ -0,0 +1,223 @@
/** @file
*/
#ifndef __LWIP_DHCP_H__
#define __LWIP_DHCP_H__
#include "lwip/opt.h"
#include "lwip/netif.h"
#include "lwip/udp.h"
/** period (in seconds) of the application calling dhcp_coarse_tmr() */
#define DHCP_COARSE_TIMER_SECS 60
/** period (in milliseconds) of the application calling dhcp_fine_tmr() */
#define DHCP_FINE_TIMER_MSECS 500
struct dhcp
{
/** current DHCP state machine state */
u8_t state;
/** retries of current request */
u8_t tries;
/** transaction identifier of last sent request */
u32_t xid;
/** our connection to the DHCP server */
struct udp_pcb *pcb;
/** (first) pbuf of incoming msg */
struct pbuf *p;
/** incoming msg */
struct dhcp_msg *msg_in;
/** incoming msg options */
struct dhcp_msg *options_in;
/** ingoing msg options length */
u16_t options_in_len;
struct pbuf *p_out; /* pbuf of outcoming msg */
struct dhcp_msg *msg_out; /* outgoing msg */
u16_t options_out_len; /* outgoing msg options length */
u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */
u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */
u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */
struct ip_addr server_ip_addr; /* dhcp server address that offered this lease */
struct ip_addr offered_ip_addr;
struct ip_addr offered_sn_mask;
struct ip_addr offered_gw_addr;
struct ip_addr offered_bc_addr;
#define DHCP_MAX_DNS 2
u32_t dns_count; /* actual number of DNS servers obtained */
struct ip_addr offered_dns_addr[DHCP_MAX_DNS]; /* DNS server addresses */
u32_t offered_t0_lease; /* lease period (in seconds) */
u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */
u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */
/** Patch #1308
* TODO: See dhcp.c "TODO"s
*/
#if 0
struct ip_addr offered_si_addr;
u8_t *boot_file_name;
#endif
};
/* MUST be compiled with "pack structs" or equivalent! */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** minimum set of fields of any DHCP message */
struct dhcp_msg
{
PACK_STRUCT_FIELD(u8_t op);
PACK_STRUCT_FIELD(u8_t htype);
PACK_STRUCT_FIELD(u8_t hlen);
PACK_STRUCT_FIELD(u8_t hops);
PACK_STRUCT_FIELD(u32_t xid);
PACK_STRUCT_FIELD(u16_t secs);
PACK_STRUCT_FIELD(u16_t flags);
PACK_STRUCT_FIELD(struct ip_addr ciaddr);
PACK_STRUCT_FIELD(struct ip_addr yiaddr);
PACK_STRUCT_FIELD(struct ip_addr siaddr);
PACK_STRUCT_FIELD(struct ip_addr giaddr);
#define DHCP_CHADDR_LEN 16U
PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);
#define DHCP_SNAME_LEN 64U
PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);
#define DHCP_FILE_LEN 128U
PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);
PACK_STRUCT_FIELD(u32_t cookie);
#define DHCP_MIN_OPTIONS_LEN 68U
/** make sure user does not configure this too small */
#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN))
# undef DHCP_OPTIONS_LEN
#endif
/** allow this to be configured in lwipopts.h, but not too small */
#if (!defined(DHCP_OPTIONS_LEN))
/** set this to be sufficient for your options in outgoing DHCP msgs */
# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN
#endif
PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** start DHCP configuration */
err_t dhcp_start(struct netif *netif);
/** enforce early lease renewal (not needed normally)*/
err_t dhcp_renew(struct netif *netif);
/** release the DHCP lease, usually called before dhcp_stop()*/
err_t dhcp_release(struct netif *netif);
/** stop DHCP configuration */
void dhcp_stop(struct netif *netif);
/** inform server of our manual IP address */
void dhcp_inform(struct netif *netif);
/** if enabled, check whether the offered IP address is not in use, using ARP */
#if DHCP_DOES_ARP_CHECK
void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr);
#endif
/** to be called every minute */
void dhcp_coarse_tmr(void);
/** to be called every half second */
void dhcp_fine_tmr(void);
/** DHCP message item offsets and length */
#define DHCP_MSG_OFS (UDP_DATA_OFS)
#define DHCP_OP_OFS (DHCP_MSG_OFS + 0)
#define DHCP_HTYPE_OFS (DHCP_MSG_OFS + 1)
#define DHCP_HLEN_OFS (DHCP_MSG_OFS + 2)
#define DHCP_HOPS_OFS (DHCP_MSG_OFS + 3)
#define DHCP_XID_OFS (DHCP_MSG_OFS + 4)
#define DHCP_SECS_OFS (DHCP_MSG_OFS + 8)
#define DHCP_FLAGS_OFS (DHCP_MSG_OFS + 10)
#define DHCP_CIADDR_OFS (DHCP_MSG_OFS + 12)
#define DHCP_YIADDR_OFS (DHCP_MSG_OFS + 16)
#define DHCP_SIADDR_OFS (DHCP_MSG_OFS + 20)
#define DHCP_GIADDR_OFS (DHCP_MSG_OFS + 24)
#define DHCP_CHADDR_OFS (DHCP_MSG_OFS + 28)
#define DHCP_SNAME_OFS (DHCP_MSG_OFS + 44)
#define DHCP_FILE_OFS (DHCP_MSG_OFS + 108)
#define DHCP_MSG_LEN 236
#define DHCP_COOKIE_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN)
#define DHCP_OPTIONS_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN + 4)
#define DHCP_CLIENT_PORT 68
#define DHCP_SERVER_PORT 67
/** DHCP client states */
#define DHCP_REQUESTING 1
#define DHCP_INIT 2
#define DHCP_REBOOTING 3
#define DHCP_REBINDING 4
#define DHCP_RENEWING 5
#define DHCP_SELECTING 6
#define DHCP_INFORMING 7
#define DHCP_CHECKING 8
#define DHCP_PERMANENT 9
#define DHCP_BOUND 10
/** not yet implemented #define DHCP_RELEASING 11 */
#define DHCP_BACKING_OFF 12
#define DHCP_OFF 13
#define DHCP_BOOTREQUEST 1
#define DHCP_BOOTREPLY 2
#define DHCP_DISCOVER 1
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_DECLINE 4
#define DHCP_ACK 5
#define DHCP_NAK 6
#define DHCP_RELEASE 7
#define DHCP_INFORM 8
#define DHCP_HTYPE_ETH 1
#define DHCP_HLEN_ETH 6
#define DHCP_BROADCAST_FLAG 15
#define DHCP_BROADCAST_MASK (1 << DHCP_FLAG_BROADCAST)
/** BootP options */
#define DHCP_OPTION_PAD 0
#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */
#define DHCP_OPTION_ROUTER 3
#define DHCP_OPTION_DNS_SERVER 6
#define DHCP_OPTION_HOSTNAME 12
#define DHCP_OPTION_IP_TTL 23
#define DHCP_OPTION_MTU 26
#define DHCP_OPTION_BROADCAST 28
#define DHCP_OPTION_TCP_TTL 37
#define DHCP_OPTION_END 255
/** DHCP options */
#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */
#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */
#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */
#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */
#define DHCP_OPTION_MESSAGE_TYPE_LEN 1
#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */
#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */
#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */
#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2
#define DHCP_OPTION_T1 58 /* T1 renewal time */
#define DHCP_OPTION_T2 59 /* T2 rebinding time */
#define DHCP_OPTION_CLIENT_ID 61
#define DHCP_OPTION_TFTP_SERVERNAME 66
#define DHCP_OPTION_BOOTFILE 67
/** possible combinations of overloading the file and sname fields with options */
#define DHCP_OVERLOAD_NONE 0
#define DHCP_OVERLOAD_FILE 1
#define DHCP_OVERLOAD_SNAME 2
#define DHCP_OVERLOAD_SNAME_FILE 3
#endif /*__LWIP_DHCP_H__*/

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_ERR_H__
#define __LWIP_ERR_H__
#include "lwip/opt.h"
#include "arch/cc.h"
typedef s8_t err_t;
/* Definitions for error constants. */
#define ERR_OK 0 /* No error, everything OK. */
#define ERR_MEM -1 /* Out of memory error. */
#define ERR_BUF -2 /* Buffer error. */
#define ERR_ABRT -3 /* Connection aborted. */
#define ERR_RST -4 /* Connection reset. */
#define ERR_CLSD -5 /* Connection closed. */
#define ERR_CONN -6 /* Not connected. */
#define ERR_VAL -7 /* Illegal value. */
#define ERR_ARG -8 /* Illegal argument. */
#define ERR_RTE -9 /* Routing problem. */
#define ERR_USE -10 /* Address in use. */
#define ERR_IF -11 /* Low-level netif error */
#define ERR_ISCONN -12 /* Already connected. */
#ifdef LWIP_DEBUG
extern char *lwip_strerr(err_t err);
#else
#define lwip_strerr(x) ""
#endif /* LWIP_DEBUG */
#endif /* __LWIP_ERR_H__ */

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_MEM_H__
#define __LWIP_MEM_H__
#include "lwip/opt.h"
#include "lwip/arch.h"
#if MEM_SIZE > 64000l
typedef u32_t mem_size_t;
#else
typedef u16_t mem_size_t;
#endif /* MEM_SIZE > 64000 */
void mem_init(void);
void *mem_malloc(mem_size_t size);
void mem_free(void *mem);
void *mem_realloc(void *mem, mem_size_t size);
void *mem_reallocm(void *mem, mem_size_t size);
#ifndef MEM_ALIGN_SIZE
#define MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))
#endif
#ifndef MEM_ALIGN
#define MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1)))
#endif
#endif /* __LWIP_MEM_H__ */

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_MEMP_H__
#define __LWIP_MEMP_H__
#include "lwip/opt.h"
typedef enum {
MEMP_PBUF,
MEMP_RAW_PCB,
MEMP_UDP_PCB,
MEMP_TCP_PCB,
MEMP_TCP_PCB_LISTEN,
MEMP_TCP_SEG,
MEMP_NETBUF,
MEMP_NETCONN,
MEMP_API_MSG,
MEMP_TCPIP_MSG,
MEMP_SYS_TIMEOUT,
MEMP_MAX
} memp_t;
void memp_init(void);
void *memp_malloc(memp_t type);
void *memp_realloc(memp_t fromtype, memp_t totype, void *mem);
void memp_free(memp_t type, void *mem);
#endif /* __LWIP_MEMP_H__ */

View file

@ -0,0 +1,150 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_NETIF_H__
#define __LWIP_NETIF_H__
#include "lwip/opt.h"
#include "lwip/err.h"
#include "lwip/ip_addr.h"
#include "lwip/inet.h"
#include "lwip/pbuf.h"
#if LWIP_DHCP
# include "lwip/dhcp.h"
#endif
/** must be the maximum of all used hardware address lengths
across all types of interfaces in use */
#define NETIF_MAX_HWADDR_LEN 6U
/** TODO: define the use (where, when, whom) of netif flags */
/** whether the network interface is 'up'. this is
* a software flag used to control whether this network
* interface is enabled and processes traffic.
*/
#define NETIF_FLAG_UP 0x1U
/** if set, the netif has broadcast capability */
#define NETIF_FLAG_BROADCAST 0x2U
/** if set, the netif is one end of a point-to-point connection */
#define NETIF_FLAG_POINTTOPOINT 0x4U
/** if set, the interface is configured using DHCP */
#define NETIF_FLAG_DHCP 0x08U
/** if set, the interface has an active link
* (set by the network interface driver) */
#define NETIF_FLAG_LINK_UP 0x10U
/** Generic data structure used for all lwIP network interfaces.
* The following fields should be filled in by the initialization
* function for the device driver: hwaddr_len, hwaddr[], mtu, flags */
struct netif {
/** pointer to next in linked list */
struct netif *next;
/** IP address configuration in network byte order */
struct ip_addr ip_addr;
struct ip_addr netmask;
struct ip_addr gw;
/** This function is called by the network device driver
* to pass a packet up the TCP/IP stack. */
err_t (* input)(struct pbuf *p, struct netif *inp);
/** This function is called by the IP module when it wants
* to send a packet on the interface. This function typically
* first resolves the hardware address, then sends the packet. */
err_t (* output)(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr);
/** This function is called by the ARP module when it wants
* to send a packet on the interface. This function outputs
* the pbuf as-is on the link medium. */
err_t (* linkoutput)(struct netif *netif, struct pbuf *p);
/** This field can be set by the device driver and could point
* to state information for the device. */
void *state;
#if LWIP_DHCP
/** the DHCP client state information for this netif */
struct dhcp *dhcp;
#endif
/** number of bytes used in hwaddr */
unsigned char hwaddr_len;
/** link level hardware address of this interface */
unsigned char hwaddr[NETIF_MAX_HWADDR_LEN];
/** maximum transfer unit (in bytes) */
u16_t mtu;
/** flags (see NETIF_FLAG_ above) */
u8_t flags;
/** link type */
u8_t link_type;
/** descriptive abbreviation */
char name[2];
/** number of this interface */
u8_t num;
};
/** The list of network interfaces. */
extern struct netif *netif_list;
/** The default network interface. */
extern struct netif *netif_default;
/* netif_init() must be called first. */
void netif_init(void);
struct netif *netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
struct ip_addr *gw,
void *state,
err_t (* init)(struct netif *netif),
err_t (* input)(struct pbuf *p, struct netif *netif));
void
netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask,
struct ip_addr *gw);
void netif_remove(struct netif * netif);
/* Returns a network interface given its name. The name is of the form
"et0", where the first two letters are the "name" field in the
netif structure, and the digit is in the num field in the same
structure. */
struct netif *netif_find(char *name);
void netif_set_default(struct netif *netif);
void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr);
void netif_set_netmask(struct netif *netif, struct ip_addr *netmast);
void netif_set_gw(struct netif *netif, struct ip_addr *gw);
void netif_set_up(struct netif *netif);
void netif_set_down(struct netif *netif);
u8_t netif_is_up(struct netif *netif);
#endif /* __LWIP_NETIF_H__ */

View file

@ -0,0 +1,669 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_OPT_H__
#define __LWIP_OPT_H__
/* Include user defined options first */
#include "lwipopts.h"
#include "lwip/debug.h"
/* Define default values for unconfigured parameters. */
/* Platform specific locking */
/*
* enable SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection
* for certain critical regions during buffer allocation, deallocation and memory
* allocation and deallocation.
*/
#ifndef SYS_LIGHTWEIGHT_PROT
#define SYS_LIGHTWEIGHT_PROT 0
#endif
#ifndef NO_SYS
#define NO_SYS 0
#endif
/* ---------- Memory options ---------- */
/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which
lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2
byte alignment -> define MEM_ALIGNMENT to 2. */
#ifndef MEM_ALIGNMENT
#define MEM_ALIGNMENT 1
#endif
/* MEM_SIZE: the size of the heap memory. If the application will send
a lot of data that needs to be copied, this should be set high. */
#ifndef MEM_SIZE
#define MEM_SIZE 1600
#endif
#ifndef MEMP_SANITY_CHECK
#define MEMP_SANITY_CHECK 0
#endif
/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
sends a lot of data out of ROM (or other static memory), this
should be set high. */
#ifndef MEMP_NUM_PBUF
#define MEMP_NUM_PBUF 16
#endif
/* Number of raw connection PCBs */
#ifndef MEMP_NUM_RAW_PCB
#define MEMP_NUM_RAW_PCB 4
#endif
/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
per active UDP "connection". */
#ifndef MEMP_NUM_UDP_PCB
#define MEMP_NUM_UDP_PCB 4
#endif
/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
connections. */
#ifndef MEMP_NUM_TCP_PCB
#define MEMP_NUM_TCP_PCB 5
#endif
/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
connections. */
#ifndef MEMP_NUM_TCP_PCB_LISTEN
#define MEMP_NUM_TCP_PCB_LISTEN 8
#endif
/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
segments. */
#ifndef MEMP_NUM_TCP_SEG
#define MEMP_NUM_TCP_SEG 16
#endif
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
timeouts. */
#ifndef MEMP_NUM_SYS_TIMEOUT
#define MEMP_NUM_SYS_TIMEOUT 3
#endif
/* The following four are used only with the sequential API and can be
set to 0 if the application only will use the raw API. */
/* MEMP_NUM_NETBUF: the number of struct netbufs. */
#ifndef MEMP_NUM_NETBUF
#define MEMP_NUM_NETBUF 2
#endif
/* MEMP_NUM_NETCONN: the number of struct netconns. */
#ifndef MEMP_NUM_NETCONN
#define MEMP_NUM_NETCONN 4
#endif
/* MEMP_NUM_APIMSG: the number of struct api_msg, used for
communication between the TCP/IP stack and the sequential
programs. */
#ifndef MEMP_NUM_API_MSG
#define MEMP_NUM_API_MSG 8
#endif
/* MEMP_NUM_TCPIPMSG: the number of struct tcpip_msg, which is used
for sequential API communication and incoming packets. Used in
src/api/tcpip.c. */
#ifndef MEMP_NUM_TCPIP_MSG
#define MEMP_NUM_TCPIP_MSG 8
#endif
/* ---------- Pbuf options ---------- */
/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
#ifndef PBUF_POOL_SIZE
#define PBUF_POOL_SIZE 16
#endif
/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
#ifndef PBUF_POOL_BUFSIZE
#define PBUF_POOL_BUFSIZE 128
#endif
/* PBUF_LINK_HLEN: the number of bytes that should be allocated for a
link level header. Defaults to 14 for Ethernet. */
#ifndef PBUF_LINK_HLEN
#define PBUF_LINK_HLEN 14
#endif
/* ---------- ARP options ---------- */
/** Number of active hardware address, IP address pairs cached */
#ifndef ARP_TABLE_SIZE
#define ARP_TABLE_SIZE 10
#endif
/**
* If enabled, outgoing packets are queued during hardware address
* resolution.
*
* This feature has not stabilized yet. Single-packet queueing is
* believed to be stable, multi-packet queueing is believed to
* clash with the TCP segment queueing.
*
* As multi-packet-queueing is currently disabled, enabling this
* _should_ work, but we need your testing feedback on lwip-users.
*
*/
#ifndef ARP_QUEUEING
#define ARP_QUEUEING 1
#endif
/* This option is deprecated */
#ifdef ETHARP_QUEUE_FIRST
#error ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h.
#endif
/* This option is removed to comply with the ARP standard */
#ifdef ETHARP_ALWAYS_INSERT
#error ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h.
#endif
/* ---------- IP options ---------- */
/* Define IP_FORWARD to 1 if you wish to have the ability to forward
IP packets across network interfaces. If you are going to run lwIP
on a device with only one network interface, define this to 0. */
#ifndef IP_FORWARD
#define IP_FORWARD 0
#endif
/* If defined to 1, IP options are allowed (but not parsed). If
defined to 0, all packets with IP options are dropped. */
#ifndef IP_OPTIONS
#define IP_OPTIONS 1
#endif
/** IP reassembly and segmentation. Even if they both deal with IP
* fragments, note that these are orthogonal, one dealing with incoming
* packets, the other with outgoing packets
*/
/** Reassemble incoming fragmented IP packets */
#ifndef IP_REASSEMBLY
#define IP_REASSEMBLY 1
#endif
/** Fragment outgoing IP packets if their size exceeds MTU */
#ifndef IP_FRAG
#define IP_FRAG 1
#endif
/* ---------- ICMP options ---------- */
#ifndef ICMP_TTL
#define ICMP_TTL 255
#endif
/* ---------- RAW options ---------- */
#ifndef LWIP_RAW
#define LWIP_RAW 1
#endif
#ifndef RAW_TTL
#define RAW_TTL 255
#endif
/* ---------- DHCP options ---------- */
#ifndef LWIP_DHCP
#define LWIP_DHCP 0
#endif
/* 1 if you want to do an ARP check on the offered address
(recommended). */
#ifndef DHCP_DOES_ARP_CHECK
#define DHCP_DOES_ARP_CHECK 1
#endif
/* ---------- UDP options ---------- */
#ifndef LWIP_UDP
#define LWIP_UDP 1
#endif
#ifndef UDP_TTL
#define UDP_TTL 255
#endif
/* ---------- TCP options ---------- */
#ifndef LWIP_TCP
#define LWIP_TCP 1
#endif
#ifndef TCP_TTL
#define TCP_TTL 255
#endif
#ifndef TCP_WND
#define TCP_WND 2048
#endif
#ifndef TCP_MAXRTX
#define TCP_MAXRTX 12
#endif
#ifndef TCP_SYNMAXRTX
#define TCP_SYNMAXRTX 6
#endif
/* Controls if TCP should queue segments that arrive out of
order. Define to 0 if your device is low on memory. */
#ifndef TCP_QUEUE_OOSEQ
#define TCP_QUEUE_OOSEQ 1
#endif
/* TCP Maximum segment size. */
#ifndef TCP_MSS
#define TCP_MSS 128 /* A *very* conservative default. */
#endif
/* TCP sender buffer space (bytes). */
#ifndef TCP_SND_BUF
#define TCP_SND_BUF 256
#endif
/* TCP sender buffer space (pbufs). This must be at least = 2 *
TCP_SND_BUF/TCP_MSS for things to work. */
#ifndef TCP_SND_QUEUELEN
#define TCP_SND_QUEUELEN 4 * TCP_SND_BUF/TCP_MSS
#endif
/* Maximum number of retransmissions of data segments. */
/* Maximum number of retransmissions of SYN segments. */
/* TCP writable space (bytes). This must be less than or equal
to TCP_SND_BUF. It is the amount of space which must be
available in the tcp snd_buf for select to return writable */
#ifndef TCP_SNDLOWAT
#define TCP_SNDLOWAT TCP_SND_BUF/2
#endif
/* Support loop interface (127.0.0.1) */
#ifndef LWIP_HAVE_LOOPIF
#define LWIP_HAVE_LOOPIF 1
#endif
#ifndef LWIP_EVENT_API
#define LWIP_EVENT_API 0
#define LWIP_CALLBACK_API 1
#else
#define LWIP_EVENT_API 1
#define LWIP_CALLBACK_API 0
#endif
#ifndef LWIP_COMPAT_SOCKETS
#define LWIP_COMPAT_SOCKETS 1
#endif
#ifndef TCPIP_THREAD_PRIO
#define TCPIP_THREAD_PRIO 1
#endif
#ifndef SLIPIF_THREAD_PRIO
#define SLIPIF_THREAD_PRIO 1
#endif
#ifndef PPP_THREAD_PRIO
#define PPP_THREAD_PRIO 1
#endif
#ifndef DEFAULT_THREAD_PRIO
#define DEFAULT_THREAD_PRIO 1
#endif
/* ---------- Socket Options ---------- */
/* Enable SO_REUSEADDR and SO_REUSEPORT options */
#ifndef SO_REUSE
# define SO_REUSE 0
#endif
/* ---------- Statistics options ---------- */
#ifndef LWIP_STATS
#define LWIP_STATS 1
#endif
#if LWIP_STATS
#ifndef LWIP_STATS_DISPLAY
#define LWIP_STATS_DISPLAY 0
#endif
#ifndef LINK_STATS
#define LINK_STATS 1
#endif
#ifndef IP_STATS
#define IP_STATS 1
#endif
#ifndef IPFRAG_STATS
#define IPFRAG_STATS 1
#endif
#ifndef ICMP_STATS
#define ICMP_STATS 1
#endif
#ifndef UDP_STATS
#define UDP_STATS 1
#endif
#ifndef TCP_STATS
#define TCP_STATS 1
#endif
#ifndef MEM_STATS
#define MEM_STATS 1
#endif
#ifndef MEMP_STATS
#define MEMP_STATS 1
#endif
#ifndef PBUF_STATS
#define PBUF_STATS 1
#endif
#ifndef SYS_STATS
#define SYS_STATS 1
#endif
#ifndef RAW_STATS
#define RAW_STATS 0
#endif
#else
#define LINK_STATS 0
#define IP_STATS 0
#define IPFRAG_STATS 0
#define ICMP_STATS 0
#define UDP_STATS 0
#define TCP_STATS 0
#define MEM_STATS 0
#define MEMP_STATS 0
#define PBUF_STATS 0
#define SYS_STATS 0
#define RAW_STATS 0
#define LWIP_STATS_DISPLAY 0
#endif /* LWIP_STATS */
/* ---------- PPP options ---------- */
#ifndef PPP_SUPPORT
#define PPP_SUPPORT 0 /* Set for PPP */
#endif
#if PPP_SUPPORT
#define NUM_PPP 1 /* Max PPP sessions. */
#ifndef PAP_SUPPORT
#define PAP_SUPPORT 0 /* Set for PAP. */
#endif
#ifndef CHAP_SUPPORT
#define CHAP_SUPPORT 0 /* Set for CHAP. */
#endif
#define MSCHAP_SUPPORT 0 /* Set for MSCHAP (NOT FUNCTIONAL!) */
#define CBCP_SUPPORT 0 /* Set for CBCP (NOT FUNCTIONAL!) */
#define CCP_SUPPORT 0 /* Set for CCP (NOT FUNCTIONAL!) */
#ifndef VJ_SUPPORT
#define VJ_SUPPORT 0 /* Set for VJ header compression. */
#endif
#ifndef MD5_SUPPORT
#define MD5_SUPPORT 0 /* Set for MD5 (see also CHAP) */
#endif
/*
* Timeouts.
*/
#define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */
#define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */
#define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */
#define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */
#define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */
#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */
#define CHAP_DEFTIMEOUT 6 /* Timeout time in seconds */
#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */
/* Interval in seconds between keepalive echo requests, 0 to disable. */
#if 1
#define LCP_ECHOINTERVAL 0
#else
#define LCP_ECHOINTERVAL 10
#endif
/* Number of unanswered echo requests before failure. */
#define LCP_MAXECHOFAILS 3
/* Max Xmit idle time (in jiffies) before resend flag char. */
#define PPP_MAXIDLEFLAG 100
/*
* Packet sizes
*
* Note - lcp shouldn't be allowed to negotiate stuff outside these
* limits. See lcp.h in the pppd directory.
* (XXX - these constants should simply be shared by lcp.c instead
* of living in lcp.h)
*/
#define PPP_MTU 1500 /* Default MTU (size of Info field) */
#if 0
#define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN)
#else
#define PPP_MAXMTU 1500 /* Largest MTU we allow */
#endif
#define PPP_MINMTU 64
#define PPP_MRU 1500 /* default MRU = max length of info field */
#define PPP_MAXMRU 1500 /* Largest MRU we allow */
#define PPP_DEFMRU 296 /* Try for this */
#define PPP_MINMRU 128 /* No MRUs below this */
#define MAXNAMELEN 256 /* max length of hostname or name for auth */
#define MAXSECRETLEN 256 /* max length of password or secret */
#endif /* PPP_SUPPORT */
/* checksum options - set to zero for hardware checksum support */
#ifndef CHECKSUM_GEN_IP
#define CHECKSUM_GEN_IP 1
#endif
#ifndef CHECKSUM_GEN_UDP
#define CHECKSUM_GEN_UDP 1
#endif
#ifndef CHECKSUM_GEN_TCP
#define CHECKSUM_GEN_TCP 1
#endif
#ifndef CHECKSUM_CHECK_IP
#define CHECKSUM_CHECK_IP 1
#endif
#ifndef CHECKSUM_CHECK_UDP
#define CHECKSUM_CHECK_UDP 1
#endif
#ifndef CHECKSUM_CHECK_TCP
#define CHECKSUM_CHECK_TCP 1
#endif
/* Debugging options all default to off */
#ifndef DBG_TYPES_ON
#define DBG_TYPES_ON 0
#endif
#ifndef ETHARP_DEBUG
#define ETHARP_DEBUG DBG_OFF
#endif
#ifndef NETIF_DEBUG
#define NETIF_DEBUG DBG_OFF
#endif
#ifndef PBUF_DEBUG
#define PBUF_DEBUG DBG_OFF
#endif
#ifndef API_LIB_DEBUG
#define API_LIB_DEBUG DBG_OFF
#endif
#ifndef API_MSG_DEBUG
#define API_MSG_DEBUG DBG_OFF
#endif
#ifndef SOCKETS_DEBUG
#define SOCKETS_DEBUG DBG_OFF
#endif
#ifndef ICMP_DEBUG
#define ICMP_DEBUG DBG_OFF
#endif
#ifndef INET_DEBUG
#define INET_DEBUG DBG_OFF
#endif
#ifndef IP_DEBUG
#define IP_DEBUG DBG_OFF
#endif
#ifndef IP_REASS_DEBUG
#define IP_REASS_DEBUG DBG_OFF
#endif
#ifndef RAW_DEBUG
#define RAW_DEBUG DBG_OFF
#endif
#ifndef MEM_DEBUG
#define MEM_DEBUG DBG_OFF
#endif
#ifndef MEMP_DEBUG
#define MEMP_DEBUG DBG_OFF
#endif
#ifndef SYS_DEBUG
#define SYS_DEBUG DBG_OFF
#endif
#ifndef TCP_DEBUG
#define TCP_DEBUG DBG_OFF
#endif
#ifndef TCP_INPUT_DEBUG
#define TCP_INPUT_DEBUG DBG_OFF
#endif
#ifndef TCP_FR_DEBUG
#define TCP_FR_DEBUG DBG_OFF
#endif
#ifndef TCP_RTO_DEBUG
#define TCP_RTO_DEBUG DBG_OFF
#endif
#ifndef TCP_REXMIT_DEBUG
#define TCP_REXMIT_DEBUG DBG_OFF
#endif
#ifndef TCP_CWND_DEBUG
#define TCP_CWND_DEBUG DBG_OFF
#endif
#ifndef TCP_WND_DEBUG
#define TCP_WND_DEBUG DBG_OFF
#endif
#ifndef TCP_OUTPUT_DEBUG
#define TCP_OUTPUT_DEBUG DBG_OFF
#endif
#ifndef TCP_RST_DEBUG
#define TCP_RST_DEBUG DBG_OFF
#endif
#ifndef TCP_QLEN_DEBUG
#define TCP_QLEN_DEBUG DBG_OFF
#endif
#ifndef UDP_DEBUG
#define UDP_DEBUG DBG_OFF
#endif
#ifndef TCPIP_DEBUG
#define TCPIP_DEBUG DBG_OFF
#endif
#ifndef PPP_DEBUG
#define PPP_DEBUG DBG_OFF
#endif
#ifndef SLIP_DEBUG
#define SLIP_DEBUG DBG_OFF
#endif
#ifndef DHCP_DEBUG
#define DHCP_DEBUG DBG_OFF
#endif
#ifndef DBG_MIN_LEVEL
#define DBG_MIN_LEVEL DBG_LEVEL_OFF
#endif
#endif /* __LWIP_OPT_H__ */

View file

@ -0,0 +1,113 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_PBUF_H__
#define __LWIP_PBUF_H__
#include "arch/cc.h"
#define PBUF_TRANSPORT_HLEN 20
#define PBUF_IP_HLEN 20
typedef enum {
PBUF_TRANSPORT,
PBUF_IP,
PBUF_LINK,
PBUF_RAW
} pbuf_layer;
typedef enum {
PBUF_RAM,
PBUF_ROM,
PBUF_REF,
PBUF_POOL
} pbuf_flag;
/* Definitions for the pbuf flag field. These are NOT the flags that
* are passed to pbuf_alloc(). */
#define PBUF_FLAG_RAM 0x00U /* Flags that pbuf data is stored in RAM */
#define PBUF_FLAG_ROM 0x01U /* Flags that pbuf data is stored in ROM */
#define PBUF_FLAG_POOL 0x02U /* Flags that the pbuf comes from the pbuf pool */
#define PBUF_FLAG_REF 0x04U /* Flags thet the pbuf payload refers to RAM */
/** indicates this packet was broadcast on the link */
#define PBUF_FLAG_LINK_BROADCAST 0x80U
struct pbuf {
/** next pbuf in singly linked pbuf chain */
struct pbuf *next;
/** pointer to the actual data in the buffer */
void *payload;
/**
* total length of this buffer and all next buffers in chain
* belonging to the same packet.
*
* For non-queue packet chains this is the invariant:
* p->tot_len == p->len + (p->next? p->next->tot_len: 0)
*/
u16_t tot_len;
/** length of this buffer */
u16_t len;
/** flags telling the type of pbuf, see PBUF_FLAG_ */
u16_t flags;
/**
* the reference count always equals the number of pointers
* that refer to this pbuf. This can be pointers from an application,
* the stack itself, or pbuf->next pointers from a chain.
*/
u16_t ref;
};
void pbuf_init(void);
struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag);
void pbuf_realloc(struct pbuf *p, u16_t size);
u8_t pbuf_header(struct pbuf *p, s16_t header_size);
void pbuf_ref(struct pbuf *p);
void pbuf_ref_chain(struct pbuf *p);
u8_t pbuf_free(struct pbuf *p);
u8_t pbuf_clen(struct pbuf *p);
void pbuf_cat(struct pbuf *h, struct pbuf *t);
void pbuf_chain(struct pbuf *h, struct pbuf *t);
struct pbuf *pbuf_take(struct pbuf *f);
struct pbuf *pbuf_dechain(struct pbuf *p);
void pbuf_queue(struct pbuf *p, struct pbuf *n);
struct pbuf * pbuf_dequeue(struct pbuf *p);
#endif /* __LWIP_PBUF_H__ */

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_RAW_H__
#define __LWIP_RAW_H__
#include "lwip/arch.h"
#include "lwip/pbuf.h"
#include "lwip/inet.h"
#include "lwip/ip.h"
struct raw_pcb {
/* Common members of all PCB types */
IP_PCB;
struct raw_pcb *next;
u16_t protocol;
u8_t (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
struct ip_addr *addr);
void *recv_arg;
};
/* The following functions is the application layer interface to the
RAW code. */
struct raw_pcb * raw_new (u16_t proto);
void raw_remove (struct raw_pcb *pcb);
err_t raw_bind (struct raw_pcb *pcb, struct ip_addr *ipaddr);
err_t raw_connect (struct raw_pcb *pcb, struct ip_addr *ipaddr);
void raw_recv (struct raw_pcb *pcb,
u8_t (* recv)(void *arg, struct raw_pcb *pcb,
struct pbuf *p,
struct ip_addr *addr),
void *recv_arg);
err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr);
err_t raw_send (struct raw_pcb *pcb, struct pbuf *p);
/* The following functions are the lower layer interface to RAW. */
u8_t raw_input (struct pbuf *p, struct netif *inp);
void raw_init (void);
#endif /* __LWIP_RAW_H__ */

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*/
/*
* This is the interface to the platform specific serial IO module
* It needs to be implemented by those platforms which need SLIP or PPP
*/
#include "arch/cc.h"
#ifndef __sio_fd_t_defined
typedef void * sio_fd_t;
#endif
#ifndef sio_open
sio_fd_t sio_open(u8_t);
#endif
#ifndef sio_send
void sio_send(u8_t, sio_fd_t);
#endif
#ifndef sio_recv
u8_t sio_recv(sio_fd_t);
#endif
#ifndef sio_read
u32_t sio_read(sio_fd_t, u8_t *, u32_t);
#endif
#ifndef sio_write
u32_t sio_write(sio_fd_t, u8_t *, u32_t);
#endif
#ifndef sio_read_abort
void sio_read_abort(sio_fd_t);
#endif

View file

@ -0,0 +1,178 @@
/*
* Copyright (c) 2001, 2002 Leon Woestenberg <leon.woestenberg@axon.tv>
* Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Leon Woestenberg <leon.woestenberg@axon.tv>
*
*/
#ifndef __LWIP_SNMP_H__
#define __LWIP_SNMP_H__
#include "lwip/opt.h"
/* SNMP support available? */
#if defined(LWIP_SNMP) && (LWIP_SNMP > 0)
/* network interface */
void snmp_add_ifinoctets(unsigned long value);
void snmp_inc_ifinucastpkts(void);
void snmp_inc_ifinnucastpkts(void);
void snmp_inc_ifindiscards(void);
void snmp_add_ifoutoctets(unsigned long value);
void snmp_inc_ifoutucastpkts(void);
void snmp_inc_ifoutnucastpkts(void);
void snmp_inc_ifoutdiscards(void);
/* IP */
void snmp_inc_ipinreceives(void);
void snmp_inc_ipindelivers(void);
void snmp_inc_ipindiscards(void);
void snmp_inc_ipoutdiscards(void);
void snmp_inc_ipoutrequests(void);
void snmp_inc_ipunknownprotos(void);
void snmp_inc_ipnoroutes(void);
void snmp_inc_ipforwdatagrams(void);
/* ICMP */
void snmp_inc_icmpinmsgs(void);
void snmp_inc_icmpinerrors(void);
void snmp_inc_icmpindestunreachs(void);
void snmp_inc_icmpintimeexcds(void);
void snmp_inc_icmpinparmprobs(void);
void snmp_inc_icmpinsrcquenchs(void);
void snmp_inc_icmpinredirects(void);
void snmp_inc_icmpinechos(void);
void snmp_inc_icmpinechoreps(void);
void snmp_inc_icmpintimestamps(void);
void snmp_inc_icmpintimestampreps(void);
void snmp_inc_icmpinaddrmasks(void);
void snmp_inc_icmpinaddrmaskreps(void);
void snmp_inc_icmpoutmsgs(void);
void snmp_inc_icmpouterrors(void);
void snmp_inc_icmpoutdestunreachs(void);
void snmp_inc_icmpouttimeexcds(void);
void snmp_inc_icmpoutparmprobs(void);
void snmp_inc_icmpoutsrcquenchs(void);
void snmp_inc_icmpoutredirects(void);
void snmp_inc_icmpoutechos(void);
void snmp_inc_icmpoutechoreps(void);
void snmp_inc_icmpouttimestamps(void);
void snmp_inc_icmpouttimestampreps(void);
void snmp_inc_icmpoutaddrmasks(void);
void snmp_inc_icmpoutaddrmaskreps(void);
/* TCP */
void snmp_inc_tcpactiveopens(void);
void snmp_inc_tcppassiveopens(void);
void snmp_inc_tcpattemptfails(void);
void snmp_inc_tcpestabresets(void);
void snmp_inc_tcpcurrestab(void);
void snmp_inc_tcpinsegs(void);
void snmp_inc_tcpoutsegs(void);
void snmp_inc_tcpretranssegs(void);
void snmp_inc_tcpinerrs(void);
void snmp_inc_tcpoutrsts(void);
/* UDP */
void snmp_inc_udpindatagrams(void);
void snmp_inc_udpnoports(void);
void snmp_inc_udpinerrors(void);
void snmp_inc_udpoutdatagrams(void);
/* LWIP_SNMP support not available */
/* define everything to be empty */
#else
/* network interface */
#define snmp_add_ifinoctets(value)
#define snmp_inc_ifinucastpkts()
#define snmp_inc_ifinnucastpkts()
#define snmp_inc_ifindiscards()
#define snmp_add_ifoutoctets(value)
#define snmp_inc_ifoutucastpkts()
#define snmp_inc_ifoutnucastpkts()
#define snmp_inc_ifoutdiscards()
/* IP */
#define snmp_inc_ipinreceives()
#define snmp_inc_ipindelivers()
#define snmp_inc_ipindiscards()
#define snmp_inc_ipoutdiscards()
#define snmp_inc_ipoutrequests()
#define snmp_inc_ipunknownprotos()
#define snmp_inc_ipnoroutes()
#define snmp_inc_ipforwdatagrams()
/* ICMP */
#define snmp_inc_icmpinmsgs()
#define snmp_inc_icmpinerrors()
#define snmp_inc_icmpindestunreachs()
#define snmp_inc_icmpintimeexcds()
#define snmp_inc_icmpinparmprobs()
#define snmp_inc_icmpinsrcquenchs()
#define snmp_inc_icmpinredirects()
#define snmp_inc_icmpinechos()
#define snmp_inc_icmpinechoreps()
#define snmp_inc_icmpintimestamps()
#define snmp_inc_icmpintimestampreps()
#define snmp_inc_icmpinaddrmasks()
#define snmp_inc_icmpinaddrmaskreps()
#define snmp_inc_icmpoutmsgs()
#define snmp_inc_icmpouterrors()
#define snmp_inc_icmpoutdestunreachs()
#define snmp_inc_icmpouttimeexcds()
#define snmp_inc_icmpoutparmprobs()
#define snmp_inc_icmpoutsrcquenchs()
#define snmp_inc_icmpoutredirects()
#define snmp_inc_icmpoutechos()
#define snmp_inc_icmpoutechoreps()
#define snmp_inc_icmpouttimestamps()
#define snmp_inc_icmpouttimestampreps()
#define snmp_inc_icmpoutaddrmasks()
#define snmp_inc_icmpoutaddrmaskreps()
/* TCP */
#define snmp_inc_tcpactiveopens()
#define snmp_inc_tcppassiveopens()
#define snmp_inc_tcpattemptfails()
#define snmp_inc_tcpestabresets()
#define snmp_inc_tcpcurrestab()
#define snmp_inc_tcpinsegs()
#define snmp_inc_tcpoutsegs()
#define snmp_inc_tcpretranssegs()
#define snmp_inc_tcpinerrs()
#define snmp_inc_tcpoutrsts()
/* UDP */
#define snmp_inc_udpindatagrams()
#define snmp_inc_udpnoports()
#define snmp_inc_udpinerrors()
#define snmp_inc_udpoutdatagrams()
#endif
#endif /* __LWIP_SNMP_H__ */

View file

@ -0,0 +1,271 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_SOCKETS_H__
#define __LWIP_SOCKETS_H__
#include "lwip/ip_addr.h"
struct sockaddr_in {
u8_t sin_len;
u8_t sin_family;
u16_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct sockaddr {
u8_t sa_len;
u8_t sa_family;
char sa_data[14];
};
#ifndef socklen_t
# define socklen_t int
#endif
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define SOCK_RAW 3
/*
* Option flags per-socket.
*/
#define SO_DEBUG 0x0001 /* turn on debugging info recording */
#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
#define SO_REUSEADDR 0x0004 /* allow local address reuse */
#define SO_KEEPALIVE 0x0008 /* keep connections alive */
#define SO_DONTROUTE 0x0010 /* just use interface addresses */
#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
#define SO_LINGER 0x0080 /* linger on close if data present */
#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
#define SO_REUSEPORT 0x0200 /* allow local address & port reuse */
#define SO_DONTLINGER (int)(~SO_LINGER)
/*
* Additional options, not kept in so_options.
*/
#define SO_SNDBUF 0x1001 /* send buffer size */
#define SO_RCVBUF 0x1002 /* receive buffer size */
#define SO_SNDLOWAT 0x1003 /* send low-water mark */
#define SO_RCVLOWAT 0x1004 /* receive low-water mark */
#define SO_SNDTIMEO 0x1005 /* send timeout */
#define SO_RCVTIMEO 0x1006 /* receive timeout */
#define SO_ERROR 0x1007 /* get error status and clear */
#define SO_TYPE 0x1008 /* get socket type */
/*
* Structure used for manipulating linger option.
*/
struct linger {
int l_onoff; /* option on/off */
int l_linger; /* linger time */
};
/*
* Level number for (get/set)sockopt() to apply to socket itself.
*/
#define SOL_SOCKET 0xfff /* options for socket level */
#define AF_UNSPEC 0
#define AF_INET 2
#define PF_INET AF_INET
#define PF_UNSPEC AF_UNSPEC
#define IPPROTO_IP 0
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17
#define INADDR_ANY 0
#define INADDR_BROADCAST 0xffffffff
/* Flags we can use with send and recv. */
#define MSG_DONTWAIT 0x40 /* Nonblocking i/o for this operation only */
/*
* Options for level IPPROTO_IP
*/
#define IP_TOS 1
#define IP_TTL 2
#define IPTOS_TOS_MASK 0x1E
#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK)
#define IPTOS_LOWDELAY 0x10
#define IPTOS_THROUGHPUT 0x08
#define IPTOS_RELIABILITY 0x04
#define IPTOS_LOWCOST 0x02
#define IPTOS_MINCOST IPTOS_LOWCOST
/*
* Definitions for IP precedence (also in ip_tos) (hopefully unused)
*/
#define IPTOS_PREC_MASK 0xe0
#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK)
#define IPTOS_PREC_NETCONTROL 0xe0
#define IPTOS_PREC_INTERNETCONTROL 0xc0
#define IPTOS_PREC_CRITIC_ECP 0xa0
#define IPTOS_PREC_FLASHOVERRIDE 0x80
#define IPTOS_PREC_FLASH 0x60
#define IPTOS_PREC_IMMEDIATE 0x40
#define IPTOS_PREC_PRIORITY 0x20
#define IPTOS_PREC_ROUTINE 0x00
/*
* Commands for ioctlsocket(), taken from the BSD file fcntl.h.
*
*
* Ioctl's have the command encoded in the lower word,
* and the size of any in or out parameters in the upper
* word. The high 2 bits of the upper word are used
* to encode the in/out status of the parameter; for now
* we restrict parameters to at most 128 bytes.
*/
#if !defined(FIONREAD) || !defined(FIONBIO)
#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */
#define IOC_VOID 0x20000000 /* no parameters */
#define IOC_OUT 0x40000000 /* copy out parameters */
#define IOC_IN 0x80000000 /* copy in parameters */
#define IOC_INOUT (IOC_IN|IOC_OUT)
/* 0x20000000 distinguishes new &
old ioctl's */
#define _IO(x,y) (IOC_VOID|((x)<<8)|(y))
#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
#endif
#ifndef FIONREAD
#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */
#endif
#ifndef FIONBIO
#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */
#endif
/* Socket I/O Controls */
#ifndef SIOCSHIWAT
#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */
#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */
#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */
#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */
#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */
#endif
#ifndef O_NONBLOCK
#define O_NONBLOCK 04000U
#endif
#ifndef FD_SET
#undef FD_SETSIZE
#define FD_SETSIZE 16
#define FD_SET(n, p) ((p)->fd_bits[(n)/8] |= (1 << ((n) & 7)))
#define FD_CLR(n, p) ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7)))
#define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] & (1 << ((n) & 7)))
#define FD_ZERO(p) memset((void*)(p),0,sizeof(*(p)))
typedef struct fd_set {
unsigned char fd_bits [(FD_SETSIZE+7)/8];
} fd_set;
/*
* only define this in sockets.c so it does not interfere
* with other projects namespaces where timeval is present
*/
#ifndef LWIP_TIMEVAL_PRIVATE
#define LWIP_TIMEVAL_PRIVATE 1
#endif
#if LWIP_TIMEVAL_PRIVATE
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */
};
#endif
#endif
int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
int lwip_bind(int s, struct sockaddr *name, socklen_t namelen);
int lwip_shutdown(int s, int how);
int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen);
int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen);
int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen);
int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen);
int lwip_close(int s);
int lwip_connect(int s, struct sockaddr *name, socklen_t namelen);
int lwip_listen(int s, int backlog);
int lwip_recv(int s, void *mem, int len, unsigned int flags);
int lwip_read(int s, void *mem, int len);
int lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
struct sockaddr *from, socklen_t *fromlen);
int lwip_send(int s, void *dataptr, int size, unsigned int flags);
int lwip_sendto(int s, void *dataptr, int size, unsigned int flags,
struct sockaddr *to, socklen_t tolen);
int lwip_socket(int domain, int type, int protocol);
int lwip_write(int s, void *dataptr, int size);
int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
struct timeval *timeout);
int lwip_ioctl(int s, long cmd, void *argp);
#if LWIP_COMPAT_SOCKETS
#define accept(a,b,c) lwip_accept(a,b,c)
#define bind(a,b,c) lwip_bind(a,b,c)
#define shutdown(a,b) lwip_shutdown(a,b)
#define close(s) lwip_close(s)
#define connect(a,b,c) lwip_connect(a,b,c)
#define getsockname(a,b,c) lwip_getsockname(a,b,c)
#define getpeername(a,b,c) lwip_getpeername(a,b,c)
#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e)
#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e)
#define listen(a,b) lwip_listen(a,b)
#define recv(a,b,c,d) lwip_recv(a,b,c,d)
#define read(a,b,c) lwip_read(a,b,c)
#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f)
#define send(a,b,c,d) lwip_send(a,b,c,d)
#define sendto(a,b,c,d,e,f) lwip_sendto(a,b,c,d,e,f)
#define socket(a,b,c) lwip_socket(a,b,c)
#define write(a,b,c) lwip_write(a,b,c)
#define select(a,b,c,d,e) lwip_select(a,b,c,d,e)
#define ioctlsocket(a,b,c) lwip_ioctl(a,b,c)
#endif /* LWIP_COMPAT_SOCKETS */
#endif /* __LWIP_SOCKETS_H__ */

View file

@ -0,0 +1,158 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_STATS_H__
#define __LWIP_STATS_H__
#include "lwip/opt.h"
#include "arch/cc.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#if LWIP_STATS
struct stats_proto {
u16_t xmit; /* Transmitted packets. */
u16_t rexmit; /* Retransmitted packets. */
u16_t recv; /* Received packets. */
u16_t fw; /* Forwarded packets. */
u16_t drop; /* Dropped packets. */
u16_t chkerr; /* Checksum error. */
u16_t lenerr; /* Invalid length error. */
u16_t memerr; /* Out of memory error. */
u16_t rterr; /* Routing error. */
u16_t proterr; /* Protocol error. */
u16_t opterr; /* Error in options. */
u16_t err; /* Misc error. */
u16_t cachehit;
};
struct stats_mem {
mem_size_t avail;
mem_size_t used;
mem_size_t max;
mem_size_t err;
};
struct stats_pbuf {
u16_t avail;
u16_t used;
u16_t max;
u16_t err;
u16_t alloc_locked;
u16_t refresh_locked;
};
struct stats_syselem {
u16_t used;
u16_t max;
u16_t err;
};
struct stats_sys {
struct stats_syselem sem;
struct stats_syselem mbox;
};
struct stats_ {
struct stats_proto link;
struct stats_proto ip_frag;
struct stats_proto ip;
struct stats_proto icmp;
struct stats_proto udp;
struct stats_proto tcp;
struct stats_pbuf pbuf;
struct stats_mem mem;
struct stats_mem memp[MEMP_MAX];
struct stats_sys sys;
};
extern struct stats_ lwip_stats;
void stats_init(void);
#define STATS_INC(x) ++lwip_stats.x
#else
#define stats_init()
#define STATS_INC(x)
#endif /* LWIP_STATS */
#if TCP_STATS
#define TCP_STATS_INC(x) STATS_INC(x)
#else
#define TCP_STATS_INC(x)
#endif
#if UDP_STATS
#define UDP_STATS_INC(x) STATS_INC(x)
#else
#define UDP_STATS_INC(x)
#endif
#if ICMP_STATS
#define ICMP_STATS_INC(x) STATS_INC(x)
#else
#define ICMP_STATS_INC(x)
#endif
#if IP_STATS
#define IP_STATS_INC(x) STATS_INC(x)
#else
#define IP_STATS_INC(x)
#endif
#if IPFRAG_STATS
#define IPFRAG_STATS_INC(x) STATS_INC(x)
#else
#define IPFRAG_STATS_INC(x)
#endif
#if LINK_STATS
#define LINK_STATS_INC(x) STATS_INC(x)
#else
#define LINK_STATS_INC(x)
#endif
/* Display of statistics */
#if LWIP_STATS_DISPLAY
void stats_display(void);
#else
#define stats_display()
#endif
#endif /* __LWIP_STATS_H__ */

View file

@ -0,0 +1,183 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_SYS_H__
#define __LWIP_SYS_H__
#include "arch/cc.h"
#include "lwip/opt.h"
#if NO_SYS
/* For a totally minimal and standalone system, we provide null
definitions of the sys_ functions. */
typedef u8_t sys_sem_t;
typedef u8_t sys_mbox_t;
struct sys_timeout {u8_t dummy;};
#define sys_init()
#define sys_timeout(m,h,a)
#define sys_untimeout(m,a)
#define sys_sem_new(c) c
#define sys_sem_signal(s)
#define sys_sem_wait(s)
#define sys_sem_free(s)
#define sys_mbox_new() 0
#define sys_mbox_fetch(m,d)
#define sys_mbox_post(m,d)
#define sys_mbox_free(m)
#define sys_thread_new(t,a,p)
#else /* NO_SYS */
#include "arch/sys_arch.h"
/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */
#define SYS_ARCH_TIMEOUT 0xffffffff
typedef void (* sys_timeout_handler)(void *arg);
struct sys_timeout {
struct sys_timeout *next;
u32_t time;
sys_timeout_handler h;
void *arg;
};
struct sys_timeouts {
struct sys_timeout *next;
};
/* sys_init() must be called before anthing else. */
void sys_init(void);
/*
* sys_timeout():
*
* Schedule a timeout a specified amount of milliseconds in the
* future. When the timeout occurs, the specified timeout handler will
* be called. The handler will be passed the "arg" argument when
* called.
*
*/
void sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg);
void sys_untimeout(sys_timeout_handler h, void *arg);
struct sys_timeouts *sys_arch_timeouts(void);
/* Semaphore functions. */
sys_sem_t sys_sem_new(u8_t count);
void sys_sem_signal(sys_sem_t sem);
u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout);
void sys_sem_free(sys_sem_t sem);
void sys_sem_wait(sys_sem_t sem);
int sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout);
/* Time functions. */
#ifndef sys_msleep
void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */
#endif
#ifndef sys_jiffies
u32_t sys_jiffies(void); /* since power up. */
#endif
/* Mailbox functions. */
sys_mbox_t sys_mbox_new(void);
void sys_mbox_post(sys_mbox_t mbox, void *msg);
u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout);
void sys_mbox_free(sys_mbox_t mbox);
void sys_mbox_fetch(sys_mbox_t mbox, void **msg);
/* Thread functions. */
sys_thread_t sys_thread_new(void (* thread)(void *arg), void *arg, int prio);
/* The following functions are used only in Unix code, and
can be omitted when porting the stack. */
/* Returns the current time in microseconds. */
unsigned long sys_now(void);
#endif /* NO_SYS */
/* Critical Region Protection */
/* These functions must be implemented in the sys_arch.c file.
In some implementations they can provide a more light-weight protection
mechanism than using semaphores. Otherwise semaphores can be used for
implementation */
#ifndef SYS_ARCH_PROTECT
/** SYS_LIGHTWEIGHT_PROT
* define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection
* for certain critical regions during buffer allocation, deallocation and memory
* allocation and deallocation.
*/
#if SYS_LIGHTWEIGHT_PROT
/** SYS_ARCH_DECL_PROTECT
* declare a protection variable. This macro will default to defining a variable of
* type sys_prot_t. If a particular port needs a different implementation, then
* this macro may be defined in sys_arch.h.
*/
#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev
/** SYS_ARCH_PROTECT
* Perform a "fast" protect. This could be implemented by
* disabling interrupts for an embedded system or by using a semaphore or
* mutex. The implementation should allow calling SYS_ARCH_PROTECT when
* already protected. The old protection level is returned in the variable
* "lev". This macro will default to calling the sys_arch_protect() function
* which should be implemented in sys_arch.c. If a particular port needs a
* different implementation, then this macro may be defined in sys_arch.h
*/
#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect()
/** SYS_ARCH_UNPROTECT
* Perform a "fast" set of the protection level to "lev". This could be
* implemented by setting the interrupt level to "lev" within the MACRO or by
* using a semaphore or mutex. This macro will default to calling the
* sys_arch_unprotect() function which should be implemented in
* sys_arch.c. If a particular port needs a different implementation, then
* this macro may be defined in sys_arch.h
*/
#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev)
sys_prot_t sys_arch_protect(void);
void sys_arch_unprotect(sys_prot_t pval);
#else
#define SYS_ARCH_DECL_PROTECT(lev)
#define SYS_ARCH_PROTECT(lev)
#define SYS_ARCH_UNPROTECT(lev)
#endif /* SYS_LIGHTWEIGHT_PROT */
#endif /* SYS_ARCH_PROTECT */
#endif /* __LWIP_SYS_H__ */

View file

@ -0,0 +1,531 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_TCP_H__
#define __LWIP_TCP_H__
#include "lwip/sys.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/opt.h"
#include "lwip/ip.h"
#include "lwip/icmp.h"
#include "lwip/err.h"
struct tcp_pcb;
/* Functions for interfacing with TCP: */
/* Lower layer interface to TCP: */
void tcp_init (void); /* Must be called first to
initialize TCP. */
void tcp_tmr (void); /* Must be called every
TCP_TMR_INTERVAL
ms. (Typically 250 ms). */
/* Application program's interface: */
struct tcp_pcb * tcp_new (void);
struct tcp_pcb * tcp_alloc (u8_t prio);
void tcp_arg (struct tcp_pcb *pcb, void *arg);
void tcp_accept (struct tcp_pcb *pcb,
err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
err_t err));
void tcp_recv (struct tcp_pcb *pcb,
err_t (* recv)(void *arg, struct tcp_pcb *tpcb,
struct pbuf *p, err_t err));
void tcp_sent (struct tcp_pcb *pcb,
err_t (* sent)(void *arg, struct tcp_pcb *tpcb,
u16_t len));
void tcp_poll (struct tcp_pcb *pcb,
err_t (* poll)(void *arg, struct tcp_pcb *tpcb),
u8_t interval);
void tcp_err (struct tcp_pcb *pcb,
void (* err)(void *arg, err_t err));
#define tcp_mss(pcb) ((pcb)->mss)
#define tcp_sndbuf(pcb) ((pcb)->snd_buf)
void tcp_recved (struct tcp_pcb *pcb, u16_t len);
err_t tcp_bind (struct tcp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port);
err_t tcp_connect (struct tcp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port, err_t (* connected)(void *arg,
struct tcp_pcb *tpcb,
err_t err));
struct tcp_pcb * tcp_listen (struct tcp_pcb *pcb);
void tcp_abort (struct tcp_pcb *pcb);
err_t tcp_close (struct tcp_pcb *pcb);
err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len,
u8_t copy);
void tcp_setprio (struct tcp_pcb *pcb, u8_t prio);
#define TCP_PRIO_MIN 1
#define TCP_PRIO_NORMAL 64
#define TCP_PRIO_MAX 127
/* It is also possible to call these two functions at the right
intervals (instead of calling tcp_tmr()). */
void tcp_slowtmr (void);
void tcp_fasttmr (void);
/* Only used by IP to pass a TCP segment to TCP: */
void tcp_input (struct pbuf *p, struct netif *inp);
/* Used within the TCP code only: */
err_t tcp_output (struct tcp_pcb *pcb);
void tcp_rexmit (struct tcp_pcb *pcb);
void tcp_rexmit_rto (struct tcp_pcb *pcb);
#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0)
#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0)
#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0)
#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0)
/* is b<=a<=c? */
#if 0 /* see bug #10548 */
#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b))
#endif
#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c))
#define TCP_FIN 0x01U
#define TCP_SYN 0x02U
#define TCP_RST 0x04U
#define TCP_PSH 0x08U
#define TCP_ACK 0x10U
#define TCP_URG 0x20U
#define TCP_ECE 0x40U
#define TCP_CWR 0x80U
#define TCP_FLAGS 0x3fU
/* Length of the TCP header, excluding options. */
#define TCP_HLEN 20
#ifndef TCP_TMR_INTERVAL
#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in
milliseconds. */
#endif /* TCP_TMR_INTERVAL */
#ifndef TCP_FAST_INTERVAL
#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in
milliseconds */
#endif /* TCP_FAST_INTERVAL */
#ifndef TCP_SLOW_INTERVAL
#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in
milliseconds */
#endif /* TCP_SLOW_INTERVAL */
#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */
#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */
#define TCP_OOSEQ_TIMEOUT 6 /* x RTO */
#define TCP_MSL 60000 /* The maximum segment lifetime in microseconds */
/*
* User-settable options (used with setsockopt).
*/
#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keepalive miliseconds */
/* Keepalive values */
#define TCP_KEEPDEFAULT 7200000 /* KEEPALIVE timer in miliseconds */
#define TCP_KEEPINTVL 75000 /* Time between KEEPALIVE probes in miliseconds */
#define TCP_KEEPCNT 9 /* Counter for KEEPALIVE probes */
#define TCP_MAXIDLE TCP_KEEPCNT * TCP_KEEPINTVL /* Maximum KEEPALIVE probe time */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct tcp_hdr {
PACK_STRUCT_FIELD(u16_t src);
PACK_STRUCT_FIELD(u16_t dest);
PACK_STRUCT_FIELD(u32_t seqno);
PACK_STRUCT_FIELD(u32_t ackno);
PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);
PACK_STRUCT_FIELD(u16_t wnd);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u16_t urgp);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8)
#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)
#define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS)
#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr))
#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr))
#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons((ntohs((phdr)->_hdrlen_rsvd_flags) & ~TCP_FLAGS) | (flags))
#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (flags))
#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) )
#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & TCP_FIN || \
TCPH_FLAGS((seg)->tcphdr) & TCP_SYN)? 1: 0))
enum tcp_state {
CLOSED = 0,
LISTEN = 1,
SYN_SENT = 2,
SYN_RCVD = 3,
ESTABLISHED = 4,
FIN_WAIT_1 = 5,
FIN_WAIT_2 = 6,
CLOSE_WAIT = 7,
CLOSING = 8,
LAST_ACK = 9,
TIME_WAIT = 10
};
/* the TCP protocol control block */
struct tcp_pcb {
/** common PCB members */
IP_PCB;
/** protocol specific PCB members */
struct tcp_pcb *next; /* for the linked list */
enum tcp_state state; /* TCP state */
u8_t prio;
void *callback_arg;
u16_t local_port;
u16_t remote_port;
u8_t flags;
#define TF_ACK_DELAY (u8_t)0x01U /* Delayed ACK. */
#define TF_ACK_NOW (u8_t)0x02U /* Immediate ACK. */
#define TF_INFR (u8_t)0x04U /* In fast recovery. */
#define TF_RESET (u8_t)0x08U /* Connection was reset. */
#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */
#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */
#define TF_NODELAY (u8_t)0x40U /* Disable Nagle algorithm */
/* receiver variables */
u32_t rcv_nxt; /* next seqno expected */
u16_t rcv_wnd; /* receiver window */
/* Timers */
u32_t tmr;
u8_t polltmr, pollinterval;
/* Retransmission timer. */
u16_t rtime;
u16_t mss; /* maximum segment size */
/* RTT (round trip time) estimation variables */
u32_t rttest; /* RTT estimate in 500ms ticks */
u32_t rtseq; /* sequence number being timed */
s16_t sa, sv; /* @todo document this */
u16_t rto; /* retransmission time-out */
u8_t nrtx; /* number of retransmissions */
/* fast retransmit/recovery */
u32_t lastack; /* Highest acknowledged seqno. */
u8_t dupacks;
/* congestion avoidance/control variables */
u16_t cwnd;
u16_t ssthresh;
/* sender variables */
u32_t snd_nxt, /* next seqno to be sent */
snd_max, /* Highest seqno sent. */
snd_wnd, /* sender window */
snd_wl1, snd_wl2, /* Sequence and acknowledgement numbers of last
window update. */
snd_lbb; /* Sequence number of next byte to be buffered. */
u16_t acked;
u16_t snd_buf; /* Available buffer space for sending (in bytes). */
u8_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */
/* These are ordered by sequence number: */
struct tcp_seg *unsent; /* Unsent (queued) segments. */
struct tcp_seg *unacked; /* Sent but unacknowledged segments. */
#if TCP_QUEUE_OOSEQ
struct tcp_seg *ooseq; /* Received out of sequence segments. */
#endif /* TCP_QUEUE_OOSEQ */
#if LWIP_CALLBACK_API
/* Function to be called when more send buffer space is available. */
err_t (* sent)(void *arg, struct tcp_pcb *pcb, u16_t space);
/* Function to be called when (in-sequence) data has arrived. */
err_t (* recv)(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
/* Function to be called when a connection has been set up. */
err_t (* connected)(void *arg, struct tcp_pcb *pcb, err_t err);
/* Function to call when a listener has been connected. */
err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err);
/* Function which is called periodically. */
err_t (* poll)(void *arg, struct tcp_pcb *pcb);
/* Function to be called whenever a fatal error occurs. */
void (* errf)(void *arg, err_t err);
#endif /* LWIP_CALLBACK_API */
/* idle time before KEEPALIVE is sent */
u32_t keepalive;
/* KEEPALIVE counter */
u8_t keep_cnt;
};
struct tcp_pcb_listen {
/* Common members of all PCB types */
IP_PCB;
/* Protocol specific PCB members */
struct tcp_pcb_listen *next; /* for the linked list */
/* Even if state is obviously LISTEN this is here for
* field compatibility with tpc_pcb to which it is cast sometimes
* Until a cleaner solution emerges this is here.FIXME
*/
enum tcp_state state; /* TCP state */
u8_t prio;
void *callback_arg;
u16_t local_port;
#if LWIP_CALLBACK_API
/* Function to call when a listener has been connected. */
err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err);
#endif /* LWIP_CALLBACK_API */
};
#if LWIP_EVENT_API
enum lwip_event {
LWIP_EVENT_ACCEPT,
LWIP_EVENT_SENT,
LWIP_EVENT_RECV,
LWIP_EVENT_CONNECTED,
LWIP_EVENT_POLL,
LWIP_EVENT_ERR
};
err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,
enum lwip_event,
struct pbuf *p,
u16_t size,
err_t err);
#define TCP_EVENT_ACCEPT(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_ACCEPT, NULL, 0, err)
#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_SENT, NULL, space, ERR_OK)
#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_RECV, (p), 0, (err))
#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_CONNECTED, NULL, 0, (err))
#define TCP_EVENT_POLL(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_POLL, NULL, 0, ERR_OK)
#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \
LWIP_EVENT_ERR, NULL, 0, (err))
#else /* LWIP_EVENT_API */
#define TCP_EVENT_ACCEPT(pcb,err,ret) \
if((pcb)->accept != NULL) \
(ret = (pcb)->accept((pcb)->callback_arg,(pcb),(err)))
#define TCP_EVENT_SENT(pcb,space,ret) \
if((pcb)->sent != NULL) \
(ret = (pcb)->sent((pcb)->callback_arg,(pcb),(space)))
#define TCP_EVENT_RECV(pcb,p,err,ret) \
if((pcb)->recv != NULL) \
{ ret = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); } else { \
if (p) pbuf_free(p); }
#define TCP_EVENT_CONNECTED(pcb,err,ret) \
if((pcb)->connected != NULL) \
(ret = (pcb)->connected((pcb)->callback_arg,(pcb),(err)))
#define TCP_EVENT_POLL(pcb,ret) \
if((pcb)->poll != NULL) \
(ret = (pcb)->poll((pcb)->callback_arg,(pcb)))
#define TCP_EVENT_ERR(errf,arg,err) \
if((errf) != NULL) \
(errf)((arg),(err))
#endif /* LWIP_EVENT_API */
/* This structure represents a TCP segment on the unsent and unacked queues */
struct tcp_seg {
struct tcp_seg *next; /* used when putting segements on a queue */
struct pbuf *p; /* buffer containing data + TCP header */
void *dataptr; /* pointer to the TCP data in the pbuf */
u16_t len; /* the TCP length of this segment */
struct tcp_hdr *tcphdr; /* the TCP header */
};
/* Internal functions and global variables: */
struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb);
void tcp_pcb_purge(struct tcp_pcb *pcb);
void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb);
u8_t tcp_segs_free(struct tcp_seg *seg);
u8_t tcp_seg_free(struct tcp_seg *seg);
struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg);
#define tcp_ack(pcb) if((pcb)->flags & TF_ACK_DELAY) { \
(pcb)->flags &= ~TF_ACK_DELAY; \
(pcb)->flags |= TF_ACK_NOW; \
tcp_output(pcb); \
} else { \
(pcb)->flags |= TF_ACK_DELAY; \
}
#define tcp_ack_now(pcb) (pcb)->flags |= TF_ACK_NOW; \
tcp_output(pcb)
err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags);
err_t tcp_enqueue(struct tcp_pcb *pcb, void *dataptr, u16_t len,
u8_t flags, u8_t copy,
u8_t *optdata, u8_t optlen);
void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg);
void tcp_rst(u32_t seqno, u32_t ackno,
struct ip_addr *local_ip, struct ip_addr *remote_ip,
u16_t local_port, u16_t remote_port);
u32_t tcp_next_iss(void);
void tcp_keepalive(struct tcp_pcb *pcb);
extern struct tcp_pcb *tcp_input_pcb;
extern u32_t tcp_ticks;
#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
void tcp_debug_print(struct tcp_hdr *tcphdr);
void tcp_debug_print_flags(u8_t flags);
void tcp_debug_print_state(enum tcp_state s);
void tcp_debug_print_pcbs(void);
int tcp_pcbs_sane(void);
#else
# define tcp_debug_print(tcphdr)
# define tcp_debug_print_flags(flags)
# define tcp_debug_print_state(s)
# define tcp_debug_print_pcbs()
# define tcp_pcbs_sane() 1
#endif /* TCP_DEBUG */
#if NO_SYS
#define tcp_timer_needed()
#else
void tcp_timer_needed(void);
#endif
/* The TCP PCB lists. */
union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */
struct tcp_pcb_listen *listen_pcbs;
struct tcp_pcb *pcbs;
};
extern union tcp_listen_pcbs_t tcp_listen_pcbs;
extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a
state in which they accept or send
data. */
extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */
extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */
/* Axioms about the above lists:
1) Every TCP PCB that is not CLOSED is in one of the lists.
2) A PCB is only in one of the lists.
3) All PCBs in the tcp_listen_pcbs list is in LISTEN state.
4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state.
*/
/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB
with a PCB list or removes a PCB from a list, respectively. */
#if 0
#define TCP_REG(pcbs, npcb) do {\
LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", npcb, npcb->local_port)); \
for(tcp_tmp_pcb = *pcbs; \
tcp_tmp_pcb != NULL; \
tcp_tmp_pcb = tcp_tmp_pcb->next) { \
LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != npcb); \
} \
LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", npcb->state != CLOSED); \
npcb->next = *pcbs; \
LWIP_ASSERT("TCP_REG: npcb->next != npcb", npcb->next != npcb); \
*(pcbs) = npcb; \
LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \
tcp_timer_needed(); \
} while(0)
#define TCP_RMV(pcbs, npcb) do { \
LWIP_ASSERT("TCP_RMV: pcbs != NULL", *pcbs != NULL); \
LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", npcb, *pcbs)); \
if(*pcbs == npcb) { \
*pcbs = (*pcbs)->next; \
} else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \
if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \
tcp_tmp_pcb->next = npcb->next; \
break; \
} \
} \
npcb->next = NULL; \
LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \
LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", npcb, *pcbs)); \
} while(0)
#else /* LWIP_DEBUG */
#define TCP_REG(pcbs, npcb) do { \
npcb->next = *pcbs; \
*(pcbs) = npcb; \
tcp_timer_needed(); \
} while(0)
#define TCP_RMV(pcbs, npcb) do { \
if(*(pcbs) == npcb) { \
(*(pcbs)) = (*pcbs)->next; \
} else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \
if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \
tcp_tmp_pcb->next = npcb->next; \
break; \
} \
} \
npcb->next = NULL; \
} while(0)
#endif /* LWIP_DEBUG */
#endif /* __LWIP_TCP_H__ */

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_TCPIP_H__
#define __LWIP_TCPIP_H__
#include "lwip/api_msg.h"
#include "lwip/pbuf.h"
void tcpip_init(void (* tcpip_init_done)(void *), void *arg);
void tcpip_apimsg(struct api_msg *apimsg);
err_t tcpip_input(struct pbuf *p, struct netif *inp);
err_t tcpip_callback(void (*f)(void *ctx), void *ctx);
void tcpip_tcp_timer_needed(void);
enum tcpip_msg_type {
TCPIP_MSG_API,
TCPIP_MSG_INPUT,
TCPIP_MSG_CALLBACK
};
struct tcpip_msg {
enum tcpip_msg_type type;
sys_sem_t *sem;
union {
struct api_msg *apimsg;
struct {
struct pbuf *p;
struct netif *netif;
} inp;
struct {
void (*f)(void *ctx);
void *ctx;
} cb;
} msg;
};
#endif /* __LWIP_TCPIP_H__ */

View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_UDP_H__
#define __LWIP_UDP_H__
#include "lwip/arch.h"
#include "lwip/pbuf.h"
#include "lwip/inet.h"
#include "lwip/ip.h"
#define UDP_HLEN 8
struct udp_hdr {
PACK_STRUCT_FIELD(u16_t src);
PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */
PACK_STRUCT_FIELD(u16_t len);
PACK_STRUCT_FIELD(u16_t chksum);
} PACK_STRUCT_STRUCT;
#define UDP_FLAGS_NOCHKSUM 0x01U
#define UDP_FLAGS_UDPLITE 0x02U
#define UDP_FLAGS_CONNECTED 0x04U
struct udp_pcb {
/* Common members of all PCB types */
IP_PCB;
/* Protocol specific PCB members */
struct udp_pcb *next;
u8_t flags;
u16_t local_port, remote_port;
u16_t chksum_len;
void (* recv)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
struct ip_addr *addr, u16_t port);
void *recv_arg;
};
/* The following functions is the application layer interface to the
UDP code. */
struct udp_pcb * udp_new (void);
void udp_remove (struct udp_pcb *pcb);
err_t udp_bind (struct udp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port);
err_t udp_connect (struct udp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port);
void udp_disconnect (struct udp_pcb *pcb);
void udp_recv (struct udp_pcb *pcb,
void (* recv)(void *arg, struct udp_pcb *upcb,
struct pbuf *p,
struct ip_addr *addr,
u16_t port),
void *recv_arg);
err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port);
err_t udp_send (struct udp_pcb *pcb, struct pbuf *p);
#define udp_flags(pcb) ((pcb)->flags)
#define udp_setflags(pcb, f) ((pcb)->flags = (f))
/* The following functions are the lower layer interface to UDP. */
void udp_input (struct pbuf *p, struct netif *inp);
void udp_init (void);
#if UDP_DEBUG
int udp_debug_print(struct udp_hdr *udphdr);
#else
#define udp_debug_print(udphdr)
#endif
#endif /* __LWIP_UDP_H__ */

View file

@ -0,0 +1,126 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
* Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __NETIF_ETHARP_H__
#define __NETIF_ETHARP_H__
#ifndef ETH_PAD_SIZE
#define ETH_PAD_SIZE 0
#endif
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/ip.h"
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct eth_addr {
PACK_STRUCT_FIELD(u8_t addr[6]);
} 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 eth_hdr {
#if ETH_PAD_SIZE
PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
#endif
PACK_STRUCT_FIELD(struct eth_addr dest);
PACK_STRUCT_FIELD(struct eth_addr src);
PACK_STRUCT_FIELD(u16_t type);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** the ARP message */
struct etharp_hdr {
PACK_STRUCT_FIELD(struct eth_hdr ethhdr);
PACK_STRUCT_FIELD(u16_t hwtype);
PACK_STRUCT_FIELD(u16_t proto);
PACK_STRUCT_FIELD(u16_t _hwlen_protolen);
PACK_STRUCT_FIELD(u16_t opcode);
PACK_STRUCT_FIELD(struct eth_addr shwaddr);
PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);
PACK_STRUCT_FIELD(struct eth_addr dhwaddr);
PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ethip_hdr {
PACK_STRUCT_FIELD(struct eth_hdr eth);
PACK_STRUCT_FIELD(struct ip_hdr ip);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** 5 seconds period */
#define ARP_TMR_INTERVAL 5000
#define ETHTYPE_ARP 0x0806
#define ETHTYPE_IP 0x0800
void etharp_init(void);
void etharp_tmr(void);
void etharp_ip_input(struct netif *netif, struct pbuf *p);
void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr,
struct pbuf *p);
err_t etharp_output(struct netif *netif, struct ip_addr *ipaddr,
struct pbuf *q);
err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q);
err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr);
#endif /* __NETIF_ARP_H__ */

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __NETIF_LOOPIF_H__
#define __NETIF_LOOPIF_H__
#include "lwip/netif.h"
err_t loopif_init(struct netif *netif);
#endif /* __NETIF_LOOPIF_H__ */

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2001, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __NETIF_SLIPIF_H__
#define __NETIF_SLIPIF_H__
#include "lwip/netif.h"
err_t slipif_init(struct netif * netif);
#endif

View file

@ -0,0 +1,27 @@
This directory contains generic network interface device drivers that
do not contain any hardware or architecture specific code. The files
are:
etharp.c
Implements the ARP (Address Resolution Protocol) over
Ethernet. The code in this file should be used together with
Ethernet device drivers. Note that this module has been
largely made Ethernet independent so you should be able to
adapt this for other link layers (such as Firewire).
ethernetif.c
An example of how an Ethernet device driver could look. This
file can be used as a "skeleton" for developing new Ethernet
network device drivers. It uses the etharp.c ARP code.
loopif.c
An example network interface that shows how a "loopback"
interface would work. This is not really intended for actual
use, but as a very basic example of how initialization and
output functions work.
slipif.c
A generic implementation of the SLIP (Serial Line IP)
protocol. It requires a sio (serial I/O) module to work.
ppp/ Point-to-Point Protocol stack

View file

@ -0,0 +1,828 @@
/**
* @file
* Address Resolution Protocol module for IP over Ethernet
*
* Functionally, ARP is divided into two parts. The first maps an IP address
* to a physical address when sending a packet, and the second part answers
* requests from other machines for our physical address.
*
* This implementation complies with RFC 826 (Ethernet ARP). It supports
* Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6
* if an interface calls etharp_query(our_netif, its_ip_addr, NULL) upon
* address change.
*/
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
* Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include "lwip/opt.h"
#include "lwip/inet.h"
#include "netif/etharp.h"
#include "lwip/ip.h"
#include "lwip/stats.h"
/* ARP needs to inform DHCP of any ARP replies? */
#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
# include "lwip/dhcp.h"
#endif
/** the time an ARP entry stays valid after its last update,
* (240 * 5) seconds = 20 minutes.
*/
#define ARP_MAXAGE 240
/** the time an ARP entry stays pending after first request,
* (2 * 5) seconds = 10 seconds.
*
* @internal Keep this number at least 2, otherwise it might
* run out instantly if the timeout occurs directly after a request.
*/
#define ARP_MAXPENDING 2
#define HWTYPE_ETHERNET 1
/** ARP message types */
#define ARP_REQUEST 1
#define ARP_REPLY 2
#define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8)
#define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff)
#define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8))
#define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8))
enum etharp_state {
ETHARP_STATE_EMPTY,
ETHARP_STATE_PENDING,
ETHARP_STATE_STABLE,
/** @internal transitional state used in etharp_tmr() for convenience*/
ETHARP_STATE_EXPIRED
};
struct etharp_entry {
#if ARP_QUEUEING
/**
* Pointer to queue of pending outgoing packets on this ARP entry.
*/
struct pbuf *p;
#endif
struct ip_addr ipaddr;
struct eth_addr ethaddr;
enum etharp_state state;
u8_t ctime;
};
static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
static struct etharp_entry arp_table[ARP_TABLE_SIZE];
/**
* Try hard to create a new entry - we want the IP address to appear in
* the cache (even if this means removing an active entry or so). */
#define ETHARP_TRY_HARD 1
static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags);
static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);
/**
* Initializes ARP module.
*/
void
etharp_init(void)
{
u8_t i;
/* clear ARP entries */
for(i = 0; i < ARP_TABLE_SIZE; ++i) {
arp_table[i].state = ETHARP_STATE_EMPTY;
#if ARP_QUEUEING
arp_table[i].p = NULL;
#endif
arp_table[i].ctime = 0;
}
}
/**
* Clears expired entries in the ARP table.
*
* This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds),
* in order to expire entries in the ARP table.
*/
void
etharp_tmr(void)
{
u8_t i;
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
/* remove expired entries from the ARP table */
for (i = 0; i < ARP_TABLE_SIZE; ++i) {
arp_table[i].ctime++;
/* stable entry? */
if ((arp_table[i].state == ETHARP_STATE_STABLE) &&
/* entry has become old? */
(arp_table[i].ctime >= ARP_MAXAGE)) {
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %u.\n", i));
arp_table[i].state = ETHARP_STATE_EXPIRED;
/* pending entry? */
} else if (arp_table[i].state == ETHARP_STATE_PENDING) {
/* entry unresolved/pending for too long? */
if (arp_table[i].ctime >= ARP_MAXPENDING) {
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u.\n", i));
arp_table[i].state = ETHARP_STATE_EXPIRED;
#if ARP_QUEUEING
} else if (arp_table[i].p != NULL) {
/* resend an ARP query here */
#endif
}
}
/* clean up entries that have just been expired */
if (arp_table[i].state == ETHARP_STATE_EXPIRED) {
#if ARP_QUEUEING
/* and empty packet queue */
if (arp_table[i].p != NULL) {
/* remove all queued packets */
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %u, packet queue %p.\n", i, (void *)(arp_table[i].p)));
pbuf_free(arp_table[i].p);
arp_table[i].p = NULL;
}
#endif
/* recycle entry for re-use */
arp_table[i].state = ETHARP_STATE_EMPTY;
}
}
}
/**
* Search the ARP table for a matching or new entry.
*
* If an IP address is given, return a pending or stable ARP entry that matches
* the address. If no match is found, create a new entry with this address set,
* but in state ETHARP_EMPTY. The caller must check and possibly change the
* state of the returned entry.
*
* If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.
*
* In all cases, attempt to create new entries from an empty entry. If no
* empty entries are available and ETHARP_TRY_HARD flag is set, recycle
* old entries. Heuristic choose the least important entry for recycling.
*
* @param ipaddr IP address to find in ARP cache, or to add if not found.
* @param flags
* - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of
* active (stable or pending) entries.
*
* @return The ARP entry index that matched or is created, ERR_MEM if no
* entry is found or could be recycled.
*/
static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
{
s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
s8_t empty = ARP_TABLE_SIZE;
u8_t i = 0, age_pending = 0, age_stable = 0;
#if ARP_QUEUEING
/* oldest entry with packets on queue */
s8_t old_queue = ARP_TABLE_SIZE;
/* its age */
u8_t age_queue = 0;
#endif
/**
* a) do a search through the cache, remember candidates
* b) select candidate entry
* c) create new entry
*/
/* a) in a single search sweep, do all of this
* 1) remember the first empty entry (if any)
* 2) remember the oldest stable entry (if any)
* 3) remember the oldest pending entry without queued packets (if any)
* 4) remember the oldest pending entry with queued packets (if any)
* 5) search for a matching IP entry, either pending or stable
* until 5 matches, or all entries are searched for.
*/
for (i = 0; i < ARP_TABLE_SIZE; ++i) {
/* no empty entry found yet and now we do find one? */
if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_EMPTY)) {
LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %d\n", i));
/* remember first empty entry */
empty = i;
}
/* pending entry? */
else if (arp_table[i].state == ETHARP_STATE_PENDING) {
/* if given, does IP address match IP address in ARP entry? */
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching pending entry %d\n", i));
/* found exact IP address match, simply bail out */
return i;
#if ARP_QUEUEING
/* pending with queued packets? */
} else if (arp_table[i].p != NULL) {
if (arp_table[i].ctime >= age_queue) {
old_queue = i;
age_queue = arp_table[i].ctime;
}
#endif
/* pending without queued packets? */
} else {
if (arp_table[i].ctime >= age_pending) {
old_pending = i;
age_pending = arp_table[i].ctime;
}
}
}
/* stable entry? */
else if (arp_table[i].state == ETHARP_STATE_STABLE) {
/* if given, does IP address match IP address in ARP entry? */
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching stable entry %d\n", i));
/* found exact IP address match, simply bail out */
return i;
/* remember entry with oldest stable entry in oldest, its age in maxtime */
} else if (arp_table[i].ctime >= age_stable) {
old_stable = i;
age_stable = arp_table[i].ctime;
}
}
}
/* { we have no match } => try to create a new entry */
/* no empty entry found and not allowed to recycle? */
if ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0))
{
return (s8_t)ERR_MEM;
}
/* b) choose the least destructive entry to recycle:
* 1) empty entry
* 2) oldest stable entry
* 3) oldest pending entry without queued packets
* 4) oldest pending entry without queued packets
*
* { ETHARP_TRY_HARD is set at this point }
*/
/* 1) empty entry available? */
if (empty < ARP_TABLE_SIZE) {
i = empty;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting empty entry %d\n", i));
}
/* 2) found recyclable stable entry? */
else if (old_stable < ARP_TABLE_SIZE) {
/* recycle oldest stable*/
i = old_stable;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest stable entry %d\n", i));
#if ARP_QUEUEING
/* no queued packets should exist on stable entries */
LWIP_ASSERT("arp_table[i].p == NULL", arp_table[i].p == NULL);
#endif
/* 3) found recyclable pending entry without queued packets? */
} else if (old_pending < ARP_TABLE_SIZE) {
/* recycle oldest pending */
i = old_pending;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %d (without queue)\n", i));
#if ARP_QUEUEING
/* 4) found recyclable pending entry with queued packets? */
} else if (old_queue < ARP_TABLE_SIZE) {
/* recycle oldest pending */
i = old_queue;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %d, freeing packet queue %p\n", i, (void *)(arp_table[i].p)));
pbuf_free(arp_table[i].p);
arp_table[i].p = NULL;
#endif
/* no empty or recyclable entries found */
} else {
return (s8_t)ERR_MEM;
}
/* { empty or recyclable entry found } */
LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
/* recycle entry (no-op for an already empty entry) */
arp_table[i].state = ETHARP_STATE_EMPTY;
/* IP address given? */
if (ipaddr != NULL) {
/* set IP address */
ip_addr_set(&arp_table[i].ipaddr, ipaddr);
}
arp_table[i].ctime = 0;
return (err_t)i;
}
/**
* Update (or insert) a IP/MAC address pair in the ARP cache.
*
* If a pending entry is resolved, any queued packets will be sent
* at this point.
*
* @param ipaddr IP address of the inserted ARP entry.
* @param ethaddr Ethernet address of the inserted ARP entry.
* @param flags Defines behaviour:
* - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified,
* only existing ARP entries will be updated.
*
* @return
* - ERR_OK Succesfully updated ARP cache.
* - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set.
* - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
*
* @see pbuf_free()
*/
static err_t
update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)
{
s8_t i, k;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n"));
LWIP_ASSERT("netif->hwaddr_len != 0", netif->hwaddr_len != 0);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: %u.%u.%u.%u - %02x:%02x:%02x:%02x:%02x:%02x\n",
ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr),
ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
/* non-unicast address? */
if (ip_addr_isany(ipaddr) ||
ip_addr_isbroadcast(ipaddr, netif) ||
ip_addr_ismulticast(ipaddr)) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
return ERR_ARG;
}
/* find or create ARP entry */
i = find_entry(ipaddr, flags);
/* bail out if no entry could be found */
if (i < 0) return (err_t)i;
/* mark it stable */
arp_table[i].state = ETHARP_STATE_STABLE;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %u\n", i));
/* update address */
for (k = 0; k < netif->hwaddr_len; ++k) {
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
}
/* reset time stamp */
arp_table[i].ctime = 0;
/* this is where we will send out queued packets! */
#if ARP_QUEUEING
while (arp_table[i].p != NULL) {
/* get the first packet on the queue */
struct pbuf *p = arp_table[i].p;
/* Ethernet header */
struct eth_hdr *ethhdr = p->payload;
/* remember (and reference) remainder of queue */
/* note: this will also terminate the p pbuf chain */
arp_table[i].p = pbuf_dequeue(p);
/* fill-in Ethernet header */
for (k = 0; k < netif->hwaddr_len; ++k) {
ethhdr->dest.addr[k] = ethaddr->addr[k];
ethhdr->src.addr[k] = netif->hwaddr[k];
}
ethhdr->type = htons(ETHTYPE_IP);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n", (void *)p));
/* send the queued IP packet */
netif->linkoutput(netif, p);
/* free the queued IP packet */
pbuf_free(p);
}
#endif
return ERR_OK;
}
/**
* Updates the ARP table using the given IP packet.
*
* Uses the incoming IP packet's source address to update the
* ARP cache for the local network. The function does not alter
* or free the packet. This function must be called before the
* packet p is passed to the IP layer.
*
* @param netif The lwIP network interface on which the IP packet pbuf arrived.
* @param pbuf The IP packet that arrived on netif.
*
* @return NULL
*
* @see pbuf_free()
*/
void
etharp_ip_input(struct netif *netif, struct pbuf *p)
{
struct ethip_hdr *hdr;
/* Only insert an entry if the source IP address of the
incoming IP packet comes from a host on the local network. */
hdr = p->payload;
/* source is not on the local network? */
if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
/* do nothing */
return;
}
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));
/* update ARP table */
/* @todo We could use ETHARP_TRY_HARD if we think we are going to talk
* back soon (for example, if the destination IP address is ours. */
update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0);
}
/**
* Responds to ARP requests to us. Upon ARP replies to us, add entry to cache
* send out queued IP packets. Updates cache with snooped address pairs.
*
* Should be called for incoming ARP packets. The pbuf in the argument
* is freed by this function.
*
* @param netif The lwIP network interface on which the ARP packet pbuf arrived.
* @param pbuf The ARP packet that arrived on netif. Is freed by this function.
* @param ethaddr Ethernet address of netif.
*
* @return NULL
*
* @see pbuf_free()
*/
void
etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
{
struct etharp_hdr *hdr;
/* these are aligned properly, whereas the ARP header fields might not be */
struct ip_addr sipaddr, dipaddr;
u8_t i;
u8_t for_us;
/* drop short ARP packets */
if (p->tot_len < sizeof(struct etharp_hdr)) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 1, ("etharp_arp_input: packet dropped, too short (%d/%d)\n", p->tot_len, sizeof(struct etharp_hdr)));
pbuf_free(p);
return;
}
hdr = p->payload;
/* get aligned copies of addresses */
*(struct ip_addr2 *)&sipaddr = hdr->sipaddr;
*(struct ip_addr2 *)&dipaddr = hdr->dipaddr;
/* this interface is not configured? */
if (netif->ip_addr.addr == 0) {
for_us = 0;
} else {
/* ARP packet directed to us? */
for_us = ip_addr_cmp(&dipaddr, &(netif->ip_addr));
}
/* ARP message directed to us? */
if (for_us) {
/* add IP address in ARP cache; assume requester wants to talk to us.
* can result in directly sending the queued packets for this host. */
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);
/* ARP message not directed to us? */
} else {
/* update the source IP address in the cache, if present */
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0);
}
/* now act on the message itself */
switch (htons(hdr->opcode)) {
/* ARP request? */
case ARP_REQUEST:
/* ARP request. If it asked for our address, we send out a
* reply. In any case, we time-stamp any existing ARP entry,
* and possiby send out an IP packet that was queued on it. */
LWIP_DEBUGF (ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP request\n"));
/* ARP request for our address? */
if (for_us) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n"));
/* re-use pbuf to send ARP reply */
hdr->opcode = htons(ARP_REPLY);
hdr->dipaddr = hdr->sipaddr;
hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;
for(i = 0; i < netif->hwaddr_len; ++i) {
hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];
hdr->shwaddr.addr[i] = ethaddr->addr[i];
hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i];
hdr->ethhdr.src.addr[i] = ethaddr->addr[i];
}
hdr->hwtype = htons(HWTYPE_ETHERNET);
ARPH_HWLEN_SET(hdr, netif->hwaddr_len);
hdr->proto = htons(ETHTYPE_IP);
ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
hdr->ethhdr.type = htons(ETHTYPE_ARP);
/* return ARP reply */
netif->linkoutput(netif, p);
/* we are not configured? */
} else if (netif->ip_addr.addr == 0) {
/* { for_us == 0 and netif->ip_addr.addr == 0 } */
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));
/* request was not directed to us */
} else {
/* { for_us == 0 and netif->ip_addr.addr != 0 } */
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n"));
}
break;
case ARP_REPLY:
/* ARP reply. We already updated the ARP cache earlier. */
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));
#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
/* When unconfigured, DHCP wants to know about ARP replies from the
* address offered to us, as that means someone else uses it already! */
if (netif->ip_addr.addr == 0) dhcp_arp_reply(netif, &sipaddr);
#endif
break;
default:
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %d\n", htons(hdr->opcode)));
break;
}
/* free ARP packet */
pbuf_free(p);
}
/**
* Resolve and fill-in Ethernet address header for outgoing packet.
*
* For IP multicast and broadcast, corresponding Ethernet addresses
* are selected and the packet is transmitted on the link.
*
* For unicast addresses, the packet is submitted to etharp_query(). In
* case the IP address is outside the local network, the IP address of
* the gateway is used.
*
* @param netif The lwIP network interface which the IP packet will be sent on.
* @param ipaddr The IP address of the packet destination.
* @param pbuf The pbuf(s) containing the IP packet to be sent.
*
* @return
* - ERR_RTE No route to destination (no gateway to external networks),
* or the return type of either etharp_query() or netif->linkoutput().
*/
err_t
etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
{
struct eth_addr *dest, *srcaddr, mcastaddr;
struct eth_hdr *ethhdr;
u8_t i;
/* make room for Ethernet header - should not fail */
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
/* bail out */
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n"));
LINK_STATS_INC(link.lenerr);
return ERR_BUF;
}
/* assume unresolved Ethernet address */
dest = NULL;
/* Determine on destination hardware address. Broadcasts and multicasts
* are special, other IP addresses are looked up in the ARP table. */
/* broadcast destination IP address? */
if (ip_addr_isbroadcast(ipaddr, netif)) {
/* broadcast on Ethernet also */
dest = (struct eth_addr *)&ethbroadcast;
/* multicast destination IP address? */
} else if (ip_addr_ismulticast(ipaddr)) {
/* Hash IP multicast address to MAC address.*/
mcastaddr.addr[0] = 0x01;
mcastaddr.addr[1] = 0x00;
mcastaddr.addr[2] = 0x5e;
mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
mcastaddr.addr[4] = ip4_addr3(ipaddr);
mcastaddr.addr[5] = ip4_addr4(ipaddr);
/* destination Ethernet address is multicast */
dest = &mcastaddr;
/* unicast destination IP address? */
} else {
/* outside local network? */
if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
/* interface has default gateway? */
if (netif->gw.addr != 0) {
/* send to hardware address of default gateway IP address */
ipaddr = &(netif->gw);
/* no default gateway available */
} else {
/* no route to destination error (default gateway missing) */
return ERR_RTE;
}
}
/* queue on destination Ethernet address belonging to ipaddr */
return etharp_query(netif, ipaddr, q);
}
/* continuation for multicast/broadcast destinations */
/* obtain source Ethernet address of the given interface */
srcaddr = (struct eth_addr *)netif->hwaddr;
ethhdr = q->payload;
for (i = 0; i < netif->hwaddr_len; i++) {
ethhdr->dest.addr[i] = dest->addr[i];
ethhdr->src.addr[i] = srcaddr->addr[i];
}
ethhdr->type = htons(ETHTYPE_IP);
/* send packet directly on the link */
return netif->linkoutput(netif, q);
}
/**
* Send an ARP request for the given IP address and/or queue a packet.
*
* If the IP address was not yet in the cache, a pending ARP cache entry
* is added and an ARP request is sent for the given address. The packet
* is queued on this entry.
*
* If the IP address was already pending in the cache, a new ARP request
* is sent for the given address. The packet is queued on this entry.
*
* If the IP address was already stable in the cache, and a packet is
* given, it is directly sent and no ARP request is sent out.
*
* If the IP address was already stable in the cache, and no packet is
* given, an ARP request is sent out.
*
* @param netif The lwIP network interface on which ipaddr
* must be queried for.
* @param ipaddr The IP address to be resolved.
* @param q If non-NULL, a pbuf that must be delivered to the IP address.
* q is not freed by this function.
*
* @return
* - ERR_BUF Could not make room for Ethernet header.
* - ERR_MEM Hardware address unknown, and no more ARP entries available
* to query for address or queue the packet.
* - ERR_MEM Could not queue packet due to memory shortage.
* - ERR_RTE No route to destination (no gateway to external networks).
* - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
*
*/
err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
{
struct pbuf *p;
struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
err_t result = ERR_MEM;
s8_t i; /* ARP entry index */
u8_t k; /* Ethernet address octet index */
/* non-unicast address? */
if (ip_addr_isbroadcast(ipaddr, netif) ||
ip_addr_ismulticast(ipaddr) ||
ip_addr_isany(ipaddr)) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n"));
return ERR_ARG;
}
/* find entry in ARP cache, ask to create entry if queueing packet */
i = find_entry(ipaddr, ETHARP_TRY_HARD);
/* could not find or create entry? */
if (i < 0)
{
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not create ARP entry\n"));
#ifdef LWIP_DEBUG
if (q) LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: packet dropped\n"));
#endif
return (err_t)i;
}
/* mark a fresh entry as pending (we just sent a request) */
if (arp_table[i].state == ETHARP_STATE_EMPTY) {
arp_table[i].state = ETHARP_STATE_PENDING;
}
/* { i is either a STABLE or (new or existing) PENDING entry } */
LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
((arp_table[i].state == ETHARP_STATE_PENDING) ||
(arp_table[i].state == ETHARP_STATE_STABLE)));
/* do we have a pending entry? or an implicit query request? */
if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
/* try to resolve it; send out ARP request */
result = etharp_request(netif, ipaddr);
}
/* packet given? */
if (q != NULL) {
/* stable entry? */
if (arp_table[i].state == ETHARP_STATE_STABLE) {
/* we have a valid IP->Ethernet address mapping,
* fill in the Ethernet header for the outgoing packet */
struct eth_hdr *ethhdr = q->payload;
for(k = 0; k < netif->hwaddr_len; k++) {
ethhdr->dest.addr[k] = arp_table[i].ethaddr.addr[k];
ethhdr->src.addr[k] = srcaddr->addr[k];
}
ethhdr->type = htons(ETHTYPE_IP);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending packet %p\n", (void *)q));
/* send the packet */
result = netif->linkoutput(netif, q);
/* pending entry? (either just created or already pending */
} else if (arp_table[i].state == ETHARP_STATE_PENDING) {
#if ARP_QUEUEING /* queue the given q packet */
/* copy any PBUF_REF referenced payloads into PBUF_RAM */
/* (the caller of lwIP assumes the referenced payload can be
* freed after it returns from the lwIP call that brought us here) */
p = pbuf_take(q);
/* packet could be taken over? */
if (p != NULL) {
/* queue packet ... */
if (arp_table[i].p == NULL) {
/* ... in the empty queue */
pbuf_ref(p);
arp_table[i].p = p;
#if 0 /* multi-packet-queueing disabled, see bug #11400 */
} else {
/* ... at tail of non-empty queue */
pbuf_queue(arp_table[i].p, p);
#endif
}
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %d\n", (void *)q, i));
result = ERR_OK;
} else {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
/* { result == ERR_MEM } through initialization */
}
#else /* ARP_QUEUEING == 0 */
/* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */
/* { result == ERR_MEM } through initialization */
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));
#endif
}
}
return result;
}
err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr)
{
struct pbuf *p;
struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
err_t result = ERR_OK;
u8_t k; /* ARP entry index */
/* allocate a pbuf for the outgoing ARP request packet */
p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);
/* could allocate a pbuf for an ARP request? */
if (p != NULL) {
struct etharp_hdr *hdr = p->payload;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_request: sending ARP request.\n"));
hdr->opcode = htons(ARP_REQUEST);
for (k = 0; k < netif->hwaddr_len; k++)
{
hdr->shwaddr.addr[k] = srcaddr->addr[k];
/* the hardware address is what we ask for, in
* a request it is a don't-care value, we use zeroes */
hdr->dhwaddr.addr[k] = 0x00;
}
hdr->dipaddr = *(struct ip_addr2 *)ipaddr;
hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;
hdr->hwtype = htons(HWTYPE_ETHERNET);
ARPH_HWLEN_SET(hdr, netif->hwaddr_len);
hdr->proto = htons(ETHTYPE_IP);
ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
for (k = 0; k < netif->hwaddr_len; ++k)
{
/* broadcast to all network interfaces on the local network */
hdr->ethhdr.dest.addr[k] = 0xff;
hdr->ethhdr.src.addr[k] = srcaddr->addr[k];
}
hdr->ethhdr.type = htons(ETHTYPE_ARP);
/* send ARP query */
result = netif->linkoutput(netif, p);
/* free ARP query packet */
pbuf_free(p);
p = NULL;
/* could not allocate pbuf for ARP request */
} else {
result = ERR_MEM;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_request: could not allocate pbuf for ARP request.\n"));
}
return result;
}

View file

@ -0,0 +1,354 @@
/*
* 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>
*
*/
/* lwIP includes. */
#include <string.h>
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include <lwip/stats.h>
#include "netif/etharp.h"
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "SAM7_EMAC.h"
#include "Emac.h"
#define netifMTU ( 1500 )
#define netifINTERFACE_TASK_STACK_SIZE ( 350 )
#define netifINTERFACE_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define netifGUARD_BLOCK_TIME ( 250 )
#define IFNAME0 'e'
#define IFNAME1 'm'
/* lwIP definitions. */
struct ethernetif
{
struct eth_addr *ethaddr;
};
static const struct eth_addr ethbroadcast = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
static struct netif *xNetIf = NULL;
/* Forward declarations. */
static void ethernetif_input( void * );
static err_t ethernetif_output( struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr );
err_t ethernetif_init( struct netif *netif );
/*-----------------------------------------------------------*/
static void low_level_init( struct netif *netif )
{
unsigned portBASE_TYPE uxPriority;
/* set MAC hardware address length */
netif->hwaddr_len = 6;
/* set MAC hardware address */
netif->hwaddr[0] = emacETHADDR0;
netif->hwaddr[1] = emacETHADDR1;
netif->hwaddr[2] = emacETHADDR2;
netif->hwaddr[3] = emacETHADDR3;
netif->hwaddr[4] = emacETHADDR4;
netif->hwaddr[5] = emacETHADDR5;
/* maximum transfer unit */
netif->mtu = netifMTU;
/* broadcast capability */
netif->flags = NETIF_FLAG_BROADCAST;
xNetIf = netif;
/* Initialise the EMAC. This routine contains code that polls status bits.
If the Ethernet cable is not plugged in then this can take a considerable
time. To prevent this starving lower priority tasks of processing time we
lower our priority prior to the call, then raise it back again once the
initialisation is complete. */
uxPriority = uxTaskPriorityGet( NULL );
vTaskPrioritySet( NULL, tskIDLE_PRIORITY );
while( xEMACInit() == NULL )
{
__asm( "NOP" );
}
vTaskPrioritySet( NULL, uxPriority );
/* Create the task that handles the EMAC. */
xTaskCreate( ethernetif_input, ( signed char * ) "ETH_INT", netifINTERFACE_TASK_STACK_SIZE, NULL, netifINTERFACE_TASK_PRIORITY, NULL );
}
/*-----------------------------------------------------------*/
/*
* low_level_output(): Should do the actual transmission of the packet. The
* packet is contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*/
static err_t low_level_output( struct netif *netif, struct pbuf *p )
{
struct pbuf *q;
static xSemaphoreHandle xTxSemaphore = NULL;
err_t xReturn = ERR_OK;
/* Parameter not used. */
( void ) netif;
if( xTxSemaphore == NULL )
{
vSemaphoreCreateBinary( xTxSemaphore );
}
#if ETH_PAD_SIZE
pbuf_header( p, -ETH_PAD_SIZE ); /* drop the padding word */
#endif
/* Access to the EMAC is guarded using a semaphore. */
if( xSemaphoreTake( xTxSemaphore, netifGUARD_BLOCK_TIME ) )
{
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. if q->next == NULL then this is the last pbuf in the
chain. */
if( !lEMACSend( q->payload, q->len, ( q->next == NULL ) ) )
{
xReturn = ~ERR_OK;
}
}
xSemaphoreGive( xTxSemaphore );
}
#if ETH_PAD_SIZE
pbuf_header( p, ETH_PAD_SIZE ); /* reclaim the padding word */
#endif
#if LINK_STATS
lwip_stats.link.xmit++;
#endif /* LINK_STATS */
return xReturn;
}
/*-----------------------------------------------------------*/
/*
* low_level_input(): Should allocate a pbuf and transfer the bytes of the
* incoming packet from the interface into the pbuf.
*/
static struct pbuf *low_level_input( struct netif *netif )
{
struct pbuf *p = NULL, *q;
u16_t len = 0;
static xSemaphoreHandle xRxSemaphore = NULL;
/* Parameter not used. */
( void ) netif;
if( xRxSemaphore == NULL )
{
vSemaphoreCreateBinary( xRxSemaphore );
}
/* Access to the emac is guarded using a semaphore. */
if( xSemaphoreTake( xRxSemaphore, netifGUARD_BLOCK_TIME ) )
{
/* Obtain the size of the packet. */
len = ulEMACInputLength();
if( len )
{
#if ETH_PAD_SIZE
len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
#endif
/* We allocate a pbuf chain of pbufs from the pool. */
p = pbuf_alloc( PBUF_RAW, len, PBUF_POOL );
if( p != NULL )
{
#if ETH_PAD_SIZE
pbuf_header( p, -ETH_PAD_SIZE ); /* drop the padding word */
#endif
/* Let the driver know we are going to read a new packet. */
vEMACRead( NULL, 0, len );
/* 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. */
vEMACRead( q->payload, q->len, len );
}
#if ETH_PAD_SIZE
pbuf_header( p, ETH_PAD_SIZE ); /* reclaim the padding word */
#endif
#if LINK_STATS
lwip_stats.link.recv++;
#endif /* LINK_STATS */
}
else
{
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif /* LINK_STATS */
}
}
xSemaphoreGive( xRxSemaphore );
}
return p;
}
/*-----------------------------------------------------------*/
/*
* ethernetif_output(): This function is called by the TCP/IP stack when an
* IP packet should be sent. It calls the function called low_level_output()
* to do the actual transmission of the packet.
*/
static err_t ethernetif_output( struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr )
{
/* resolve hardware address, then send (or queue) packet */
return etharp_output( netif, ipaddr, p );
}
/*-----------------------------------------------------------*/
/*
* ethernetif_input(): This function should be called when a packet is ready to
* be read from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network interface.
*/
static void ethernetif_input( void * pvParameters )
{
struct ethernetif *ethernetif;
struct eth_hdr *ethhdr;
struct pbuf *p;
( void ) pvParameters;
for( ;; )
{
do
{
ethernetif = xNetIf->state;
/* move received packet into a new pbuf */
p = low_level_input( xNetIf );
if( p == NULL )
{
/* No packet could be read. Wait a for an interrupt to tell us
there is more data available. */
vEMACWaitForInput();
}
} while( p == NULL );
/* points to packet payload, which starts with an Ethernet header */
ethhdr = p->payload;
#if LINK_STATS
lwip_stats.link.recv++;
#endif /* LINK_STATS */
ethhdr = p->payload;
switch( htons( ethhdr->type ) )
{
/* IP packet? */
case ETHTYPE_IP:
/* update ARP table */
etharp_ip_input( xNetIf, p );
/* skip Ethernet header */
pbuf_header( p, (s16_t)-sizeof(struct eth_hdr) );
/* pass to network layer */
xNetIf->input( p, xNetIf );
break;
case ETHTYPE_ARP:
/* pass p to ARP module */
etharp_arp_input( xNetIf, ethernetif->ethaddr, p );
break;
default:
pbuf_free( p );
p = NULL;
break;
}
}
}
/*-----------------------------------------------------------*/
static void arp_timer( void *arg )
{
( void ) arg;
etharp_tmr();
sys_timeout( ARP_TMR_INTERVAL, arp_timer, NULL );
}
/*-----------------------------------------------------------*/
err_t ethernetif_init( struct netif *netif )
{
struct ethernetif *ethernetif;
ethernetif = mem_malloc( sizeof(struct ethernetif) );
if( ethernetif == NULL )
{
LWIP_DEBUGF( NETIF_DEBUG, ("ethernetif_init: out of memory\n") );
return ERR_MEM;
}
netif->state = ethernetif;
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->output = ethernetif_output;
netif->linkoutput = low_level_output;
ethernetif->ethaddr = ( struct eth_addr * ) &( netif->hwaddr[0] );
low_level_init( netif );
etharp_init();
sys_timeout( ARP_TMR_INTERVAL, arp_timer, NULL );
return ERR_OK;
}

View file

@ -0,0 +1,119 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#if LWIP_HAVE_LOOPIF
#include "netif/loopif.h"
#include "lwip/mem.h"
#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)
#include "netif/tcpdump.h"
#endif /* LWIP_DEBUG && LWIP_TCPDUMP */
#include "lwip/tcp.h"
#include "lwip/ip.h"
static void
loopif_input( void * arg )
{
struct netif *netif = (struct netif *)( ((void **)arg)[ 0 ] );
struct pbuf *r = (struct pbuf *)( ((void **)arg)[ 1 ] );
mem_free( arg );
netif -> input( r, netif );
}
static err_t
loopif_output(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr)
{
struct pbuf *q, *r;
char *ptr;
void **arg;
#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)
tcpdump(p);
#endif /* LWIP_DEBUG && LWIP_TCPDUMP */
r = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
if (r != NULL) {
ptr = r->payload;
for(q = p; q != NULL; q = q->next) {
memcpy(ptr, q->payload, q->len);
ptr += q->len;
}
arg = mem_malloc( sizeof( void *[2]));
if( NULL == arg ) {
return ERR_MEM;
}
arg[0] = netif;
arg[1] = r;
/**
* workaround (patch #1779) to try to prevent bug #2595:
* When connecting to "localhost" with the loopif interface,
* tcp_output doesn't get the opportunity to finnish sending the
* segment before tcp_process gets it, resulting in tcp_process
* referencing pcb->unacked-> which still is NULL.
*
* TODO: Is there still a race condition here? Leon
*/
sys_timeout( 1, loopif_input, arg );
return ERR_OK;
}
return ERR_MEM;
}
err_t
loopif_init(struct netif *netif)
{
netif->name[0] = 'l';
netif->name[1] = 'o';
#if 0 /** TODO: I think this should be enabled, or not? Leon */
netif->input = loopif_input;
#endif
netif->output = loopif_output;
return ERR_OK;
}
#endif /* LWIP_HAVE_LOOPIF */

View file

@ -0,0 +1,927 @@
/*****************************************************************************
* auth.c - Network Authentication and Phase Control program file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* Copyright (c) 1997 by Global Election Systems Inc. All rights reserved.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
* Ported from public pppd code.
*****************************************************************************/
/*
* auth.c - PPP authentication and phase control.
*
* Copyright (c) 1993 The Australian National University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the Australian National University. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "ppp.h"
#if PPP_SUPPORT > 0
#include "fsm.h"
#include "lcp.h"
#include "pap.h"
#include "chap.h"
#include "auth.h"
#include "ipcp.h"
#if CBCP_SUPPORT > 0
#include "cbcp.h"
#endif
#include "pppdebug.h"
/*************************/
/*** LOCAL DEFINITIONS ***/
/*************************/
/* Bits in auth_pending[] */
#define PAP_WITHPEER 1
#define PAP_PEER 2
#define CHAP_WITHPEER 4
#define CHAP_PEER 8
/************************/
/*** LOCAL DATA TYPES ***/
/************************/
/* Used for storing a sequence of words. Usually malloced. */
struct wordlist {
struct wordlist *next;
char word[1];
};
/***********************************/
/*** LOCAL FUNCTION DECLARATIONS ***/
/***********************************/
extern char *crypt (const char *, const char *);
/* Prototypes for procedures local to this file. */
static void network_phase (int);
static void check_idle (void *);
static void connect_time_expired (void *);
#if 0
static int login (char *, char *, char **, int *);
#endif
static void logout (void);
static int null_login (int);
static int get_pap_passwd (int, char *, char *);
static int have_pap_secret (void);
static int have_chap_secret (char *, char *, u32_t);
static int ip_addr_check (u32_t, struct wordlist *);
#if 0 /* PAP_SUPPORT > 0 || CHAP_SUPPORT > 0 */
static void set_allowed_addrs(int unit, struct wordlist *addrs);
static void free_wordlist (struct wordlist *);
#endif
#if CBCP_SUPPORT > 0
static void callback_phase (int);
#endif
/******************************/
/*** PUBLIC DATA STRUCTURES ***/
/******************************/
/*****************************/
/*** LOCAL DATA STRUCTURES ***/
/*****************************/
#if PAP_SUPPORT > 0 || CHAP_SUPPORT > 0
/* The name by which the peer authenticated itself to us. */
static char peer_authname[MAXNAMELEN];
#endif
/* Records which authentication operations haven't completed yet. */
static int auth_pending[NUM_PPP];
/* Set if we have successfully called login() */
static int logged_in;
/* Set if we have run the /etc/ppp/auth-up script. */
static int did_authup;
/* List of addresses which the peer may use. */
static struct wordlist *addresses[NUM_PPP];
/* Number of network protocols which we have opened. */
static int num_np_open;
/* Number of network protocols which have come up. */
static int num_np_up;
#if PAP_SUPPORT > 0 || CHAP_SUPPORT > 0
/* Set if we got the contents of passwd[] from the pap-secrets file. */
static int passwd_from_file;
#endif
/***********************************/
/*** PUBLIC FUNCTION DEFINITIONS ***/
/***********************************/
/*
* An Open on LCP has requested a change from Dead to Establish phase.
* Do what's necessary to bring the physical layer up.
*/
void link_required(int unit)
{
AUTHDEBUG((LOG_INFO, "link_required: %d\n", unit));
}
/*
* LCP has terminated the link; go to the Dead phase and take the
* physical layer down.
*/
void link_terminated(int unit)
{
AUTHDEBUG((LOG_INFO, "link_terminated: %d\n", unit));
if (lcp_phase[unit] == PHASE_DEAD)
return;
if (logged_in)
logout();
lcp_phase[unit] = PHASE_DEAD;
AUTHDEBUG((LOG_NOTICE, "Connection terminated.\n"));
pppMainWakeup(unit);
}
/*
* LCP has gone down; it will either die or try to re-establish.
*/
void link_down(int unit)
{
int i;
struct protent *protp;
AUTHDEBUG((LOG_INFO, "link_down: %d\n", unit));
if (did_authup) {
/* XXX Do link down processing. */
did_authup = 0;
}
for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
if (!protp->enabled_flag)
continue;
if (protp->protocol != PPP_LCP && protp->lowerdown != NULL)
(*protp->lowerdown)(unit);
if (protp->protocol < 0xC000 && protp->close != NULL)
(*protp->close)(unit, "LCP down");
}
num_np_open = 0;
num_np_up = 0;
if (lcp_phase[unit] != PHASE_DEAD)
lcp_phase[unit] = PHASE_TERMINATE;
pppMainWakeup(unit);
}
/*
* The link is established.
* Proceed to the Dead, Authenticate or Network phase as appropriate.
*/
void link_established(int unit)
{
int auth;
int i;
struct protent *protp;
lcp_options *wo = &lcp_wantoptions[unit];
lcp_options *go = &lcp_gotoptions[unit];
#if PAP_SUPPORT > 0 || CHAP_SUPPORT > 0
lcp_options *ho = &lcp_hisoptions[unit];
#endif
AUTHDEBUG((LOG_INFO, "link_established: %d\n", unit));
/*
* Tell higher-level protocols that LCP is up.
*/
for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i)
if (protp->protocol != PPP_LCP && protp->enabled_flag
&& protp->lowerup != NULL)
(*protp->lowerup)(unit);
if (ppp_settings.auth_required && !(go->neg_chap || go->neg_upap)) {
/*
* We wanted the peer to authenticate itself, and it refused:
* treat it as though it authenticated with PAP using a username
* of "" and a password of "". If that's not OK, boot it out.
*/
if (!wo->neg_upap || !null_login(unit)) {
AUTHDEBUG((LOG_WARNING, "peer refused to authenticate\n"));
lcp_close(unit, "peer refused to authenticate");
return;
}
}
lcp_phase[unit] = PHASE_AUTHENTICATE;
auth = 0;
#if CHAP_SUPPORT > 0
if (go->neg_chap) {
ChapAuthPeer(unit, ppp_settings.our_name, go->chap_mdtype);
auth |= CHAP_PEER;
}
#endif
#if PAP_SUPPORT > 0 && CHAP_SUPPORT > 0
else
#endif
#if PAP_SUPPORT > 0
if (go->neg_upap) {
upap_authpeer(unit);
auth |= PAP_PEER;
}
#endif
#if CHAP_SUPPORT > 0
if (ho->neg_chap) {
ChapAuthWithPeer(unit, ppp_settings.user, ho->chap_mdtype);
auth |= CHAP_WITHPEER;
}
#endif
#if PAP_SUPPORT > 0 && CHAP_SUPPORT > 0
else
#endif
#if PAP_SUPPORT > 0
if (ho->neg_upap) {
if (ppp_settings.passwd[0] == 0) {
passwd_from_file = 1;
if (!get_pap_passwd(unit, ppp_settings.user, ppp_settings.passwd))
AUTHDEBUG((LOG_ERR, "No secret found for PAP login\n"));
}
upap_authwithpeer(unit, ppp_settings.user, ppp_settings.passwd);
auth |= PAP_WITHPEER;
}
#endif
auth_pending[unit] = auth;
if (!auth)
network_phase(unit);
}
/*
* The peer has failed to authenticate himself using `protocol'.
*/
void auth_peer_fail(int unit, u16_t protocol)
{
AUTHDEBUG((LOG_INFO, "auth_peer_fail: %d proto=%X\n", unit, protocol));
/*
* Authentication failure: take the link down
*/
lcp_close(unit, "Authentication failed");
}
#if PAP_SUPPORT > 0 || CHAP_SUPPORT > 0
/*
* The peer has been successfully authenticated using `protocol'.
*/
void auth_peer_success(int unit, u16_t protocol, char *name, int namelen)
{
int pbit;
AUTHDEBUG((LOG_INFO, "auth_peer_success: %d proto=%X\n", unit, protocol));
switch (protocol) {
case PPP_CHAP:
pbit = CHAP_PEER;
break;
case PPP_PAP:
pbit = PAP_PEER;
break;
default:
AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n",
protocol));
return;
}
/*
* Save the authenticated name of the peer for later.
*/
if (namelen > sizeof(peer_authname) - 1)
namelen = sizeof(peer_authname) - 1;
BCOPY(name, peer_authname, namelen);
peer_authname[namelen] = 0;
/*
* If there is no more authentication still to be done,
* proceed to the network (or callback) phase.
*/
if ((auth_pending[unit] &= ~pbit) == 0)
network_phase(unit);
}
/*
* We have failed to authenticate ourselves to the peer using `protocol'.
*/
void auth_withpeer_fail(int unit, u16_t protocol)
{
int errCode = PPPERR_AUTHFAIL;
AUTHDEBUG((LOG_INFO, "auth_withpeer_fail: %d proto=%X\n", unit, protocol));
if (passwd_from_file)
BZERO(ppp_settings.passwd, MAXSECRETLEN);
/*
* XXX Warning: the unit number indicates the interface which is
* not necessarily the PPP connection. It works here as long
* as we are only supporting PPP interfaces.
*/
pppIOCtl(unit, PPPCTLS_ERRCODE, &errCode);
/*
* We've failed to authenticate ourselves to our peer.
* He'll probably take the link down, and there's not much
* we can do except wait for that.
*/
}
/*
* We have successfully authenticated ourselves with the peer using `protocol'.
*/
void auth_withpeer_success(int unit, u16_t protocol)
{
int pbit;
AUTHDEBUG((LOG_INFO, "auth_withpeer_success: %d proto=%X\n", unit, protocol));
switch (protocol) {
case PPP_CHAP:
pbit = CHAP_WITHPEER;
break;
case PPP_PAP:
if (passwd_from_file)
BZERO(ppp_settings.passwd, MAXSECRETLEN);
pbit = PAP_WITHPEER;
break;
default:
AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n",
protocol));
pbit = 0;
}
/*
* If there is no more authentication still being done,
* proceed to the network (or callback) phase.
*/
if ((auth_pending[unit] &= ~pbit) == 0)
network_phase(unit);
}
#endif
/*
* np_up - a network protocol has come up.
*/
void np_up(int unit, u16_t proto)
{
AUTHDEBUG((LOG_INFO, "np_up: %d proto=%X\n", unit, proto));
if (num_np_up == 0) {
AUTHDEBUG((LOG_INFO, "np_up: maxconnect=%d idle_time_limit=%d\n",ppp_settings.maxconnect,ppp_settings.idle_time_limit));
/*
* At this point we consider that the link has come up successfully.
*/
if (ppp_settings.idle_time_limit > 0)
TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit);
/*
* Set a timeout to close the connection once the maximum
* connect time has expired.
*/
if (ppp_settings.maxconnect > 0)
TIMEOUT(connect_time_expired, 0, ppp_settings.maxconnect);
}
++num_np_up;
}
/*
* np_down - a network protocol has gone down.
*/
void np_down(int unit, u16_t proto)
{
AUTHDEBUG((LOG_INFO, "np_down: %d proto=%X\n", unit, proto));
if (--num_np_up == 0 && ppp_settings.idle_time_limit > 0) {
UNTIMEOUT(check_idle, NULL);
}
}
/*
* np_finished - a network protocol has finished using the link.
*/
void np_finished(int unit, u16_t proto)
{
AUTHDEBUG((LOG_INFO, "np_finished: %d proto=%X\n", unit, proto));
if (--num_np_open <= 0) {
/* no further use for the link: shut up shop. */
lcp_close(0, "No network protocols running");
}
}
/*
* auth_reset - called when LCP is starting negotiations to recheck
* authentication options, i.e. whether we have appropriate secrets
* to use for authenticating ourselves and/or the peer.
*/
void auth_reset(int unit)
{
lcp_options *go = &lcp_gotoptions[unit];
lcp_options *ao = &lcp_allowoptions[0];
ipcp_options *ipwo = &ipcp_wantoptions[0];
u32_t remote;
AUTHDEBUG((LOG_INFO, "auth_reset: %d\n", unit));
ao->neg_upap = !ppp_settings.refuse_pap && (ppp_settings.passwd[0] != 0 || get_pap_passwd(unit, NULL, NULL));
ao->neg_chap = !ppp_settings.refuse_chap && ppp_settings.passwd[0] != 0 /*have_chap_secret(ppp_settings.user, ppp_settings.remote_name, (u32_t)0)*/;
if (go->neg_upap && !have_pap_secret())
go->neg_upap = 0;
if (go->neg_chap) {
remote = ipwo->accept_remote? 0: ipwo->hisaddr;
if (!have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote))
go->neg_chap = 0;
}
}
#if PAP_SUPPORT > 0
/*
* check_passwd - Check the user name and passwd against the PAP secrets
* file. If requested, also check against the system password database,
* and login the user if OK.
*
* returns:
* UPAP_AUTHNAK: Authentication failed.
* UPAP_AUTHACK: Authentication succeeded.
* In either case, msg points to an appropriate message.
*/
int check_passwd(
int unit,
char *auser,
int userlen,
char *apasswd,
int passwdlen,
char **msg,
int *msglen
)
{
#if 1
*msg = (char *) 0;
return UPAP_AUTHACK; /* XXX Assume all entries OK. */
#else
int ret = 0;
struct wordlist *addrs = NULL;
char passwd[256], user[256];
char secret[MAXWORDLEN];
static u_short attempts = 0;
/*
* Make copies of apasswd and auser, then null-terminate them.
*/
BCOPY(apasswd, passwd, passwdlen);
passwd[passwdlen] = '\0';
BCOPY(auser, user, userlen);
user[userlen] = '\0';
*msg = (char *) 0;
/* XXX Validate user name and password. */
ret = UPAP_AUTHACK; /* XXX Assume all entries OK. */
if (ret == UPAP_AUTHNAK) {
if (*msg == (char *) 0)
*msg = "Login incorrect";
*msglen = strlen(*msg);
/*
* Frustrate passwd stealer programs.
* Allow 10 tries, but start backing off after 3 (stolen from login).
* On 10'th, drop the connection.
*/
if (attempts++ >= 10) {
AUTHDEBUG((LOG_WARNING, "%d LOGIN FAILURES BY %s\n", attempts, user));
/*ppp_panic("Excess Bad Logins");*/
}
if (attempts > 3) {
sys_msleep((attempts - 3) * 5);
}
if (addrs != NULL) {
free_wordlist(addrs);
}
} else {
attempts = 0; /* Reset count */
if (*msg == (char *) 0)
*msg = "Login ok";
*msglen = strlen(*msg);
set_allowed_addrs(unit, addrs);
}
BZERO(passwd, sizeof(passwd));
BZERO(secret, sizeof(secret));
return ret;
#endif
}
#endif
/*
* auth_ip_addr - check whether the peer is authorized to use
* a given IP address. Returns 1 if authorized, 0 otherwise.
*/
int auth_ip_addr(int unit, u32_t addr)
{
return ip_addr_check(addr, addresses[unit]);
}
/*
* bad_ip_adrs - return 1 if the IP address is one we don't want
* to use, such as an address in the loopback net or a multicast address.
* addr is in network byte order.
*/
int bad_ip_adrs(u32_t addr)
{
addr = ntohl(addr);
return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET
|| IN_MULTICAST(addr) || IN_BADCLASS(addr);
}
#if CHAP_SUPPORT > 0
/*
* get_secret - open the CHAP secret file and return the secret
* for authenticating the given client on the given server.
* (We could be either client or server).
*/
int get_secret(
int unit,
char *client,
char *server,
char *secret,
int *secret_len,
int save_addrs
)
{
#if 1
int len;
struct wordlist *addrs;
addrs = NULL;
if(!client || !client[0] || strcmp(client, ppp_settings.user)) {
return 0;
}
len = strlen(ppp_settings.passwd);
if (len > MAXSECRETLEN) {
AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server));
len = MAXSECRETLEN;
}
BCOPY(ppp_settings.passwd, secret, len);
*secret_len = len;
return 1;
#else
int ret = 0, len;
struct wordlist *addrs;
char secbuf[MAXWORDLEN];
addrs = NULL;
secbuf[0] = 0;
/* XXX Find secret. */
if (ret < 0)
return 0;
if (save_addrs)
set_allowed_addrs(unit, addrs);
len = strlen(secbuf);
if (len > MAXSECRETLEN) {
AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server));
len = MAXSECRETLEN;
}
BCOPY(secbuf, secret, len);
BZERO(secbuf, sizeof(secbuf));
*secret_len = len;
return 1;
#endif
}
#endif
#if 0 /* UNUSED */
/*
* auth_check_options - called to check authentication options.
*/
void auth_check_options(void)
{
lcp_options *wo = &lcp_wantoptions[0];
int can_auth;
ipcp_options *ipwo = &ipcp_wantoptions[0];
u32_t remote;
/* Default our_name to hostname, and user to our_name */
if (ppp_settings.our_name[0] == 0 || ppp_settings.usehostname)
strcpy(ppp_settings.our_name, ppp_settings.hostname);
if (ppp_settings.user[0] == 0)
strcpy(ppp_settings.user, ppp_settings.our_name);
/* If authentication is required, ask peer for CHAP or PAP. */
if (ppp_settings.auth_required && !wo->neg_chap && !wo->neg_upap) {
wo->neg_chap = 1;
wo->neg_upap = 1;
}
/*
* Check whether we have appropriate secrets to use
* to authenticate the peer.
*/
can_auth = wo->neg_upap && have_pap_secret();
if (!can_auth && wo->neg_chap) {
remote = ipwo->accept_remote? 0: ipwo->hisaddr;
can_auth = have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote);
}
if (ppp_settings.auth_required && !can_auth) {
ppp_panic("No auth secret");
}
}
#endif
/**********************************/
/*** LOCAL FUNCTION DEFINITIONS ***/
/**********************************/
/*
* Proceed to the network phase.
*/
static void network_phase(int unit)
{
int i;
struct protent *protp;
lcp_options *go = &lcp_gotoptions[unit];
/*
* If the peer had to authenticate, run the auth-up script now.
*/
if ((go->neg_chap || go->neg_upap) && !did_authup) {
/* XXX Do setup for peer authentication. */
did_authup = 1;
}
#if CBCP_SUPPORT > 0
/*
* If we negotiated callback, do it now.
*/
if (go->neg_cbcp) {
lcp_phase[unit] = PHASE_CALLBACK;
(*cbcp_protent.open)(unit);
return;
}
#endif
lcp_phase[unit] = PHASE_NETWORK;
for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i)
if (protp->protocol < 0xC000 && protp->enabled_flag
&& protp->open != NULL) {
(*protp->open)(unit);
if (protp->protocol != PPP_CCP)
++num_np_open;
}
if (num_np_open == 0)
/* nothing to do */
lcp_close(0, "No network protocols running");
}
/*
* check_idle - check whether the link has been idle for long
* enough that we can shut it down.
*/
static void check_idle(void *arg)
{
struct ppp_idle idle;
u_short itime;
(void)arg;
if (!get_idle_time(0, &idle))
return;
itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle);
if (itime >= ppp_settings.idle_time_limit) {
/* link is idle: shut it down. */
AUTHDEBUG((LOG_INFO, "Terminating connection due to lack of activity.\n"));
lcp_close(0, "Link inactive");
} else {
TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit - itime);
}
}
/*
* connect_time_expired - log a message and close the connection.
*/
static void connect_time_expired(void *arg)
{
(void)arg;
AUTHDEBUG((LOG_INFO, "Connect time expired\n"));
lcp_close(0, "Connect time expired"); /* Close connection */
}
#if 0
/*
* login - Check the user name and password against the system
* password database, and login the user if OK.
*
* returns:
* UPAP_AUTHNAK: Login failed.
* UPAP_AUTHACK: Login succeeded.
* In either case, msg points to an appropriate message.
*/
static int login(char *user, char *passwd, char **msg, int *msglen)
{
/* XXX Fail until we decide that we want to support logins. */
return (UPAP_AUTHNAK);
}
#endif
/*
* logout - Logout the user.
*/
static void logout(void)
{
logged_in = 0;
}
/*
* null_login - Check if a username of "" and a password of "" are
* acceptable, and iff so, set the list of acceptable IP addresses
* and return 1.
*/
static int null_login(int unit)
{
(void)unit;
/* XXX Fail until we decide that we want to support logins. */
return 0;
}
/*
* get_pap_passwd - get a password for authenticating ourselves with
* our peer using PAP. Returns 1 on success, 0 if no suitable password
* could be found.
*/
static int get_pap_passwd(int unit, char *user, char *passwd)
{
/* normally we would reject PAP if no password is provided,
but this causes problems with some providers (like CHT in Taiwan)
who incorrectly request PAP and expect a bogus/empty password, so
always provide a default user/passwd of "none"/"none"
*/
if(user)
strcpy(user, "none");
if(passwd)
strcpy(passwd, "none");
return 1;
}
/*
* have_pap_secret - check whether we have a PAP file with any
* secrets that we could possibly use for authenticating the peer.
*/
static int have_pap_secret(void)
{
/* XXX Fail until we set up our passwords. */
return 0;
}
/*
* have_chap_secret - check whether we have a CHAP file with a
* secret that we could possibly use for authenticating `client'
* on `server'. Either can be the null string, meaning we don't
* know the identity yet.
*/
static int have_chap_secret(char *client, char *server, u32_t remote)
{
(void)client;
(void)server;
(void)remote;
/* XXX Fail until we set up our passwords. */
return 0;
}
#if 0 /* PAP_SUPPORT > 0 || CHAP_SUPPORT > 0 */
/*
* set_allowed_addrs() - set the list of allowed addresses.
*/
static void set_allowed_addrs(int unit, struct wordlist *addrs)
{
if (addresses[unit] != NULL)
free_wordlist(addresses[unit]);
addresses[unit] = addrs;
#if 0
/*
* If there's only one authorized address we might as well
* ask our peer for that one right away
*/
if (addrs != NULL && addrs->next == NULL) {
char *p = addrs->word;
struct ipcp_options *wo = &ipcp_wantoptions[unit];
u32_t a;
struct hostent *hp;
if (wo->hisaddr == 0 && *p != '!' && *p != '-'
&& strchr(p, '/') == NULL) {
hp = gethostbyname(p);
if (hp != NULL && hp->h_addrtype == AF_INET)
a = *(u32_t *)hp->h_addr;
else
a = inet_addr(p);
if (a != (u32_t) -1)
wo->hisaddr = a;
}
}
#endif
}
#endif
static int ip_addr_check(u32_t addr, struct wordlist *addrs)
{
/* don't allow loopback or multicast address */
if (bad_ip_adrs(addr))
return 0;
if (addrs == NULL)
return !ppp_settings.auth_required; /* no addresses authorized */
/* XXX All other addresses allowed. */
return 1;
}
#if 0 /* PAP_SUPPORT > 0 || CHAP_SUPPORT */
/*
* free_wordlist - release memory allocated for a wordlist.
*/
static void free_wordlist(struct wordlist *wp)
{
struct wordlist *next;
while (wp != NULL) {
next = wp->next;
free(wp);
wp = next;
}
}
#endif
#endif /* PPP_SUPPORT */

View file

@ -0,0 +1,94 @@
/*****************************************************************************
* auth.h - PPP Authentication and phase control header file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* portions Copyright (c) 1998 Global Election Systems Inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
* Original derived from BSD pppd.h.
*****************************************************************************/
/*
* pppd.h - PPP daemon global declarations.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#ifndef AUTH_H
#define AUTH_H
/***********************
*** PUBLIC FUNCTIONS ***
***********************/
void link_required (int); /* we are starting to use the link */
void link_terminated (int); /* we are finished with the link */
void link_down (int); /* the LCP layer has left the Opened state */
void link_established (int); /* the link is up; authenticate now */
void np_up (int, u16_t); /* a network protocol has come up */
void np_down (int, u16_t); /* a network protocol has gone down */
void np_finished (int, u16_t); /* a network protocol no longer needs link */
void auth_peer_fail (int, u16_t);/* peer failed to authenticate itself */
/* peer successfully authenticated itself */
void auth_peer_success (int, u16_t, char *, int);
/* we failed to authenticate ourselves */
void auth_withpeer_fail (int, u16_t);
/* we successfully authenticated ourselves */
void auth_withpeer_success (int, u16_t);
/* check authentication options supplied */
void auth_check_options (void);
void auth_reset (int); /* check what secrets we have */
/* Check peer-supplied username/password */
int check_passwd (int, char *, int, char *, int, char **, int *);
/* get "secret" for chap */
int get_secret (int, char *, char *, char *, int *, int);
/* check if IP address is authorized */
int auth_ip_addr (int, u32_t);
/* check if IP address is unreasonable */
int bad_ip_adrs (u32_t);
#endif /* AUTH_H */

View file

@ -0,0 +1,872 @@
/*** WARNING - THIS HAS NEVER BEEN FINISHED ***/
/*****************************************************************************
* chap.c - Network Challenge Handshake Authentication Protocol program file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* portions Copyright (c) 1997 by Global Election Systems Inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
* Original based on BSD chap.c.
*****************************************************************************/
/*
* chap.c - Challenge Handshake Authentication Protocol.
*
* Copyright (c) 1993 The Australian National University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the Australian National University. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Copyright (c) 1991 Gregory M. Christy.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Gregory M. Christy. The name of the author may not be used to
* endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "ppp.h"
#if PPP_SUPPORT > 0
#include "magic.h"
#if CHAP_SUPPORT > 0
#include "randm.h"
#include "auth.h"
#include "md5.h"
#include "chap.h"
#include "chpms.h"
#include "pppdebug.h"
/*************************/
/*** LOCAL DEFINITIONS ***/
/*************************/
/************************/
/*** LOCAL DATA TYPES ***/
/************************/
/***********************************/
/*** LOCAL FUNCTION DECLARATIONS ***/
/***********************************/
/*
* Protocol entry points.
*/
static void ChapInit (int);
static void ChapLowerUp (int);
static void ChapLowerDown (int);
static void ChapInput (int, u_char *, int);
static void ChapProtocolReject (int);
static int ChapPrintPkt (u_char *, int,
void (*) (void *, char *, ...), void *);
static void ChapChallengeTimeout (void *);
static void ChapResponseTimeout (void *);
static void ChapReceiveChallenge (chap_state *, u_char *, int, int);
static void ChapRechallenge (void *);
static void ChapReceiveResponse (chap_state *, u_char *, int, int);
static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);
static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);
static void ChapSendStatus (chap_state *, int);
static void ChapSendChallenge (chap_state *);
static void ChapSendResponse (chap_state *);
static void ChapGenChallenge (chap_state *);
/******************************/
/*** PUBLIC DATA STRUCTURES ***/
/******************************/
chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
struct protent chap_protent = {
PPP_CHAP,
ChapInit,
ChapInput,
ChapProtocolReject,
ChapLowerUp,
ChapLowerDown,
NULL,
NULL,
#if 0
ChapPrintPkt,
NULL,
#endif
1,
"CHAP",
#if 0
NULL,
NULL,
NULL
#endif
};
/*****************************/
/*** LOCAL DATA STRUCTURES ***/
/*****************************/
static char *ChapCodenames[] = {
"Challenge", "Response", "Success", "Failure"
};
/***********************************/
/*** PUBLIC FUNCTION DEFINITIONS ***/
/***********************************/
/*
* ChapAuthWithPeer - Authenticate us with our peer (start client).
*
*/
void ChapAuthWithPeer(int unit, char *our_name, int digest)
{
chap_state *cstate = &chap[unit];
cstate->resp_name = our_name;
cstate->resp_type = digest;
if (cstate->clientstate == CHAPCS_INITIAL ||
cstate->clientstate == CHAPCS_PENDING) {
/* lower layer isn't up - wait until later */
cstate->clientstate = CHAPCS_PENDING;
return;
}
/*
* We get here as a result of LCP coming up.
* So even if CHAP was open before, we will
* have to re-authenticate ourselves.
*/
cstate->clientstate = CHAPCS_LISTEN;
}
/*
* ChapAuthPeer - Authenticate our peer (start server).
*/
void ChapAuthPeer(int unit, char *our_name, int digest)
{
chap_state *cstate = &chap[unit];
cstate->chal_name = our_name;
cstate->chal_type = digest;
if (cstate->serverstate == CHAPSS_INITIAL ||
cstate->serverstate == CHAPSS_PENDING) {
/* lower layer isn't up - wait until later */
cstate->serverstate = CHAPSS_PENDING;
return;
}
ChapGenChallenge(cstate);
ChapSendChallenge(cstate); /* crank it up dude! */
cstate->serverstate = CHAPSS_INITIAL_CHAL;
}
/**********************************/
/*** LOCAL FUNCTION DEFINITIONS ***/
/**********************************/
/*
* ChapInit - Initialize a CHAP unit.
*/
static void ChapInit(int unit)
{
chap_state *cstate = &chap[unit];
BZERO(cstate, sizeof(*cstate));
cstate->unit = unit;
cstate->clientstate = CHAPCS_INITIAL;
cstate->serverstate = CHAPSS_INITIAL;
cstate->timeouttime = CHAP_DEFTIMEOUT;
cstate->max_transmits = CHAP_DEFTRANSMITS;
/* random number generator is initialized in magic_init */
}
/*
* ChapChallengeTimeout - Timeout expired on sending challenge.
*/
static void ChapChallengeTimeout(void *arg)
{
chap_state *cstate = (chap_state *) arg;
/* if we aren't sending challenges, don't worry. then again we */
/* probably shouldn't be here either */
if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
cstate->serverstate != CHAPSS_RECHALLENGE)
return;
if (cstate->chal_transmits >= cstate->max_transmits) {
/* give up on peer */
CHAPDEBUG((LOG_ERR, "Peer failed to respond to CHAP challenge\n"));
cstate->serverstate = CHAPSS_BADAUTH;
auth_peer_fail(cstate->unit, PPP_CHAP);
return;
}
ChapSendChallenge(cstate); /* Re-send challenge */
}
/*
* ChapResponseTimeout - Timeout expired on sending response.
*/
static void ChapResponseTimeout(void *arg)
{
chap_state *cstate = (chap_state *) arg;
/* if we aren't sending a response, don't worry. */
if (cstate->clientstate != CHAPCS_RESPONSE)
return;
ChapSendResponse(cstate); /* re-send response */
}
/*
* ChapRechallenge - Time to challenge the peer again.
*/
static void ChapRechallenge(void *arg)
{
chap_state *cstate = (chap_state *) arg;
/* if we aren't sending a response, don't worry. */
if (cstate->serverstate != CHAPSS_OPEN)
return;
ChapGenChallenge(cstate);
ChapSendChallenge(cstate);
cstate->serverstate = CHAPSS_RECHALLENGE;
}
/*
* ChapLowerUp - The lower layer is up.
*
* Start up if we have pending requests.
*/
static void ChapLowerUp(int unit)
{
chap_state *cstate = &chap[unit];
if (cstate->clientstate == CHAPCS_INITIAL)
cstate->clientstate = CHAPCS_CLOSED;
else if (cstate->clientstate == CHAPCS_PENDING)
cstate->clientstate = CHAPCS_LISTEN;
if (cstate->serverstate == CHAPSS_INITIAL)
cstate->serverstate = CHAPSS_CLOSED;
else if (cstate->serverstate == CHAPSS_PENDING) {
ChapGenChallenge(cstate);
ChapSendChallenge(cstate);
cstate->serverstate = CHAPSS_INITIAL_CHAL;
}
}
/*
* ChapLowerDown - The lower layer is down.
*
* Cancel all timeouts.
*/
static void ChapLowerDown(int unit)
{
chap_state *cstate = &chap[unit];
/* Timeout(s) pending? Cancel if so. */
if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
cstate->serverstate == CHAPSS_RECHALLENGE)
UNTIMEOUT(ChapChallengeTimeout, cstate);
else if (cstate->serverstate == CHAPSS_OPEN
&& cstate->chal_interval != 0)
UNTIMEOUT(ChapRechallenge, cstate);
if (cstate->clientstate == CHAPCS_RESPONSE)
UNTIMEOUT(ChapResponseTimeout, cstate);
cstate->clientstate = CHAPCS_INITIAL;
cstate->serverstate = CHAPSS_INITIAL;
}
/*
* ChapProtocolReject - Peer doesn't grok CHAP.
*/
static void ChapProtocolReject(int unit)
{
chap_state *cstate = &chap[unit];
if (cstate->serverstate != CHAPSS_INITIAL &&
cstate->serverstate != CHAPSS_CLOSED)
auth_peer_fail(unit, PPP_CHAP);
if (cstate->clientstate != CHAPCS_INITIAL &&
cstate->clientstate != CHAPCS_CLOSED)
auth_withpeer_fail(unit, PPP_CHAP);
ChapLowerDown(unit); /* shutdown chap */
}
/*
* ChapInput - Input CHAP packet.
*/
static void ChapInput(int unit, u_char *inpacket, int packet_len)
{
chap_state *cstate = &chap[unit];
u_char *inp;
u_char code, id;
int len;
/*
* Parse header (code, id and length).
* If packet too short, drop it.
*/
inp = inpacket;
if (packet_len < CHAP_HEADERLEN) {
CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.\n"));
return;
}
GETCHAR(code, inp);
GETCHAR(id, inp);
GETSHORT(len, inp);
if (len < CHAP_HEADERLEN) {
CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.\n"));
return;
}
if (len > packet_len) {
CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.\n"));
return;
}
len -= CHAP_HEADERLEN;
/*
* Action depends on code (as in fact it usually does :-).
*/
switch (code) {
case CHAP_CHALLENGE:
ChapReceiveChallenge(cstate, inp, id, len);
break;
case CHAP_RESPONSE:
ChapReceiveResponse(cstate, inp, id, len);
break;
case CHAP_FAILURE:
ChapReceiveFailure(cstate, inp, id, len);
break;
case CHAP_SUCCESS:
ChapReceiveSuccess(cstate, inp, id, len);
break;
default: /* Need code reject? */
CHAPDEBUG((LOG_WARNING, "Unknown CHAP code (%d) received.\n", code));
break;
}
}
/*
* ChapReceiveChallenge - Receive Challenge and send Response.
*/
static void ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len)
{
int rchallenge_len;
u_char *rchallenge;
int secret_len;
char secret[MAXSECRETLEN];
char rhostname[256];
MD5_CTX mdContext;
u_char hash[MD5_SIGNATURE_SIZE];
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.\n", id));
if (cstate->clientstate == CHAPCS_CLOSED ||
cstate->clientstate == CHAPCS_PENDING) {
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d\n",
cstate->clientstate));
return;
}
if (len < 2) {
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));
return;
}
GETCHAR(rchallenge_len, inp);
len -= sizeof (u_char) + rchallenge_len; /* now name field length */
if (len < 0) {
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));
return;
}
rchallenge = inp;
INCPTR(rchallenge_len, inp);
if (len >= sizeof(rhostname))
len = sizeof(rhostname) - 1;
BCOPY(inp, rhostname, len);
rhostname[len] = '\000';
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'\n",
rhostname));
/* Microsoft doesn't send their name back in the PPP packet */
if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {
strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));
rhostname[sizeof(rhostname) - 1] = 0;
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name\n",
rhostname));
}
/* get secret for authenticating ourselves with the specified host */
if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
secret, &secret_len, 0)) {
secret_len = 0; /* assume null secret if can't find one */
CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating us to %s\n", rhostname));
}
/* cancel response send timeout if necessary */
if (cstate->clientstate == CHAPCS_RESPONSE)
UNTIMEOUT(ChapResponseTimeout, cstate);
cstate->resp_id = id;
cstate->resp_transmits = 0;
/* generate MD based on negotiated type */
switch (cstate->resp_type) {
case CHAP_DIGEST_MD5:
MD5Init(&mdContext);
MD5Update(&mdContext, &cstate->resp_id, 1);
MD5Update(&mdContext, (u_char*)secret, secret_len);
MD5Update(&mdContext, rchallenge, rchallenge_len);
MD5Final(hash, &mdContext);
BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
cstate->resp_length = MD5_SIGNATURE_SIZE;
break;
#ifdef CHAPMS
case CHAP_MICROSOFT:
ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
break;
#endif
default:
CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->resp_type));
return;
}
BZERO(secret, sizeof(secret));
ChapSendResponse(cstate);
}
/*
* ChapReceiveResponse - Receive and process response.
*/
static void ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
{
u_char *remmd, remmd_len;
int secret_len, old_state;
int code;
char rhostname[256];
MD5_CTX mdContext;
char secret[MAXSECRETLEN];
u_char hash[MD5_SIGNATURE_SIZE];
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.\n", id));
if (cstate->serverstate == CHAPSS_CLOSED ||
cstate->serverstate == CHAPSS_PENDING) {
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d\n",
cstate->serverstate));
return;
}
if (id != cstate->chal_id)
return; /* doesn't match ID of last challenge */
/*
* If we have received a duplicate or bogus Response,
* we have to send the same answer (Success/Failure)
* as we did for the first Response we saw.
*/
if (cstate->serverstate == CHAPSS_OPEN) {
ChapSendStatus(cstate, CHAP_SUCCESS);
return;
}
if (cstate->serverstate == CHAPSS_BADAUTH) {
ChapSendStatus(cstate, CHAP_FAILURE);
return;
}
if (len < 2) {
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));
return;
}
GETCHAR(remmd_len, inp); /* get length of MD */
remmd = inp; /* get pointer to MD */
INCPTR(remmd_len, inp);
len -= sizeof (u_char) + remmd_len;
if (len < 0) {
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));
return;
}
UNTIMEOUT(ChapChallengeTimeout, cstate);
if (len >= sizeof(rhostname))
len = sizeof(rhostname) - 1;
BCOPY(inp, rhostname, len);
rhostname[len] = '\000';
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s\n",
rhostname));
/*
* Get secret for authenticating them with us,
* do the hash ourselves, and compare the result.
*/
code = CHAP_FAILURE;
if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
secret, &secret_len, 1)) {
/* CHAPDEBUG((LOG_WARNING, TL_CHAP, "No CHAP secret found for authenticating %s\n", rhostname)); */
CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating %s\n",
rhostname));
} else {
/* generate MD based on negotiated type */
switch (cstate->chal_type) {
case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
if (remmd_len != MD5_SIGNATURE_SIZE)
break; /* it's not even the right length */
MD5Init(&mdContext);
MD5Update(&mdContext, &cstate->chal_id, 1);
MD5Update(&mdContext, (u_char*)secret, secret_len);
MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
MD5Final(hash, &mdContext);
/* compare local and remote MDs and send the appropriate status */
if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
code = CHAP_SUCCESS; /* they are the same! */
break;
default:
CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->chal_type));
}
}
BZERO(secret, sizeof(secret));
ChapSendStatus(cstate, code);
if (code == CHAP_SUCCESS) {
old_state = cstate->serverstate;
cstate->serverstate = CHAPSS_OPEN;
if (old_state == CHAPSS_INITIAL_CHAL) {
auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
}
if (cstate->chal_interval != 0)
TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
} else {
CHAPDEBUG((LOG_ERR, "CHAP peer authentication failed\n"));
cstate->serverstate = CHAPSS_BADAUTH;
auth_peer_fail(cstate->unit, PPP_CHAP);
}
}
/*
* ChapReceiveSuccess - Receive Success
*/
static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)
{
CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.\n", id));
if (cstate->clientstate == CHAPCS_OPEN)
/* presumably an answer to a duplicate response */
return;
if (cstate->clientstate != CHAPCS_RESPONSE) {
/* don't know what this is */
CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n",
cstate->clientstate));
return;
}
UNTIMEOUT(ChapResponseTimeout, cstate);
/*
* Print message.
*/
if (len > 0)
PRINTMSG(inp, len);
cstate->clientstate = CHAPCS_OPEN;
auth_withpeer_success(cstate->unit, PPP_CHAP);
}
/*
* ChapReceiveFailure - Receive failure.
*/
static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)
{
CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.\n", id));
if (cstate->clientstate != CHAPCS_RESPONSE) {
/* don't know what this is */
CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n",
cstate->clientstate));
return;
}
UNTIMEOUT(ChapResponseTimeout, cstate);
/*
* Print message.
*/
if (len > 0)
PRINTMSG(inp, len);
CHAPDEBUG((LOG_ERR, "CHAP authentication failed\n"));
auth_withpeer_fail(cstate->unit, PPP_CHAP);
}
/*
* ChapSendChallenge - Send an Authenticate challenge.
*/
static void ChapSendChallenge(chap_state *cstate)
{
u_char *outp;
int chal_len, name_len;
int outlen;
chal_len = cstate->chal_len;
name_len = strlen(cstate->chal_name);
outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
outp = outpacket_buf[cstate->unit];
MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */
PUTCHAR(CHAP_CHALLENGE, outp);
PUTCHAR(cstate->chal_id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(chal_len, outp); /* put length of challenge */
BCOPY(cstate->challenge, outp, chal_len);
INCPTR(chal_len, outp);
BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.\n", cstate->chal_id));
TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
++cstate->chal_transmits;
}
/*
* ChapSendStatus - Send a status response (ack or nak).
*/
static void ChapSendStatus(chap_state *cstate, int code)
{
u_char *outp;
int outlen, msglen;
char msg[256];
if (code == CHAP_SUCCESS)
strcpy(msg, "Welcome!");
else
strcpy(msg, "I don't like you. Go 'way.");
msglen = strlen(msg);
outlen = CHAP_HEADERLEN + msglen;
outp = outpacket_buf[cstate->unit];
MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
PUTCHAR(code, outp);
PUTCHAR(cstate->chal_id, outp);
PUTSHORT(outlen, outp);
BCOPY(msg, outp, msglen);
pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.\n", code,
cstate->chal_id));
}
/*
* ChapGenChallenge is used to generate a pseudo-random challenge string of
* a pseudo-random length between min_len and max_len. The challenge
* string and its length are stored in *cstate, and various other fields of
* *cstate are initialized.
*/
static void ChapGenChallenge(chap_state *cstate)
{
int chal_len;
u_char *ptr = cstate->challenge;
int i;
/* pick a random challenge length between MIN_CHALLENGE_LENGTH and
MAX_CHALLENGE_LENGTH */
chal_len = (unsigned)
((((magic() >> 16) *
(MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)
+ MIN_CHALLENGE_LENGTH);
cstate->chal_len = chal_len;
cstate->chal_id = ++cstate->id;
cstate->chal_transmits = 0;
/* generate a random string */
for (i = 0; i < chal_len; i++ )
*ptr++ = (char) (magic() & 0xff);
}
/*
* ChapSendResponse - send a response packet with values as specified
* in *cstate.
*/
/* ARGSUSED */
static void ChapSendResponse(chap_state *cstate)
{
u_char *outp;
int outlen, md_len, name_len;
md_len = cstate->resp_length;
name_len = strlen(cstate->resp_name);
outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
outp = outpacket_buf[cstate->unit];
MAKEHEADER(outp, PPP_CHAP);
PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
PUTSHORT(outlen, outp); /* packet length */
PUTCHAR(md_len, outp); /* length of MD */
BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
INCPTR(md_len, outp);
BCOPY(cstate->resp_name, outp, name_len); /* append our name */
/* send the packet */
pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
cstate->clientstate = CHAPCS_RESPONSE;
TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
++cstate->resp_transmits;
}
/*
* ChapPrintPkt - print the contents of a CHAP packet.
*/
static int ChapPrintPkt(
u_char *p,
int plen,
void (*printer) (void *, char *, ...),
void *arg
)
{
int code, id, len;
int clen, nlen;
u_char x;
if (plen < CHAP_HEADERLEN)
return 0;
GETCHAR(code, p);
GETCHAR(id, p);
GETSHORT(len, p);
if (len < CHAP_HEADERLEN || len > plen)
return 0;
if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
printer(arg, " %s", ChapCodenames[code-1]);
else
printer(arg, " code=0x%x", code);
printer(arg, " id=0x%x", id);
len -= CHAP_HEADERLEN;
switch (code) {
case CHAP_CHALLENGE:
case CHAP_RESPONSE:
if (len < 1)
break;
clen = p[0];
if (len < clen + 1)
break;
++p;
nlen = len - clen - 1;
printer(arg, " <");
for (; clen > 0; --clen) {
GETCHAR(x, p);
printer(arg, "%.2x", x);
}
printer(arg, ">, name = %.*Z", nlen, p);
break;
case CHAP_FAILURE:
case CHAP_SUCCESS:
printer(arg, " %.*Z", len, p);
break;
default:
for (clen = len; clen > 0; --clen) {
GETCHAR(x, p);
printer(arg, " %.2x", x);
}
}
return len + CHAP_HEADERLEN;
}
#endif
#endif /* PPP_SUPPORT */

View file

@ -0,0 +1,167 @@
/*****************************************************************************
* chap.h - Network Challenge Handshake Authentication Protocol header file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* portions Copyright (c) 1998 Global Election Systems Inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 97-12-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
* Original built from BSD network code.
******************************************************************************/
/*
* chap.h - Challenge Handshake Authentication Protocol definitions.
*
* Copyright (c) 1993 The Australian National University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the Australian National University. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Copyright (c) 1991 Gregory M. Christy
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the author.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: chap.h,v 1.1 2003/05/27 14:37:56 jani Exp $
*/
#ifndef CHAP_H
#define CHAP_H
/*************************
*** PUBLIC DEFINITIONS ***
*************************/
/* Code + ID + length */
#define CHAP_HEADERLEN 4
/*
* CHAP codes.
*/
#define CHAP_DIGEST_MD5 5 /* use MD5 algorithm */
#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */
#define CHAP_MICROSOFT 0x80 /* use Microsoft-compatible alg. */
#define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */
#define CHAP_CHALLENGE 1
#define CHAP_RESPONSE 2
#define CHAP_SUCCESS 3
#define CHAP_FAILURE 4
/*
* Challenge lengths (for challenges we send) and other limits.
*/
#define MIN_CHALLENGE_LENGTH 32
#define MAX_CHALLENGE_LENGTH 64
#define MAX_RESPONSE_LENGTH 64 /* sufficient for MD5 or MS-CHAP */
/*
* Client (peer) states.
*/
#define CHAPCS_INITIAL 0 /* Lower layer down, not opened */
#define CHAPCS_CLOSED 1 /* Lower layer up, not opened */
#define CHAPCS_PENDING 2 /* Auth us to peer when lower up */
#define CHAPCS_LISTEN 3 /* Listening for a challenge */
#define CHAPCS_RESPONSE 4 /* Sent response, waiting for status */
#define CHAPCS_OPEN 5 /* We've received Success */
/*
* Server (authenticator) states.
*/
#define CHAPSS_INITIAL 0 /* Lower layer down, not opened */
#define CHAPSS_CLOSED 1 /* Lower layer up, not opened */
#define CHAPSS_PENDING 2 /* Auth peer when lower up */
#define CHAPSS_INITIAL_CHAL 3 /* We've sent the first challenge */
#define CHAPSS_OPEN 4 /* We've sent a Success msg */
#define CHAPSS_RECHALLENGE 5 /* We've sent another challenge */
#define CHAPSS_BADAUTH 6 /* We've sent a Failure msg */
/************************
*** PUBLIC DATA TYPES ***
************************/
/*
* Each interface is described by a chap structure.
*/
typedef struct chap_state {
int unit; /* Interface unit number */
int clientstate; /* Client state */
int serverstate; /* Server state */
u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */
u_char chal_len; /* challenge length */
u_char chal_id; /* ID of last challenge */
u_char chal_type; /* hash algorithm for challenges */
u_char id; /* Current id */
char *chal_name; /* Our name to use with challenge */
int chal_interval; /* Time until we challenge peer again */
int timeouttime; /* Timeout time in seconds */
int max_transmits; /* Maximum # of challenge transmissions */
int chal_transmits; /* Number of transmissions of challenge */
int resp_transmits; /* Number of transmissions of response */
u_char response[MAX_RESPONSE_LENGTH]; /* Response to send */
u_char resp_length; /* length of response */
u_char resp_id; /* ID for response messages */
u_char resp_type; /* hash algorithm for responses */
char *resp_name; /* Our name to send with response */
} chap_state;
/******************
*** PUBLIC DATA ***
******************/
extern chap_state chap[];
extern struct protent chap_protent;
/***********************
*** PUBLIC FUNCTIONS ***
***********************/
void ChapAuthWithPeer (int, char *, int);
void ChapAuthPeer (int, char *, int);
#endif /* CHAP_H */

View file

@ -0,0 +1,398 @@
/*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/
/*****************************************************************************
* chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* Copyright (c) 1997 by Global Election Systems Inc. All rights reserved.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
* Original based on BSD chap_ms.c.
*****************************************************************************/
/*
* chap_ms.c - Microsoft MS-CHAP compatible implementation.
*
* Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
* http://www.strataware.com/
*
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Eric Rosenquist. The name of the author may not be used to
* endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
* Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
*
* Implemented LANManager type password response to MS-CHAP challenges.
* Now pppd provides both NT style and LANMan style blocks, and the
* prefered is set by option "ms-lanman". Default is to use NT.
* The hash text (StdText) was taken from Win95 RASAPI32.DLL.
*
* You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
*/
#define USE_CRYPT
#include "ppp.h"
#if MSCHAP_SUPPORT > 0
#include "md4.h"
#ifndef USE_CRYPT
#include "des.h"
#endif
#include "chap.h"
#include "chpms.h"
#include "pppdebug.h"
/*************************/
/*** LOCAL DEFINITIONS ***/
/*************************/
/************************/
/*** LOCAL DATA TYPES ***/
/************************/
typedef struct {
u_char LANManResp[24];
u_char NTResp[24];
u_char UseNT; /* If 1, ignore the LANMan response field */
} MS_ChapResponse;
/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
in case this struct gets padded. */
/***********************************/
/*** LOCAL FUNCTION DECLARATIONS ***/
/***********************************/
/* XXX Don't know what to do with these. */
extern void setkey(const char *);
extern void encrypt(char *, int);
static void DesEncrypt (u_char *, u_char *, u_char *);
static void MakeKey (u_char *, u_char *);
#ifdef USE_CRYPT
static void Expand (u_char *, u_char *);
static void Collapse (u_char *, u_char *);
#endif
static void ChallengeResponse(
u_char *challenge, /* IN 8 octets */
u_char *pwHash, /* IN 16 octets */
u_char *response /* OUT 24 octets */
);
static void ChapMS_NT(
char *rchallenge,
int rchallenge_len,
char *secret,
int secret_len,
MS_ChapResponse *response
);
static u_char Get7Bits(
u_char *input,
int startBit
);
/***********************************/
/*** PUBLIC FUNCTION DEFINITIONS ***/
/***********************************/
void ChapMS(
chap_state *cstate,
char *rchallenge,
int rchallenge_len,
char *secret,
int secret_len
)
{
MS_ChapResponse response;
#ifdef MSLANMAN
extern int ms_lanman;
#endif
#if 0
CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'\n", secret_len, secret));
#endif
BZERO(&response, sizeof(response));
/* Calculate both always */
ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
#ifdef MSLANMAN
ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
/* prefered method is set by option */
response.UseNT = !ms_lanman;
#else
response.UseNT = 1;
#endif
BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
cstate->resp_length = MS_CHAP_RESPONSE_LEN;
}
/**********************************/
/*** LOCAL FUNCTION DEFINITIONS ***/
/**********************************/
static void ChallengeResponse(
u_char *challenge, /* IN 8 octets */
u_char *pwHash, /* IN 16 octets */
u_char *response /* OUT 24 octets */
)
{
char ZPasswordHash[21];
BZERO(ZPasswordHash, sizeof(ZPasswordHash));
BCOPY(pwHash, ZPasswordHash, 16);
#if 0
log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);
#endif
DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
DesEncrypt(challenge, ZPasswordHash + 7, response + 8);
DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
#if 0
log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);
#endif
}
#ifdef USE_CRYPT
static void DesEncrypt(
u_char *clear, /* IN 8 octets */
u_char *key, /* IN 7 octets */
u_char *cipher /* OUT 8 octets */
)
{
u_char des_key[8];
u_char crypt_key[66];
u_char des_input[66];
MakeKey(key, des_key);
Expand(des_key, crypt_key);
setkey(crypt_key);
#if 0
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
#endif
Expand(clear, des_input);
encrypt(des_input, 0);
Collapse(des_input, cipher);
#if 0
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
#endif
}
#else /* USE_CRYPT */
static void DesEncrypt(
u_char *clear, /* IN 8 octets */
u_char *key, /* IN 7 octets */
u_char *cipher /* OUT 8 octets */
)
{
des_cblock des_key;
des_key_schedule key_schedule;
MakeKey(key, des_key);
des_set_key(&des_key, key_schedule);
#if 0
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
#endif
des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
#if 0
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
#endif
}
#endif /* USE_CRYPT */
static u_char Get7Bits(
u_char *input,
int startBit
)
{
register unsigned int word;
word = (unsigned)input[startBit / 8] << 8;
word |= (unsigned)input[startBit / 8 + 1];
word >>= 15 - (startBit % 8 + 7);
return word & 0xFE;
}
#ifdef USE_CRYPT
/* in == 8-byte string (expanded version of the 56-bit key)
* out == 64-byte string where each byte is either 1 or 0
* Note that the low-order "bit" is always ignored by by setkey()
*/
static void Expand(u_char *in, u_char *out)
{
int j, c;
int i;
for(i = 0; i < 64; in++){
c = *in;
for(j = 7; j >= 0; j--)
*out++ = (c >> j) & 01;
i += 8;
}
}
/* The inverse of Expand
*/
static void Collapse(u_char *in, u_char *out)
{
int j;
int i;
unsigned int c;
for (i = 0; i < 64; i += 8, out++) {
c = 0;
for (j = 7; j >= 0; j--, in++)
c |= *in << j;
*out = c & 0xff;
}
}
#endif
static void MakeKey(
u_char *key, /* IN 56 bit DES key missing parity bits */
u_char *des_key /* OUT 64 bit DES key with parity bits added */
)
{
des_key[0] = Get7Bits(key, 0);
des_key[1] = Get7Bits(key, 7);
des_key[2] = Get7Bits(key, 14);
des_key[3] = Get7Bits(key, 21);
des_key[4] = Get7Bits(key, 28);
des_key[5] = Get7Bits(key, 35);
des_key[6] = Get7Bits(key, 42);
des_key[7] = Get7Bits(key, 49);
#ifndef USE_CRYPT
des_set_odd_parity((des_cblock *)des_key);
#endif
#if 0
CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n",
key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
#endif
}
static void ChapMS_NT(
char *rchallenge,
int rchallenge_len,
char *secret,
int secret_len,
MS_ChapResponse *response
)
{
int i;
MDstruct md4Context;
u_char unicodePassword[MAX_NT_PASSWORD * 2];
static int low_byte_first = -1;
/* Initialize the Unicode version of the secret (== password). */
/* This implicitly supports 8-bit ISO8859/1 characters. */
BZERO(unicodePassword, sizeof(unicodePassword));
for (i = 0; i < secret_len; i++)
unicodePassword[i * 2] = (u_char)secret[i];
MDbegin(&md4Context);
MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8); /* Unicode is 2 bytes/char, *8 for bit count */
if (low_byte_first == -1)
low_byte_first = (htons((unsigned short int)1) != 1);
if (low_byte_first == 0)
MDreverse((u_long *)&md4Context); /* sfb 961105 */
MDupdate(&md4Context, NULL, 0); /* Tell MD4 we're done */
ChallengeResponse(rchallenge, (char *)md4Context.buffer, response->NTResp);
}
#ifdef MSLANMAN
static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
static ChapMS_LANMan(
char *rchallenge,
int rchallenge_len,
char *secret,
int secret_len,
MS_ChapResponse *response
)
{
int i;
u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
u_char PasswordHash[16];
/* LANMan password is case insensitive */
BZERO(UcasePassword, sizeof(UcasePassword));
for (i = 0; i < secret_len; i++)
UcasePassword[i] = (u_char)toupper(secret[i]);
DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
}
#endif
#endif /* MSCHAP_SUPPORT */

View file

@ -0,0 +1,64 @@
/*****************************************************************************
* chpms.h - Network Microsoft Challenge Handshake Protocol header file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* portions Copyright (c) 1998 Global Election Systems Inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 98-01-30 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
* Original built from BSD network code.
******************************************************************************/
/*
* chap.h - Challenge Handshake Authentication Protocol definitions.
*
* Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
* http://www.strataware.com/
*
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Eric Rosenquist. The name of the author may not be used to
* endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: chpms.h,v 1.3 2004/02/07 00:30:03 likewise Exp $
*/
#ifndef CHPMS_H
#define CHPMS_H
#define MAX_NT_PASSWORD 256 /* Maximum number of (Unicode) chars in an NT password */
void ChapMS (chap_state *, char *, int, char *, int);
#endif /* CHPMS_H */

View file

@ -0,0 +1,838 @@
/*****************************************************************************
* fsm.c - Network Control Protocol Finite State Machine program file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* portions Copyright (c) 1997 by Global Election Systems Inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
* Original based on BSD fsm.c.
*****************************************************************************/
/*
* fsm.c - {Link, IP} Control Protocol Finite State Machine.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
* TODO:
* Randomize fsm id on link/init.
* Deal with variable outgoing MTU.
*/
#include "ppp.h"
#if PPP_SUPPORT > 0
#include "fsm.h"
#include "pppdebug.h"
/*************************/
/*** LOCAL DEFINITIONS ***/
/*************************/
/************************/
/*** LOCAL DATA TYPES ***/
/************************/
/***********************************/
/*** LOCAL FUNCTION DECLARATIONS ***/
/***********************************/
static void fsm_timeout (void *);
static void fsm_rconfreq (fsm *, u_char, u_char *, int);
static void fsm_rconfack (fsm *, int, u_char *, int);
static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);
static void fsm_rtermreq (fsm *, int, u_char *, int);
static void fsm_rtermack (fsm *);
static void fsm_rcoderej (fsm *, u_char *, int);
static void fsm_sconfreq (fsm *, int);
#define PROTO_NAME(f) ((f)->callbacks->proto_name)
/******************************/
/*** PUBLIC DATA STRUCTURES ***/
/******************************/
/*****************************/
/*** LOCAL DATA STRUCTURES ***/
/*****************************/
int peer_mru[NUM_PPP];
/***********************************/
/*** PUBLIC FUNCTION DEFINITIONS ***/
/***********************************/
/*
* fsm_init - Initialize fsm.
*
* Initialize fsm state.
*/
void fsm_init(fsm *f)
{
f->state = INITIAL;
f->flags = 0;
f->id = 0; /* XXX Start with random id? */
f->timeouttime = FSM_DEFTIMEOUT;
f->maxconfreqtransmits = FSM_DEFMAXCONFREQS;
f->maxtermtransmits = FSM_DEFMAXTERMREQS;
f->maxnakloops = FSM_DEFMAXNAKLOOPS;
f->term_reason_len = 0;
}
/*
* fsm_lowerup - The lower layer is up.
*/
void fsm_lowerup(fsm *f)
{
int oldState = f->state;
switch( f->state ){
case INITIAL:
f->state = CLOSED;
break;
case STARTING:
if( f->flags & OPT_SILENT )
f->state = STOPPED;
else {
/* Send an initial configure-request */
fsm_sconfreq(f, 0);
f->state = REQSENT;
}
break;
default:
FSMDEBUG((LOG_INFO, "%s: Up event in state %d!\n",
PROTO_NAME(f), f->state));
}
FSMDEBUG((LOG_INFO, "%s: lowerup state %d -> %d\n",
PROTO_NAME(f), oldState, f->state));
}
/*
* fsm_lowerdown - The lower layer is down.
*
* Cancel all timeouts and inform upper layers.
*/
void fsm_lowerdown(fsm *f)
{
int oldState = f->state;
switch( f->state ){
case CLOSED:
f->state = INITIAL;
break;
case STOPPED:
f->state = STARTING;
if( f->callbacks->starting )
(*f->callbacks->starting)(f);
break;
case CLOSING:
f->state = INITIAL;
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
break;
case STOPPING:
case REQSENT:
case ACKRCVD:
case ACKSENT:
f->state = STARTING;
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
break;
case OPENED:
if( f->callbacks->down )
(*f->callbacks->down)(f);
f->state = STARTING;
break;
default:
FSMDEBUG((LOG_INFO, "%s: Down event in state %d!\n",
PROTO_NAME(f), f->state));
}
FSMDEBUG((LOG_INFO, "%s: lowerdown state %d -> %d\n",
PROTO_NAME(f), oldState, f->state));
}
/*
* fsm_open - Link is allowed to come up.
*/
void fsm_open(fsm *f)
{
int oldState = f->state;
switch( f->state ){
case INITIAL:
f->state = STARTING;
if( f->callbacks->starting )
(*f->callbacks->starting)(f);
break;
case CLOSED:
if( f->flags & OPT_SILENT )
f->state = STOPPED;
else {
/* Send an initial configure-request */
fsm_sconfreq(f, 0);
f->state = REQSENT;
}
break;
case CLOSING:
f->state = STOPPING;
/* fall through */
case STOPPED:
case OPENED:
if( f->flags & OPT_RESTART ){
fsm_lowerdown(f);
fsm_lowerup(f);
}
break;
}
FSMDEBUG((LOG_INFO, "%s: open state %d -> %d\n",
PROTO_NAME(f), oldState, f->state));
}
/*
* fsm_close - Start closing connection.
*
* Cancel timeouts and either initiate close or possibly go directly to
* the CLOSED state.
*/
void fsm_close(fsm *f, char *reason)
{
int oldState = f->state;
f->term_reason = reason;
f->term_reason_len = (reason == NULL? 0: strlen(reason));
switch( f->state ){
case STARTING:
f->state = INITIAL;
break;
case STOPPED:
f->state = CLOSED;
break;
case STOPPING:
f->state = CLOSING;
break;
case REQSENT:
case ACKRCVD:
case ACKSENT:
case OPENED:
if( f->state != OPENED )
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
else if( f->callbacks->down )
(*f->callbacks->down)(f); /* Inform upper layers we're down */
/* Init restart counter, send Terminate-Request */
f->retransmits = f->maxtermtransmits;
fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
(u_char *) f->term_reason, f->term_reason_len);
TIMEOUT(fsm_timeout, f, f->timeouttime);
--f->retransmits;
f->state = CLOSING;
break;
}
FSMDEBUG((LOG_INFO, "%s: close reason=%s state %d -> %d\n",
PROTO_NAME(f), reason, oldState, f->state));
}
/*
* fsm_sdata - Send some data.
*
* Used for all packets sent to our peer by this module.
*/
void fsm_sdata(
fsm *f,
u_char code,
u_char id,
u_char *data,
int datalen
)
{
u_char *outp;
int outlen;
/* Adjust length to be smaller than MTU */
outp = outpacket_buf[f->unit];
if (datalen > peer_mru[f->unit] - (int)HEADERLEN)
datalen = peer_mru[f->unit] - HEADERLEN;
if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)
BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
outlen = datalen + HEADERLEN;
MAKEHEADER(outp, f->protocol);
PUTCHAR(code, outp);
PUTCHAR(id, outp);
PUTSHORT(outlen, outp);
pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);
FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d,%d,%d.\n",
PROTO_NAME(f), code, id, outlen));
}
/*
* fsm_input - Input packet.
*/
void fsm_input(fsm *f, u_char *inpacket, int l)
{
u_char *inp = inpacket;
u_char code, id;
int len;
/*
* Parse header (code, id and length).
* If packet too short, drop it.
*/
if (l < HEADERLEN) {
FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.\n",
f->protocol));
return;
}
GETCHAR(code, inp);
GETCHAR(id, inp);
GETSHORT(len, inp);
if (len < HEADERLEN) {
FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.\n",
f->protocol));
return;
}
if (len > l) {
FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.\n",
f->protocol));
return;
}
len -= HEADERLEN; /* subtract header length */
if( f->state == INITIAL || f->state == STARTING ){
FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.\n",
f->protocol, f->state));
return;
}
FSMDEBUG((LOG_INFO, "fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));
/*
* Action depends on code.
*/
switch (code) {
case CONFREQ:
fsm_rconfreq(f, id, inp, len);
break;
case CONFACK:
fsm_rconfack(f, id, inp, len);
break;
case CONFNAK:
case CONFREJ:
fsm_rconfnakrej(f, code, id, inp, len);
break;
case TERMREQ:
fsm_rtermreq(f, id, inp, len);
break;
case TERMACK:
fsm_rtermack(f);
break;
case CODEREJ:
fsm_rcoderej(f, inp, len);
break;
default:
if( !f->callbacks->extcode
|| !(*f->callbacks->extcode)(f, code, id, inp, len) )
fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
break;
}
}
/*
* fsm_protreject - Peer doesn't speak this protocol.
*
* Treat this as a catastrophic error (RXJ-).
*/
void fsm_protreject(fsm *f)
{
switch( f->state ){
case CLOSING:
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
/* fall through */
case CLOSED:
f->state = CLOSED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case STOPPING:
case REQSENT:
case ACKRCVD:
case ACKSENT:
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
/* fall through */
case STOPPED:
f->state = STOPPED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case OPENED:
if( f->callbacks->down )
(*f->callbacks->down)(f);
/* Init restart counter, send Terminate-Request */
f->retransmits = f->maxtermtransmits;
fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
(u_char *) f->term_reason, f->term_reason_len);
TIMEOUT(fsm_timeout, f, f->timeouttime);
--f->retransmits;
f->state = STOPPING;
break;
default:
FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!\n",
PROTO_NAME(f), f->state));
}
}
/**********************************/
/*** LOCAL FUNCTION DEFINITIONS ***/
/**********************************/
/*
* fsm_timeout - Timeout expired.
*/
static void fsm_timeout(void *arg)
{
fsm *f = (fsm *) arg;
switch (f->state) {
case CLOSING:
case STOPPING:
if( f->retransmits <= 0 ){
FSMDEBUG((LOG_WARNING, "%s: timeout sending Terminate-Request state=%d\n",
PROTO_NAME(f), f->state));
/*
* We've waited for an ack long enough. Peer probably heard us.
*/
f->state = (f->state == CLOSING)? CLOSED: STOPPED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
} else {
FSMDEBUG((LOG_WARNING, "%s: timeout resending Terminate-Requests state=%d\n",
PROTO_NAME(f), f->state));
/* Send Terminate-Request */
fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
(u_char *) f->term_reason, f->term_reason_len);
TIMEOUT(fsm_timeout, f, f->timeouttime);
--f->retransmits;
}
break;
case REQSENT:
case ACKRCVD:
case ACKSENT:
if (f->retransmits <= 0) {
FSMDEBUG((LOG_WARNING, "%s: timeout sending Config-Requests state=%d\n",
PROTO_NAME(f), f->state));
f->state = STOPPED;
if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
(*f->callbacks->finished)(f);
} else {
FSMDEBUG((LOG_WARNING, "%s: timeout resending Config-Request state=%d\n",
PROTO_NAME(f), f->state));
/* Retransmit the configure-request */
if (f->callbacks->retransmit)
(*f->callbacks->retransmit)(f);
fsm_sconfreq(f, 1); /* Re-send Configure-Request */
if( f->state == ACKRCVD )
f->state = REQSENT;
}
break;
default:
FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!\n",
PROTO_NAME(f), f->state));
}
}
/*
* fsm_rconfreq - Receive Configure-Request.
*/
static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)
{
int code, reject_if_disagree;
FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d state=%d\n",
PROTO_NAME(f), id, f->state));
switch( f->state ){
case CLOSED:
/* Go away, we're closed */
fsm_sdata(f, TERMACK, id, NULL, 0);
return;
case CLOSING:
case STOPPING:
return;
case OPENED:
/* Go down and restart negotiation */
if( f->callbacks->down )
(*f->callbacks->down)(f); /* Inform upper layers */
fsm_sconfreq(f, 0); /* Send initial Configure-Request */
break;
case STOPPED:
/* Negotiation started by our peer */
fsm_sconfreq(f, 0); /* Send initial Configure-Request */
f->state = REQSENT;
break;
}
/*
* Pass the requested configuration options
* to protocol-specific code for checking.
*/
if (f->callbacks->reqci){ /* Check CI */
reject_if_disagree = (f->nakloops >= f->maxnakloops);
code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
}
else if (len)
code = CONFREJ; /* Reject all CI */
else
code = CONFACK;
/* send the Ack, Nak or Rej to the peer */
fsm_sdata(f, (u_char)code, id, inp, len);
if (code == CONFACK) {
if (f->state == ACKRCVD) {
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
f->state = OPENED;
if (f->callbacks->up)
(*f->callbacks->up)(f); /* Inform upper layers */
}
else
f->state = ACKSENT;
f->nakloops = 0;
}
else {
/* we sent CONFACK or CONFREJ */
if (f->state != ACKRCVD)
f->state = REQSENT;
if( code == CONFNAK )
++f->nakloops;
}
}
/*
* fsm_rconfack - Receive Configure-Ack.
*/
static void fsm_rconfack(fsm *f, int id, u_char *inp, int len)
{
FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d state=%d\n",
PROTO_NAME(f), id, f->state));
if (id != f->reqid || f->seen_ack) /* Expected id? */
return; /* Nope, toss... */
if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len):
(len == 0)) ){
/* Ack is bad - ignore it */
FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)\n",
PROTO_NAME(f), len));
return;
}
f->seen_ack = 1;
switch (f->state) {
case CLOSED:
case STOPPED:
fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
break;
case REQSENT:
f->state = ACKRCVD;
f->retransmits = f->maxconfreqtransmits;
break;
case ACKRCVD:
/* Huh? an extra valid Ack? oh well... */
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
fsm_sconfreq(f, 0);
f->state = REQSENT;
break;
case ACKSENT:
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
f->state = OPENED;
f->retransmits = f->maxconfreqtransmits;
if (f->callbacks->up)
(*f->callbacks->up)(f); /* Inform upper layers */
break;
case OPENED:
/* Go down and restart negotiation */
if (f->callbacks->down)
(*f->callbacks->down)(f); /* Inform upper layers */
fsm_sconfreq(f, 0); /* Send initial Configure-Request */
f->state = REQSENT;
break;
}
}
/*
* fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
*/
static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)
{
int (*proc) (fsm *, u_char *, int);
int ret;
FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d state=%d\n",
PROTO_NAME(f), id, f->state));
if (id != f->reqid || f->seen_ack) /* Expected id? */
return; /* Nope, toss... */
proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
if (!proc || !(ret = proc(f, inp, len))) {
/* Nak/reject is bad - ignore it */
FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)\n",
PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
return;
}
f->seen_ack = 1;
switch (f->state) {
case CLOSED:
case STOPPED:
fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
break;
case REQSENT:
case ACKSENT:
/* They didn't agree to what we wanted - try another request */
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
if (ret < 0)
f->state = STOPPED; /* kludge for stopping CCP */
else
fsm_sconfreq(f, 0); /* Send Configure-Request */
break;
case ACKRCVD:
/* Got a Nak/reject when we had already had an Ack?? oh well... */
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
fsm_sconfreq(f, 0);
f->state = REQSENT;
break;
case OPENED:
/* Go down and restart negotiation */
if (f->callbacks->down)
(*f->callbacks->down)(f); /* Inform upper layers */
fsm_sconfreq(f, 0); /* Send initial Configure-Request */
f->state = REQSENT;
break;
}
}
/*
* fsm_rtermreq - Receive Terminate-Req.
*/
static void fsm_rtermreq(fsm *f, int id, u_char *p, int len)
{
FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d state=%d\n",
PROTO_NAME(f), id, f->state));
switch (f->state) {
case ACKRCVD:
case ACKSENT:
f->state = REQSENT; /* Start over but keep trying */
break;
case OPENED:
if (len > 0) {
FSMDEBUG((LOG_INFO, "%s terminated by peer (%x)\n", PROTO_NAME(f), p));
} else {
FSMDEBUG((LOG_INFO, "%s terminated by peer\n", PROTO_NAME(f)));
}
if (f->callbacks->down)
(*f->callbacks->down)(f); /* Inform upper layers */
f->retransmits = 0;
f->state = STOPPING;
TIMEOUT(fsm_timeout, f, f->timeouttime);
break;
}
fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
}
/*
* fsm_rtermack - Receive Terminate-Ack.
*/
static void fsm_rtermack(fsm *f)
{
FSMDEBUG((LOG_INFO, "fsm_rtermack(%s): state=%d\n",
PROTO_NAME(f), f->state));
switch (f->state) {
case CLOSING:
UNTIMEOUT(fsm_timeout, f);
f->state = CLOSED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case STOPPING:
UNTIMEOUT(fsm_timeout, f);
f->state = STOPPED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case ACKRCVD:
f->state = REQSENT;
break;
case OPENED:
if (f->callbacks->down)
(*f->callbacks->down)(f); /* Inform upper layers */
fsm_sconfreq(f, 0);
break;
}
}
/*
* fsm_rcoderej - Receive an Code-Reject.
*/
static void fsm_rcoderej(fsm *f, u_char *inp, int len)
{
u_char code, id;
FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s): state=%d\n",
PROTO_NAME(f), f->state));
if (len < HEADERLEN) {
FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!\n"));
return;
}
GETCHAR(code, inp);
GETCHAR(id, inp);
FSMDEBUG((LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d\n",
PROTO_NAME(f), code, id));
if( f->state == ACKRCVD )
f->state = REQSENT;
}
/*
* fsm_sconfreq - Send a Configure-Request.
*/
static void fsm_sconfreq(fsm *f, int retransmit)
{
u_char *outp;
int cilen;
if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
/* Not currently negotiating - reset options */
if( f->callbacks->resetci )
(*f->callbacks->resetci)(f);
f->nakloops = 0;
}
if( !retransmit ){
/* New request - reset retransmission counter, use new ID */
f->retransmits = f->maxconfreqtransmits;
f->reqid = ++f->id;
}
f->seen_ack = 0;
/*
* Make up the request packet
*/
outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN;
if( f->callbacks->cilen && f->callbacks->addci ){
cilen = (*f->callbacks->cilen)(f);
if( cilen > peer_mru[f->unit] - (int)HEADERLEN )
cilen = peer_mru[f->unit] - HEADERLEN;
if (f->callbacks->addci)
(*f->callbacks->addci)(f, outp, &cilen);
} else
cilen = 0;
/* send the request to our peer */
fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
/* start the retransmit timer */
--f->retransmits;
TIMEOUT(fsm_timeout, f, f->timeouttime);
FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d\n",
PROTO_NAME(f), f->reqid));
}
#endif /* PPP_SUPPORT */

View file

@ -0,0 +1,187 @@
/*****************************************************************************
* fsm.h - Network Control Protocol Finite State Machine header file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* Copyright (c) 1997 Global Election Systems Inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
* Original based on BSD code.
*****************************************************************************/
/*
* fsm.h - {Link, IP} Control Protocol Finite State Machine definitions.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: fsm.h,v 1.1 2003/05/27 14:37:56 jani Exp $
*/
#ifndef FSM_H
#define FSM_H
/*****************************************************************************
************************* PUBLIC DEFINITIONS *********************************
*****************************************************************************/
/*
* LCP Packet header = Code, id, length.
*/
#define HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
/*
* CP (LCP, IPCP, etc.) codes.
*/
#define CONFREQ 1 /* Configuration Request */
#define CONFACK 2 /* Configuration Ack */
#define CONFNAK 3 /* Configuration Nak */
#define CONFREJ 4 /* Configuration Reject */
#define TERMREQ 5 /* Termination Request */
#define TERMACK 6 /* Termination Ack */
#define CODEREJ 7 /* Code Reject */
/*
* Link states.
*/
#define INITIAL 0 /* Down, hasn't been opened */
#define STARTING 1 /* Down, been opened */
#define CLOSED 2 /* Up, hasn't been opened */
#define STOPPED 3 /* Open, waiting for down event */
#define CLOSING 4 /* Terminating the connection, not open */
#define STOPPING 5 /* Terminating, but open */
#define REQSENT 6 /* We've sent a Config Request */
#define ACKRCVD 7 /* We've received a Config Ack */
#define ACKSENT 8 /* We've sent a Config Ack */
#define OPENED 9 /* Connection available */
/*
* Flags - indicate options controlling FSM operation
*/
#define OPT_PASSIVE 1 /* Don't die if we don't get a response */
#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */
#define OPT_SILENT 4 /* Wait for peer to speak first */
/*****************************************************************************
************************* PUBLIC DATA TYPES **********************************
*****************************************************************************/
/*
* Each FSM is described by an fsm structure and fsm callbacks.
*/
typedef struct fsm {
int unit; /* Interface unit number */
u_short protocol; /* Data Link Layer Protocol field value */
int state; /* State */
int flags; /* Contains option bits */
u_char id; /* Current id */
u_char reqid; /* Current request id */
u_char seen_ack; /* Have received valid Ack/Nak/Rej to Req */
int timeouttime; /* Timeout time in milliseconds */
int maxconfreqtransmits;/* Maximum Configure-Request transmissions */
int retransmits; /* Number of retransmissions left */
int maxtermtransmits; /* Maximum Terminate-Request transmissions */
int nakloops; /* Number of nak loops since last ack */
int maxnakloops; /* Maximum number of nak loops tolerated */
struct fsm_callbacks* callbacks;/* Callback routines */
char* term_reason; /* Reason for closing protocol */
int term_reason_len; /* Length of term_reason */
} fsm;
typedef struct fsm_callbacks {
void (*resetci) /* Reset our Configuration Information */
(fsm*);
int (*cilen) /* Length of our Configuration Information */
(fsm*);
void (*addci) /* Add our Configuration Information */
(fsm*, u_char*, int*);
int (*ackci) /* ACK our Configuration Information */
(fsm*, u_char*, int);
int (*nakci) /* NAK our Configuration Information */
(fsm*, u_char*, int);
int (*rejci) /* Reject our Configuration Information */
(fsm*, u_char*, int);
int (*reqci) /* Request peer's Configuration Information */
(fsm*, u_char*, int*, int);
void (*up) /* Called when fsm reaches OPENED state */
(fsm*);
void (*down) /* Called when fsm leaves OPENED state */
(fsm*);
void (*starting) /* Called when we want the lower layer */
(fsm*);
void (*finished) /* Called when we don't want the lower layer */
(fsm*);
void (*protreject) /* Called when Protocol-Reject received */
(int);
void (*retransmit) /* Retransmission is necessary */
(fsm*);
int (*extcode) /* Called when unknown code received */
(fsm*, int, u_char, u_char*, int);
char *proto_name; /* String name for protocol (for messages) */
} fsm_callbacks;
/*****************************************************************************
*********************** PUBLIC DATA STRUCTURES *******************************
*****************************************************************************/
/*
* Variables
*/
extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */
/*****************************************************************************
************************** PUBLIC FUNCTIONS **********************************
*****************************************************************************/
/*
* Prototypes
*/
void fsm_init (fsm*);
void fsm_lowerup (fsm*);
void fsm_lowerdown (fsm*);
void fsm_open (fsm*);
void fsm_close (fsm*, char*);
void fsm_input (fsm*, u_char*, int);
void fsm_protreject (fsm*);
void fsm_sdata (fsm*, u_char, u_char, u_char*, int);
#endif /* FSM_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,126 @@
/*****************************************************************************
* ipcp.h - PPP IP NCP: Internet Protocol Network Control Protocol header file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* portions Copyright (c) 1997 Global Election Systems Inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
* Original derived from BSD codes.
*****************************************************************************/
/*
* ipcp.h - IP Control Protocol definitions.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: ipcp.h,v 1.1 2003/05/27 14:37:56 jani Exp $
*/
#ifndef IPCP_H
#define IPCP_H
/*************************
*** PUBLIC DEFINITIONS ***
*************************/
/*
* Options.
*/
#define CI_ADDRS 1 /* IP Addresses */
#define CI_COMPRESSTYPE 2 /* Compression Type */
#define CI_ADDR 3
#define CI_MS_WINS1 128 /* Primary WINS value */
#define CI_MS_DNS1 129 /* Primary DNS value */
#define CI_MS_WINS2 130 /* Secondary WINS value */
#define CI_MS_DNS2 131 /* Secondary DNS value */
#define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */
#define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */
#define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */
/* maxslot and slot number compression) */
#define IPCP_VJ_COMP 0x002d /* current value for VJ compression option*/
#define IPCP_VJ_COMP_OLD 0x0037 /* "old" (i.e, broken) value for VJ */
/* compression option*/
/************************
*** PUBLIC DATA TYPES ***
************************/
typedef struct ipcp_options {
u_int neg_addr : 1; /* Negotiate IP Address? */
u_int old_addrs : 1; /* Use old (IP-Addresses) option? */
u_int req_addr : 1; /* Ask peer to send IP address? */
u_int default_route : 1; /* Assign default route through interface? */
u_int proxy_arp : 1; /* Make proxy ARP entry for peer? */
u_int neg_vj : 1; /* Van Jacobson Compression? */
u_int old_vj : 1; /* use old (short) form of VJ option? */
u_int accept_local : 1; /* accept peer's value for ouraddr */
u_int accept_remote : 1; /* accept peer's value for hisaddr */
u_int req_dns1 : 1; /* Ask peer to send primary DNS address? */
u_int req_dns2 : 1; /* Ask peer to send secondary DNS address? */
u_short vj_protocol; /* protocol value to use in VJ option */
u_char maxslotindex; /* VJ slots - 1. */
u_char cflag; /* VJ slot compression flag. */
u32_t ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */
u32_t dnsaddr[2]; /* Primary and secondary MS DNS entries */
u32_t winsaddr[2]; /* Primary and secondary MS WINS entries */
} ipcp_options;
/*****************************
*** PUBLIC DATA STRUCTURES ***
*****************************/
extern fsm ipcp_fsm[];
extern ipcp_options ipcp_wantoptions[];
extern ipcp_options ipcp_gotoptions[];
extern ipcp_options ipcp_allowoptions[];
extern ipcp_options ipcp_hisoptions[];
extern struct protent ipcp_protent;
/***********************
*** PUBLIC FUNCTIONS ***
***********************/
#endif /* IPCP_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,169 @@
/*****************************************************************************
* lcp.h - Network Link Control Protocol header file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* portions Copyright (c) 1997 Global Election Systems Inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
* Original derived from BSD codes.
*****************************************************************************/
/*
* lcp.h - Link Control Protocol definitions.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: lcp.h,v 1.1 2003/05/27 14:37:56 jani Exp $
*/
#ifndef LCP_H
#define LCP_H
/*************************
*** PUBLIC DEFINITIONS ***
*************************/
/*
* Options.
*/
#define CI_MRU 1 /* Maximum Receive Unit */
#define CI_ASYNCMAP 2 /* Async Control Character Map */
#define CI_AUTHTYPE 3 /* Authentication Type */
#define CI_QUALITY 4 /* Quality Protocol */
#define CI_MAGICNUMBER 5 /* Magic Number */
#define CI_PCOMPRESSION 7 /* Protocol Field Compression */
#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */
#define CI_CALLBACK 13 /* callback */
#define CI_MRRU 17 /* max reconstructed receive unit; multilink */
#define CI_SSNHF 18 /* short sequence numbers for multilink */
#define CI_EPDISC 19 /* endpoint discriminator */
/*
* LCP-specific packet types.
*/
#define PROTREJ 8 /* Protocol Reject */
#define ECHOREQ 9 /* Echo Request */
#define ECHOREP 10 /* Echo Reply */
#define DISCREQ 11 /* Discard Request */
#define CBCP_OPT 6 /* Use callback control protocol */
/************************
*** PUBLIC DATA TYPES ***
************************/
/*
* The state of options is described by an lcp_options structure.
*/
typedef struct lcp_options {
u_int passive : 1; /* Don't die if we don't get a response */
u_int silent : 1; /* Wait for the other end to start first */
u_int restart : 1; /* Restart vs. exit after close */
u_int neg_mru : 1; /* Negotiate the MRU? */
u_int neg_asyncmap : 1; /* Negotiate the async map? */
u_int neg_upap : 1; /* Ask for UPAP authentication? */
u_int neg_chap : 1; /* Ask for CHAP authentication? */
u_int neg_magicnumber : 1; /* Ask for magic number? */
u_int neg_pcompression : 1; /* HDLC Protocol Field Compression? */
u_int neg_accompression : 1; /* HDLC Address/Control Field Compression? */
u_int neg_lqr : 1; /* Negotiate use of Link Quality Reports */
u_int neg_cbcp : 1; /* Negotiate use of CBCP */
#ifdef PPP_MULTILINK
u_int neg_mrru : 1; /* Negotiate multilink MRRU */
u_int neg_ssnhf : 1; /* Negotiate short sequence numbers */
u_int neg_endpoint : 1; /* Negotiate endpoint discriminator */
#endif
u_short mru; /* Value of MRU */
#ifdef PPP_MULTILINK
u_short mrru; /* Value of MRRU, and multilink enable */
#endif
u_char chap_mdtype; /* which MD type (hashing algorithm) */
u32_t asyncmap; /* Value of async map */
u32_t magicnumber;
int numloops; /* Number of loops during magic number neg. */
u32_t lqr_period; /* Reporting period for LQR 1/100ths second */
#ifdef PPP_MULTILINK
struct epdisc endpoint; /* endpoint discriminator */
#endif
} lcp_options;
/*
* Values for phase from BSD pppd.h based on RFC 1661.
*/
typedef enum {
PHASE_DEAD = 0,
PHASE_INITIALIZE,
PHASE_ESTABLISH,
PHASE_AUTHENTICATE,
PHASE_CALLBACK,
PHASE_NETWORK,
PHASE_TERMINATE
} LinkPhase;
/*****************************
*** PUBLIC DATA STRUCTURES ***
*****************************/
extern LinkPhase lcp_phase[NUM_PPP]; /* Phase of link session (RFC 1661) */
extern lcp_options lcp_wantoptions[];
extern lcp_options lcp_gotoptions[];
extern lcp_options lcp_allowoptions[];
extern lcp_options lcp_hisoptions[];
extern ext_accm xmit_accm[];
/***********************
*** PUBLIC FUNCTIONS ***
***********************/
void lcp_init (int);
void lcp_open (int);
void lcp_close (int, char *);
void lcp_lowerup (int);
void lcp_lowerdown (int);
void lcp_sprotrej (int, u_char *, int); /* send protocol reject */
extern struct protent lcp_protent;
/* Default number of times we receive our magic number from the peer
before deciding the link is looped-back. */
#define DEFLOOPBACKFAIL 10
#endif /* LCP_H */

View file

@ -0,0 +1,79 @@
/*****************************************************************************
* magic.c - Network Random Number Generator program file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* portions Copyright (c) 1997 by Global Election Systems Inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
* Original based on BSD magic.c.
*****************************************************************************/
/*
* magic.c - PPP Magic Number routines.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "ppp.h"
#include "randm.h"
#include "magic.h"
/***********************************/
/*** PUBLIC FUNCTION DEFINITIONS ***/
/***********************************/
/*
* magicInit - Initialize the magic number generator.
*
* Since we use another random number generator that has its own
* initialization, we do nothing here.
*/
void magicInit()
{
return;
}
/*
* magic - Returns the next magic number.
*/
u32_t magic()
{
return avRandom();
}

View file

@ -0,0 +1,64 @@
/*****************************************************************************
* magic.h - Network Random Number Generator header file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* portions Copyright (c) 1997 Global Election Systems Inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
* Original derived from BSD codes.
*****************************************************************************/
/*
* magic.h - PPP Magic Number definitions.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: magic.h,v 1.1 2003/05/27 14:37:56 jani Exp $
*/
#ifndef MAGIC_H
#define MAGIC_H
/*****************************************************************************
************************** PUBLIC FUNCTIONS **********************************
*****************************************************************************/
void magicInit(void); /* Initialize the magic number generator */
u32_t magic(void); /* Returns the next magic number */
#endif /* MAGIC_H */

View file

@ -0,0 +1,306 @@
/*
***********************************************************************
** md5.c -- the source code for MD5 routines **
** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
** Created: 2/17/90 RLR **
** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
***********************************************************************
*/
/*
***********************************************************************
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
** **
** License to copy and use this software is granted provided that **
** it is identified as the "RSA Data Security, Inc. MD5 Message- **
** Digest Algorithm" in all material mentioning or referencing this **
** software or this function. **
** **
** License is also granted to make and use derivative works **
** provided that such works are identified as "derived from the RSA **
** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
** material mentioning or referencing the derived work. **
** **
** RSA Data Security, Inc. makes no representations concerning **
** either the merchantability of this software or the suitability **
** of this software for any particular purpose. It is provided "as **
** is" without express or implied warranty of any kind. **
** **
** These notices must be retained in any copies of any part of this **
** documentation and/or software. **
***********************************************************************
*/
#include "ppp.h"
#include "md5.h"
#include "pppdebug.h"
#if CHAP_SUPPORT > 0 || MD5_SUPPORT > 0
/*
***********************************************************************
** Message-digest routines: **
** To form the message digest for a message M **
** (1) Initialize a context buffer mdContext using MD5Init **
** (2) Call MD5Update on mdContext and M **
** (3) Call MD5Final on mdContext **
** The message digest is now in mdContext->digest[0...15] **
***********************************************************************
*/
/* forward declaration */
static void Transform (u32_t *buf, u32_t *in);
static unsigned char PADDING[64] = {
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* F, G, H and I are basic MD5 functions */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
/* Rotation is separate from addition to prevent recomputation */
#define FF(a, b, c, d, x, s, ac) \
{(a) += F ((b), (c), (d)) + (x) + (u32_t)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) \
{(a) += G ((b), (c), (d)) + (x) + (u32_t)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) \
{(a) += H ((b), (c), (d)) + (x) + (u32_t)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) \
{(a) += I ((b), (c), (d)) + (x) + (u32_t)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#ifdef __STDC__
#define UL(x) x##UL
#else
#ifdef WIN32
#define UL(x) x##UL
#else
#define UL(x) x
#endif
#endif
/* The routine MD5Init initializes the message-digest context
mdContext. All fields are set to zero.
*/
void MD5Init (MD5_CTX *mdContext)
{
mdContext->i[0] = mdContext->i[1] = (u32_t)0;
/* Load magic initialization constants.
*/
mdContext->buf[0] = (u32_t)0x67452301UL;
mdContext->buf[1] = (u32_t)0xefcdab89UL;
mdContext->buf[2] = (u32_t)0x98badcfeUL;
mdContext->buf[3] = (u32_t)0x10325476UL;
}
/* The routine MD5Update updates the message-digest context to
account for the presence of each of the characters inBuf[0..inLen-1]
in the message whose digest is being computed.
*/
void MD5Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen)
{
u32_t in[16];
int mdi;
unsigned int i, ii;
#if 0
ppp_trace(LOG_INFO, "MD5Update: %u:%.*H\n", inLen, MIN(inLen, 20) * 2, inBuf);
ppp_trace(LOG_INFO, "MD5Update: %u:%s\n", inLen, inBuf);
#endif
/* compute number of bytes mod 64 */
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
/* update number of bits */
if ((mdContext->i[0] + ((u32_t)inLen << 3)) < mdContext->i[0])
mdContext->i[1]++;
mdContext->i[0] += ((u32_t)inLen << 3);
mdContext->i[1] += ((u32_t)inLen >> 29);
while (inLen--) {
/* add new character to buffer, increment mdi */
mdContext->in[mdi++] = *inBuf++;
/* transform if necessary */
if (mdi == 0x40) {
for (i = 0, ii = 0; i < 16; i++, ii += 4)
in[i] = (((u32_t)mdContext->in[ii+3]) << 24) |
(((u32_t)mdContext->in[ii+2]) << 16) |
(((u32_t)mdContext->in[ii+1]) << 8) |
((u32_t)mdContext->in[ii]);
Transform (mdContext->buf, in);
mdi = 0;
}
}
}
/* The routine MD5Final terminates the message-digest computation and
ends with the desired message digest in mdContext->digest[0...15].
*/
void MD5Final (unsigned char hash[], MD5_CTX *mdContext)
{
u32_t in[16];
int mdi;
unsigned int i, ii;
unsigned int padLen;
/* save number of bits */
in[14] = mdContext->i[0];
in[15] = mdContext->i[1];
/* compute number of bytes mod 64 */
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
/* pad out to 56 mod 64 */
padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
MD5Update (mdContext, PADDING, padLen);
/* append length in bits and transform */
for (i = 0, ii = 0; i < 14; i++, ii += 4)
in[i] = (((u32_t)mdContext->in[ii+3]) << 24) |
(((u32_t)mdContext->in[ii+2]) << 16) |
(((u32_t)mdContext->in[ii+1]) << 8) |
((u32_t)mdContext->in[ii]);
Transform (mdContext->buf, in);
/* store buffer in digest */
for (i = 0, ii = 0; i < 4; i++, ii += 4) {
mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
mdContext->digest[ii+1] =
(unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
mdContext->digest[ii+2] =
(unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
mdContext->digest[ii+3] =
(unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
}
memcpy(hash, mdContext->digest, 16);
}
/* Basic MD5 step. Transforms buf based on in.
*/
static void Transform (u32_t *buf, u32_t *in)
{
u32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3];
/* Round 1 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
/* Round 2 */
#define S21 5
#define S22 9
#define S23 14
#define S24 20
GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */
GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
/* Round 3 */
#define S31 4
#define S32 11
#define S33 16
#define S34 23
HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */
HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
/* Round 4 */
#define S41 6
#define S42 10
#define S43 15
#define S44 21
II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
#endif

View file

@ -0,0 +1,55 @@
/*
***********************************************************************
** md5.h -- header file for implementation of MD5 **
** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
** Created: 2/17/90 RLR **
** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
** Revised (for MD5): RLR 4/27/91 **
** -- G modified to have y&~z instead of y&z **
** -- FF, GG, HH modified to add in last register done **
** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
** -- distinct additive constant for each step **
** -- round 4 added, working mod 7 **
***********************************************************************
*/
/*
***********************************************************************
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
** **
** License to copy and use this software is granted provided that **
** it is identified as the "RSA Data Security, Inc. MD5 Message- **
** Digest Algorithm" in all material mentioning or referencing this **
** software or this function. **
** **
** License is also granted to make and use derivative works **
** provided that such works are identified as "derived from the RSA **
** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
** material mentioning or referencing the derived work. **
** **
** RSA Data Security, Inc. makes no representations concerning **
** either the merchantability of this software or the suitability **
** of this software for any particular purpose. It is provided "as **
** is" without express or implied warranty of any kind. **
** **
** These notices must be retained in any copies of any part of this **
** documentation and/or software. **
***********************************************************************
*/
#ifndef MD5_H
#define MD5_H
/* Data structure for MD5 (Message-Digest) computation */
typedef struct {
u32_t i[2]; /* number of _bits_ handled mod 2^64 */
u32_t buf[4]; /* scratch buffer */
unsigned char in[64]; /* input buffer */
unsigned char digest[16]; /* actual digest after MD5Final call */
} MD5_CTX;
void MD5Init (MD5_CTX *mdContext);
void MD5Update (MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen);
void MD5Final (unsigned char hash[], MD5_CTX *mdContext);
#endif /* MD5_H */

View file

@ -0,0 +1,608 @@
/*****************************************************************************
* pap.c - Network Password Authentication Protocol program file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* portions Copyright (c) 1997 by Global Election Systems Inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 97-12-12 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
* Original.
*****************************************************************************/
/*
* upap.c - User/Password Authentication Protocol.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "ppp.h"
#include "auth.h"
#include "pap.h"
#include "pppdebug.h"
#if PAP_SUPPORT > 0
/***********************************/
/*** LOCAL FUNCTION DECLARATIONS ***/
/***********************************/
/*
* Protocol entry points.
*/
static void upap_init (int);
static void upap_lowerup (int);
static void upap_lowerdown (int);
static void upap_input (int, u_char *, int);
static void upap_protrej (int);
static void upap_timeout (void *);
static void upap_reqtimeout (void *);
static void upap_rauthreq (upap_state *, u_char *, int, int);
static void upap_rauthack (upap_state *, u_char *, int, int);
static void upap_rauthnak (upap_state *, u_char *, int, int);
static void upap_sauthreq (upap_state *);
static void upap_sresp (upap_state *, u_char, u_char, char *, int);
/******************************/
/*** PUBLIC DATA STRUCTURES ***/
/******************************/
struct protent pap_protent = {
PPP_PAP,
upap_init,
upap_input,
upap_protrej,
upap_lowerup,
upap_lowerdown,
NULL,
NULL,
#if 0
upap_printpkt,
NULL,
#endif
1,
"PAP",
#if 0
NULL,
NULL,
NULL
#endif
};
upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */
/***********************************/
/*** PUBLIC FUNCTION DEFINITIONS ***/
/***********************************/
/*
* Set the default login name and password for the pap sessions
*/
void upap_setloginpasswd(int unit, const char *luser, const char *lpassword)
{
upap_state *u = &upap[unit];
/* Save the username and password we're given */
u->us_user = luser;
u->us_userlen = strlen(luser);
u->us_passwd = lpassword;
u->us_passwdlen = strlen(lpassword);
}
/*
* upap_authwithpeer - Authenticate us with our peer (start client).
*
* Set new state and send authenticate's.
*/
void upap_authwithpeer(int unit, char *user, char *password)
{
upap_state *u = &upap[unit];
UPAPDEBUG((LOG_INFO, "upap_authwithpeer: %d user=%s password=%s s=%d\n",
unit, user, password, u->us_clientstate));
upap_setloginpasswd(unit, user, password);
u->us_transmits = 0;
/* Lower layer up yet? */
if (u->us_clientstate == UPAPCS_INITIAL ||
u->us_clientstate == UPAPCS_PENDING) {
u->us_clientstate = UPAPCS_PENDING;
return;
}
upap_sauthreq(u); /* Start protocol */
}
/*
* upap_authpeer - Authenticate our peer (start server).
*
* Set new state.
*/
void upap_authpeer(int unit)
{
upap_state *u = &upap[unit];
/* Lower layer up yet? */
if (u->us_serverstate == UPAPSS_INITIAL ||
u->us_serverstate == UPAPSS_PENDING) {
u->us_serverstate = UPAPSS_PENDING;
return;
}
u->us_serverstate = UPAPSS_LISTEN;
if (u->us_reqtimeout > 0)
TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
}
/**********************************/
/*** LOCAL FUNCTION DEFINITIONS ***/
/**********************************/
/*
* upap_init - Initialize a UPAP unit.
*/
static void upap_init(int unit)
{
upap_state *u = &upap[unit];
UPAPDEBUG((LOG_INFO, "upap_init: %d\n", unit));
u->us_unit = unit;
u->us_user = NULL;
u->us_userlen = 0;
u->us_passwd = NULL;
u->us_passwdlen = 0;
u->us_clientstate = UPAPCS_INITIAL;
u->us_serverstate = UPAPSS_INITIAL;
u->us_id = 0;
u->us_timeouttime = UPAP_DEFTIMEOUT;
u->us_maxtransmits = 10;
u->us_reqtimeout = UPAP_DEFREQTIME;
}
/*
* upap_timeout - Retransmission timer for sending auth-reqs expired.
*/
static void upap_timeout(void *arg)
{
upap_state *u = (upap_state *) arg;
UPAPDEBUG((LOG_INFO, "upap_timeout: %d timeout %d expired s=%d\n",
u->us_unit, u->us_timeouttime, u->us_clientstate));
if (u->us_clientstate != UPAPCS_AUTHREQ)
return;
if (u->us_transmits >= u->us_maxtransmits) {
/* give up in disgust */
UPAPDEBUG((LOG_ERR, "No response to PAP authenticate-requests\n"));
u->us_clientstate = UPAPCS_BADAUTH;
auth_withpeer_fail(u->us_unit, PPP_PAP);
return;
}
upap_sauthreq(u); /* Send Authenticate-Request */
}
/*
* upap_reqtimeout - Give up waiting for the peer to send an auth-req.
*/
static void upap_reqtimeout(void *arg)
{
upap_state *u = (upap_state *) arg;
if (u->us_serverstate != UPAPSS_LISTEN)
return; /* huh?? */
auth_peer_fail(u->us_unit, PPP_PAP);
u->us_serverstate = UPAPSS_BADAUTH;
}
/*
* upap_lowerup - The lower layer is up.
*
* Start authenticating if pending.
*/
static void upap_lowerup(int unit)
{
upap_state *u = &upap[unit];
UPAPDEBUG((LOG_INFO, "upap_lowerup: %d s=%d\n", unit, u->us_clientstate));
if (u->us_clientstate == UPAPCS_INITIAL)
u->us_clientstate = UPAPCS_CLOSED;
else if (u->us_clientstate == UPAPCS_PENDING) {
upap_sauthreq(u); /* send an auth-request */
}
if (u->us_serverstate == UPAPSS_INITIAL)
u->us_serverstate = UPAPSS_CLOSED;
else if (u->us_serverstate == UPAPSS_PENDING) {
u->us_serverstate = UPAPSS_LISTEN;
if (u->us_reqtimeout > 0)
TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
}
}
/*
* upap_lowerdown - The lower layer is down.
*
* Cancel all timeouts.
*/
static void upap_lowerdown(int unit)
{
upap_state *u = &upap[unit];
UPAPDEBUG((LOG_INFO, "upap_lowerdown: %d s=%d\n", unit, u->us_clientstate));
if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
UNTIMEOUT(upap_timeout, u); /* Cancel timeout */
if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
UNTIMEOUT(upap_reqtimeout, u);
u->us_clientstate = UPAPCS_INITIAL;
u->us_serverstate = UPAPSS_INITIAL;
}
/*
* upap_protrej - Peer doesn't speak this protocol.
*
* This shouldn't happen. In any case, pretend lower layer went down.
*/
static void upap_protrej(int unit)
{
upap_state *u = &upap[unit];
if (u->us_clientstate == UPAPCS_AUTHREQ) {
UPAPDEBUG((LOG_ERR, "PAP authentication failed due to protocol-reject\n"));
auth_withpeer_fail(unit, PPP_PAP);
}
if (u->us_serverstate == UPAPSS_LISTEN) {
UPAPDEBUG((LOG_ERR, "PAP authentication of peer failed (protocol-reject)\n"));
auth_peer_fail(unit, PPP_PAP);
}
upap_lowerdown(unit);
}
/*
* upap_input - Input UPAP packet.
*/
static void upap_input(int unit, u_char *inpacket, int l)
{
upap_state *u = &upap[unit];
u_char *inp;
u_char code, id;
int len;
/*
* Parse header (code, id and length).
* If packet too short, drop it.
*/
inp = inpacket;
if (l < UPAP_HEADERLEN) {
UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header.\n"));
return;
}
GETCHAR(code, inp);
GETCHAR(id, inp);
GETSHORT(len, inp);
if (len < UPAP_HEADERLEN) {
UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length.\n"));
return;
}
if (len > l) {
UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet.\n"));
return;
}
len -= UPAP_HEADERLEN;
/*
* Action depends on code.
*/
switch (code) {
case UPAP_AUTHREQ:
upap_rauthreq(u, inp, id, len);
break;
case UPAP_AUTHACK:
upap_rauthack(u, inp, id, len);
break;
case UPAP_AUTHNAK:
upap_rauthnak(u, inp, id, len);
break;
default: /* XXX Need code reject */
break;
}
}
/*
* upap_rauth - Receive Authenticate.
*/
static void upap_rauthreq(
upap_state *u,
u_char *inp,
int id,
int len
)
{
u_char ruserlen, rpasswdlen;
char *ruser, *rpasswd;
int retcode;
char *msg;
int msglen;
UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.\n", id));
if (u->us_serverstate < UPAPSS_LISTEN)
return;
/*
* If we receive a duplicate authenticate-request, we are
* supposed to return the same status as for the first request.
*/
if (u->us_serverstate == UPAPSS_OPEN) {
upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
return;
}
if (u->us_serverstate == UPAPSS_BADAUTH) {
upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
return;
}
/*
* Parse user/passwd.
*/
if (len < sizeof (u_char)) {
UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));
return;
}
GETCHAR(ruserlen, inp);
len -= sizeof (u_char) + ruserlen + sizeof (u_char);
if (len < 0) {
UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));
return;
}
ruser = (char *) inp;
INCPTR(ruserlen, inp);
GETCHAR(rpasswdlen, inp);
if (len < rpasswdlen) {
UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));
return;
}
rpasswd = (char *) inp;
/*
* Check the username and password given.
*/
retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
rpasswdlen, &msg, &msglen);
BZERO(rpasswd, rpasswdlen);
upap_sresp(u, retcode, id, msg, msglen);
if (retcode == UPAP_AUTHACK) {
u->us_serverstate = UPAPSS_OPEN;
auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
} else {
u->us_serverstate = UPAPSS_BADAUTH;
auth_peer_fail(u->us_unit, PPP_PAP);
}
if (u->us_reqtimeout > 0)
UNTIMEOUT(upap_reqtimeout, u);
}
/*
* upap_rauthack - Receive Authenticate-Ack.
*/
static void upap_rauthack(
upap_state *u,
u_char *inp,
int id,
int len
)
{
u_char msglen;
char *msg;
UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d s=%d\n", id, u->us_clientstate));
if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
return;
/*
* Parse message.
*/
if (len < sizeof (u_char)) {
UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n"));
return;
}
GETCHAR(msglen, inp);
len -= sizeof (u_char);
if (len < msglen) {
UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n"));
return;
}
msg = (char *) inp;
PRINTMSG(msg, msglen);
u->us_clientstate = UPAPCS_OPEN;
auth_withpeer_success(u->us_unit, PPP_PAP);
}
/*
* upap_rauthnak - Receive Authenticate-Nakk.
*/
static void upap_rauthnak(
upap_state *u,
u_char *inp,
int id,
int len
)
{
u_char msglen;
char *msg;
UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d s=%d\n", id, u->us_clientstate));
if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
return;
/*
* Parse message.
*/
if (len < sizeof (u_char)) {
UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));
return;
}
GETCHAR(msglen, inp);
len -= sizeof (u_char);
if (len < msglen) {
UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));
return;
}
msg = (char *) inp;
PRINTMSG(msg, msglen);
u->us_clientstate = UPAPCS_BADAUTH;
UPAPDEBUG((LOG_ERR, "PAP authentication failed\n"));
auth_withpeer_fail(u->us_unit, PPP_PAP);
}
/*
* upap_sauthreq - Send an Authenticate-Request.
*/
static void upap_sauthreq(upap_state *u)
{
u_char *outp;
int outlen;
outlen = UPAP_HEADERLEN + 2 * sizeof (u_char)
+ u->us_userlen + u->us_passwdlen;
outp = outpacket_buf[u->us_unit];
MAKEHEADER(outp, PPP_PAP);
PUTCHAR(UPAP_AUTHREQ, outp);
PUTCHAR(++u->us_id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(u->us_userlen, outp);
BCOPY(u->us_user, outp, u->us_userlen);
INCPTR(u->us_userlen, outp);
PUTCHAR(u->us_passwdlen, outp);
BCOPY(u->us_passwd, outp, u->us_passwdlen);
pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);
UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d\n", u->us_id));
TIMEOUT(upap_timeout, u, u->us_timeouttime);
++u->us_transmits;
u->us_clientstate = UPAPCS_AUTHREQ;
}
/*
* upap_sresp - Send a response (ack or nak).
*/
static void upap_sresp(
upap_state *u,
u_char code,
u_char id,
char *msg,
int msglen
)
{
u_char *outp;
int outlen;
outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
outp = outpacket_buf[u->us_unit];
MAKEHEADER(outp, PPP_PAP);
PUTCHAR(code, outp);
PUTCHAR(id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(msglen, outp);
BCOPY(msg, outp, msglen);
pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);
UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d s=%d\n",
code, id, u->us_clientstate));
}
#if 0
/*
* upap_printpkt - print the contents of a PAP packet.
*/
static int upap_printpkt(
u_char *p,
int plen,
void (*printer) (void *, char *, ...),
void *arg
)
{
(void)p;
(void)plen;
(void)printer;
(void)arg;
return 0;
}
#endif
#endif /* PAP_SUPPORT */

View file

@ -0,0 +1,129 @@
/*****************************************************************************
* pap.h - PPP Password Authentication Protocol header file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* portions Copyright (c) 1997 Global Election Systems Inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
* Original derived from BSD codes.
*****************************************************************************/
/*
* upap.h - User/Password Authentication Protocol definitions.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef PAP_H
#define PAP_H
/*************************
*** PUBLIC DEFINITIONS ***
*************************/
/*
* Packet header = Code, id, length.
*/
#define UPAP_HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
/*
* UPAP codes.
*/
#define UPAP_AUTHREQ 1 /* Authenticate-Request */
#define UPAP_AUTHACK 2 /* Authenticate-Ack */
#define UPAP_AUTHNAK 3 /* Authenticate-Nak */
/*
* Client states.
*/
#define UPAPCS_INITIAL 0 /* Connection down */
#define UPAPCS_CLOSED 1 /* Connection up, haven't requested auth */
#define UPAPCS_PENDING 2 /* Connection down, have requested auth */
#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */
#define UPAPCS_OPEN 4 /* We've received an Ack */
#define UPAPCS_BADAUTH 5 /* We've received a Nak */
/*
* Server states.
*/
#define UPAPSS_INITIAL 0 /* Connection down */
#define UPAPSS_CLOSED 1 /* Connection up, haven't requested auth */
#define UPAPSS_PENDING 2 /* Connection down, have requested auth */
#define UPAPSS_LISTEN 3 /* Listening for an Authenticate */
#define UPAPSS_OPEN 4 /* We've sent an Ack */
#define UPAPSS_BADAUTH 5 /* We've sent a Nak */
/************************
*** PUBLIC DATA TYPES ***
************************/
/*
* Each interface is described by upap structure.
*/
typedef struct upap_state {
int us_unit; /* Interface unit number */
const char *us_user; /* User */
int us_userlen; /* User length */
const char *us_passwd; /* Password */
int us_passwdlen; /* Password length */
int us_clientstate; /* Client state */
int us_serverstate; /* Server state */
u_char us_id; /* Current id */
int us_timeouttime; /* Timeout (seconds) for auth-req retrans. */
int us_transmits; /* Number of auth-reqs sent */
int us_maxtransmits; /* Maximum number of auth-reqs to send */
int us_reqtimeout; /* Time to wait for auth-req from peer */
} upap_state;
/***********************
*** PUBLIC FUNCTIONS ***
***********************/
extern upap_state upap[];
void upap_setloginpasswd(int unit, const char *luser, const char *lpassword);
void upap_authwithpeer (int, char *, char *);
void upap_authpeer (int);
extern struct protent pap_protent;
#endif /* PAP_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,446 @@
/*****************************************************************************
* ppp.h - Network Point to Point Protocol header file.
*
* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
* portions Copyright (c) 1997 Global Election Systems Inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 03-01-01 Marc Boucher <marc@mbsi.ca>
* Ported to lwIP.
* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
* Original derived from BSD codes.
*****************************************************************************/
#ifndef PPP_H
#define PPP_H
#include "lwip/opt.h"
#if PPP_SUPPORT > 0
#include "lwip/sio.h"
#include "lwip/api.h"
#include "lwip/sockets.h"
#include "lwip/stats.h"
#include "lwip/mem.h"
#include "lwip/tcpip.h"
#include "lwip/netif.h"
/*
* pppd.h - PPP daemon global declarations.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
/*
* ppp_defs.h - PPP definitions.
*
* Copyright (c) 1994 The Australian National University.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, provided that the above copyright
* notice appears in all copies. This software is provided without any
* warranty, express or implied. The Australian National University
* makes no representations about the suitability of this software for
* any purpose.
*
* IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
* PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
* THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
* OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
* OR MODIFICATIONS.
*/
#define TIMEOUT(f, a, t) sys_untimeout((f), (a)), sys_timeout((t)*1000, (f), (a))
#define UNTIMEOUT(f, a) sys_untimeout((f), (a))
# ifndef __u_char_defined
/* Type definitions for BSD code. */
typedef unsigned long u_long;
typedef unsigned int u_int;
typedef unsigned short u_short;
typedef unsigned char u_char;
#endif
/*
* Constants and structures defined by the internet system,
* Per RFC 790, September 1981, and numerous additions.
*/
/*
* The basic PPP frame.
*/
#define PPP_HDRLEN 4 /* octets for standard ppp header */
#define PPP_FCSLEN 2 /* octets for FCS */
/*
* Significant octet values.
*/
#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */
#define PPP_UI 0x03 /* Unnumbered Information */
#define PPP_FLAG 0x7e /* Flag Sequence */
#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */
#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */
/*
* Protocol field values.
*/
#define PPP_IP 0x21 /* Internet Protocol */
#define PPP_AT 0x29 /* AppleTalk Protocol */
#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */
#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */
#define PPP_COMP 0xfd /* compressed packet */
#define PPP_IPCP 0x8021 /* IP Control Protocol */
#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */
#define PPP_CCP 0x80fd /* Compression Control Protocol */
#define PPP_LCP 0xc021 /* Link Control Protocol */
#define PPP_PAP 0xc023 /* Password Authentication Protocol */
#define PPP_LQR 0xc025 /* Link Quality Report protocol */
#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */
#define PPP_CBCP 0xc029 /* Callback Control Protocol */
/*
* Values for FCS calculations.
*/
#define PPP_INITFCS 0xffff /* Initial FCS value */
#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
/*
* Extended asyncmap - allows any character to be escaped.
*/
typedef u_char ext_accm[32];
/*
* What to do with network protocol (NP) packets.
*/
enum NPmode {
NPMODE_PASS, /* pass the packet through */
NPMODE_DROP, /* silently drop the packet */
NPMODE_ERROR, /* return an error */
NPMODE_QUEUE /* save it up for later. */
};
/*
* Inline versions of get/put char/short/long.
* Pointer is advanced; we assume that both arguments
* are lvalues and will already be in registers.
* cp MUST be u_char *.
*/
#define GETCHAR(c, cp) { \
(c) = *(cp)++; \
}
#define PUTCHAR(c, cp) { \
*(cp)++ = (u_char) (c); \
}
#define GETSHORT(s, cp) { \
(s) = *(cp)++ << 8; \
(s) |= *(cp)++; \
}
#define PUTSHORT(s, cp) { \
*(cp)++ = (u_char) ((s) >> 8); \
*(cp)++ = (u_char) (s); \
}
#define GETLONG(l, cp) { \
(l) = *(cp)++ << 8; \
(l) |= *(cp)++; (l) <<= 8; \
(l) |= *(cp)++; (l) <<= 8; \
(l) |= *(cp)++; \
}
#define PUTLONG(l, cp) { \
*(cp)++ = (u_char) ((l) >> 24); \
*(cp)++ = (u_char) ((l) >> 16); \
*(cp)++ = (u_char) ((l) >> 8); \
*(cp)++ = (u_char) (l); \
}
#define INCPTR(n, cp) ((cp) += (n))
#define DECPTR(n, cp) ((cp) -= (n))
#define BCMP(s0, s1, l) memcmp((u_char *)(s0), (u_char *)(s1), (l))
#define BCOPY(s, d, l) memcpy((d), (s), (l))
#define BZERO(s, n) memset(s, 0, n)
#if PPP_DEBUG
#define PRINTMSG(m, l) { m[l] = '\0'; ppp_trace(LOG_INFO, "Remote message: %s\n", m); }
#else
#define PRINTMSG(m, l)
#endif
/*
* MAKEHEADER - Add PPP Header fields to a packet.
*/
#define MAKEHEADER(p, t) { \
PUTCHAR(PPP_ALLSTATIONS, p); \
PUTCHAR(PPP_UI, p); \
PUTSHORT(t, p); }
/*************************
*** PUBLIC DEFINITIONS ***
*************************/
/* Error codes. */
#define PPPERR_NONE 0 /* No error. */
#define PPPERR_PARAM -1 /* Invalid parameter. */
#define PPPERR_OPEN -2 /* Unable to open PPP session. */
#define PPPERR_DEVICE -3 /* Invalid I/O device for PPP. */
#define PPPERR_ALLOC -4 /* Unable to allocate resources. */
#define PPPERR_USER -5 /* User interrupt. */
#define PPPERR_CONNECT -6 /* Connection lost. */
#define PPPERR_AUTHFAIL -7 /* Failed authentication challenge. */
#define PPPERR_PROTOCOL -8 /* Failed to meet protocol. */
/*
* PPP IOCTL commands.
*/
/*
* Get the up status - 0 for down, non-zero for up. The argument must
* point to an int.
*/
#define PPPCTLG_UPSTATUS 100 /* Get the up status - 0 down else up */
#define PPPCTLS_ERRCODE 101 /* Set the error code */
#define PPPCTLG_ERRCODE 102 /* Get the error code */
#define PPPCTLG_FD 103 /* Get the fd associated with the ppp */
/************************
*** PUBLIC DATA TYPES ***
************************/
/*
* The following struct gives the addresses of procedures to call
* for a particular protocol.
*/
struct protent {
u_short protocol; /* PPP protocol number */
/* Initialization procedure */
void (*init) (int unit);
/* Process a received packet */
void (*input) (int unit, u_char *pkt, int len);
/* Process a received protocol-reject */
void (*protrej) (int unit);
/* Lower layer has come up */
void (*lowerup) (int unit);
/* Lower layer has gone down */
void (*lowerdown) (int unit);
/* Open the protocol */
void (*open) (int unit);
/* Close the protocol */
void (*close) (int unit, char *reason);
#if 0
/* Print a packet in readable form */
int (*printpkt) (u_char *pkt, int len,
void (*printer) (void *, char *, ...),
void *arg);
/* Process a received data packet */
void (*datainput) (int unit, u_char *pkt, int len);
#endif
int enabled_flag; /* 0 iff protocol is disabled */
char *name; /* Text name of protocol */
#if 0
/* Check requested options, assign defaults */
void (*check_options) (u_long);
/* Configure interface for demand-dial */
int (*demand_conf) (int unit);
/* Say whether to bring up link for this pkt */
int (*active_pkt) (u_char *pkt, int len);
#endif
};
/*
* The following structure records the time in seconds since
* the last NP packet was sent or received.
*/
struct ppp_idle {
u_short xmit_idle; /* seconds since last NP packet sent */
u_short recv_idle; /* seconds since last NP packet received */
};
struct ppp_settings {
u_int disable_defaultip : 1; /* Don't use hostname for default IP addrs */
u_int auth_required : 1; /* Peer is required to authenticate */
u_int explicit_remote : 1; /* remote_name specified with remotename opt */
u_int refuse_pap : 1; /* Don't wanna auth. ourselves with PAP */
u_int refuse_chap : 1; /* Don't wanna auth. ourselves with CHAP */
u_int usehostname : 1; /* Use hostname for our_name */
u_int usepeerdns : 1; /* Ask peer for DNS adds */
u_short idle_time_limit; /* Shut down link if idle for this long */
int maxconnect; /* Maximum connect time (seconds) */
char user[MAXNAMELEN + 1];/* Username for PAP */
char passwd[MAXSECRETLEN + 1]; /* Password for PAP, secret for CHAP */
char our_name[MAXNAMELEN + 1]; /* Our name for authentication purposes */
char remote_name[MAXNAMELEN + 1]; /* Peer's name for authentication */
};
struct ppp_addrs {
struct ip_addr our_ipaddr, his_ipaddr, netmask, dns1, dns2;
};
/*****************************
*** PUBLIC DATA STRUCTURES ***
*****************************/
/* Buffers for outgoing packets. */
extern u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
extern struct ppp_settings ppp_settings;
extern struct protent *ppp_protocols[];/* Table of pointers to supported protocols */
/***********************
*** PUBLIC FUNCTIONS ***
***********************/
/* Initialize the PPP subsystem. */
void pppInit(void);
/* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
* RFC 1994 says:
*
* In practice, within or associated with each PPP server, there is a
* database which associates "user" names with authentication
* information ("secrets"). It is not anticipated that a particular
* named user would be authenticated by multiple methods. This would
* make the user vulnerable to attacks which negotiate the least secure
* method from among a set (such as PAP rather than CHAP). If the same
* secret was used, PAP would reveal the secret to be used later with
* CHAP.
*
* Instead, for each user name there should be an indication of exactly
* one method used to authenticate that user name. If a user needs to
* make use of different authentication methods under different
* circumstances, then distinct user names SHOULD be employed, each of
* which identifies exactly one authentication method.
*
*/
enum pppAuthType {
PPPAUTHTYPE_NONE,
PPPAUTHTYPE_ANY,
PPPAUTHTYPE_PAP,
PPPAUTHTYPE_CHAP
};
void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd);
/*
* Open a new PPP connection using the given I/O device.
* This initializes the PPP control block but does not
* attempt to negotiate the LCP session.
* Return a new PPP connection descriptor on success or
* an error code (negative) on failure.
*/
int pppOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx);
/*
* Close a PPP connection and release the descriptor.
* Any outstanding packets in the queues are dropped.
* Return 0 on success, an error code on failure.
*/
int pppClose(int pd);
/*
* Indicate to the PPP process that the line has disconnected.
*/
void pppSigHUP(int pd);
/*
* Get and set parameters for the given connection.
* Return 0 on success, an error code on failure.
*/
int pppIOCtl(int pd, int cmd, void *arg);
/*
* Return the Maximum Transmission Unit for the given PPP connection.
*/
u_int pppMTU(int pd);
/*
* Write n characters to a ppp link.
* RETURN: >= 0 Number of characters written
* -1 Failed to write to device
*/
int pppWrite(int pd, const u_char *s, int n);
void pppMainWakeup(int pd);
/* Configure i/f transmit parameters */
void ppp_send_config (int, int, u32_t, int, int);
/* Set extended transmit ACCM */
void ppp_set_xaccm (int, ext_accm *);
/* Configure i/f receive parameters */
void ppp_recv_config (int, int, u32_t, int, int);
/* Find out how long link has been idle */
int get_idle_time (int, struct ppp_idle *);
/* Configure VJ TCP header compression */
int sifvjcomp (int, int, int, int);
/* Configure i/f down (for IP) */
int sifup (int);
/* Set mode for handling packets for proto */
int sifnpmode (int u, int proto, enum NPmode mode);
/* Configure i/f down (for IP) */
int sifdown (int);
/* Configure IP addresses for i/f */
int sifaddr (int, u32_t, u32_t, u32_t, u32_t, u32_t);
/* Reset i/f IP addresses */
int cifaddr (int, u32_t, u32_t);
/* Create default route through i/f */
int sifdefaultroute (int, u32_t, u32_t);
/* Delete default route through i/f */
int cifdefaultroute (int, u32_t, u32_t);
/* Get appropriate netmask for address */
u32_t GetMask (u32_t);
#endif /* PPP_SUPPORT */
#endif /* PPP_H */

Some files were not shown because too many files have changed in this diff Show more