commit f06e955072d0cd6a6360b8c4d7afb8ca431d5468 Author: likewise Date: Sat Oct 19 12:59:30 2002 +0000 Initial revision diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 00000000..7b40fe6c --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,284 @@ +(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. diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..e3016d63 --- /dev/null +++ b/COPYING @@ -0,0 +1,29 @@ +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. + + diff --git a/FILES b/FILES new file mode 100644 index 00000000..1cef7dbf --- /dev/null +++ b/FILES @@ -0,0 +1,5 @@ +src/ - The source code for the lwIP TCP/IP stack. + +proj/ - Makefiles and code for compiling lwIP. + +See also the FILES file in each subdirectory. \ No newline at end of file diff --git a/doc/rawapi.txt b/doc/rawapi.txt new file mode 100644 index 00000000..fe8680f8 --- /dev/null +++ b/doc/rawapi.txt @@ -0,0 +1,289 @@ +Raw TCP/IP interface for lwIP 0.5 + +Author: Adam Dunkels + +$Id: rawapi.txt,v 1.1 2002/10/19 12:59:32 likewise Exp $ + +lwIP provides two Application Program's Interfaces (APIs) for programs +to use for communication with the TCP/IP code: the sequential API +(often just called "the API") and the raw TCP/IP interface. This +document is intended as a description of the latter. For lwIP versions +lower than 0.5, this API was not documented. + +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 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 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_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. \ No newline at end of file diff --git a/doc/sys_arch.txt b/doc/sys_arch.txt new file mode 100644 index 00000000..841d1274 --- /dev/null +++ b/doc/sys_arch.txt @@ -0,0 +1,125 @@ +sys_arch interface for lwIP 0.5 + +Author: Adam Dunkels + +$Id: sys_arch.txt,v 1.1 2002/10/19 12:59:33 likewise Exp $ + +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. + +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. + +- u16_t sys_arch_sem_wait(sys_sem_t sem, u16_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 amount + of time spent waiting for the semaphore to be signaled. If the + semaphore wasn't signaled within the specified time, the return + value is zero. If the thread didn't have to wait for the semaphore + (i.e., it was already signaled), care must be taken to ensure that + the function does not return a zero value since this is used to + indicate that a timeout occured. A suitable way to implement this is + to check if the time spent waiting is zero and if so, the value 1 is + returned. + + 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. + +- u16_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u16_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 and the function must not return zero even if a message was + present in the mailbox and the time spent waiting was zero + milliseconds. + + 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: + +- void sys_thread_new(void (* thread)(void *arg), void *arg) + + Starts a new thread that will begin its execution in the function + "thread()". The "arg" argument will be passed as an argument to the + thread() function. + diff --git a/proj/minimal/Makefile b/proj/minimal/Makefile new file mode 100644 index 00000000..6c2033d6 --- /dev/null +++ b/proj/minimal/Makefile @@ -0,0 +1,94 @@ +# 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 +# +# $Id: Makefile,v 1.1 2002/10/19 12:59:33 likewise Exp $ + +CCDEP=gcc +CC=gcc +CFLAGS=-g -Wall -DIPv4 -Os -fpack-struct +LWIPARCH=unix +ARFLAGS=rs +LWIPDIR=../../src + +CFLAGS:=$(CFLAGS) \ + -I$(LWIPDIR)/include -I$(LWIPDIR)/arch/$(LWIPARCH)/include -I$(LWIPDIR)/include/ipv4 \ + -Iapps -I. + +# COREFILES, CORE4FILES: The minimum set of files needed for lwIP. +COREFILES=$(LWIPDIR)/core/mem.c $(LWIPDIR)/core/memp.c $(LWIPDIR)/core/netif.c \ + $(LWIPDIR)/core/pbuf.c $(LWIPDIR)/core/stats.c $(LWIPDIR)/core/sys.c \ + $(LWIPDIR)/core/tcp.c $(LWIPDIR)/core/tcp_input.c \ + $(LWIPDIR)/core/tcp_output.c $(LWIPDIR)/core/udp.c +CORE4FILES=$(LWIPDIR)/core/ipv4/icmp.c $(LWIPDIR)/core/ipv4/ip.c \ + $(LWIPDIR)/core/inet.c $(LWIPDIR)/core/ipv4/ip_addr.c + +# NETIFFILES: Files implementing various generic network interface functions.' +NETIFFILES=$(LWIPDIR)/netif/etharp.c mintapif.c + +# LWIPFILES: All the above. +LWIPFILES=$(COREFILES) $(CORE4FILES) $(NETIFFILES) +LWIPFILESW=$(wildcard $(LWIPFILES)) +LWIPOBJS=$(notdir $(LWIPFILESW:.c=.o)) + +# APPFILES +APPFILES=echo.c + +LWIPLIB=liblwip4.a +APPLIB=liblwipapps.a +APPOBJS=$(notdir $(APPFILES:.c=.o)) + +%.o: + $(CC) $(CFLAGS) -c $(<:.o=.c) + +all ipv4 compile: minimal +.PHONY: all + +clean: + rm -f *.o $(LWIPLIB) $(APPLIB) minimal .depend* *.core core + +depend dep: .depend + +include .depend + +$(APPLIB): $(APPOBJS) + $(AR) $(ARFLAGS) $(APPLIB) $? + +$(LWIPLIB): $(LWIPOBJS) + $(AR) $(ARFLAGS) $(LWIPLIB) $? + +.depend: main.c $(LWIPFILES) $(APPFILES) + $(CCDEP) $(CFLAGS) -MM $^ > .depend || rm -f .depend + +minimal: .depend $(LWIPLIB) $(APPLIB) main.o $(APPFILES) + $(CC) $(CFLAGS) $(LDFLAGS) -o minimal main.o $(APPLIB) $(LWIPLIB) + + diff --git a/proj/minimal/README b/proj/minimal/README new file mode 100644 index 00000000..0edb5f78 --- /dev/null +++ b/proj/minimal/README @@ -0,0 +1,3 @@ +This is an example of a very minimal lwIP project. It runs in a single +thread and runs a single example application - an echo server. The +echo application is implemented using the raw API. \ No newline at end of file diff --git a/proj/minimal/echo.c b/proj/minimal/echo.c new file mode 100644 index 00000000..652208ea --- /dev/null +++ b/proj/minimal/echo.c @@ -0,0 +1,220 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" +#include "lwip/stats.h" +#include "lwip/tcp.h" + +struct echo_state { + struct pbuf *p; + u8_t failed; +#define FAILED_MAX 8 +}; +/*-----------------------------------------------------------------------------------*/ +static void +echo_err(void *arg, err_t err) +{ + struct echo_state *es = arg; + + if(arg != NULL) { + pbuf_free(es->p); + mem_free(arg); + } +} +/*-----------------------------------------------------------------------------------*/ +static void +close_conn(struct tcp_pcb *pcb, struct echo_state *es) +{ + tcp_arg(pcb, NULL); +#if 0 + tcp_sent(pcb, NULL); + tcp_recv(pcb, NULL); +#endif /* 0 */ + if(es != NULL) { + pbuf_free(es->p); + mem_free(es); + } + tcp_close(pcb); +} +/*-----------------------------------------------------------------------------------*/ +static void +send_buf(struct tcp_pcb *pcb, struct echo_state *es) +{ + struct pbuf *q; + + do { + q = es->p; + es->p = pbuf_dechain(q); + if(tcp_write(pcb, q->payload, q->len, 1) == ERR_MEM) { + pbuf_chain(q, es->p); + es->p = q; + return; + } + tcp_recved(pcb, q->len); + pbuf_free(q); + } while(es->p != NULL); +} +/*-----------------------------------------------------------------------------------*/ +static err_t +echo_poll(void *arg, struct tcp_pcb *pcb) +{ + struct echo_state *es; + + if(arg == NULL) { + return tcp_close(pcb); + } + + es = arg; + + if(es->failed >= FAILED_MAX) { + close_conn(pcb, es); + tcp_abort(pcb); + return ERR_ABRT; + } + + if(es->p != NULL) { + ++es->failed; + send_buf(pcb, es); + } + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +static err_t +echo_sent(void *arg, struct tcp_pcb *pcb, u16_t len) +{ + struct echo_state *es; + + es = arg; + + if(es != NULL && es->p != NULL) { + send_buf(pcb, es); + } + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +static err_t +echo_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + struct echo_state *es; + + es = arg; + + if(p == NULL) { + close_conn(pcb, es); + return ERR_OK; + } + + if(es->p != NULL) { + pbuf_chain(es->p, p); + } else { + es->p = p; + } + + send_buf(pcb, es); + + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +static err_t +echo_accept(void *arg, struct tcp_pcb *pcb, err_t err) +{ + struct echo_state *es; + + tcp_setprio(pcb, TCP_PRIO_MIN); + + /* Allocate memory for the structure that holds the state of the + connection. */ + es = mem_malloc(sizeof(struct echo_state)); + + if(es == NULL) { + return ERR_MEM; + } + + /* Initialize the structure. */ + es->p = NULL; + es->failed = 0; + + /* Tell TCP that this is the structure we wish to be passed for our + callbacks. */ + tcp_arg(pcb, es); + + /* Tell TCP that we wish to be informed of incoming data by a call + to the http_recv() function. */ +#if 0 + tcp_recv(pcb, echo_recv); + + tcp_err(pcb, echo_err); +#endif /* 0 */ + + tcp_poll(pcb, echo_poll, 2); + + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +void +echo_init(void) +{ + struct tcp_pcb *pcb; + + pcb = tcp_new(); + tcp_bind(pcb, IP_ADDR_ANY, 7); + pcb = tcp_listen(pcb); +#if 0 + tcp_accept(pcb, echo_accept); +#endif /* 0 */ +} +/*-----------------------------------------------------------------------------------*/ +err_t +lwip_tcp_event(void *arg, struct tcp_pcb *pcb, + enum lwip_event ev, struct pbuf *p, + u16_t size, err_t err) +{ + switch(ev) { + case LWIP_EVENT_ACCEPT: + return echo_accept(arg, pcb, err); + case LWIP_EVENT_SENT: + return echo_sent(arg, pcb, size); + case LWIP_EVENT_RECV: + return echo_recv(arg, pcb, p, err); + case LWIP_EVENT_ERR: + echo_err(arg, err); + break; + case LWIP_EVENT_POLL: + return echo_poll(arg, pcb); + default: + break; + } + + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ + diff --git a/proj/minimal/lwipopts.h b/proj/minimal/lwipopts.h new file mode 100644 index 00000000..85e304de --- /dev/null +++ b/proj/minimal/lwipopts.h @@ -0,0 +1,168 @@ +/* + * 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 + * + */ +#ifndef __LWIPOPTS_H__ +#define __LWIPOPTS_H__ + +#define NO_SYS 1 +#define LWIP_EVENT_API 1 + +/* ---------- 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. */ +#define MEM_ALIGNMENT 2 + +/* 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. */ +#define MEM_SIZE 1000 + +/* 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. */ +#define MEMP_NUM_PBUF 8 +/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + per active UDP "connection". */ +#define MEMP_NUM_UDP_PCB 4 +/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP + connections. */ +#define MEMP_NUM_TCP_PCB 2 +/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP + connections. */ +#define MEMP_NUM_TCP_PCB_LISTEN 8 +/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP + segments. */ +#define MEMP_NUM_TCP_SEG 8 + +/* 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. */ +#define MEMP_NUM_NETBUF 0 +/* MEMP_NUM_NETCONN: the number of struct netconns. */ +#define MEMP_NUM_NETCONN 0 +/* MEMP_NUM_APIMSG: the number of struct api_msg, used for + communication between the TCP/IP stack and the sequential + programs. */ +#define MEMP_NUM_API_MSG 0 +/* 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. */ +#define MEMP_NUM_TCPIP_MSG 0 +/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active + timeouts. */ +#define MEMP_NUM_SYS_TIMEOUT 0 + +/* ---------- Pbuf options ---------- */ +/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ +#define PBUF_POOL_SIZE 8 + +/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ +#define PBUF_POOL_BUFSIZE 128 + +/* PBUF_LINK_HLEN: the number of bytes that should be allocated for a + link level header. */ +#define PBUF_LINK_HLEN 16 + +/* ---------- TCP options ---------- */ +#define LWIP_TCP 1 +#define TCP_TTL 255 + +/* Controls if TCP should queue segments that arrive out of + order. Define to 0 if your device is low on memory. */ +#define TCP_QUEUE_OOSEQ 0 + +/* TCP Maximum segment size. */ +#define TCP_MSS 128 + +/* TCP sender buffer space (bytes). */ +#define TCP_SND_BUF 256 + +/* TCP sender buffer space (pbufs). This must be at least = 2 * + TCP_SND_BUF/TCP_MSS for things to work. */ +#define TCP_SND_QUEUELEN 4 * TCP_SND_BUF/TCP_MSS + +/* TCP receive window. */ +#define TCP_WND 512 + +/* Maximum number of retransmissions of data segments. */ +#define TCP_MAXRTX 12 + +/* Maximum number of retransmissions of SYN segments. */ +#define TCP_SYNMAXRTX 4 + +/* ---------- ARP options ---------- */ +#define ARP_TABLE_SIZE 10 + +/* ---------- 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. */ +#define IP_FORWARD 0 + +/* If defined to 1, IP options are allowed (but not parsed). If + defined to 0, all packets with IP options are dropped. */ +#define IP_OPTIONS 1 + +/* ---------- ICMP options ---------- */ +#define ICMP_TTL 255 + + +/* ---------- DHCP options ---------- */ +/* Define LWIP_DHCP to 1 if you want DHCP configuration of + interfaces. DHCP is not implemented in lwIP 0.5.1, however, so + turning this on does currently not work. */ +#define LWIP_DHCP 0 + +/* 1 if you want to do an ARP check on the offered address + (recommended). */ +#define DHCP_DOES_ARP_CHECK 1 + +/* ---------- UDP options ---------- */ +#define LWIP_UDP 0 +#define UDP_TTL 255 + + +/* ---------- Statistics options ---------- */ +/*#define STATS*/ + +#ifdef STATS +#define LINK_STATS +#define IP_STATS +#define ICMP_STATS +#define UDP_STATS +#define TCP_STATS +#define MEM_STATS +#define MEMP_STATS +#define PBUF_STATS +#define SYS_STATS +#endif /* STATS */ + +#endif /* __LWIPOPTS_H__ */ diff --git a/proj/minimal/main.c b/proj/minimal/main.c new file mode 100644 index 00000000..0a6e1a83 --- /dev/null +++ b/proj/minimal/main.c @@ -0,0 +1,101 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" + +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/sys.h" + +#include "lwip/stats.h" + +#include "lwip/ip.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" + +#include "mintapif.h" + +/*-----------------------------------------------------------------------------------*/ +int +main(int argc, char **argv) +{ + struct ip_addr ipaddr, netmask, gw; + struct netif *netif; + +#ifdef PERF + perf_init("/tmp/minimal.perf"); +#endif /* PERF */ +#ifdef STATS + stats_init(); +#endif /* STATS */ + + mem_init(); + memp_init(); + pbuf_init(); + netif_init(); + ip_init(); + udp_init(); + tcp_init(); + printf("TCP/IP initialized.\n"); + + IP4_ADDR(&gw, 192,168,0,1); + IP4_ADDR(&ipaddr, 192,168,0,2); + IP4_ADDR(&netmask, 255,255,255,0); + + netif = netif_add(&ipaddr, &netmask, &gw, mintapif_init, ip_input); + + netif_set_default(netif); + + echo_init(); + + printf("Applications started.\n"); + + + while(1) { + + if(mintapif_wait(netif, 100) == MINTAPIF_TIMEOUT) { + tcp_tmr(); + } + + } + + return 0; +} +/*-----------------------------------------------------------------------------------*/ + + + + + + + + diff --git a/proj/minimal/mintapif.c b/proj/minimal/mintapif.c new file mode 100644 index 00000000..38cad399 --- /dev/null +++ b/proj/minimal/mintapif.c @@ -0,0 +1,354 @@ +/*-----------------------------------------------------------------------------------*/ +/* + * 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef linux +#include +#include +#include +#define DEVTAP "/dev/net/tun" +#else /* linux */ +#define DEVTAP "/dev/tap0" +#endif /* linux */ + +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "netif/etharp.h" + +#include "mintapif.h" + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 't' + +struct mintapif { + struct eth_addr *ethaddr; + /* Add whatever per-interface state that is needed here. */ + u32_t lasttime; + int fd; +}; + +static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; + +/* Forward declarations. */ +static void mintapif_input(struct netif *netif); +static err_t mintapif_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr); + +/*-----------------------------------------------------------------------------------*/ +static void +low_level_init(struct netif *netif) +{ + struct mintapif *mintapif; + char buf[1024]; + + mintapif = netif->state; + + /* Obtain MAC address from network interface. */ + mintapif->ethaddr->addr[0] = 1; + mintapif->ethaddr->addr[1] = 2; + mintapif->ethaddr->addr[2] = 3; + mintapif->ethaddr->addr[3] = 4; + mintapif->ethaddr->addr[4] = 5; + mintapif->ethaddr->addr[5] = 6; + + /* Do whatever else is needed to initialize interface. */ + + mintapif->fd = open(DEVTAP, O_RDWR); + if(mintapif->fd == -1) { + perror("tapif: tapif_init: open"); + exit(1); + } + +#ifdef linux + { + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP|IFF_NO_PI; + if (ioctl(mintapif->fd, TUNSETIFF, (void *) &ifr) < 0) { + perror(buf); + exit(1); + } + } +#endif /* Linux */ + + snprintf(buf, sizeof(buf), "ifconfig tap0 inet %d.%d.%d.%d", + ip4_addr1(&(netif->gw)), + ip4_addr2(&(netif->gw)), + ip4_addr3(&(netif->gw)), + ip4_addr4(&(netif->gw))); + + system(buf); + + mintapif->lasttime = 0; + +} +/*-----------------------------------------------------------------------------------*/ +/* + * 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 mintapif *mintapif; + struct pbuf *q; + char buf[1500]; + char *bufptr; + + mintapif = netif->state; + + /* initiate transfer(); */ + + bufptr = &buf[0]; + + for(q = p; q != NULL; q = q->next) { + /* Send the data from the pbuf to the interface, one pbuf at a + time. The size of the data in each pbuf is kept in the ->len + variable. */ + /* send data from(q->payload, q->len); */ + bcopy(q->payload, bufptr, q->len); + bufptr += q->len; + } + + /* signal that packet should be sent(); */ + if(write(mintapif->fd, buf, p->tot_len) == -1) { + perror("tapif: write"); + } + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +/* + * low_level_input(): + * + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + */ +/*-----------------------------------------------------------------------------------*/ +static struct pbuf * +low_level_input(struct mintapif *mintapif) +{ + struct pbuf *p, *q; + u16_t len; + char buf[1500]; + char *bufptr; + + /* Obtain the size of the packet and put it into the "len" + variable. */ + len = read(mintapif->fd, buf, sizeof(buf)); + + /* if(((double)rand()/(double)RAND_MAX) < 0.1) { + printf("drop\n"); + return NULL; + }*/ + + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL); + + if(p != NULL) { + /* We iterate over the pbuf chain until we have read the entire + packet into the pbuf. */ + bufptr = &buf[0]; + for(q = p; q != NULL; q = q->next) { + /* Read enough bytes to fill this pbuf in the chain. The + avaliable data in the pbuf is given by the q->len + variable. */ + /* read data into(q->payload, q->len); */ + bcopy(bufptr, q->payload, q->len); + bufptr += q->len; + } + /* acknowledge that packet has been read(); */ + } else { + /* drop packet(); */ + printf("Could not allocate pbufs\n"); + } + + return p; +} +/*-----------------------------------------------------------------------------------*/ +/* + * mintapif_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 actuall transmission of the packet. + * + */ +/*-----------------------------------------------------------------------------------*/ +static err_t +mintapif_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr) +{ + p = etharp_output(netif, ipaddr, p); + if(p != NULL) { + return low_level_output(netif, p); + } + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +/* + * mintapif_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 +mintapif_input(struct netif *netif) +{ + struct mintapif *mintapif; + struct eth_hdr *ethhdr; + struct pbuf *p, *q; + + + mintapif = netif->state; + + p = low_level_input(mintapif); + + if(p != NULL) { + +#ifdef LINK_STATS + stats.link.recv++; +#endif /* LINK_STATS */ + + ethhdr = p->payload; + + q = NULL; + switch(htons(ethhdr->type)) { + case ETHTYPE_IP: + q = etharp_ip_input(netif, p); + pbuf_header(p, -14); + netif->input(p, netif); + break; + case ETHTYPE_ARP: + q = etharp_arp_input(netif, mintapif->ethaddr, p); + break; + default: + pbuf_free(p); + break; + } + if(q != NULL) { + low_level_output(netif, q); + pbuf_free(q); + } + + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * mintapif_init(): + * + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +mintapif_init(struct netif *netif) +{ + struct mintapif *mintapif; + + mintapif = mem_malloc(sizeof(struct mintapif)); + netif->state = mintapif; + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + netif->output = mintapif_output; + netif->linkoutput = low_level_output; + + mintapif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); + + low_level_init(netif); +} +/*-----------------------------------------------------------------------------------*/ +enum mintapif_signal +mintapif_wait(struct netif *netif, u16_t time) +{ + fd_set fdset; + struct timeval tv, now; + struct timezone tz; + int ret; + struct mintapif *mintapif; + + mintapif = netif->state; + + while(1) { + + if(mintapif->lasttime >= (u32_t)time * 1000) { + mintapif->lasttime = 0; + return MINTAPIF_TIMEOUT; + } + + tv.tv_sec = 0; + tv.tv_usec = (u32_t)time * 1000 - mintapif->lasttime; + + + FD_ZERO(&fdset); + FD_SET(mintapif->fd, &fdset); + + gettimeofday(&now, &tz); + ret = select(mintapif->fd + 1, &fdset, NULL, NULL, &tv); + if(ret == 0) { + mintapif->lasttime = 0; + return MINTAPIF_TIMEOUT; + } + gettimeofday(&tv, &tz); + mintapif->lasttime += (tv.tv_sec - now.tv_sec) * 1000000 + (tv.tv_usec - now.tv_usec); + + mintapif_input(netif); + } + + return MINTAPIF_PACKET; +} diff --git a/proj/minimal/mintapif.h b/proj/minimal/mintapif.h new file mode 100644 index 00000000..7203167c --- /dev/null +++ b/proj/minimal/mintapif.h @@ -0,0 +1,45 @@ +/* + * 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 + * + */ +#ifndef __MINTAPIF_H__ +#define __MINTAPIF_H__ + +#include "lwip/netif.h" + +enum mintapif_signal { + MINTAPIF_TIMEOUT, + MINTAPIF_PACKET +}; + +void mintapif_init(struct netif *netif); +enum mintapif_signal mintapif_wait(struct netif *netif, u16_t time); + +#endif /* __MINTAPIF_H__ */ diff --git a/proj/unixsim/Makefile b/proj/unixsim/Makefile new file mode 100644 index 00000000..341f7c02 --- /dev/null +++ b/proj/unixsim/Makefile @@ -0,0 +1,111 @@ +# 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 +# +# $Id: Makefile,v 1.1 2002/10/19 12:59:37 likewise Exp $ + +CCDEP=gcc +CC=gcc +CFLAGS=-g -Wall -DIPv4 -DLWIP_DEBUG -pedantic +LDFLAGS=-lpcap +LWIPARCH=unix +ARFLAGS=rs +LWIPDIR=../../src + +CFLAGS:=$(CFLAGS) \ + -I$(LWIPDIR)/include -I$(LWIPDIR)/arch/$(LWIPARCH)/include -I$(LWIPDIR)/include/ipv4 \ + -Iapps -I. + +# COREFILES, CORE4FILES: The minimum set of files needed for lwIP. +COREFILES=$(LWIPDIR)/core/mem.c $(LWIPDIR)/core/memp.c $(LWIPDIR)/core/netif.c \ + $(LWIPDIR)/core/pbuf.c $(LWIPDIR)/core/stats.c $(LWIPDIR)/core/sys.c \ + $(LWIPDIR)/core/tcp.c $(LWIPDIR)/core/tcp_input.c \ + $(LWIPDIR)/core/tcp_output.c $(LWIPDIR)/core/udp.c +CORE4FILES=$(LWIPDIR)/core/ipv4/icmp.c $(LWIPDIR)/core/ipv4/ip.c \ + $(LWIPDIR)/core/inet.c $(LWIPDIR)/core/ipv4/ip_addr.c + + +# APIFILES: The files which implement the sequential and socket APIs. +APIFILES=$(LWIPDIR)/api/api_lib.c $(LWIPDIR)/api/api_msg.c $(LWIPDIR)/api/tcpip.c \ + $(LWIPDIR)/api/err.c $(LWIPDIR)/api/sockets.c + +# NETIFFILES: Files implementing various generic network interface functions.' +NETIFFILES=$(LWIPDIR)/netif/loopif.c \ + $(LWIPDIR)/netif/tcpdump.c $(LWIPDIR)/netif/etharp.c + +# ARCHFILES: Archiecture specific files. +ARCHFILES=$(wildcard $(LWIPDIR)/arch/$(LWIPARCH)/*.c $(LWIPDIR)/arch/$(LWIPARCH)/netif/*.c) + +# APPFILES: Applications. +APPFILES=apps/fs.c apps/httpd.c \ + apps/udpecho.c apps/tcpecho.c \ + apps/shell.c + +# LWIPFILES: All the above. +LWIPFILES=$(COREFILES) $(CORE4FILES) $(APIFILES) $(NETIFFILES) $(ARCHFILES) +LWIPFILESW=$(wildcard $(LWIPFILES)) +LWIPOBJS=$(notdir $(LWIPFILESW:.c=.o)) + +LWIPLIB=liblwip4.a +APPLIB=liblwipapps.a +APPOBJS=$(notdir $(APPFILES:.c=.o)) + +%.o: + $(CC) $(CFLAGS) -c $(<:.o=.c) + +all ipv4 compile: simhost simnode simrouter +.PHONY: all + +clean: + rm -f *.o $(LWIPLIB) $(APPLIB) simhost simnode simrouter *.s .depend* *.core core + +depend dep: .depend + +include .depend + +$(APPLIB): $(APPOBJS) + $(AR) $(ARFLAGS) $(APPLIB) $? + +$(LWIPLIB): $(LWIPOBJS) + $(AR) $(ARFLAGS) $(LWIPLIB) $? + +.depend: simhost.c simnode.c simrouter.c $(LWIPFILES) $(APPFILES) + $(CCDEP) $(CFLAGS) -MM $^ > .depend || rm -f .depend + +simhost: .depend $(LWIPLIB) $(APPLIB) simhost.o $(APPFILES) + $(CC) $(CFLAGS) $(LDFLAGS) -pthread -o simhost simhost.o $(APPLIB) $(LWIPLIB) + +simrouter: .depend $(LWIPLIB) $(APPLIB) simrouter.o + $(CC) $(CFLAGS) $(LDFLAGS) -pthread -o simrouter simrouter.o $(APPLIB) $(LWIPLIB) + +simnode: .depend $(LWIPLIB) $(APPLIB) simnode.o + $(CC) $(CFLAGS) $(LDFLAGS) -pthread -o simnode simnode.o $(APPLIB) $(LWIPLIB) + diff --git a/proj/unixsim/README b/proj/unixsim/README new file mode 100644 index 00000000..c2125783 --- /dev/null +++ b/proj/unixsim/README @@ -0,0 +1,47 @@ +This directory contains an example of how a project using lwIP might +look. It is also the development platform of lwIP, since it can be run +as a user process under FreeBSD or Linux. There are also a number of +example applications (including a simple web server) in the apps/ +directory. + +Some short instructions on how to build and run lwIP on a FreeBSD or +Linux host. For FreeBSD, the tap interface must be enabled in the +kernel configuration and the kernel must be recompiled. The tap +interface is enabled by adding the line "pseudo-device tap" in the +kernel configuration. See Chapter 9 in the FreeBSD handbook for +instructions on how to build a custom FreeBSD kernel. + +* Compile the code. This must be done by using GNU Make. Under + FreeBSD, GNU Make can be found in the ports collection under + /usr/ports/devel/gmake (type "make install distclean" to + install). Under Linux, GNU Make is the default "make". + + > gmake (FreeBSD) + + > make (Linux) + +* The compilation process produces the executable file "simhost". To + run this, you have to be root. + + > su (Type password for the root account) + # ./simhost + +* The lwIP TCP/IP stack is now running with IP address + 192.168.0.2. Some things that you can try: + + To see the packets that are going to and from the lwIP stack, run + tcpdump: + + # tcpdump -l -n -i tap0 + + You can ping lwIP: + + > ping 192.168.0.2 + + For a telnet shell, run: + + > telnet 192.168.0.2 + + Finally, "simhost" also includes a simple web server; the URL is + of course http://192.168.0.2/. + diff --git a/proj/unixsim/apps/fs.c b/proj/unixsim/apps/fs.c new file mode 100644 index 00000000..3c741125 --- /dev/null +++ b/proj/unixsim/apps/fs.c @@ -0,0 +1,55 @@ +/* + * 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 + * + */ +#include "lwip/def.h" +#include "fs.h" +#include "fsdata.h" +#include "fsdata.c" + +/*-----------------------------------------------------------------------------------*/ + + +/*-----------------------------------------------------------------------------------*/ +int +fs_open(char *name, struct fs_file *file) +{ + struct fsdata_file_noconst *f; + + for(f = (struct fsdata_file_noconst *)FS_ROOT; f != NULL; f = (struct fsdata_file_noconst *)f->next) { + if(!strcmp(name, f->name)) { + file->data = f->data; + file->len = f->len; + return 1; + } + } + return 0; +} +/*-----------------------------------------------------------------------------------*/ diff --git a/proj/unixsim/apps/fs.h b/proj/unixsim/apps/fs.h new file mode 100644 index 00000000..e6a1d63d --- /dev/null +++ b/proj/unixsim/apps/fs.h @@ -0,0 +1,44 @@ +/* + * 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 + * + */ +#ifndef __FS_H__ +#define __FS_H__ + +struct fs_file { + char *data; + int len; +}; + +/* file must be allocated by caller and will be filled in + by the function. */ +int fs_open(char *name, struct fs_file *file); + +#endif /* __FS_H__ */ diff --git a/proj/unixsim/apps/fs/documentation.html b/proj/unixsim/apps/fs/documentation.html new file mode 100644 index 00000000..baf35809 --- /dev/null +++ b/proj/unixsim/apps/fs/documentation.html @@ -0,0 +1,191 @@ + + + + + + + + + + + + + +lwIP - A Lightweight TCP/IP Stack - Documentation + + + + + +
+

lwIP - A Lightweight TCP/IP Stack

+
+ + + + + +
+
+ + + + +Introduction + +| + +News + +| + +[Documentation] + + +| + +Mailing list + +| + +Changelog + +| + +Download + +| + +Links + + + +
+

Documentation

+
+ + + + + +
+  + + + + +

+For more documentation regarding lwIP and a proxy architecture to +support TCP/IP communication for small clients, look in Adam Dunkels' masters thesis. +

+ + +

+The lwIP mailing list can be used to +discuss lwIP. +

+ +

+For questions or suggestions, please contact the author at Adam Dunkels +<adam@sics.se>. +

+ + +

+ +$Date: 2002/10/19 13:00:01 $ + +

+ + +
+  +
+ + + + + +
+ +
+ + + + +Introduction + +| + +News + +| + +[Documentation] + + +| + +Mailing list + +| + +Changelog + +| + +Download + +| + +Links + + + +
+ +
+ +
+ + + diff --git a/proj/unixsim/apps/fs/download.html b/proj/unixsim/apps/fs/download.html new file mode 100644 index 00000000..59d7cf5c --- /dev/null +++ b/proj/unixsim/apps/fs/download.html @@ -0,0 +1,232 @@ + + + + + + + + + + + + + +lwIP - A Lightweight TCP/IP Stack - Download + + + + + +
+

lwIP - A Lightweight TCP/IP Stack

+
+ + + + + +
+
+ + + + +Introduction + +| + +News + +| + +Documentation + +| + +Mailing list + +| + +Changelog + +| + +[Download] + + +| + +Links + + + +
+

Download

+
+ + + + + +
+  + + + +

+lwIP is avaliable for download provided that you read and accept this BSD-style license. +

+ +

Release versions

+

+The latest version is 0.5.3. (Older versions are also provided for an +unknown reason.) +

+ + +

Development version

+

+The latest development code from the CVS is also avaliable here. Note that this code may +very well be unstable and might not even compile. +

+ +

Source code online

+

+Joe MacDonald has put an HTML version of the latest lwIP source code +online at http://www.deserted.net/lwIP/. +

+ +

Ports

+

+Florian Shulze has ported lwIP to DJGPP/MS-DOS and to Visual C++ +6.0/Win32. They can be downloaded here +(DJGPP/MS-DOS) and here +(Visual C++ 6.0/Win32). +

+ +

Add-ons/drivers/applications

+ +

DHCP client

+

+Leon Woestenberg from Axon Digital Design B.V. has written a CS8900a +network interface driver and is currently developing a DHCP client for +lwIP. They can both be found here. The plan is +to eventually integrate Leon's DHCP client in the main lwIP +distribution. +

+ +

IGMPv2 implementation

+

+Steve Reynolds of Citel Technologies Ltd. has donated his IGMPv2 +implementation for lwIP to the community. It is avaliable for download +here (note that the copyright and +license differs slightly from lwIP - read the license in the igmp.c +file). The plan is to integrate his code into the main lwIP +distribution. +

+ +

Alternative BSD socket layer

+

+Paul Sheer has incorporated lwIP into his PaulOS system and has +written an alternative BSD socket layer. It is avaliable for download +here. It is copyright Paul Sheer +and licensed under the GNU GPL. +

+ +

+ +$Date: 2002/10/19 13:00:06 $ + +

+ +
+  +
+ + + + + +
+ +
+ + + + +Introduction + +| + +News + +| + +Documentation + +| + +Mailing list + +| + +Changelog + +| + +[Download] + + +| + +Links + + + +
+ +
+ +
+ + + diff --git a/proj/unixsim/apps/fs/img/sics.gif b/proj/unixsim/apps/fs/img/sics.gif new file mode 100644 index 00000000..0a4fc7bb Binary files /dev/null and b/proj/unixsim/apps/fs/img/sics.gif differ diff --git a/proj/unixsim/apps/fs/licence.html b/proj/unixsim/apps/fs/licence.html new file mode 100644 index 00000000..40f05972 --- /dev/null +++ b/proj/unixsim/apps/fs/licence.html @@ -0,0 +1,169 @@ + + + + + + + + + + + + + +lwIP - A Lightweight TCP/IP Stack - lwIP source code licence + + + + + +
+

lwIP - A Lightweight TCP/IP Stack

+
+ + + + + +
+
+ + + + +Introduction + +| + +News + +| + +Documentation + +| + +Mailing list + +| + +Changelog + +| + +Download + +| + +Links + + + +
+

lwIP source code licence

+
+ + + + + +
+  + + +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.
+ + + +

+ +$Date: 2002/10/19 13:00:01 $ + +

+ +
+  +
+ + + + + +
+ +
+ + + + +Introduction + +| + +News + +| + +Documentation + +| + +Mailing list + +| + +Changelog + +| + +Download + +| + +Links + + + +
+ +
+ +
+ + + diff --git a/proj/unixsim/apps/fs/links.html b/proj/unixsim/apps/fs/links.html new file mode 100644 index 00000000..2dfa0f90 --- /dev/null +++ b/proj/unixsim/apps/fs/links.html @@ -0,0 +1,266 @@ + + + + + + + + + + + + + +lwIP - A Lightweight TCP/IP Stack - Links + + + + + +
+

lwIP - A Lightweight TCP/IP Stack

+
+ + + + + +
+
+ + + + +Introduction + +| + +News + +| + +Documentation + +| + +Mailing list + +| + +Changelog + +| + +Download + +| + +[Links] + + + + +
+

Links

+
+ + + + + +
+  + + + + + + + + + + + + + + + + + + + + + + + + +lwIP pages: + + +Companies using lwIP in their products: +
    +
  • UK based Tangent Devices Ltd are incorporating lwIP in their film +and video post-production equipment. +
  • Axon Digital Design BV in The +Netherlands is merging lwIP with their current IP stack for use in the +Synapse modular broadcasting system. +
+ +Projects using lwIP: + + +Other small TCP/IP implementations: +
    +
  • uIP - A very small TCP/IP +implementation, suitable for systems with hundreds of bytes free RAM +and a few kilobytes of free code space.
    +
  • uC/IP - uC/IP is a BSD-based +TCP/IP protocol stack for microcontrollers.
    +
  • Liquorice - Liquorice +includes a TCP/IP stack.
    +
  • CPC/IP - A TCP/IP stack for +Amstrad CPCs.
    +
  • LUnix - LUnix contains a small +TCP/IP stack.
    +
  • JOS - JOS includes a +TCP/IP implementation.
    +
  • TinyTCP - A very slim +TCP, IP, and FTP implementation.
    +
  • WWWpic2 - Small +HTTP/TCP/IP implementation for a PIC.
    +
  • PIC Web Server - Small HTTP/TCP/IP/SLIP PIC implementation.
    +
+ +Very small web servers: +
    +
  • webACE - World's Smallest +Web Server.
    +
  • iPIC - A Match +Head Sized Web Server.
    +
+ +Related RFCs: + + +Related publications: +
    +
  • V. Jacobson. Congestion avoidance and control. In Proceedings of +the SIGCOMM '88 Conference, Stanford, California, August 1988. +
  • V. Jacobson. 4.3BSD TCP header prediction. ACM Computer +Communications Review, 20(2), April 1990. +
  • P. Karn and C. Partridge. Improving round-trip time estimates +in reliablie transport protocols. In Proceedings of the SIGCOMM '87 +Conference, Stowe, Vermont, August 1987. +
  • J. Kay and J. Pasquale. Profiling and Reducing Processing +Overheads in TCP/IP. IEEE/ACM Transactions of Networking, 4(6), December 1996. +
  • L. Larzon, M. Degermark, and S. Pink. UDP Lite for +real-time multimedia applications. In Proceedings of the IEEE +International Conference of Communications, Vancouver, British +Columbia, Canada, June 1999. +
  • P. E. McKenney and K. F. Dove. Efcient demultiplexing of +incoming TCP packets. In Proceedings of the SIGCOMM '92 Conference, Baltimore, Maryland, August 1992. +
  • C. Partridge and S. Pink. A faster UDP. IEEE/ACM Transactions +in Networking, 1(4), August 1993. +
+ + + +

+ +$Date: 2002/10/19 13:00:02 $ + +

+ + +
+  +
+ + + + + +
+ +
+ + + + +Introduction + +| + +News + +| + +Documentation + +| + +Mailing list + +| + +Changelog + +| + +Download + +| + +[Links] + + + + +
+ +
+ +
+ + + diff --git a/proj/unixsim/apps/fs/mailinglist.html b/proj/unixsim/apps/fs/mailinglist.html new file mode 100644 index 00000000..1cd8914f --- /dev/null +++ b/proj/unixsim/apps/fs/mailinglist.html @@ -0,0 +1,187 @@ + + + + + + + + + + + + + +lwIP - A Lightweight TCP/IP Stack - Mailing list + + + + + +
+

lwIP - A Lightweight TCP/IP Stack

+
+ + + + + +
+
+ + + + +Introduction + +| + +News + +| + +Documentation + +| + +[Mailing list] + + +| + +Changelog + +| + +Download + +| + +Links + + + +
+

Mailing list

+
+ + + + + +
+  + + + +

+The lwIP mailing list is the place to discuss lwIP. All topics related +to lwIP, such as porting or using lwIP, writing device drivers or +application programs for lwIP can be discussed here. +

+ +

Archives

+

+Archives can be found here. +

+ +

Subscribe

+

+To subscribe, send a mail to majordomo@sics.se with the message +

+subscribe lwip
+
+
+in the message body. The subject should be kept blank. +

+

+In a few minutes, you should receive a welcome message and some +information regarding the subscription, including instructions for +unsubscribing. Save those messages for future reference. +

+ +

+You are now an lwIP mailing list subscriber! +

+ +

Post

+

+Posting to the lwIP mailing list is a simple as sending a mail to the +address lwip@sics.se. +

+ +

Unsubscribe

+

+To subscribe, send a mail to majordomo@sics.se with the message +

+unsubscribe lwip
+
+
+in the message body. The subject should be kept blank. +

+ +

+ +$Date: 2002/10/19 13:00:02 $ + +

+ + +
+  +
+ + + + + +
+ +
+ + + + +Introduction + +| + +News + +| + +Documentation + +| + +[Mailing list] + + +| + +Changelog + +| + +Download + +| + +Links + + + +
+ +
+ +
+ + + diff --git a/proj/unixsim/apps/fs/os.html b/proj/unixsim/apps/fs/os.html new file mode 100644 index 00000000..6d66b82d --- /dev/null +++ b/proj/unixsim/apps/fs/os.html @@ -0,0 +1,225 @@ + + + + + + + + + + + + + +lwIP - A Lightweight TCP/IP Stack - OS vs non-OS + + + + + +
+

lwIP - A Lightweight TCP/IP Stack

+
+ + + + + +
+
+ + + + +Introduction + +| + +News + +| + +Documentation + +| + +Mailing list + +| + +Changelog + +| + +Download + +| + +Links + + + +
+

OS vs non-OS

+
+ + + + + +
+  + + +

Using lwIP with or without an operating system

+ +

+There has been a few questions about how lwIP can be used in a +standalone environment (i.e., an environment without a multi-threaded +operating system) lately. The purpose of this document is to describe +how lwIP is designed to be used with and without a multi-threaded +operating system. +

+ +
+ +

The lwIP single-threaded core

+

+The core of lwIP consists of the actual implementations of the IP, +ICMP, UDP, and TCP protocols, as well as the support functions such as +buffer and memory management. The core components are the only ones +that are needed when lwIP is to be run in a single-threaded (non-OS) +environment. +

+

+The core components can be viewed as a software library which has the +following interface: +

+
    +
  • ip_input(pbuf, netif): Takes an IP packet and the incoming network +interface as arguments and does the TCP/IP processing for the packet. +
  • tcp_tmr(): Should be called every 100 ms. Does all TCP +timer processing such as doing retransmissions. +
+

+Because none of the core functions ever needs to block when run in a +single-threaded environment, the sys_arch (the operating +system abstraction layer) does not need to implement locking +semaphores or mailboxes. In future versions of lwIP, the dependancy of +the sys_arch will be removed in the single-threaded case. +

+

+A simple main loop for a single-threaded system might look +like this: +

+
+  while(1) {
+    if(poll_driver(netif) == PACKET_READY) {
+      pbuf = get_packet(netif);
+      ip_input(pbuf, netif);
+    }
+
+    if(clock() - last_time == 100 * CLOCK_MS) {
+      tcp_tmr();
+      last_time = clock();
+    }    
+  }
+
+ +

lwIP in a multi-threaded system

+

+lwIP is designed to be able to be run in a multi-threaded system with +applications running in concurrent threads. The model used in this +case is that all TCP/IP processing is done in a single thread. The +application thread communicate with the TCP/IP thread using the +sequential API. +

+ +
+ +

+The inter-thread communication is implemented in the two files +api_lib.c and api_msg.c. The former contains the +functions used by the application programs and the latter implements +the TCP/IP stack interface. A third file, tcpip.c, handles +incoming packets and timer events as described in the previous +section. +

+ +

+When run in a multi-threaded environment, incoming packets are handled +by the function tcpip_input(), which takes the same arguments +as the ip_input() function. The difference between the two +functions is that the tcpip_input() function does not process +the incoming packet immediately. It merely puts the packet on a queue +which later is drained by the TCP/IP thread. +

+ +

+When being run in a multi-threaded system, timer events are taken care +of internally in tcpip.c. +

+ +

+ +$Date: 2002/10/19 13:00:03 $ + +

+ + +
+  +
+ + + + + +
+ +
+ + + + +Introduction + +| + +News + +| + +Documentation + +| + +Mailing list + +| + +Changelog + +| + +Download + +| + +Links + + + +
+ +
+ +
+ + + diff --git a/proj/unixsim/apps/fs/os.png b/proj/unixsim/apps/fs/os.png new file mode 100644 index 00000000..deea8f2c Binary files /dev/null and b/proj/unixsim/apps/fs/os.png differ diff --git a/proj/unixsim/apps/fs/threads.png b/proj/unixsim/apps/fs/threads.png new file mode 100644 index 00000000..2486ab4f Binary files /dev/null and b/proj/unixsim/apps/fs/threads.png differ diff --git a/proj/unixsim/apps/fsdata.c b/proj/unixsim/apps/fsdata.c new file mode 100644 index 00000000..4ffaed5f --- /dev/null +++ b/proj/unixsim/apps/fsdata.c @@ -0,0 +1,4188 @@ +static const char data_404_html[] = { + /* /404.html */ + 0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x34, + 0x30, 0x34, 0x20, 0x46, 0x69, 0x6c, 0x65, 0x20, 0x6e, 0x6f, + 0x74, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0xd, 0xa, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, + 0x50, 0x2f, 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, + 0x28, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, + 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, + 0x2f, 0x29, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, + 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x3c, 0x62, + 0x6f, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6f, 0x6c, 0x6f, + 0x72, 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, 0x65, 0x22, 0x3e, + 0xa, 0x3c, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0xa, + 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x36, 0x30, 0x30, 0x22, 0x20, 0x62, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, 0x3e, + 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0xa, 0x3c, + 0x68, 0x31, 0x3e, 0x34, 0x30, 0x34, 0x20, 0x2d, 0x20, 0x66, + 0x69, 0x6c, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x66, 0x6f, + 0x75, 0x6e, 0x64, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0xa, 0x3c, + 0x62, 0x72, 0x3e, 0xa, 0x54, 0x72, 0x79, 0x20, 0x61, 0x6e, + 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x70, 0x61, 0x67, 0x65, + 0x2e, 0xa, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x3c, 0x2f, 0x74, + 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, + 0xa, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, + 0xa, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, 0x3c, + 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, }; + +static const char data_mailinglist_html[] = { + /* /mailinglist.html */ + 0x2f, 0x6d, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, 0xa, + 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, + 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x3c, 0x68, + 0x65, 0x61, 0x64, 0x3e, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, + 0x3e, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x2d, 0x20, 0x41, 0x20, + 0x4c, 0x69, 0x67, 0x68, 0x74, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, 0x53, + 0x74, 0x61, 0x63, 0x6b, 0x20, 0x2d, 0x20, 0x4d, 0x61, 0x69, + 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x3c, + 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x3c, 0x2f, 0x68, + 0x65, 0x61, 0x64, 0x3e, 0xa, 0xa, 0xa, 0x3c, 0x62, 0x6f, + 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6f, 0x6c, 0x6f, 0x72, + 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, 0x65, 0x22, 0x3e, 0xa, + 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, + 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, + 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, + 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, + 0x6c, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, + 0x30, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, + 0x64, 0x3e, 0xa, 0x3c, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, + 0x3e, 0x3c, 0x68, 0x31, 0x3e, 0x6c, 0x77, 0x49, 0x50, 0x20, + 0x2d, 0x20, 0x41, 0x20, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x77, + 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x54, 0x43, 0x50, 0x2f, + 0x49, 0x50, 0x20, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x3c, 0x2f, + 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, + 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, + 0x74, 0x72, 0x3e, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x3e, 0xa, 0xa, 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, + 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, + 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, + 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, + 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, + 0x67, 0x3d, 0x22, 0x30, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, + 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, + 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x3e, + 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0xa, 0xa, 0xa, 0xa, + 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, + 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x6e, 0x65, 0x77, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, + 0x22, 0x3e, 0x4e, 0x65, 0x77, 0x73, 0x3c, 0x2f, 0x61, 0x3e, + 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x22, 0x3e, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, + 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x5b, 0x4d, 0x61, 0x69, + 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x5d, + 0xa, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x6c, 0x6f, 0x67, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, + 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, + 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0x22, 0x3e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, + 0x64, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, + 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6c, + 0x69, 0x6e, 0x6b, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x3c, 0x2f, 0x61, 0x3e, + 0xa, 0xa, 0xa, 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0x3c, + 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, + 0x3c, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0x3c, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0x3c, 0x68, 0x32, + 0x3e, 0x4d, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x6c, + 0x69, 0x73, 0x74, 0x3c, 0x2f, 0x68, 0x32, 0x3e, 0x3c, 0x2f, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0xa, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x3c, 0x2f, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, 0x3c, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3d, 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, + 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, + 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, + 0x22, 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x70, + 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0x3e, + 0x3c, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x20, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x30, 0x22, 0x3e, + 0xa, 0x26, 0x6e, 0x62, 0x73, 0x70, 0x3b, 0xa, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x20, 0x62, 0x67, + 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x77, 0x68, 0x69, + 0x74, 0x65, 0x22, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x22, 0x35, 0x34, 0x30, 0x22, 0x3e, 0xa, 0xa, 0xa, 0x3c, + 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x6a, + 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, 0x54, + 0x68, 0x65, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x6d, 0x61, + 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x69, 0x73, 0x74, + 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6c, + 0x61, 0x63, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x69, 0x73, + 0x63, 0x75, 0x73, 0x73, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2e, + 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x74, 0x6f, 0x70, 0x69, 0x63, + 0x73, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0xa, + 0x74, 0x6f, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2c, 0x20, 0x73, + 0x75, 0x63, 0x68, 0x20, 0x61, 0x73, 0x20, 0x70, 0x6f, 0x72, + 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x72, 0x20, 0x75, 0x73, + 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2c, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x20, 0x64, 0x72, 0x69, 0x76, 0x65, + 0x72, 0x73, 0x20, 0x6f, 0x72, 0xa, 0x61, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x72, + 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x73, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x63, 0x61, 0x6e, 0x20, + 0x62, 0x65, 0x20, 0x64, 0x69, 0x73, 0x63, 0x75, 0x73, 0x73, + 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x2e, 0xa, 0x3c, + 0x2f, 0x70, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x33, 0x3e, 0x41, + 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, 0x3c, 0x2f, 0x68, + 0x33, 0x3e, 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, + 0x6e, 0x3d, 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, + 0x22, 0x3e, 0xa, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, + 0x73, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x66, + 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x6d, 0x61, 0x69, 0x6c, 0x6c, 0x69, + 0x73, 0x74, 0x2f, 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, 0x3c, + 0x2f, 0x61, 0x3e, 0x2e, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, + 0xa, 0x3c, 0x68, 0x33, 0x3e, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x3c, 0x2f, 0x68, 0x33, 0x3e, 0xa, + 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, + 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, + 0x54, 0x6f, 0x20, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x2c, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x61, + 0x20, 0x6d, 0x61, 0x69, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x3c, + 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6d, 0x61, + 0x69, 0x6c, 0x74, 0x6f, 0x3a, 0x6d, 0x61, 0x6a, 0x6f, 0x72, + 0x64, 0x6f, 0x6d, 0x6f, 0x40, 0x73, 0x69, 0x63, 0x73, 0x2e, + 0x73, 0x65, 0x22, 0x3e, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x64, + 0x6f, 0x6d, 0x6f, 0x40, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, + 0x65, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0xa, 0x3c, 0x70, 0x72, 0x65, 0x3e, 0xa, 0x73, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x20, 0x6c, + 0x77, 0x69, 0x70, 0xa, 0xa, 0x3c, 0x2f, 0x70, 0x72, 0x65, + 0x3e, 0xa, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x62, 0x6f, 0x64, + 0x79, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, + 0x64, 0x20, 0x62, 0x65, 0x20, 0x6b, 0x65, 0x70, 0x74, 0x20, + 0x62, 0x6c, 0x61, 0x6e, 0x6b, 0x2e, 0xa, 0x3c, 0x2f, 0x70, + 0x3e, 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, + 0x3d, 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, + 0x3e, 0xa, 0x49, 0x6e, 0x20, 0x61, 0x20, 0x66, 0x65, 0x77, + 0x20, 0x6d, 0x69, 0x6e, 0x75, 0x74, 0x65, 0x73, 0x2c, 0x20, + 0x79, 0x6f, 0x75, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, + 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 0x61, + 0x20, 0x77, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x20, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x73, 0x6f, 0x6d, 0x65, 0xa, 0x69, 0x6e, 0x66, 0x6f, + 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, + 0x67, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x73, 0x74, + 0x72, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x66, + 0x6f, 0x72, 0xa, 0x75, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x69, 0x6e, 0x67, 0x2e, 0x20, 0x53, 0x61, + 0x76, 0x65, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65, 0x20, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x20, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x20, + 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, 0x3c, 0x70, 0x20, + 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x6a, 0x75, 0x73, + 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, 0x59, 0x6f, 0x75, + 0x20, 0x61, 0x72, 0x65, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x61, + 0x6e, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x6d, 0x61, 0x69, + 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, + 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, + 0x21, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, 0x3c, 0x68, + 0x33, 0x3e, 0x50, 0x6f, 0x73, 0x74, 0x3c, 0x2f, 0x68, 0x33, + 0x3e, 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, + 0x3d, 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, + 0x3e, 0xa, 0x50, 0x6f, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, + 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x77, 0x49, + 0x50, 0x20, 0x6d, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, + 0x6c, 0x69, 0x73, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, + 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x61, 0x73, 0x20, + 0x73, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, + 0x6d, 0x61, 0x69, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, + 0x65, 0xa, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, + 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6d, + 0x61, 0x69, 0x6c, 0x74, 0x6f, 0x3a, 0x6c, 0x77, 0x69, 0x70, + 0x40, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x22, 0x3e, + 0x6c, 0x77, 0x69, 0x70, 0x40, 0x73, 0x69, 0x63, 0x73, 0x2e, + 0x73, 0x65, 0x3c, 0x2f, 0x61, 0x3e, 0x2e, 0xa, 0x3c, 0x2f, + 0x70, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x33, 0x3e, 0x55, 0x6e, + 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x3c, + 0x2f, 0x68, 0x33, 0x3e, 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, + 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, + 0x66, 0x79, 0x22, 0x3e, 0xa, 0x54, 0x6f, 0x20, 0x73, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2c, 0x20, 0x73, + 0x65, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x69, 0x6c, + 0x20, 0x74, 0x6f, 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x6f, 0x3a, + 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x64, 0x6f, 0x6d, 0x6f, 0x40, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x22, 0x3e, 0x6d, + 0x61, 0x6a, 0x6f, 0x72, 0x64, 0x6f, 0x6d, 0x6f, 0x40, 0x73, + 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x3c, 0x2f, 0x61, 0x3e, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0xa, 0x3c, 0x70, + 0x72, 0x65, 0x3e, 0xa, 0x75, 0x6e, 0x73, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x62, 0x65, 0x20, 0x6c, 0x77, 0x69, 0x70, + 0xa, 0xa, 0x3c, 0x2f, 0x70, 0x72, 0x65, 0x3e, 0xa, 0x69, + 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x2e, 0x20, + 0x54, 0x68, 0x65, 0x20, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, + 0x65, 0x20, 0x6b, 0x65, 0x70, 0x74, 0x20, 0x62, 0x6c, 0x61, + 0x6e, 0x6b, 0x2e, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, + 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, 0x3e, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0xa, 0x3c, 0x66, 0x6f, 0x6e, + 0x74, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x22, 0x2d, 0x31, + 0x22, 0x3e, 0x3c, 0x69, 0x3e, 0xa, 0x24, 0x44, 0x61, 0x74, + 0x65, 0x3a, 0x20, 0x32, 0x30, 0x30, 0x31, 0x2f, 0x31, 0x32, + 0x2f, 0x31, 0x32, 0x20, 0x31, 0x35, 0x3a, 0x34, 0x38, 0x3a, + 0x35, 0x37, 0x20, 0x24, 0xa, 0x3c, 0x2f, 0x69, 0x3e, 0x3c, + 0x2f, 0x66, 0x6f, 0x6e, 0x74, 0x3e, 0xa, 0x3c, 0x2f, 0x70, + 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa, 0xa, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x20, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x30, 0x22, + 0x3e, 0xa, 0x26, 0x6e, 0x62, 0x73, 0x70, 0x3b, 0xa, 0x3c, + 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x72, 0x3e, + 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, + 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, + 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, + 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, + 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, + 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, + 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x22, 0x3e, 0xa, 0xa, 0x3c, 0x68, + 0x72, 0x3e, 0xa, 0xa, 0xa, 0xa, 0xa, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x49, 0x6e, + 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6e, 0x65, + 0x77, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, + 0x65, 0x77, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, + 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, + 0x7c, 0xa, 0xa, 0x5b, 0x4d, 0x61, 0x69, 0x6c, 0x69, 0x6e, + 0x67, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x5d, 0xa, 0xa, 0xa, + 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, + 0x67, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x3c, 0x2f, 0x61, + 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x77, 0x6e, 0x6c, + 0x6f, 0x61, 0x64, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x3c, 0x2f, + 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6c, 0x69, 0x6e, 0x6b, + 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4c, 0x69, + 0x6e, 0x6b, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0xa, + 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x74, + 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x72, + 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x64, 0x69, + 0x76, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x22, 0x3e, 0xa, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, + 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, + 0x2f, 0x22, 0x3e, 0x41, 0x64, 0x61, 0x6d, 0x20, 0x44, 0x75, + 0x6e, 0x6b, 0x65, 0x6c, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, + 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x2f, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, 0x3c, 0x2f, + 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, 0x3c, 0x2f, 0x68, 0x74, + 0x6d, 0x6c, 0x3e, 0xa, }; + +static const char data_links_html[] = { + /* /links.html */ + 0x2f, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, 0xa, + 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, + 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x3c, 0x68, + 0x65, 0x61, 0x64, 0x3e, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, + 0x3e, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x2d, 0x20, 0x41, 0x20, + 0x4c, 0x69, 0x67, 0x68, 0x74, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, 0x53, + 0x74, 0x61, 0x63, 0x6b, 0x20, 0x2d, 0x20, 0x4c, 0x69, 0x6e, + 0x6b, 0x73, 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, + 0x3c, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0xa, 0xa, + 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6f, + 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, 0x65, + 0x22, 0x3e, 0xa, 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, + 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, + 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, + 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, + 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, + 0x67, 0x3d, 0x22, 0x30, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, + 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x63, 0x65, 0x6e, + 0x74, 0x65, 0x72, 0x3e, 0x3c, 0x68, 0x31, 0x3e, 0x6c, 0x77, + 0x49, 0x50, 0x20, 0x2d, 0x20, 0x41, 0x20, 0x4c, 0x69, 0x67, + 0x68, 0x74, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x54, + 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, 0x53, 0x74, 0x61, 0x63, + 0x6b, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x3c, 0x2f, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, 0xa, 0x3c, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, 0x6c, + 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, + 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x70, 0x61, + 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0x3e, 0xa, + 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, + 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, + 0x72, 0x22, 0x3e, 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0xa, + 0xa, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x22, 0x3e, 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, 0x3e, + 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x6e, 0x65, 0x77, 0x73, 0x2e, 0x68, + 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x77, 0x73, 0x3c, + 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x63, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x44, 0x6f, 0x63, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6d, 0x61, + 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x74, 0x2e, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4d, 0x61, 0x69, 0x6c, + 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x3c, 0x2f, + 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x2e, 0x68, 0x74, 0x6d, 0x6c, + 0x22, 0x3e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, + 0x67, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, + 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, + 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x22, 0x3e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, + 0x61, 0x64, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, + 0xa, 0x5b, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x5d, 0xa, 0xa, + 0xa, 0xa, 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, + 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x63, + 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0x3c, 0x68, 0x32, 0x3e, + 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x3c, 0x2f, 0x68, 0x32, 0x3e, + 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0xa, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, + 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, + 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, + 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, + 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, + 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, + 0x22, 0x3e, 0x3c, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x30, + 0x22, 0x3e, 0xa, 0x26, 0x6e, 0x62, 0x73, 0x70, 0x3b, 0xa, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x20, + 0x62, 0x67, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x77, + 0x68, 0x69, 0x74, 0x65, 0x22, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x35, 0x34, 0x30, 0x22, 0x3e, 0xa, 0xa, + 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, + 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, + 0xa, 0xa, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x70, 0x61, 0x67, + 0x65, 0x73, 0x3a, 0xa, 0x3c, 0x75, 0x6c, 0x3e, 0xa, 0x3c, + 0x6c, 0x69, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x65, 0x73, 0x72, 0x61, 0x63, 0x2e, 0x65, + 0x6c, 0x65, 0x2e, 0x74, 0x75, 0x65, 0x2e, 0x6e, 0x6c, 0x2f, + 0x7e, 0x6c, 0x65, 0x6f, 0x6e, 0x2f, 0x6c, 0x77, 0x69, 0x70, + 0x2f, 0x22, 0x3e, 0x4c, 0x65, 0x6f, 0x6e, 0x20, 0x57, 0x6f, + 0x65, 0x73, 0x74, 0x65, 0x6e, 0x62, 0x65, 0x72, 0x67, 0x27, + 0x73, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x70, 0x61, 0x67, + 0x65, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0x3c, 0x2f, 0x75, 0x6c, + 0x3e, 0xa, 0xa, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x69, + 0x65, 0x73, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x6c, + 0x77, 0x49, 0x50, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x69, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, + 0x73, 0x3a, 0xa, 0x3c, 0x75, 0x6c, 0x3e, 0xa, 0x3c, 0x6c, + 0x69, 0x3e, 0x55, 0x4b, 0x20, 0x62, 0x61, 0x73, 0x65, 0x64, + 0x20, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, + 0x2e, 0x74, 0x61, 0x6e, 0x67, 0x65, 0x6e, 0x74, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x2e, 0x75, + 0x6b, 0x2f, 0x22, 0x3e, 0x54, 0x61, 0x6e, 0x67, 0x65, 0x6e, + 0x74, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, + 0x4c, 0x74, 0x64, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x61, 0x72, + 0x65, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x77, 0x49, 0x50, + 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, + 0x66, 0x69, 0x6c, 0x6d, 0xa, 0x61, 0x6e, 0x64, 0x20, 0x76, + 0x69, 0x64, 0x65, 0x6f, 0x20, 0x70, 0x6f, 0x73, 0x74, 0x2d, + 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x65, 0x71, 0x75, 0x69, 0x70, 0x6d, 0x65, 0x6e, 0x74, + 0x2e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x3c, 0x61, 0x20, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x78, 0x6f, 0x6e, + 0x2e, 0x74, 0x76, 0x22, 0x3e, 0x41, 0x78, 0x6f, 0x6e, 0x20, + 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x44, 0x65, + 0x73, 0x69, 0x67, 0x6e, 0x20, 0x42, 0x56, 0x3c, 0x2f, 0x61, + 0x3e, 0x20, 0x69, 0x6e, 0x20, 0x54, 0x68, 0x65, 0xa, 0x4e, + 0x65, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x73, + 0x20, 0x69, 0x73, 0x20, 0x6d, 0x65, 0x72, 0x67, 0x69, 0x6e, + 0x67, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x49, 0x50, 0x20, 0x73, + 0x74, 0x61, 0x63, 0x6b, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x75, + 0x73, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0xa, + 0x53, 0x79, 0x6e, 0x61, 0x70, 0x73, 0x65, 0x20, 0x6d, 0x6f, + 0x64, 0x75, 0x6c, 0x61, 0x72, 0x20, 0x62, 0x72, 0x6f, 0x61, + 0x64, 0x63, 0x61, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0xa, 0x3c, 0x2f, 0x75, + 0x6c, 0x3e, 0xa, 0xa, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x6c, + 0x77, 0x49, 0x50, 0x3a, 0xa, 0x3c, 0x75, 0x6c, 0x3e, 0xa, + 0x3c, 0x6c, 0x69, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x63, 0x64, 0x74, 0x2e, 0x6c, 0x75, + 0x74, 0x68, 0x2e, 0x73, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x2f, 0x61, 0x72, 0x65, 0x6e, 0x61, + 0x2f, 0x22, 0x3e, 0x54, 0x68, 0x65, 0x20, 0x41, 0x52, 0x45, + 0x4e, 0x41, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x2d, 0x20, 0x48, 0x6f, 0x63, + 0x6b, 0x65, 0x79, 0x20, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, + 0x73, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70, 0x70, 0x65, 0x64, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x70, 0x75, 0x6c, 0x73, + 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x62, 0x72, 0x65, 0x61, + 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x65, 0x6e, 0x73, + 0x6f, 0x72, 0x73, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, + 0x67, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2e, 0x3c, 0x62, 0x72, + 0x3e, 0x20, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x62, 0x61, 0x72, 0x74, 0x2e, 0x73, 0x6d, + 0x2e, 0x6c, 0x75, 0x74, 0x68, 0x2e, 0x73, 0x65, 0x2f, 0x65, + 0x69, 0x73, 0x32, 0x30, 0x30, 0x31, 0x2f, 0x22, 0x3e, 0x54, + 0x68, 0x65, 0x20, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, + 0x64, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, + 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x32, + 0x30, 0x30, 0x31, 0x20, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6e, + 0x74, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x3c, + 0x2f, 0x61, 0x3e, 0x20, 0x2d, 0x20, 0x46, 0x6c, 0x6f, 0x77, + 0x20, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x62, 0x65, 0x6c, 0x74, 0x20, 0x74, 0x65, 0x6e, 0x73, + 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65, 0x6e, 0x73, 0x6f, 0x72, + 0x73, 0xa, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, + 0x6c, 0x77, 0x49, 0x50, 0x2e, 0x3c, 0x62, 0x72, 0x3e, 0xa, + 0x3c, 0x6c, 0x69, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x64, 0x63, 0x64, 0x65, 0x76, 0x2e, 0x61, 0x6c, 0x6c, 0x75, + 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x22, + 0x3e, 0x4b, 0x4f, 0x53, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x2d, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x4b, 0x4f, 0x53, 0x20, 0x6f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x66, 0x6f, 0x72, 0xa, + 0x53, 0x65, 0x67, 0x61, 0x20, 0x44, 0x72, 0x65, 0x61, 0x6d, + 0x63, 0x61, 0x73, 0x74, 0x20, 0x75, 0x73, 0x65, 0x73, 0x20, + 0x6c, 0x77, 0x49, 0x50, 0x2e, 0x3c, 0x62, 0x72, 0x3e, 0xa, + 0x3c, 0x2f, 0x75, 0x6c, 0x3e, 0xa, 0xa, 0x4f, 0x74, 0x68, + 0x65, 0x72, 0x20, 0x73, 0x6d, 0x61, 0x6c, 0x6c, 0x20, 0x54, + 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, 0x69, 0x6d, 0x70, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x3a, 0xa, 0x3c, 0x75, 0x6c, 0x3e, 0xa, 0x3c, 0x6c, + 0x69, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x64, 0x75, + 0x6e, 0x6b, 0x65, 0x6c, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x75, 0x69, 0x70, 0x2f, 0x22, + 0x3e, 0x75, 0x49, 0x50, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x2d, + 0x20, 0x41, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x73, 0x6d, + 0x61, 0x6c, 0x6c, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, + 0x20, 0xa, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x73, 0x75, + 0x69, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x68, 0x75, 0x6e, 0x64, 0x72, 0x65, + 0x64, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20, 0x52, 0x41, 0x4d, + 0xa, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x66, 0x65, 0x77, + 0x20, 0x6b, 0x69, 0x6c, 0x6f, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x20, 0x6f, 0x66, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20, 0x63, + 0x6f, 0x64, 0x65, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, + 0x3c, 0x62, 0x72, 0x3e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x75, 0x63, 0x69, 0x70, 0x2e, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x66, 0x6f, 0x72, 0x67, + 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x22, 0x3e, 0x75, 0x43, + 0x2f, 0x49, 0x50, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x2d, 0x20, + 0x75, 0x43, 0x2f, 0x49, 0x50, 0x20, 0x69, 0x73, 0x20, 0x61, + 0x20, 0x42, 0x53, 0x44, 0x2d, 0x62, 0x61, 0x73, 0x65, 0x64, + 0xa, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x20, 0x73, 0x74, 0x61, + 0x63, 0x6b, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6d, 0x69, 0x63, + 0x72, 0x6f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x73, 0x2e, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0x3c, + 0x6c, 0x69, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, + 0x69, 0x71, 0x75, 0x6f, 0x72, 0x69, 0x63, 0x65, 0x2e, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x66, 0x6f, 0x72, 0x67, 0x65, + 0x2e, 0x6e, 0x65, 0x74, 0x22, 0x3e, 0x4c, 0x69, 0x71, 0x75, + 0x6f, 0x72, 0x69, 0x63, 0x65, 0x3c, 0x2f, 0x61, 0x3e, 0x20, + 0x2d, 0x20, 0x4c, 0x69, 0x71, 0x75, 0x6f, 0x72, 0x69, 0x63, + 0x65, 0xa, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, + 0x20, 0x61, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, + 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x3c, 0x62, 0x72, 0x3e, + 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 0x65, 0x6e, 0x69, 0x65, + 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x63, 0x70, 0x63, 0x69, 0x70, + 0x2f, 0x22, 0x3e, 0x43, 0x50, 0x43, 0x2f, 0x49, 0x50, 0x3c, + 0x2f, 0x61, 0x3e, 0x20, 0x2d, 0x20, 0x41, 0x20, 0x54, 0x43, + 0x50, 0x2f, 0x49, 0x50, 0x20, 0x73, 0x74, 0x61, 0x63, 0x6b, + 0x20, 0x66, 0x6f, 0x72, 0xa, 0x41, 0x6d, 0x73, 0x74, 0x72, + 0x61, 0x64, 0x20, 0x43, 0x50, 0x43, 0x73, 0x2e, 0x3c, 0x62, + 0x72, 0x3e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x6c, 0x6e, 0x67, 0x2e, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x66, 0x6f, 0x72, 0x67, 0x65, 0x2e, 0x6e, + 0x65, 0x74, 0x2f, 0x22, 0x3e, 0x4c, 0x55, 0x6e, 0x69, 0x78, + 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x2d, 0x20, 0x4c, 0x55, 0x6e, + 0x69, 0x78, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x73, 0x20, 0x61, 0x20, 0x73, 0x6d, 0x61, 0x6c, 0x6c, 0xa, + 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, 0x73, 0x74, 0x61, + 0x63, 0x6b, 0x2e, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0x3c, 0x6c, + 0x69, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x73, 0x77, 0x65, 0x65, 0x74, 0x63, 0x68, 0x65, + 0x72, 0x72, 0x69, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, + 0x6f, 0x6c, 0x7a, 0x36, 0x34, 0x2f, 0x6a, 0x6f, 0x73, 0x2f, + 0x22, 0x3e, 0x4a, 0x4f, 0x53, 0x3c, 0x2f, 0x61, 0x3e, 0x20, + 0x2d, 0x20, 0x4a, 0x4f, 0x53, 0x20, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x65, 0x73, 0x20, 0x61, 0xa, 0x54, 0x43, 0x50, + 0x2f, 0x49, 0x50, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x3c, + 0x62, 0x72, 0x3e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x73, + 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x6e, 0x65, 0x74, + 0x2f, 0x62, 0x70, 0x61, 0x64, 0x64, 0x6f, 0x63, 0x6b, 0x2f, + 0x74, 0x69, 0x6e, 0x79, 0x74, 0x63, 0x70, 0x2f, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x68, 0x74, 0x6d, 0x22, + 0x3e, 0x54, 0x69, 0x6e, 0x79, 0x54, 0x43, 0x50, 0x3c, 0x2f, + 0x61, 0x3e, 0x20, 0x2d, 0x20, 0x41, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x73, 0x6c, 0x69, 0x6d, 0xa, 0x54, 0x43, 0x50, + 0x2c, 0x20, 0x49, 0x50, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x46, 0x54, 0x50, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x3c, + 0x62, 0x72, 0x3e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x6b, 0x79, 0x6c, 0x6c, 0x69, 0x6b, + 0x6b, 0x69, 0x2e, 0x66, 0x6c, 0x75, 0x66, 0x66, 0x2e, 0x6f, + 0x72, 0x67, 0x2f, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, + 0x65, 0x2f, 0x77, 0x77, 0x77, 0x70, 0x69, 0x63, 0x32, 0x2f, + 0x22, 0x3e, 0x57, 0x57, 0x57, 0x70, 0x69, 0x63, 0x32, 0x3c, + 0x2f, 0x61, 0x3e, 0x20, 0x2d, 0x20, 0x53, 0x6d, 0x61, 0x6c, + 0x6c, 0xa, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x54, 0x43, 0x50, + 0x2f, 0x49, 0x50, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x61, 0x20, 0x50, 0x49, 0x43, 0x2e, 0x3c, + 0x62, 0x72, 0x3e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x72, 0x6d, + 0x62, 0x65, 0x61, 0x6c, 0x65, 0x73, 0x2e, 0x66, 0x73, 0x6e, + 0x65, 0x74, 0x2e, 0x63, 0x6f, 0x2e, 0x75, 0x6b, 0x2f, 0x66, + 0x69, 0x6c, 0x65, 0x73, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2f, + 0x70, 0x69, 0x63, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, + 0x70, 0x69, 0x63, 0x73, 0x65, 0x72, 0x76, 0x64, 0x2e, 0x68, + 0x74, 0x6d, 0x22, 0x3e, 0x50, 0x49, 0x43, 0x20, 0x57, 0x65, + 0x62, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3c, 0x2f, + 0x61, 0x3e, 0x20, 0x2d, 0x20, 0x53, 0x6d, 0x61, 0x6c, 0x6c, + 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x54, 0x43, 0x50, 0x2f, + 0x49, 0x50, 0x2f, 0x53, 0x4c, 0x49, 0x50, 0x20, 0x50, 0x49, + 0x43, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x3c, 0x62, 0x72, + 0x3e, 0xa, 0x3c, 0x2f, 0x75, 0x6c, 0x3e, 0xa, 0xa, 0x56, + 0x65, 0x72, 0x79, 0x20, 0x73, 0x6d, 0x61, 0x6c, 0x6c, 0x20, + 0x77, 0x65, 0x62, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x73, 0x3a, 0xa, 0x3c, 0x75, 0x6c, 0x3e, 0xa, 0x3c, 0x6c, + 0x69, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x6f, + 0x72, 0x6c, 0x64, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x7e, 0x66, 0x77, 0x68, 0x69, 0x74, 0x65, 0x2f, + 0x61, 0x63, 0x65, 0x2f, 0x22, 0x3e, 0x77, 0x65, 0x62, 0x41, + 0x43, 0x45, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x2d, 0x20, 0x57, + 0x6f, 0x72, 0x6c, 0x64, 0x27, 0x73, 0x20, 0x53, 0x6d, 0x61, + 0x6c, 0x6c, 0x65, 0x73, 0x74, 0xa, 0x57, 0x65, 0x62, 0x20, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x3c, 0x62, 0x72, + 0x3e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x3c, 0x61, 0x20, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2d, 0x63, 0x63, 0x73, 0x2e, + 0x63, 0x73, 0x2e, 0x75, 0x6d, 0x61, 0x73, 0x73, 0x2e, 0x65, + 0x64, 0x75, 0x2f, 0x7e, 0x73, 0x68, 0x72, 0x69, 0x2f, 0x69, + 0x50, 0x69, 0x63, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x69, 0x50, 0x49, 0x43, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x2d, + 0x20, 0x41, 0x20, 0x4d, 0x61, 0x74, 0x63, 0x68, 0xa, 0x48, + 0x65, 0x61, 0x64, 0x20, 0x53, 0x69, 0x7a, 0x65, 0x64, 0x20, + 0x57, 0x65, 0x62, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x2e, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x75, 0x6c, + 0x3e, 0xa, 0xa, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, + 0x20, 0x52, 0x46, 0x43, 0x73, 0x3a, 0xa, 0x3c, 0x75, 0x6c, + 0x3e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x4a, 0x2e, 0x20, 0x50, + 0x6f, 0x73, 0x74, 0x65, 0x6c, 0x2c, 0x20, 0x3c, 0x61, 0xa, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x66, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x66, 0x74, 0x70, 0x2e, 0x69, 0x65, 0x74, 0x66, + 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x72, 0x66, 0x63, 0x2f, 0x72, + 0x66, 0x63, 0x37, 0x39, 0x31, 0x2e, 0x74, 0x78, 0x74, 0x22, + 0x3e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x3c, 0x2f, + 0x61, 0x3e, 0x2c, 0x20, 0x52, 0x46, 0x43, 0x37, 0x39, 0x31, + 0x2c, 0x20, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x20, 0x31, 0x39, 0x38, 0x31, 0x2e, 0xa, 0x3c, 0x6c, + 0x69, 0x3e, 0x4a, 0x2e, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x65, + 0x6c, 0x2c, 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x66, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x66, 0x74, + 0x70, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, 0x67, + 0x2f, 0x72, 0x66, 0x63, 0x2f, 0x72, 0x66, 0x63, 0x37, 0x39, + 0x32, 0x2e, 0x74, 0x78, 0x74, 0x22, 0x3e, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x20, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x3c, 0x2f, 0x61, 0x3e, 0x2c, 0x20, 0x52, 0x46, 0x43, 0x37, + 0x39, 0x32, 0x2c, 0x20, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x20, 0x31, 0x39, 0x38, 0x31, 0x2e, 0xa, + 0x3c, 0x6c, 0x69, 0x3e, 0x4a, 0x2e, 0x20, 0x50, 0x6f, 0x73, + 0x74, 0x65, 0x6c, 0x2c, 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x66, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x66, 0x74, 0x70, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, + 0x72, 0x67, 0x2f, 0x72, 0x66, 0x63, 0x2f, 0x72, 0x66, 0x63, + 0x37, 0x36, 0x38, 0x2e, 0x74, 0x78, 0x74, 0x22, 0x3e, 0x55, + 0x73, 0x65, 0x72, 0x20, 0x44, 0x61, 0x74, 0x61, 0x67, 0x72, + 0x61, 0x6d, 0x20, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x3c, 0x2f, 0x61, 0x3e, 0x2c, 0x20, 0x52, 0x46, 0x43, + 0x37, 0x36, 0x38, 0x2c, 0x20, 0x41, 0x75, 0x67, 0x75, 0x73, + 0x74, 0x20, 0x31, 0x39, 0x38, 0x30, 0x2e, 0xa, 0x3c, 0x6c, + 0x69, 0x3e, 0x4a, 0x2e, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x65, + 0x6c, 0x2c, 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x66, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x66, 0x74, + 0x70, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, 0x67, + 0x2f, 0x72, 0x66, 0x63, 0x2f, 0x72, 0x66, 0x63, 0x37, 0x39, + 0x33, 0x2e, 0x74, 0x78, 0x74, 0x22, 0x3e, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x3c, 0x2f, 0x61, 0x3e, + 0x2c, 0x20, 0x52, 0x46, 0x43, 0x37, 0x39, 0x33, 0x2c, 0x20, + 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x20, + 0x31, 0x39, 0x38, 0x31, 0x2e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, + 0x44, 0x2e, 0x20, 0x44, 0x2e, 0x20, 0x43, 0x6c, 0x61, 0x72, + 0x6b, 0x2c, 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x66, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x66, 0x74, + 0x70, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, 0x67, + 0x2f, 0x72, 0x66, 0x63, 0x2f, 0x72, 0x66, 0x63, 0x38, 0x31, + 0x33, 0x2e, 0x74, 0x78, 0x74, 0x22, 0x3e, 0x57, 0x69, 0x6e, + 0x64, 0x6f, 0x77, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x41, 0x63, + 0x6b, 0x6e, 0x6f, 0x77, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x20, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, + 0x67, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x54, 0x43, 0x50, 0x3c, + 0x2f, 0x61, 0x3e, 0x2c, 0x20, 0x52, 0x46, 0x43, 0x38, 0x31, + 0x33, 0x2c, 0x20, 0x4a, 0x75, 0x6c, 0x79, 0x20, 0x31, 0x39, + 0x38, 0x32, 0x2e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x44, 0x2e, + 0x20, 0x44, 0x2e, 0x20, 0x43, 0x6c, 0x61, 0x72, 0x6b, 0x2c, + 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x66, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x66, 0x74, 0x70, 0x2e, + 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x72, + 0x66, 0x63, 0x2f, 0x72, 0x66, 0x63, 0x38, 0x31, 0x37, 0x2e, + 0x74, 0x78, 0x74, 0x22, 0x3e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, + 0x61, 0x72, 0x69, 0x74, 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x45, 0x66, 0x66, 0x69, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x79, + 0x20, 0x69, 0x6e, 0x20, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, + 0x3e, 0x2c, 0x20, 0x52, 0x46, 0x43, 0x38, 0x31, 0x37, 0x2c, + 0x20, 0x4a, 0x75, 0x6c, 0x79, 0x20, 0x31, 0x39, 0x38, 0x32, + 0x2e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x52, 0x2e, 0x20, 0x42, + 0x72, 0x61, 0x64, 0x65, 0x6e, 0x2c, 0x20, 0x3c, 0x61, 0xa, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x66, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x66, 0x74, 0x70, 0x2e, 0x69, 0x65, 0x74, 0x66, + 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x72, 0x66, 0x63, 0x2f, 0x72, + 0x66, 0x63, 0x31, 0x31, 0x32, 0x32, 0x2e, 0x74, 0x78, 0x74, + 0x22, 0x3e, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x48, 0x6f, + 0x73, 0x74, 0x73, 0x20, 0x2d, 0x2d, 0x20, 0x43, 0x6f, 0x6d, + 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x3c, 0x2f, 0x61, + 0x3e, 0x2c, 0x20, 0x52, 0x46, 0x43, 0x31, 0x31, 0x32, 0x32, + 0x2c, 0x20, 0x4f, 0x63, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x20, + 0x31, 0x39, 0x38, 0x39, 0x2e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, + 0x54, 0x2e, 0x20, 0x4d, 0x61, 0x6c, 0x6c, 0x6f, 0x72, 0x79, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x41, 0x2e, 0x20, 0x4b, 0x75, + 0x6c, 0x6c, 0x62, 0x65, 0x72, 0x67, 0x2c, 0x20, 0x3c, 0x61, + 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x66, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x66, 0x74, 0x70, 0x2e, 0x69, 0x65, 0x74, + 0x66, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x72, 0x66, 0x63, 0x2f, + 0x72, 0x66, 0x63, 0x31, 0x31, 0x34, 0x31, 0x2e, 0x74, 0x78, + 0x74, 0x22, 0x3e, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x6c, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x3c, 0x2f, + 0x61, 0x3e, 0x2c, 0x20, 0x52, 0x46, 0x43, 0x31, 0x31, 0x34, + 0x31, 0x2c, 0x20, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x79, + 0x20, 0x31, 0x39, 0x39, 0x30, 0x2e, 0xa, 0x3c, 0x6c, 0x69, + 0x3e, 0x41, 0x2e, 0x20, 0x52, 0x69, 0x6a, 0x73, 0x69, 0x6e, + 0x67, 0x68, 0x61, 0x6e, 0x69, 0x2c, 0x20, 0x3c, 0x61, 0xa, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x66, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x66, 0x74, 0x70, 0x2e, 0x69, 0x65, 0x74, 0x66, + 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x72, 0x66, 0x63, 0x2f, 0x72, + 0x66, 0x63, 0x31, 0x36, 0x32, 0x34, 0x2e, 0x74, 0x78, 0x74, + 0x22, 0x3e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x20, 0x76, + 0x69, 0x61, 0x20, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x6c, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x3c, 0x2f, 0x61, 0x3e, 0x2c, 0x20, 0x52, 0x46, 0x43, + 0x31, 0x36, 0x32, 0x34, 0x2c, 0x20, 0x4d, 0x61, 0x79, 0x20, + 0x31, 0x39, 0x39, 0x34, 0x2e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, + 0x52, 0x2e, 0x20, 0x42, 0x72, 0x61, 0x64, 0x65, 0x6e, 0x2c, + 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x66, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x66, 0x74, 0x70, 0x2e, + 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x72, + 0x66, 0x63, 0x2f, 0x72, 0x66, 0x63, 0x31, 0x33, 0x33, 0x37, + 0x2e, 0x74, 0x78, 0x74, 0x22, 0x3e, 0x54, 0x49, 0x4d, 0x45, + 0x2d, 0x57, 0x41, 0x49, 0x54, 0x20, 0x41, 0x73, 0x73, 0x61, + 0x73, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x48, + 0x61, 0x7a, 0x61, 0x72, 0x64, 0x73, 0x20, 0x69, 0x6e, 0x20, + 0x54, 0x43, 0x50, 0x3c, 0x2f, 0x61, 0x3e, 0x2c, 0x20, 0x52, + 0x46, 0x43, 0x31, 0x33, 0x33, 0x37, 0x2c, 0x20, 0x4d, 0x61, + 0x79, 0x20, 0x31, 0x39, 0x39, 0x32, 0x2e, 0xa, 0x3c, 0x6c, + 0x69, 0x3e, 0x42, 0x2e, 0x20, 0x43, 0x61, 0x72, 0x70, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x2c, 0x20, 0x3c, 0x61, 0xa, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x66, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x66, 0x74, 0x70, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, + 0x6f, 0x72, 0x67, 0x2f, 0x72, 0x66, 0x63, 0x2f, 0x72, 0x66, + 0x63, 0x31, 0x39, 0x35, 0x38, 0x2e, 0x74, 0x78, 0x74, 0x22, + 0x3e, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, + 0x75, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x72, 0x69, 0x6e, 0x63, + 0x69, 0x70, 0x6c, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x3c, 0x2f, 0x61, 0x3e, 0x2c, 0x20, 0x52, 0x46, 0x43, + 0x31, 0x39, 0x35, 0x38, 0x2c, 0x20, 0x4a, 0x75, 0x6e, 0x65, + 0x20, 0x31, 0x39, 0x39, 0x36, 0x2e, 0xa, 0x3c, 0x6c, 0x69, + 0x3e, 0x4d, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, + 0x2c, 0x20, 0x56, 0x2e, 0x20, 0x50, 0x61, 0x78, 0x73, 0x6f, + 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x57, 0x2e, 0x20, 0x53, + 0x74, 0x65, 0x76, 0x65, 0x6e, 0x73, 0x2c, 0x20, 0x3c, 0x61, + 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x66, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x66, 0x74, 0x70, 0x2e, 0x69, 0x65, 0x74, + 0x66, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x72, 0x66, 0x63, 0x2f, + 0x72, 0x66, 0x63, 0x32, 0x35, 0x38, 0x31, 0x2e, 0x74, 0x78, + 0x74, 0x22, 0x3e, 0x54, 0x43, 0x50, 0x20, 0x43, 0x6f, 0x6e, + 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3c, 0x2f, 0x61, 0x3e, 0x2c, + 0x20, 0x52, 0x46, 0x43, 0x32, 0x35, 0x38, 0x31, 0x2c, 0x20, + 0x41, 0x70, 0x72, 0x69, 0x6c, 0x20, 0x31, 0x39, 0x39, 0x39, + 0x2e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x53, 0x2e, 0x20, 0x50, + 0x61, 0x72, 0x6b, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x43, 0x2e, 0x20, 0x53, 0x63, 0x68, 0x6d, 0x65, 0x63, 0x68, + 0x65, 0x6c, 0x2c, 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x66, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x66, + 0x74, 0x70, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, + 0x67, 0x2f, 0x72, 0x66, 0x63, 0x2f, 0x72, 0x66, 0x63, 0x32, + 0x33, 0x39, 0x38, 0x2e, 0x74, 0x78, 0x74, 0x22, 0x3e, 0x53, + 0x6f, 0x6d, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x67, 0x20, 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x54, 0x43, 0x50, 0x20, 0x49, 0x6d, 0x70, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x73, 0x3c, 0x2f, + 0x61, 0x3e, 0x2c, 0x20, 0x52, 0x46, 0x43, 0x32, 0x33, 0x39, + 0x38, 0x2c, 0x20, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x20, + 0x31, 0x39, 0x39, 0x38, 0x2e, 0xa, 0x3c, 0x2f, 0x75, 0x6c, + 0x3e, 0xa, 0xa, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, + 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x3a, 0xa, 0x3c, 0x75, 0x6c, 0x3e, 0xa, + 0x3c, 0x6c, 0x69, 0x3e, 0x56, 0x2e, 0x20, 0x4a, 0x61, 0x63, + 0x6f, 0x62, 0x73, 0x6f, 0x6e, 0x2e, 0x20, 0x43, 0x6f, 0x6e, + 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x76, + 0x6f, 0x69, 0x64, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, + 0x20, 0x49, 0x6e, 0x20, 0x3c, 0x69, 0x3e, 0x50, 0x72, 0x6f, + 0x63, 0x65, 0x65, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x6f, + 0x66, 0xa, 0x74, 0x68, 0x65, 0x20, 0x53, 0x49, 0x47, 0x43, + 0x4f, 0x4d, 0x4d, 0x20, 0x27, 0x38, 0x38, 0x20, 0x43, 0x6f, + 0x6e, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x3c, 0x2f, + 0x69, 0x3e, 0x2c, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x66, 0x6f, + 0x72, 0x64, 0x2c, 0x20, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, + 0x72, 0x6e, 0x69, 0x61, 0x2c, 0x20, 0x41, 0x75, 0x67, 0x75, + 0x73, 0x74, 0x20, 0x31, 0x39, 0x38, 0x38, 0x2e, 0xa, 0x3c, + 0x6c, 0x69, 0x3e, 0x56, 0x2e, 0x20, 0x4a, 0x61, 0x63, 0x6f, + 0x62, 0x73, 0x6f, 0x6e, 0x2e, 0x20, 0x34, 0x2e, 0x33, 0x42, + 0x53, 0x44, 0x20, 0x54, 0x43, 0x50, 0x20, 0x68, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x20, 0x70, 0x72, 0x65, 0x64, 0x69, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x3c, 0x69, 0x3e, 0x41, + 0x43, 0x4d, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, + 0x72, 0xa, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x52, 0x65, 0x76, + 0x69, 0x65, 0x77, 0x3c, 0x2f, 0x69, 0x3e, 0x2c, 0x20, 0x32, + 0x30, 0x28, 0x32, 0x29, 0x2c, 0x20, 0x41, 0x70, 0x72, 0x69, + 0x6c, 0x20, 0x31, 0x39, 0x39, 0x30, 0x2e, 0xa, 0x3c, 0x6c, + 0x69, 0x3e, 0x50, 0x2e, 0x20, 0x4b, 0x61, 0x72, 0x6e, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x43, 0x2e, 0x20, 0x50, 0x61, 0x72, + 0x74, 0x72, 0x69, 0x64, 0x67, 0x65, 0x2e, 0x20, 0x49, 0x6d, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x6f, + 0x75, 0x6e, 0x64, 0x2d, 0x74, 0x72, 0x69, 0x70, 0x20, 0x74, + 0x69, 0x6d, 0x65, 0x20, 0x65, 0x73, 0x74, 0x69, 0x6d, 0x61, + 0x74, 0x65, 0x73, 0xa, 0x69, 0x6e, 0x20, 0x72, 0x65, 0x6c, + 0x69, 0x61, 0x62, 0x6c, 0x69, 0x65, 0x20, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x2e, 0x20, 0x49, 0x6e, + 0x20, 0x3c, 0x69, 0x3e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x65, + 0x64, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x53, 0x49, 0x47, 0x43, 0x4f, 0x4d, 0x4d, + 0x20, 0x27, 0x38, 0x37, 0xa, 0x43, 0x6f, 0x6e, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x3c, 0x2f, 0x69, 0x3e, 0x2c, + 0x20, 0x53, 0x74, 0x6f, 0x77, 0x65, 0x2c, 0x20, 0x56, 0x65, + 0x72, 0x6d, 0x6f, 0x6e, 0x74, 0x2c, 0x20, 0x41, 0x75, 0x67, + 0x75, 0x73, 0x74, 0x20, 0x31, 0x39, 0x38, 0x37, 0x2e, 0xa, + 0x3c, 0x6c, 0x69, 0x3e, 0x4a, 0x2e, 0x20, 0x4b, 0x61, 0x79, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x4a, 0x2e, 0x20, 0x50, 0x61, + 0x73, 0x71, 0x75, 0x61, 0x6c, 0x65, 0x2e, 0x20, 0x50, 0x72, + 0x6f, 0x66, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x52, 0x65, 0x64, 0x75, 0x63, 0x69, 0x6e, 0x67, + 0x20, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, + 0x67, 0xa, 0x4f, 0x76, 0x65, 0x72, 0x68, 0x65, 0x61, 0x64, + 0x73, 0x20, 0x69, 0x6e, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, + 0x50, 0x2e, 0x20, 0x3c, 0x69, 0x3e, 0x49, 0x45, 0x45, 0x45, + 0x2f, 0x41, 0x43, 0x4d, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6f, 0x66, + 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, + 0x67, 0x3c, 0x2f, 0x69, 0x3e, 0x2c, 0x20, 0x34, 0x28, 0x36, + 0x29, 0x2c, 0x20, 0x44, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x20, 0x31, 0x39, 0x39, 0x36, 0x2e, 0xa, 0x3c, 0x6c, + 0x69, 0x3e, 0x4c, 0x2e, 0x20, 0x4c, 0x61, 0x72, 0x7a, 0x6f, + 0x6e, 0x2c, 0x20, 0x4d, 0x2e, 0x20, 0x44, 0x65, 0x67, 0x65, + 0x72, 0x6d, 0x61, 0x72, 0x6b, 0x2c, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x53, 0x2e, 0x20, 0x50, 0x69, 0x6e, 0x6b, 0x2e, 0x20, + 0x55, 0x44, 0x50, 0x20, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, + 0x6f, 0x72, 0xa, 0x72, 0x65, 0x61, 0x6c, 0x2d, 0x74, 0x69, + 0x6d, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x6d, 0x65, + 0x64, 0x69, 0x61, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x20, 0x49, 0x6e, + 0x20, 0x3c, 0x69, 0x3e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x65, + 0x64, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x49, 0x45, 0x45, 0x45, 0xa, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x20, 0x43, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x43, 0x6f, 0x6d, 0x6d, + 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x3c, 0x2f, 0x69, 0x3e, 0x2c, 0x20, 0x56, 0x61, 0x6e, 0x63, + 0x6f, 0x75, 0x76, 0x65, 0x72, 0x2c, 0x20, 0x42, 0x72, 0x69, + 0x74, 0x69, 0x73, 0x68, 0xa, 0x43, 0x6f, 0x6c, 0x75, 0x6d, + 0x62, 0x69, 0x61, 0x2c, 0x20, 0x43, 0x61, 0x6e, 0x61, 0x64, + 0x61, 0x2c, 0x20, 0x4a, 0x75, 0x6e, 0x65, 0x20, 0x31, 0x39, + 0x39, 0x39, 0x2e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x50, 0x2e, + 0x20, 0x45, 0x2e, 0x20, 0x4d, 0x63, 0x4b, 0x65, 0x6e, 0x6e, + 0x65, 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x4b, 0x2e, 0x20, + 0x46, 0x2e, 0x20, 0x44, 0x6f, 0x76, 0x65, 0x2e, 0x20, 0x45, + 0x66, 0x63, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x64, 0x65, 0x6d, + 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, + 0x67, 0x20, 0x6f, 0x66, 0xa, 0x69, 0x6e, 0x63, 0x6f, 0x6d, + 0x69, 0x6e, 0x67, 0x20, 0x54, 0x43, 0x50, 0x20, 0x70, 0x61, + 0x63, 0x6b, 0x65, 0x74, 0x73, 0x2e, 0x20, 0x49, 0x6e, 0x20, + 0x3c, 0x69, 0x3e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x65, 0x64, + 0x69, 0x6e, 0x67, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x53, 0x49, 0x47, 0x43, 0x4f, 0x4d, 0x4d, 0x20, + 0x27, 0x39, 0x32, 0x20, 0x43, 0x6f, 0x6e, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x3c, 0x2f, 0x69, 0x3e, 0x2c, 0x20, + 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x2c, + 0x20, 0x4d, 0x61, 0x72, 0x79, 0x6c, 0x61, 0x6e, 0x64, 0x2c, + 0x20, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x20, 0x31, 0x39, + 0x39, 0x32, 0x2e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x43, 0x2e, + 0x20, 0x50, 0x61, 0x72, 0x74, 0x72, 0x69, 0x64, 0x67, 0x65, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x53, 0x2e, 0x20, 0x50, 0x69, + 0x6e, 0x6b, 0x2e, 0x20, 0x41, 0x20, 0x66, 0x61, 0x73, 0x74, + 0x65, 0x72, 0x20, 0x55, 0x44, 0x50, 0x2e, 0x20, 0x3c, 0x69, + 0x3e, 0x49, 0x45, 0x45, 0x45, 0x2f, 0x41, 0x43, 0x4d, 0x20, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0xa, 0x69, 0x6e, 0x20, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x3c, 0x2f, 0x69, 0x3e, + 0x2c, 0x20, 0x31, 0x28, 0x34, 0x29, 0x2c, 0x20, 0x41, 0x75, + 0x67, 0x75, 0x73, 0x74, 0x20, 0x31, 0x39, 0x39, 0x33, 0x2e, + 0xa, 0x3c, 0x2f, 0x75, 0x6c, 0x3e, 0xa, 0xa, 0xa, 0xa, + 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, 0x3e, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0xa, 0x3c, 0x66, 0x6f, 0x6e, + 0x74, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x22, 0x2d, 0x31, + 0x22, 0x3e, 0x3c, 0x69, 0x3e, 0xa, 0x24, 0x44, 0x61, 0x74, + 0x65, 0x3a, 0x20, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x30, 0x31, + 0x2f, 0x31, 0x34, 0x20, 0x31, 0x32, 0x3a, 0x35, 0x32, 0x3a, + 0x32, 0x32, 0x20, 0x24, 0xa, 0x3c, 0x2f, 0x69, 0x3e, 0x3c, + 0x2f, 0x66, 0x6f, 0x6e, 0x74, 0x3e, 0xa, 0x3c, 0x2f, 0x70, + 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa, 0xa, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x20, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x30, 0x22, + 0x3e, 0xa, 0x26, 0x6e, 0x62, 0x73, 0x70, 0x3b, 0xa, 0x3c, + 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x72, 0x3e, + 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, + 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, + 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, + 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, + 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, + 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, + 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x22, 0x3e, 0xa, 0xa, 0x3c, 0x68, + 0x72, 0x3e, 0xa, 0xa, 0xa, 0xa, 0xa, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x49, 0x6e, + 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6e, 0x65, + 0x77, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, + 0x65, 0x77, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, + 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, + 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x6d, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x6c, + 0x69, 0x73, 0x74, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x4d, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x69, + 0x73, 0x74, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, + 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x2e, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x3c, 0x2f, 0x61, 0x3e, 0xa, + 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, + 0x64, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x44, 0x6f, + 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x3c, 0x2f, 0x61, 0x3e, + 0xa, 0xa, 0x7c, 0xa, 0xa, 0x5b, 0x4c, 0x69, 0x6e, 0x6b, + 0x73, 0x5d, 0xa, 0xa, 0xa, 0xa, 0xa, 0x3c, 0x68, 0x72, + 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, + 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, + 0x64, 0x3e, 0xa, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x61, 0x6c, + 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x22, 0x3e, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, + 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x22, 0x3e, 0x41, + 0x64, 0x61, 0x6d, 0x20, 0x44, 0x75, 0x6e, 0x6b, 0x65, 0x6c, + 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, + 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x2f, + 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, + 0x3e, 0xa, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, +}; + +static const char data_licence_html[] = { + /* /licence.html */ + 0x2f, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, 0xa, + 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, + 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x3c, 0x68, + 0x65, 0x61, 0x64, 0x3e, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, + 0x3e, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x2d, 0x20, 0x41, 0x20, + 0x4c, 0x69, 0x67, 0x68, 0x74, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, 0x53, + 0x74, 0x61, 0x63, 0x6b, 0x20, 0x2d, 0x20, 0x6c, 0x77, 0x49, + 0x50, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x63, + 0x6f, 0x64, 0x65, 0x20, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x63, + 0x65, 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x3c, + 0x2f, 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0xa, 0xa, 0x3c, + 0x62, 0x6f, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6f, 0x6c, + 0x6f, 0x72, 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, 0x65, 0x22, + 0x3e, 0xa, 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, 0x30, + 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, + 0x30, 0x22, 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, + 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, 0x63, + 0x65, 0x6c, 0x6c, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, + 0x3d, 0x22, 0x30, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, + 0x3c, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x63, 0x65, 0x6e, 0x74, + 0x65, 0x72, 0x3e, 0x3c, 0x68, 0x31, 0x3e, 0x6c, 0x77, 0x49, + 0x50, 0x20, 0x2d, 0x20, 0x41, 0x20, 0x4c, 0x69, 0x67, 0x68, + 0x74, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x54, 0x43, + 0x50, 0x2f, 0x49, 0x50, 0x20, 0x53, 0x74, 0x61, 0x63, 0x6b, + 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x63, 0x65, 0x6e, + 0x74, 0x65, 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, + 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x3c, 0x2f, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x3e, 0xa, 0xa, 0xa, 0x3c, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, + 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, 0x6c, 0x6c, + 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, + 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x70, 0x61, 0x63, + 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0x3e, 0xa, 0x3c, + 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, + 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, + 0x22, 0x3e, 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0xa, 0xa, + 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0x22, 0x3e, 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, 0x3e, 0xa, + 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x6e, 0x65, 0x77, 0x73, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x77, 0x73, 0x3c, 0x2f, + 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x44, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3c, + 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6d, 0x61, 0x69, + 0x6c, 0x69, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x68, + 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4d, 0x61, 0x69, 0x6c, 0x69, + 0x6e, 0x67, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x3c, 0x2f, 0x61, + 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x6c, 0x6f, 0x67, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, + 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, + 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0x22, 0x3e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, + 0x64, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, + 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6c, + 0x69, 0x6e, 0x6b, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x3c, 0x2f, 0x61, 0x3e, + 0xa, 0xa, 0xa, 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0x3c, + 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, + 0x3c, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0x3c, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0x3c, 0x68, 0x32, + 0x3e, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x6c, 0x69, + 0x63, 0x65, 0x6e, 0x63, 0x65, 0x3c, 0x2f, 0x68, 0x32, 0x3e, + 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0xa, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, + 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, + 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, + 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, + 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, + 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, + 0x22, 0x3e, 0x3c, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x30, + 0x22, 0x3e, 0xa, 0x26, 0x6e, 0x62, 0x73, 0x70, 0x3b, 0xa, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x20, + 0x62, 0x67, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x77, + 0x68, 0x69, 0x74, 0x65, 0x22, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x35, 0x34, 0x30, 0x22, 0x3e, 0xa, 0xa, + 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, + 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x31, 0x2c, 0x20, + 0x53, 0x77, 0x65, 0x64, 0x69, 0x73, 0x68, 0x20, 0x49, 0x6e, + 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x20, 0x6f, 0x66, + 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20, + 0x53, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0xa, 0x41, + 0x6c, 0x6c, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, + 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x2e, 0x3c, + 0x62, 0x72, 0x3e, 0xa, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0x52, + 0x65, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x75, 0x73, + 0x65, 0x20, 0x69, 0x6e, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x62, 0x69, 0x6e, 0x61, + 0x72, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2c, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x72, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0xa, 0x6d, 0x6f, 0x64, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, + 0x20, 0x61, 0x72, 0x65, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, + 0x74, 0x74, 0x65, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, + 0x6e, 0x67, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0xa, 0x61, 0x72, 0x65, 0x20, 0x6d, + 0x65, 0x74, 0x3a, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0x3c, 0x6f, + 0x6c, 0x3e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x20, 0x52, 0x65, + 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x6d, + 0x75, 0x73, 0x74, 0x20, 0x72, 0x65, 0x74, 0x61, 0x69, 0x6e, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x62, 0x6f, 0x76, 0x65, + 0x20, 0x63, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, + 0xa, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x2c, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, + 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67, + 0x20, 0x64, 0x69, 0x73, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x65, + 0x72, 0x2e, 0x3c, 0x62, 0x72, 0x3e, 0x20, 0xa, 0x3c, 0x62, + 0x72, 0x3e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x20, 0x52, 0x65, + 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x62, 0x69, 0x6e, + 0x61, 0x72, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, + 0x75, 0x73, 0x74, 0x20, 0x72, 0x65, 0x70, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x62, + 0x6f, 0x76, 0x65, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x72, 0x69, + 0x67, 0x68, 0x74, 0xa, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, + 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6c, 0x69, 0x73, + 0x74, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, + 0x69, 0x6e, 0x67, 0x20, 0x64, 0x69, 0x73, 0x63, 0x6c, 0x61, + 0x69, 0x6d, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, + 0x65, 0xa, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x2f, + 0x6f, 0x72, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x6d, + 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x20, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0xa, 0x64, 0x69, 0x73, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x3c, 0x62, 0x72, 0x3e, 0x20, 0xa, 0x3c, 0x62, 0x72, 0x3e, + 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x20, 0x4e, 0x65, 0x69, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x61, + 0x6d, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x20, + 0x6e, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x69, 0x74, 0x73, + 0xa, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x6f, 0x72, 0x73, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, + 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x65, + 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x20, 0x6f, 0x72, 0x20, + 0x70, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x20, 0x70, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x20, 0x64, 0x65, 0x72, + 0x69, 0x76, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0xa, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, + 0x61, 0x72, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, + 0x74, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, + 0x20, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x20, 0x77, 0x72, 0x69, + 0x74, 0x74, 0x65, 0x6e, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x3c, 0x62, 0x72, + 0x3e, 0x20, 0xa, 0x3c, 0x2f, 0x6f, 0x6c, 0x3e, 0xa, 0x3c, + 0x62, 0x72, 0x3e, 0xa, 0x54, 0x48, 0x49, 0x53, 0x20, 0x53, + 0x4f, 0x46, 0x54, 0x57, 0x41, 0x52, 0x45, 0x20, 0x49, 0x53, + 0x20, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44, 0x45, 0x44, 0x20, + 0x42, 0x59, 0x20, 0x54, 0x48, 0x45, 0x20, 0x49, 0x4e, 0x53, + 0x54, 0x49, 0x54, 0x55, 0x54, 0x45, 0x20, 0x41, 0x4e, 0x44, + 0x20, 0x43, 0x4f, 0x4e, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, + 0x4f, 0x52, 0x53, 0x20, 0x60, 0x41, 0x53, 0x20, 0x49, 0x53, + 0x27, 0x20, 0x41, 0x4e, 0x44, 0x20, 0xa, 0x41, 0x4e, 0x59, + 0x20, 0x45, 0x58, 0x50, 0x52, 0x45, 0x53, 0x53, 0x20, 0x4f, + 0x52, 0x20, 0x49, 0x4d, 0x50, 0x4c, 0x49, 0x45, 0x44, 0x20, + 0x57, 0x41, 0x52, 0x52, 0x41, 0x4e, 0x54, 0x49, 0x45, 0x53, + 0x2c, 0x20, 0x49, 0x4e, 0x43, 0x4c, 0x55, 0x44, 0x49, 0x4e, + 0x47, 0x2c, 0x20, 0x42, 0x55, 0x54, 0x20, 0x4e, 0x4f, 0x54, + 0x20, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x45, 0x44, 0x20, 0x54, + 0x4f, 0x2c, 0x20, 0x54, 0x48, 0x45, 0x20, 0xa, 0x49, 0x4d, + 0x50, 0x4c, 0x49, 0x45, 0x44, 0x20, 0x57, 0x41, 0x52, 0x52, + 0x41, 0x4e, 0x54, 0x49, 0x45, 0x53, 0x20, 0x4f, 0x46, 0x20, + 0x4d, 0x45, 0x52, 0x43, 0x48, 0x41, 0x4e, 0x54, 0x41, 0x42, + 0x49, 0x4c, 0x49, 0x54, 0x59, 0x20, 0x41, 0x4e, 0x44, 0x20, + 0x46, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x20, 0x46, 0x4f, + 0x52, 0x20, 0x41, 0x20, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, + 0x55, 0x4c, 0x41, 0x52, 0x20, 0x50, 0x55, 0x52, 0x50, 0x4f, + 0x53, 0x45, 0x20, 0xa, 0x41, 0x52, 0x45, 0x20, 0x44, 0x49, + 0x53, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, 0x2e, 0x20, + 0x20, 0x49, 0x4e, 0x20, 0x4e, 0x4f, 0x20, 0x45, 0x56, 0x45, + 0x4e, 0x54, 0x20, 0x53, 0x48, 0x41, 0x4c, 0x4c, 0x20, 0x54, + 0x48, 0x45, 0x20, 0x49, 0x4e, 0x53, 0x54, 0x49, 0x54, 0x55, + 0x54, 0x45, 0x20, 0x4f, 0x52, 0x20, 0x43, 0x4f, 0x4e, 0x54, + 0x52, 0x49, 0x42, 0x55, 0x54, 0x4f, 0x52, 0x53, 0x20, 0x42, + 0x45, 0x20, 0x4c, 0x49, 0x41, 0x42, 0x4c, 0x45, 0x20, 0xa, + 0x46, 0x4f, 0x52, 0x20, 0x41, 0x4e, 0x59, 0x20, 0x44, 0x49, + 0x52, 0x45, 0x43, 0x54, 0x2c, 0x20, 0x49, 0x4e, 0x44, 0x49, + 0x52, 0x45, 0x43, 0x54, 0x2c, 0x20, 0x49, 0x4e, 0x43, 0x49, + 0x44, 0x45, 0x4e, 0x54, 0x41, 0x4c, 0x2c, 0x20, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x41, 0x4c, 0x2c, 0x20, 0x45, 0x58, 0x45, + 0x4d, 0x50, 0x4c, 0x41, 0x52, 0x59, 0x2c, 0x20, 0x4f, 0x52, + 0x20, 0x43, 0x4f, 0x4e, 0x53, 0x45, 0x51, 0x55, 0x45, 0x4e, + 0x54, 0x49, 0x41, 0x4c, 0x20, 0xa, 0x44, 0x41, 0x4d, 0x41, + 0x47, 0x45, 0x53, 0x20, 0x28, 0x49, 0x4e, 0x43, 0x4c, 0x55, + 0x44, 0x49, 0x4e, 0x47, 0x2c, 0x20, 0x42, 0x55, 0x54, 0x20, + 0x4e, 0x4f, 0x54, 0x20, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x45, + 0x44, 0x20, 0x54, 0x4f, 0x2c, 0x20, 0x50, 0x52, 0x4f, 0x43, + 0x55, 0x52, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x20, 0x4f, 0x46, + 0x20, 0x53, 0x55, 0x42, 0x53, 0x54, 0x49, 0x54, 0x55, 0x54, + 0x45, 0x20, 0x47, 0x4f, 0x4f, 0x44, 0x53, 0x20, 0xa, 0x4f, + 0x52, 0x20, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x53, + 0x3b, 0x20, 0x4c, 0x4f, 0x53, 0x53, 0x20, 0x4f, 0x46, 0x20, + 0x55, 0x53, 0x45, 0x2c, 0x20, 0x44, 0x41, 0x54, 0x41, 0x2c, + 0x20, 0x4f, 0x52, 0x20, 0x50, 0x52, 0x4f, 0x46, 0x49, 0x54, + 0x53, 0x3b, 0x20, 0x4f, 0x52, 0x20, 0x42, 0x55, 0x53, 0x49, + 0x4e, 0x45, 0x53, 0x53, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x52, + 0x52, 0x55, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x29, 0x20, 0xa, + 0x48, 0x4f, 0x57, 0x45, 0x56, 0x45, 0x52, 0x20, 0x43, 0x41, + 0x55, 0x53, 0x45, 0x44, 0x20, 0x41, 0x4e, 0x44, 0x20, 0x4f, + 0x4e, 0x20, 0x41, 0x4e, 0x59, 0x20, 0x54, 0x48, 0x45, 0x4f, + 0x52, 0x59, 0x20, 0x4f, 0x46, 0x20, 0x4c, 0x49, 0x41, 0x42, + 0x49, 0x4c, 0x49, 0x54, 0x59, 0x2c, 0x20, 0x57, 0x48, 0x45, + 0x54, 0x48, 0x45, 0x52, 0x20, 0x49, 0x4e, 0x20, 0x43, 0x4f, + 0x4e, 0x54, 0x52, 0x41, 0x43, 0x54, 0x2c, 0x20, 0x53, 0x54, + 0x52, 0x49, 0x43, 0x54, 0x20, 0xa, 0x4c, 0x49, 0x41, 0x42, + 0x49, 0x4c, 0x49, 0x54, 0x59, 0x2c, 0x20, 0x4f, 0x52, 0x20, + 0x54, 0x4f, 0x52, 0x54, 0x20, 0x28, 0x49, 0x4e, 0x43, 0x4c, + 0x55, 0x44, 0x49, 0x4e, 0x47, 0x20, 0x4e, 0x45, 0x47, 0x4c, + 0x49, 0x47, 0x45, 0x4e, 0x43, 0x45, 0x20, 0x4f, 0x52, 0x20, + 0x4f, 0x54, 0x48, 0x45, 0x52, 0x57, 0x49, 0x53, 0x45, 0x29, + 0x20, 0x41, 0x52, 0x49, 0x53, 0x49, 0x4e, 0x47, 0x20, 0x49, + 0x4e, 0x20, 0x41, 0x4e, 0x59, 0x20, 0x57, 0x41, 0x59, 0x20, + 0xa, 0x4f, 0x55, 0x54, 0x20, 0x4f, 0x46, 0x20, 0x54, 0x48, + 0x45, 0x20, 0x55, 0x53, 0x45, 0x20, 0x4f, 0x46, 0x20, 0x54, + 0x48, 0x49, 0x53, 0x20, 0x53, 0x4f, 0x46, 0x54, 0x57, 0x41, + 0x52, 0x45, 0x2c, 0x20, 0x45, 0x56, 0x45, 0x4e, 0x20, 0x49, + 0x46, 0x20, 0x41, 0x44, 0x56, 0x49, 0x53, 0x45, 0x44, 0x20, + 0x4f, 0x46, 0x20, 0x54, 0x48, 0x45, 0x20, 0x50, 0x4f, 0x53, + 0x53, 0x49, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x20, 0x4f, + 0x46, 0x20, 0xa, 0x53, 0x55, 0x43, 0x48, 0x20, 0x44, 0x41, + 0x4d, 0x41, 0x47, 0x45, 0x2e, 0x20, 0x3c, 0x62, 0x72, 0x3e, + 0xa, 0xa, 0xa, 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, + 0x67, 0x6e, 0x3d, 0x22, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, + 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa, + 0x3c, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x7a, 0x65, + 0x3d, 0x22, 0x2d, 0x31, 0x22, 0x3e, 0x3c, 0x69, 0x3e, 0xa, + 0x24, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x32, 0x30, 0x30, + 0x31, 0x2f, 0x31, 0x30, 0x2f, 0x30, 0x38, 0x20, 0x31, 0x33, + 0x3a, 0x31, 0x31, 0x3a, 0x34, 0x35, 0x20, 0x24, 0xa, 0x3c, + 0x2f, 0x69, 0x3e, 0x3c, 0x2f, 0x66, 0x6f, 0x6e, 0x74, 0x3e, + 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x74, + 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x35, 0x30, 0x22, 0x3e, 0xa, 0x26, + 0x6e, 0x62, 0x73, 0x70, 0x3b, 0xa, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x3c, 0x2f, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, 0x3c, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, 0x6c, + 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, + 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x70, 0x61, + 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0x3e, 0xa, + 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, + 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, + 0x72, 0x22, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, + 0xa, 0xa, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, + 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x49, 0x6e, 0x74, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, + 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6e, 0x65, 0x77, 0x73, 0x2e, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x77, 0x73, + 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, + 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x44, 0x6f, + 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, + 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6d, + 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x74, + 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4d, 0x61, 0x69, + 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x3c, + 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0x22, 0x3e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, + 0x6f, 0x67, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, + 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x68, + 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, + 0x6f, 0x61, 0x64, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, + 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0x22, 0x3e, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x3c, 0x2f, + 0x61, 0x3e, 0xa, 0xa, 0xa, 0xa, 0x3c, 0x68, 0x72, 0x3e, + 0xa, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, + 0x72, 0x3e, 0x3c, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, + 0x3e, 0xa, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x61, 0x6c, 0x69, + 0x67, 0x6e, 0x3d, 0x22, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, + 0x3e, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, + 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x22, 0x3e, 0x41, 0x64, + 0x61, 0x6d, 0x20, 0x44, 0x75, 0x6e, 0x6b, 0x65, 0x6c, 0x73, + 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, + 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x2f, 0x74, + 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, + 0xa, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, }; + +static const char data_img_sics_gif[] = { + /* /img/sics.gif */ + 0x2f, 0x69, 0x6d, 0x67, 0x2f, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x69, 0x66, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, + 0x65, 0x2f, 0x67, 0x69, 0x66, 0xd, 0xa, 0xd, 0xa, 0x47, + 0x49, 0x46, 0x38, 0x39, 0x61, 0x46, 00, 0x22, 00, 0xa5, + 00, 00, 0xd9, 0x2b, 0x39, 0x6a, 0x6a, 0x6a, 0xbf, 0xbf, + 0xbf, 0x93, 0x93, 0x93, 0xf, 0xf, 0xf, 0xb0, 0xb0, 0xb0, + 0xa6, 0xa6, 0xa6, 0x80, 0x80, 0x80, 0x76, 0x76, 0x76, 0x1e, + 0x1e, 0x1e, 0x9d, 0x9d, 0x9d, 0x2e, 0x2e, 0x2e, 0x49, 0x49, + 0x49, 0x54, 0x54, 0x54, 0x8a, 0x8a, 0x8a, 0x60, 0x60, 0x60, + 0xc6, 0xa6, 0x99, 0xbd, 0xb5, 0xb2, 0xc2, 0xab, 0xa1, 0xd9, + 0x41, 0x40, 0xd5, 0x67, 0x55, 0xc0, 0xb0, 0xaa, 0xd5, 0x5e, + 0x4e, 0xd6, 0x50, 0x45, 0xcc, 0x93, 0x7d, 0xc8, 0xa1, 0x90, + 0xce, 0x8b, 0x76, 0xd2, 0x7b, 0x65, 0xd1, 0x84, 0x6d, 0xc9, + 0x99, 0x86, 0x3a, 0x3a, 0x3a, 00, 00, 00, 0xb8, 0xb8, + 0xb8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x2c, 00, 00, 00, 00, 0x46, + 00, 0x22, 00, 00, 0x6, 0xfe, 0x40, 0x90, 0x70, 0x48, + 0x2c, 0x1a, 0x8f, 0xc8, 0xa4, 0x72, 0xc9, 0x6c, 0x3a, 0x9f, + 0xd0, 0xa8, 0x74, 0x4a, 0xad, 0x5a, 0xaf, 0xd8, 0xac, 0x76, + 0xa9, 0x40, 0x4, 0xbe, 0x83, 0xe2, 0x60, 0x3c, 0x50, 0x20, + 0xd, 0x8e, 0x6f, 00, 0x31, 0x28, 0x1c, 0xd, 0x7, 0xb5, + 0xc3, 0x60, 0x75, 0x24, 0x3e, 0xf8, 0xfc, 0x87, 0x11, 0x6, + 0xe9, 0x3d, 0x46, 0x7, 0xb, 0x7a, 0x7a, 0x7c, 0x43, 0x6, + 0x1e, 0x84, 0x78, 0xb, 0x7, 0x6e, 0x51, 0x1, 0x8a, 0x84, + 0x8, 0x7e, 0x79, 0x80, 0x87, 0x89, 0x91, 0x7a, 0x93, 0xa, + 0x4, 0x99, 0x78, 0x96, 0x4f, 0x3, 0x9e, 0x79, 0x1, 0x94, + 0x9f, 0x43, 0x9c, 0xa3, 0xa4, 0x5, 0x77, 0xa3, 0xa0, 0x4e, + 0x98, 0x79, 0xb, 0x1e, 0x83, 0xa4, 0xa6, 0x1f, 0x96, 0x5, + 0x9d, 0xaa, 0x78, 0x1, 0x7, 0x84, 0x4, 0x1e, 0x1e, 0xbb, + 0xb8, 0x51, 0x84, 0xe, 0x43, 0x5, 0x7, 0x77, 0xa5, 0x7f, + 0x42, 0xb1, 0xb2, 0x1, 0x63, 0x8, 0xd, 0xbb, 0x1, 0xc, + 0x7a, 0xd, 0x44, 0xe, 0xd8, 0xaf, 0x4c, 0x5, 0x7a, 0x4, + 0x47, 0x7, 0x7, 0xb7, 0x80, 0xa2, 0xe1, 0x7d, 0x44, 0x5, + 0x1, 0x4, 0x1, 0xd0, 0xea, 0x87, 0x93, 0x4f, 0xe0, 0x9a, + 0x49, 0xce, 0xd8, 0x79, 0x4, 0x66, 0x20, 0x15, 0x10, 0x10, + 0x11, 0x92, 0x29, 0x80, 0xb6, 0xc0, 0x91, 0x15, 0x45, 0x1e, + 0x90, 0x19, 0x71, 0x46, 0xa8, 0x5c, 0x4, 0xe, 00, 0x22, + 0x4e, 0xe8, 0x40, 0x24, 0x9f, 0x3e, 0x4, 0x6, 0xa7, 0x58, + 0xd4, 0x93, 0xa0, 0x1c, 0x91, 0x3f, 0xe8, 0xf0, 0x88, 0x3, + 0xb1, 0x21, 0xa2, 0x49, 00, 0x19, 0x86, 0xfc, 0x52, 0x44, + 0xe0, 0x1, 0x9d, 0x29, 0x21, 0x15, 0x25, 0x50, 0xf7, 0x67, + 0x25, 0x1e, 0x6, 0xfd, 0x4e, 0x9a, 0xb4, 0x90, 0xac, 0x15, + 0xfa, 0xcb, 0x52, 0x53, 0x1e, 0x8c, 0xf2, 0xf8, 0x7, 0x92, + 0x2d, 0x8, 0x3a, 0x4d, 0x12, 0x49, 0x95, 0x49, 0xdb, 0x14, + 0x4, 0xc4, 0x14, 0x85, 0x29, 0xaa, 0xe7, 0x1, 0x8, 0xa4, + 0x49, 0x1, 0x14, 0x51, 0xe0, 0x53, 0x91, 0xd5, 0x29, 0x6, + 0x1a, 0x64, 0x2, 0xf4, 0xc7, 0x81, 0x9e, 0x5, 0x20, 0x22, + 0x64, 0xa5, 0x30, 0xae, 0xab, 0x9e, 0x97, 0x53, 0xd8, 0xb9, + 0xfd, 0x50, 0xef, 0x93, 0x2, 0x42, 0x74, 0x34, 0xe8, 0x9c, + 0x20, 0x21, 0xc9, 0x1, 0x68, 0x78, 0xe6, 0x55, 0x29, 0x20, + 0x56, 0x4f, 0x4c, 0x40, 0x51, 0x71, 0x82, 0xc0, 0x70, 0x21, + 0x22, 0x85, 0xbe, 0x4b, 0x1c, 0x44, 0x5, 0xea, 0xa4, 0x1, + 0xbf, 0x22, 0xb5, 0xf0, 0x1c, 0x6, 0x51, 0x38, 0x8f, 0xe0, + 0x22, 0xec, 0x18, 0xac, 0x39, 0x22, 0xd4, 0xd6, 0x93, 0x44, + 0x1, 0x32, 0x82, 0xc8, 0xfc, 0x61, 0xb3, 0x1, 0x45, 0xc, + 0x2e, 0x83, 0x30, 0xd0, 0xe, 0x17, 0x24, 0xf, 0x70, 0x85, + 0x94, 0xee, 0x5, 0x5, 0x53, 0x4b, 0x32, 0x1b, 0x3f, 0x98, + 0xd3, 0x1d, 0x29, 0x81, 0xb0, 0xae, 0x1e, 0x8c, 0x7e, 0x68, + 0xe0, 0x60, 0x5a, 0x54, 0x8f, 0xb0, 0x78, 0x69, 0x73, 0x6, + 0xa2, 00, 0x6b, 0x57, 0xca, 0x3d, 0x11, 0x50, 0xbd, 0x4, + 0x30, 0x4b, 0x3a, 0xd4, 0xab, 0x5f, 0x1f, 0x9b, 0x3d, 0x13, + 0x74, 0x27, 0x88, 0x3c, 0x25, 0xe0, 0x17, 0xbe, 0x7a, 0x79, + 0x45, 0xd, 0xc, 0xb0, 0x8b, 0xda, 0x90, 0xca, 0x80, 0x6, + 0x5d, 0x17, 0x60, 0x1c, 0x22, 0x4c, 0xd8, 0x57, 0x22, 0x6, + 0x20, 00, 0x98, 0x7, 0x8, 0xe4, 0x56, 0x80, 0x80, 0x1c, + 0xc5, 0xb7, 0xc5, 0x82, 0xc, 0x36, 0xe8, 0xe0, 0x83, 0x10, + 0x46, 0x28, 0xe1, 0x84, 0x14, 0x56, 0x68, 0xa1, 0x10, 0x41, + 00, 00, 0x3b, }; + +static const char data_index_html[] = { + /* /index.html */ + 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, 0xa, + 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, + 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x3c, 0x68, + 0x65, 0x61, 0x64, 0x3e, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, + 0x3e, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x2d, 0x20, 0x41, 0x20, + 0x4c, 0x69, 0x67, 0x68, 0x74, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, 0x53, + 0x74, 0x61, 0x63, 0x6b, 0x20, 0x2d, 0x20, 0x49, 0x6e, 0x74, + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3c, + 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x3c, 0x2f, 0x68, + 0x65, 0x61, 0x64, 0x3e, 0xa, 0x3c, 0x6d, 0x65, 0x74, 0x61, + 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x20, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x3d, 0x22, 0x6c, + 0x77, 0x49, 0x50, 0x20, 0x2d, 0x20, 0x41, 0x20, 0x46, 0x72, + 0x65, 0x65, 0x20, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x77, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, + 0x50, 0xa, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, + 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, 0x3e, + 0xa, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x6e, 0x61, 0x6d, + 0x65, 0x3d, 0x22, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, + 0x73, 0x22, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x3d, 0x22, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x61, 0x6c, 0x2c, + 0x20, 0x74, 0x69, 0x6e, 0x79, 0x2c, 0x20, 0x54, 0x43, 0x50, + 0x2f, 0x49, 0x50, 0x2c, 0x20, 0x73, 0x74, 0x61, 0x63, 0x6b, + 0x2c, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0xa, 0x65, 0x6d, + 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x2c, 0x20, 0x73, 0x6d, + 0x61, 0x6c, 0x6c, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x2c, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x72, 0x65, 0x65, 0x2c, + 0x20, 0x42, 0x53, 0x44, 0x2d, 0x6c, 0x69, 0x63, 0x65, 0x6e, + 0x63, 0x65, 0x2c, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, + 0x20, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x22, 0x3e, 0xa, 0xa, + 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6f, + 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, 0x65, + 0x22, 0x3e, 0xa, 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, + 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, + 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, + 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, + 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, + 0x67, 0x3d, 0x22, 0x30, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, + 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x63, 0x65, 0x6e, + 0x74, 0x65, 0x72, 0x3e, 0x3c, 0x68, 0x31, 0x3e, 0x6c, 0x77, + 0x49, 0x50, 0x20, 0x2d, 0x20, 0x41, 0x20, 0x4c, 0x69, 0x67, + 0x68, 0x74, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x54, + 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, 0x53, 0x74, 0x61, 0x63, + 0x6b, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x3c, 0x2f, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, 0xa, 0x3c, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, 0x6c, + 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, + 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x70, 0x61, + 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0x3e, 0xa, + 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, + 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, + 0x72, 0x22, 0x3e, 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0xa, + 0xa, 0xa, 0xa, 0x5b, 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5d, 0xa, 0xa, 0xa, + 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x6e, 0x65, 0x77, 0x73, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x77, 0x73, 0x3c, 0x2f, 0x61, + 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x63, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x68, + 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x44, 0x6f, 0x63, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, + 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6d, 0x61, 0x69, 0x6c, + 0x69, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x22, 0x3e, 0x4d, 0x61, 0x69, 0x6c, 0x69, 0x6e, + 0x67, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x3c, 0x2f, 0x61, 0x3e, + 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x6c, 0x6f, 0x67, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x3c, + 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x77, + 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x68, 0x74, 0x6d, 0x6c, + 0x22, 0x3e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, + 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6c, 0x69, + 0x6e, 0x6b, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0xa, + 0xa, 0xa, 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, + 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x63, + 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0x3c, 0x68, 0x32, 0x3e, + 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x3c, 0x2f, 0x68, 0x32, 0x3e, 0x3c, 0x2f, 0x63, + 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, + 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x3c, 0x2f, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, 0x3c, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, 0x6c, + 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, + 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x70, 0x61, + 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0x3e, 0x3c, + 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x30, 0x22, 0x3e, 0xa, + 0x26, 0x6e, 0x62, 0x73, 0x70, 0x3b, 0xa, 0x3c, 0x2f, 0x74, + 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x20, 0x62, 0x67, 0x63, + 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, + 0x65, 0x22, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x35, 0x34, 0x30, 0x22, 0x3e, 0xa, 0xa, 0x3c, 0x70, 0x20, + 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x6a, 0x75, 0x73, + 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, 0x6c, 0x77, 0x49, + 0x50, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x73, 0x6d, 0x61, + 0x6c, 0x6c, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x70, 0x65, 0x6e, + 0x64, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x43, 0x50, + 0x2f, 0x49, 0x50, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0xa, 0x73, 0x75, 0x69, 0x74, 0x65, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x62, 0x65, + 0x65, 0x6e, 0x20, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x3c, 0x61, 0xa, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, + 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, + 0x22, 0x3e, 0x41, 0x64, 0x61, 0x6d, 0x20, 0x44, 0x75, 0x6e, + 0x6b, 0x65, 0x6c, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x61, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x3c, 0x61, 0xa, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, + 0x2e, 0x73, 0x65, 0x2f, 0x63, 0x6e, 0x61, 0x2f, 0x22, 0x3e, + 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x20, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, + 0x74, 0x75, 0x72, 0x65, 0x73, 0xa, 0x6c, 0x61, 0x62, 0x3c, + 0x2f, 0x61, 0x3e, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, + 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x22, + 0x3e, 0x53, 0x77, 0x65, 0x64, 0x69, 0x73, 0x68, 0x20, 0x49, + 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x20, 0x6f, + 0x66, 0xa, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, + 0x20, 0x53, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x3c, 0x2f, + 0x61, 0x3e, 0x20, 0x61, 0x73, 0x20, 0x70, 0x61, 0x72, 0x74, + 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x3c, 0x61, + 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, + 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x63, 0x6e, 0x61, 0x2f, + 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x2f, + 0x22, 0x3e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x2e, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, + 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, + 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, + 0xa, 0x54, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x63, 0x75, 0x73, + 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x77, + 0x49, 0x50, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x74, 0x6f, + 0x20, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x52, 0x41, 0x4d, 0x20, 0x75, 0x73, 0x61, 0x67, + 0x65, 0xa, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x73, 0x74, + 0x69, 0x6c, 0x6c, 0x20, 0x68, 0x61, 0x76, 0x69, 0x6e, 0x67, + 0x20, 0x61, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x73, 0x63, + 0x61, 0x6c, 0x65, 0x20, 0x54, 0x43, 0x50, 0x2e, 0x20, 0x54, + 0x68, 0x69, 0x73, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x73, 0x20, + 0x6c, 0x77, 0x49, 0x50, 0x20, 0x73, 0x75, 0x69, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x75, 0x73, + 0x65, 0xa, 0x69, 0x6e, 0x20, 0x65, 0x6d, 0x62, 0x65, 0x64, + 0x64, 0x65, 0x64, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x65, 0x6e, + 0x74, 0x68, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x6b, 0x69, 0x6c, + 0x6f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, + 0x66, 0x72, 0x65, 0x65, 0x20, 0x52, 0x41, 0x4d, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x72, 0x6f, 0x6f, 0x6d, 0x20, 0x66, 0x6f, + 0x72, 0xa, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x34, + 0x30, 0x20, 0x6b, 0x69, 0x6c, 0x6f, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, + 0x52, 0x4f, 0x4d, 0x2e, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, + 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, + 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, + 0xa, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x66, 0x65, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x3a, 0xa, 0x3c, 0x75, 0x6c, 0x3e, + 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x49, 0x50, 0x20, 0x28, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x29, 0x20, 0x69, 0x6e, + 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x61, + 0x63, 0x6b, 0x65, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x77, 0x61, + 0x72, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x76, 0x65, 0x72, + 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0xa, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x20, 0xa, + 0x3c, 0x6c, 0x69, 0x3e, 0x49, 0x43, 0x4d, 0x50, 0x20, 0x28, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x43, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x20, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x29, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x6d, 0x61, 0x69, + 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0xa, 0x61, + 0x6e, 0x64, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67, 0x67, 0x69, + 0x6e, 0x67, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x55, 0x44, 0x50, + 0x20, 0x28, 0x55, 0x73, 0x65, 0x72, 0x20, 0x44, 0x61, 0x74, + 0x61, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x29, 0x20, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x78, 0x70, 0x65, + 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x20, 0x55, + 0x44, 0x50, 0x2d, 0x6c, 0x69, 0x74, 0x65, 0xa, 0x65, 0x78, + 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0xa, + 0x3c, 0x6c, 0x69, 0x3e, 0x54, 0x43, 0x50, 0x20, 0x28, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x29, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x63, 0x6f, 0x6e, 0x67, 0x65, + 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x2c, 0x20, 0x52, 0x54, 0x54, 0xa, 0x65, + 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x66, 0x61, 0x73, 0x74, 0x20, 0x72, + 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2f, 0x66, 0x61, + 0x73, 0x74, 0x20, 0x72, 0x65, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x6d, 0x69, 0x74, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x53, 0x70, + 0x65, 0x63, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x20, + 0x6e, 0x6f, 0x2d, 0x63, 0x6f, 0x70, 0x79, 0x20, 0x41, 0x50, + 0x49, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x6e, 0x68, 0x61, + 0x6e, 0x63, 0x65, 0x64, 0x20, 0x70, 0x65, 0x72, 0x66, 0x6f, + 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0xa, 0x3c, 0x6c, 0x69, + 0x3e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, + 0x42, 0x65, 0x72, 0x6b, 0x65, 0x6c, 0x65, 0x79, 0x20, 0x73, + 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x41, 0x50, 0x49, 0xa, + 0x3c, 0x2f, 0x75, 0x6c, 0x3e, 0xa, 0x3c, 0x2f, 0x70, 0x3e, + 0xa, 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, + 0x3d, 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, + 0x3e, 0xa, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x69, 0x73, 0x20, + 0x66, 0x72, 0x65, 0x65, 0x6c, 0x79, 0x20, 0x61, 0x76, 0x61, + 0x6c, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x28, 0x75, 0x6e, + 0x64, 0x65, 0x72, 0x20, 0x61, 0x20, 0x42, 0x53, 0x44, 0x2d, + 0x73, 0x74, 0x79, 0x6c, 0x65, 0x20, 0x6c, 0x69, 0x63, 0x65, + 0x6e, 0x73, 0x65, 0x29, 0x20, 0x69, 0x6e, 0x20, 0x43, 0x20, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x63, 0x6f, 0x64, + 0x65, 0xa, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, + 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, + 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, + 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x22, 0x3e, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, + 0x61, 0x64, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x70, 0x61, 0x67, + 0x65, 0x2e, 0x20, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, + 0x3c, 0x68, 0x32, 0x3e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, + 0x20, 0x6e, 0x65, 0x77, 0x73, 0x3c, 0x2f, 0x68, 0x32, 0x3e, + 0xa, 0xa, 0x3c, 0x75, 0x6c, 0x3e, 0xa, 0x3c, 0x6c, 0x69, + 0x3e, 0x3c, 0x62, 0x3e, 0x32, 0x30, 0x30, 0x32, 0x2d, 0x30, + 0x33, 0x2d, 0x31, 0x39, 0x3c, 0x2f, 0x62, 0x3e, 0x20, 0x50, + 0x61, 0x75, 0x6c, 0x20, 0x53, 0x68, 0x65, 0x65, 0x72, 0x20, + 0x68, 0x61, 0x73, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, + 0x6e, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x6c, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x42, 0x53, 0x44, + 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0xa, 0x6c, 0x61, + 0x79, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x68, 0x69, + 0x73, 0x20, 0x50, 0x61, 0x75, 0x6c, 0x4f, 0x53, 0x20, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x20, 0x48, 0x69, 0x73, + 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x63, 0x6f, + 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, + 0x61, 0x76, 0x61, 0x6c, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, + 0x64, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x64, 0x6f, + 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x3c, 0x2f, 0x61, 0x3e, + 0x2e, 0x3c, 0x62, 0x72, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0x20, + 0xa, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x3c, 0x62, 0x3e, 0x32, + 0x30, 0x30, 0x32, 0x2d, 0x30, 0x33, 0x2d, 0x31, 0x38, 0x3c, + 0x2f, 0x62, 0x3e, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x20, 0x30, 0x2e, 0x35, 0x2e, 0x33, 0x20, 0x72, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x2e, 0x20, 0x43, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x61, 0x20, 0x62, + 0x75, 0x67, 0x66, 0x69, 0x78, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x61, 0xa, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x20, + 0x70, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x71, + 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x41, 0x50, + 0x49, 0x20, 0x28, 0x61, 0x70, 0x69, 0x5f, 0x6c, 0x69, 0x62, + 0x2e, 0x63, 0x29, 0x2e, 0x3c, 0x62, 0x72, 0x3e, 0x3c, 0x62, + 0x72, 0x3e, 0xa, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x3c, 0x62, + 0x3e, 0x32, 0x30, 0x30, 0x32, 0x2d, 0x30, 0x33, 0x2d, 0x31, + 0x38, 0x3c, 0x2f, 0x62, 0x3e, 0x20, 0x53, 0x74, 0x65, 0x76, + 0x65, 0x20, 0x52, 0x65, 0x79, 0x6f, 0x6e, 0x6f, 0x6c, 0x64, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x43, 0x69, 0x74, 0x65, 0x6c, + 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, + 0x69, 0x65, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x20, 0x68, + 0x61, 0x73, 0xa, 0x64, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x64, + 0x20, 0x68, 0x69, 0x73, 0x20, 0x49, 0x47, 0x4d, 0x50, 0x76, + 0x32, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x63, + 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x2e, 0x20, + 0x49, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0xa, + 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, + 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, + 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x22, 0x3e, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, + 0x61, 0x64, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x70, 0x61, 0x67, + 0x65, 0x2e, 0x3c, 0x62, 0x72, 0x3e, 0x3c, 0x62, 0x72, 0x3e, + 0xa, 0x3c, 0x2f, 0x75, 0x6c, 0x3e, 0xa, 0xa, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6e, 0x65, 0x77, + 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, + 0x77, 0x73, 0x20, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, + 0x3c, 0x2f, 0x61, 0x3e, 0x2e, 0xa, 0xa, 0x3c, 0x70, 0x20, + 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x22, 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0xa, 0x3c, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x73, + 0x69, 0x7a, 0x65, 0x3d, 0x22, 0x2d, 0x31, 0x22, 0x3e, 0x3c, + 0x69, 0x3e, 0xa, 0x24, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, + 0x32, 0x30, 0x30, 0x32, 0x2f, 0x30, 0x34, 0x2f, 0x30, 0x32, + 0x20, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x3a, 0x31, 0x32, 0x20, + 0x24, 0xa, 0x3c, 0x2f, 0x69, 0x3e, 0x3c, 0x2f, 0x66, 0x6f, + 0x6e, 0x74, 0x3e, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x20, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x30, 0x22, + 0x3e, 0xa, 0x26, 0x6e, 0x62, 0x73, 0x70, 0x3b, 0xa, 0x3c, + 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x72, 0x3e, + 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, + 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, + 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, + 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, + 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, + 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, + 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x22, 0x3e, 0xa, 0xa, 0x3c, 0x68, + 0x72, 0x3e, 0xa, 0xa, 0xa, 0xa, 0xa, 0x5b, 0x49, 0x6e, + 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x5d, 0xa, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6e, 0x65, 0x77, 0x73, + 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x77, + 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, + 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, + 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x44, + 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, + 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x6d, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x6c, 0x69, 0x73, + 0x74, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4d, 0x61, + 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x69, 0x73, 0x74, + 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x22, 0x3e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x6c, 0x6f, 0x67, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, + 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2e, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x44, 0x6f, 0x77, 0x6e, + 0x6c, 0x6f, 0x61, 0x64, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, + 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x22, 0x3e, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x3c, + 0x2f, 0x61, 0x3e, 0xa, 0xa, 0xa, 0xa, 0x3c, 0x68, 0x72, + 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, + 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, + 0x64, 0x3e, 0xa, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x61, 0x6c, + 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x22, 0x3e, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, + 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x22, 0x3e, 0x41, + 0x64, 0x61, 0x6d, 0x20, 0x44, 0x75, 0x6e, 0x6b, 0x65, 0x6c, + 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, + 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x2f, + 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, + 0x3e, 0xa, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, +}; + +static const char data_download_html[] = { + /* /download.html */ + 0x2f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, 0xa, + 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, + 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x3c, 0x68, + 0x65, 0x61, 0x64, 0x3e, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, + 0x3e, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x2d, 0x20, 0x41, 0x20, + 0x4c, 0x69, 0x67, 0x68, 0x74, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, 0x53, + 0x74, 0x61, 0x63, 0x6b, 0x20, 0x2d, 0x20, 0x44, 0x6f, 0x77, + 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x3c, 0x2f, 0x74, 0x69, 0x74, + 0x6c, 0x65, 0x3e, 0x3c, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x3e, + 0xa, 0xa, 0xa, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x62, + 0x67, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x77, 0x68, + 0x69, 0x74, 0x65, 0x22, 0x3e, 0xa, 0xa, 0x3c, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, 0x6c, + 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, + 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x70, 0x61, + 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0x3e, 0xa, + 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0xa, 0x3c, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0x3c, 0x68, 0x31, + 0x3e, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x2d, 0x20, 0x41, 0x20, + 0x4c, 0x69, 0x67, 0x68, 0x74, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, 0x53, + 0x74, 0x61, 0x63, 0x6b, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, + 0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0xa, 0x3c, + 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x3c, + 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, 0xa, + 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, + 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, + 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, + 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, + 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, + 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x22, 0x3e, 0xa, 0x3c, 0x68, 0x72, + 0x3e, 0xa, 0xa, 0xa, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x49, 0x6e, 0x74, + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3c, + 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6e, 0x65, 0x77, + 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, + 0x77, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, + 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, + 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x6d, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x6c, 0x69, + 0x73, 0x74, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4d, + 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x69, 0x73, + 0x74, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, + 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x2e, 0x68, + 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x6c, 0x6f, 0x67, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, + 0x7c, 0xa, 0xa, 0x5b, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, + 0x61, 0x64, 0x5d, 0xa, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6c, 0x69, + 0x6e, 0x6b, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0xa, + 0xa, 0xa, 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, + 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x63, + 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0x3c, 0x68, 0x32, 0x3e, + 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x3c, 0x2f, + 0x68, 0x32, 0x3e, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, + 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, + 0x74, 0x72, 0x3e, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x3e, 0xa, 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, 0x30, + 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, + 0x30, 0x22, 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, + 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, 0x63, + 0x65, 0x6c, 0x6c, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, + 0x3d, 0x22, 0x30, 0x22, 0x3e, 0x3c, 0x74, 0x72, 0x3e, 0xa, + 0x3c, 0x74, 0x64, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x22, 0x35, 0x30, 0x22, 0x3e, 0xa, 0x26, 0x6e, 0x62, 0x73, + 0x70, 0x3b, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, + 0x74, 0x64, 0x20, 0x62, 0x67, 0x63, 0x6f, 0x6c, 0x6f, 0x72, + 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, 0x65, 0x22, 0x20, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x34, 0x30, 0x22, + 0x3e, 0xa, 0xa, 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, + 0x67, 0x6e, 0x3d, 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, + 0x79, 0x22, 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0xa, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x76, 0x61, 0x6c, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, + 0x61, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75, + 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x20, 0x3c, 0x61, 0xa, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6c, 0x69, 0x63, 0x65, + 0x6e, 0x63, 0x65, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x74, 0x68, 0x69, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x42, + 0x53, 0x44, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x20, 0x6c, + 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2e, 0xa, 0x3c, 0x2f, + 0x70, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x33, 0x3e, 0x52, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x3c, 0x2f, 0x68, 0x33, 0x3e, 0xa, + 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, + 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, + 0x54, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, + 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, + 0x73, 0x20, 0x30, 0x2e, 0x35, 0x2e, 0x33, 0x2e, 0x20, 0x28, + 0x4f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, + 0x6c, 0x73, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6e, 0xa, + 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x72, 0x65, + 0x61, 0x73, 0x6f, 0x6e, 0x2e, 0x29, 0xa, 0x3c, 0x2f, 0x70, + 0x3e, 0xa, 0x3c, 0x75, 0x6c, 0x3e, 0xa, 0x3c, 0x6c, 0x69, + 0x3e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x30, + 0x2e, 0x35, 0x2e, 0x33, 0x20, 0x28, 0x6c, 0x61, 0x74, 0x65, + 0x73, 0x74, 0x29, 0x3a, 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, + 0x61, 0x64, 0x2f, 0x3f, 0x66, 0x3d, 0x6c, 0x77, 0x69, 0x70, + 0x2d, 0x30, 0x2e, 0x35, 0x2e, 0x33, 0x2e, 0x74, 0x61, 0x72, + 0x2e, 0x67, 0x7a, 0x22, 0x3e, 0x6c, 0x77, 0x69, 0x70, 0x2d, + 0x30, 0x2e, 0x35, 0x2e, 0x33, 0x2e, 0x74, 0x61, 0x72, 0x2e, + 0x67, 0x7a, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0xa, 0x3c, 0x62, + 0x72, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0xa, 0x3c, 0x6c, + 0x69, 0x3e, 0xa, 0x3c, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x73, + 0x69, 0x7a, 0x65, 0x3d, 0x22, 0x2d, 0x32, 0x22, 0x3e, 0xa, + 0x4f, 0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x20, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x3c, + 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, + 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2f, 0x3f, 0x66, 0x3d, + 0x6c, 0x77, 0x69, 0x70, 0x2d, 0x30, 0x2e, 0x35, 0x2e, 0x32, + 0x2e, 0x74, 0x61, 0x72, 0x2e, 0x67, 0x7a, 0x22, 0x3e, 0x6c, + 0x77, 0x69, 0x70, 0x2d, 0x30, 0x2e, 0x35, 0x2e, 0x32, 0x2e, + 0x74, 0x61, 0x72, 0x2e, 0x67, 0x7a, 0x3c, 0x2f, 0x61, 0x3e, + 0xa, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2f, 0x3f, + 0x66, 0x3d, 0x6c, 0x77, 0x69, 0x70, 0x2d, 0x30, 0x2e, 0x35, + 0x2e, 0x31, 0x2e, 0x74, 0x61, 0x72, 0x2e, 0x67, 0x7a, 0x22, + 0x3e, 0x6c, 0x77, 0x69, 0x70, 0x2d, 0x30, 0x2e, 0x35, 0x2e, + 0x31, 0x2e, 0x74, 0x61, 0x72, 0x2e, 0x67, 0x7a, 0x3c, 0x2f, + 0x61, 0x3e, 0xa, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, + 0x2f, 0x3f, 0x66, 0x3d, 0x6c, 0x77, 0x69, 0x70, 0x2d, 0x30, + 0x2e, 0x35, 0x2e, 0x30, 0x2e, 0x74, 0x61, 0x72, 0x2e, 0x67, + 0x7a, 0x22, 0x3e, 0x6c, 0x77, 0x69, 0x70, 0x2d, 0x30, 0x2e, + 0x35, 0x2e, 0x30, 0x2e, 0x74, 0x61, 0x72, 0x2e, 0x67, 0x7a, + 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0x3c, 0x61, 0xa, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, + 0x61, 0x64, 0x2f, 0x3f, 0x66, 0x3d, 0x6c, 0x77, 0x69, 0x70, + 0x2d, 0x30, 0x2e, 0x34, 0x2e, 0x32, 0x2e, 0x74, 0x61, 0x72, + 0x2e, 0x67, 0x7a, 0x22, 0x3e, 0x6c, 0x77, 0x69, 0x70, 0x2d, + 0x30, 0x2e, 0x34, 0x2e, 0x32, 0x2e, 0x74, 0x61, 0x72, 0x2e, + 0x67, 0x7a, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0x3c, 0x61, 0xa, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x77, 0x6e, + 0x6c, 0x6f, 0x61, 0x64, 0x2f, 0x3f, 0x66, 0x3d, 0x6c, 0x77, + 0x69, 0x70, 0x2d, 0x30, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x74, + 0x61, 0x72, 0x2e, 0x67, 0x7a, 0x22, 0x3e, 0x6c, 0x77, 0x69, + 0x70, 0x2d, 0x30, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x74, 0x61, + 0x72, 0x2e, 0x67, 0x7a, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0xa, + 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, + 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2f, 0x3f, 0x66, + 0x3d, 0x6c, 0x77, 0x69, 0x70, 0x2d, 0x30, 0x2e, 0x34, 0x2e, + 0x74, 0x61, 0x72, 0x2e, 0x67, 0x7a, 0x22, 0x3e, 0x6c, 0x77, + 0x69, 0x70, 0x2d, 0x30, 0x2e, 0x34, 0x2e, 0x74, 0x61, 0x72, + 0x2e, 0x67, 0x7a, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0xa, 0x3c, + 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, + 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2f, 0x3f, 0x66, 0x3d, + 0x6c, 0x77, 0x69, 0x70, 0x2d, 0x30, 0x2e, 0x33, 0x2e, 0x31, + 0x2e, 0x74, 0x61, 0x72, 0x2e, 0x67, 0x7a, 0x22, 0x3e, 0x6c, + 0x77, 0x69, 0x70, 0x2d, 0x30, 0x2e, 0x33, 0x2e, 0x31, 0x2e, + 0x74, 0x61, 0x72, 0x2e, 0x67, 0x7a, 0x3c, 0x2f, 0x61, 0x3e, + 0x20, 0xa, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2f, + 0x3f, 0x66, 0x3d, 0x6c, 0x77, 0x69, 0x70, 0x2d, 0x30, 0x2e, + 0x33, 0x2e, 0x74, 0x61, 0x72, 0x2e, 0x67, 0x7a, 0x22, 0x3e, + 0x6c, 0x77, 0x69, 0x70, 0x2d, 0x30, 0x2e, 0x33, 0x2e, 0x74, + 0x61, 0x72, 0x2e, 0x67, 0x7a, 0x3c, 0x2f, 0x61, 0x3e, 0x20, + 0xa, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2f, 0x3f, + 0x66, 0x3d, 0x6c, 0x77, 0x69, 0x70, 0x2d, 0x30, 0x2e, 0x32, + 0x2e, 0x74, 0x61, 0x72, 0x2e, 0x67, 0x7a, 0x22, 0x3e, 0x6c, + 0x77, 0x69, 0x70, 0x2d, 0x30, 0x2e, 0x32, 0x2e, 0x74, 0x61, + 0x72, 0x2e, 0x67, 0x7a, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0x3c, + 0x2f, 0x66, 0x6f, 0x6e, 0x74, 0x3e, 0xa, 0x3c, 0x62, 0x72, + 0x3e, 0xa, 0x3c, 0x2f, 0x75, 0x6c, 0x3e, 0xa, 0xa, 0x3c, + 0x68, 0x33, 0x3e, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x3c, 0x2f, 0x68, 0x33, 0x3e, 0xa, 0x3c, 0x70, + 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x6a, 0x75, + 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, 0x54, 0x68, + 0x65, 0x20, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x20, 0x64, + 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74, + 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x56, 0x53, 0x20, 0x69, + 0x73, 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x61, 0x76, 0x61, + 0x6c, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x3c, 0x61, 0xa, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x77, 0x6e, + 0x6c, 0x6f, 0x61, 0x64, 0x2f, 0x3f, 0x66, 0x3d, 0x6c, 0x77, + 0x69, 0x70, 0x2d, 0x63, 0x76, 0x73, 0x2e, 0x74, 0x61, 0x72, + 0x2e, 0x67, 0x7a, 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, 0x3c, + 0x2f, 0x61, 0x3e, 0x2e, 0x20, 0x4e, 0x6f, 0x74, 0x65, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x63, 0x6f, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x79, 0xa, 0x76, + 0x65, 0x72, 0x79, 0x20, 0x77, 0x65, 0x6c, 0x6c, 0x20, 0x62, + 0x65, 0x20, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x69, 0x67, 0x68, 0x74, + 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x20, + 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x2e, 0xa, 0x3c, + 0x2f, 0x70, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x33, 0x3e, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x63, 0x6f, 0x64, 0x65, + 0x20, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x3c, 0x2f, 0x68, + 0x33, 0x3e, 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, + 0x6e, 0x3d, 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, + 0x22, 0x3e, 0xa, 0x4a, 0x6f, 0x65, 0x20, 0x4d, 0x61, 0x63, + 0x44, 0x6f, 0x6e, 0x61, 0x6c, 0x64, 0x20, 0x68, 0x61, 0x73, + 0x20, 0x70, 0x75, 0x74, 0x20, 0x61, 0x6e, 0x20, 0x48, 0x54, + 0x4d, 0x4c, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, + 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x63, 0x6f, 0x64, + 0x65, 0xa, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x61, + 0x74, 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x64, 0x65, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, + 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x22, 0x3e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x64, 0x65, 0x73, 0x65, 0x72, 0x74, 0x65, + 0x64, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x6c, 0x77, 0x49, 0x50, + 0x2f, 0x3c, 0x2f, 0x61, 0x3e, 0x2e, 0x20, 0xa, 0x3c, 0x2f, + 0x70, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x33, 0x3e, 0x50, 0x6f, + 0x72, 0x74, 0x73, 0x3c, 0x2f, 0x68, 0x33, 0x3e, 0xa, 0x3c, + 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x6a, + 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, 0x46, + 0x6c, 0x6f, 0x72, 0x69, 0x61, 0x6e, 0x20, 0x53, 0x68, 0x75, + 0x6c, 0x7a, 0x65, 0x20, 0x68, 0x61, 0x73, 0x20, 0x70, 0x6f, + 0x72, 0x74, 0x65, 0x64, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, + 0x74, 0x6f, 0x20, 0x44, 0x4a, 0x47, 0x50, 0x50, 0x2f, 0x4d, + 0x53, 0x2d, 0x44, 0x4f, 0x53, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x74, 0x6f, 0x20, 0x56, 0x69, 0x73, 0x75, 0x61, 0x6c, 0x20, + 0x43, 0x2b, 0x2b, 0xa, 0x36, 0x2e, 0x30, 0x2f, 0x57, 0x69, + 0x6e, 0x33, 0x32, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x79, 0x20, + 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x64, 0x6f, 0x77, + 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x20, 0x3c, 0x61, + 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x70, 0x61, + 0x67, 0x65, 0x73, 0x2e, 0x66, 0x68, 0x2d, 0x67, 0x69, 0x65, + 0x73, 0x73, 0x65, 0x6e, 0x2e, 0x64, 0x65, 0x2f, 0x7e, 0x68, + 0x67, 0x31, 0x30, 0x38, 0x33, 0x36, 0x2f, 0x64, 0x65, 0x76, + 0x2f, 0x64, 0x6a, 0x67, 0x70, 0x70, 0x2f, 0x6c, 0x77, 0x69, + 0x70, 0x64, 0x6a, 0x67, 0x70, 0x70, 0x74, 0x65, 0x73, 0x74, + 0x2d, 0x30, 0x2e, 0x31, 0x2e, 0x7a, 0x69, 0x70, 0x22, 0x3e, + 0x68, 0x65, 0x72, 0x65, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0x28, + 0x44, 0x4a, 0x47, 0x50, 0x50, 0x2f, 0x4d, 0x53, 0x2d, 0x44, + 0x4f, 0x53, 0x29, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x3c, 0x61, + 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x70, 0x61, + 0x67, 0x65, 0x73, 0x2e, 0x66, 0x68, 0x2d, 0x67, 0x69, 0x65, + 0x73, 0x73, 0x65, 0x6e, 0x2e, 0x64, 0x65, 0x2f, 0x7e, 0x68, + 0x67, 0x31, 0x30, 0x38, 0x33, 0x36, 0x2f, 0x63, 0x72, 0x6f, + 0x77, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x6c, 0x77, 0x69, + 0x70, 0x2d, 0x77, 0x69, 0x6e, 0x33, 0x32, 0x2d, 0x6d, 0x73, + 0x76, 0x63, 0x2d, 0x30, 0x2e, 0x31, 0x2e, 0x7a, 0x69, 0x70, + 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, 0x3c, 0x2f, 0x61, 0x3e, + 0xa, 0x28, 0x56, 0x69, 0x73, 0x75, 0x61, 0x6c, 0x20, 0x43, + 0x2b, 0x2b, 0x20, 0x36, 0x2e, 0x30, 0x2f, 0x57, 0x69, 0x6e, + 0x33, 0x32, 0x29, 0x2e, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, + 0xa, 0x3c, 0x68, 0x33, 0x3e, 0x41, 0x64, 0x64, 0x2d, 0x6f, + 0x6e, 0x73, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x73, + 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x3c, 0x2f, 0x68, 0x33, 0x3e, 0xa, 0xa, + 0x3c, 0x68, 0x34, 0x3e, 0x44, 0x48, 0x43, 0x50, 0x20, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x68, 0x34, 0x3e, + 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, + 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, + 0xa, 0x4c, 0x65, 0x6f, 0x6e, 0x20, 0x57, 0x6f, 0x65, 0x73, + 0x74, 0x65, 0x6e, 0x62, 0x65, 0x72, 0x67, 0x20, 0x66, 0x72, + 0x6f, 0x6d, 0x20, 0x41, 0x78, 0x6f, 0x6e, 0x20, 0x44, 0x69, + 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x44, 0x65, 0x73, 0x69, + 0x67, 0x6e, 0x20, 0x42, 0x2e, 0x56, 0x2e, 0x20, 0x68, 0x61, + 0x73, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, + 0x61, 0x20, 0x43, 0x53, 0x38, 0x39, 0x30, 0x30, 0x61, 0xa, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x20, 0x64, 0x72, + 0x69, 0x76, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, + 0x73, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x6c, + 0x79, 0x20, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x69, + 0x6e, 0x67, 0x20, 0x61, 0x20, 0x44, 0x48, 0x43, 0x50, 0x20, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, + 0xa, 0x6c, 0x77, 0x49, 0x50, 0x2e, 0x20, 0x54, 0x68, 0x65, + 0x79, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x6f, 0x74, 0x68, + 0x20, 0x62, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, + 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x65, 0x73, 0x72, 0x61, 0x63, 0x2e, 0x65, 0x6c, 0x65, 0x2e, + 0x74, 0x75, 0x65, 0x2e, 0x6e, 0x6c, 0x2f, 0x7e, 0x6c, 0x65, + 0x6f, 0x6e, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x22, 0x3e, + 0x68, 0x65, 0x72, 0x65, 0x3c, 0x2f, 0x61, 0x3e, 0x2e, 0x20, + 0x54, 0x68, 0x65, 0x20, 0x70, 0x6c, 0x61, 0x6e, 0x20, 0x69, + 0x73, 0xa, 0x74, 0x6f, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x69, 0x6e, 0x74, 0x65, + 0x67, 0x72, 0x61, 0x74, 0x65, 0x20, 0x4c, 0x65, 0x6f, 0x6e, + 0x27, 0x73, 0x20, 0x44, 0x48, 0x43, 0x50, 0x20, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x6c, 0x77, 0x49, + 0x50, 0x20, 0xa, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0xa, 0x3c, 0x2f, 0x70, + 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x34, 0x3e, 0x49, 0x47, 0x4d, + 0x50, 0x76, 0x32, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, + 0x68, 0x34, 0x3e, 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, + 0x67, 0x6e, 0x3d, 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, + 0x79, 0x22, 0x3e, 0xa, 0x53, 0x74, 0x65, 0x76, 0x65, 0x20, + 0x52, 0x65, 0x79, 0x6e, 0x6f, 0x6c, 0x64, 0x73, 0x20, 0x6f, + 0x66, 0x20, 0x43, 0x69, 0x74, 0x65, 0x6c, 0x20, 0x54, 0x65, + 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, + 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x20, 0x68, 0x61, 0x73, 0x20, + 0x64, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x20, 0x68, 0x69, + 0x73, 0x20, 0x49, 0x47, 0x4d, 0x50, 0x76, 0x32, 0xa, 0x69, + 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6c, 0x77, + 0x49, 0x50, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x2e, + 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x76, 0x61, + 0x6c, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0xa, + 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, + 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2f, 0x69, 0x67, + 0x6d, 0x70, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x7a, 0x69, + 0x70, 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, 0x3c, 0x2f, 0x61, + 0x3e, 0x20, 0x28, 0x6e, 0x6f, 0x74, 0x65, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x70, + 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x61, 0x6e, 0x64, + 0xa, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x64, + 0x69, 0x66, 0x66, 0x65, 0x72, 0x73, 0x20, 0x73, 0x6c, 0x69, + 0x67, 0x68, 0x74, 0x6c, 0x79, 0x20, 0x66, 0x72, 0x6f, 0x6d, + 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x2d, 0x20, 0x72, 0x65, + 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x69, 0x63, + 0x65, 0x6e, 0x73, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x69, 0x67, 0x6d, 0x70, 0x2e, 0x63, 0xa, 0x66, + 0x69, 0x6c, 0x65, 0x29, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, + 0x70, 0x6c, 0x61, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x74, 0x6f, + 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x65, + 0x20, 0x68, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, + 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, + 0x61, 0x69, 0x6e, 0x20, 0x6c, 0x77, 0x49, 0x50, 0xa, 0x64, + 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, 0x3c, + 0x68, 0x34, 0x3e, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x74, 0x69, 0x76, 0x65, 0x20, 0x42, 0x53, 0x44, 0x20, 0x73, + 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x6c, 0x61, 0x79, 0x65, + 0x72, 0x3c, 0x2f, 0x68, 0x34, 0x3e, 0xa, 0x3c, 0x70, 0x20, + 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x6a, 0x75, 0x73, + 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, 0x50, 0x61, 0x75, + 0x6c, 0x20, 0x53, 0x68, 0x65, 0x65, 0x72, 0x20, 0x68, 0x61, + 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, + 0x61, 0x74, 0x65, 0x64, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, + 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x68, 0x69, 0x73, 0x20, 0x50, + 0x61, 0x75, 0x6c, 0x4f, 0x53, 0x20, 0x73, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, 0x61, 0x73, + 0xa, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, 0x61, + 0x6e, 0x20, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, + 0x69, 0x76, 0x65, 0x20, 0x42, 0x53, 0x44, 0x20, 0x73, 0x6f, + 0x63, 0x6b, 0x65, 0x74, 0x20, 0x6c, 0x61, 0x79, 0x65, 0x72, + 0x2e, 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x76, + 0x61, 0x6c, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, + 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2f, 0x62, + 0x73, 0x64, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, + 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, 0x3c, 0x2f, 0x61, 0x3e, + 0x2e, 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6f, + 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x50, 0x61, + 0x75, 0x6c, 0x20, 0x53, 0x68, 0x65, 0x65, 0x72, 0xa, 0x61, + 0x6e, 0x64, 0x20, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, + 0x64, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x67, 0x6e, 0x75, 0x2e, 0x6f, 0x72, 0x67, 0x2f, + 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x2f, 0x67, + 0x70, 0x6c, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x47, + 0x4e, 0x55, 0x20, 0x47, 0x50, 0x4c, 0x3c, 0x2f, 0x61, 0x3e, + 0x2e, 0x20, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, 0x3c, + 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x22, 0x3e, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0xa, 0x3c, 0x66, 0x6f, 0x6e, 0x74, + 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x22, 0x2d, 0x31, 0x22, + 0x3e, 0x3c, 0x69, 0x3e, 0xa, 0x24, 0x44, 0x61, 0x74, 0x65, + 0x3a, 0x20, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x30, 0x33, 0x2f, + 0x31, 0x39, 0x20, 0x30, 0x39, 0x3a, 0x30, 0x32, 0x3a, 0x34, + 0x32, 0x20, 0x24, 0xa, 0x3c, 0x2f, 0x69, 0x3e, 0x3c, 0x2f, + 0x66, 0x6f, 0x6e, 0x74, 0x3e, 0xa, 0x3c, 0x2f, 0x70, 0x3e, + 0xa, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, + 0x64, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, + 0x30, 0x22, 0x3e, 0xa, 0x26, 0x6e, 0x62, 0x73, 0x70, 0x3b, + 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x2f, 0x74, + 0x72, 0x3e, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, + 0xa, 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, 0x30, 0x22, + 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, + 0x22, 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, + 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, 0x63, 0x65, + 0x6c, 0x6c, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3d, + 0x22, 0x30, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, + 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x3e, 0xa, 0xa, + 0x3c, 0x68, 0x72, 0x3e, 0xa, 0xa, 0xa, 0xa, 0xa, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, + 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x6e, 0x65, 0x77, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x4e, 0x65, 0x77, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0xa, + 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0x22, 0x3e, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, 0x3e, + 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x6d, 0x61, 0x69, 0x6c, 0x69, 0x6e, + 0x67, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x68, 0x74, 0x6d, 0x6c, + 0x22, 0x3e, 0x4d, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, + 0x6c, 0x69, 0x73, 0x74, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, + 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, + 0x67, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x3c, 0x2f, 0x61, + 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x5b, 0x44, 0x6f, 0x77, + 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x5d, 0xa, 0xa, 0xa, 0x7c, + 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0x22, 0x3e, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x3c, 0x2f, + 0x61, 0x3e, 0xa, 0xa, 0xa, 0xa, 0x3c, 0x68, 0x72, 0x3e, + 0xa, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, + 0x72, 0x3e, 0x3c, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, + 0x3e, 0xa, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x61, 0x6c, 0x69, + 0x67, 0x6e, 0x3d, 0x22, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, + 0x3e, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, + 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x22, 0x3e, 0x41, 0x64, + 0x61, 0x6d, 0x20, 0x44, 0x75, 0x6e, 0x6b, 0x65, 0x6c, 0x73, + 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, + 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x2f, 0x74, + 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, + 0xa, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, }; + +static const char data_documentation_html[] = { + /* /documentation.html */ + 0x2f, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, 0xa, + 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, + 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x3c, 0x68, + 0x65, 0x61, 0x64, 0x3e, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, + 0x3e, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x2d, 0x20, 0x41, 0x20, + 0x4c, 0x69, 0x67, 0x68, 0x74, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, 0x53, + 0x74, 0x61, 0x63, 0x6b, 0x20, 0x2d, 0x20, 0x44, 0x6f, 0x63, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x3c, 0x2f, + 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0xa, 0xa, 0x3c, 0x62, + 0x6f, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6f, 0x6c, 0x6f, + 0x72, 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, 0x65, 0x22, 0x3e, + 0xa, 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, 0x30, 0x22, + 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, + 0x22, 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, + 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, 0x63, 0x65, + 0x6c, 0x6c, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3d, + 0x22, 0x30, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, + 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x63, 0x65, 0x6e, 0x74, 0x65, + 0x72, 0x3e, 0x3c, 0x68, 0x31, 0x3e, 0x6c, 0x77, 0x49, 0x50, + 0x20, 0x2d, 0x20, 0x41, 0x20, 0x4c, 0x69, 0x67, 0x68, 0x74, + 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x54, 0x43, 0x50, + 0x2f, 0x49, 0x50, 0x20, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x3c, + 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, + 0x65, 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, + 0x2f, 0x74, 0x72, 0x3e, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x3e, 0xa, 0xa, 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, + 0x34, 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x3d, 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, + 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, + 0xa, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x70, 0x61, 0x63, 0x69, + 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0x3e, 0xa, 0x3c, 0x74, + 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, + 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, + 0x3e, 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0xa, 0xa, 0xa, + 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, + 0x22, 0x3e, 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, + 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x6e, 0x65, 0x77, 0x73, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x77, 0x73, 0x3c, 0x2f, 0x61, + 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x5b, 0x44, 0x6f, 0x63, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5d, 0xa, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6d, 0x61, 0x69, 0x6c, + 0x69, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x22, 0x3e, 0x4d, 0x61, 0x69, 0x6c, 0x69, 0x6e, + 0x67, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x3c, 0x2f, 0x61, 0x3e, + 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x6c, 0x6f, 0x67, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x3c, + 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x77, + 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x68, 0x74, 0x6d, 0x6c, + 0x22, 0x3e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, + 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6c, 0x69, + 0x6e, 0x6b, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0xa, + 0xa, 0xa, 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, + 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x63, + 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0x3c, 0x68, 0x32, 0x3e, + 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x68, 0x32, 0x3e, 0x3c, 0x2f, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0xa, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x3c, 0x2f, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, 0x3c, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3d, 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, + 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, + 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, + 0x22, 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x70, + 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0x3e, + 0x3c, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x20, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x30, 0x22, 0x3e, + 0xa, 0x26, 0x6e, 0x62, 0x73, 0x70, 0x3b, 0xa, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x20, 0x62, 0x67, + 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x77, 0x68, 0x69, + 0x74, 0x65, 0x22, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x22, 0x35, 0x34, 0x30, 0x22, 0x3e, 0xa, 0xa, 0x3c, 0x75, + 0x6c, 0x3e, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6f, 0x73, 0x2e, 0x68, + 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x55, 0x73, 0x69, 0x6e, 0x67, + 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, + 0x75, 0x74, 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0xa, 0x73, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x3c, 0x2f, 0x61, 0x3e, 0x2e, 0xa, 0x3c, 0x62, + 0x72, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0xa, 0x3c, 0x6c, + 0x69, 0x3e, 0x54, 0x68, 0x65, 0x20, 0x6c, 0x77, 0x49, 0x50, + 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x61, 0x72, + 0x63, 0x68, 0x69, 0x76, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x73, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, + 0x6e, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x74, 0x6f, 0x20, 0x70, + 0x6f, 0x72, 0x74, 0x20, 0x6c, 0x77, 0x49, 0x50, 0xa, 0x61, + 0x6e, 0x64, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x74, 0x6f, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x61, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x75, + 0x73, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, + 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x41, 0x50, 0x49, 0x2e, + 0x20, 0x54, 0x68, 0x65, 0x79, 0x20, 0x63, 0x61, 0x6e, 0x20, + 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x62, 0x65, 0xa, 0x66, 0x6f, + 0x75, 0x6e, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x3a, 0x20, + 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, + 0x6f, 0x63, 0x2f, 0x73, 0x79, 0x73, 0x5f, 0x61, 0x72, 0x63, + 0x68, 0x2e, 0x74, 0x78, 0x74, 0x22, 0x3e, 0x73, 0x79, 0x73, + 0x5f, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x74, 0x78, 0x74, 0x3c, + 0x2f, 0x61, 0x3e, 0x2c, 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x63, 0x2f, 0x72, 0x61, + 0x77, 0x61, 0x70, 0x69, 0x2e, 0x74, 0x78, 0x74, 0x22, 0x3e, + 0x72, 0x61, 0x77, 0x61, 0x70, 0x69, 0x2e, 0x74, 0x78, 0x74, + 0x3c, 0x2f, 0x61, 0x3e, 0x2e, 0x20, 0xa, 0x3c, 0x62, 0x72, + 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0xa, 0x3c, 0x6c, 0x69, + 0x3e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x20, 0x66, + 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x61, + 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x74, 0x3a, + 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x6d, 0x61, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x6d, + 0x73, 0x67, 0x30, 0x30, 0x32, 0x33, 0x31, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x22, 0x3e, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x6d, + 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x62, 0x75, 0x66, 0x66, + 0x65, 0x72, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x6c, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x3c, 0x2f, + 0x61, 0x3e, 0x2c, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x6d, 0x61, 0x69, 0x6c, 0x6c, 0x69, 0x73, + 0x74, 0x2f, 0x6d, 0x73, 0x67, 0x30, 0x30, 0x32, 0x32, 0x37, + 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x54, 0x68, 0x72, + 0x65, 0x61, 0x64, 0x73, 0x2c, 0x20, 0x73, 0x65, 0x6d, 0x61, + 0x70, 0x68, 0x6f, 0x72, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x72, 0x61, 0x77, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x20, 0xa, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, 0x3e, 0x2c, 0x20, + 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6d, + 0x61, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x6d, 0x73, + 0x67, 0x30, 0x30, 0x32, 0x34, 0x32, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0x22, 0x3e, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, + 0x2c, 0x20, 0x73, 0x65, 0x6d, 0x61, 0x70, 0x68, 0x6f, 0x72, + 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0xa, 0x72, 0x61, 0x77, + 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, + 0x20, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x5b, 0x32, 0x5d, 0x3c, 0x2f, 0x61, 0x3e, 0x2e, 0x20, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6d, 0x61, + 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x6d, 0x73, 0x67, + 0x30, 0x30, 0x34, 0x36, 0x30, 0x2e, 0x68, 0x74, 0x6d, 0x6c, + 0x22, 0x3e, 0x53, 0x6f, 0x6d, 0x65, 0x20, 0x6e, 0x6f, 0x74, + 0x65, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x75, 0x73, 0x69, 0x6e, + 0x67, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x76, 0x65, + 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, + 0x76, 0x69, 0x72, 0x6f, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x41, + 0x44, 0x53, 0xa, 0x31, 0x2e, 0x31, 0x20, 0x66, 0x72, 0x6f, + 0x6d, 0x20, 0x41, 0x52, 0x4d, 0x2e, 0x3c, 0x2f, 0x61, 0x3e, + 0xa, 0x3c, 0x62, 0x72, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0xa, + 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x41, 0x20, 0x72, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, + 0x65, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, + 0x20, 0x6f, 0x6c, 0x64, 0xa, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x77, 0x49, 0x50, + 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x6c, 0x67, 0x6f, + 0x72, 0x69, 0x74, 0x68, 0x6d, 0x73, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x73, 0x74, 0x72, 0x75, + 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x75, 0x73, 0x65, + 0x64, 0x20, 0x62, 0x6f, 0x74, 0x68, 0x20, 0x69, 0x6e, 0x20, + 0x74, 0x68, 0x65, 0xa, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x73, 0x75, 0x62, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x73, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, + 0x20, 0x61, 0x6e, 0x64, 0xa, 0x62, 0x75, 0x66, 0x66, 0x65, + 0x72, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, + 0x20, 0x61, 0x72, 0x65, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x64, 0x2e, 0x20, 0x41, 0x6c, 0x73, 0x6f, + 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x20, + 0x69, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x72, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0xa, 0x69, 0x73, 0x20, 0x61, 0x20, + 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, + 0x6d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, + 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x20, 0x41, 0x50, 0x49, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, + 0x6f, 0x6d, 0x65, 0x20, 0x63, 0x6f, 0x64, 0x65, 0xa, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x20, 0x6f, 0x66, + 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x77, 0x49, + 0x50, 0x2e, 0x20, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x64, 0x6f, 0x63, 0x2f, 0x6c, 0x77, 0x69, 0x70, + 0x2e, 0x70, 0x64, 0x66, 0x22, 0x3e, 0x50, 0x44, 0x46, 0x3c, + 0x2f, 0x61, 0x3e, 0x2c, 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x63, 0x2f, 0x6c, 0x77, + 0x69, 0x70, 0x2e, 0x70, 0x73, 0x2e, 0x67, 0x7a, 0x22, 0x3e, + 0x2e, 0x70, 0x73, 0x2e, 0x67, 0x7a, 0x3c, 0x2f, 0x61, 0x3e, + 0x2e, 0xa, 0xa, 0x3c, 0x62, 0x72, 0x3e, 0x3c, 0x62, 0x72, + 0x3e, 0xa, 0xa, 0x3c, 0x6c, 0x69, 0x3e, 0x53, 0x6c, 0x69, + 0x64, 0x65, 0x73, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, + 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, + 0x61, 0x6c, 0x6b, 0x73, 0x20, 0x61, 0x20, 0x62, 0x69, 0x74, + 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x6c, 0x77, 0x49, + 0x50, 0x3a, 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x64, 0x6f, 0x63, 0x2f, 0x70, 0x72, 0x65, 0x73, + 0x2e, 0x70, 0x64, 0x66, 0x22, 0x3e, 0x50, 0x44, 0x46, 0x3c, + 0x2f, 0x61, 0x3e, 0x20, 0x28, 0x38, 0x36, 0x6b, 0x29, 0x2c, + 0x20, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x64, 0x6f, 0x63, 0x2f, 0x70, 0x72, 0x65, 0x73, 0x2e, 0x70, + 0x73, 0x2e, 0x67, 0x7a, 0x22, 0x3e, 0x2e, 0x70, 0x73, 0x2e, + 0x67, 0x7a, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0x28, 0x33, 0x36, + 0x6b, 0x29, 0x2e, 0x20, 0xa, 0x3c, 0x2f, 0x75, 0x6c, 0x3e, + 0xa, 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, + 0x3d, 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, + 0x3e, 0xa, 0x46, 0x6f, 0x72, 0x20, 0x6d, 0x6f, 0x72, 0x65, + 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x67, 0x61, 0x72, + 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x70, 0x72, 0x6f, 0x78, + 0x79, 0x20, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, + 0x74, 0x75, 0x72, 0x65, 0x20, 0x74, 0x6f, 0xa, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x54, 0x43, 0x50, 0x2f, + 0x49, 0x50, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x73, 0x6d, 0x61, 0x6c, 0x6c, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, + 0x20, 0x69, 0x6e, 0x20, 0x3c, 0x61, 0xa, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, + 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x41, + 0x64, 0x61, 0x6d, 0x20, 0x44, 0x75, 0x6e, 0x6b, 0x65, 0x6c, + 0x73, 0x27, 0x20, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x73, 0x69, 0x73, 0x3c, 0x2f, 0x61, + 0x3e, 0x2e, 0x20, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, + 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, + 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, + 0xa, 0x54, 0x68, 0x65, 0x20, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x6d, 0x61, 0x69, 0x6c, 0x69, 0x6e, + 0x67, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x68, 0x74, 0x6d, 0x6c, + 0x22, 0x3e, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x6d, 0x61, 0x69, + 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x3c, + 0x2f, 0x61, 0x3e, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, + 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0xa, 0x64, + 0x69, 0x73, 0x63, 0x75, 0x73, 0x73, 0x20, 0x6c, 0x77, 0x49, + 0x50, 0x2e, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, 0x3c, + 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x6a, + 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, 0x46, + 0x6f, 0x72, 0x20, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x73, 0x75, 0x67, 0x67, + 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x70, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x63, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x20, 0x61, 0x74, 0x20, 0x3c, 0x61, + 0xa, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6d, 0x61, 0x69, + 0x6c, 0x74, 0x6f, 0x3a, 0x41, 0x64, 0x61, 0x6d, 0x20, 0x44, + 0x75, 0x6e, 0x6b, 0x65, 0x6c, 0x73, 0x20, 0x3c, 0x61, 0x64, + 0x61, 0x6d, 0x40, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, + 0x3e, 0x22, 0x3e, 0x41, 0x64, 0x61, 0x6d, 0x20, 0x44, 0x75, + 0x6e, 0x6b, 0x65, 0x6c, 0x73, 0xa, 0x26, 0x6c, 0x74, 0x3b, + 0x61, 0x64, 0x61, 0x6d, 0x40, 0x73, 0x69, 0x63, 0x73, 0x2e, + 0x73, 0x65, 0x26, 0x67, 0x74, 0x3b, 0x3c, 0x2f, 0x61, 0x3e, + 0x2e, 0x20, 0x20, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, + 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, + 0x22, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, 0x3e, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa, 0x3c, 0x66, 0x6f, + 0x6e, 0x74, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x22, 0x2d, + 0x31, 0x22, 0x3e, 0x3c, 0x69, 0x3e, 0xa, 0x24, 0x44, 0x61, + 0x74, 0x65, 0x3a, 0x20, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x30, + 0x33, 0x2f, 0x31, 0x38, 0x20, 0x31, 0x33, 0x3a, 0x31, 0x31, + 0x3a, 0x35, 0x35, 0x20, 0x24, 0xa, 0x3c, 0x2f, 0x69, 0x3e, + 0x3c, 0x2f, 0x66, 0x6f, 0x6e, 0x74, 0x3e, 0xa, 0x3c, 0x2f, + 0x70, 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa, + 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x30, + 0x22, 0x3e, 0xa, 0x26, 0x6e, 0x62, 0x73, 0x70, 0x3b, 0xa, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x72, + 0x3e, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, + 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, + 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, + 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, + 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, + 0x6c, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, + 0x30, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, + 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, + 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x3e, 0xa, 0xa, 0x3c, + 0x68, 0x72, 0x3e, 0xa, 0xa, 0xa, 0xa, 0xa, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x49, + 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, + 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6e, + 0x65, 0x77, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x4e, 0x65, 0x77, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, + 0x7c, 0xa, 0xa, 0x5b, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5d, 0xa, 0xa, + 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x6d, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, + 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x4d, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x6c, + 0x69, 0x73, 0x74, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, + 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, + 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x3c, 0x2f, 0x61, 0x3e, + 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, + 0x61, 0x64, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x44, + 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x3c, 0x2f, 0x61, + 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6c, 0x69, 0x6e, 0x6b, 0x73, + 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4c, 0x69, 0x6e, + 0x6b, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0xa, 0xa, + 0x3c, 0x68, 0x72, 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x72, 0x3e, + 0xa, 0x3c, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x64, 0x69, 0x76, + 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x22, 0x3e, 0xa, 0x3c, 0x61, 0x20, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, + 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, + 0x22, 0x3e, 0x41, 0x64, 0x61, 0x6d, 0x20, 0x44, 0x75, 0x6e, + 0x6b, 0x65, 0x6c, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, + 0x64, 0x69, 0x76, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, + 0xa, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x62, + 0x6f, 0x64, 0x79, 0x3e, 0xa, 0x3c, 0x2f, 0x68, 0x74, 0x6d, + 0x6c, 0x3e, 0xa, }; + +static const char data_os_html[] = { + /* /os.html */ + 0x2f, 0x6f, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, 0xa, + 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, + 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x3c, 0x68, + 0x65, 0x61, 0x64, 0x3e, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, + 0x3e, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x2d, 0x20, 0x41, 0x20, + 0x4c, 0x69, 0x67, 0x68, 0x74, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, 0x53, + 0x74, 0x61, 0x63, 0x6b, 0x20, 0x2d, 0x20, 0x4f, 0x53, 0x20, + 0x76, 0x73, 0x20, 0x6e, 0x6f, 0x6e, 0x2d, 0x4f, 0x53, 0x3c, + 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x3c, 0x2f, 0x68, + 0x65, 0x61, 0x64, 0x3e, 0xa, 0xa, 0xa, 0x3c, 0x62, 0x6f, + 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6f, 0x6c, 0x6f, 0x72, + 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, 0x65, 0x22, 0x3e, 0xa, + 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, 0x30, 0x22, 0x20, + 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, 0x22, + 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, + 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, 0x63, 0x65, 0x6c, + 0x6c, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3d, 0x22, + 0x30, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, + 0x64, 0x3e, 0xa, 0x3c, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, + 0x3e, 0x3c, 0x68, 0x31, 0x3e, 0x6c, 0x77, 0x49, 0x50, 0x20, + 0x2d, 0x20, 0x41, 0x20, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x77, + 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x54, 0x43, 0x50, 0x2f, + 0x49, 0x50, 0x20, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x3c, 0x2f, + 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, + 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, + 0x74, 0x72, 0x3e, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x3e, 0xa, 0xa, 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, + 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, + 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, + 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, + 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, + 0x67, 0x3d, 0x22, 0x30, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, + 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, + 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x3e, + 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0xa, 0xa, 0xa, 0xa, + 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, + 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, + 0x22, 0x6e, 0x65, 0x77, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, + 0x22, 0x3e, 0x4e, 0x65, 0x77, 0x73, 0x3c, 0x2f, 0x61, 0x3e, + 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x22, 0x3e, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, + 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6d, 0x61, 0x69, 0x6c, 0x69, + 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0x22, 0x3e, 0x4d, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, + 0x20, 0x6c, 0x69, 0x73, 0x74, 0x3c, 0x2f, 0x61, 0x3e, 0xa, + 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, + 0x6f, 0x67, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x3c, 0x2f, + 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x77, 0x6e, + 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x3c, + 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6c, 0x69, 0x6e, + 0x6b, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4c, + 0x69, 0x6e, 0x6b, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, + 0xa, 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, + 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, + 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x3e, 0x3c, 0x68, 0x32, 0x3e, 0x4f, + 0x53, 0x20, 0x76, 0x73, 0x20, 0x6e, 0x6f, 0x6e, 0x2d, 0x4f, + 0x53, 0x3c, 0x2f, 0x68, 0x32, 0x3e, 0x3c, 0x2f, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x3c, 0x2f, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, 0x3c, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x36, 0x34, 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, + 0x72, 0x3d, 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, 0x6c, 0x6c, + 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, + 0x22, 0xa, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x70, 0x61, 0x63, + 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0x3e, 0x3c, 0x74, + 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x35, 0x30, 0x22, 0x3e, 0xa, 0x26, + 0x6e, 0x62, 0x73, 0x70, 0x3b, 0xa, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x20, 0x62, 0x67, 0x63, 0x6f, + 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, 0x65, + 0x22, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, + 0x34, 0x30, 0x22, 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x32, 0x3e, + 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x77, 0x49, 0x50, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x72, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x61, 0x6e, 0x20, + 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, + 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3c, 0x2f, 0x68, 0x32, + 0x3e, 0xa, 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, + 0x6e, 0x3d, 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, + 0x22, 0x3e, 0xa, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x68, + 0x61, 0x73, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, 0x61, 0x20, + 0x66, 0x65, 0x77, 0x20, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20, + 0x68, 0x6f, 0x77, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x63, + 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, + 0x20, 0x69, 0x6e, 0x20, 0x61, 0xa, 0x73, 0x74, 0x61, 0x6e, + 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, 0x20, 0x65, 0x6e, 0x76, + 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x28, + 0x69, 0x2e, 0x65, 0x2e, 0x2c, 0x20, 0x61, 0x6e, 0x20, 0x65, + 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x61, + 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x2d, 0x74, 0x68, 0x72, + 0x65, 0x61, 0x64, 0x65, 0x64, 0xa, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x29, 0x20, 0x6c, 0x61, 0x74, 0x65, 0x6c, 0x79, + 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, 0x75, 0x72, 0x70, + 0x6f, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x20, 0x69, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x62, 0x65, 0xa, 0x68, 0x6f, 0x77, 0x20, + 0x6c, 0x77, 0x49, 0x50, 0x20, 0x69, 0x73, 0x20, 0x64, 0x65, + 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, + 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x6f, 0x75, 0x74, 0x20, 0x61, 0x20, 0x6d, 0x75, 0x6c, + 0x74, 0x69, 0x2d, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x65, + 0x64, 0xa, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, + 0x67, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0xa, + 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, 0x3c, 0x63, 0x65, 0x6e, + 0x74, 0x65, 0x72, 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, + 0x72, 0x63, 0x3d, 0x22, 0x6f, 0x73, 0x2e, 0x70, 0x6e, 0x67, + 0x22, 0x3e, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, + 0x3e, 0xa, 0xa, 0x3c, 0x68, 0x33, 0x3e, 0x54, 0x68, 0x65, + 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x73, 0x69, 0x6e, 0x67, + 0x6c, 0x65, 0x2d, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x65, + 0x64, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x3c, 0x2f, 0x68, 0x33, + 0x3e, 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, + 0x3d, 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, + 0x3e, 0xa, 0x54, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x72, 0x65, + 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x63, + 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x73, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x63, 0x74, 0x75, 0x61, + 0x6c, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x50, 0x2c, 0xa, 0x49, + 0x43, 0x4d, 0x50, 0x2c, 0x20, 0x55, 0x44, 0x50, 0x2c, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x54, 0x43, 0x50, 0x20, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x2c, 0x20, 0x61, + 0x73, 0x20, 0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, 0x73, 0xa, + 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x20, + 0x54, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x63, + 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x20, + 0x61, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x6e, + 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x73, 0xa, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6e, 0x65, 0x65, + 0x64, 0x65, 0x64, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x6c, + 0x77, 0x49, 0x50, 0x20, 0x69, 0x73, 0x20, 0x74, 0x6f, 0x20, + 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, + 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x2d, 0x74, + 0x68, 0x72, 0x65, 0x61, 0x64, 0x65, 0x64, 0x20, 0x28, 0x6e, + 0x6f, 0x6e, 0x2d, 0x4f, 0x53, 0x29, 0xa, 0x65, 0x6e, 0x76, + 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x20, + 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0x3c, 0x70, 0x20, 0x61, + 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x6a, 0x75, 0x73, 0x74, + 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, 0x54, 0x68, 0x65, 0x20, + 0x63, 0x6f, 0x72, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x63, 0x61, 0x6e, 0x20, + 0x62, 0x65, 0x20, 0x76, 0x69, 0x65, 0x77, 0x65, 0x64, 0x20, + 0x61, 0x73, 0x20, 0x61, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, + 0x61, 0x72, 0x65, 0x20, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, + 0x79, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x68, 0x61, + 0x73, 0x20, 0x74, 0x68, 0x65, 0xa, 0x66, 0x6f, 0x6c, 0x6c, + 0x6f, 0x77, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x66, 0x61, 0x63, 0x65, 0x3a, 0xa, 0x3c, 0x2f, 0x70, + 0x3e, 0xa, 0x3c, 0x75, 0x6c, 0x3e, 0xa, 0x3c, 0x6c, 0x69, + 0x3e, 0x3c, 0x74, 0x74, 0x3e, 0x69, 0x70, 0x5f, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x28, 0x70, 0x62, 0x75, 0x66, 0x2c, 0x20, + 0x6e, 0x65, 0x74, 0x69, 0x66, 0x29, 0x3c, 0x2f, 0x74, 0x74, + 0x3e, 0x3a, 0x20, 0x54, 0x61, 0x6b, 0x65, 0x73, 0x20, 0x61, + 0x6e, 0x20, 0x49, 0x50, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0xa, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x20, 0x61, 0x73, 0x20, + 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, + 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, + 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, + 0x61, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0xa, 0x3c, 0x6c, 0x69, + 0x3e, 0x3c, 0x74, 0x74, 0x3e, 0x74, 0x63, 0x70, 0x5f, 0x74, + 0x6d, 0x72, 0x28, 0x29, 0x3c, 0x2f, 0x74, 0x74, 0x3e, 0x3a, + 0x20, 0x53, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, + 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x65, 0x76, + 0x65, 0x72, 0x79, 0x20, 0x31, 0x30, 0x30, 0x20, 0x6d, 0x73, + 0x2e, 0x20, 0x44, 0x6f, 0x65, 0x73, 0x20, 0x61, 0x6c, 0x6c, + 0x20, 0x54, 0x43, 0x50, 0xa, 0x74, 0x69, 0x6d, 0x65, 0x72, + 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, + 0x67, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, 0x73, 0x20, + 0x64, 0x6f, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0xa, 0x3c, 0x2f, 0x75, 0x6c, 0x3e, 0xa, 0x3c, + 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x6a, + 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, 0x42, + 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x6e, 0x6f, 0x6e, + 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x6f, 0x72, 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x65, 0x76, 0x65, 0x72, 0x20, 0x6e, + 0x65, 0x65, 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x72, + 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x61, 0xa, 0x73, 0x69, + 0x6e, 0x67, 0x6c, 0x65, 0x2d, 0x74, 0x68, 0x72, 0x65, 0x61, + 0x64, 0x65, 0x64, 0x20, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, + 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x3c, 0x74, 0x74, 0x3e, 0x73, 0x79, 0x73, 0x5f, 0x61, + 0x72, 0x63, 0x68, 0x3c, 0x2f, 0x74, 0x74, 0x3e, 0x20, 0x28, + 0x74, 0x68, 0x65, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6e, 0x67, 0xa, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x20, 0x61, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x29, 0x20, + 0x64, 0x6f, 0x65, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6e, + 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6d, 0x70, + 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63, + 0x6b, 0x69, 0x6e, 0x67, 0xa, 0x73, 0x65, 0x6d, 0x61, 0x70, + 0x68, 0x6f, 0x72, 0x65, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x6d, + 0x61, 0x69, 0x6c, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x2e, 0x20, + 0x49, 0x6e, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x20, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6f, + 0x66, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2c, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x6e, + 0x63, 0x79, 0x20, 0x6f, 0x66, 0xa, 0x74, 0x68, 0x65, 0x20, + 0x3c, 0x74, 0x74, 0x3e, 0x73, 0x79, 0x73, 0x5f, 0x61, 0x72, + 0x63, 0x68, 0x3c, 0x2f, 0x74, 0x74, 0x3e, 0x20, 0x77, 0x69, + 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x2d, 0x74, 0x68, + 0x72, 0x65, 0x61, 0x64, 0x65, 0x64, 0x20, 0x63, 0x61, 0x73, + 0x65, 0x2e, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0x3c, 0x70, + 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x6a, 0x75, + 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, 0x41, 0x20, + 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x6d, 0x61, 0x69, + 0x6e, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x2d, + 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x65, 0x64, 0x20, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x6d, 0x69, 0x67, 0x68, + 0x74, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0xa, 0x6c, 0x69, 0x6b, + 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x3a, 0xa, 0x3c, 0x2f, + 0x70, 0x3e, 0xa, 0x3c, 0x70, 0x72, 0x65, 0x3e, 0xa, 0x20, + 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x28, 0x31, 0x29, 0x20, + 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x28, 0x70, + 0x6f, 0x6c, 0x6c, 0x5f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, + 0x28, 0x6e, 0x65, 0x74, 0x69, 0x66, 0x29, 0x20, 0x3d, 0x3d, + 0x20, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x52, 0x45, + 0x41, 0x44, 0x59, 0x29, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x70, 0x62, 0x75, 0x66, 0x20, 0x3d, 0x20, + 0x67, 0x65, 0x74, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, + 0x28, 0x6e, 0x65, 0x74, 0x69, 0x66, 0x29, 0x3b, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x70, 0x5f, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x28, 0x70, 0x62, 0x75, 0x66, 0x2c, 0x20, + 0x6e, 0x65, 0x74, 0x69, 0x66, 0x29, 0x3b, 0xa, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0xa, 0xa, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x28, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x28, 0x29, 0x20, + 0x2d, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x20, 0x2a, + 0x20, 0x43, 0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x4d, 0x53, 0x29, + 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, + 0x63, 0x70, 0x5f, 0x74, 0x6d, 0x72, 0x28, 0x29, 0x3b, 0xa, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x61, 0x73, 0x74, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x6c, + 0x6f, 0x63, 0x6b, 0x28, 0x29, 0x3b, 0xa, 0x20, 0x20, 0x20, + 0x20, 0x7d, 0x20, 0x20, 0x20, 0x20, 0xa, 0x20, 0x20, 0x7d, + 0xa, 0x3c, 0x2f, 0x70, 0x72, 0x65, 0x3e, 0xa, 0xa, 0x3c, + 0x68, 0x33, 0x3e, 0x6c, 0x77, 0x49, 0x50, 0x20, 0x69, 0x6e, + 0x20, 0x61, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x2d, 0x74, + 0x68, 0x72, 0x65, 0x61, 0x64, 0x65, 0x64, 0x20, 0x73, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x3c, 0x2f, 0x68, 0x33, 0x3e, 0xa, + 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, + 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, + 0x6c, 0x77, 0x49, 0x50, 0x20, 0x69, 0x73, 0x20, 0x64, 0x65, + 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, + 0x62, 0x65, 0x20, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x6f, + 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, + 0x20, 0x61, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x2d, 0x74, + 0x68, 0x72, 0x65, 0x61, 0x64, 0x65, 0x64, 0x20, 0x73, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x20, 0x77, 0x69, 0x74, 0x68, 0xa, + 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, + 0x20, 0x69, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, + 0x64, 0x73, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, + 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0xa, 0x63, 0x61, 0x73, + 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x61, 0x6c, 0x6c, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, + 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, + 0x67, 0x20, 0x69, 0x73, 0x20, 0x64, 0x6f, 0x6e, 0x65, 0x20, + 0x69, 0x6e, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, + 0x65, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x2e, 0x20, + 0x54, 0x68, 0x65, 0xa, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x72, 0x65, + 0x61, 0x64, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, + 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x75, 0x73, + 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0xa, 0x73, 0x65, + 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x41, + 0x50, 0x49, 0x2e, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, + 0x3c, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0x3c, 0x69, + 0x6d, 0x67, 0x20, 0x73, 0x72, 0x63, 0x3d, 0x22, 0x74, 0x68, + 0x72, 0x65, 0x61, 0x64, 0x73, 0x2e, 0x70, 0x6e, 0x67, 0x22, + 0x3e, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, + 0xa, 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, + 0x3d, 0x22, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, + 0x3e, 0xa, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x2d, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x63, + 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6d, 0x70, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x77, 0x6f, 0x20, 0x66, + 0x69, 0x6c, 0x65, 0x73, 0xa, 0x3c, 0x74, 0x74, 0x3e, 0x61, + 0x70, 0x69, 0x5f, 0x6c, 0x69, 0x62, 0x2e, 0x63, 0x3c, 0x2f, + 0x74, 0x74, 0x3e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x3c, 0x74, + 0x74, 0x3e, 0x61, 0x70, 0x69, 0x5f, 0x6d, 0x73, 0x67, 0x2e, + 0x63, 0x3c, 0x2f, 0x74, 0x74, 0x3e, 0x2e, 0x20, 0x54, 0x68, + 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x20, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x74, 0x68, + 0x65, 0xa, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x67, + 0x72, 0x61, 0x6d, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6c, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0xa, 0x74, 0x68, 0x65, 0x20, 0x54, 0x43, 0x50, 0x2f, 0x49, + 0x50, 0x20, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x2e, 0x20, 0x41, + 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, 0x20, 0x66, 0x69, 0x6c, + 0x65, 0x2c, 0x20, 0x3c, 0x74, 0x74, 0x3e, 0x74, 0x63, 0x70, + 0x69, 0x70, 0x2e, 0x63, 0x3c, 0x2f, 0x74, 0x74, 0x3e, 0x2c, + 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0xa, 0x69, + 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x61, + 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x74, 0x69, 0x6d, 0x65, 0x72, 0x20, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, + 0x73, 0xa, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x20, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, 0x3c, 0x70, + 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x6a, 0x75, + 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, 0x57, 0x68, + 0x65, 0x6e, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, + 0x61, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x2d, 0x74, 0x68, + 0x72, 0x65, 0x61, 0x64, 0x65, 0x64, 0x20, 0x65, 0x6e, 0x76, + 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x2c, 0x20, + 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x70, + 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, 0x61, 0x72, 0x65, + 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x64, 0xa, 0x62, + 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3c, 0x74, 0x74, 0x3e, 0x74, + 0x63, 0x70, 0x69, 0x70, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, + 0x28, 0x29, 0x3c, 0x2f, 0x74, 0x74, 0x3e, 0x2c, 0x20, 0x77, + 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x61, 0x6b, 0x65, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, + 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0xa, + 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x3c, 0x74, 0x74, + 0x3e, 0x69, 0x70, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x28, + 0x29, 0x3c, 0x2f, 0x74, 0x74, 0x3e, 0x20, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x77, 0x6f, 0xa, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x69, 0x73, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x3c, 0x74, 0x74, 0x3e, 0x74, 0x63, 0x70, 0x69, 0x70, 0x5f, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x28, 0x29, 0x3c, 0x2f, 0x74, + 0x74, 0x3e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x20, 0x6e, 0x6f, 0x74, + 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0xa, 0x74, + 0x68, 0x65, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, + 0x67, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x69, + 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x6c, 0x79, + 0x2e, 0x20, 0x49, 0x74, 0x20, 0x6d, 0x65, 0x72, 0x65, 0x6c, + 0x79, 0x20, 0x70, 0x75, 0x74, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x6f, 0x6e, + 0x20, 0x61, 0x20, 0x71, 0x75, 0x65, 0x75, 0x65, 0xa, 0x77, + 0x68, 0x69, 0x63, 0x68, 0x20, 0x6c, 0x61, 0x74, 0x65, 0x72, + 0x20, 0x69, 0x73, 0x20, 0x64, 0x72, 0x61, 0x69, 0x6e, 0x65, + 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, + 0x43, 0x50, 0x2f, 0x49, 0x50, 0x20, 0x74, 0x68, 0x72, 0x65, + 0x61, 0x64, 0x2e, 0xa, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0xa, + 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, + 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x22, 0x3e, 0xa, + 0x57, 0x68, 0x65, 0x6e, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, + 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, + 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x2d, 0x74, 0x68, 0x72, 0x65, + 0x61, 0x64, 0x65, 0x64, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x2c, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x20, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, + 0x74, 0x61, 0x6b, 0x65, 0x6e, 0x20, 0x63, 0x61, 0x72, 0x65, + 0xa, 0x6f, 0x66, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x3c, 0x74, + 0x74, 0x3e, 0x74, 0x63, 0x70, 0x69, 0x70, 0x2e, 0x63, 0x3c, + 0x2f, 0x74, 0x74, 0x3e, 0x2e, 0xa, 0x3c, 0x2f, 0x70, 0x3e, + 0xa, 0xa, 0x3c, 0x70, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, + 0x3d, 0x22, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, 0x3e, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa, 0x3c, 0x66, + 0x6f, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x22, + 0x2d, 0x31, 0x22, 0x3e, 0x3c, 0x69, 0x3e, 0xa, 0x24, 0x44, + 0x61, 0x74, 0x65, 0x3a, 0x20, 0x32, 0x30, 0x30, 0x32, 0x2f, + 0x30, 0x32, 0x2f, 0x30, 0x31, 0x20, 0x31, 0x38, 0x3a, 0x32, + 0x33, 0x3a, 0x33, 0x35, 0x20, 0x24, 0xa, 0x3c, 0x2f, 0x69, + 0x3e, 0x3c, 0x2f, 0x66, 0x6f, 0x6e, 0x74, 0x3e, 0xa, 0x3c, + 0x2f, 0x70, 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0xa, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, + 0x64, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, + 0x30, 0x22, 0x3e, 0xa, 0x26, 0x6e, 0x62, 0x73, 0x70, 0x3b, + 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x2f, 0x74, + 0x72, 0x3e, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, + 0xa, 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x34, 0x30, 0x22, + 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, 0x22, 0x30, + 0x22, 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, + 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x30, 0x22, 0xa, 0x63, 0x65, + 0x6c, 0x6c, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3d, + 0x22, 0x30, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, + 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x3e, 0xa, 0xa, + 0x3c, 0x68, 0x72, 0x3e, 0xa, 0xa, 0xa, 0xa, 0xa, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, + 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, + 0x6e, 0x65, 0x77, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x4e, 0x65, 0x77, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0xa, + 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0x22, 0x3e, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x61, 0x3e, + 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x6d, 0x61, 0x69, 0x6c, 0x69, 0x6e, + 0x67, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x68, 0x74, 0x6d, 0x6c, + 0x22, 0x3e, 0x4d, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, + 0x6c, 0x69, 0x73, 0x74, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, + 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, + 0x67, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x3c, 0x2f, 0x61, + 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, 0x68, + 0x72, 0x65, 0x66, 0x3d, 0x22, 0x64, 0x6f, 0x77, 0x6e, 0x6c, + 0x6f, 0x61, 0x64, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x3c, 0x2f, + 0x61, 0x3e, 0xa, 0xa, 0x7c, 0xa, 0xa, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x6c, 0x69, 0x6e, 0x6b, + 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4c, 0x69, + 0x6e, 0x6b, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0xa, 0xa, 0xa, + 0xa, 0x3c, 0x68, 0x72, 0x3e, 0xa, 0xa, 0x3c, 0x2f, 0x74, + 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x72, + 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x64, 0x69, + 0x76, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x22, 0x3e, 0xa, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, + 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, + 0x2f, 0x22, 0x3e, 0x41, 0x64, 0x61, 0x6d, 0x20, 0x44, 0x75, + 0x6e, 0x6b, 0x65, 0x6c, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, + 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0xa, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x2f, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0xa, 0x3c, 0x2f, + 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, 0x3c, 0x2f, 0x68, 0x74, + 0x6d, 0x6c, 0x3e, 0xa, }; + +static const char data_threads_png[] = { + /* /threads.png */ + 0x2f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x2e, 0x70, 0x6e, 0x67, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, + 0x65, 0x2f, 0x70, 0x6e, 0x67, 0xd, 0xa, 0xd, 0xa, 0x89, + 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 00, 00, 00, + 0xd, 0x49, 0x48, 0x44, 0x52, 00, 00, 0x1, 0x44, 00, + 00, 00, 0xf5, 0x8, 0x2, 00, 00, 00, 0xa7, 0x69, + 0x1b, 0xf5, 00, 00, 00, 0x9, 0x70, 0x48, 0x59, 0x73, + 00, 00, 0xc, 0x4d, 00, 00, 0xc, 0x4d, 0x1, 0xd2, + 0xce, 0xad, 0x4e, 00, 00, 00, 0x1d, 0x74, 0x45, 0x58, + 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 00, + 0x47, 0x4e, 0x55, 0x20, 0x47, 0x68, 0x6f, 0x73, 0x74, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x36, 0x2e, 0x35, 0x32, + 0x19, 0x40, 0x45, 0x56, 00, 00, 0x7, 0x16, 0x49, 0x44, + 0x41, 0x54, 0x78, 0x9c, 0xed, 0xdd, 0xdb, 0x76, 0xa3, 0x38, + 00, 0x45, 0x41, 0xbb, 0xd7, 0xfc, 0xff, 0x2f, 0x7b, 0x1e, + 0xb2, 0x9a, 0x61, 00, 0x13, 0x2e, 0x2, 0xa4, 0xa3, 0xaa, + 0xa7, 0xee, 0xc4, 0xc6, 0x8e, 0x9c, 0x8d, 0x84, 0x2f, 0xe4, + 0xfd, 0xf9, 0x7c, 0x5e, 0x40, 0xfb, 0xfe, 0xbc, 0x5e, 0xaf, + 0xf7, 0xfb, 0xbd, 0x7e, 0xa1, 0xf7, 0x5f, 0x93, 0xff, 0x8e, + 0xbf, 0xf8, 0xeb, 0x16, 0x4e, 0xde, 0xd1, 0x52, 0x1b, 0xa9, + 0xdf, 0xb1, 0x1f, 0x73, 0xfc, 0xe8, 0xdc, 0x73, 0x8b, 0xc3, + 0x75, 0x33, 0x1e, 0x97, 0x86, 0x86, 0xfd, 0x5b, 0x7a, 0x7f, + 0xb6, 0x5c, 0xf9, 0x67, 0xf6, 0x1e, 0xcf, 0xe1, 0x9f, 0xcf, + 0xe7, 0xd7, 0x29, 0x3d, 0xe3, 0x31, 0xbe, 0xd9, 0xf9, 0x41, + 0xdb, 0xbe, 0xd4, 0x1a, 0x6e, 0xeb, 0xcc, 0xea, 0x2c, 0x63, + 0x65, 0xd7, 0xd0, 0xb0, 0xff, 0x5c, 0xfd, 0xe7, 0xba, 0x93, + 0xbb, 0xbd, 0x29, 0xe6, 0x6f, 0x56, 0xee, 0xcd, 0x96, 0xd9, + 0xfe, 0xcc, 0x4d, 0x67, 0x9b, 0xc, 0xce, 0x7c, 0xac, 0xce, + 0x8f, 0xde, 0xf6, 0x2d, 0xf4, 0xf3, 0x48, 0x35, 0x31, 0xec, + 0xc3, 0x3c, 0x3a, 0xaf, 0xef, 0x9f, 0xc9, 0xf5, 0x87, 0xe2, + 0x27, 0xff, 0x38, 0x79, 0xcf, 0x5e, 0x5f, 0x76, 0x48, 0x3f, + 0xdb, 0x1f, 0x6f, 0x67, 0xfc, 0xdf, 0xc5, 0xdd, 0x4f, 0xb0, + 0xf1, 0xb0, 0xcf, 0xbf, 0xf5, 0xf3, 0x8f, 0x61, 0xf4, 0xbe, + 0x8d, 0xe7, 0x6b, 0x69, 0xdc, 0x26, 0x5f, 0xf9, 0x76, 0x95, + 0xc5, 0x6b, 0x7d, 0xbb, 0x62, 0x8c, 0x98, 0x61, 0xff, 0xe7, + 0xf7, 0x8b, 0x2c, 0x39, 0xd0, 0xdb, 0xe2, 0x25, 0x27, 0x25, + 0xcf, 0x2f, 0x39, 0xde, 0x9b, 0xf4, 0x53, 0xf5, 0xdc, 0x30, + 0x26, 0xc3, 0x80, 0xcc, 0xbf, 0xf2, 0x1a, 0x8d, 0xe7, 0xe2, + 0x5e, 0x78, 0x3c, 0xb0, 0xc3, 0x25, 0xc7, 0xf, 0xc1, 0x64, + 0xb4, 0xe7, 0xb7, 0x75, 0xf5, 0x8f, 0x59, 0x9b, 0x9a, 0x87, + 0x7d, 0x7e, 0x5b, 0xff, 0x8b, 0x79, 0x72, 0x3, 0xaf, 0xef, + 0xbb, 0x84, 0xc9, 0xd7, 0x17, 0x2f, 0xb6, 0xeb, 0xb1, 0x9f, + 0x4f, 0xd7, 0xdb, 0xaf, 0x9b, 0x64, 0xf1, 0x1, 0x1e, 0xcc, + 0xf7, 0x7d, 0x8b, 0x7b, 0xc3, 0x95, 0x8d, 0x6f, 0x1f, 0xd8, + 0x5d, 0x5b, 0x6e, 0x5d, 0x73, 0xc3, 0xbe, 0x78, 0x99, 0xe5, + 0x63, 0xe6, 0xa7, 0x5a, 0x5a, 0x7c, 0x8e, 0xae, 0x93, 0x5f, + 0xa9, 0x9f, 0x87, 0x7c, 0x50, 0x64, 0x83, 0xe3, 0x7f, 0x6c, + 0x1c, 0xc6, 0xc9, 0xb5, 0xe2, 0x35, 0x3a, 0xec, 0x8b, 0xf7, + 0x76, 0x21, 0xe6, 0xf1, 0xe2, 0x61, 0x72, 0x7b, 0xe3, 0x9b, + 0x3c, 0xbc, 0xff, 0x98, 0x7c, 0x77, 0xb2, 0x6e, 0x59, 0x5c, + 0x63, 0xf, 0x37, 0x97, 0xfa, 0x1b, 0x36, 0xf9, 0xe9, 0xe6, + 0x3f, 0xec, 0xfb, 0xaf, 0xc9, 0x7a, 0xec, 0xdb, 0x5e, 0x7f, + 0x65, 0x7d, 0x38, 0xbf, 0xa1, 0xc5, 0x6b, 0xbd, 0x36, 0xec, + 0xd3, 0x5b, 0x7f, 0x5c, 0x9a, 0x1e, 0xf6, 0xc1, 0x7f, 0x5f, + 0xef, 0x76, 0x41, 0xdb, 0x90, 0xf9, 0xaf, 0xce, 0xae, 0x95, + 0x1b, 0xc7, 0x34, 0x37, 0xec, 0xa7, 0x5e, 0x9a, 0x2, 0xea, + 0x21, 0xe6, 0xda, 0x75, 0xfb, 0x24, 0xc2, 0xb3, 0x5a, 0x1c, + 0xf6, 0xaa, 0x97, 0xd, 0xc0, 0x76, 0x66, 0x66, 0x8, 0x21, + 0x66, 0x8, 0x21, 0x66, 0x8, 0x21, 0x66, 0x8, 0x21, 0x66, + 0x8, 0x21, 0x66, 0x8, 0x21, 0xe6, 0x70, 0xf5, 0xbf, 0x3a, + 0x1a, 0xe9, 0x91, 0x61, 0x17, 0x33, 0x84, 0x10, 0x33, 0x84, + 0x10, 0x33, 0x84, 0x10, 0x33, 0x84, 0x28, 0x19, 0xb3, 0xe7, + 0x5a, 0xe0, 0x41, 0x66, 0x66, 0x8, 0x21, 0x66, 0x8, 0x21, + 0x66, 0x8, 0x21, 0x66, 0x8, 0x21, 0x66, 0x8, 0x71, 0xf0, + 0x24, 0xf8, 0xd4, 0xcc, 0xcb, 0xa, 0x7d, 0x12, 0x73, 0x82, + 0xc5, 0x53, 0xb7, 0x2e, 0x7e, 0x8b, 0x60, 0x62, 0x6e, 0xd2, + 0x4a, 0xbd, 0x74, 0x4b, 0xcc, 0xd, 0x98, 0xcf, 0xae, 0xea, + 0x65, 0x4e, 0xcc, 0x35, 0x32, 0xf1, 0x72, 0x80, 0x98, 0x9f, + 0x67, 0xe2, 0xa5, 0x8, 0x31, 0x3f, 0xc0, 0xc4, 0xcb, 0x15, + 0xc4, 0x7c, 0x7, 0xf5, 0x72, 0x3, 0x31, 0x97, 0x67, 0xd9, + 0xcc, 0x23, 0xc4, 0x5c, 0x80, 0x89, 0x97, 0x1a, 0x88, 0x79, + 0x37, 0x13, 0x2f, 0x75, 0x12, 0xf3, 0xef, 0x4c, 0xbc, 0x34, + 0x41, 0xcc, 0xb, 0xd4, 0x4b, 0x8b, 0xc4, 0x6c, 0xd9, 0x4c, + 0x88, 0x1e, 0x63, 0x36, 0xf1, 0x12, 0x29, 0x3f, 0x66, 0x13, + 0x2f, 0x9d, 0x8, 0x8c, 0xd9, 0xc4, 0x4b, 0x9f, 0x12, 0x62, + 0x56, 0x2f, 0xbc, 0x9e, 0x8a, 0xf9, 0xfd, 0x7e, 0x1f, 0x4e, + 0xce, 0xb2, 0x19, 0x16, 0xdd, 0x1d, 0xf3, 0x90, 0xe2, 0xf6, + 0x9e, 0x4d, 0xbc, 0xb0, 0xc5, 0x7d, 0x31, 0x6f, 0x3c, 0x7f, + 0x8d, 0x89, 0x17, 0x8e, 0xb9, 0x23, 0xe6, 0xf5, 0x8c, 0x4d, + 0xbc, 0x50, 0xc4, 0xb5, 0x31, 0x6f, 0xc9, 0x58, 0xbd, 0x50, + 0xc4, 0x55, 0x31, 0x6f, 0x59, 0x54, 0xcb, 0x18, 0xa, 0x2a, + 0x1c, 0xf3, 0xae, 0x13, 0xbb, 0x9e, 0x79, 0x4e, 0x1b, 0x98, + 0xf0, 0x17, 0x2d, 0x20, 0x44, 0xe1, 0x99, 0xd9, 0x4c, 0xb, + 0x4f, 0x31, 0x33, 0x43, 0x8, 0x31, 0x43, 0x88, 0xcb, 0x9f, + 00, 0xb3, 0xf0, 0x86, 0x7b, 0x5c, 0x7e, 0xcc, 0xbc, 0xf2, + 0xfc, 0xb6, 0xce, 0xa1, 0xa0, 0xcb, 0xdf, 0x1, 0xb6, 0x52, + 0xac, 0xce, 0xa1, 0xa0, 0x27, 0x3f, 0x2, 0xa9, 0x73, 0x28, + 0xa8, 0xd2, 0xcf, 0x33, 0xeb, 0x1c, 0xf6, 0xaa, 0x34, 0xe6, + 0x15, 0x3a, 0x87, 0x45, 0xed, 0xc5, 0xbc, 0x42, 0xe7, 0xf4, + 0x2c, 0x2a, 0xe6, 0x15, 0x3a, 0x27, 0x5e, 0x2f, 0x31, 0xaf, + 0xd0, 0x39, 0x19, 0xc4, 0xbc, 0xa6, 0xc2, 0xce, 0x7d, 0x8, + 0x9c, 0x6f, 0xc4, 0x7c, 0xd0, 0xb3, 0x9d, 0x4b, 0x9a, 0x39, + 0x31, 0x97, 0x77, 0x5b, 0xe7, 0xc3, 0xd6, 0x54, 0xcd, 0x4b, + 0xcc, 0x37, 0xbb, 0xa8, 0x73, 0x13, 0x35, 0x2f, 0x31, 0xd7, + 0xe3, 0x58, 0xe7, 0x8b, 0x17, 0x53, 0x75, 0x9f, 0xc4, 0xdc, + 0x80, 0x71, 0x9c, 0x5b, 0xc2, 0x56, 0x75, 0x9f, 0xc4, 0x9c, + 0x6c, 0xd7, 0x29, 0xd9, 0xd8, 0xa5, 0xc2, 0xb1, 0x15, 0x73, + 0x4b, 0xe, 0x1c, 0x57, 0x57, 0xf8, 0x3b, 0x57, 0xb9, 0x8d, + 0x23, 0xb6, 0xbe, 0xea, 0x79, 0x64, 0xd8, 0xc5, 0xdc, 0x18, + 0x2b, 0xe7, 0xc3, 0x8a, 0x54, 0x5a, 0x33, 0x31, 0xb7, 0xa4, + 0xdd, 0xdf, 0xb3, 0x4b, 0xc5, 0x57, 0xba, 0x91, 0x98, 0xa9, + 0x97, 0x4a, 0x77, 0x11, 0x33, 0xf, 0x50, 0xe9, 0x15, 0xc4, + 0x4c, 0x49, 0x2a, 0x7d, 0x90, 0x98, 0xd9, 0x44, 0xa5, 0xf5, + 0x13, 0x73, 0xef, 0x54, 0x1a, 0x43, 0xcc, 0xb1, 0x86, 0x4a, + 0xd7, 0x73, 0x55, 0x69, 0xc, 0x31, 0xb7, 0x67, 0xd7, 0x5c, + 0xea, 0x4f, 0x6d, 0xf6, 0x43, 0xcc, 0x15, 0xb1, 0xe2, 0xe5, + 0xc, 0x31, 0xdf, 0x41, 0xa5, 0xdc, 0x40, 0xcc, 0xa7, 0xa8, + 0x94, 0x7a, 0x88, 0x79, 0x99, 0x4a, 0x69, 0xce, 0x33, 0x31, + 0x3f, 0x78, 0x66, 0xc, 0x95, 0x92, 0xea, 0xbe, 0x98, 0xaf, + 0xfe, 0x50, 0x98, 0x4a, 0xe9, 0xdc, 0xe5, 0x31, 0x9f, 0x6f, + 0x58, 0xa5, 0xb0, 0xc5, 0x85, 0x31, 0xff, 0x1a, 0xa1, 0x4a, + 0xa1, 0xa0, 0xf2, 0x31, 0x6f, 0x9f, 0x8a, 0x55, 0xa, 0x5, + 0xfd, 0x29, 0xbb, 0x39, 0x27, 0xa9, 0x81, 0xa7, 0x14, 0x9e, + 0x99, 0x27, 0x93, 0xad, 0xb6, 0xe1, 0x36, 0xd7, 0x3e, 0x1, + 0x36, 0x5f, 0x48, 0xcb, 0x1b, 0x2e, 0x72, 0xf7, 0xeb, 0xcc, + 0x8e, 0x93, 0xe1, 0x22, 0x85, 0x8f, 0x99, 0x81, 0xa7, 0x88, + 0x19, 0x42, 0x88, 0x19, 0x42, 0x88, 0x19, 0x42, 0x88, 0x19, + 0x42, 0x88, 0x19, 0x42, 0x14, 0x7e, 0x69, 0x6a, 0xcb, 0xcb, + 0xc8, 0x5e, 0x9d, 0x82, 0x2b, 0x5c, 0xfb, 0xe, 0xb0, 0x45, + 0xc7, 0xde, 0x37, 0x62, 0x17, 00, 0xeb, 0x1e, 0x38, 0x39, + 0xc1, 0xb1, 0x2c, 0xf, 0xec, 0x2, 0xf4, 0x4f, 0x57, 0x9a, + 0x39, 0x6d, 0xd0, 0x81, 0x32, 0xf5, 0x4f, 0x57, 0x9a, 0x89, + 0xf9, 0x80, 0x7b, 0xfa, 0x3f, 0x76, 0x43, 0x50, 0x5c, 0x72, + 0xcc, 0x7, 0x38, 0x4, 0xa0, 0x5d, 0x62, 0x2e, 0xc0, 0x21, + 00, 0x35, 0x10, 0xf3, 0x33, 0x6e, 0x3b, 0x4, 0xa0, 0x1f, + 0x62, 0x6e, 0xc6, 0xe1, 0x43, 0x80, 0xbd, 0x7b, 0x1, 0x4b, + 0x80, 0x46, 0x89, 0x39, 0xdf, 0xde, 0x38, 0x1d, 0x2, 0x34, + 0x4a, 0xcc, 0x4c, 0x79, 0x15, 0x60, 0xee, 0xc1, 0x3f, 0xdb, + 0xb0, 0x9d, 0x98, 0x29, 0xa0, 0x93, 0x57, 0x1, 0x86, 0x3b, + 0x5c, 0x67, 0xd5, 0x62, 0xe6, 0x31, 0xed, 0xbe, 0xa, 0x50, + 0x67, 0xd5, 0x62, 0xa6, 0x25, 0xb5, 0x1d, 0x2, 0x54, 0x55, + 0xb5, 0x98, 0x9, 0x77, 0xcf, 0x21, 0xc0, 0xf8, 0xf2, 0x4f, + 0x85, 0x2d, 0x66, 0x58, 0x70, 0xe6, 0xc, 0xf0, 0x4f, 0xbd, + 0x23, 0x40, 0xcc, 0x70, 0x56, 0x25, 0xe7, 0x87, 0x17, 0x33, + 0xec, 0x56, 0xc3, 0x11, 0xf2, 0x9c, 0x98, 0xe1, 0x77, 0x75, + 0xd6, 0x3b, 0xe1, 0x1c, 0x60, 0x10, 0x42, 0xcc, 0x10, 0x42, + 0xcc, 0x10, 0x42, 0xcc, 0x10, 0x42, 0xcc, 0x10, 0x42, 0xcc, + 0x10, 0x42, 0xcc, 0x10, 0x42, 0xcc, 0x10, 0x42, 0xcc, 0x10, + 0x42, 0xcc, 0x10, 0x42, 0xcc, 0x10, 0x42, 0xcc, 0x10, 0x42, + 0xcc, 0xc9, 0x9c, 0x6a, 0xbb, 0x2b, 0x3e, 0x35, 0x15, 0x65, + 0x52, 0xef, 0xe7, 0xf3, 0xd1, 0x73, 0x3f, 0xc4, 0xdc, 0xb6, + 0x79, 0xbd, 0x4f, 0xdd, 0x13, 0x1e, 0x27, 0xe6, 0x96, 0xcc, + 0xa7, 0x59, 0xf5, 0x32, 0x10, 0x73, 0xd5, 0x4c, 0xbc, 0x6c, + 0x27, 0xe6, 0x8a, 0x98, 0x78, 0x39, 0x43, 0xcc, 0x4f, 0x32, + 0xf1, 0x52, 0x90, 0x98, 0x6f, 0xa5, 0x5e, 0xae, 0x23, 0xe6, + 0xb, 0x59, 0x36, 0x73, 0x27, 0x31, 0x97, 0x64, 0xe2, 0xe5, + 0x41, 0x62, 0x3e, 0xce, 0xc4, 0x4b, 0x55, 0xc4, 0xbc, 0x83, + 0x89, 0x97, 0x9a, 0x89, 0x79, 0x8d, 0x7a, 0x69, 0x88, 0x98, + 0xff, 0x63, 0xd9, 0x4c, 0xd3, 0xba, 0x8e, 0xd9, 0xc4, 0x4b, + 0x92, 0x8e, 0x62, 0x36, 0xf1, 0x92, 0x2d, 0x39, 0x66, 0x13, + 0x2f, 0x5d, 0x89, 0x8a, 0x59, 0xbd, 0xf4, 0xac, 0xe1, 0x98, + 0x2d, 0x9b, 0x61, 0xec, 0x81, 0x98, 0x87, 0x8, 0xf7, 0xb6, + 0x67, 0xe2, 0x85, 0x15, 0xb7, 0xc6, 0xbc, 0xeb, 0x14, 0x36, + 0x26, 0x5e, 0xd8, 0xe5, 0xa6, 0x98, 0xb7, 0x64, 0x6c, 0xe2, + 0x85, 0x33, 0x2e, 0x8f, 0x79, 0x25, 0x63, 0xf5, 0x42, 0x41, + 0x17, 0xc6, 0xfc, 0xeb, 0x6c, 0xac, 0x5e, 0x28, 0xe8, 0x92, + 0xf3, 0x66, 0xbf, 0xdf, 0xef, 0x3, 0xeb, 0x6a, 0xe0, 0x8c, + 0xc2, 0x33, 0xb3, 0x3e, 0xe1, 0x29, 0x85, 0x63, 0xfe, 0xb6, + 0x72, 0x16, 0x39, 0x5c, 0xed, 0xa6, 0x67, 0xb3, 0x1d, 0x1e, + 0xc3, 0xd5, 0xfc, 0xad, 0x29, 0x8, 0x21, 0x66, 0x8, 0x21, + 0x66, 0x8, 0x21, 0x66, 0x8, 0x21, 0x66, 0x8, 0x21, 0x66, + 0x8, 0x51, 0x38, 0x66, 0xaf, 0x27, 0xc3, 0x53, 0xca, 0xbf, + 0x69, 0x64, 0xa5, 0x67, 0xaf, 0x36, 0xc3, 0x75, 0xca, 0xbf, + 0x69, 0x64, 0xa5, 0x58, 0x9d, 0xc3, 0x75, 0x6e, 0x3d, 0x39, + 0x81, 0xce, 0xe1, 0x3a, 0xb5, 0x9c, 0x3, 0x4c, 0xe7, 0x70, + 0x52, 0x2d, 0x31, 0xaf, 0xd0, 0x39, 0x6c, 0xd1, 0x40, 0xcc, + 0x2b, 0x74, 0xe, 0x83, 0xb6, 0x63, 0x5e, 0xa1, 0x73, 0x7a, + 0x13, 0x1b, 0xf3, 0xa, 0x9d, 0x13, 0xa9, 0xc7, 0x98, 0x57, + 0xe8, 0x9c, 0x76, 0x89, 0x79, 0xab, 0x4a, 0x3a, 0x3f, 0xfc, + 0x27, 0x4, 0x88, 0x27, 0xe6, 0x2, 0x1e, 0xe9, 0xfc, 0x67, + 0xcb, 0x92, 0x66, 0x20, 0xe6, 0x6b, 0x5d, 0xdd, 0xb9, 0x89, + 0x9a, 0x81, 0x98, 0x1f, 0x73, 0xac, 0xf3, 0xf5, 0xab, 0x48, + 0xba, 0x67, 0x62, 0xae, 0xd1, 0xe1, 0xce, 0x4d, 0xd4, 0x3d, + 0x13, 0x73, 0x26, 0x9f, 0x45, 0xed, 0x90, 0x98, 0x5b, 0xb2, + 0x31, 0xd1, 0xf1, 0xb4, 0xac, 0xea, 0x7e, 0x88, 0xb9, 0x61, + 0xd6, 0xd2, 0x8c, 0x89, 0xb9, 0x25, 0xea, 0x65, 0x85, 0x73, + 0x80, 0x41, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, + 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, + 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, + 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, + 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, + 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, + 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, + 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, + 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, + 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, + 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, + 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, + 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, + 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, + 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, 0x31, 0x43, 0x8, + 0x31, 0x43, 0x8, 0x31, 0x43, 0x88, 0x92, 0x31, 0x7f, 0x3e, + 0x9f, 0x82, 0x5b, 0xa3, 0x8, 0xf, 0x4a, 0x3f, 0xcc, 0xcc, + 0x10, 0x42, 0xcc, 0x10, 0x42, 0xcc, 0x10, 0x42, 0xcc, 0x10, + 0xe2, 0x5f, 0x1d, 0x46, 0x9f, 0xd9, 0x7, 0x30, 0xb3, 0xe1, + 00, 00, 00, 00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, + 0x60, 0x82, }; + +static const char data_os_png[] = { + /* /os.png */ + 0x2f, 0x6f, 0x73, 0x2e, 0x70, 0x6e, 0x67, 0, + 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, + 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, + 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, + 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, + 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, + 0x65, 0x2f, 0x70, 0x6e, 0x67, 0xd, 0xa, 0xd, 0xa, 0x89, + 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 00, 00, 00, + 0xd, 0x49, 0x48, 0x44, 0x52, 00, 00, 0x2, 0x54, 00, + 00, 0x2, 0x13, 0x8, 0x2, 00, 00, 00, 0x4e, 0xa7, + 0x15, 0xaa, 00, 00, 00, 0x9, 0x70, 0x48, 0x59, 0x73, + 00, 00, 0xc, 0x4d, 00, 00, 0xc, 0x4d, 0x1, 0xd2, + 0xce, 0xad, 0x4e, 00, 00, 00, 0x1d, 0x74, 0x45, 0x58, + 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 00, + 0x47, 0x4e, 0x55, 0x20, 0x47, 0x68, 0x6f, 0x73, 0x74, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x36, 0x2e, 0x35, 0x32, + 0x19, 0x40, 0x45, 0x56, 00, 00, 0x20, 00, 0x49, 0x44, + 0x41, 0x54, 0x78, 0x9c, 0xed, 0xdd, 0xdb, 0x9a, 0xa3, 0xaa, + 0x16, 0x6, 0x50, 0x6b, 0x7f, 0xeb, 0xfd, 0x5f, 0xb9, 0xf6, + 0x45, 0x7a, 0xb9, 0x6c, 0x41, 0x82, 0x67, 0x60, 0x8e, 0x71, + 0xd5, 0x9d, 0x32, 0xc6, 0x78, 0xe0, 0x77, 0xa2, 0x91, 0x9f, + 0xdf, 0xdf, 0xdf, 0x89, 0x7e, 0xfc, 0xfc, 0xfc, 0xac, 0x5e, + 0xb1, 0x5, 0x1, 0xf6, 0xfa, 0xe7, 0xed, 0x5, 0x18, 0x4a, + 0x9a, 0x4c, 0x97, 0x4b, 0xa3, 0xee, 0x95, 0xf, 0x5, 0xe8, + 0xda, 0x8f, 0x76, 0xed, 0xab, 0xfa, 0x74, 0x19, 0x75, 0x65, + 0x5a, 0x3, 0xc0, 0x60, 0x84, 0xdf, 0x1f, 0x85, 0xf6, 0xdd, + 0x2a, 0xaa, 0xf7, 0x35, 0x26, 0xad, 0x4c, 0xa0, 0x5, 0x11, + 0xc3, 0x2f, 0xdb, 0x40, 0x7, 0x5c, 0xf, 0xaf, 0x70, 0x92, + 0x1, 0xb4, 0x60, 0xfc, 0xf0, 0x73, 0x87, 0x48, 0x17, 0xb6, + 0x42, 0xd1, 0xc6, 0x2, 0xee, 0x30, 0x66, 0xf8, 0xad, 0x5a, + 0xd2, 0x21, 0xbf, 0x63, 0x10, 0xce, 0x5d, 0x80, 0x3b, 0x8c, + 0x13, 0x7e, 0xcb, 0x56, 0x72, 0x98, 0x2f, 0x45, 0xca, 0x99, + 0xd, 0x70, 0x5e, 0xdf, 0xe1, 0x27, 0xf0, 0x90, 0x85, 0xc0, + 0x1, 0x5d, 0x86, 0xdf, 0xdc, 0xde, 0xf5, 0xb8, 0xf0, 0xdc, + 0xca, 0xf9, 0x10, 0x50, 0xa3, 0xa7, 0xf0, 0xeb, 0x34, 0xf3, + 0x1e, 0xf8, 0x11, 0x7a, 0x83, 0x5a, 0xd8, 0x46, 0x82, 0x10, + 0xd8, 0xd2, 0x41, 0xf8, 0xb5, 0xd9, 0x84, 0xf9, 0xdd, 0x77, + 0xd9, 0x25, 0x91, 0x7f, 0xe1, 0xaa, 0x6b, 0x73, 0x2f, 0x2, + 0xde, 0xd2, 0x74, 0xf8, 0x7d, 0x1a, 0xac, 0xb7, 0x96, 0xb0, + 0xdc, 0x7c, 0xb7, 0xbc, 0xde, 0x86, 0x71, 0x20, 0x41, 0x6b, + 0xb6, 0x4b, 0xa7, 0x5d, 0x8, 0xc0, 0x85, 0x1a, 0xd, 0xbf, + 0x27, 0x63, 0xcf, 0x2f, 0xcc, 0x46, 0xb2, 0xab, 0x22, 0x97, + 0x82, 0x8f, 0xf9, 0xf9, 0x69, 0xb4, 0xa9, 0xa1, 0x60, 0xec, + 0xad, 0xd6, 0xdc, 0x77, 0xbb, 0x3b, 0xf6, 0xfc, 0x6e, 0x8c, + 0xa9, 0x2e, 0x23, 0xed, 0x18, 0x27, 0x6d, 0x1d, 0x6b, 0xc7, + 0x8e, 0xf1, 0xc3, 0x2d, 0xc3, 0xb2, 0x5, 0xbf, 0xb5, 0x79, + 0xa9, 0x9f, 0xf9, 0xbb, 0x7d, 0x5a, 0xcb, 0x65, 0x98, 0xad, + 0x56, 0x51, 0xf6, 0x4f, 0xab, 0xf7, 0x56, 0x2e, 0xff, 0x6a, + 0xe2, 0x76, 0x6e, 0xcf, 0x6e, 0x68, 0x54, 0x87, 0x3b, 0x76, + 0x8, 0x51, 0x47, 0x56, 0x76, 0x37, 0x58, 0x15, 0x82, 0x9e, + 0x53, 0x7a, 0x46, 0x7a, 0x38, 0xc7, 0xbc, 0xf3, 0xab, 0x4d, + 0x69, 0x20, 0x7d, 0x4e, 0x11, 0x1e, 0xdb, 0x6a, 0xf3, 0x21, + 0xf6, 0x62, 0x71, 0xd9, 0x44, 0xf8, 0x5d, 0x18, 0x7b, 0xed, + 0x9c, 0x56, 0xd0, 0x9d, 0xbd, 0xf5, 0x81, 0xe7, 0x94, 0x7e, + 0xb5, 0x6c, 0xda, 0xd2, 0x7f, 0x3c, 0xb3, 00, 0x8f, 0x7d, + 0x56, 0x2f, 0xb6, 0x76, 0xef, 0x79, 0x5d, 0x65, 0xb7, 0xda, + 0x78, 0x5e, 0xe, 0xbf, 0x4b, 0x62, 0xcf, 0x8d, 0x7c, 0x5c, + 0xab, 0xb2, 0x77, 0xae, 0xf0, 0x27, 0xb9, 0x38, 0xdb, 0x2a, + 0x26, 0x96, 0xd7, 0x5c, 0x67, 0x5b, 0x35, 0xf7, 0x6a, 0xa5, + 0x55, 0x1e, 0xf2, 0xd9, 0xd6, 0x3c, 0xfb, 0xf6, 0xf4, 0xa4, + 0xb9, 0x66, 0x9a, 0xec, 0xa2, 0x56, 0x7e, 0x44, 0x59, 0xe5, + 0x9a, 0xa9, 0x5c, 0x5d, 0x5f, 0xa5, 0xdb, 0xe2, 0x58, 0x17, + 0xee, 0x72, 0xcb, 0xb6, 0xbf, 0x9f, 0xbf, 0x16, 0x7e, 0x27, + 0x63, 0x4f, 0xe0, 0x71, 0xb7, 0x33, 0x17, 0xa8, 0xf6, 0xe6, + 0xe2, 0x78, 0xfb, 0xf0, 0xaa, 0x5d, 0x2e, 0xb4, 0x86, 0xe9, + 0x94, 0x53, 0xdd, 0xca, 0xff, 0x34, 0xb2, 0xe5, 0x39, 0x67, + 0xe7, 0x50, 0xce, 0x8c, 0x55, 0xdb, 0xb2, 0xfa, 0x88, 0x65, + 0x4e, 0x94, 0xaf, 0x66, 0x2d, 0xdf, 0xbe, 0x9c, 0x7f, 0x76, + 0xca, 0xad, 0xe5, 0x9f, 0x8a, 0x6b, 0x26, 0x2d, 0xd1, 0x4e, + 0x56, 0xba, 0xf5, 0x5b, 0xed, 0xa4, 0x16, 0xee, 0x35, 0x7b, + 0x27, 0xfc, 0xe, 0xaf, 0xd3, 0x16, 0x56, 0x19, 0xa1, 0xcc, + 0xcd, 0xc1, 0x55, 0xbb, 0x5c, 0xf9, 0x72, 0xe3, 0xd7, 0x29, + 0xfb, 0xb2, 0xd5, 0x52, 0x9f, 0xb1, 0xa, 0x83, 0x69, 0xbb, + 0xc5, 0x3f, 0xf6, 0x71, 0x69, 0xbc, 0x2d, 0x5f, 0xaf, 0x49, + 0x97, 0xaf, 0xb, 0x76, 0x5e, 0xb6, 0x6e, 0xce, 0x2e, 0x43, + 0xfa, 0xc6, 0x9a, 0x99, 0x4f, 0xd5, 0x5b, 0x2d, 0x5d, 0x2d, + 0xbd, 0xdc, 0x4d, 0xf6, 0x42, 0xf8, 0x1d, 0x38, 0x6, 0x64, + 0x1e, 0xef, 0xda, 0xaa, 0x21, 0x2e, 0x9c, 0x7f, 0xfa, 0x62, + 0xd7, 0xb7, 0x6b, 0x6d, 0x55, 0x4b, 0x5f, 0xad, 0x8a, 0x8f, + 0x63, 0xdd, 0xce, 0x57, 0xa9, 0xec, 0xad, 0xfd, 0xfa, 0xf6, + 0xe7, 0x2f, 0x3d, 0x1e, 0xae, 0x2e, 0x8e, 0x6d, 0xb5, 0xd5, + 0x5b, 0xba, 0xd8, 0x51, 0x1f, 0xd, 0xbf, 0xbd, 0xeb, 0x45, + 0xe6, 0xd1, 0x8e, 0x33, 0xbd, 0xa0, 0x67, 0x3e, 0x71, 0xa9, + 0xaf, 0x38, 0x3c, 0xd9, 0xc1, 0xf3, 0xb5, 0x33, 0xf3, 0xe4, + 0xa7, 0x14, 0xa4, 0x1f, 0x31, 0xbf, 0x9e, 0x4e, 0x9c, 0x2e, + 0xc0, 0xd6, 0xdb, 0xb3, 0x8b, 0x7a, 0xa0, 0x55, 0x3c, 0xf9, + 0x7d, 0xd3, 0xbe, 0xdc, 0x65, 0xae, 0x1f, 0x9e, 0x7f, 0xcb, + 0xbb, 0x62, 0xd6, 0x73, 0xe1, 0xb7, 0x6b, 0x9d, 0x76, 0x74, + 0xfa, 0x40, 0x28, 0x97, 0xf7, 0x82, 0x1e, 0xf8, 0xf4, 0xa5, + 0xc6, 0xe3, 0xf0, 0xc0, 0xb5, 0xf9, 0xb4, 0xcf, 0x70, 0x55, + 0x7e, 0xa5, 0x4d, 0x76, 0xcd, 0x3c, 0x8f, 0x4d, 0xb6, 0xaa, + 0xf6, 0xb6, 0xee, 0x8b, 0x29, 0xdf, 0xf6, 0xb2, 0xea, 0x45, + 0x4c, 0x27, 0xa8, 0xb4, 0xfa, 0xb8, 0x33, 0x1b, 0x3a, 0xed, + 0xab, 0x2c, 0xdf, 0x10, 0x94, 0x35, 0xaf, 0xae, 0xec, 0xfd, + 0x41, 0xab, 0x59, 0xfd, 0x2c, 0x7e, 0x4a, 0x31, 0xbd, 0x77, + 0x4, 0x2d, 0x3d, 0xb4, 0x4, 0xf5, 0x5f, 0x55, 0xec, 0xd1, + 0x85, 0x16, 0x8e, 0xde, 0xac, 0xb4, 0x81, 0x7e, 0x6b, 0x49, + 0xe, 0x6b, 0x3c, 0xd1, 0x2f, 0xd7, 0xec, 0xbe, 0x34, 0xb6, + 0x27, 0x2a, 0xbf, 0xfa, 0xd3, 0xae, 0x69, 0xf4, 0xbd, 0x9c, + 0x61, 0x34, 0x7b, 0x79, 0x23, 0x5b, 0xbb, 0x64, 0xff, 0xd4, + 0xb2, 0xad, 0x42, 0x64, 0x3c, 0x92, 0xef, 0x2d, 0xb7, 0xaf, + 0xf7, 0x9a, 0x4d, 0xdb, 0x66, 0x23, 0x2, 0x35, 0x3a, 0x6a, + 0xbc, 0x7a, 0x29, 0xa, 0x7b, 0x59, 0x4e, 0xba, 0x76, 0xef, + 0x71, 0xfb, 0xb5, 0x5d, 0x10, 0x7b, 0xc, 0xa0, 0xa3, 0xfc, + 0x5b, 0xea, 0xb4, 0x28, 0x84, 0x4b, 0xdc, 0xf8, 0x1b, 0xc6, + 0x33, 0xb1, 0x37, 0x76, 0x47, 0x7, 0x11, 0xf4, 0x15, 0x27, + 0x82, 0x90, 0x68, 0x6e, 0xb9, 0xe6, 0x57, 0x93, 0x7c, 0x5f, + 0xf, 0x30, 0x47, 0x20, 0x7d, 0x49, 0x6f, 0x44, 0xec, 0xc8, + 0x81, 0x9b, 0xfd, 0xa0, 0x6b, 0x4f, 0xff, 0xc8, 0x5d, 0x3f, + 0x27, 0xa3, 0xfa, 0xed, 0xe4, 0x91, 0x86, 0x5f, 0x65, 0x83, + 0x70, 0x80, 0xef, 0x5, 0x4b, 0xd7, 0x87, 0x5f, 0xe1, 0xf8, + 0x1f, 0xa3, 0x69, 0x80, 0x2d, 0xc3, 0xe4, 0xdf, 0x2c, 0x5b, + 0xcb, 0x8e, 0xf4, 0x5, 0x9, 0xeb, 0xe2, 0xf0, 0x93, 0x7c, + 0x4, 0x77, 0xe0, 0xa1, 0x50, 0x5d, 0x50, 0xe, 0x32, 0x98, + 0x2b, 0xc3, 0x4f, 0xf2, 0x41, 0x4, 0x69, 0x39, 0xe8, 0xe8, + 0xa6, 0x3b, 0x97, 0x85, 0x9f, 0xe4, 0x83, 0x8f, 0x51, 0x8b, + 0xbf, 0x94, 0x14, 0xa4, 0x5f, 0xb7, 0xdf, 0xf0, 0x22, 0xf9, + 0x88, 0x29, 0xd4, 0x9e, 0x2f, 0x5, 0xe9, 0xce, 0x35, 0xe1, + 0xb7, 0x75, 0x9c, 0x87, 0x3a, 0xfe, 0x61, 0x69, 0xbc, 0x9b, + 0x5f, 0x6a, 0x1c, 0x78, 0xea, 0x34, 0xbc, 0xe2, 0x82, 0xf0, + 0x93, 0x7c, 0xc0, 0xca, 0x72, 0x28, 0x83, 0x49, 0xa, 0xd2, + 0x9e, 0xbb, 0xba, 0x3d, 0x25, 0x1f, 0xc4, 0x2c, 0xfe, 0x96, + 0x14, 0x82, 0x34, 0xeb, 0x6c, 0xf8, 0x6d, 0xd, 0xcf, 0x68, + 0x2f, 0x87, 0x49, 0xfe, 0xfd, 0x4b, 0x21, 0x48, 0x6b, 0x4e, + 0x85, 0xdf, 00, 0xc9, 0xd7, 0xd7, 0xd2, 0x42, 0xd7, 0x14, + 0x82, 0xb4, 0xe3, 0x7f, 0xd7, 0xce, 0xae, 0xaf, 0x2c, 0x9, + 0x72, 0x3f, 0x3a, 0xef, 0x8a, 0xf3, 0xcb, 0x87, 0x7a, 0xbf, + 0xbf, 0xbf, 0xe9, 0x60, 0xe2, 0xf0, 0xa4, 0xe3, 0x95, 0x5f, + 0x5f, 0x39, 0xb7, 0x65, 0x80, 0xaf, 0x40, 0xfb, 0x74, 0x7e, + 0x66, 0xe9, 0xb, 0xe5, 0x45, 0xf, 0x3d, 0xe1, 0xe5, 0xc2, + 0x8f, 0x98, 0xff, 0xbd, 0x3a, 0x72, 0xa6, 0xbf, 0x3b, 0x55, + 0x56, 0x3, 0x6d, 0xa7, 0x7, 0x98, 0xc6, 0x8, 0x5a, 0xa0, + 0x2f, 0x94, 0x57, 0x1c, 0xc, 0xbf, 0x34, 0x39, 0x1e, 0xcb, + 0x92, 0x65, 0x98, 0x65, 0xe3, 0x2d, 0x5d, 0x9e, 0xf9, 0xdf, + 0xfa, 0x58, 0x78, 0x8b, 0xe2, 0xef, 0xab, 0xe5, 0x41, 0x6a, + 0x45, 0x71, 0xb7, 0xa7, 0x87, 0x34, 0x3a, 0x63, 0xd9, 0x76, + 0xac, 0xa, 0xbb, 0xd5, 0x64, 0x53, 0x72, 0x3a, 0x99, 0xbe, + 0xe8, 0xe8, 0x82, 0x6, 0xcd, 0x11, 0xe8, 0x8, 0xe5, 0x56, + 0x47, 0xc2, 0xef, 0xc5, 0xb2, 0x6f, 0xa5, 0xf2, 0x43, 0xd3, + 0xa5, 0xbd, 0x67, 0x71, 0xa0, 0x44, 0xf1, 0x57, 0xaf, 0x70, + 0x76, 0xb, 0x97, 0xb8, 0xf1, 0x9, 0x2f, 0x4f, 0x5a, 0xe5, + 0x99, 0x61, 0xe2, 0xa1, 0x77, 0x7a, 0x41, 0xb9, 0xd5, 0xee, + 0xf0, 0x7b, 0x37, 0xea, 0x96, 0x47, 0xc2, 0xea, 0xe, 0xf2, + 0xc2, 0x52, 0x15, 0x2e, 0xd, 0xc2, 0x93, 0x14, 0x7f, 0x7b, + 0x89, 0x40, 0x6e, 0x72, 0xcb, 0x13, 0x5e, 0x6e, 0x92, 0x7e, + 0x50, 0xf6, 0xa3, 0x57, 0x2f, 0x96, 0xff, 0xb, 0xb4, 0xcf, + 0x85, 0x40, 0x2e, 0xb7, 0xef, 0x47, 0xee, 0x76, 0x3e, 0xe0, + 0x2d, 0x7e, 0x17, 0xcf, 0x85, 0x4e, 0x3d, 0xe1, 0x45, 0x16, + 0xc2, 0x5e, 0x1e, 0xf8, 0x72, 0xc6, 0xfc, 0x68, 0x98, 0xb7, + 0x17, 0x84, 0xee, 0x5d, 0xfc, 0x78, 0x33, 0x80, 0xbb, 0x29, + 0x1, 0x39, 0x6f, 0x47, 0xf8, 0xad, 0xea, 0x3c, 0x65, 0x1f, + 0x1c, 0xa3, 0x76, 0x39, 0x4f, 0x9, 0xc8, 0x49, 0x2a, 0x3f, + 0xa0, 0x57, 0xf2, 0x8f, 0xc3, 0x6a, 0xc3, 0x2f, 0x2d, 0xfb, + 0xee, 0x59, 0x1e, 0x80, 0x1d, 0x74, 0x81, 0x72, 0xcc, 0xf1, + 0xca, 0x4f, 0x9f, 0x27, 0x1c, 0xa6, 0x64, 0xb9, 0x90, 0x2e, + 0x50, 0xe, 0xd0, 0xed, 0x9, 0x8c, 0x40, 0xfe, 0xb1, 0x4b, + 0x55, 0xf8, 0xb9, 0xb7, 0x5, 0x68, 0x9f, 0xfc, 0xa3, 0xde, + 0x91, 0xca, 0x4f, 0x16, 0xc2, 0x79, 0x5a, 0xea, 0x3b, 0x58, + 0xab, 0x54, 0xd2, 0xed, 0x9, 0xc, 0x45, 0xfe, 0x51, 0x23, + 0x4a, 0xf8, 0x39, 0x18, 0xe, 0x3b, 0xb0, 0xea, 0xd2, 0x81, + 0x85, 0x8f, 0xcd, 0x7, 0x8e, 0x91, 0x7f, 0x7c, 0xf5, 0x3d, + 0xfc, 0xc6, 0xf8, 0x6d, 0x7b, 0xfd, 0x32, 0x3b, 0x66, 0x56, + 0xae, 0xda, 0xdc, 0x3d, 0xee, 0x36, 0xf, 0xb0, 0xbf, 0xdd, + 0x44, 0xfe, 0x51, 0x16, 0xa5, 0xf2, 0x9b, 0x95, 0x8f, 0x7, + 0x47, 0x4b, 0xc1, 0x85, 0x2b, 0xc7, 0x7a, 0xfe, 0x70, 0x42, + 00, 0x6f, 0xb9, 0x60, 0x30, 0xdb, 0xf6, 0xad, 0x6, 0x3, + 0x9b, 0x5b, 0xde, 0xfa, 0x11, 0xfe, 0x2a, 0x7, 0xe, 0x1c, + 0x4f, 0x61, 0xd5, 0xad, 0x46, 0x49, 0xdc, 0x5a, 0x2d, 0x9f, + 0x3f, 0xa5, 0xe3, 0xb1, 0xad, 0xb6, 0x42, 0xfa, 0x7a, 0xfa, + 0x27, 0xd8, 0xc5, 0xe8, 0x89, 0x14, 0x7c, 0xa9, 0xfc, 0xc6, + 0xd8, 0x75, 0xd2, 0x21, 0xfd, 0xd2, 0xd6, 0x3c, 0x3b, 0xe5, + 0x3c, 0xcd, 0xef, 0xc2, 0x7d, 0xcb, 0xd9, 0xa0, 0xad, 0x55, + 0x37, 0xef, 0x18, 0x95, 0x35, 0x5c, 0x76, 0x2c, 0xc6, 0x74, + 0xe, 0x91, 0x57, 0x35, 0x77, 0xd0, 0xf9, 0xc9, 0x16, 0xe3, + 0xf9, 0x4d, 0xd3, 0xbf, 0xd, 0xf1, 0x90, 0x5f, 0xed, 0xe, + 0xf3, 0x8a, 0x4a, 0x83, 0x70, 0x7e, 0xd0, 0x54, 0xe5, 0x13, + 0xa7, 0xac, 0x73, 0xee, 0x26, 0xff, 0xc8, 0xa, 0x77, 0xcd, + 0xaf, 0xa0, 0x70, 0x84, 0xcc, 0x7f, 0x72, 0x14, 0x15, 0x2c, + 0xcf, 0x21, 0xe6, 0x27, 0x4e, 0xed, 0x8d, 0xb7, 0x68, 0xab, + 0x5a, 0xd3, 0xfc, 00, 0x2b, 0x99, 0x54, 0x29, 0xfc, 0x22, + 0xec, 0x2e, 0xcb, 0x92, 0x25, 0xed, 0xb, 0x5d, 0x5d, 0xd6, + 0x1a, 0xb5, 0xf0, 0xad, 0x37, 0xd7, 0x76, 0xab, 0xe2, 0xef, + 0xfc, 0xac, 0xac, 0x6a, 0xe0, 0x49, 0xa5, 0x26, 0x26, 0x6d, + 0x80, 0x1e, 0x6b, 0x92, 0xb4, 0x7d, 0xd, 0xba, 0x70, 0xa3, + 0xc, 0xbf, 0x7d, 0x77, 0x7d, 0xc1, 0xe1, 0xd7, 0x46, 0x23, + 0xac, 0x67, 0x96, 0x74, 0x7b, 0x2, 0x10, 0xce, 0xbe, 0x91, + 0xdc, 0xef, 0x5b, 0xe, 0x1a, 0xe7, 0x47, 0x7e, 0xb7, 0xb2, + 0x4e, 0x1e, 0xe0, 0xca, 0x1f, 0x4b, 0xfb, 0x2a, 0x3f, 0x9d, + 0x6, 0x61, 0x5d, 0x78, 0x37, 0xac, 0x1b, 0x6b, 0x57, 0xac, + 0x8d, 0xc7, 0xc8, 0x3f, 0x66, 0x9b, 0xe1, 0xa7, 0x7f, 0x1c, + 0x80, 0x51, 0xb9, 0xe6, 0x7, 0x4, 0xa2, 0xf8, 0xe3, 0x43, + 0xf8, 0x1, 0x10, 0x8e, 0xf0, 0xe3, 0xb, 0x43, 0x1a, 0x1, + 0xe3, 0xc9, 0x87, 0x9f, 0xb, 0x7e, 0xcc, 0xc, 0x69, 0xf4, + 00, 0x7d, 0x71, 0x4f, 0xb2, 0xb6, 0x99, 0x54, 0x7e, 0xd4, + 0x7b, 0xa5, 0xbd, 0xd0, 0x48, 0x1, 0x77, 0x8, 0x31, 0xa4, + 0xd1, 0xf4, 0xf7, 0xc0, 0x3a, 0x4b, 0xab, 0x17, 0xe7, 0xc7, + 0x51, 0x66, 0xa7, 0x5c, 0xcd, 0x70, 0xeb, 0x4f, 0x23, 0xb9, + 0x69, 0x48, 0xa3, 0x5d, 0xeb, 0xdc, 0xe0, 0x47, 0xc0, 0xe5, + 0xa2, 0x84, 0xdf, 0xc7, 0xea, 0x51, 0xcb, 0x85, 0x91, 0x7, + 0xd2, 0x29, 0x97, 0x7f, 0x8d, 0xd3, 0x2d, 0x9c, 0x9e, 0x1c, + 0x4c, 0x8b, 0x67, 0x6f, 0xd6, 0x3f, 0x84, 0x73, 0x39, 0x9f, + 0xad, 0xb7, 0x6c, 0xad, 0xf3, 0xad, 0xe7, 0xaf, 0x6, 0xd9, + 0x4, 0xdc, 0xe1, 0xd8, 0x53, 0xd7, 0x19, 0x49, 0xac, 0xf0, + 0xdb, 0xe2, 0x18, 0xd8, 0x65, 0x59, 0xc9, 0xa5, 0xf, 0xa7, + 0xfe, 0x58, 0x95, 0x7a, 0x17, 0x7e, 0x28, 0xc0, 0x79, 0x99, + 0x6b, 0x7e, 0x61, 0x4f, 0x88, 0x76, 0xb5, 0xad, 0xd1, 0x46, + 0xde, 0xa9, 0x51, 0x3f, 0xa4, 0xd1, 0x25, 0x6b, 0xcf, 0x26, + 00, 0xe, 0xab, 0xbd, 0xe1, 0xa5, 0xeb, 0x44, 0x5c, 0xdd, + 0x6a, 0xbf, 0xec, 0xed, 0x4c, 0xfb, 0xf1, 0xb6, 0xa6, 0x5c, + 0xce, 0x2a, 0xec, 0xc8, 0x3b, 0x97, 0xc, 0x69, 0x74, 0x60, + 0x9d, 0xa7, 0xf5, 0xe5, 0x90, 0x9b, 0x40, 0x8a, 0xc3, 0x63, + 0x32, 0xd, 0x47, 0xb6, 0x35, 0x79, 0xb8, 0x89, 0x19, 0xa9, + 0x45, 0x1b, 0xc6, 0x2b, 0x1b, 0xa5, 0xd3, 0x3d, 0xe1, 0xd8, + 0x62, 0x77, 0xfa, 0x65, 0xfb, 0x65, 0x85, 0x47, 0xe6, 0xa7, + 0xe, 00, 0x84, 0x23, 0xfc, 0xa8, 0xe2, 0x47, 0x7e, 0xcd, + 0x9a, 0xbb, 0x85, 0xb3, 0xaf, 0x4f, 0xdf, 0x56, 0xe3, 0xb1, + 0x95, 0xfc, 0xee, 0xa6, 0xb1, 0x63, 0x70, 0x9e, 0xbb, 0x3d, + 0xa9, 0xf2, 0x4a, 0xef, 0x90, 0x2e, 0xa9, 0x1a, 0xd9, 0xfb, + 0x60, 0x97, 0x57, 0x46, 0xcb, 0xab, 0xd1, 0x4a, 0x26, 0xa6, + 0x75, 0xe5, 0xa7, 0x13, 0x1c, 0x3a, 0x55, 0x53, 0xf, 0x75, + 0x54, 0x33, 0x75, 0xb4, 0xa8, 0xf4, 0x48, 0xe5, 0x7, 0x23, + 0x48, 0x1f, 0x23, 0xb0, 0xec, 0xf3, 0x5c, 0x9e, 0xd1, 0x2e, + 0x6f, 0x75, 0x5e, 0xdd, 0x3a, 0xfb, 0xf5, 0x29, 0x48, 0x85, + 0xe7, 0xf8, 0x2c, 0xa7, 0x5f, 0x7e, 0x6e, 0x3a, 0xdb, 0xf2, + 0xaf, 0x5f, 0xd2, 0xe7, 0xf8, 0x6c, 0x3d, 0x69, 0x61, 0x6b, + 0xfa, 0xf2, 0x7, 0xc1, 0x87, 0xf0, 0x83, 0x71, 0xa4, 0x3d, + 0x37, 0x69, 0x9e, 0xa5, 0xe1, 0x94, 0x4e, 0xbf, 0x7a, 0xce, + 0x4e, 0xfa, 0x10, 0x83, 0xac, 0xaf, 0x61, 0x53, 0x98, 0x60, + 0xeb, 0x23, 0xb6, 0x7e, 0x2d, 0x9a, 0x9d, 0x5e, 0xc7, 0x15, + 0xf5, 0xdc, 0xf0, 0xc2, 0x17, 0x7, 0x7a, 0x9f, 0xb2, 0x3f, + 0x8e, 0xbc, 0xaa, 0x17, 0x6b, 0xeb, 0xfa, 0x16, 0x5f, 0x9f, + 0xb3, 0x7a, 0x58, 0x65, 0xec, 0xa5, 0xbf, 0xa0, 0x2d, 0x4c, + 0xb0, 0xf7, 0x23, 0xe0, 0x5a, 0xc2, 0x8f, 0x2f, 0xc, 0x69, + 0xf4, 0x98, 0x36, 0x1f, 0xe1, 0x56, 0x79, 0x29, 0x71, 0x7e, + 0xb8, 0x4f, 0xfa, 0x7a, 0x61, 0x82, 0xca, 0x8f, 0x58, 0xf6, + 0xe8, 0x5e, 0x35, 0x25, 0xc1, 0xed, 0x8, 0x3f, 0x3b, 0xd3, + 0x14, 0x7b, 0x25, 0x5c, 0xf8, 0xdd, 0x6f, 0x5a, 0x8d, 0xb6, + 0xce, 0xb4, 0x71, 0x79, 0xaf, 0xf2, 0xed, 0xd9, 0xe7, 0xec, + 0x2c, 0x3b, 0x18, 0xb, 0x33, 0x4c, 0xab, 0xba, 0xf4, 0x6a, + 0xdc, 0xd6, 0xdb, 0xb7, 0x3e, 0xa2, 0xfe, 0x69, 0x3e, 0x3, + 0x3f, 0xf7, 0x87, 0x9b, 0xac, 0x77, 0x91, 0xf2, 0xee, 0xf5, + 0xd8, 0xfe, 0x74, 0xf9, 0x67, 0xd5, 0x5c, 0xcc, 0x9f, 0x36, + 0xae, 0xcf, 0xcf, 0x7f, 0x9a, 0x8a, 0x97, 0xd3, 0x87, 0xbc, + 0xd2, 0xbe, 0x75, 0xc9, 0x27, 0x7b, 0xaf, 0xc4, 0xf2, 0x5d, + 0xab, 0xe1, 0x17, 0x56, 0xb7, 0x5d, 0xd4, 0xac, 0xab, 0x6c, + 0xe3, 0xfb, 0xf5, 0x95, 0xf4, 0x12, 0xd1, 0x2b, 0xdb, 0xe5, + 0xf0, 0xe, 0x3c, 0x52, 0xab, 0xdd, 0xfe, 0x77, 0x69, 0x7f, + 0x9, 0xb9, 0xcf, 0x5f, 0x37, 0xbc, 0xc, 0xbf, 0x2b, 0xa4, + 0x17, 0xf3, 0xb, 0xa7, 0xa2, 0xe9, 0x65, 0xff, 0xf9, 0x4f, + 0x53, 0x72, 0x76, 0x39, 0xea, 0xaa, 0xdb, 0xba, 0xd1, 0x6e, + 0x8e, 0x99, 0xca, 0x2f, 0x5e, 0xb8, 0xed, 0x62, 0x6b, 0xe, + 0xab, 0x6a, 0x60, 0xb5, 0x2d, 0xb6, 0xb6, 0xce, 0x94, 0x94, + 0x3e, 0x43, 0x6e, 0x97, 0xc6, 0x95, 0x57, 0xfb, 0xd6, 0x99, + 0x25, 0x3c, 0xc9, 0xdd, 0x9e, 0xd3, 0x74, 0xf4, 0xe9, 0xcc, + 0x61, 0x3b, 0xd9, 0x96, 0x95, 0xdc, 0x32, 0xbd, 0xb6, 0x3a, + 0xac, 0x6a, 0x66, 0x95, 0x92, 0x5b, 0x5d, 0x2b, 0x6c, 0x3e, + 0x9b, 0x95, 0x16, 0xb8, 0xe1, 0xe5, 0x3f, 0x27, 0xc3, 0xcc, + 0x95, 0xf6, 0xdf, 0x7f, 0xcd, 0xff, 0x3e, 0xd3, 0xfb, 0x77, + 0xe0, 0x95, 0xf2, 0xac, 0xc2, 0x6e, 0x97, 0xe7, 0x15, 0xee, + 0x6d, 0x81, 0x46, 0x84, 0x8, 0xbf, 0x9a, 0x8b, 0xf9, 0xcb, + 0x4b, 0x53, 0xd9, 0x29, 0x97, 0x73, 0x4b, 0xcb, 0x9d, 0x20, + 0x57, 0xda, 0x57, 0xdf, 0x7d, 0x3a, 0x71, 0x16, 0x9f, 0xce, + 0x6a, 0x29, 0xdb, 0xe7, 0x39, 0x6f, 0x8e, 0xec, 0x2b, 0xf3, + 0x6c, 0x97, 0xff, 0x8, 0xb2, 0x5d, 0x80, 0xbd, 0x36, 0xef, + 0x53, 0xc8, 0x4c, 0xda, 0xf3, 0xd, 0x2f, 0x57, 0x69, 0x76, + 0xc1, 0x1e, 0x70, 0xe1, 0x77, 0x1f, 0x7e, 0x35, 0xba, 0xe1, + 0xa5, 0xb, 0xd6, 0x76, 0x64, 0xae, 0xf9, 0xf1, 0x3e, 0x77, + 0x40, 0xf0, 0x3c, 0xc9, 0x17, 0x9c, 0xf0, 0xdb, 0x21, 0xf2, + 0x45, 0xa3, 0xb, 0xbf, 0xbb, 0xa8, 0x3, 0x5e, 0xf7, 0x5f, + 0xf8, 0x39, 0xf, 0xfa, 0x2a, 0xf2, 0xfa, 0xb9, 0xf0, 0xbb, + 0x47, 0x5e, 0x8d, 0x40, 0x23, 0x42, 0xdc, 0xf0, 0x2, 0xbd, + 0x88, 0xfc, 0x13, 0x1a, 0x78, 0x92, 0xf0, 0x3, 0xc2, 0xd1, + 0xd1, 0x85, 0xf0, 0xfb, 0x22, 0xfb, 0x6b, 0x7, 00, 0xba, + 0xb6, 0x23, 0xfc, 0x82, 0x74, 0xc8, 0xa4, 0x8f, 0x29, 0x99, + 0x62, 0xdf, 0xea, 0x52, 0x60, 0xb5, 0xd0, 0x23, 0x65, 0x1f, + 0x93, 0xbb, 0x3d, 0x67, 0xf3, 0xf1, 0xb0, 0x3a, 0x2a, 0x1c, + 0x24, 00, 0xe3, 0x89, 0xd2, 0xed, 0x59, 0xae, 0x51, 0x54, + 0x30, 0x27, 0x59, 0x81, 0xf4, 0xc2, 0xbe, 0xca, 0x47, 0xa0, + 0xca, 0x2f, 0x7d, 0xa4, 0xd9, 0xd6, 0x34, 0xe9, 0xe8, 0x62, + 0xaf, 0xf, 0x91, 0xf3, 0xa2, 0xe5, 0x83, 0xdf, 0xbe, 0xae, + 0xba, 0x29, 0x59, 0x27, 0xd1, 0x56, 0x17, 0xed, 0xb3, 0x1f, + 0x32, 0x85, 0xa, 0xbf, 0xad, 0x1, 0x33, 0xa7, 0x64, 0x98, + 0x82, 0xe5, 0x8b, 0xf5, 0xe3, 0x1d, 0x8e, 0x6d, 0xf9, 0xe0, + 0x53, 0x23, 0x3d, 0xd1, 0x29, 0x3b, 0x24, 0xb3, 0x3f, 0xe1, + 0x17, 0x73, 0x9f, 0x8, 0xf8, 0x95, 0xef, 0x16, 0xe4, 0xae, + 0x28, 0xa0, 0x77, 0x51, 0xae, 0xf9, 0x15, 0xec, 0x6d, 0xac, + 0xdd, 0x2, 0xba, 0xeb, 0x8b, 0x5b, 0x5d, 0x34, 0x22, 0xe6, + 0x29, 0x3e, 0x5b, 0xf6, 0x85, 0xdf, 0x30, 0xe7, 0xf5, 0x5b, + 0x7d, 0x74, 0xe9, 0x94, 0x86, 0xc8, 0x99, 0xb6, 0x7, 0x81, + 0x9a, 0x92, 0xe1, 0x9f, 0x7e, 0x42, 0x8e, 0xf4, 0x44, 0xfb, + 0xec, 0x81, 0xac, 0x44, 0xb9, 0xe6, 0x97, 0x8e, 0x3f, 0xb7, + 0xf5, 0x93, 0x86, 0xe5, 0xeb, 0xd9, 0x7f, 0x47, 0x3b, 0x84, + 0xd2, 0xef, 0x5b, 0x18, 0x81, 0x2f, 0xfd, 0x6f, 0xb4, 0xd5, + 0x5, 0x74, 0x41, 0xb7, 0x27, 0x30, 0x38, 0x65, 0x1f, 0x29, + 0xe1, 0xc7, 0x59, 0x63, 0xf4, 0x84, 0x33, 0x2a, 0xc9, 0x47, + 0x96, 0xf0, 0xe3, 0xac, 0xdf, 0xdf, 0x5f, 0x8d, 0xcb, 0x85, + 0x86, 0xb9, 0xb2, 0xde, 0x2, 0xc9, 0xc7, 0x16, 0xe1, 0x7, + 0x8c, 0x49, 0xf2, 0x51, 0xb0, 0x3b, 0xfc, 0x9c, 0x96, 0x2, + 0xed, 0x93, 0x7c, 0x94, 0xa9, 0xfc, 0xbe, 0x30, 0xa4, 0x11, + 0x74, 0x47, 0xf2, 0xf1, 0x55, 0xdc, 0xf0, 0xab, 0x89, 0x34, + 0x3f, 0xd0, 0x86, 0xee, 0x48, 0x3e, 0x6a, 0x44, 0xf9, 0x9d, + 0xdf, 0x61, 0x8e, 0x22, 0x4d, 0x9, 0x1d, 0xb1, 0xbb, 0x52, + 0x29, 0x4a, 0xe5, 0xa7, 0x74, 0x3b, 0xa6, 0xb0, 0xde, 0xac, + 0x52, 0x5a, 0x23, 0xf9, 0xa8, 0xf7, 0xcf, 0xb4, 0x7f, 0x8f, + 0xc9, 0xe, 0x77, 0xd0, 0xbe, 0x74, 0xcc, 0x9d, 0xf4, 0x91, + 0x5d, 0xe9, 0xf0, 0xe, 0x86, 0x34, 0x9a, 0x65, 0xc7, 0x70, + 0x58, 0xfe, 0xb7, 0x30, 0x25, 0xdc, 0xad, 0xc7, 0x46, 0x89, + 0x17, 0x5, 0xea, 0xf6, 0x4c, 0x9f, 0x33, 0x99, 0x7d, 0xf2, + 0xe4, 0x2a, 0xff, 0x82, 0xf, 0x69, 0x94, 0x1d, 0xc9, 0x68, + 0xf9, 0xd7, 0xc9, 0x30, 0x46, 0xbc, 0x2d, 0x3d, 0x43, 0x85, + 0xaf, 0xa2, 0x74, 0x7b, 0xce, 0x2a, 0x9f, 0x54, 0x49, 0x3d, + 0x2b, 0x90, 0x17, 0x7d, 0x4e, 0xb6, 0xec, 0x84, 0xec, 0x15, + 0x2e, 0xfc, 0x52, 0x86, 0x34, 0xaa, 0x54, 0xff, 0xc5, 0xc3, + 0xae, 0x22, 0x9e, 0x64, 0xb4, 0x10, 0xce, 0x38, 0xd8, 0xed, + 0xd9, 0xe3, 0x65, 0xbf, 0xaf, 0xd7, 0xfc, 0xa6, 0x5c, 0x63, + 0xbd, 0x1c, 0xa3, 0xe7, 0x73, 0x82, 0x39, 0xff, 0xf2, 0xaf, + 0xaf, 0xaf, 0x7f, 0xc6, 0x7c, 0x35, 0x74, 0xf5, 0xc5, 0xb3, + 0x17, 0x4d, 0x63, 0xae, 0x22, 0x1e, 0xd6, 0x5d, 0xfb, 0x43, + 0x6b, 0xc2, 0x5d, 0xf3, 0xdb, 0xfa, 0xef, 0xd7, 0x57, 0xc2, + 0x8e, 0xd1, 0x53, 0xf8, 0xe2, 0x86, 0x31, 0xe2, 0x15, 0x92, + 0x8f, 0xf3, 0x2, 0x85, 0x1f, 0xd0, 0x3b, 0x3d, 0xa, 0x5c, + 0x25, 0x44, 0xf8, 0xb9, 0xf2, 0x74, 0x39, 0xab, 0x94, 0x87, + 0x89, 0x3d, 0xae, 0x75, 0x3c, 0xfc, 0x3a, 0xba, 0xec, 0xd7, + 0xc5, 0x42, 0xf6, 0xc5, 0x2a, 0xbd, 0x55, 0x47, 0x7, 0xd7, + 0x33, 0xac, 0xd, 0x2e, 0x17, 0xa2, 0xf2, 0x3, 0x3a, 0xa5, + 0xe0, 0xe3, 0x26, 0xc2, 0xf, 0x68, 0x91, 0xd8, 0xe3, 0x56, + 0xa7, 0x7e, 0xe7, 0x67, 0x6c, 0x3f, 0xe0, 0xe, 0x7e, 0xba, + 0xce, 0xdd, 0xfc, 0xc8, 0x9d, 0x1b, 0x39, 0x37, 0x62, 0x2f, + 0x3f, 0x5d, 0xe7, 0x19, 0x11, 0xc3, 0xcf, 0x48, 0x5, 0xbb, + 0x9c, 0x59, 0x27, 0xe7, 0x9b, 0x30, 0x5b, 0x24, 0x8e, 0x39, + 0xf6, 0x24, 0x1f, 0xf, 0x8, 0x17, 0x7e, 0x92, 0x6f, 0x97, + 0xb, 0x57, 0x57, 0xf6, 0xe9, 0x39, 0x87, 0x3f, 0x9d, 0x91, + 0x88, 0x3d, 0x9e, 0x77, 0xf6, 0x86, 0x97, 0x2e, 0xee, 0xc9, + 0xae, 0x69, 0xc1, 0x2b, 0x7, 0x2d, 0x8a, 0x3c, 0x58, 0x4f, + 0xfd, 0x90, 0x46, 0xcb, 0xe9, 0xb3, 0x2b, 0xb6, 0x72, 0x54, + 0xa9, 0xca, 0xc5, 0xa0, 0x5f, 0xee, 0x6a, 0xe1, 0x2d, 0x81, + 0xee, 0xf6, 0xcc, 0x3e, 0xc0, 0x73, 0xd9, 0x88, 0xaf, 0xee, + 0xdf, 0x49, 0xf, 0xc8, 0xf6, 0x63, 0xfe, 0x72, 0x7, 0x86, + 0x34, 0x4a, 0xdf, 0x9b, 0x4e, 0x5f, 0x9e, 0x43, 0x3a, 0xaa, + 0xe2, 0x2c, 0xe0, 0x26, 0x18, 0x95, 0xd8, 0xe3, 0x5d, 0x21, + 0xba, 0x3d, 0x97, 0x2d, 0xec, 0xea, 0x4f, 0xd9, 0xa2, 0xb0, + 0x30, 0x3d, 0xa9, 0xf3, 0xed, 0x97, 0x16, 0x30, 0x14, 0x9d, + 0x9c, 0xb4, 0xe0, 0x82, 0xf0, 0x6b, 0xff, 0x7, 0xf, 0x5b, + 0x47, 0xda, 0xd6, 0x62, 0x17, 0x8e, 0xcc, 0xc8, 0x83, 0xf5, + 0x34, 0xf2, 0xdd, 0x1b, 0x59, 0xc, 0xe, 0x10, 0x7b, 0xb4, + 0x23, 0x4a, 0xb7, 0x67, 0xb6, 0xf7, 0x6c, 0x39, 0xf8, 0xce, + 0x72, 0xe8, 0xa2, 0x9a, 0xe9, 0x43, 0x1d, 0xbd, 0x95, 0x43, + 0x1a, 0x1d, 0x9b, 0xf3, 0x6a, 0xe, 0xd9, 0xea, 0x7c, 0xbe, + 0xb4, 0x1c, 0x76, 0x13, 0xf4, 0xce, 0x26, 0xa3, 0x35, 0xff, + 0x35, 0x2b, 0x67, 0x67, 0x74, 0xe9, 0xc5, 0x18, 0x97, 0x76, + 0xda, 0x77, 0x7e, 0x1b, 0xd, 0xbc, 0x95, 0xad, 0x9c, 0x99, + 0xd8, 0xa3, 0x4d, 0x51, 0x2a, 0x3f, 0xee, 0x96, 0x56, 0x6c, + 0xda, 0xbb, 0xe0, 0xc4, 0x1e, 0x2d, 0xfb, 0x67, 0x98, 0x13, + 0x4c, 0x9e, 0x74, 0x3e, 0xea, 0x5c, 0xb1, 0x1b, 0x98, 0xd8, + 0xa3, 0x7d, 0x97, 0x55, 0x7e, 0x5d, 0xfc, 0xe0, 0x8f, 0xab, + 0xb8, 0xc3, 0x93, 0x2c, 0xb1, 0x47, 0x2f, 0x74, 0x7b, 0x42, + 0x8b, 0xba, 0x3b, 0x9b, 0x14, 0x7b, 0xf4, 0x45, 0xf8, 0x1, + 0xc7, 0x9d, 0xbf, 0xe3, 0x17, 0x5e, 0x71, 0x65, 0xf8, 0x75, + 0x77, 0xae, 0xa, 0x1c, 0xa6, 0xd4, 0xa3, 0x6b, 0x2a, 0x3f, + 0x60, 0x1f, 0xb1, 0xc7, 00, 0x2e, 0x7e, 0xbc, 0x59, 0xfb, + 0x4f, 0x7b, 0x61, 0xaf, 0xbb, 0x37, 0xe8, 0xf9, 0xd1, 0x21, + 0x78, 0x8c, 0x47, 0xb4, 0x30, 0xc, 0x95, 0x1f, 0x25, 0xe5, + 0x1, 0x31, 0x2e, 0x1f, 0xae, 0xef, 0xeb, 0x3c, 0x25, 0xdf, + 0x2b, 0x5c, 0xd8, 0x63, 0x3c, 0xd7, 0x87, 0x5f, 0x83, 0x57, + 0xfe, 0x56, 0xc3, 0x8, 0x2c, 0x47, 0xc, 0x28, 0x8f, 0xe4, + 0x60, 0xf4, 0x9c, 0xa5, 0xbd, 0x43, 0x1a, 0x6d, 0xbd, 0xa5, + 0x3c, 0x68, 0x91, 0x41, 0x8e, 0x9a, 0xa2, 0x87, 0x93, 0x51, + 0x5, 0xaa, 0xfc, 0xca, 0x7, 0xb0, 0x1, 0x8c, 0xb2, 0xce, + 0xc, 0x69, 0xb4, 0x7c, 0xb1, 0x7e, 0xd0, 0x22, 0x83, 0x1c, + 0x35, 0x42, 0xec, 0x31, 0xb6, 0x88, 0x43, 0x1a, 0xad, 0x8e, + 0x67, 0x3, 0x18, 0x9d, 0x54, 0xd3, 0x3e, 0xee, 0x6d, 0x43, + 0xb5, 0xb9, 0x6f, 0xf9, 0xf9, 0x97, 0xb, 0x7b, 0x8c, 0xed, + 0x96, 0xf0, 0x6b, 0xed, 0xb6, 0x97, 0xec, 0x91, 0xbc, 0x1c, + 0xc6, 0xc1, 00, 0x46, 0x35, 0xe, 0xac, 0x8d, 0x67, 0x56, + 0xa0, 0xcd, 0x74, 0x89, 0x65, 0xe6, 0x89, 0x3d, 0x86, 0x17, + 0xa5, 0xdb, 0x33, 0xed, 0x5b, 0x5b, 0xbe, 0x62, 00, 0xa3, + 0xb2, 0x63, 0x43, 0x1a, 0x2d, 0xdf, 0x92, 0x7d, 0xd7, 0x6a, + 0xfe, 0x5b, 0xf3, 0xdc, 0x9a, 0xde, 0x66, 0xba, 0x84, 0x9b, + 0x59, 0x88, 0xe9, 0xc6, 0x26, 0xe3, 0xcc, 0xc5, 0x98, 0xbb, + 0x2f, 0xe4, 0xb8, 0x50, 0x74, 0xde, 0x1d, 0xeb, 0x70, 0x98, + 0xed, 0x72, 0xd5, 0xad, 0xb0, 0x77, 0x1f, 0x5, 0x93, 0xcc, + 0x23, 0xaa, 0x28, 0x95, 0xdf, 0x6c, 0x98, 0xe6, 0xb5, 0x35, + 0x69, 0x7d, 0x66, 0x3d, 0x37, 0x4b, 0xec, 0xc1, 0x8d, 0xe1, + 0xd7, 0xe0, 0x6f, 0x1e, 0x3e, 0xda, 0x5c, 0xaa, 0xbe, 0xdc, + 0x11, 0x75, 0xae, 0xd8, 0xad, 0x5c, 0x7e, 0x4, 0xe9, 0xe1, + 0x84, 0xd9, 0xbd, 0x95, 0x5f, 0x83, 0xf9, 0xd7, 0xd4, 0xc2, + 0xf4, 0xeb, 0x8e, 0xd5, 0x68, 0xd3, 0xdc, 0x47, 0xa9, 0x7, + 0x2b, 0xe1, 0xba, 0x3d, 0x21, 0xe, 0xa5, 0x1e, 0x6c, 0xb9, + 0x3d, 0xfc, 0x1a, 0x2c, 0xfe, 0x60, 0x78, 0x4a, 0x3d, 0x28, + 0x53, 0xf9, 0xc1, 0x38, 0x94, 0x7a, 0x50, 0xe9, 0x89, 0xf0, + 0x53, 0xfc, 0xc1, 0xdd, 0x94, 0x7a, 0xb0, 0x8b, 0xca, 0xf, + 0x3a, 0xa6, 0xd4, 0x83, 0x63, 0x1e, 0xa, 0x3f, 0xc5, 0x1f, + 0x5c, 0x4b, 0xa9, 0x7, 0x67, 0x3c, 0x57, 0xf9, 0xc9, 0x3f, + 0x38, 0x4f, 0xa9, 0x7, 0x97, 0xd0, 0xed, 0x9, 0x7d, 0x50, + 0xea, 0xc1, 0x85, 0x1e, 0xd, 0x3f, 0xc5, 0x1f, 0xec, 0xa5, + 0xd4, 0x83, 0x3b, 0x3c, 0x3d, 0x9e, 0x5f, 0x6b, 0xa3, 0x1d, + 0x41, 0xb3, 0x96, 0xb1, 0x27, 0xf9, 0xe0, 0x5a, 0xba, 0x3d, + 0xa1, 0x2d, 0xab, 0x52, 0xcf, 0xc9, 0x22, 0xdc, 0xe1, 0x85, + 0xf0, 0xd3, 0xf9, 0x9, 0x59, 0xae, 0xea, 0xc1, 0x63, 0xde, + 0xa9, 0xfc, 0xe4, 0x1f, 0xcc, 0x5c, 0xd5, 0x83, 0xe7, 0xbd, + 0xd6, 0xed, 0x29, 0xff, 0x8, 0x4e, 0xe6, 0xc1, 0x8b, 0x5c, + 0xf3, 0x83, 0xa7, 0xe9, 0xde, 0x84, 0xd7, 0xbd, 0x19, 0x7e, + 0xe5, 0xe2, 0xcf, 0x75, 0x7e, 0x6, 0xa3, 0xd4, 0x83, 0x76, + 0xbc, 0x5c, 0xf9, 0x6d, 0xe5, 0x9f, 0xd6, 0x81, 0x91, 0x28, + 0xf5, 0xa0, 0x35, 0xef, 0x77, 0x7b, 0xba, 0xf8, 0xc7, 0xa8, + 0x94, 0x7a, 0xd0, 0xac, 0xf7, 0xc3, 0x6f, 0x92, 0x7f, 0x8c, + 0x45, 0xe6, 0x41, 0xfb, 0x9a, 0x8, 0xbf, 0x49, 0xfe, 0xd1, + 0x3f, 0x99, 0x7, 0x1d, 0x69, 0x25, 0xfc, 0xa0, 0x5f, 0xb7, + 0x5e, 0xd2, 0x73, 0x5e, 0x8, 0x77, 0xf8, 0xa7, 0x9d, 0x43, + 0xab, 0x9d, 0x25, 0x81, 0x1a, 0x4a, 0x3d, 0xe8, 0x57, 0x5b, + 0x95, 0x9f, 0x46, 0x84, 0xf6, 0xc9, 0x3c, 0x18, 0x40, 0x5b, + 0xe1, 0xf7, 0xa1, 0xfe, 0xa3, 0x41, 0x32, 0xf, 0x46, 0xd2, + 0x62, 0xf8, 0xcd, 0xc3, 0x1e, 0x69, 0x65, 0x78, 0x9d, 0xcc, + 0x83, 0x21, 0xb5, 0x18, 0x7e, 0xd3, 0x62, 0x30, 0x17, 0x2d, + 0xe, 0x6f, 0x71, 0x6, 0x6, 0x3, 0x6b, 0x34, 0xfc, 0x3e, + 0xdc, 0x2, 0xc3, 0xf3, 0x94, 0x7a, 0x10, 0x41, 0xd3, 0xe1, + 0x37, 0xc9, 0x3f, 0x9e, 0x22, 0xf3, 0x20, 0x94, 0xd6, 0xc3, + 0x6f, 0x92, 0x7f, 0xdc, 0x49, 0xe6, 0x41, 0x4c, 0x1d, 0x84, + 0xdf, 0xe4, 0x16, 0x18, 0xae, 0xd6, 0x57, 0xe6, 0x39, 0xff, + 0x83, 0xcb, 0xf5, 0x11, 0x7e, 0x93, 0x5b, 0x60, 0xb8, 0x42, + 0x5f, 0x99, 0x7, 0xdc, 0xa7, 0x9b, 0xf0, 0xfb, 0x50, 0x2, + 0xb2, 0xd7, 0x72, 0x60, 0x48, 0xbb, 0xd, 0xf0, 0xd1, 0x59, + 0xf8, 0x4d, 0x4a, 0x40, 0xea, 0x28, 0xf2, 0x80, 0x82, 0xfe, + 0xc2, 0xef, 0x43, 0x9, 0x48, 0x96, 0xcc, 0x3, 0x6a, 0xf4, + 0x1a, 0x7e, 0x93, 0x12, 0x90, 0x5, 0x99, 0x7, 0xec, 0xd2, + 0x71, 0xf8, 0x7d, 0x28, 0x1, 0x23, 0x93, 0x79, 0xc0, 0x31, + 0xdd, 0x87, 0xdf, 0xb4, 0x28, 0x1, 0x27, 0x8d, 0x60, 00, + 0x31, 0x6f, 0x60, 0xf1, 0x6b, 0x7, 0xb8, 0xd6, 0x8, 0xe1, + 0xf7, 0x21, 0x2, 0xc7, 0xa6, 0xc8, 0x3, 0x2e, 0x34, 0x4e, + 0xf8, 0x7d, 0x88, 0xc0, 0x91, 0xc4, 0x2c, 0xf2, 0x80, 0x7, + 0x8c, 0x16, 0x7e, 0x1f, 0x22, 0xb0, 0x6b, 0x8a, 0x3c, 0xe0, + 0x6e, 0x63, 0x86, 0xdf, 0x87, 0x8, 0xec, 0x88, 0x22, 0xf, + 0x78, 0xd2, 0xc8, 0xe1, 0xf7, 0xb1, 0x8c, 0xc0, 0x49, 0xc3, + 0xda, 0x12, 0x81, 0x7, 0xbc, 0x65, 0xfc, 0xf0, 0xfb, 0x98, + 0xdb, 0x56, 0x85, 0xe0, 0xbb, 0x96, 0x81, 0x37, 0xd9, 0x10, + 0xc0, 0x4b, 0xa2, 0x84, 0xdf, 0x4c, 0x21, 0xf8, 0x3c, 0x15, + 0x1e, 0xd0, 0x9a, 0x70, 0xe1, 0xf7, 0xb1, 0x2a, 0x4, 0x27, + 0x8d, 0xf2, 0xd5, 0x4, 0xde, 0xe5, 0xfc, 0xd4, 0xf, 0x2e, + 0x14, 0x34, 0xfc, 0x66, 0x69, 0xa, 0x4e, 0x1a, 0xeb, 0xa3, + 0xac, 0x43, 0xa0, 0x17, 0xd1, 0xc3, 0x6f, 0xb6, 0x4c, 0x41, + 0xe5, 0x60, 0x25, 0x17, 0xf0, 0x80, 0x4e, 0x9, 0xbf, 0xb5, + 0x65, 0xb, 0xae, 0x94, 0x59, 0x91, 0x76, 0xc0, 0x18, 0x84, + 0x5f, 0xc9, 0x56, 0x10, 0xa6, 0x7f, 0x1d, 0x52, 0xc0, 0xaf, + 0xc, 0x4, 0x21, 0xfc, 0x6a, 0xad, 0xda, 0xfd, 0x65, 0xef, + 0x68, 0x76, 0x82, 0xee, 0xa4, 0x51, 0x37, 0xf5, 0xff, 0xa5, + 00, 0xb2, 0x84, 0xdf, 0x41, 0x69, 0x2a, 0xf4, 0x12, 0x1e, + 0xd9, 0xe5, 0x9c, 0x9a, 0x5c, 0x54, 0x56, 0xdc, 0xf0, 0x9, + 0x57, 0x11, 0x7e, 0x97, 0xc9, 0x36, 0x49, 0x5b, 0x49, 0x53, + 0x7e, 0xd7, 0x19, 0xcf, 0x7f, 0x22, 0x40, 0x77, 0x84, 0xdf, + 0xbd, 0xbe, 0x26, 0xcd, 0xd7, 0xac, 0xba, 0xfc, 0x13, 0x1, + 0xf8, 0x67, 0xd2, 0x97, 0xf2, 0x2a, 0xab, 0x1d, 0xe0, 0x79, + 0xff, 0x7b, 0x7b, 0x1, 00, 0xe0, 0x69, 0xc2, 0xf, 0x80, + 0x70, 0x84, 0x1f, 0xf4, 0xe4, 0x73, 0x91, 0xe2, 0xed, 0xa5, + 0x80, 0xee, 0x9, 0x3f, 00, 0xc2, 0x11, 0x7e, 00, 0x84, + 0x23, 0xfc, 00, 0x8, 0x47, 0xf8, 0x1, 0x10, 0x8e, 0xf0, + 0x83, 0xce, 0xb8, 0xe7, 0x5, 0xce, 0x13, 0x7e, 00, 0x84, + 0x23, 0xfc, 00, 0x8, 0x47, 0xf8, 0x1, 0x10, 0x8e, 0xf0, + 0x3, 0x20, 0x1c, 0xe1, 0x7, 0xfd, 0x71, 0xcf, 0xb, 0x9c, + 0x24, 0xfc, 00, 0x8, 0x47, 0xf8, 0x1, 0x10, 0x8e, 0xf0, + 0x3, 0x20, 0x1c, 0xe1, 0x7, 0x5d, 0x72, 0xd9, 0xf, 0xce, + 0x10, 0x7e, 00, 0x84, 0x23, 0xfc, 00, 0x8, 0x47, 0xf8, + 0x1, 0x10, 0xce, 0x9f, 0xf0, 0x73, 0xfd, 00, 0xba, 0xe3, + 0xb0, 0x85, 0xc3, 0x54, 0x7e, 00, 0x84, 0x23, 0xfc, 00, + 0x8, 0x47, 0xf8, 0x1, 0x10, 0x8e, 0xf0, 0x83, 0x8e, 0xb9, + 0xec, 0x7, 0xc7, 0x8, 0x3f, 00, 0xc2, 0x11, 0x7e, 00, + 0x84, 0x23, 0xfc, 00, 0x8, 0x47, 0xf8, 0x41, 0xdf, 0x5c, + 0xf6, 0x83, 0x3, 0x84, 0x1f, 00, 0xe1, 0x8, 0x3f, 00, + 0xc2, 0x11, 0x7e, 0xd0, 0x3d, 0x3d, 0x9f, 0xb0, 0x97, 0xf0, + 0x3, 0x20, 0x1c, 0xe1, 0x7, 0x40, 0x38, 0xc2, 0xf, 0x46, + 0xa0, 0xe7, 0x13, 0x76, 0x11, 0x7e, 00, 0x84, 0x23, 0xfc, + 00, 0x8, 0xe7, 0xbf, 0xf0, 0xd3, 0x6d, 0x2, 0x5d, 0x73, + 0x8, 0x43, 0x3d, 0x95, 0x1f, 00, 0xe1, 0x8, 0x3f, 00, + 0xc2, 0x11, 0x7e, 0x30, 0xe, 0x3d, 0x9f, 0x50, 0x49, 0xf8, + 0x1, 0x10, 0x8e, 0xf0, 0x83, 0xa1, 0x28, 0xfe, 0xa0, 0x86, + 0xf0, 0x3, 0x20, 0x1c, 0xe1, 0x7, 0x40, 0x38, 0xc2, 0xf, + 0x46, 0xa3, 0xe7, 0x13, 0xbe, 0x12, 0x7e, 00, 0x84, 0x23, + 0xfc, 0x60, 0x40, 0x8a, 0x3f, 0x28, 0x13, 0x7e, 00, 0x84, + 0x23, 0xfc, 0x60, 0x4c, 0x8a, 0x3f, 0x28, 0x10, 0x7e, 00, + 0x84, 0x23, 0xfc, 0x60, 0x58, 0x8a, 0x3f, 0xd8, 0x22, 0xfc, + 00, 0x8, 0x47, 0xf8, 0xc1, 0xc8, 0x14, 0x7f, 0x90, 0xf5, + 0x57, 0xf8, 0x39, 0x4e, 00, 0x88, 0x40, 0xe5, 0x7, 0x83, + 0x73, 0x52, 0xb, 0x29, 0xe1, 0x7, 0x40, 0x38, 0xc2, 0xf, + 0xc6, 0xa7, 0xf8, 0x83, 0x15, 0xe1, 0x7, 0x40, 0x38, 0xc2, + 0xf, 0x42, 0x50, 0xfc, 0xc1, 0x92, 0xf0, 0x83, 0x28, 0xe4, + 0x1f, 0xcc, 0x84, 0x1f, 00, 0xe1, 0x8, 0x3f, 0x8, 0x44, + 0xf1, 0x7, 0x1f, 0xc2, 0xf, 0x62, 0x91, 0x7f, 0x30, 0x9, + 0x3f, 00, 0x2, 0x12, 0x7e, 0x10, 0x8e, 0xe2, 0xf, 0x84, + 0x1f, 0x44, 0x24, 0xff, 0x8, 0x4e, 0xf8, 0x1, 0x10, 0xce, + 0x3a, 0xfc, 0x9c, 0xf, 0x42, 0x10, 0xe, 0x76, 0x22, 0x53, + 0xf9, 0x41, 0x5c, 0xf2, 0x8f, 0xb0, 0x84, 0x1f, 0x84, 0x26, + 0xff, 0x88, 0x49, 0xf8, 0x1, 0x10, 0x8e, 0xf0, 0x83, 0xe8, + 0x14, 0x7f, 0x4, 0x24, 0xfc, 00, 0xf9, 0x47, 0x38, 0xc2, + 0xf, 0x98, 0x26, 0xf9, 0x47, 0x30, 0xc2, 0xf, 0xf8, 0x43, + 0xfe, 0x11, 0x87, 0xf0, 0x3, 0xfe, 0x23, 0xff, 0x8, 0x42, + 0xf8, 0x1, 0x7f, 0x91, 0x7f, 0x44, 0x20, 0xfc, 0x80, 0x35, + 0xf9, 0xc7, 0xf0, 0x84, 0x1f, 0x90, 0x21, 0xff, 0x18, 0x9b, + 0xf0, 0x3, 0xf2, 0xe4, 0x1f, 0x3, 0xcb, 0x84, 0x9f, 0x3d, + 0x1e, 0xf8, 0xd0, 0x1a, 0x30, 0x2a, 0x95, 0x1f, 0x50, 0x22, + 0xff, 0x18, 0x92, 0xf0, 0x3, 0xbe, 0x90, 0x7f, 0x8c, 0x47, + 0xf8, 0x1, 0xdf, 0xc9, 0x3f, 0x6, 0x23, 0xfc, 0x80, 0x2a, + 0xf2, 0x8f, 0x91, 0x8, 0x3f, 0xa0, 0x96, 0xfc, 0x63, 0x18, + 0xc2, 0xf, 0xd8, 0x41, 0xfe, 0x31, 0x6, 0xe1, 0x7, 0xec, + 0x23, 0xff, 0x18, 0x80, 0xf0, 0x3, 0x76, 0x93, 0x7f, 0xf4, + 0x4e, 0xf8, 0x1, 0x47, 0x7c, 0xf2, 0x4f, 0x4, 0xd2, 0x29, + 0xe1, 0x7, 0x1c, 0xf4, 0xfb, 0xfb, 0xab, 0x4, 0xa4, 0x53, + 0xc2, 0xf, 0x38, 0x45, 0xfe, 0xd1, 0x23, 0xe1, 0x7, 0x9c, + 0x25, 0xff, 0xe8, 0xce, 0xcf, 0xef, 0xef, 0x6f, 0xfe, 0xf, + 0x3f, 0x9b, 0x7f, 0x2, 0x48, 0x7d, 0xf2, 0x4f, 0xbb, 0x41, + 0x17, 0x54, 0x7e, 0xc0, 0x35, 0x5c, 0x2, 0xa4, 0x23, 0xc2, + 0xf, 0xb8, 0x92, 0xfc, 0xa3, 0xb, 0xc2, 0xf, 0xb8, 0x98, + 0x5f, 0x41, 0xd0, 0x3e, 0xe1, 0x7, 0x5c, 0x4f, 0x17, 0x28, + 0x8d, 0x13, 0x7e, 0xc0, 0x5d, 0x94, 0x80, 0x34, 0x4b, 0xf8, + 0x1, 0x37, 0x52, 0x2, 0xd2, 0x26, 0xe1, 0x7, 0xdc, 0x4e, + 0x9, 0x48, 0x6b, 0x84, 0x1f, 0xf0, 0x4, 0x25, 0x20, 0x4d, + 0x11, 0x7e, 0xc0, 0x73, 0x94, 0x80, 0x34, 0x42, 0xf8, 0x1, + 0x8f, 0x52, 0x2, 0xd2, 0x2, 0xe1, 0x7, 0xbc, 0x40, 0x9, + 0xc8, 0xbb, 0xfe, 0x79, 0x7b, 0x1, 0x80, 0xa0, 0x3e, 0x4f, + 0x1, 0xf5, 0x44, 0x50, 0x5e, 0x51, 0x7a, 0x7a, 0xb5, 0x67, + 0x5b, 0x3, 0xcf, 0xd0, 0xda, 0xf0, 0x30, 0xdd, 0x9e, 0xc0, + 0xfb, 0xf4, 0x82, 0xf2, 0x30, 0xdd, 0x9e, 0x40, 0x13, 0xf4, + 0x82, 0xf2, 0x24, 0xe1, 0x7, 0x34, 0x44, 0x4, 0xf2, 0x8c, + 0x3e, 0xc2, 0x4f, 0x67, 0x8, 0xcf, 0xd0, 0xda, 0x36, 0x42, + 0x4, 0x72, 0xb7, 0x3e, 0xc2, 0x6f, 0x72, 00, 0x70, 0x3f, + 0xe7, 0x58, 0xad, 0x99, 0x23, 0xd0, 0xe1, 0xcf, 0xe5, 0xdc, + 0xf0, 0x2, 0x34, 0xcd, 0xbd, 0x30, 0xdc, 0xa1, 0x9b, 0xca, + 0xf, 0x8, 0x4b, 0x2f, 0x28, 0x97, 0x13, 0x7e, 0x40, 0x1f, + 0x44, 0x20, 0x17, 0x12, 0x7e, 0x40, 0x4f, 0x44, 0x20, 0x97, + 0x10, 0x7e, 0x40, 0x7f, 0x44, 0x20, 0x27, 0x9, 0x3f, 0xa0, + 0x57, 0x22, 0x90, 0xc3, 0x4a, 0x77, 0x7b, 0x1a, 0x76, 0x4, + 0x68, 0xdf, 0x3c, 0x46, 0x92, 0xf6, 0x8a, 0x7a, 0x2a, 0x3f, + 0x60, 0x4, 0xaa, 0x40, 0x76, 0x11, 0x7e, 0xc0, 0x38, 0x44, + 0x20, 0x95, 0x84, 0x1f, 0x30, 0x9a, 0x65, 0x4, 0x4e, 0x52, + 0x90, 0x9c, 0x28, 0xe1, 0x97, 0x9e, 0x9, 0x7a, 0x66, 0x12, + 0x8c, 0x6d, 0x3e, 0xc0, 0x15, 0x82, 0xa4, 0xa2, 0x84, 0xdf, + 0x6a, 0xbf, 0x77, 0x61, 0x1c, 0xe2, 0xd0, 0x17, 0x4a, 0x2a, + 0x4a, 0xf8, 0xa5, 0x1c, 0x3, 0x10, 0x8a, 0x8, 0x64, 0xa9, + 0xef, 0xf0, 0x5b, 0x15, 0x70, 0xe9, 0x6f, 0x33, 0xb2, 0xbb, + 0xbb, 0xe, 0x4f, 0x8, 0x4b, 0x4, 0xf2, 0xd1, 0x71, 0xf8, + 0x2d, 0x77, 0xdf, 0x55, 0x9e, 0xad, 0x2e, 0x77, 0x3, 0x2c, + 0x89, 0x40, 0x3a, 0xe, 0xbf, 0xe9, 0xd0, 0x5e, 0xab, 0xec, + 0x3, 0x3e, 0x44, 0x60, 0x64, 0xbd, 0x86, 0xdf, 0x32, 0xc3, + 0xb2, 0x5d, 0x9d, 0x2b, 0x6a, 0x41, 0x20, 0x4b, 0x4, 0xc6, + 0xf4, 0x65, 0x30, 0xdb, 0xf6, 0x9f, 0x70, 0xb6, 0xb5, 0xcb, + 0x6e, 0x55, 0x78, 0x76, 0x6e, 0x20, 0xe5, 0x19, 0x69, 0xd1, + 0xf4, 0x5a, 0xf9, 0x4d, 0x8b, 0xd8, 0xfb, 0xec, 0xaf, 0x73, + 0x4e, 0x17, 0xe2, 0xf0, 0xf9, 0x85, 0x4, 0x3a, 0xa2, 0xa, + 0x8c, 0xa3, 0xd7, 0xf0, 0x4b, 0x6f, 0x6f, 0xd9, 0xfa, 0xef, + 0xfc, 0x8a, 0x5d, 0x19, 0xa8, 0x21, 0x2, 0x23, 0xe8, 0x35, + 0xfc, 00, 0x6e, 0x25, 0x2, 0xc7, 0xf6, 0xe5, 0x9a, 0x5f, + 0x77, 0xec, 0xa3, 0xc0, 0x85, 0xe6, 0x6b, 0x81, 0x6f, 0x2f, + 0x8, 0x17, 0x1b, 0x2a, 0xfc, 0x24, 0x1f, 0x70, 0x7, 0xf7, + 0xc2, 0x8c, 0x67, 0xa8, 0xf0, 0x3, 0xb8, 0x89, 0x12, 0x70, + 0x30, 0xc2, 0xf, 0xa0, 0x96, 0x12, 0x70, 0x18, 0xc2, 0xf, + 0x60, 0x7, 0x25, 0xe0, 0x18, 0x84, 0x5f, 0x5e, 0x61, 0xcf, + 0x5e, 0xfe, 0x69, 0xfe, 0xb7, 0x23, 0x1, 0x42, 0x51, 0x2, + 0xf6, 0x4e, 0xf8, 0xe5, 0x55, 0xde, 0x3b, 0xe3, 0x16, 0x1b, + 0x8, 0x4b, 0x9, 0xd8, 0xb5, 0xaa, 0xf0, 0x1b, 0x7e, 0xeb, + 0xe, 0xff, 0x5, 0x81, 0x9b, 0xc8, 0xbf, 0x4e, 0x7d, 0xff, + 0x91, 0xfb, 0x90, 0x9b, 0x76, 0xfe, 0x46, 0xe9, 0xd3, 0xb1, + 0xe7, 0xef, 0xfb, 0xb5, 0xaa, 0x4b, 0x87, 0x9, 0x5c, 0xcd, + 0x73, 0xf5, 0x7a, 0xcd, 0x3c, 0x81, 0xee, 0x7c, 0x1a, 0xd, + 0x47, 0x77, 0x5f, 0x82, 0x76, 0x7b, 0x7e, 0xfa, 0x2b, 0xb2, + 0xaf, 0xd4, 0xef, 0xc4, 0x85, 0x39, 0xcc, 0x2f, 0x7e, 0xe6, + 0x36, 0xbb, 0x60, 0xd1, 0x81, 0xf6, 0xb8, 0x4, 0xd8, 0x9d, + 0xa0, 0xe1, 0xb7, 0xb5, 0x8f, 0x9e, 0xcf, 0x27, 0x9, 0x7, + 0x31, 0xb9, 0x4, 0xd8, 0x97, 0x88, 0xe1, 0x77, 0xeb, 0xde, + 0x99, 0xce, 0xdc, 0x1d, 0xa1, 00, 0xad, 0x89, 0x18, 0x7e, + 0xcb, 0xce, 0xc9, 0x65, 0x32, 0xcd, 0x43, 0x23, 0x1d, 0x9b, + 0xed, 0xdc, 0xe9, 0x91, 0x3e, 0xf, 0xf7, 0xe4, 0x9c, 0x81, + 0x5e, 0x28, 0xfe, 0x7a, 0x51, 0xd5, 0x22, 0xbf, 0xde, 0x70, + 0xdf, 0xbd, 00, 0xaf, 0x7f, 0x41, 0x5a, 0x60, 0x37, 0xe0, + 0x2a, 0xf6, 0xa5, 0xf6, 0x19, 0xd2, 0xa8, 0x24, 0x3d, 0x83, + 0xb3, 0x43, 0x3, 0x5f, 0xb9, 0xff, 0xb3, 0x7d, 0x11, 0xbb, + 0x3d, 0x57, 0xa, 0x7d, 0x14, 0xbf, 0x89, 0x27, 0x17, 0xc, + 0xae, 0x72, 0x6d, 0x47, 0x5c, 0xe1, 0xc2, 0xf6, 0x3, 0x8b, + 0xa1, 0x53, 0x91, 0x4b, 0x8, 0xbf, 0xcc, 0xcf, 0x1e, 0x80, + 0x82, 0xf4, 0xb7, 0xad, 0x5, 0x63, 0x64, 0xd5, 0x81, 0x6f, + 0xe1, 0xe2, 0x5f, 0xe3, 0x84, 0x1f, 0x8c, 0xe0, 0xf9, 0x76, + 0xf6, 0x92, 0xe4, 0x7b, 0x66, 0xb1, 0x8f, 0x95, 0xaa, 0xee, + 0xd3, 0x1e, 0x5b, 0xd5, 0x35, 0x3f, 0xfd, 0xd7, 0x70, 0xad, + 0xd5, 0x73, 0x7f, 0xe6, 0x7b, 0x83, 0x3f, 0x7, 0x5a, 0xcd, + 0x53, 0x81, 0xb2, 0x4f, 0x14, 0x2a, 0xbc, 0x7d, 0xef, 0x13, + 0x88, 0xe6, 0x43, 0x7e, 0xf5, 0x8f, 0xad, 0xe7, 0x1f, 0x6d, + 0xcd, 0xff, 0xf0, 0x62, 0xaf, 0xa6, 0xdc, 0x4a, 0xa0, 0x74, + 0xf9, 0xb3, 0xcb, 0x59, 0x7e, 0xa8, 0x53, 0x79, 0x3d, 0x14, + 0xbe, 0x4e, 0x99, 0x96, 0xb3, 0x65, 0x6e, 0x78, 0x81, 0xd7, + 0x94, 0x9b, 0xc5, 0x9a, 0xbf, 0xae, 0x9a, 0xe6, 0x42, 0x6b, + 0x9b, 0x9d, 0xfe, 0x40, 0xd3, 0xbc, 0x8a, 0xea, 0x9a, 0xe5, + 0xa9, 0x5c, 0xec, 0xc2, 0x2, 0x2f, 0x97, 0x33, 0x9b, 0x46, + 0xe9, 0xb7, 0xd8, 0x5a, 0xbc, 0x79, 0x56, 0xcb, 0x57, 0xa6, + 0xbf, 0x43, 0x71, 0xf9, 0x71, 0xe5, 0xe8, 0xa5, 0x5f, 0xba, + 0x3d, 0xf3, 0xec, 0xeb, 0xdc, 0x6a, 0xab, 0xe5, 0xcd, 0xfe, + 0x35, 0xeb, 0xee, 0x5d, 0x74, 0xf9, 0xbc, 0xae, 0xc7, 0x7e, + 0xa8, 0xba, 0xbc, 0xb3, 0xac, 0xf2, 0xb, 0xd6, 0xac, 0xab, + 0xd5, 0xc4, 0x7b, 0x5f, 0x61, 0x48, 0xc2, 0x2f, 0xcf, 0x1, + 0xc0, 0xad, 0x7e, 0xfe, 0x7d, 0xe8, 0x6b, 0xfa, 0xe2, 0xd6, + 0x5f, 0x57, 0x53, 0x96, 0x67, 0x5e, 0x33, 0x59, 0xe5, 0xc4, + 0xcf, 0x1f, 0xb, 0xd9, 0x24, 0x2b, 0x74, 0x7b, 0x5e, 0x72, + 0xcf, 0x9a, 0x2b, 0x7c, 0xd1, 0x8, 0xbf, 0x69, 0xb2, 0xbb, + 0xf3, 0x86, 0x55, 0x13, 0x9f, 0x6, 0x61, 0xf9, 0x47, 0x38, + 0x53, 0xee, 0x29, 0x45, 0x53, 0xae, 0x7f, 0x6f, 0xeb, 0xd3, + 0x6b, 0x26, 0x5e, 0xf5, 0xfe, 0x6d, 0xcd, 0xa7, 0xac, 0x26, + 0xaa, 0x57, 0x4b, 0x92, 0xed, 0xf3, 0x5c, 0x56, 0xa2, 0xab, + 0x39, 0x54, 0xbe, 0xb2, 0xea, 0x3e, 0x4d, 0x3f, 0x2e, 0xed, + 0x2, 0xdd, 0xf5, 0x4d, 0x77, 0x7d, 0x71, 0xde, 0x55, 0xdb, + 0x95, 0xf1, 0x4c, 0xa7, 0xc7, 0x63, 0x9f, 0x3e, 0xef, 0x94, + 0xd9, 0x6b, 0xdd, 0xd9, 0x9e, 0xa8, 0xd5, 0xc2, 0x64, 0x2f, + 0x51, 0x64, 0xe7, 0xb3, 0x7c, 0x25, 0x5d, 0x80, 0xc2, 0x7, + 0xf1, 0xb0, 0xc1, 0x76, 0x72, 0x66, 0xe9, 0xba, 0x7d, 0x66, + 0x6d, 0xdb, 0xa6, 0x2d, 0xb, 0x7a, 0xc3, 0xcb, 0xd6, 0xfd, + 0x5d, 0xf3, 0x99, 0xe0, 0xd7, 0x53, 0xb6, 0xd5, 0x9d, 0x5, + 0xd9, 0x59, 0x2d, 0xff, 0x9d, 0xbd, 0x8f, 0xe, 0xa6, 0x8a, + 0xfd, 0x21, 0x7b, 0xa6, 0x75, 0xe7, 0x12, 0xc1, 0xf8, 0x82, + 0x86, 0x5f, 0xa1, 0x93, 0xe7, 0x4c, 0x4f, 0xc5, 0xf2, 0x1e, + 0x81, 0x93, 0xb3, 0x22, 0x94, 0x72, 0xfe, 0x89, 0xba, 0x33, + 0xea, 0x2f, 0x1f, 0x5e, 0xfe, 0xb9, 0x36, 0x5c, 0xcb, 0x22, + 0x86, 0xdf, 0x7d, 0xbb, 0xfe, 0xf2, 0xe2, 0xc4, 0xf2, 0xb3, + 0xb2, 0x3f, 0x8a, 0xca, 0x16, 0x85, 0x4, 0x64, 0x7, 0xb8, + 0xd5, 0x2b, 0xf7, 0x73, 0x3a, 0xae, 0xdb, 0x57, 0x7b, 0xc3, + 0xcb, 0x48, 0x75, 0xcc, 0xd6, 0xcd, 0x2, 0x5f, 0xef, 0x11, + 0xd8, 0x7a, 0xd7, 0x6a, 0x82, 0xc2, 0x99, 0xe6, 0xae, 0x5b, + 0x12, 0x80, 0x1e, 0x39, 0xae, 0xbb, 0xb0, 0x63, 0x23, 0xbd, + 0xb8, 0x45, 0xef, 0xfe, 0xe8, 0x5b, 0xe7, 0xbf, 0xba, 0xb9, + 0x86, 0x66, 0x69, 0xb3, 0x38, 0xa9, 0x7c, 0xaf, 0x1c, 0x4d, + 0x89, 0xd8, 0xed, 0x59, 0xef, 0xcc, 0x8d, 0x6, 0x73, 0x4b, + 0x5a, 0x78, 0xe8, 0x6, 0x30, 0x6, 0xb1, 0xd7, 0x1d, 0xe1, + 0x57, 0xba, 0x4, 0x78, 0x66, 0x57, 0xfe, 0x4d, 0x1e, 0x4e, + 0xd8, 0x11, 0x69, 0xd, 0x95, 0xfa, 0x3d, 0xcc, 0x83, 0x13, + 0x7e, 0x37, 0xee, 0xb2, 0x3, 0x1f, 0xc, 0xd2, 0x11, 0x54, + 0x7b, 0x5d, 0x13, 0x7e, 0xec, 0x36, 0xcc, 0xad, 0x4f, 0x70, + 0x80, 0x52, 0x6f, 0xc, 0xc2, 0x6f, 0x7c, 0x85, 0xe7, 0xce, + 0x6c, 0xfd, 0xd8, 0x7f, 0x7e, 0x63, 0xf6, 0x57, 0xfc, 0x5b, + 0x73, 0xae, 0xfc, 0x13, 0xf4, 0x48, 0xe6, 0xd, 0x46, 0xf8, + 0x45, 0x91, 0xfe, 0xac, 0x30, 0x7d, 0x92, 0xe1, 0x52, 0x21, + 0xf9, 0xb2, 0x9, 0xba, 0xf5, 0x5e, 0xe8, 0x9a, 0xcc, 0x1b, + 0xd5, 0x8e, 0xf0, 0x73, 0xd7, 0x62, 0xa7, 0x96, 0xcf, 0x9d, + 0x49, 0x5f, 0x2f, 0xbc, 0x71, 0xb5, 0xb9, 0xb3, 0x3f, 0x16, + 0x2e, 0x27, 0x28, 0xf4, 0x48, 0xbf, 0x45, 0x4, 0x46, 0x75, + 0x18, 0xdf, 0xcf, 0xdf, 0x63, 0xbe, 0xac, 0x7e, 0x71, 0x9f, + 0xfd, 0xc7, 0x54, 0xf7, 0x14, 0xff, 0xd5, 0x9c, 0xb3, 0x93, + 0xb9, 0x40, 0x48, 0x2f, 0xe6, 0x27, 0x5d, 0x4c, 0x7f, 0x8f, + 0x2c, 0xc8, 0x90, 0xf6, 0x55, 0x72, 0x6f, 0x55, 0x7e, 0x4f, + 0xfe, 0xc8, 0x7d, 0xbc, 0xea, 0xb6, 0xfe, 0x9a, 0xdf, 0xd7, + 0xe7, 0x74, 0xa7, 0xff, 0x4d, 0x27, 0xdb, 0x9a, 0x67, 0xfb, + 0xc6, 0xdb, 0xf4, 0xd4, 0xe8, 0x71, 0x5f, 0xe5, 0xbc, 0xa0, + 0xd7, 0xfc, 0xb2, 0x25, 0x4e, 0x21, 0x2, 0xbb, 0xee, 0x6, + 0x59, 0x2d, 0x70, 0xcd, 0xa3, 0xe, 0xbf, 0xbe, 0xb2, 0xb5, + 0x12, 0xe6, 0xd7, 0xbb, 0x5b, 0x4b, 0x84, 0xd2, 0xf5, 0x11, + 0xcd, 0x25, 0x22, 0x86, 0xdf, 0x56, 0x47, 0xdc, 0xd6, 0xf5, + 0x2d, 0x5, 0x1, 0x8c, 0x41, 0x91, 0xc7, 0x2c, 0x62, 0xf8, + 0x7d, 0xd8, 0xfb, 0x21, 0x2, 0x45, 0x1e, 0x59, 0x71, 0xc3, + 0xef, 0xa3, 0xb2, 0xaa, 0x33, 0x2, 0x11, 0x74, 0x44, 0xe0, + 0xf1, 0x55, 0xc4, 0xf0, 0xcb, 0xde, 0xa0, 0x9f, 0xbd, 0xe0, + 0x37, 0xdf, 0xcd, 0xe8, 0x86, 0x7e, 0x68, 0x9f, 0x5e, 0x4d, + 0xea, 0xed, 0xae, 0x63, 0x5e, 0x29, 0x7d, 0xd4, 0x5b, 0x3c, + 0xc0, 0x6e, 0xd6, 0x29, 0x99, 0xc7, 0x1, 0x11, 0x2b, 0x3f, + 0xa0, 0x77, 0x3a, 0x36, 0x39, 0x49, 0xf8, 0x1, 0xdd, 0x50, + 0xe4, 0x71, 0x15, 0xe1, 0x7, 0xb4, 0x4e, 0x9d, 0xc7, 0xe5, + 0x84, 0x1f, 0xd0, 0x28, 0x75, 0x1e, 0xf7, 0x11, 0x7e, 0x40, + 0x5b, 0x64, 0x1e, 0xf, 0x10, 0x7e, 0x40, 0x2b, 0xfc, 0xa0, + 0x88, 0xc7, 0xec, 0xe, 0xbf, 0x68, 0x3, 0x1b, 0x85, 0xfa, + 0xb2, 0xf0, 0xa, 0xa5, 0x1e, 0xcf, 0xb, 0x5a, 0xf9, 0xd5, + 0x47, 0x9a, 0xa3, 0x11, 0xee, 0xa3, 0xd4, 0xe3, 0x2d, 0x11, + 0xc3, 0xaf, 0x30, 0xc2, 0x5c, 0x39, 0x14, 0x55, 0x81, 0x70, + 0x9, 0xa5, 0x1e, 0xaf, 0x8b, 0x18, 0x7e, 0x4b, 0xe5, 0x81, + 0xeb, 0xd2, 0xd3, 0xd2, 0xad, 0x83, 0xd6, 0xad, 0xd8, 0x50, + 0x43, 0xa9, 0x47, 0x23, 0x22, 0x86, 0xdf, 0x9c, 0x6a, 0xd9, + 0x4a, 0x6e, 0x8e, 0xc0, 0xcf, 0x5f, 0x57, 0x65, 0xe2, 0xea, + 0xaf, 0x9f, 0x17, 0x55, 0x84, 0xf0, 0x95, 0xd8, 0xa3, 0x29, + 0xff, 0x7b, 0x7b, 0x1, 0x1a, 0x55, 0x3e, 0x44, 0x1d, 0xc0, + 0x50, 0x6f, 0x3e, 0x59, 0x74, 0xe0, 0xd0, 0x8e, 0x23, 0xe1, + 0x97, 0xd6, 0x43, 0xfd, 0x9a, 0xbf, 0xc8, 0xc9, 0x6f, 0x74, + 0xd5, 0x7c, 0x60, 0x24, 0x62, 0x8f, 0x66, 0x45, 0xec, 0xf6, + 0xfc, 0x98, 0x7b, 0x35, 0xd3, 0xb1, 0x8d, 0x3e, 0xff, 0xc8, + 0x1e, 0xae, 0xab, 0xbf, 0x1a, 0xf3, 0x8, 0xb2, 0x1c, 0xe, + 0x34, 0x2e, 0x68, 0xf8, 0xcd, 0xc7, 0xe4, 0xd6, 0x35, 0xbf, + 0xbd, 0xff, 0x75, 0x90, 0xc3, 0xcc, 0x55, 0x70, 0xda, 0x17, + 0x34, 0xfc, 0x80, 0x3b, 0x28, 0xf8, 0xe8, 0x85, 0xf0, 0xfb, + 0x4f, 0xf9, 0x72, 0x9d, 0x8b, 0x79, 0x50, 0xa6, 0xe0, 0xa3, + 0x23, 0x7, 0xc3, 0x6f, 0xc8, 0x87, 0x9c, 0xb9, 0xc3, 0x13, + 0x8e, 0x51, 0xf0, 0xd1, 0x1d, 0x95, 0x1f, 0x70, 0xca, 0x78, + 0xe7, 0xc1, 0x44, 0x20, 0xfc, 0x80, 0x83, 0x14, 0x7c, 0xf4, + 0x4b, 0xf8, 0x1, 0x47, 0x28, 0xf8, 0xe8, 0x9a, 0x27, 0xbc, + 00, 0xbb, 0x49, 0x3e, 0x7a, 0x77, 0x3c, 0xfc, 0x46, 0x7a, + 0xce, 0xb, 0x50, 0x4f, 0xf2, 0x31, 00, 0xdd, 0x9e, 0x40, + 0x2d, 0x17, 0xf9, 0x18, 0x86, 0xf0, 0x3, 0xaa, 0x28, 0xf8, + 0x18, 0x89, 0x6b, 0x7e, 0xc0, 0x77, 0x92, 0x8f, 0xc1, 0x8, + 0x3f, 0xe0, 0xb, 0xc9, 0xc7, 0x78, 0x4e, 0x85, 0x9f, 0x7b, + 0x5e, 0x60, 0x78, 0x92, 0x8f, 0x21, 0xa9, 0xfc, 0x80, 0x4d, + 0x92, 0x8f, 0x51, 0x9, 0x3f, 0x20, 0x4f, 0xf2, 0x31, 0x30, + 0x77, 0x7b, 0x2, 0x6b, 0x7e, 0xd2, 0xc0, 0xf0, 0x84, 0x1f, + 0xf0, 0x17, 0x5, 0x1f, 0x11, 0x9c, 0xed, 0xf6, 0x74, 0xcf, + 0xb, 0x8c, 0x44, 0xf2, 0x11, 0x84, 0x6b, 0x7e, 0xc0, 0x1f, + 0x92, 0x8f, 0x38, 0x84, 0x1f, 0x30, 0x4d, 0x92, 0x8f, 0x60, + 0x84, 0x1f, 0x20, 0xf9, 0x8, 0xe7, 0x82, 0xf0, 0x73, 0xd9, + 0xf, 0x7a, 0x27, 0xf9, 0x88, 0x46, 0xe5, 0x7, 0xa1, 0x39, + 0x73, 0x25, 0x26, 0xe1, 0x7, 0x71, 0xe9, 0xed, 0x24, 0xac, + 0x6b, 0xc2, 0x4f, 0xcf, 0x27, 0x74, 0x47, 0xf2, 0x71, 0x46, + 0xef, 0x6d, 0xbe, 0x1f, 0xb9, 0x43, 0x44, 0xc7, 0x92, 0x6f, + 0x6e, 0xef, 0x56, 0xef, 0xdd, 0x7a, 0x3d, 0xfb, 0xf6, 0x79, + 0x9a, 0x79, 0x19, 0x2a, 0x1f, 0x28, 0xb3, 0x5c, 0xe6, 0x5b, + 0x9f, 0x41, 0x53, 0x3f, 0xf3, 0xec, 0x94, 0xbb, 0x96, 0x2d, + 0x9d, 0x78, 0x15, 0x2a, 0x7b, 0xbf, 0xe3, 0xd6, 0x4a, 0xae, + 0x5f, 0xb0, 0xc2, 0x2, 0xac, 0xfe, 0xd4, 0xe0, 0xf9, 0x53, + 0xfd, 0x22, 0xe9, 0xf6, 0x84, 0x70, 0xce, 0xb7, 0x59, 0xbd, + 0x9f, 0xf5, 0xb7, 0xef, 0xf7, 0xf7, 0x77, 0x79, 0x66, 0xf0, + 0x98, 0x39, 0x20, 0xd3, 0x5, 0x58, 0xfd, 0xa9, 0xb5, 0xd8, + 0xdb, 0x4b, 0xf8, 0x41, 0x2c, 0x27, 0x93, 0x2f, 0x7d, 0xef, + 0xc9, 0x22, 0x72, 0x5a, 0x34, 0xf4, 0x95, 0xd3, 0x53, 0xb0, + 0x5c, 0x99, 0x7b, 0x57, 0xda, 0x56, 0x69, 0xb8, 0x9c, 0xcf, + 0x6a, 0xc3, 0x1d, 0x5c, 0xca, 0x7b, 0xec, 0xfa, 0xbe, 0x97, + 0x75, 0x7b, 0x7e, 0x2e, 0xfb, 0xdd, 0xb7, 0x2e, 0xec, 0xfa, + 0x70, 0xde, 0x33, 0xfd, 0x54, 0xcb, 0x36, 0xb4, 0xd0, 0x31, + 0x38, 0x2f, 0xcf, 0xd7, 0xee, 0xb8, 0xd5, 0xf4, 0xe9, 0xeb, + 0xab, 0x8f, 0x5b, 0xbe, 0x58, 0x33, 0x4d, 0xfa, 0x62, 0xfd, + 0x47, 0x94, 0x65, 0x57, 0xc5, 0xc9, 0xad, 0x50, 0x9e, 0xe7, + 0xf2, 0x95, 0x79, 0xfa, 0xf2, 0x4a, 0x2b, 0xc8, 0xde, 0xcf, + 0x51, 0xd8, 0x5e, 0xab, 0x99, 0x6f, 0xed, 0x9, 0x5b, 0x3d, + 0xab, 0xbb, 0x5e, 0x2f, 0x6c, 0xb2, 0x9a, 0xd5, 0xdb, 0xc7, + 0x35, 0xbf, 0xd6, 0xce, 0x2f, 0xa0, 0x47, 0x57, 0x25, 0xdf, + 0xa7, 0x51, 0x9b, 0x73, 0xeb, 0xc0, 0x3c, 0x6b, 0x2, 0xaf, + 0x66, 0xfa, 0xad, 0x46, 0x30, 0x7d, 0x7d, 0xb9, 0xcc, 0xab, + 0x79, 0x4e, 0x49, 0x6b, 0x9e, 0x9d, 0xe1, 0xe7, 0xed, 0xcb, + 0xf9, 0x67, 0xa7, 0xbc, 0x4a, 0xe5, 0x65, 0xd4, 0x82, 0xbd, + 0x2b, 0xad, 0x66, 0x86, 0xd3, 0xf6, 0x89, 0x48, 0x3a, 0x65, + 0xfd, 0xc, 0x57, 0xb3, 0x5a, 0xbd, 0x9e, 0xa6, 0xe6, 0x6a, + 0x3b, 0xce, 0xaf, 0xec, 0xda, 0xa9, 0xfa, 0x8, 0x3f, 0xe0, + 0xa4, 0x3b, 0x6a, 0xbe, 0xcb, 0x9b, 0xfe, 0xad, 0x19, 0x1e, + 0x5b, 0xf2, 0x34, 0xde, 0x96, 0xaf, 0xd7, 0x2c, 0x7c, 0xf6, + 0xed, 0x7, 0x96, 0x61, 0xab, 0xdb, 0xb0, 0xfc, 0xc6, 0xcb, + 0xe7, 0x79, 0x89, 0xad, 0x10, 0x5a, 0xba, 0xaf, 0x83, 0x21, + 0x5b, 0x89, 0x4e, 0x87, 0xf6, 0x90, 0x2b, 0xc3, 0xef, 0xee, + 0x9e, 0x4f, 0xe0, 0x98, 0x5b, 0x1b, 0xa3, 0x66, 0xe7, 0xb6, + 0x35, 0xe7, 0xb4, 0x63, 0xb0, 0xfe, 0xed, 0x67, 0x62, 0x66, + 0x6f, 0x69, 0xf2, 0xd6, 0x3c, 0xb7, 0x6c, 0xd5, 0xcd, 0xd9, + 0xe5, 0x69, 0x3f, 0xb, 0xdc, 0xf0, 0x2, 0x83, 0xbb, 0xa3, + 0x19, 0x6a, 0xbc, 0x5d, 0x9b, 0xa5, 0xd7, 0x1a, 0x2b, 0xaf, + 0x57, 0x6d, 0xbd, 0x7d, 0x6b, 0xca, 0xbd, 0x4b, 0x72, 0x89, + 0x9b, 0x36, 0x6b, 0x5a, 0x53, 0x56, 0x66, 0xff, 0x3c, 0xf1, + 0x1d, 0x5f, 0xf6, 0xf2, 0xea, 0x56, 0xf8, 0xc1, 0xc8, 0x2e, + 0x4c, 0xbe, 0xf9, 0x8c, 0x7e, 0x7e, 0x25, 0x6d, 0x13, 0x57, + 0xed, 0x66, 0xb6, 0xc1, 0x3a, 0xd3, 0x5f, 0x57, 0x39, 0x7d, + 0xf6, 0x1e, 0x8d, 0x9f, 0xbf, 0x7f, 0xf1, 0xb6, 0xf5, 0x45, + 0xb6, 0x96, 0xf9, 0xf3, 0xf6, 0xaf, 0x53, 0xa6, 0xcb, 0x90, + 0xbd, 0xe4, 0xb6, 0x9a, 0xa6, 0xf0, 0x8f, 0xac, 0xc2, 0x3c, + 0xb, 0x4b, 0x52, 0x63, 0x79, 0xbd, 0x2d, 0x7b, 0xa2, 0x50, + 0xf8, 0xd3, 0xf2, 0xaf, 0xab, 0xaf, 0x59, 0x58, 0xab, 0x5b, + 0x1f, 0x31, 0xbf, 0xbe, 0x5a, 0xe7, 0xab, 0x70, 0xcd, 0x6e, + 0xeb, 0x9a, 0x6f, 0x7a, 0xf1, 0x29, 0xe1, 0x63, 0x5, 0x38, + 0xf0, 0x55, 0xfb, 0x5d, 0x4f, 0xc4, 0x54, 0xc8, 0xce, 0xec, + 0xeb, 0x77, 0xb8, 0xb8, 0xf2, 0x73, 0xa4, 0x41, 0x23, 0x24, + 0x1f, 0x14, 0xe8, 0xf6, 0x84, 0x1, 0x49, 0x3e, 0x9a, 0xb5, + 0xd5, 0x2d, 0xf9, 0xe4, 0x3d, 0xab, 0x93, 0x9f, 0x3a, 0xc0, + 0x78, 0x24, 0x1f, 0x2d, 0x3b, 0xf9, 0xeb, 0xc0, 0xab, 0x5c, + 0x5f, 0xf9, 0xed, 0xba, 0x81, 0x18, 0xb8, 0x96, 0xe4, 0x83, + 0x1a, 0xba, 0x3d, 0x61, 0x1c, 0x92, 0xf, 0x2a, 0x9, 0x3f, + 0x18, 0x84, 0xe4, 0x83, 0x7a, 0xb7, 0x84, 0x9f, 0x9e, 0x4f, + 0x78, 0x98, 0xe4, 0x83, 0x5d, 0x54, 0x7e, 0xd0, 0x3d, 0xc9, + 0x7, 0x7b, 0xdd, 0x15, 0x7e, 0x8a, 0x3f, 0x78, 0x86, 0xe4, + 0x83, 0x3, 0x54, 0x7e, 0xd0, 0x31, 0xc9, 0x7, 0xc7, 0x8, + 0x3f, 0xe8, 0x95, 0xe4, 0x83, 0xc3, 0x6e, 0xc, 0x3f, 0x3d, + 0x9f, 0x70, 0x1f, 0xc9, 0x7, 0x67, 0xa8, 0xfc, 0xa0, 0x3f, + 0x92, 0xf, 0x4e, 0xba, 0x37, 0xfc, 0x14, 0x7f, 0x70, 0x39, + 0xc9, 0x7, 0xe7, 0xa9, 0xfc, 0xa0, 0x27, 0x92, 0xf, 0x2e, + 0x21, 0xfc, 0xa0, 0x1b, 0x92, 0xf, 0xae, 0x72, 0x7b, 0xf8, + 0xe9, 0xf9, 0x84, 0x4b, 0x48, 0x3e, 0xb8, 0x90, 0x21, 0x8d, + 0xa0, 0x75, 0x4f, 0xe, 0x6f, 0xd, 0x41, 0x3c, 0x74, 0x2e, + 0xe9, 0xa4, 0x15, 0x8e, 0x71, 0xec, 0xc0, 0x1d, 0x5c, 0xf3, + 0x83, 0x76, 0x49, 0x3e, 0xb8, 0xc9, 0x43, 0xe1, 0xe7, 0xca, + 0x1f, 0xec, 0x25, 0xf9, 0xe0, 0x3e, 0x2a, 0x3f, 0x68, 0x91, + 0xe4, 0x83, 0x5b, 0x3d, 0x17, 0x7e, 0x8a, 0x3f, 0xa8, 0x24, + 0xf9, 0xe0, 0x6e, 0xee, 0xf6, 0x84, 0x86, 0xb8, 0xb1, 0x13, + 0x9e, 0xf1, 0xf4, 0x9, 0xa6, 0x53, 0x5a, 0xd8, 0xe2, 0xe8, + 0x80, 0xc7, 0xb8, 0xe6, 0x7, 0x4d, 0x90, 0x7c, 0xf0, 0xa4, + 0xa7, 0xc3, 0xcf, 0x95, 0x3f, 0x48, 0x49, 0x3e, 0x78, 0xd8, + 0x3b, 0x87, 0x9c, 0x43, 0x1d, 0x3e, 0x5c, 0xe4, 0x83, 0x57, + 0xb8, 0xe1, 0x5, 0x5e, 0xe3, 0x2c, 0x10, 0xde, 0xf2, 0xce, + 0x35, 0x3f, 0x9d, 0x9f, 0x20, 0xf9, 0xe0, 0x45, 0x6e, 0x78, + 0x81, 0x17, 0x48, 0x3e, 0x78, 0xd7, 0x9b, 0x47, 0xa0, 0xe3, + 0x9f, 0x80, 0x5c, 0xe4, 0x83, 0x16, 0xbc, 0x1c, 0x3f, 0xf2, + 0x8f, 0x50, 0xec, 0xf0, 0xd0, 0x8, 0x37, 0xbc, 0xc0, 0x13, + 0x14, 0x7c, 0xd0, 0x94, 0xf7, 0xcf, 0x43, 0x9d, 0xb, 0x33, + 0x3c, 0x3b, 0x39, 0xb4, 0xe6, 0xfd, 0x1b, 0x5e, 0xdc, 0xf9, + 0xc9, 0xd8, 0x24, 0x1f, 0x34, 0x48, 0xb7, 0x27, 0xdc, 0x45, + 0x57, 0x27, 0x34, 0xab, 0x95, 0x73, 0x52, 0x67, 0xc7, 0xc, + 0xc6, 0x2e, 0xd, 0x2d, 0x6b, 0xe8, 0xf8, 0xd4, 0x58, 0x30, + 0x6, 0x5, 0x1f, 0xb4, 0xaf, 0xad, 0xbc, 0x91, 0x7f, 0xf4, + 0xce, 0x3e, 0xc, 0x5d, 0x70, 0xcd, 0xf, 0xae, 0xa1, 0xe0, + 0x83, 0x8e, 0x34, 0x77, 0x96, 0xea, 0xc4, 0x99, 0x1e, 0xd9, + 0x6f, 0xa1, 0x2f, 0x2d, 0x1e, 0xb1, 0xda, 0x11, 0x3a, 0xa2, + 0xe0, 0x83, 0x1e, 0x35, 0x1a, 0x33, 0xf2, 0x8f, 0xf6, 0x89, + 0x3d, 0xe8, 0x57, 0xbb, 0x19, 0x23, 0xff, 0x68, 0x99, 0xfd, + 0x13, 0xba, 0xd6, 0xf4, 0x1, 0xac, 0x7d, 0xa1, 0x41, 0xa, + 0x3e, 0x18, 0x40, 0xeb, 0xe9, 0x22, 0xff, 0x68, 0x8a, 0x1d, + 0x12, 0xc6, 0xd0, 0xc1, 0x91, 0xac, 0xb9, 0xa1, 0x5, 0xa, + 0x3e, 0x18, 0x49, 0x1f, 0xb9, 0x22, 0xff, 0x78, 0x91, 0xd8, + 0x83, 0xf1, 0x74, 0x13, 0x2a, 0xf2, 0x8f, 0x57, 0xd8, 0xf1, + 0x60, 0x48, 0x3d, 0x1d, 0xd8, 0x9a, 0x21, 0x9e, 0xa4, 0xe0, + 0x83, 0x81, 0x75, 0x16, 0x27, 0xf2, 0x8f, 0x7, 0x88, 0x3d, + 0x18, 0x5e, 0x7f, 0x59, 0x22, 0xff, 0xb8, 0x8f, 0xd8, 0x83, + 0x20, 0xba, 0xc, 0x12, 0xf9, 0xc7, 0xe5, 0xc4, 0x1e, 0x84, + 0xd2, 0x6b, 0x8a, 0xc8, 0x3f, 0x2e, 0x64, 0x77, 0x82, 0x68, + 0x3a, 0x3e, 0xe6, 0x9d, 0xaa, 0x73, 0x9e, 0xbd, 0x8, 0x62, + 0xea, 0x38, 0xfc, 0x3e, 0x9c, 0xb3, 0x73, 0x8c, 0xd8, 0x83, + 0xc8, 0x46, 0x48, 0xe, 0xf9, 0xc7, 0x2e, 0x62, 0xf, 0x18, + 0x24, 0x36, 0x34, 0x67, 0xd4, 0xb0, 0x9f, 00, 0x1f, 0x83, + 0x84, 0xdf, 0x87, 0x12, 0x90, 0x2d, 0x62, 0xf, 0x58, 0x1a, + 0x2d, 0x2d, 0xe4, 0x1f, 0x2b, 0x62, 0xf, 0x48, 0xd, 0x18, + 0x15, 0x1a, 0x3b, 0x3e, 0xec, 0x9, 0xc0, 0x96, 0x1, 0xc3, + 0xef, 0x43, 0x9, 0x18, 0x99, 0xd8, 0x3, 0xca, 0x46, 0x4e, + 0x8, 0x2d, 0x60, 0x40, 0x36, 0x3a, 0x50, 0x63, 0xe4, 0xf0, + 0xfb, 0xd0, 0x1a, 0x6, 0x61, 0x43, 0x3, 0xf5, 0xc6, 0xf, + 0xbf, 0xf, 0xbd, 0xa0, 0xa3, 0xfa, 0x64, 0xde, 0x24, 0xf6, + 0x80, 0x3d, 0x2, 0x45, 0x82, 0xca, 0x60, 0x30, 0x36, 0x28, + 0x70, 0x58, 0xa0, 0xf0, 0xfb, 0xd0, 0x62, 0xe, 0xc0, 0x46, + 0x4, 0x4e, 0xa, 0x17, 0x7e, 0x1f, 0x5a, 0xcf, 0x1e, 0xe9, + 0xe1, 0x4, 0xae, 0x12, 0x34, 0xfc, 0x3e, 0x44, 0x60, 0x2f, + 0x6c, 0x29, 0xe0, 0x5a, 0xa1, 0xc3, 0xef, 0x43, 0xc3, 0xda, + 0x2c, 0xa5, 0x1e, 0x70, 0x13, 0xe1, 0xf7, 0x87, 0x8, 0x6c, + 0x8a, 0xcd, 0x1, 0xdc, 0x4a, 0xf8, 0xfd, 0x45, 0x9b, 0xfb, + 0x2e, 0xa5, 0x1e, 0xf0, 0xc, 0xe1, 0x97, 0x21, 0x2, 0x9f, + 0x67, 0x9d, 0x3, 0x4f, 0x12, 0x7e, 0x9b, 0x54, 0x21, 0xf, + 0xb0, 0x92, 0x81, 0x57, 0x8, 0xbf, 0xef, 0x14, 0x25, 0x97, + 0x93, 0x79, 0xc0, 0xbb, 0x84, 0x5f, 0x2d, 0xed, 0xf5, 0x79, + 0xd6, 0x21, 0xd0, 0x8, 0xe1, 0xb7, 0x9b, 0x16, 0x7c, 0x2f, + 0x6b, 0xc, 0x68, 0x8d, 0xf0, 0x3b, 0x4e, 0x9b, 0x5e, 0x30, + 0xaf, 0x9c, 0xc9, 0xfa, 0x1, 0xda, 0x23, 0xfc, 0x2e, 0x20, + 0x5, 0x67, 0x56, 0x5, 0xd0, 0x5, 0xe1, 0x77, 0xa5, 0x98, + 0xe5, 0x4e, 0xcc, 0x6f, 0xd, 0x74, 0x4d, 0xf8, 0xdd, 0x62, + 0xf8, 0x3c, 0x18, 0xfe, 0xb, 0x2, 0x63, 0x13, 0x7e, 0xb7, + 0x5b, 0xe6, 0xc4, 0xd4, 0x6d, 0x54, 0x8c, 0xf1, 0x2d, 00, + 0x3e, 0x84, 0xdf, 0xd3, 0x7a, 0x49, 0x91, 0x5e, 0x96, 0x13, + 0xe0, 00, 0xe1, 0xf7, 0xb2, 0x55, 0xc6, 0x7c, 0x3c, 0xbc, + 0x51, 0x5a, 0x58, 0x6, 0x80, 0x27, 0x9, 0xbf, 0x16, 0x65, + 0xd3, 0x68, 0xa9, 0x7e, 0xab, 0x7d, 0x9d, 0xd5, 0xae, 0xb9, + 0x1, 0x8c, 0x41, 0xf8, 0x75, 0xa9, 0x26, 0xd2, 0x3e, 0x6c, + 0x5f, 0x80, 0xd4, 0xff, 0xc2, 0xdb, 0x4d, 0xcb, 00, 00, + 00, 0x5, 0x49, 0x44, 0x41, 0x54, 0x1, 0x5b, 0x8a, 0x3b, + 0xa9, 0x12, 0xfa, 0x92, 0xf8, 00, 00, 00, 00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, }; + +const struct fsdata_file file_404_html[] = {{NULL, data_404_html, data_404_html + 10, sizeof(data_404_html) - 10}}; + +const struct fsdata_file file_mailinglist_html[] = {{file_404_html, data_mailinglist_html, data_mailinglist_html + 18, sizeof(data_mailinglist_html) - 18}}; + +const struct fsdata_file file_links_html[] = {{file_mailinglist_html, data_links_html, data_links_html + 12, sizeof(data_links_html) - 12}}; + +const struct fsdata_file file_licence_html[] = {{file_links_html, data_licence_html, data_licence_html + 14, sizeof(data_licence_html) - 14}}; + +const struct fsdata_file file_img_sics_gif[] = {{file_licence_html, data_img_sics_gif, data_img_sics_gif + 14, sizeof(data_img_sics_gif) - 14}}; + +const struct fsdata_file file_index_html[] = {{file_img_sics_gif, data_index_html, data_index_html + 12, sizeof(data_index_html) - 12}}; + +const struct fsdata_file file_download_html[] = {{file_index_html, data_download_html, data_download_html + 15, sizeof(data_download_html) - 15}}; + +const struct fsdata_file file_documentation_html[] = {{file_download_html, data_documentation_html, data_documentation_html + 20, sizeof(data_documentation_html) - 20}}; + +const struct fsdata_file file_os_html[] = {{file_documentation_html, data_os_html, data_os_html + 9, sizeof(data_os_html) - 9}}; + +const struct fsdata_file file_threads_png[] = {{file_os_html, data_threads_png, data_threads_png + 13, sizeof(data_threads_png) - 13}}; + +const struct fsdata_file file_os_png[] = {{file_threads_png, data_os_png, data_os_png + 8, sizeof(data_os_png) - 8}}; + +#define FS_ROOT file_os_png + +#define FS_NUMFILES 11 \ No newline at end of file diff --git a/proj/unixsim/apps/fsdata.h b/proj/unixsim/apps/fsdata.h new file mode 100644 index 00000000..4ee3db92 --- /dev/null +++ b/proj/unixsim/apps/fsdata.h @@ -0,0 +1,49 @@ +/* + * 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 + * + */ +#ifndef __FSDATA_H__ +#define __FSDATA_H__ + +struct fsdata_file { + const struct fsdata_file *next; + const char *name; + const char *data; + const int len; +}; + +struct fsdata_file_noconst { + struct fsdata_file *next; + char *name; + char *data; + int len; +}; + +#endif /* __FSDATA_H__ */ diff --git a/proj/unixsim/apps/httpd.c b/proj/unixsim/apps/httpd.c new file mode 100644 index 00000000..4b391bac --- /dev/null +++ b/proj/unixsim/apps/httpd.c @@ -0,0 +1,244 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" + +#include "lwip/stats.h" + +#include "httpd.h" + +#include "lwip/tcp.h" + +#include "fs.h" + +struct http_state { + char *file; + u32_t left; + u8_t retries; +}; + +/*-----------------------------------------------------------------------------------*/ +static void +conn_err(void *arg, err_t err) +{ + struct http_state *hs; + + hs = arg; + mem_free(hs); +} +/*-----------------------------------------------------------------------------------*/ +static void +close_conn(struct tcp_pcb *pcb, struct http_state *hs) +{ + tcp_arg(pcb, NULL); + tcp_sent(pcb, NULL); + tcp_recv(pcb, NULL); + mem_free(hs); + tcp_close(pcb); +} +/*-----------------------------------------------------------------------------------*/ +static void +send_data(struct tcp_pcb *pcb, struct http_state *hs) +{ + err_t err; + u16_t len; + + /* We cannot send more data than space avaliable in the send + buffer. */ + if(tcp_sndbuf(pcb) < hs->left) { + len = tcp_sndbuf(pcb); + } else { + len = hs->left; + } + + do { + err = tcp_write(pcb, hs->file, len, 0); + if(err == ERR_MEM) { + len /= 2; + } + } while(err == ERR_MEM && len > 1); + + if(err == ERR_OK) { + hs->file += len; + hs->left -= len; + /* } else { + printf("send_data: error %s len %d %d\n", lwip_strerr(err), len, tcp_sndbuf(pcb));*/ + } +} +/*-----------------------------------------------------------------------------------*/ +static err_t +http_poll(void *arg, struct tcp_pcb *pcb) +{ + struct http_state *hs; + + hs = arg; + + /* printf("Polll\n");*/ + if(hs == NULL) { + /* printf("Null, close\n");*/ + tcp_abort(pcb); + return ERR_ABRT; + } else { + ++hs->retries; + if(hs->retries == 4) { + tcp_abort(pcb); + return ERR_ABRT; + } + send_data(pcb, hs); + } + + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +static err_t +http_sent(void *arg, struct tcp_pcb *pcb, u16_t len) +{ + struct http_state *hs; + + hs = arg; + + hs->retries = 0; + + if(hs->left > 0) { + send_data(pcb, hs); + } else { + close_conn(pcb, hs); + } + + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +static err_t +http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + int i; + char *data; + struct fs_file file; + struct http_state *hs; + + hs = arg; + + if(err == ERR_OK && p != NULL) { + + /* Inform TCP that we have taken the data. */ + tcp_recved(pcb, p->tot_len); + + if(hs->file == NULL) { + data = p->payload; + + if(strncmp(data, "GET ", 4) == 0) { + for(i = 0; i < 40; i++) { + if(((char *)data + 4)[i] == ' ' || + ((char *)data + 4)[i] == '\r' || + ((char *)data + 4)[i] == '\n') { + ((char *)data + 4)[i] = 0; + } + } + + if(*(char *)(data + 4) == '/' && + *(char *)(data + 5) == 0) { + fs_open("/index.html", &file); + } else if(!fs_open((char *)data + 4, &file)) { + fs_open("/404.html", &file); + } + hs->file = file.data; + hs->left = file.len; + /* printf("data %p len %ld\n", hs->file, hs->left);*/ + + pbuf_free(p); + send_data(pcb, hs); + + /* Tell TCP that we wish be to informed of data that has been + successfully sent by a call to the http_sent() function. */ + tcp_sent(pcb, http_sent); + } else { + pbuf_free(p); + close_conn(pcb, hs); + } + } else { + pbuf_free(p); + } + } + + if(err == ERR_OK && p == NULL) { + close_conn(pcb, hs); + } + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +static err_t +http_accept(void *arg, struct tcp_pcb *pcb, err_t err) +{ + struct http_state *hs; + + tcp_setprio(pcb, TCP_PRIO_MIN); + + /* Allocate memory for the structure that holds the state of the + connection. */ + hs = mem_malloc(sizeof(struct http_state)); + + if(hs == NULL) { + printf("http_accept: Out of memory\n"); + return ERR_MEM; + } + + /* Initialize the structure. */ + hs->file = NULL; + hs->left = 0; + hs->retries = 0; + + /* Tell TCP that this is the structure we wish to be passed for our + callbacks. */ + tcp_arg(pcb, hs); + + /* Tell TCP that we wish to be informed of incoming data by a call + to the http_recv() function. */ + tcp_recv(pcb, http_recv); + + tcp_err(pcb, conn_err); + + tcp_poll(pcb, http_poll, 4); + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +void +httpd_init(void) +{ + struct tcp_pcb *pcb; + + pcb = tcp_new(); + tcp_bind(pcb, IP_ADDR_ANY, 80); + pcb = tcp_listen(pcb); + tcp_accept(pcb, http_accept); +} +/*-----------------------------------------------------------------------------------*/ + diff --git a/proj/unixsim/apps/httpd.h b/proj/unixsim/apps/httpd.h new file mode 100644 index 00000000..323a3a03 --- /dev/null +++ b/proj/unixsim/apps/httpd.h @@ -0,0 +1,37 @@ +/* + * 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 + * + */ +#ifndef __HTTPD_H__ +#define __HTTPD_H__ + +void httpd_init(void); + +#endif /* __HTTPD_H__ */ diff --git a/proj/unixsim/apps/makefsdata b/proj/unixsim/apps/makefsdata new file mode 100644 index 00000000..90dee2fd --- /dev/null +++ b/proj/unixsim/apps/makefsdata @@ -0,0 +1,97 @@ +#!/usr/bin/perl + +open(OUTPUT, "> fsdata.c"); + +chdir("fs"); +open(FILES, "find . -type f |"); + +while($file = ) { + + # Do not include files in CVS directories nor backup files. + if($file =~ /(CVS|~)/) { + next; + } + + chop($file); + + open(HEADER, "> /tmp/header") || die $!; + if($file =~ /404/) { + print(HEADER "HTTP/1.0 404 File not found\r\n"); + } else { + print(HEADER "HTTP/1.0 200 OK\r\n"); + } + print(HEADER "Server: lwIP/pre-0.6 (http://www.sics.se/~adam/lwip/)\r\n"); + if($file =~ /\.html$/) { + print(HEADER "Content-type: text/html\r\n"); + } elsif($file =~ /\.gif$/) { + print(HEADER "Content-type: image/gif\r\n"); + } elsif($file =~ /\.png$/) { + print(HEADER "Content-type: image/png\r\n"); + } elsif($file =~ /\.jpg$/) { + print(HEADER "Content-type: image/jpeg\r\n"); + } elsif($file =~ /\.class$/) { + print(HEADER "Content-type: application/octet-stream\r\n"); + } elsif($file =~ /\.ram$/) { + print(HEADER "Content-type: audio/x-pn-realaudio\r\n"); + } else { + print(HEADER "Content-type: text/plain\r\n"); + } + print(HEADER "\r\n"); + close(HEADER); + + unless($file =~ /\.plain$/ || $file =~ /cgi/) { + system("cat /tmp/header $file > /tmp/file"); + } else { + system("cp $file /tmp/file"); + } + + open(FILE, "/tmp/file"); + unlink("/tmp/file"); + unlink("/tmp/header"); + + $file =~ s/\.//; + $fvar = $file; + $fvar =~ s-/-_-g; + $fvar =~ s-\.-_-g; + print(OUTPUT "static const char data".$fvar."[] = {\n"); + print(OUTPUT "\t/* $file */\n\t"); + for($j = 0; $j < length($file); $j++) { + printf(OUTPUT "%#02x, ", unpack("C", substr($file, $j, 1))); + } + printf(OUTPUT "0,\n"); + + + $i = 0; + while(read(FILE, $data, 1)) { + if($i == 0) { + print(OUTPUT "\t"); + } + printf(OUTPUT "%#02x, ", unpack("C", $data)); + $i++; + if($i == 10) { + print(OUTPUT "\n"); + $i = 0; + } + } + print(OUTPUT "};\n\n"); + close(FILE); + push(@fvars, $fvar); + push(@files, $file); +} + +for($i = 0; $i < @fvars; $i++) { + $file = $files[$i]; + $fvar = $fvars[$i]; + + if($i == 0) { + $prevfile = "NULL"; + } else { + $prevfile = "file" . $fvars[$i - 1]; + } + print(OUTPUT "const struct fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, "); + print(OUTPUT "data$fvar + ". (length($file) + 1) .", "); + print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n"); +} + +print(OUTPUT "#define FS_ROOT file$fvars[$i - 1]\n\n"); +print(OUTPUT "#define FS_NUMFILES $i"); diff --git a/proj/unixsim/apps/shell.c b/proj/unixsim/apps/shell.c new file mode 100644 index 00000000..e6f1a31c --- /dev/null +++ b/proj/unixsim/apps/shell.c @@ -0,0 +1,1056 @@ +/* + * 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 + * + */ + +#include +#include + +#include "lwip/mem.h" +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/api.h" +#include "lwip/stats.h" + +static unsigned char buffer[1024]; + +struct command { + struct netconn *conn; + s8_t (* exec)(struct command *); + u8_t nargs; + char *args[10]; +}; + +#include +#include + +#define ESUCCESS 0 +#define ESYNTAX -1 +#define ETOOFEW -2 +#define ETOOMANY -3 +#define ECLOSED -4 + +#define NCONNS 10 +static struct netconn *conns[NCONNS]; + +static char help_msg[] = "Avaliable commands:\n\ +open [IP address] [TCP port]: opens a TCP connection to the specified address.\n\ +lstn [TCP port]: sets up a server on the specified port.\n\ +acpt [connection #]: waits for an incoming connection request.\n\ +send [connection #] [message]: sends a message on a TCP connection.\n\ +udpc [local UDP port] [IP address] [remote port]: opens a UDP \"connection\".\n\ +udpl [local UDP port] [IP address] [remote port]: opens a UDP-Lite \"connection\".\n\ +udpn [local UDP port] [IP address] [remote port]: opens a UDP \"connection\" without checksums.\n\ +udpb [local port] [remote port]: opens a UDP broadcast \"connection\".\n\ +usnd [connection #] [message]: sends a message on a UDP connection.\n\ +recv [connection #]: recieves data on a TCP or UDP connection.\n\ +clos [connection #]: closes a TCP or UDP connection.\n\ +stat: prints out lwIP statistics.\n\ +quit: quits.\n"; + +static char *stat_msgs[] = { + "Link level * transmitted ", + " retransmitted ", + " * received ", + " forwarded ", + " * dropped ", + " * checksum errors ", + " * length errors ", + " * memory errors ", + " routing errors ", + " protocol errors ", + " option errors ", + " * misc errors ", + " cache hits ", + "IP * transmitted ", + " retransmitted ", + " * received ", + " * forwarded ", + " * dropped ", + " * checksum errors ", + " * length errors ", + " * memory errors ", + " * routing errors ", + " * protocol errors ", + " * option errors ", + " * misc errors ", + " cache hits ", + "ICMP * transmitted ", + " retransmitted ", + " * received ", + " forwarded ", + " * dropped ", + " * checksum errors ", + " length errors ", + " * memory errors ", + " routing errors ", + " * protocol errors ", + " option errors ", + " * misc errors ", + " cache hits ", + "UDP * transmitted ", + " retransmitted ", + " * received ", + " forwarded ", + " * dropped ", + " * checksum errors ", + " * length errors ", + " * memory errors ", + " * routing errors ", + " * protocol errors ", + " option errors ", + " * misc errors ", + " cache hits ", + "TCP * transmitted ", + " * retransmitted ", + " * received ", + " forwarded ", + " * dropped ", + " * checksum errors ", + " * length errors ", + " * memory errors ", + " * routing errors ", + " * protocol errors ", + " * option errors ", + " * misc errors ", + " * cache hits ", + "Pbufs * avaiable ", + " * used ", + " * high water mark ", + " * errors ", + " reclaimed ", + " pbuf_alloc() locked ", + " pbuf_refresh() locked ", + "Memory * avaliable ", + " * used ", + " * high water mark ", + " * errors ", + " * reclaimed ", + "Memp PBUF * avaliable ", + " * used ", + " * high water mark ", + " * errors ", + " * reclaimed ", + "UDP PCB * avaliable ", + " * used ", + " * high water mark ", + " * errors ", + " * reclaimed ", + "TCP PCB * avaliable ", + " * used ", + " * high water mark ", + " * errors ", + " * reclaimed ", + "TCP LISTEN * avaliable ", + " * used ", + " * high water mark ", + " * errors ", + " * reclaimed ", + "TCP SEG * avaliable ", + " * used ", + " * high water mark ", + " * errors ", + " * reclaimed ", + "Netbufs * avaliable ", + " * used ", + " * high water mark ", + " * errors ", + " * reclaimed ", + "Netconns * avaliable ", + " * used ", + " * high water mark ", + " * errors ", + " * reclaimed ", + "API msgs * avaliable ", + " * used ", + " * high water mark ", + " * errors ", + " * reclaimed ", + "TCPIP msgs * avaliable ", + " * used ", + " * high water mark ", + " * errors ", + " * reclaimed ", + "Timeouts * avaliable ", + " * used ", + " * high water mark ", + " * errors ", + " * reclaimed ", + "Semaphores * used ", + " * high water mark ", + " * errors ", + "Mailboxes * used ", + " * high water mark ", + " * errors " +}; +/*-----------------------------------------------------------------------------------*/ +static void +sendstr(const char *str, struct netconn *conn) +{ + netconn_write(conn, (void *)str, strlen(str), NETCONN_NOCOPY); +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_open(struct command *com) +{ + struct ip_addr ipaddr; + u16_t port; + int i; + err_t err; + + if(inet_aton(com->args[0], &ipaddr) == -1) { + sendstr(strerror(errno), com->conn); + return ESYNTAX; + } + port = strtol(com->args[1], NULL, 10); + + /* Find the first unused connection in conns. */ + for(i = 0; i < NCONNS && conns[i] != NULL; i++); + + if(i == NCONNS) { + sendstr("No more connections avaliable, sorry.\n", com->conn); + return ESUCCESS; + } + + sendstr("Opening connection to ", com->conn); + netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); + sendstr(":", com->conn); + netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); + sendstr("\n", com->conn); + + conns[i] = netconn_new(NETCONN_TCP); + if(conns[i] == NULL) { + sendstr("Could not create connection identifier (out of memory).\n", com->conn); + return ESUCCESS; + } + err = netconn_connect(conns[i], &ipaddr, port); + if(err != ERR_OK) { + fprintf(stderr, "error %s\n", lwip_strerr(err)); + sendstr("Could not connect to remote host: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + netconn_delete(conns[i]); + conns[i] = NULL; + return ESUCCESS; + } + + sendstr("Opened connection, connection identifier is ", com->conn); + sprintf(buffer, "%d\n", i); + netconn_write(com->conn, buffer, strlen(buffer), NETCONN_COPY); + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_lstn(struct command *com) +{ + u16_t port; + int i; + err_t err; + + port = strtol(com->args[0], NULL, 10); + + /* Find the first unused connection in conns. */ + for(i = 0; i < NCONNS && conns[i] != NULL; i++); + + if(i == NCONNS) { + sendstr("No more connections avaliable, sorry.\n", com->conn); + return ESUCCESS; + } + + sendstr("Opening a listening connection on port ", com->conn); + netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); + sendstr("\n", com->conn); + + conns[i] = netconn_new(NETCONN_TCP); + if(conns[i] == NULL) { + sendstr("Could not create connection identifier (out of memory).\n", com->conn); + return ESUCCESS; + } + + err = netconn_bind(conns[i], IP_ADDR_ANY, port); + if(err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not bind: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + + err = netconn_listen(conns[i]); + if(err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not listen: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + + sendstr("Opened connection, connection identifier is ", com->conn); + sprintf(buffer, "%d\n", i); + netconn_write(com->conn, buffer, strlen(buffer), NETCONN_COPY); + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_clos(struct command *com) +{ + int i; + err_t err; + + i = strtol(com->args[0], NULL, 10); + + if(i > NCONNS) { + sendstr("Connection identifier too high.\n", com->conn); + return ESUCCESS; + } + if(conns[i] == NULL) { + sendstr("Connection identifier not in use.\n", com->conn); + return ESUCCESS; + } + + err = netconn_close(conns[i]); + if(err != ERR_OK) { + sendstr("Could not close connection: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + + sendstr("Connection closed.\n", com->conn); + netconn_delete(conns[i]); + conns[i] = NULL; + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_acpt(struct command *com) +{ + int i, j; + + /* Find the first unused connection in conns. */ + for(j = 0; j < NCONNS && conns[j] != NULL; j++); + + if(j == NCONNS) { + sendstr("No more connections avaliable, sorry.\n", com->conn); + return ESUCCESS; + } + + i = strtol(com->args[0], NULL, 10); + + if(i > NCONNS) { + sendstr("Connection identifier too high.\n", com->conn); + return ESUCCESS; + } + if(conns[i] == NULL) { + sendstr("Connection identifier not in use.\n", com->conn); + return ESUCCESS; + } + + conns[j] = netconn_accept(conns[i]); + + if(conns[j] == NULL) { + sendstr("Could not accept connection: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(netconn_err(conns[i])), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + + sendstr("Accepted connection, connection identifier for new connection is ", com->conn); + sprintf(buffer, "%d\n", j); + netconn_write(com->conn, buffer, strlen(buffer), NETCONN_COPY); + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_stat(struct command *com) +{ + int i; + char buf[100]; + u16_t len; + + for(i = 0; i < sizeof(struct stats_) / 2; i++) { + len = sprintf(buf, "%d", ((u16_t *)&stats)[i]); + sendstr(stat_msgs[i], com->conn); + netconn_write(com->conn, buf, len, NETCONN_COPY); + sendstr("\n", com->conn); + } + + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_send(struct command *com) +{ + int i; + err_t err; + int len; + + i = strtol(com->args[0], NULL, 10); + + if(i > NCONNS) { + sendstr("Connection identifier too high.\n", com->conn); + return ESUCCESS; + } + + if(conns[i] == NULL) { + sendstr("Connection identifier not in use.\n", com->conn); + return ESUCCESS; + } + + len = strlen(com->args[1]); + com->args[1][len] = '\r'; + com->args[1][len + 1] = '\n'; + com->args[1][len + 2] = 0; + + err = netconn_write(conns[i], com->args[1], len + 3, NETCONN_COPY); + if(err != ERR_OK) { + sendstr("Could not send data: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + + sendstr("Data enqueued for sending.\n", com->conn); + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_recv(struct command *com) +{ + int i; + err_t err; + struct netbuf *buf; + u16_t len; + + i = strtol(com->args[0], NULL, 10); + + if(i > NCONNS) { + sendstr("Connection identifier too high.\n", com->conn); + return ESUCCESS; + } + + if(conns[i] == NULL) { + sendstr("Connection identifier not in use.\n", com->conn); + return ESUCCESS; + } + + buf = netconn_recv(conns[i]); + if(buf != NULL) { + + netbuf_copy(buf, buffer, 1024); + len = netbuf_len(buf); + sendstr("Reading from connection:\n", com->conn); + netconn_write(com->conn, buffer, len, NETCONN_COPY); + netbuf_delete(buf); + } else { + sendstr("EOF.\n", com->conn); + } + err = netconn_err(conns[i]); + if(err != ERR_OK) { + sendstr("Could not receive data: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_udpc(struct command *com) +{ + struct ip_addr ipaddr; + u16_t lport, rport; + int i; + err_t err; + + lport = strtol(com->args[0], NULL, 10); + if(inet_aton(com->args[1], &ipaddr) == -1) { + sendstr(strerror(errno), com->conn); + return ESYNTAX; + } + rport = strtol(com->args[2], NULL, 10); + + /* Find the first unused connection in conns. */ + for(i = 0; i < NCONNS && conns[i] != NULL; i++); + + if(i == NCONNS) { + sendstr("No more connections avaliable, sorry.\n", com->conn); + return ESUCCESS; + } + + sendstr("Setting up UDP connection from port ", com->conn); + netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); + sendstr(" to ", com->conn); + netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); + sendstr(":", com->conn); + netconn_write(com->conn, com->args[2], strlen(com->args[2]), NETCONN_COPY); + sendstr("\n", com->conn); + + conns[i] = netconn_new(NETCONN_UDP); + if(conns[i] == NULL) { + sendstr("Could not create connection identifier (out of memory).\n", com->conn); + return ESUCCESS; + } + + err = netconn_connect(conns[i], &ipaddr, rport); + if(err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not connect to remote host: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + + err = netconn_bind(conns[i], IP_ADDR_ANY, lport); + if(err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not bind: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + + sendstr("Connection set up, connection identifier is ", com->conn); + sprintf(buffer, "%d\n", i); + netconn_write(com->conn, buffer, strlen(buffer), NETCONN_COPY); + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_udpl(struct command *com) +{ + struct ip_addr ipaddr; + u16_t lport, rport; + int i; + err_t err; + + lport = strtol(com->args[0], NULL, 10); + if(inet_aton(com->args[1], &ipaddr) == -1) { + sendstr(strerror(errno), com->conn); + return ESYNTAX; + } + rport = strtol(com->args[2], NULL, 10); + + /* Find the first unused connection in conns. */ + for(i = 0; i < NCONNS && conns[i] != NULL; i++); + + if(i == NCONNS) { + sendstr("No more connections avaliable, sorry.\n", com->conn); + return ESUCCESS; + } + + sendstr("Setting up UDP-Lite connection from port ", com->conn); + netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); + sendstr(" to ", com->conn); + netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); + sendstr(":", com->conn); + netconn_write(com->conn, com->args[2], strlen(com->args[2]), NETCONN_COPY); + sendstr("\n", com->conn); + + conns[i] = netconn_new(NETCONN_UDPLITE); + if(conns[i] == NULL) { + sendstr("Could not create connection identifier (out of memory).\n", com->conn); + return ESUCCESS; + } + + err = netconn_connect(conns[i], &ipaddr, rport); + if(err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not connect to remote host: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + + err = netconn_bind(conns[i], IP_ADDR_ANY, lport); + if(err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not bind: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + + sendstr("Connection set up, connection identifier is ", com->conn); + sprintf(buffer, "%d\n", i); + netconn_write(com->conn, buffer, strlen(buffer), NETCONN_COPY); + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_udpn(struct command *com) +{ + struct ip_addr ipaddr; + u16_t lport, rport; + int i; + err_t err; + + lport = strtol(com->args[0], NULL, 10); + if(inet_aton(com->args[1], &ipaddr) == -1) { + sendstr(strerror(errno), com->conn); + return ESYNTAX; + } + rport = strtol(com->args[2], NULL, 10); + + /* Find the first unused connection in conns. */ + for(i = 0; i < NCONNS && conns[i] != NULL; i++); + + if(i == NCONNS) { + sendstr("No more connections avaliable, sorry.\n", com->conn); + return ESUCCESS; + } + + sendstr("Setting up UDP connection without checksums from port ", com->conn); + netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); + sendstr(" to ", com->conn); + netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); + sendstr(":", com->conn); + netconn_write(com->conn, com->args[2], strlen(com->args[2]), NETCONN_COPY); + sendstr("\n", com->conn); + + conns[i] = netconn_new(NETCONN_UDPNOCHKSUM); + if(conns[i] == NULL) { + sendstr("Could not create connection identifier (out of memory).\n", com->conn); + return ESUCCESS; + } + + err = netconn_connect(conns[i], &ipaddr, rport); + if(err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not connect to remote host: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + + err = netconn_bind(conns[i], IP_ADDR_ANY, lport); + if(err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not bind: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + + sendstr("Connection set up, connection identifier is ", com->conn); + sprintf(buffer, "%d\n", i); + netconn_write(com->conn, buffer, strlen(buffer), NETCONN_COPY); + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_udpb(struct command *com) +{ + struct ip_addr ipaddr; + u16_t lport, rport; + int i; + err_t err; + struct ip_addr bcaddr; + + lport = strtol(com->args[0], NULL, 10); + if(inet_aton(com->args[1], &ipaddr) == -1) { + sendstr(strerror(errno), com->conn); + return ESYNTAX; + } + rport = strtol(com->args[2], NULL, 10); + + /* Find the first unused connection in conns. */ + for(i = 0; i < NCONNS && conns[i] != NULL; i++); + + if(i == NCONNS) { + sendstr("No more connections avaliable, sorry.\n", com->conn); + return ESUCCESS; + } + + sendstr("Setting up UDP broadcast connection from port ", com->conn); + netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); + sendstr(" to ", com->conn); + netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); + sendstr("\n", com->conn); + + conns[i] = netconn_new(NETCONN_UDP); + if(conns[i] == NULL) { + sendstr("Could not create connection identifier (out of memory).\n", com->conn); + return ESUCCESS; + } + + err = netconn_connect(conns[i], &ipaddr, rport); + if(err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not connect to remote host: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + + IP4_ADDR(&bcaddr, 255,255,255,255); + err = netconn_bind(conns[i], &bcaddr, lport); + if(err != ERR_OK) { + netconn_delete(conns[i]); + conns[i] = NULL; + sendstr("Could not bind: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + + sendstr("Connection set up, connection identifier is ", com->conn); + sprintf(buffer, "%d\n", i); + netconn_write(com->conn, buffer, strlen(buffer), NETCONN_COPY); + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_usnd(struct command *com) +{ + int i; + err_t err; + struct netbuf *buf; + char *mem; + + i = strtol(com->args[0], NULL, 10); + + if(i > NCONNS) { + sendstr("Connection identifier too high.\n", com->conn); + return ESUCCESS; + } + + if(conns[i] == NULL) { + sendstr("Connection identifier not in use.\n", com->conn); + return ESUCCESS; + } + + buf = netbuf_new(); + mem = netbuf_alloc(buf, strlen(com->args[1]) + 1); + if(mem == NULL) { + sendstr("Could not allocate memory for sending.\n", com->conn); + return ESUCCESS; + } + strncpy(mem, com->args[1], strlen(com->args[1]) + 1); + err = netconn_send(conns[i], buf); + netbuf_delete(buf); + if(err != ERR_OK) { + sendstr("Could not send data: ", com->conn); +#ifdef LWIP_DEBUG + sendstr(lwip_strerr(err), com->conn); +#else + sendstr("(debugging must be turned on for error message to appear)", com->conn); +#endif /* LWIP_DEBUG */ + sendstr("\n", com->conn); + return ESUCCESS; + } + + sendstr("Data sent.\n", com->conn); + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +com_help(struct command *com) +{ + sendstr(help_msg, com->conn); + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static s8_t +parse_command(struct command *com, u32_t len) +{ + u16_t i; + u16_t bufp; + + if(strncmp(buffer, "open", 4) == 0) { + com->exec = com_open; + com->nargs = 2; + } else if(strncmp(buffer, "lstn", 4) == 0) { + com->exec = com_lstn; + com->nargs = 1; + } else if(strncmp(buffer, "acpt", 4) == 0) { + com->exec = com_acpt; + com->nargs = 1; + } else if(strncmp(buffer, "clos", 4) == 0) { + com->exec = com_clos; + com->nargs = 1; + } else if(strncmp(buffer, "stat", 4) == 0) { + com->exec = com_stat; + com->nargs = 0; + } else if(strncmp(buffer, "send", 4) == 0) { + com->exec = com_send; + com->nargs = 2; + } else if(strncmp(buffer, "recv", 4) == 0) { + com->exec = com_recv; + com->nargs = 1; + } else if(strncmp(buffer, "udpc", 4) == 0) { + com->exec = com_udpc; + com->nargs = 3; + } else if(strncmp(buffer, "udpb", 4) == 0) { + com->exec = com_udpb; + com->nargs = 2; + } else if(strncmp(buffer, "udpl", 4) == 0) { + com->exec = com_udpl; + com->nargs = 3; + } else if(strncmp(buffer, "udpn", 4) == 0) { + com->exec = com_udpn; + com->nargs = 3; + } else if(strncmp(buffer, "usnd", 4) == 0) { + com->exec = com_usnd; + com->nargs = 2; + } else if(strncmp(buffer, "help", 4) == 0) { + com->exec = com_help; + com->nargs = 0; + } else if(strncmp(buffer, "quit", 4) == 0) { + printf("quit\n"); + return ECLOSED; + } else { + return ESYNTAX; + } + + if(com->nargs == 0) { + return ESUCCESS; + } + bufp = 0; + for(; bufp < len && buffer[bufp] != ' '; bufp++); + for(i = 0; i < 10; i++) { + for(; bufp < len && buffer[bufp] == ' '; bufp++); + if(buffer[bufp] == '\r' || + buffer[bufp] == '\n') { + buffer[bufp] = 0; + if(i < com->nargs - 1) { + return ETOOFEW; + } + if(i > com->nargs - 1) { + return ETOOMANY; + } + break; + } + if(bufp > len) { + return ETOOFEW; + } + com->args[i] = &buffer[bufp]; + for(; bufp < len && buffer[bufp] != ' ' && buffer[bufp] != '\r' && + buffer[bufp] != '\n'; bufp++) { + if(buffer[bufp] == '\\') { + buffer[bufp] = ' '; + } + } + if(bufp > len) { + return ESYNTAX; + } + buffer[bufp] = 0; + bufp++; + if(i == com->nargs - 1) { + break; + } + + } + + return ESUCCESS; +} +/*-----------------------------------------------------------------------------------*/ +static void +error(s8_t err, struct netconn *conn) +{ + switch(err) { + case ESYNTAX: + sendstr("## Syntax error\n", conn); + break; + case ETOOFEW: + sendstr("## Too few arguments to command given\n", conn); + break; + case ETOOMANY: + sendstr("## Too many arguments to command given\n", conn); + break; + } +} +/*-----------------------------------------------------------------------------------*/ +static void +prompt(struct netconn *conn) +{ + sendstr("> ", conn); +} +/*-----------------------------------------------------------------------------------*/ +static void +shell_main(struct netconn *conn) +{ + struct netbuf *buf; + u32_t len; + struct command com; + s8_t err; + int i; + + do { + buf = netconn_recv(conn); + if(buf != NULL) { + netbuf_copy(buf, buffer, 1024); + len = netbuf_len(buf); + netbuf_delete(buf); + if(len >= 4) { + if(buffer[0] != 0xff && + buffer[1] != 0xfe) { + err = parse_command(&com, len); + if(err == ESUCCESS) { + com.conn = conn; + err = com.exec(&com); + } + if(err != ESUCCESS) { + error(err, conn); + } + if(err == ECLOSED) { + printf("Closed\n"); + error(err, conn); + goto close; + } + } else { + sendstr("\n\n" + "lwIP simple interactive shell.\n" + "(c) Copyright 2001, Swedish Institute of Computer Science.\n" + "Written by Adam Dunkels.\n" + "For help, try the \"help\" command.\n", conn); + } + } + } + if(buf != NULL) { + prompt(conn); + } + } while(buf != NULL); + printf("buf == NULL err %s\n", lwip_strerr(conn->err)); + close: + netconn_close(conn); + + for(i = 0; i < NCONNS; i++) { + if(conns[i] != NULL) { + netconn_delete(conns[i]); + } + conns[i] = NULL; + } + +} +/*-----------------------------------------------------------------------------------*/ +static void +shell_thread(void *arg) +{ + struct netconn *conn, *newconn; + + conn = netconn_new(NETCONN_TCP); + netconn_bind(conn, NULL, 23); + netconn_listen(conn); + + while(1) { + newconn = netconn_accept(conn); + shell_main(newconn); + netconn_delete(newconn); + } +} +/*-----------------------------------------------------------------------------------*/ +void +shell_init(void) +{ + sys_thread_new(shell_thread, NULL); +} + + + + diff --git a/proj/unixsim/apps/shell.h b/proj/unixsim/apps/shell.h new file mode 100644 index 00000000..34e648b3 --- /dev/null +++ b/proj/unixsim/apps/shell.h @@ -0,0 +1,37 @@ +/* + * 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 + * + */ +#ifndef __SHELL_H__ +#define __SHELL_H__ + +void shell_init(void); + +#endif /* __SHELL_H__ */ diff --git a/proj/unixsim/apps/tcpecho.c b/proj/unixsim/apps/tcpecho.c new file mode 100644 index 00000000..eacf95e5 --- /dev/null +++ b/proj/unixsim/apps/tcpecho.c @@ -0,0 +1,88 @@ +/* + * 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 + * + */ + +#include "lwip/sys.h" +#include "lwip/api.h" +/*-----------------------------------------------------------------------------------*/ +static void +tcpecho_thread(void *arg) +{ + struct netconn *conn, *newconn; + err_t err; + + /* Create a new connection identifier. */ + conn = netconn_new(NETCONN_TCP); + + /* Bind connection to well known port number 7. */ + netconn_bind(conn, NULL, 7); + + /* Tell connection to go into listening mode. */ + netconn_listen(conn); + + while(1) { + + /* Grab new connection. */ + newconn = netconn_accept(conn); + /*printf("accepted new connection %p\n", newconn);*/ + /* Process the new connection. */ + if(newconn != NULL) { + struct netbuf *buf; + void *data; + u16_t len; + + while((buf = netconn_recv(newconn)) != NULL) { + /*printf("Recved\n");*/ + do { + netbuf_data(buf, &data, &len); + err = netconn_write(newconn, data, len, NETCONN_COPY); + if(err != ERR_OK) { + /* printf("tcpecho: netconn_write: error \"%s\"\n", lwip_strerr(err));*/ + } + } while(netbuf_next(buf) >= 0); + netbuf_delete(buf); + } + /*printf("Got EOF, looping\n");*/ + /* Close connection and discard connection identifier. */ + netconn_delete(newconn); + } + } +} +/*-----------------------------------------------------------------------------------*/ +void +tcpecho_init(void) +{ + sys_thread_new(tcpecho_thread, NULL); +} +/*-----------------------------------------------------------------------------------*/ + + + diff --git a/proj/unixsim/apps/tcpecho.h b/proj/unixsim/apps/tcpecho.h new file mode 100644 index 00000000..83318527 --- /dev/null +++ b/proj/unixsim/apps/tcpecho.h @@ -0,0 +1,38 @@ +/* + * 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 + * + */ + +#ifndef __TCPECHO_H__ +#define __TCPECHO_H__ + +void tcpecho_init(void); + +#endif /* __TCPECHO_H__ */ diff --git a/proj/unixsim/apps/udpecho.c b/proj/unixsim/apps/udpecho.c new file mode 100644 index 00000000..50239a0b --- /dev/null +++ b/proj/unixsim/apps/udpecho.c @@ -0,0 +1,65 @@ +/* + * 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 + * + */ + +#include "lwip/api.h" +#include "lwip/sys.h" + +/*-----------------------------------------------------------------------------------*/ +void +udpecho_thread(void *arg) +{ + static struct netconn *conn; + static struct netbuf *buf; + static struct ip_addr *addr; + static unsigned short port; + char buffer[4096]; + + conn = netconn_new(NETCONN_UDP); + netconn_bind(conn, NULL, 7); + + while(1) { + buf = netconn_recv(conn); + addr = netbuf_fromaddr(buf); + port = netbuf_fromport(buf); + netconn_connect(conn, addr, port); + netconn_send(conn, buf); + netbuf_copy(buf, buffer, sizeof(buffer)); + printf("got %s\n", buffer); + netbuf_delete(buf); + } +} +/*-----------------------------------------------------------------------------------*/ +void +udpecho_init(void) +{ + sys_thread_new(udpecho_thread, NULL); +} diff --git a/proj/unixsim/apps/udpecho.h b/proj/unixsim/apps/udpecho.h new file mode 100644 index 00000000..e955f981 --- /dev/null +++ b/proj/unixsim/apps/udpecho.h @@ -0,0 +1,37 @@ +/* + * 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 + * + */ +#ifndef __UDPECHO_H__ +#define __UDPECHO_H__ + +void udpecho_init(void); + +#endif /* __UDPECHO_H__ */ diff --git a/proj/unixsim/lwipopts.h b/proj/unixsim/lwipopts.h new file mode 100644 index 00000000..fcc19448 --- /dev/null +++ b/proj/unixsim/lwipopts.h @@ -0,0 +1,171 @@ +/* + * 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 + * + */ +#ifndef __LWIPOPTS_H__ +#define __LWIPOPTS_H__ + +/* ---------- 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. */ +#define MEM_ALIGNMENT 1 + +/* 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. */ +#define MEM_SIZE 1600 + +/* 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. */ +#define MEMP_NUM_PBUF 16 +/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + per active UDP "connection". */ +#define MEMP_NUM_UDP_PCB 4 +/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP + connections. */ +#define MEMP_NUM_TCP_PCB 5 +/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP + connections. */ +#define MEMP_NUM_TCP_PCB_LISTEN 8 +/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP + segments. */ +#define MEMP_NUM_TCP_SEG 16 +/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active + timeouts. */ +#define MEMP_NUM_SYS_TIMEOUT 3 + + +/* 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. */ +#define MEMP_NUM_NETBUF 2 +/* MEMP_NUM_NETCONN: the number of struct netconns. */ +#define MEMP_NUM_NETCONN 4 +/* MEMP_NUM_APIMSG: the number of struct api_msg, used for + communication between the TCP/IP stack and the sequential + programs. */ +#define MEMP_NUM_API_MSG 8 +/* 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. */ +#define MEMP_NUM_TCPIP_MSG 8 + +/* These two control is reclaimer functions should be compiled + in. Should always be turned on (1). */ +#define MEM_RECLAIM 1 +#define MEMP_RECLAIM 1 + +/* ---------- Pbuf options ---------- */ +/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ +#define PBUF_POOL_SIZE 6 + +/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ +#define PBUF_POOL_BUFSIZE 128 + +/* PBUF_LINK_HLEN: the number of bytes that should be allocated for a + link level header. */ +#define PBUF_LINK_HLEN 16 + +/* ---------- TCP options ---------- */ +#define LWIP_TCP 1 +#define TCP_TTL 255 + +/* Controls if TCP should queue segments that arrive out of + order. Define to 0 if your device is low on memory. */ +#define TCP_QUEUE_OOSEQ 1 + +/* TCP Maximum segment size. */ +#define TCP_MSS 128 + +/* TCP sender buffer space (bytes). */ +#define TCP_SND_BUF 256 + +/* TCP sender buffer space (pbufs). This must be at least = 2 * + TCP_SND_BUF/TCP_MSS for things to work. */ +#define TCP_SND_QUEUELEN 4 * TCP_SND_BUF/TCP_MSS + +/* TCP receive window. */ +#define TCP_WND 1024 + +/* Maximum number of retransmissions of data segments. */ +#define TCP_MAXRTX 12 + +/* Maximum number of retransmissions of SYN segments. */ +#define TCP_SYNMAXRTX 4 + +/* ---------- ARP options ---------- */ +#define ARP_TABLE_SIZE 10 + +/* ---------- 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. */ +#define IP_FORWARD 1 + +/* If defined to 1, IP options are allowed (but not parsed). If + defined to 0, all packets with IP options are dropped. */ +#define IP_OPTIONS 1 + +/* ---------- ICMP options ---------- */ +#define ICMP_TTL 255 + + +/* ---------- DHCP options ---------- */ +/* Define LWIP_DHCP to 1 if you want DHCP configuration of + interfaces. DHCP is not implemented in lwIP 0.5.1, however, so + turning this on does currently not work. */ +#define LWIP_DHCP 0 + +/* 1 if you want to do an ARP check on the offered address + (recommended). */ +#define DHCP_DOES_ARP_CHECK 1 + +/* ---------- UDP options ---------- */ +#define LWIP_UDP 1 +#define UDP_TTL 255 + + +/* ---------- Statistics options ---------- */ +#define STATS + +#ifdef STATS +#define LINK_STATS +#define IP_STATS +#define ICMP_STATS +#define UDP_STATS +#define TCP_STATS +#define MEM_STATS +#define MEMP_STATS +#define PBUF_STATS +#define SYS_STATS +#endif /* STATS */ + +#endif /* __LWIPOPTS_H__ */ diff --git a/proj/unixsim/simhost.c b/proj/unixsim/simhost.c new file mode 100644 index 00000000..08590037 --- /dev/null +++ b/proj/unixsim/simhost.c @@ -0,0 +1,189 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" + +#include + +#include "lwip/opt.h" + +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/sys.h" + +#include "lwip/stats.h" + + +#include "lwip/tcpip.h" + +#include "netif/tapif.h" +#include "netif/tunif.h" + +#include "netif/unixif.h" +#include "netif/dropif.h" +#include "netif/pcapif.h" +#include "netif/loopif.h" + +#include "netif/tcpdump.h" + + + + +#include "lwip/ip_addr.h" + +#include "arch/perf.h" + +#include "httpd.h" +#include "udpecho.h" +#include "tcpecho.h" +#include "shell.h" + +/*-----------------------------------------------------------------------------------*/ +static void +tcp_timeout(void *data) +{ +#if TCP_DEBUG + tcp_debug_print_pcbs(); +#endif /* TCP_DEBUG */ + sys_timeout(5000, tcp_timeout, NULL); +} +/*-----------------------------------------------------------------------------------*/ +static void +tcpip_init_done(void *arg) +{ + sys_sem_t *sem; + sem = arg; + sys_sem_signal(*sem); +} +/*-----------------------------------------------------------------------------------*/ +static void +main_thread(void *arg) +{ + struct ip_addr ipaddr, netmask, gw; + sys_sem_t sem; + + netif_init(); + + sem = sys_sem_new(0); + tcpip_init(tcpip_init_done, &sem); + sys_sem_wait(sem); + sys_sem_free(sem); + printf("TCP/IP initialized.\n"); + +#if LWIP_DHCP + { + struct netif *netif; + IP4_ADDR(&gw, 0,0,0,0); + IP4_ADDR(&ipaddr, 0,0,0,0); + IP4_ADDR(&netmask, 0,0,0,0); + + netif = netif_add(&ipaddr, &netmask, &gw, tapif_init, + tcpip_input); + netif_set_default(netif); + dhcp_init(); + dhcp_start(netif); + } +#else + IP4_ADDR(&gw, 192,168,0,1); + IP4_ADDR(&ipaddr, 192,168,0,2); + IP4_ADDR(&netmask, 255,255,255,0); + + /* netif_set_default(netif_add(&ipaddr, &netmask, &gw, tapif_init, + tcpip_input));*/ + netif_set_default(netif_add(&ipaddr, &netmask, &gw, tapif_init, + tcpip_input)); +#endif + /* Only used for testing purposes: */ + /* IP4_ADDR(&gw, 193,10,66,1); + IP4_ADDR(&ipaddr, 193,10,66,107); + IP4_ADDR(&netmask, 255,255,252,0); + + netif_add(&ipaddr, &netmask, &gw, pcapif_init, + tcpip_input);*/ + + IP4_ADDR(&gw, 127,0,0,1); + IP4_ADDR(&ipaddr, 127,0,0,1); + IP4_ADDR(&netmask, 255,0,0,0); + + netif_add(&ipaddr, &netmask, &gw, loopif_init, + tcpip_input); + + tcpecho_init(); + shell_init(); + httpd_init(); + udpecho_init(); + + printf("Applications started.\n"); + + /* sys_timeout(5000, tcp_timeout, NULL);*/ + +#ifdef MEM_PERF + mem_perf_init("/tmp/memstats.client"); +#endif /* MEM_PERF */ + + /* Block for ever. */ + sem = sys_sem_new(0); + sys_sem_wait(sem); +} +/*-----------------------------------------------------------------------------------*/ +int +main(int argc, char **argv) +{ +#ifdef PERF + perf_init("/tmp/simhost.perf"); +#endif /* PERF */ +#ifdef STATS + stats_init(); +#endif /* STATS */ + sys_init(); + mem_init(); + memp_init(); + pbuf_init(); + + tcpdump_init(); + + + printf("System initialized.\n"); + + sys_thread_new((void *)(main_thread), NULL); + pause(); + return 0; +} +/*-----------------------------------------------------------------------------------*/ + + + + + + + + diff --git a/proj/unixsim/simnode.c b/proj/unixsim/simnode.c new file mode 100644 index 00000000..f20fa18f --- /dev/null +++ b/proj/unixsim/simnode.c @@ -0,0 +1,157 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" + +#include + + +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/sys.h" + +#include "lwip/stats.h" + + +#include "lwip/tcpip.h" + + +#include "netif/unixif.h" +#include "netif/dropif.h" + +#include "netif/loopif.h" + +#include "netif/tcpdump.h" + +#include "netif/sioslipif.h" + + +#include "lwip/ip_addr.h" + +#include "arch/perf.h" + +#include "httpd.h" +#include "udpecho.h" +#include "tcpecho.h" +#include "shell.h" + +/*-----------------------------------------------------------------------------------*/ +static void +tcp_timeout(void *data) +{ +#if TCP_DEBUG + tcp_debug_print_pcbs(); +#endif /* TCP_DEBUG */ + sys_timeout(5000, tcp_timeout, NULL); +} +/*-----------------------------------------------------------------------------------*/ +static void +tcpip_init_done(void *arg) +{ + sys_sem_t *sem; + sem = arg; + sys_sem_signal(*sem); +} +/*-----------------------------------------------------------------------------------*/ +static void +main_thread(void *arg) +{ + struct ip_addr ipaddr, netmask, gw; + sys_sem_t sem; + + + IP4_ADDR(&gw, 192,168,1,1); + IP4_ADDR(&ipaddr, 192,168,1,2); + IP4_ADDR(&netmask, 255,255,255,0); + + netif_set_default(netif_add(&ipaddr, &netmask, &gw, unixif_init_client, + tcpip_input)); + /* netif_set_default(netif_add(&ipaddr, &netmask, &gw, sioslipif_init1, + tcpip_input)); */ + + + sem = sys_sem_new(0); + tcpip_init(tcpip_init_done, &sem); + sys_sem_wait(sem); + sys_sem_free(sem); + printf("TCP/IP initialized.\n"); + + tcpecho_init(); + shell_init(); + httpd_init(); + udpecho_init(); + + printf("Applications started.\n"); + + sys_timeout(5000, tcp_timeout, NULL); + +#ifdef MEM_PERF + mem_perf_init("/tmp/memstats.client"); +#endif /* MEM_PERF */ + + sem = sys_sem_new(0); + sys_sem_wait(sem); + +} +/*-----------------------------------------------------------------------------------*/ +int +main(int argc, char **argv) +{ +#ifdef PERF + perf_init("/tmp/client.perf"); +#endif /* PERF */ +#ifdef STATS + stats_init(); +#endif /* STATS */ + sys_init(); + mem_init(); + memp_init(); + pbuf_init(); + + tcpdump_init(); + + + printf("System initialized.\n"); + + sys_thread_new((void *)(main_thread), NULL); + pause(); + return 0; +} +/*-----------------------------------------------------------------------------------*/ + + + + + + + + diff --git a/proj/unixsim/simrouter.c b/proj/unixsim/simrouter.c new file mode 100644 index 00000000..bd43aa48 --- /dev/null +++ b/proj/unixsim/simrouter.c @@ -0,0 +1,167 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" + +#include + + +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/sys.h" + +#include "lwip/stats.h" + + +#include "lwip/tcpip.h" + +#include "netif/tapif.h" + +#include "netif/unixif.h" +#include "netif/dropif.h" + +#include "netif/loopif.h" + +#include "netif/tcpdump.h" + +#include "netif/sioslipif.h" + + +#include "lwip/ip_addr.h" + +#include "arch/perf.h" + +#include "httpd.h" +#include "udpecho.h" +#include "tcpecho.h" +#include "shell.h" + +/*-----------------------------------------------------------------------------------*/ +static void +tcp_timeout(void *data) +{ +#if TCP_DEBUG + tcp_debug_print_pcbs(); +#endif /* TCP_DEBUG */ + sys_timeout(5000, tcp_timeout, NULL); +} +/*-----------------------------------------------------------------------------------*/ +static void +tcpip_init_done(void *arg) +{ + sys_sem_t *sem; + sem = arg; + sys_sem_signal(*sem); +} +/*-----------------------------------------------------------------------------------*/ +static void +main_thread(void *arg) +{ + struct ip_addr ipaddr, netmask, gw; + sys_sem_t sem; + + + IP4_ADDR(&gw, 192,168,0,1); + IP4_ADDR(&ipaddr, 192,168,0,2); + IP4_ADDR(&netmask, 255,255,255,0); + + netif_set_default(netif_add(&ipaddr, &netmask, &gw, tapif_init, + tcpip_input)); + + IP4_ADDR(&gw, 192,168,1,1); + IP4_ADDR(&ipaddr, 192,168,1,1); + IP4_ADDR(&netmask, 255,255,255,0); + netif_set_default(netif_add(&ipaddr, &netmask, &gw, unixif_init_server, + tcpip_input)); + + system("route add 192.168.1.1 192.168.0.2"); + system("route add 192.168.1.2 192.168.0.2"); + + + /*netif_set_default(netif_add(&ipaddr, &netmask, &gw, sioslipif_init1, + tcpip_input)); */ + + + sem = sys_sem_new(0); + tcpip_init(tcpip_init_done, &sem); + sys_sem_wait(sem); + sys_sem_free(sem); + printf("TCP/IP initialized.\n"); + + tcpecho_init(); + shell_init(); + httpd_init(); + udpecho_init(); + + printf("Applications started.\n"); + + sys_timeout(5000, tcp_timeout, NULL); + +#ifdef MEM_PERF + mem_perf_init("/tmp/memstats.client"); +#endif /* MEM_PERF */ + sem = sys_sem_new(0); + sys_sem_wait(sem); +} +/*-----------------------------------------------------------------------------------*/ +int +main(int argc, char **argv) +{ +#ifdef PERF + perf_init("/tmp/client.perf"); +#endif /* PERF */ +#ifdef STATS + stats_init(); +#endif /* STATS */ + sys_init(); + mem_init(); + memp_init(); + pbuf_init(); + + tcpdump_init(); + + + printf("System initialized.\n"); + + sys_thread_new((void *)(main_thread), NULL); + pause(); + return 0; +} +/*-----------------------------------------------------------------------------------*/ + + + + + + + + diff --git a/src/FILES b/src/FILES new file mode 100644 index 00000000..c66ca36d --- /dev/null +++ b/src/FILES @@ -0,0 +1,13 @@ +api/ - The code for the API. + +arch/ - Architectural specific files are kept here. + +core/ - The core files including protocol implementations, memory + and buffer management etc. + +include/ - lwIP include files. + +netif/ - Generic network interface device drivers are kept here. + +For more information on the various subdirectories, check the FILES +file in each directory. diff --git a/src/api/api_lib.c b/src/api/api_lib.c new file mode 100644 index 00000000..da2def30 --- /dev/null +++ b/src/api/api_lib.c @@ -0,0 +1,639 @@ +/* + * 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 + * + */ + +/* This is the part of the API that is linked with + the application */ + +#include "lwip/debug.h" +#include "lwip/api.h" +#include "lwip/api_msg.h" +#include "lwip/memp.h" + +#include "lwip/debug.h" + +/*-----------------------------------------------------------------------------------*/ +struct +netbuf *netbuf_new(void) +{ + struct netbuf *buf; + + buf = memp_mallocp(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_freep(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_ROM); + 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_freep(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) { + 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(enum netconn_type t) +{ + struct netconn *conn; + + conn = memp_mallocp(MEMP_NETCONN); + if(conn == NULL) { + return NULL; + } + conn->type = t; + conn->pcb.tcp = NULL; + + if((conn->mbox = sys_mbox_new()) == SYS_MBOX_NULL) { + memp_freep(MEMP_NETCONN, conn); + return NULL; + } + conn->recvmbox = SYS_MBOX_NULL; + conn->acceptmbox = SYS_MBOX_NULL; + conn->sem = SYS_SEM_NULL; + conn->state = NETCONN_NONE; + return conn; +} +/*-----------------------------------------------------------------------------------*/ +err_t +netconn_delete(struct netconn *conn) +{ + struct api_msg *msg; + void *mem; + + if(conn == NULL) { + return ERR_OK; + } + + if((msg = memp_mallocp(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_freep(MEMP_API_MSG, msg); + + /* Drain the recvmbox. */ + if(conn->recvmbox != SYS_MBOX_NULL) { + while(sys_arch_mbox_fetch(conn->recvmbox, &mem, 1) != 0) { + if(conn->type == NETCONN_TCP) { + 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) != 0) { + 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_UDPLITE: + case NETCONN_UDPNOCHKSUM: + case NETCONN_UDP: + *addr = &(conn->pcb.udp->remote_ip); + *port = conn->pcb.udp->remote_port; + break; + case NETCONN_TCP: + *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_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_mallocp(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_freep(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_mallocp(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_freep(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_mallocp(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_freep(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); + + return newconn; +} +/*-----------------------------------------------------------------------------------*/ +struct netbuf * +netconn_recv(struct netconn *conn) +{ + struct api_msg *msg; + struct netbuf *buf; + struct pbuf *p; + + 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_mallocp(MEMP_NETBUF); + + if(buf == NULL) { + conn->err = ERR_MEM; + return NULL; + } + + sys_mbox_fetch(conn->recvmbox, (void **)&p); + + /* If we are closed, we indicate that we no longer wish to recieve + data by setting conn->recvmbox to SYS_MBOX_NULL. */ + if(p == NULL) { + memp_freep(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_mallocp(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_freep(MEMP_API_MSG, msg); + } else { + sys_mbox_fetch(conn->recvmbox, (void **)&buf); + } + + + + + DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", 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_mallocp(MEMP_API_MSG)) == NULL) { + return (conn->err = ERR_MEM); + } + + 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_freep(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_mallocp(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; + } + + 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_freep(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_mallocp(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_freep(MEMP_API_MSG, msg); + return conn->err; +} +/*-----------------------------------------------------------------------------------*/ +err_t +netconn_err(struct netconn *conn) +{ + return conn->err; +} +/*-----------------------------------------------------------------------------------*/ + + + + diff --git a/src/api/api_msg.c b/src/api/api_msg.c new file mode 100644 index 00000000..a914ff31 --- /dev/null +++ b/src/api/api_msg.c @@ -0,0 +1,544 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" +#include "lwip/arch.h" +#include "lwip/api_msg.h" +#include "lwip/memp.h" +#include "lwip/sys.h" +#include "lwip/tcpip.h" + +/*-----------------------------------------------------------------------------------*/ +static err_t +recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + struct netconn *conn; + + conn = arg; + + if(conn == NULL) { + pbuf_free(p); + return ERR_VAL; + } + + if(conn->recvmbox != SYS_MBOX_NULL) { + conn->err = err; + sys_mbox_post(conn->recvmbox, p); + } + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +#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; + + conn = arg; + + if(conn == NULL) { + pbuf_free(p); + return; + } + + if(conn->recvmbox != SYS_MBOX_NULL) { + buf = memp_mallocp(MEMP_NETBUF); + if(buf == NULL) { + pbuf_free(p); + return; + } else { + buf->p = p; + buf->ptr = p; + buf->fromaddr = addr; + buf->fromport = port; + } + + sys_mbox_post(conn->recvmbox, buf); + } +} +#endif /* LWIP_UDP */ +/*-----------------------------------------------------------------------------------*/ +static err_t +poll_tcp(void *arg, struct tcp_pcb *pcb) +{ + struct netconn *conn; + + 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; + + conn = arg; + if(conn != NULL && conn->sem != SYS_SEM_NULL) { + sys_sem_signal(conn->sem); + } + 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) { + sys_mbox_post(conn->recvmbox, NULL); + } + if(conn->mbox != SYS_MBOX_NULL) { + sys_mbox_post(conn->mbox, NULL); + } + if(conn->acceptmbox != SYS_MBOX_NULL) { + 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; + +#if API_MSG_DEBUG +#if TCP_DEBUG + tcp_debug_print_state(newpcb->state); +#endif /* TCP_DEBUG */ +#endif /* API_MSG_DEBUG */ + mbox = (sys_mbox_t *)arg; + newconn = memp_mallocp(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; + sys_mbox_post(*mbox, newconn); + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +static void +do_newconn(struct api_msg_msg *msg) +{ +} +/*-----------------------------------------------------------------------------------*/ +static void +do_delconn(struct api_msg_msg *msg) +{ + if(msg->conn->pcb.tcp != NULL) { + switch(msg->conn->type) { +#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 */ + case NETCONN_TCP: + if(msg->conn->pcb.tcp->state == LISTEN) { + 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); + } + } + break; + } + } + 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_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 */ + case NETCONN_TCP: + msg->conn->pcb.tcp = tcp_new(); + setup_tcp(msg->conn); + break; + } + } + switch(msg->conn->type) { +#if LWIP_UDP + case NETCONN_UDPLITE: + /* FALLTHROUGH */ + case NETCONN_UDPNOCHKSUM: + /* FALLTHROUGH */ + case NETCONN_UDP: + udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); + break; +#endif /* LWIP_UDP */ + case NETCONN_TCP: + msg->conn->err = tcp_bind(msg->conn->pcb.tcp, + msg->msg.bc.ipaddr, msg->msg.bc.port); + break; + } + sys_mbox_post(msg->conn->mbox, NULL); +} +/*-----------------------------------------------------------------------------------*/ +static err_t +do_connected(void *arg, struct tcp_pcb *pcb, err_t err) +{ + struct netconn *conn; + + 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; +} +/*-----------------------------------------------------------------------------------*/ +static void +do_connect(struct api_msg_msg *msg) +{ + if(msg->conn->pcb.tcp == NULL) { + switch(msg->conn->type) { +#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 */ + 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; + } + break; + } + } + switch(msg->conn->type) { +#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 + 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);*/ + break; + } +} +/*-----------------------------------------------------------------------------------*/ +static void +do_listen(struct api_msg_msg *msg) +{ + if(msg->conn->pcb.tcp != NULL) { + switch(msg->conn->type) { +#if LWIP_UDP + case NETCONN_UDPLITE: + /* FALLTHROUGH */ + case NETCONN_UDPNOCHKSUM: + /* FALLTHROUGH */ + case NETCONN_UDP: + DEBUGF(API_MSG_DEBUG, ("api_msg: listen UDP: cannot listen for UDP.\n")); + break; +#endif /* LWIP_UDP */ + 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, (void *)&(msg->conn->acceptmbox)); + tcp_accept(msg->conn->pcb.tcp, accept_function); + } + 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_UDP + case NETCONN_UDPLITE: + /* FALLTHROUGH */ + case NETCONN_UDPNOCHKSUM: + /* FALLTHROUGH */ + case NETCONN_UDP: + 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_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(msg->conn->pcb.tcp != NULL) { + if(msg->conn->type == NETCONN_TCP) { + tcp_recved(msg->conn->pcb.tcp, msg->msg.len); + } + } + sys_mbox_post(msg->conn->mbox, NULL); +} +/*-----------------------------------------------------------------------------------*/ +static void +do_write(struct api_msg_msg *msg) +{ + err_t err; + if(msg->conn->pcb.tcp != NULL) { + switch(msg->conn->type) { +#if LWIP_UDP + case NETCONN_UDPLITE: + /* FALLTHROUGH */ + case NETCONN_UDPNOCHKSUM: + /* FALLTHROUGH */ + case NETCONN_UDP: + msg->conn->err = ERR_VAL; + break; +#endif /* LWIP_UDP */ + 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) { + tcp_output(msg->conn->pcb.tcp); + } + msg->conn->err = err; + break; + } + } + sys_mbox_post(msg->conn->mbox, NULL); +} +/*-----------------------------------------------------------------------------------*/ +static void +do_close(struct api_msg_msg *msg) +{ + err_t err; + if(msg->conn->pcb.tcp != NULL) { + switch(msg->conn->type) { +#if LWIP_UDP + case NETCONN_UDPLITE: + /* FALLTHROUGH */ + case NETCONN_UDPNOCHKSUM: + /* FALLTHROUGH */ + case NETCONN_UDP: + break; +#endif /* LWIP_UDP */ + case NETCONN_TCP: + if(msg->conn->pcb.tcp->state == LISTEN) { + err = tcp_close(msg->conn->pcb.tcp); + } + msg->conn->err = err; + 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_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); +} +/*-----------------------------------------------------------------------------------*/ + + diff --git a/src/api/err.c b/src/api/err.c new file mode 100644 index 00000000..b9aca8d5 --- /dev/null +++ b/src/api/err.c @@ -0,0 +1,59 @@ +/* + * 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 + * + */ + +#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 */ diff --git a/src/api/sockets.c b/src/api/sockets.c new file mode 100644 index 00000000..93761c0e --- /dev/null +++ b/src/api/sockets.c @@ -0,0 +1,441 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" +#include "lwip/api.h" + +#include "lwip/sockets.h" + +#define NUM_SOCKETS 10 + +struct lwip_socket { + struct netconn *conn; + struct netbuf *lastdata; + u16_t lastoffset; +}; + +static struct lwip_socket sockets[NUM_SOCKETS]; + +/*-----------------------------------------------------------------------------------*/ +static struct lwip_socket * +get_socket(int s) +{ + struct lwip_socket *sock; + + if(s > NUM_SOCKETS) { + /* errno = EBADF; */ + return NULL; + } + + sock = &sockets[s]; + + if(sock->conn == NULL) { + /* errno = EBADF; */ + return NULL; + } + return sock; +} +/*-----------------------------------------------------------------------------------*/ +static int +alloc_socket(struct netconn *newconn) +{ + int i; + + /* allocate a new socket identifier */ + for(i = 0; i < NUM_SOCKETS; ++i) { + if(sockets[i].conn == NULL) { + sockets[i].conn = newconn; + sockets[i].lastdata = NULL; + sockets[i].lastoffset = 0; + return i; + } + } + return -1; +} +/*-----------------------------------------------------------------------------------*/ +int +lwip_accept(int s, struct sockaddr *addr, int *addrlen) +{ + struct lwip_socket *sock; + struct netconn *newconn; + struct ip_addr *naddr; + u16_t port; + int newsock; + + sock = get_socket(s); + if(sock == NULL) { + return -1; + } + + newconn = netconn_accept(sock->conn); + + /* get the IP address and port of the remote host */ + netconn_peer(newconn, &naddr, &port); + + ((struct sockaddr_in *)addr)->sin_addr.s_addr = naddr->addr; + ((struct sockaddr_in *)addr)->sin_port = port; + + newsock = alloc_socket(newconn); + if(newsock == -1) { + netconn_delete(newconn); + /* errno = ENOBUFS; */ + } + return newsock; +} +/*-----------------------------------------------------------------------------------*/ +int +lwip_bind(int s, struct sockaddr *name, int namelen) +{ + struct lwip_socket *sock; + struct ip_addr remote_addr; + u16_t remote_port; + err_t err; + + sock = get_socket(s); + if(sock == NULL) { + return -1; + } + + remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr; + remote_port = ((struct sockaddr_in *)name)->sin_port; + + err = netconn_bind(sock->conn, &remote_addr, ntohs(remote_port)); + + if(err != ERR_OK) { + /* errno = ... */ + return -1; + } + + return 0; +} +/*-----------------------------------------------------------------------------------*/ +int +lwip_close(int s) +{ + struct lwip_socket *sock; + + DEBUGF(SOCKETS_DEBUG, ("close: socket %d\n", s)); + sock = get_socket(s); + if(sock == NULL) { + return -1; + } + + + netconn_delete(sock->conn); + if(sock->lastdata != NULL) { + netbuf_delete(sock->lastdata); + } + sock->lastdata = NULL; + sock->lastoffset = 0; + sock->conn = NULL; + return 0; +} +/*-----------------------------------------------------------------------------------*/ +int +lwip_connect(int s, struct sockaddr *name, int namelen) +{ + struct lwip_socket *sock; + struct ip_addr remote_addr; + u16_t remote_port; + err_t err; + + sock = get_socket(s); + if(sock == NULL) { + return -1; + } + + remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr; + remote_port = ((struct sockaddr_in *)name)->sin_port; + + err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); + + if(err != ERR_OK) { + /* errno = ... */ + return -1; + } + + return 0; +} +/*-----------------------------------------------------------------------------------*/ +int +lwip_listen(int s, int backlog) +{ + struct lwip_socket *sock; + err_t err; + + sock = get_socket(s); + if(sock == NULL) { + return -1; + } + + err = netconn_listen(sock->conn); + + if(err != ERR_OK) { + /* errno = ... */ + return -1; + } + + return 0; +} +/*-----------------------------------------------------------------------------------*/ +int +lwip_recvfrom(int s, void *mem, int len, unsigned int flags, + struct sockaddr *from, int *fromlen) +{ + struct lwip_socket *sock; + struct netbuf *buf; + u16_t buflen, copylen; + struct ip_addr *addr; + u16_t port; + + + sock = get_socket(s); + if(sock == NULL) { + return -1; + } + + /* Check if there is data left from the last recv operation. */ + if(sock->lastdata != NULL) { + buf = sock->lastdata; + } else { + /* No data was left from the previous operation, so we try to get + some from the network. */ + buf = netconn_recv(sock->conn); + + if(buf == NULL) { + /* We should really do some error checking here. */ + return 0; + } + } + + buflen = netbuf_len(buf); + + buflen -= sock->lastoffset; + + if(len > buflen) { + copylen = buflen; + } else { + copylen = len; + } + + /* copy the contents of the received buffer into + the supplied memory pointer mem */ + netbuf_copy_partial(buf, mem, copylen, sock->lastoffset); + + /* If this is a TCP socket, check if there is data left in the + buffer. If so, it should be saved in the sock structure for next + time around. */ + if(netconn_type(sock->conn) == NETCONN_TCP && buflen - copylen > 0) { + sock->lastdata = buf; + sock->lastoffset += copylen; + } else { + sock->lastdata = NULL; + sock->lastoffset = 0; + netbuf_delete(buf); + } + + /* Check to see from where the data was. */ + if(from != NULL && fromlen != NULL) { + addr = netbuf_fromaddr(buf); + port = netbuf_fromport(buf); + ((struct sockaddr_in *)from)->sin_addr.s_addr = addr->addr; + ((struct sockaddr_in *)from)->sin_port = port; + *fromlen = sizeof(struct sockaddr_in); + } + + + /* if the length of the received data is larger than + len, this data is discarded and we return len. + otherwise we return the actual length of the received + data */ + if(len > copylen) { + return copylen; + } else { + return len; + } +} +/*-----------------------------------------------------------------------------------*/ +int +lwip_read(int s, void *mem, int len) +{ + return lwip_recv(s, mem, len, 0); +} +/*-----------------------------------------------------------------------------------*/ +int +lwip_recv(int s, void *mem, int len, unsigned int flags) +{ + return lwip_recvfrom(s, mem, len, flags, NULL, NULL); +} +/*-----------------------------------------------------------------------------------*/ +int +lwip_send(int s, void *data, int size, unsigned int flags) +{ + struct lwip_socket *sock; + struct netbuf *buf; + err_t err; + + DEBUGF(SOCKETS_DEBUG, ("send: socket %d, size %d\n", s, size)); + + sock = get_socket(s); + if(sock == NULL) { + return -1; + } + + switch(netconn_type(sock->conn)) { + case NETCONN_UDP: + /* create a buffer */ + buf = netbuf_new(); + + if(buf == NULL) { + /* errno = ENOBUFS; */ + return -1; + } + + /* make the buffer point to the data that should + be sent */ + netbuf_ref(buf, data, size); + + /* send the data */ + err = netconn_send(sock->conn, buf); + + /* deallocated the buffer */ + netbuf_delete(buf); + break; + case NETCONN_TCP: + err = netconn_write(sock->conn, data, size, NETCONN_COPY); + break; + default: + err = ERR_ARG; + break; + } + if(err != ERR_OK) { + /* errno = ... */ + return -1; + } + + return size; +} +/*-----------------------------------------------------------------------------------*/ +int +lwip_sendto(int s, void *data, int size, unsigned int flags, + struct sockaddr *to, int tolen) +{ + struct lwip_socket *sock; + struct ip_addr remote_addr, *addr; + u16_t remote_port, port; + int ret; + + sock = get_socket(s); + if(sock == NULL) { + return -1; + } + + /* get the peer if currently connected */ + netconn_peer(sock->conn, &addr, &port); + + remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr; + remote_port = ((struct sockaddr_in *)to)->sin_port; + netconn_connect(sock->conn, &remote_addr, remote_port); + + ret = lwip_send(s, data, size, flags); + + /* reset the remote address and port number + of the connection */ + netconn_connect(sock->conn, addr, port); + return ret; +} +/*-----------------------------------------------------------------------------------*/ +int +lwip_socket(int domain, int type, int protocol) +{ + struct netconn *conn; + int i; + + /* create a netconn */ + switch(type) { + case SOCK_DGRAM: + conn = netconn_new(NETCONN_UDP); + break; + case SOCK_STREAM: + conn = netconn_new(NETCONN_TCP); + break; + default: + /* errno = ... */ + return -1; + } + + if(conn == NULL) { + DEBUGF(SOCKETS_DEBUG, ("socket: could not create netconn.\n")); + /* errno = ENOBUFS; */ + return -1; + } + + i = alloc_socket(conn); + + if(i == -1) { + /* errno = ENOBUFS; */ + netconn_delete(conn); + } + return i; +} +/*-----------------------------------------------------------------------------------*/ +int +lwip_write(int s, void *data, int size) +{ + struct lwip_socket *sock; + err_t err; + + DEBUGF(SOCKETS_DEBUG, ("write: socket %d, size %d\n", s, size)); + + sock = get_socket(s); + if(sock == NULL) { + return -1; + } + + switch(netconn_type(sock->conn)) { + case NETCONN_UDP: + return lwip_send(s, data, size, 0); + + case NETCONN_TCP: + err = netconn_write(sock->conn, data, size, NETCONN_COPY); + break; + default: + err = ERR_ARG; + break; + } + if(err != ERR_OK) { + /* errno = ... */ + return -1; + } + return size; +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/api/tcpip.c b/src/api/tcpip.c new file mode 100644 index 00000000..bc3fd2cf --- /dev/null +++ b/src/api/tcpip.c @@ -0,0 +1,137 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" + +#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; + +/*-----------------------------------------------------------------------------------*/ +static void +tcpip_tcp_timer(void *arg) +{ + tcp_tmr(); + sys_timeout(TCP_TMR_INTERVAL, (sys_timeout_handler)tcpip_tcp_timer, NULL); +} +/*-----------------------------------------------------------------------------------*/ + +static void +tcpip_thread(void *arg) +{ + struct tcpip_msg *msg; + + ip_init(); + udp_init(); + tcp_init(); + + sys_timeout(TCP_TMR_INTERVAL, (sys_timeout_handler)tcpip_tcp_timer, NULL); + + 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: + DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", msg)); + api_msg_input(msg->msg.apimsg); + break; + case TCPIP_MSG_INPUT: + DEBUGF(TCPIP_DEBUG, ("tcpip_thread: IP packet %p\n", msg)); + ip_input(msg->msg.inp.p, msg->msg.inp.netif); + break; + default: + break; + } + memp_freep(MEMP_TCPIP_MSG, msg); + } +} +/*-----------------------------------------------------------------------------------*/ +err_t +tcpip_input(struct pbuf *p, struct netif *inp) +{ + struct tcpip_msg *msg; + + msg = memp_mallocp(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; +} +/*-----------------------------------------------------------------------------------*/ +void +tcpip_apimsg(struct api_msg *apimsg) +{ + struct tcpip_msg *msg; + msg = memp_mallocp(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((void *)tcpip_thread, NULL); +} +/*-----------------------------------------------------------------------------------*/ + + + diff --git a/src/arch/6502/README b/src/arch/6502/README new file mode 100644 index 00000000..2e249000 --- /dev/null +++ b/src/arch/6502/README @@ -0,0 +1 @@ +The 6502 code is far from complete. diff --git a/src/arch/6502/include/arch/cc.h b/src/arch/6502/include/arch/cc.h new file mode 100644 index 00000000..3f88973b --- /dev/null +++ b/src/arch/6502/include/arch/cc.h @@ -0,0 +1,47 @@ +/* + * 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 + * + */ +#ifndef __CC_H__ +#define __CC_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; + +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_STRUCT +#define PACK_STRUCT_END +#define PACK_STRUCT_FIELD(x) x + +#endif /* __CC_H__ */ diff --git a/src/arch/6502/include/arch/cpu.h b/src/arch/6502/include/arch/cpu.h new file mode 100644 index 00000000..4439e1c5 --- /dev/null +++ b/src/arch/6502/include/arch/cpu.h @@ -0,0 +1,37 @@ +/* + * 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 + * + */ +#ifndef __CPU_H__ +#define __CPU_H__ + +#define BYTE_ORDER LITTLE_ENDIAN + +#endif /* __CPU_H__ */ diff --git a/src/arch/6502/include/arch/lib.h b/src/arch/6502/include/arch/lib.h new file mode 100644 index 00000000..89d1c4a3 --- /dev/null +++ b/src/arch/6502/include/arch/lib.h @@ -0,0 +1,40 @@ +/* + * 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 + * + */ +#ifndef __LIB_H__ +#define __LIB_H__ + +int strlen(const char *str); +int strncmp(const char *str1, const char *str2, int len); +void bcopy(const void *src, void *dest, int len); +void bzero(void *data, int n); + +#endif /* __LIB_H__ */ diff --git a/src/arch/6502/include/arch/perf.h b/src/arch/6502/include/arch/perf.h new file mode 100644 index 00000000..55a1ff4f --- /dev/null +++ b/src/arch/6502/include/arch/perf.h @@ -0,0 +1,38 @@ +/* + * 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 + * + */ +#ifndef __PERF_H__ +#define __PERF_H__ + +#define PERF_START /* null definition */ +#define PERF_STOP(x) /* null definition */ + +#endif /* __PERF_H__ */ diff --git a/src/arch/6502/include/arch/sys_arch.h b/src/arch/6502/include/arch/sys_arch.h new file mode 100644 index 00000000..99a24925 --- /dev/null +++ b/src/arch/6502/include/arch/sys_arch.h @@ -0,0 +1,41 @@ +/* + * 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 + * + */ +#ifndef __SYS_C64_H__ +#define __SYS_C64_H__ + +#define SYS_MBOX_NULL 0 + +typedef int sys_sem_t; +typedef int sys_mbox_t; +typedef int sys_thread_t; + +#endif /* __SYS_C64_H__ */ diff --git a/src/arch/6502/lib_arch.c b/src/arch/6502/lib_arch.c new file mode 100644 index 00000000..a523166a --- /dev/null +++ b/src/arch/6502/lib_arch.c @@ -0,0 +1,63 @@ +/* + * 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 + * + */ + +/* These are generic implementations of various library functions used + * throughout the lwIP code. When porting, those should be optimized + * for the particular processor architecture, preferably coded in + * assembler. + */ + +#include "lwip/arch.h" + +/*-----------------------------------------------------------------------------------*/ +void +bcopy(const void *src, void *dst, unsigned int size) +{ + char *csrc, *cdst; + unsigned int i; + + csrc = (char *)src; + cdst = dst; + + for(i = 0; i < size; ++i) { + cdst[i] = csrc[i]; + } +} +/*-----------------------------------------------------------------------------------*/ +void +bzero(void *s, int n) +{ + for(--n ;n >= 0; --n) { + ((char *)s)[n] = 0; + } +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/arch/6502/sys_c64.c b/src/arch/6502/sys_c64.c new file mode 100644 index 00000000..eeb639a9 --- /dev/null +++ b/src/arch/6502/sys_c64.c @@ -0,0 +1,120 @@ +/* + * 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 + * + */ + +#include +#include + +#include "lwip/sys.h" +#include "lwip/def.h" + +struct sys_timeouts timeouts; + +/*-----------------------------------------------------------------------------------*/ +void +sys_arch_block(u16_t time) +{ + u16_t ticks; + + ticks = time * (CLK_TCK / 1000) + clock(); + printf("ticks %d\n", ticks); + + while(clock() != ticks); +} +/*-----------------------------------------------------------------------------------*/ +sys_mbox_t +sys_mbox_new(void) +{ + return SYS_MBOX_NULL; +} +/*-----------------------------------------------------------------------------------*/ +void +sys_mbox_free(sys_mbox_t mbox) +{ + return; +} +/*-----------------------------------------------------------------------------------*/ +void +sys_mbox_post(sys_mbox_t mbox, void *data) +{ + return; +} +/*-----------------------------------------------------------------------------------*/ +u16_t +sys_arch_mbox_fetch(sys_mbox_t mbox, void **data, u16_t timeout) +{ + sys_arch_block(timeout); + return 0; +} +/*-----------------------------------------------------------------------------------*/ +sys_sem_t +sys_sem_new(u8_t count) +{ + return 0; +} +/*-----------------------------------------------------------------------------------*/ +u16_t +sys_arch_sem_wait(sys_sem_t sem, u16_t timeout) +{ + sys_arch_block(timeout); + return 0; +} +/*-----------------------------------------------------------------------------------*/ +void +sys_sem_signal(sys_sem_t sem) +{ + return; +} +/*-----------------------------------------------------------------------------------*/ +void +sys_sem_free(sys_sem_t sem) +{ + return; +} +/*-----------------------------------------------------------------------------------*/ +void +sys_init(void) +{ + timeouts.next = NULL; + return; +} +/*-----------------------------------------------------------------------------------*/ +struct sys_timeouts * +sys_arch_timeouts(void) +{ + return &timeouts; +} +/*-----------------------------------------------------------------------------------*/ +void +sys_thread_new(void (* function)(void *arg), void *arg) +{ +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/arch/FILES b/src/arch/FILES new file mode 100644 index 00000000..7c6fd55b --- /dev/null +++ b/src/arch/FILES @@ -0,0 +1,15 @@ +6502/ - Architectural files for the 6502 CPU. + +rtxc/ - Architectural files for the RTXC operating system. + +unix/ - Architectural files for testing on unix-like systems + (assuming gcc and pthreads). + +Each subdirectory (may) also include: + +perf.c - Optional file that should be implemented when running + performance tests of lwIP. + +sys.c - Implementation of the operating system emulation layer. + +netif/ - Architectural specific network interfaces. diff --git a/src/arch/rtxc/include/arch/cc.h b/src/arch/rtxc/include/arch/cc.h new file mode 100644 index 00000000..3f88973b --- /dev/null +++ b/src/arch/rtxc/include/arch/cc.h @@ -0,0 +1,47 @@ +/* + * 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 + * + */ +#ifndef __CC_H__ +#define __CC_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; + +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_STRUCT +#define PACK_STRUCT_END +#define PACK_STRUCT_FIELD(x) x + +#endif /* __CC_H__ */ diff --git a/src/arch/rtxc/include/arch/cpu.h b/src/arch/rtxc/include/arch/cpu.h new file mode 100644 index 00000000..4439e1c5 --- /dev/null +++ b/src/arch/rtxc/include/arch/cpu.h @@ -0,0 +1,37 @@ +/* + * 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 + * + */ +#ifndef __CPU_H__ +#define __CPU_H__ + +#define BYTE_ORDER LITTLE_ENDIAN + +#endif /* __CPU_H__ */ diff --git a/src/arch/rtxc/include/arch/init.h b/src/arch/rtxc/include/arch/init.h new file mode 100644 index 00000000..dfcb98d7 --- /dev/null +++ b/src/arch/rtxc/include/arch/init.h @@ -0,0 +1,44 @@ +/* + * 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 + * + */ +#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__ */ + + + + diff --git a/src/arch/rtxc/include/arch/lib.h b/src/arch/rtxc/include/arch/lib.h new file mode 100644 index 00000000..ef36c985 --- /dev/null +++ b/src/arch/rtxc/include/arch/lib.h @@ -0,0 +1,40 @@ +/* + * 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 + * + */ +#ifndef __LIB_H__ +#define __LIB_H__ + +#include + +#define bcopy(s, d, l) memcpy(d, s, l) +#define bzero(d, l) memset(d, 0, l) + +#endif /* __LIB_H__ */ diff --git a/src/arch/rtxc/include/arch/perf.h b/src/arch/rtxc/include/arch/perf.h new file mode 100644 index 00000000..55a1ff4f --- /dev/null +++ b/src/arch/rtxc/include/arch/perf.h @@ -0,0 +1,38 @@ +/* + * 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 + * + */ +#ifndef __PERF_H__ +#define __PERF_H__ + +#define PERF_START /* null definition */ +#define PERF_STOP(x) /* null definition */ + +#endif /* __PERF_H__ */ diff --git a/src/arch/rtxc/include/arch/sys_arch.h b/src/arch/rtxc/include/arch/sys_arch.h new file mode 100644 index 00000000..a685e2ef --- /dev/null +++ b/src/arch/rtxc/include/arch/sys_arch.h @@ -0,0 +1,45 @@ +/* + * 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 + * + */ +#ifndef __SYS_RTXC_H__ +#define __SYS_RTXC_H__ + +#include "rtxcapi.h" + +#define SYS_MBOX_NULL (QUEUE)0 +#define SYS_SEM_NULL (SEMA)0 + +typedef SEMA sys_sem_t; +typedef QUEUE sys_mbox_t; +typedef TASK sys_thread_t; + +#endif /* __SYS_RTXC_H__ */ + diff --git a/src/arch/rtxc/include/netif/cs8900if.h b/src/arch/rtxc/include/netif/cs8900if.h new file mode 100644 index 00000000..46440db6 --- /dev/null +++ b/src/arch/rtxc/include/netif/cs8900if.h @@ -0,0 +1,41 @@ +/* + * 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 + * + */ +#ifndef __NETIF_CS8900IF_H__ +#define __NETIF_CS8900IF_H__ + +#include "lwip/netif.h" + +void cs8900if_init(struct netif *); +u8_t cs8900if_poll(struct netif *); +void cs8900if_input(struct netif *); + +#endif /* __NETIF_CS8900IF_H__ */ diff --git a/src/arch/rtxc/include/netif/sioslipif.h b/src/arch/rtxc/include/netif/sioslipif.h new file mode 100644 index 00000000..a22fd989 --- /dev/null +++ b/src/arch/rtxc/include/netif/sioslipif.h @@ -0,0 +1,39 @@ +/* + * 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 + * + */ +#ifndef __NETIF_SIOSLIPIF_H__ +#define __NETIF_SIOSLIPIF_H__ + +#include "lwip/netif.h" + +void sioslipif_init(struct netif *); + +#endif /* __NETIF_SIOSLIPIF_H__ */ diff --git a/src/arch/rtxc/lib.c b/src/arch/rtxc/lib.c new file mode 100644 index 00000000..726f0c63 --- /dev/null +++ b/src/arch/rtxc/lib.c @@ -0,0 +1,63 @@ +/* + * 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 + * + */ + +/* These are generic implementations of various library functions used + * throughout the lwIP code. When porting, those should be optimized + * for the particular processor architecture, preferably coded in + * assembler. + */ + +#if 0 /* Define to 1 if these are really needed. */ +/*-----------------------------------------------------------------------------------*/ +void +bcopy(const void *src, void *dst, unsigned int size) +{ + char *csrc, *cdst; + unsigned int i; + + csrc = (char *)src; + cdst = dst; + + for(i = 0; i < size; ++i) { + cdst[i] = csrc[i]; + } +} +/*-----------------------------------------------------------------------------------*/ +void +bzero(void *s, int n) +{ + for(--n ;n >= 0; --n) { + ((char *)s)[n] = 0; + } +} +/*-----------------------------------------------------------------------------------*/ +#endif /* 0 */ diff --git a/src/arch/rtxc/netif/FILES b/src/arch/rtxc/netif/FILES new file mode 100644 index 00000000..1b009e87 --- /dev/null +++ b/src/arch/rtxc/netif/FILES @@ -0,0 +1 @@ +sioslipif.c - Implementation of the SLIP protocol on top of a serial line. diff --git a/src/arch/rtxc/netif/sioslipif.c b/src/arch/rtxc/netif/sioslipif.c new file mode 100644 index 00000000..8a09e6e5 --- /dev/null +++ b/src/arch/rtxc/netif/sioslipif.c @@ -0,0 +1,170 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" +#include "lwip/def.h" +#include "netif/sioslipif.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" + +#define SLIP_END 0300 +#define SLIP_ESC 0333 +#define SLIP_ESC_END 0334 +#define SLIP_ESC_ESC 0335 + +/* This variable is used for passing the netif pointer between the + threads. */ +static struct netif *netif_pass; + +static int infd, outfd; +/*-----------------------------------------------------------------------------------*/ +static void +sio_send(u8_t c) +{ + write(outfd, &c, 1); +} +/*-----------------------------------------------------------------------------------*/ +static u8_t +sio_recv(void) +{ + u8_t c; + read(infd, &c, 1); + return c; +} +/*-----------------------------------------------------------------------------------*/ +static int +sioslipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) +{ + struct pbuf *q; + int i; + u8_t c; + + /* Send pbuf out on the serial I/O device. */ + sio_send(SLIP_END); + + for(q = p; q != NULL; q = q->next) { + for(i = 0; i < q->len; i++) { + c = ((u8_t *)q->payload)[i]; + switch(c) { + case SLIP_END: + sio_send(SLIP_ESC); + sio_send(SLIP_ESC_END); + break; + case SLIP_ESC: + sio_send(SLIP_ESC); + sio_send(SLIP_ESC_ESC); + break; + default: + sio_send(c); + break; + } + } + } + sio_send(SLIP_END); + return 0; +} +/*-----------------------------------------------------------------------------------*/ +static struct pbuf * +sioslipif_input(void) +{ + u8_t c; + struct pbuf *p, *q; + int recved; + int i; + + p = pbuf_alloc(PBUF_LINK, PBUF_MAX_SIZE, PBUF_POOL); + q = p; + recved = i = 0; + + while(1) { + c = sio_recv(); + switch(c) { + case SLIP_END: + if(recved > 0) { + /* Received whole packet. */ + pbuf_realloc(p, recved); + return p; + } + break; + case SLIP_ESC: + c = sio_recv(); + switch(c) { + case SLIP_ESC_END: + c = SLIP_END; + break; + case SLIP_ESC_ESC: + c = SLIP_ESC; + break; + } + /* FALLTHROUGH */ + default: + if(recved < p->tot_len && q != NULL) { + ((u8_t *)q->payload)[i] = c; + recved++; + i++; + if(i >= q->len) { + i = 0; + q = q->next; + } + } + break; + } + + } +} +/*-----------------------------------------------------------------------------------*/ +static void +sioslipif_loop(void) +{ + struct pbuf *p; + struct netif *netif; + + netif = netif_pass; + while(1) { + p = sioslipif_input(); + netif->input(p, netif); + } +} +/*-----------------------------------------------------------------------------------*/ +void +sioslipif_init(struct netif *netif) +{ + netif->state = NULL; + netif->name[0] = 's'; + netif->name[1] = 'l'; + netif->output = sioslipif_output; + + netif_pass = netif; + sys_thread_new((void *)sioslipif_loop, NULL); + /* Do some magic to make it possible to receive data from the serial I/O device. */ +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/arch/rtxc/perf.c b/src/arch/rtxc/perf.c new file mode 100644 index 00000000..ebf167ad --- /dev/null +++ b/src/arch/rtxc/perf.c @@ -0,0 +1,38 @@ +/* + * 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 + * + */ + +#include "arch/perf.h" + +void +perf_init(char *fname) +{ +} diff --git a/src/arch/rtxc/sys_arch.c b/src/arch/rtxc/sys_arch.c new file mode 100644 index 00000000..4237142a --- /dev/null +++ b/src/arch/rtxc/sys_arch.c @@ -0,0 +1,271 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" + +#include "lwip/def.h" +#include "lwip/sys.h" +#include "lwip/mem.h" + +#include "rtxcapi.h" +#include "csema.h" +#include "cclock.h" +#include "cqueue.h" +#include "cres.h" +#include "cpart.h" +#include "ctask.h" + +struct timeoutlist { + struct sys_timeouts timeouts; + TASK pid; +}; + +#define SYS_THREAD_MAX 2 + +static struct timeoutlist timeoutlist[SYS_THREAD_MAX]; +static u16_t nextthread = 0; + +/*-----------------------------------------------------------------------------------*/ +sys_mbox_t +sys_mbox_new(void) +{ + QUEUE mbox; + KS_dequeuew(IP_MBOXQ, &mbox); + KS_purgequeue(mbox); + return mbox; +} +/*-----------------------------------------------------------------------------------*/ +void +sys_mbox_free(sys_mbox_t mbox) +{ + KS_enqueue(IP_MBOXQ, &mbox); +} +/*-----------------------------------------------------------------------------------*/ +void +sys_mbox_post(sys_mbox_t mbox, void *data) +{ + if(KS_enqueue(mbox, &data) != RC_GOOD) { + } +} +/*-----------------------------------------------------------------------------------*/ +u16_t +sys_arch_mbox_fetch(sys_mbox_t mbox, void **data, u16_t timeout) +{ + KSRC ret; + u16_t wtime = 1; + + if(timeout == 0) { + DEBUGF(SYS_DEBUG, ("PID: %d sys_mbox_fetch: without timeouts\n",KS_inqtask())); + KS_dequeuew(mbox, data); + + } else { + + ret = KS_dequeuet(mbox, data, (TICKS)timeout/CLKTICK); + if(ret == RC_TIMEOUT) { + /* The call timed out, so we return 0. */ + wtime = 0; + } else { + /* Calculate time we waited for the message to arrive. */ + + /* XXX: we cheat and just pretend that we waited for half the timeout value! */ + wtime = timeout / 2; + + /* Make sure we don't return 0 here. */ + if(wtime == 0) { + wtime = 1; + } + } + } + return wtime; +} +/*-----------------------------------------------------------------------------------*/ +sys_sem_t +sys_sem_new(u8_t count) +{ + SEMA sem; + KS_dequeuew(IP_SEMQ, &sem); + KS_pend(sem); + if(count > 0) { + KS_signal(sem); + } + return sem; +} +/*-----------------------------------------------------------------------------------*/ +u16_t +sys_arch_sem_wait(sys_sem_t sem, u16_t timeout) +{ + KSRC ret; + u16_t wtime = 1; + + if(timeout == 0) { + DEBUGF(SYS_DEBUG, ("PID: %d sys_mbox_fetch: without timeouts\n",KS_inqtask())); + KS_wait(sem); + + } else { + ret = KS_waitt(sem, (TICKS)timeout/CLKTICK); + if(ret == RC_TIMEOUT) { + /* The call timed out, so we return 0. */ + wtime = 0; + } else { + /* Calculate time we waited for the message to arrive. */ + + /* XXX: we cheat and just pretend that we waited for half the timeout value! */ + wtime = timeout / 2; + + /* Make sure we don't return 0 here. */ + if(wtime == 0) { + wtime = 1; + } + } + } + return wtime; + +} +/*-----------------------------------------------------------------------------------*/ +void +sys_sem_signal(sys_sem_t sem) +{ + KS_signal(sem); +} +/*-----------------------------------------------------------------------------------*/ +void +sys_sem_free(sys_sem_t sem) +{ + KS_enqueue(IP_SEMQ, &sem); +} +/*-----------------------------------------------------------------------------------*/ +void +sys_init(void) +{ + /* posta in alla semaforer i IP_SEMQ, posta in alla mboxar i + IP_MBOXQ */ + QUEUE mbox; + SEMA sem; + + mbox = IP_Q_01; KS_enqueue(IP_MBOXQ, &mbox); + mbox = IP_Q_02; KS_enqueue(IP_MBOXQ, &mbox); + mbox = IP_Q_03; KS_enqueue(IP_MBOXQ, &mbox); + mbox = IP_Q_04; KS_enqueue(IP_MBOXQ, &mbox); + mbox = IP_Q_05; KS_enqueue(IP_MBOXQ, &mbox); + mbox = IP_Q_06; KS_enqueue(IP_MBOXQ, &mbox); + mbox = IP_Q_07; KS_enqueue(IP_MBOXQ, &mbox); + mbox = IP_Q_08; KS_enqueue(IP_MBOXQ, &mbox); + mbox = IP_Q_09; KS_enqueue(IP_MBOXQ, &mbox); + mbox = IP_Q_10; KS_enqueue(IP_MBOXQ, &mbox); + mbox = IP_Q_11; KS_enqueue(IP_MBOXQ, &mbox); + mbox = IP_Q_12; KS_enqueue(IP_MBOXQ, &mbox); + mbox = IP_Q_13; KS_enqueue(IP_MBOXQ, &mbox); + mbox = IP_Q_14; KS_enqueue(IP_MBOXQ, &mbox); + mbox = IP_Q_15; KS_enqueue(IP_MBOXQ, &mbox); + sem = IP_S_01; KS_enqueue(IP_SEMQ, &sem); + sem = IP_S_02; KS_enqueue(IP_SEMQ, &sem); + sem = IP_S_03; KS_enqueue(IP_SEMQ, &sem); +} +/*-----------------------------------------------------------------------------------*/ +struct sys_timeouts * +sys_arch_timeouts(void) +{ + int i; + TASK pid; + struct timeoutlist *tl; + + DEBUGF(SYS_DEBUG, ("PID: %d sys_mbox_fetch: timeoutlist not empty\n",KS_inqtask())); + pid = KS_inqtask(); + for(i = 0; i < nextthread; i++) { + tl = &timeoutlist[i]; + if(tl->pid == pid) { + DEBUGF(SYS_DEBUG, ("PID: %d sys_mbox_fetch: corresponding pid found!\n",KS_inqtask())); + return &(tl->timeouts); + } + } + + /* Error! */ + return NULL; +} +/*-----------------------------------------------------------------------------------*/ +struct sys_thread_arg { + void (* thread)(void *); + void *threadarg; + SEMA sem; +}; +/*-----------------------------------------------------------------------------------*/ +static void +sys_thread(void) +{ + struct sys_thread_arg *arg; + void (* thread)(void *); + void *threadarg; + + arg = KS_inqtask_arg(0); + if(arg != NULL) { + + timeoutlist[nextthread].timeouts.next = NULL; + timeoutlist[nextthread].pid = KS_inqtask(); + + ++nextthread; + + thread = arg->thread; + threadarg = arg->threadarg; + KS_signal(arg->sem); + thread(threadarg); + } + KS_terminate(0); +} +/*-----------------------------------------------------------------------------------*/ +void +sys_thread_new(void (* function)(void *arg), void *arg) +{ + TASK newtask; + PRIORITY pri = 2; /* This may have to be changed. */ + char *stack; + int stacksize = 512; /* This may have to be changed. */ + struct sys_thread_arg threadarg; + + + newtask = KS_alloc_task(); + stack = KS_allocw(MAP512); + + KS_deftask(newtask, pri, (char ks_stk *)stack, (size_t)stacksize, (void (*)(void))sys_thread); + + threadarg.thread = function; + threadarg.threadarg = arg; + threadarg.sem = THRDSYNC; + KS_deftask_arg(newtask, &threadarg); + KS_execute(newtask); + KS_wait(THRDSYNC); +} + + + + + + diff --git a/src/arch/unix/include/arch/cc.h b/src/arch/unix/include/arch/cc.h new file mode 100644 index 00000000..0197c8c1 --- /dev/null +++ b/src/arch/unix/include/arch/cc.h @@ -0,0 +1,51 @@ +/* + * 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 + * + */ +#ifndef __ARCH_CC_H__ +#define __ARCH_CC_H__ + +typedef unsigned char u8_t; +typedef signed char s8_t; +/*typedef unsigned short u8_t; + typedef signed short 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; + +#define PACK_STRUCT_FIELD(x) x __attribute__((packed)) +#define PACK_STRUCT_STRUCT __attribute__((packed)) +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_END + +#endif /* __ARCH_CC_H__ */ diff --git a/src/arch/unix/include/arch/cpu.h b/src/arch/unix/include/arch/cpu.h new file mode 100644 index 00000000..ae3586ef --- /dev/null +++ b/src/arch/unix/include/arch/cpu.h @@ -0,0 +1,39 @@ +/* + * 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 + * + */ +#ifndef __ARCH_CPU_H__ +#define __ARCH_CPU_H__ + +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif /* BYTE_ORDER */ + +#endif /* __ARCH_CPU_H__ */ diff --git a/src/arch/unix/include/arch/init.h b/src/arch/unix/include/arch/init.h new file mode 100644 index 00000000..d6e3735a --- /dev/null +++ b/src/arch/unix/include/arch/init.h @@ -0,0 +1,41 @@ +/* + * 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 + * + */ +#ifndef __ARCH_INIT_H__ +#define __ARCH_INIT_H__ + +#define TCPIP_INIT_DONE(arg) sys_sem_signal(*(sys_sem_t *)arg) + +#endif /* __ARCH_INIT_H__ */ + + + + diff --git a/src/arch/unix/include/arch/lib.h b/src/arch/unix/include/arch/lib.h new file mode 100644 index 00000000..f739dea5 --- /dev/null +++ b/src/arch/unix/include/arch/lib.h @@ -0,0 +1,44 @@ +/* + * 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 + * + */ +#ifndef __ARCH_LIB_H__ +#define __ARCH_LIB_H__ + +#ifndef _STRING_H_ +#ifndef _STRING_H +int strlen(const char *str); +int strncmp(const char *str1, const char *str2, int len); +void bcopy(const void *src, void *dest, int len); +void bzero(void *data, int n); +#endif /* _STRING_H */ +#endif /* _STRING_H_ */ + +#endif /* __ARCH_LIB_H__ */ diff --git a/src/arch/unix/include/arch/perf.h b/src/arch/unix/include/arch/perf.h new file mode 100644 index 00000000..8d8e767b --- /dev/null +++ b/src/arch/unix/include/arch/perf.h @@ -0,0 +1,63 @@ +/* + * 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 + * + */ +#ifndef __ARCH_PERF_H__ +#define __ARCH_PERF_H__ + +#include + +#ifdef PERF +#define PERF_START { \ + unsigned long __c1l, __c1h, __c2l, __c2h; \ + __asm__(".byte 0x0f, 0x31" : "=a" (__c1l), "=d" (__c1h)) +#define PERF_STOP(x) __asm__(".byte 0x0f, 0x31" : "=a" (__c2l), "=d" (__c2h)); \ + perf_print(__c1l, __c1h, __c2l, __c2h, x);} + +/*#define PERF_START do { \ + struct tms __perf_start, __perf_end; \ + times(&__perf_start) +#define PERF_STOP(x) times(&__perf_end); \ + perf_print_times(&__perf_start, &__perf_end, x);\ + } while(0)*/ +#else /* PERF */ +#define PERF_START /* null definition */ +#define PERF_STOP(x) /* null definition */ +#endif /* PERF */ + +void perf_print(unsigned long c1l, unsigned long c1h, + unsigned long c2l, unsigned long c2h, + char *key); + +void perf_print_times(struct tms *start, struct tms *end, char *key); + +void perf_init(char *fname); + +#endif /* __ARCH_PERF_H__ */ diff --git a/src/arch/unix/include/arch/sys_arch.h b/src/arch/unix/include/arch/sys_arch.h new file mode 100644 index 00000000..f85dd09c --- /dev/null +++ b/src/arch/unix/include/arch/sys_arch.h @@ -0,0 +1,48 @@ +/* + * 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 + * + */ +#ifndef __ARCH_SYS_ARCH_H__ +#define __ARCH_SYS_ARCH_H__ + +#define SYS_MBOX_NULL NULL +#define SYS_SEM_NULL NULL + +struct sys_sem; +typedef struct sys_sem * sys_sem_t; + +struct sys_mbox; +typedef struct sys_mbox *sys_mbox_t; + +struct sys_thread; +typedef struct sys_thread * sys_thread_t; + +#endif /* __ARCH_SYS_ARCH_H__ */ + diff --git a/src/arch/unix/include/netif/delif.h b/src/arch/unix/include/netif/delif.h new file mode 100644 index 00000000..9a7dbe73 --- /dev/null +++ b/src/arch/unix/include/netif/delif.h @@ -0,0 +1,42 @@ +/* + * 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 + * + */ +#ifndef __DELIF_H__ +#define __DELIF_H__ + +#include "lwip/netif.h" + +#include "lwip/pbuf.h" + +void delif_init(struct netif *netif); +void delif_init_thread(struct netif *netif); + +#endif /* __DELIF_H__ */ diff --git a/src/arch/unix/include/netif/dropif.h b/src/arch/unix/include/netif/dropif.h new file mode 100644 index 00000000..3e48dca4 --- /dev/null +++ b/src/arch/unix/include/netif/dropif.h @@ -0,0 +1,41 @@ +/* + * 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 + * + */ +#ifndef __DROPIF_H__ +#define __DROPIF_H__ + +#include "lwip/netif.h" + +#include "lwip/pbuf.h" + +void dropif_init(struct netif *netif); + +#endif /* __DROPIF_H__ */ diff --git a/src/arch/unix/include/netif/pcapif.h b/src/arch/unix/include/netif/pcapif.h new file mode 100644 index 00000000..80c1a344 --- /dev/null +++ b/src/arch/unix/include/netif/pcapif.h @@ -0,0 +1,39 @@ +/* + * 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 + * + */ +#ifndef __PCAPIF_H__ +#define __PCAPIF_H__ + +#include "lwip/netif.h" + +void pcapif_init(struct netif *netif); + +#endif /* __PCAPIF_H__ */ diff --git a/src/arch/unix/include/netif/sioslipif.h b/src/arch/unix/include/netif/sioslipif.h new file mode 100644 index 00000000..ac31b0d8 --- /dev/null +++ b/src/arch/unix/include/netif/sioslipif.h @@ -0,0 +1,43 @@ +/* + * 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 + * + */ +#ifndef __NETIF_SIOSLIPIF_H__ +#define __NETIF_SIOSLIPIF_H__ + +#include "lwip/netif.h" + +void sioslipif_init(struct netif *); + + +void sioslipif_init1(struct netif *); +void sioslipif_init2(struct netif *); + +#endif /* __NETIF_SIOSLIPIF_H__ */ diff --git a/src/arch/unix/include/netif/tapif.h b/src/arch/unix/include/netif/tapif.h new file mode 100644 index 00000000..d434f55b --- /dev/null +++ b/src/arch/unix/include/netif/tapif.h @@ -0,0 +1,39 @@ +/* + * 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 + * + */ +#ifndef __TAPIF_H__ +#define __TAPIF_H__ + +#include "lwip/netif.h" + +void tapif_init(struct netif *netif); + +#endif /* __TAPIF_H__ */ diff --git a/src/arch/unix/include/netif/tunif.h b/src/arch/unix/include/netif/tunif.h new file mode 100644 index 00000000..ca7cadaf --- /dev/null +++ b/src/arch/unix/include/netif/tunif.h @@ -0,0 +1,42 @@ +/* + * 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 + * + */ +#ifndef __TUNIF_H__ +#define __TUNIF_H__ + +#include "lwip/netif.h" + +#include "lwip/pbuf.h" + +void tunif_init(struct netif *netif); +void tunif_init_thread(struct netif *netif); + +#endif /* __TUNIF_H__ */ diff --git a/src/arch/unix/include/netif/unixif.h b/src/arch/unix/include/netif/unixif.h new file mode 100644 index 00000000..0e34fb1d --- /dev/null +++ b/src/arch/unix/include/netif/unixif.h @@ -0,0 +1,40 @@ +/* + * 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 + * + */ +#ifndef __UNIXIF_H__ +#define __UNIXIF_H__ + +#include "lwip/netif.h" + +void unixif_init_server(struct netif *netif); +void unixif_init_client(struct netif *netif); + +#endif /* __UNIXIF_H__ */ diff --git a/src/arch/unix/lwip_chksum.c b/src/arch/unix/lwip_chksum.c new file mode 100644 index 00000000..480a0130 --- /dev/null +++ b/src/arch/unix/lwip_chksum.c @@ -0,0 +1,73 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" + +#include "lwip/arch.h" + +#include "lwip/def.h" +#include "lwip/inet.h" + + +/*-----------------------------------------------------------------------------------*/ +/* lwip_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. + * + */ +/*-----------------------------------------------------------------------------------*/ +#if 0 +u16_t +lwip_chksum(void *dataptr, int len) +{ + u32_t acc; + + for(acc = 0; len > 1; len -= 2) { + acc += *((u16_t *)dataptr)++; + } + + /* add up any odd byte */ + if(len == 1) { + acc += htons((u16_t)((*(u8_t *)dataptr) & 0xff) << 8); + DEBUGF(INET_DEBUG, ("inet: chksum: odd byte %d\n", *(u8_t *)dataptr)); + } + acc = (acc >> 16) + (acc & 0xffffUL); + + if(acc & 0xffff0000 != 0) { + acc = (acc >> 16) + (acc & 0xffffUL); + } + + return (u16_t)acc; +} +/*-----------------------------------------------------------------------------------*/ +#endif diff --git a/src/arch/unix/netif/delif.c b/src/arch/unix/netif/delif.c new file mode 100644 index 00000000..0e41922a --- /dev/null +++ b/src/arch/unix/netif/delif.c @@ -0,0 +1,310 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" + +#include + +#include "lwip/def.h" +#include "netif/delif.h" + +#ifdef linux +#include "netif/tapif.h" +#else /* linux */ +#include "netif/tunif.h" +#endif /* linux */ + +#include "lwip/sys.h" + + +#define DELIF_INPUT_DROPRATE 0.1 +#define DELIF_OUTPUT_DROPRATE 0.1 + +#define DELIF_INPUT_DELAY 500 /* Miliseconds. */ +#define DELIF_OUTPUT_DELAY 500 /* Miliseconds. */ + +#define DELIF_TIMEOUT 10 + +struct delif { + err_t (* input)(struct pbuf *p, struct netif *inp); + struct netif *netif; +}; + +struct delif_pbuf { + struct delif_pbuf *next; + struct pbuf *p; + struct ip_addr *ipaddr; + unsigned int time; +}; + +static struct delif_pbuf *input_list = NULL; +static struct delif_pbuf *output_list = NULL; +/*-----------------------------------------------------------------------------------*/ +static void +delif_input_timeout(void *arg) +{ + struct netif *netif; + struct delif *delif; + struct delif_pbuf *dp; + unsigned int timeout, now; + + timeout = DELIF_TIMEOUT; + + netif = arg; + delif = netif->state; + + + /* Check if there is anything on the input list. */ + dp = input_list; + while(dp != NULL) { + now = sys_now(); + + if(dp->time <= now) { + delif->input(dp->p, netif); + if(dp->next != NULL) { + if(dp->next->time > now) { + timeout = dp->next->time - now; + } else { + timeout = 0; + } + DEBUGF(DELIF_DEBUG, ("delif_output_timeout: timeout %u.\n", timeout)); + + } + input_list = dp->next; + free(dp); + dp = input_list; + } else { + dp = dp->next; + } + } + + sys_timeout(timeout, delif_input_timeout, arg); +} +/*-----------------------------------------------------------------------------------*/ +static void +delif_output_timeout(void *arg) +{ + struct netif *netif; + struct delif *delif; + struct delif_pbuf *dp; + unsigned int timeout, now; + + timeout = DELIF_TIMEOUT; + + netif = arg; + delif = netif->state; + + /* Check if there is anything on the output list. */ + dp = output_list; + while(dp != NULL) { + now = sys_now(); + if(dp->time <= now) { + DEBUGF(DELIF_DEBUG, ("delif_output_timeout: now %u dp->time %u\n", + now, dp->time)); + delif->netif->output(delif->netif, dp->p, dp->ipaddr); + if(dp->next != NULL) { + if(dp->next->time > now) { + timeout = dp->next->time - now; + } else { + timeout = 0; + } + DEBUGF(DELIF_DEBUG, ("delif_output_timeout: timeout %u.\n", timeout)); + + } + pbuf_free(dp->p); + + output_list = dp->next; + free(dp); + dp = output_list; + } else { + dp = dp->next; + } + } + + + sys_timeout(timeout, delif_output_timeout, arg); +} +/*-----------------------------------------------------------------------------------*/ +static err_t +delif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) +{ + struct delif_pbuf *dp, *np; + struct pbuf *q; + int i, j; + char *data; + + DEBUGF(DELIF_DEBUG, ("delif_output\n")); + +#ifdef DELIF_OUTPUT_DROPRATE + if(((double)rand()/(double)RAND_MAX) < DELIF_OUTPUT_DROPRATE) { + DEBUGF(DELIF_DEBUG, ("delif_output: Packet dropped\n")); + return 0; + } +#endif /* DELIF_OUTPUT_DROPRATE */ + + + DEBUGF(DELIF_DEBUG, ("delif_output\n")); + + + dp = malloc(sizeof(struct delif_pbuf)); + data = malloc(p->tot_len); + + i = 0; + for(q = p; q != NULL; q = q->next) { + for(j = 0; j < q->len; j++) { + data[i] = ((char *)q->payload)[j]; + i++; + } + } + + + dp->p = pbuf_alloc(PBUF_LINK, 0, PBUF_ROM); + dp->p->payload = data; + dp->p->len = p->tot_len; + dp->p->tot_len = p->tot_len; + dp->ipaddr = ipaddr; + dp->time = sys_now() + DELIF_OUTPUT_DELAY; + dp->next = NULL; + if(output_list == NULL) { + output_list = dp; + } else { + for(np = output_list; np->next != NULL; np = np->next); + np->next = dp; + } + + + return ERR_OK; + + +} +/*-----------------------------------------------------------------------------------*/ +static err_t +delif_input(struct pbuf *p, struct netif *inp) +{ + struct delif_pbuf *dp, *np; + + DEBUGF(DELIF_DEBUG, ("delif_input\n")); +#ifdef DELIF_INPUT_DROPRATE + if(((double)rand()/(double)RAND_MAX) < DELIF_INPUT_DROPRATE) { + DEBUGF(DELIF_DEBUG, ("delif_input: Packet dropped\n")); + pbuf_free(p); + return ERR_OK; + } +#endif /* DELIF_INPUT_DROPRATE */ + + + dp = malloc(sizeof(struct delif_pbuf)); + dp->p = p; + dp->time = sys_now() + DELIF_INPUT_DELAY; + dp->next = NULL; + if(input_list == NULL) { + input_list = dp; + } else { + for(np = input_list; np->next != NULL; np = np->next); + np->next = dp; + } + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +void +delif_init(struct netif *netif) +{ + struct delif *del; + + del = malloc(sizeof(struct delif)); + netif->state = del; + netif->name[0] = 'd'; + netif->name[1] = 'e'; + netif->output = delif_output; + + del->netif = malloc(sizeof(struct netif)); +#ifdef linux + /* tapif_init(del->netif);*/ + tunif_init(del->netif); +#else /* linux */ + tunif_init(del->netif); +#endif /* linux */ + del->input = netif->input; + del->netif->input = delif_input; + sys_timeout(DELIF_TIMEOUT, delif_input_timeout, netif); + sys_timeout(DELIF_TIMEOUT, delif_output_timeout, netif); +} + +/*-----------------------------------------------------------------------------------*/ +static void +delif_thread(void *arg) +{ + struct netif *netif = arg; + struct delif *del; + sys_sem_t sem; + + del = netif->state; +#ifdef linux + tapif_init(del->netif); +#else /* linux */ + tunif_init(del->netif); +#endif /* linux */ + + sys_timeout(DELIF_TIMEOUT, delif_input_timeout, netif); + sys_timeout(DELIF_TIMEOUT, delif_output_timeout, netif); + + sem = sys_sem_new(0); + sys_sem_wait(sem); + +} +/*-----------------------------------------------------------------------------------*/ +void +delif_init_thread(struct netif *netif) +{ + struct delif *del; + + DEBUGF(DELIF_DEBUG, ("delif_init_thread\n")); + + del = malloc(sizeof(struct delif)); + netif->state = del; + netif->name[0] = 'd'; + netif->name[1] = 'e'; + netif->output = delif_output; + + del->netif = malloc(sizeof(struct netif)); + del->netif->ip_addr = netif->ip_addr; + del->netif->gw = netif->gw; + del->netif->netmask = netif->netmask; + del->input = netif->input; + del->netif->input = delif_input; + sys_thread_new(delif_thread, netif); +} + +/*-----------------------------------------------------------------------------------*/ + + + diff --git a/src/arch/unix/netif/list.c b/src/arch/unix/netif/list.c new file mode 100644 index 00000000..288cebce --- /dev/null +++ b/src/arch/unix/netif/list.c @@ -0,0 +1,162 @@ +/* + * 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 + * + */ + + +#include "lwip/list.h" + +#include + +struct list { + struct elem *first, *last; + int size, elems; +}; + +struct elem { + struct elem *next; + void *data; +}; + +/*-----------------------------------------------------------------------------------*/ +struct list * +list_new(int size) +{ + struct list *list; + list = malloc(sizeof(struct list)); + list->first = list->last = NULL; + list->size = size; + list->elems = 0; + return list; +} +/*-----------------------------------------------------------------------------------*/ +int +list_push(struct list *list, void *data) +{ + struct elem *elem; + + if(list->elems < list->size) { + elem = malloc(sizeof(struct elem)); + elem->data = data; + elem->next = NULL; + if(list->last != NULL) { + list->last->next = elem; + } + list->last = elem; + if(list->first == NULL) { + list->first = elem; + } + list->elems++; + return 1; + } + return 0; +} +/*-----------------------------------------------------------------------------------*/ +void * +list_pop(struct list *list) +{ + struct elem *elem; + void *data; + + if(list->elems > 0) { + elem = list->first; + if(elem == list->last) { + list->last = elem->next; + } + list->first = elem->next; + + list->elems--; + + data = elem->data; + free(elem); + + return data; + } + return NULL; +} +/*-----------------------------------------------------------------------------------*/ +void * +list_first(struct list *list) +{ + return list->first; +} +/*-----------------------------------------------------------------------------------*/ +int +list_elems(struct list *list) +{ + return list->elems; +} +/*-----------------------------------------------------------------------------------*/ +void +list_delete(struct list *list) +{ + while(list_pop(list) != NULL); + free(list); +} +/*-----------------------------------------------------------------------------------*/ +int +list_remove(struct list *list, void *elem) +{ + struct elem *e, *p; + + p = NULL; + for(e = list->first; e != NULL; e = e->next) { + if(e->data == elem) { + if(p != NULL) { + p->next = e->next; + } else { + list->first = e->next; + } + if(list->last == e) { + list->last = p; + if(p != NULL) { + p->next = NULL; + } + } + free(e); + list->elems--; + return 1; + } + p = e; + } + return 0; +} +/*-----------------------------------------------------------------------------------*/ +void +list_map(struct list *list, void (* func)(void *arg)) +{ + struct elem *e; + + for(e = list->first; e != NULL; e = e->next) { + func(e->data); + } +} +/*-----------------------------------------------------------------------------------*/ + diff --git a/src/arch/unix/netif/pcapif.c b/src/arch/unix/netif/pcapif.c new file mode 100644 index 00000000..cfdccc13 --- /dev/null +++ b/src/arch/unix/netif/pcapif.c @@ -0,0 +1,214 @@ +/* + * 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 + * + */ + +#ifndef linux /* Apparently, this doesn't work under Linux. */ + +#include "lwip/debug.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "netif/etharp.h" + +#include "lwip/stats.h" + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "netif/unixif.h" +#include "lwip/sys.h" + +#include "lwip/ip.h" + +#include "lwip/list.h" + +#include "netif/tcpdump.h" + +struct pcapif { + pcap_t *pd; + sys_sem_t sem; + u8_t pkt[2048]; + u32_t len; + u32_t lasttime; + struct pbuf *p; + struct eth_addr *ethaddr; +}; + +static char errbuf[PCAP_ERRBUF_SIZE]; + +/*-----------------------------------------------------------------------------------*/ +static err_t +pcapif_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr) +{ + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +static void +timeout(void *arg) +{ + struct netif *netif; + struct pcapif *pcapif; + struct pbuf *p, *q; + u8_t *bufptr; + struct eth_hdr *ethhdr; + + netif = (struct netif *)arg; + pcapif = netif->state; + ethhdr = (struct eth_hdr *)pcapif->pkt; + + + if(htons(ethhdr->type) != ETHTYPE_IP || + ip_lookup(pcapif->pkt + 14, netif)) { + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_LINK, pcapif->len, PBUF_POOL); + + if(p != NULL) { + /* We iterate over the pbuf chain until we have read the entire + packet into the pbuf. */ + bufptr = (u_char *)pcapif->pkt; + for(q = p; q != NULL; q = q->next) { + /* Read enough bytes to fill this pbuf in the chain. The + avaliable data in the pbuf is given by the q->len + variable. */ + /* read data into(q->payload, q->len); */ + bcopy(bufptr, q->payload, q->len); + bufptr += q->len; + } + + ethhdr = p->payload; + switch(htons(ethhdr->type)) { + case ETHTYPE_IP: + arp_ip_input(netif, p); + pbuf_header(p, -14); + netif->input(p, netif); + break; + case ETHTYPE_ARP: + p = arp_arp_input(netif, pcapif->ethaddr, p); + if(p != NULL) { + printf("ARP outout\n"); + pbuf_free(p); + } + break; + default: + pbuf_free(p); + break; + } + } + } else { + printf("ip_lookup dropped\n"); + } + + sys_sem_signal(pcapif->sem); +} +/*-----------------------------------------------------------------------------------*/ +static void +callback(u_char *arg, const struct pcap_pkthdr *hdr, const u_char *pkt) +{ + struct netif *netif; + struct pcapif *pcapif; + u32_t time, lasttime; + + netif = (struct netif *)arg; + pcapif = netif->state; + + pcapif->len = hdr->len; + + bcopy(pkt, pcapif->pkt, hdr->len); + + time = hdr->ts.tv_sec * 1000 + hdr->ts.tv_usec / 1000; + + lasttime = pcapif->lasttime; + pcapif->lasttime = time; + + + if(lasttime == 0) { + sys_timeout(1000, timeout, netif); + } else { + sys_timeout(time - lasttime, timeout, netif); + } +} +/*-----------------------------------------------------------------------------------*/ +static void +pcapif_thread(void *arg) +{ + struct netif *netif; + struct pcapif *pcapif; + netif = arg; + pcapif = netif->state; + + while(1) { + pcap_loop(pcapif->pd, 1, callback, (u_char *)netif); + sys_sem_wait(pcapif->sem); + if(pcapif->p != NULL) { + netif->input(pcapif->p, netif); + } + } +} +/*-----------------------------------------------------------------------------------*/ +void +pcapif_init(struct netif *netif) +{ + struct pcapif *p; + + p = malloc(sizeof(struct pcapif)); + netif->state = p; + netif->name[0] = 'p'; + netif->name[1] = 'c'; + netif->output = pcapif_output; + + p->pd = pcap_open_offline("pcapdump", errbuf); + if(p->pd == NULL) { + printf("pcapif_init: failed %s\n", errbuf); + return; + } + + p->sem = sys_sem_new(0); + p->p = NULL; + p->lasttime = 0; + + sys_thread_new(pcapif_thread, netif); +} +/*-----------------------------------------------------------------------------------*/ +#endif /* linux */ diff --git a/src/arch/unix/netif/sioslipif.c b/src/arch/unix/netif/sioslipif.c new file mode 100644 index 00000000..9659e37a --- /dev/null +++ b/src/arch/unix/netif/sioslipif.c @@ -0,0 +1,189 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" +#include "lwip/def.h" +#include "netif/sioslipif.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include "lwip/stats.h" + +/* The maximum size that an incoming packet can have. */ +#define MAX_SIZE 1500 + +#define SLIP_END 0300 +#define SLIP_ESC 0333 +#define SLIP_ESC_END 0334 +#define SLIP_ESC_ESC 0335 + +/* Define those to whatever is needed to send and receive one byte of + data. */ +#define SIO_SEND(c) +#define SIO_RECV(c) + +static const unsigned char slip_end = SLIP_END, + slip_esc = SLIP_ESC, + slip_esc_end = SLIP_ESC_END, + slip_esc_esc = SLIP_ESC_ESC; + +/*-----------------------------------------------------------------------------------*/ +static err_t +sioslipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) +{ + struct pbuf *q; + int i; + unsigned char *ptr; + u8_t c; + /* Send pbuf out on the serial I/O device. */ + SIO_SEND(slip_end); + + for(q = p; q != NULL; q = q->next) { + ptr = q->payload; + for(i = 0; i < q->len; i++) { + c = *ptr++; + switch(c) { + case SLIP_END: + SIO_SEND(slip_esc); + SIO_SEND(slip_esc_end); + break; + case SLIP_ESC: + SIO_SEND(slip_esc); + SIO_SEND(slip_esc_esc); + break; + default: + SIO_SEND(c); + break; + } + } + } +#ifdef LINK_STATS + stats.link.xmit++; +#endif /* LINK_STATS */ + SIO_SEND(slip_end); + + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +static struct pbuf * +sioslipif_input(void) +{ + u8_t c; + struct pbuf *p, *q; + int recved; + int i; + + q = p = NULL; + recved = i = 0; + c = 0; + + while(1) { + SIO_RECV(c); + switch(c) { + case SLIP_END: + if(p == NULL) { + return sioslipif_input(); + } + if(recved > 0) { + /* Received whole packet. */ + pbuf_realloc(q, recved); +#ifdef LINK_STATS + stats.link.recv++; +#endif /* LINK_STATS */ + return q; + } + break; + case SLIP_ESC: + SIO_RECV(c); + switch(c) { + case SLIP_ESC_END: + c = SLIP_END; + break; + case SLIP_ESC_ESC: + c = SLIP_ESC; + break; + } + /* FALLTHROUGH */ + default: + if(p == NULL) { + p = pbuf_alloc(PBUF_LINK, 128, PBUF_POOL); +#ifdef LINK_STATS + if(p == NULL) { + stats.link.drop++; + } +#endif /* LINK_STATS */ + if(q != NULL) { + pbuf_chain(q, p); + } else { + q = p; + } + } + if(p != NULL && recved < MAX_SIZE) { + ((u8_t *)p->payload)[i] = c; + recved++; + i++; + if(i >= p->len) { + i = 0; + p = NULL; + } + } + break; + } + + } + return NULL; +} +/*-----------------------------------------------------------------------------------*/ +static void +sioslipif_loop(void *arg) +{ + struct pbuf *p; + struct netif *netif; + + netif = arg; + while(1) { + p = sioslipif_input(); + netif->input(p, netif); + } +} +/*-----------------------------------------------------------------------------------*/ +void +sioslipif_init(struct netif *netif) +{ + netif->state = NULL; + netif->name[0] = 's'; + netif->name[1] = 'l'; + netif->output = sioslipif_output; + + sys_thread_new((void *)sioslipif_loop, netif); + /* Do some magic to make it possible to receive data from the serial I/O device. */ +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/arch/unix/netif/tapif.c b/src/arch/unix/netif/tapif.c new file mode 100644 index 00000000..ac9f1eaa --- /dev/null +++ b/src/arch/unix/netif/tapif.c @@ -0,0 +1,355 @@ +/* + * 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "lwip/debug.h" + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/ip.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" + +#include "netif/etharp.h" + +#ifdef linux +#include +#include +#include +#define DEVTAP "/dev/net/tun" +#else /* linux */ +#define DEVTAP "/dev/tap0" +#endif /* linux */ + +#define IFNAME0 't' +#define IFNAME1 'p' + +static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; + +struct tapif { + struct eth_addr *ethaddr; + /* Add whatever per-interface state that is needed here. */ + int fd; +}; + +/* Forward declarations. */ +static void tapif_input(struct netif *netif); +static err_t tapif_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr); + +static void tapif_thread(void *data); + +/*-----------------------------------------------------------------------------------*/ +static void +low_level_init(struct netif *netif) +{ + struct tapif *tapif; + char buf[100]; + + tapif = netif->state; + + /* Obtain MAC address from network interface. */ + + /* (We just fake an address...) */ + tapif->ethaddr->addr[0] = 0x1; + tapif->ethaddr->addr[1] = 0x2; + tapif->ethaddr->addr[2] = 0x3; + tapif->ethaddr->addr[3] = 0x4; + tapif->ethaddr->addr[4] = 0x5; + tapif->ethaddr->addr[5] = 0x6; + + /* Do whatever else is needed to initialize interface. */ + + tapif->fd = open(DEVTAP, O_RDWR); + DEBUGF(TAPIF_DEBUG, ("tapif_init: fd %d\n", tapif->fd)); + if(tapif->fd == -1) { + perror("tapif_init"); + exit(1); + } + +#ifdef linux + { + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP|IFF_NO_PI; + if (ioctl(tapif->fd, TUNSETIFF, (void *) &ifr) < 0) { + perror(buf); + exit(1); + } + } +#endif /* Linux */ + + snprintf(buf, sizeof(buf), "ifconfig tap0 inet %d.%d.%d.%d", + ip4_addr1(&(netif->gw)), + ip4_addr2(&(netif->gw)), + ip4_addr3(&(netif->gw)), + ip4_addr4(&(netif->gw))); + + DEBUGF(TAPIF_DEBUG, ("tapif_init: system(\"%s\");\n", buf)); + system(buf); + sys_thread_new(tapif_thread, netif); + +} +/*-----------------------------------------------------------------------------------*/ +/* + * 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; + char buf[1500]; + char *bufptr; + struct tapif *tapif; + + tapif = netif->state; + + /* initiate transfer(); */ + + bufptr = &buf[0]; + + for(q = p; q != NULL; q = q->next) { + /* Send the data from the pbuf to the interface, one pbuf at a + time. The size of the data in each pbuf is kept in the ->len + variable. */ + /* send data from(q->payload, q->len); */ + bcopy(q->payload, bufptr, q->len); + bufptr += q->len; + } + + /* signal that packet should be sent(); */ + if(write(tapif->fd, buf, p->tot_len) == -1) { + perror("tapif: write"); + } + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +/* + * low_level_input(): + * + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + */ +/*-----------------------------------------------------------------------------------*/ +static struct pbuf * +low_level_input(struct tapif *tapif) +{ + struct pbuf *p, *q; + u16_t len; + char buf[1500]; + char *bufptr; + + /* Obtain the size of the packet and put it into the "len" + variable. */ + len = read(tapif->fd, buf, sizeof(buf)); + + /* if(((double)rand()/(double)RAND_MAX) < 0.1) { + printf("drop\n"); + return NULL; + }*/ + + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL); + + if(p != NULL) { + /* We iterate over the pbuf chain until we have read the entire + packet into the pbuf. */ + bufptr = &buf[0]; + for(q = p; q != NULL; q = q->next) { + /* Read enough bytes to fill this pbuf in the chain. The + avaliable data in the pbuf is given by the q->len + variable. */ + /* read data into(q->payload, q->len); */ + bcopy(bufptr, q->payload, q->len); + bufptr += q->len; + } + /* acknowledge that packet has been read(); */ + } else { + /* drop packet(); */ + } + + return p; +} +/*-----------------------------------------------------------------------------------*/ +static void +tapif_thread(void *arg) +{ + struct netif *netif; + struct tapif *tapif; + fd_set fdset; + int ret; + + netif = arg; + tapif = netif->state; + + while(1) { + FD_ZERO(&fdset); + FD_SET(tapif->fd, &fdset); + + /* Wait for a packet to arrive. */ + ret = select(tapif->fd + 1, &fdset, NULL, NULL, NULL); + + if(ret == 1) { + /* Handle incoming packet. */ + tapif_input(netif); + } else if(ret == -1) { + perror("tapif_thread: select"); + } + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * tapif_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 actuall transmission of the packet. + * + */ +/*-----------------------------------------------------------------------------------*/ +static err_t +tapif_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr) +{ + p = etharp_output(netif, ipaddr, p); + if(p != NULL) { + return low_level_output(netif, p); + } + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +/* + * tapif_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 +tapif_input(struct netif *netif) +{ + struct tapif *tapif; + struct eth_hdr *ethhdr; + struct pbuf *p, *q; + + + tapif = netif->state; + + p = low_level_input(tapif); + + if(p == NULL) { + DEBUGF(TAPIF_DEBUG, ("tapif_input: low_level_input returned NULL\n")); + return; + } + ethhdr = p->payload; + + q = NULL; + switch(htons(ethhdr->type)) { + case ETHTYPE_IP: + DEBUGF(TAPIF_DEBUG, ("tapif_input: IP packet\n")); + q = etharp_ip_input(netif, p); + pbuf_header(p, -14); + netif->input(p, netif); + break; + case ETHTYPE_ARP: + DEBUGF(TAPIF_DEBUG, ("tapif_input: ARP packet\n")); + q = etharp_arp_input(netif, tapif->ethaddr, p); + break; + default: + pbuf_free(p); + break; + } + if(q != NULL) { + low_level_output(netif, q); + pbuf_free(q); + } + +} +/*-----------------------------------------------------------------------------------*/ +static void +arp_timer(void *arg) +{ + etharp_tmr(); + sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler)arp_timer, NULL); +} +/*-----------------------------------------------------------------------------------*/ +/* + * tapif_init(): + * + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +tapif_init(struct netif *netif) +{ + struct tapif *tapif; + + tapif = mem_malloc(sizeof(struct tapif)); + netif->state = tapif; + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + netif->output = tapif_output; + netif->linkoutput = low_level_output; + + tapif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); + + low_level_init(netif); + etharp_init(); + + sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler)arp_timer, NULL); +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/arch/unix/netif/tunif.c b/src/arch/unix/netif/tunif.c new file mode 100644 index 00000000..7e376dcb --- /dev/null +++ b/src/arch/unix/netif/tunif.c @@ -0,0 +1,298 @@ +/* + * 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "lwip/debug.h" + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/ip.h" +#include "lwip/mem.h" +#include "lwip/netif.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" + + +#define IFNAME0 't' +#define IFNAME1 'n' + +struct tunif { + /* Add whatever per-interface state that is needed here. */ + int fd; +}; + +/* Forward declarations. */ +static void tunif_input(struct netif *netif); +static err_t tunif_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr); + +static void tunif_thread(void *data); + +/*-----------------------------------------------------------------------------------*/ +static void +low_level_init(struct netif *netif) +{ + struct tunif *tunif; + char buf[100]; + + tunif = netif->state; + + /* Obtain MAC address from network interface. */ + + /* Do whatever else is needed to initialize interface. */ + + tunif->fd = open("/dev/tun0", O_RDWR); + DEBUGF(TUNIF_DEBUG, ("tunif_init: fd %d\n", tunif->fd)); + if(tunif->fd == -1) { + perror("tunif_init"); + exit(1); + } + snprintf(buf, sizeof(buf), "ifconfig tun0 inet %d.%d.%d.%d %d.%d.%d.%d", + ip4_addr1(&(netif->gw)), + ip4_addr2(&(netif->gw)), + ip4_addr3(&(netif->gw)), + ip4_addr4(&(netif->gw)), + ip4_addr1(&(netif->ip_addr)), + ip4_addr2(&(netif->ip_addr)), + ip4_addr3(&(netif->ip_addr)), + ip4_addr4(&(netif->ip_addr))); + + DEBUGF(TUNIF_DEBUG, ("tunif_init: system(\"%s\");\n", buf)); + system(buf); + sys_thread_new(tunif_thread, netif); + +} +/*-----------------------------------------------------------------------------------*/ +/* + * 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 tunif *tunif, struct pbuf *p) +{ + struct pbuf *q; + char buf[1500]; + char *bufptr; + + /* initiate transfer(); */ + + if(((double)rand()/(double)RAND_MAX) < 0.4) { + printf("drop\n"); + return ERR_OK; + } + + + bufptr = &buf[0]; + + for(q = p; q != NULL; q = q->next) { + /* Send the data from the pbuf to the interface, one pbuf at a + time. The size of the data in each pbuf is kept in the ->len + variable. */ + /* send data from(q->payload, q->len); */ + bcopy(q->payload, bufptr, q->len); + bufptr += q->len; + } + + /* signal that packet should be sent(); */ + if(write(tunif->fd, buf, p->tot_len) == -1) { + perror("tunif: write"); + } + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +/* + * low_level_input(): + * + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + */ +/*-----------------------------------------------------------------------------------*/ +static struct pbuf * +low_level_input(struct tunif *tunif) +{ + struct pbuf *p, *q; + u16_t len; + char buf[1500]; + char *bufptr; + + /* Obtain the size of the packet and put it into the "len" + variable. */ + len = read(tunif->fd, buf, sizeof(buf)); + + /* if(((double)rand()/(double)RAND_MAX) < 0.1) { + printf("drop\n"); + return NULL; + }*/ + + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL); + + if(p != NULL) { + /* We iterate over the pbuf chain until we have read the entire + packet into the pbuf. */ + bufptr = &buf[0]; + for(q = p; q != NULL; q = q->next) { + /* Read enough bytes to fill this pbuf in the chain. The + avaliable data in the pbuf is given by the q->len + variable. */ + /* read data into(q->payload, q->len); */ + bcopy(bufptr, q->payload, q->len); + bufptr += q->len; + } + /* acknowledge that packet has been read(); */ + } else { + /* drop packet(); */ + } + + return p; +} +/*-----------------------------------------------------------------------------------*/ +static void +tunif_thread(void *arg) +{ + struct netif *netif; + struct tunif *tunif; + fd_set fdset; + int ret; + + netif = arg; + tunif = netif->state; + + while(1) { + FD_ZERO(&fdset); + FD_SET(tunif->fd, &fdset); + + /* Wait for a packet to arrive. */ + ret = select(tunif->fd + 1, &fdset, NULL, NULL, NULL); + + if(ret == 1) { + /* Handle incoming packet. */ + tunif_input(netif); + } else if(ret == -1) { + perror("tunif_thread: select"); + } + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * tunif_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 actuall transmission of the packet. + * + */ +/*-----------------------------------------------------------------------------------*/ +static err_t +tunif_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr) +{ + struct tunif *tunif; + + tunif = netif->state; + + return low_level_output(tunif, p); + +} +/*-----------------------------------------------------------------------------------*/ +/* + * tunif_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 +tunif_input(struct netif *netif) +{ + struct tunif *tunif; + struct pbuf *p; + + + tunif = netif->state; + + p = low_level_input(tunif); + + if(p == NULL) { + DEBUGF(TUNIF_DEBUG, ("tunif_input: low_level_input returned NULL\n")); + return; + } + + if(ip_lookup(p->payload, netif)) { + netif->input(p, netif); + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * tunif_init(): + * + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +tunif_init(struct netif *netif) +{ + struct tunif *tunif; + + tunif = mem_malloc(sizeof(struct tunif)); + netif->state = tunif; + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + netif->output = tunif_output; + + + low_level_init(netif); +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/arch/unix/netif/unixif.c b/src/arch/unix/netif/unixif.c new file mode 100644 index 00000000..43ea14a2 --- /dev/null +++ b/src/arch/unix/netif/unixif.c @@ -0,0 +1,480 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "lwip/stats.h" + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "netif/unixif.h" +#include "lwip/sys.h" + +#include "lwip/list.h" + +#include "netif/tcpdump.h" + +#define UNIXIF_BPS 512000 +#define UNIXIF_QUEUELEN 6 +/*#define UNIXIF_DROP_FIRST */ + +struct unixif_buf { + struct pbuf *p; + unsigned short len, tot_len; + void *payload; +}; + +struct unixif { + int fd; + sys_sem_t sem; + struct list *q; +}; + + +/*-----------------------------------------------------------------------------------*/ +static int +unix_socket_client(char *name) +{ + int fd, len; + struct sockaddr_un unix_addr; + + /* create a Unix domain stream socket */ + if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + perror("unixif: unix_socket_client: socket"); + return(-1); + } + + /* fill socket address structure w/our address */ + memset(&unix_addr, 0, sizeof(unix_addr)); + unix_addr.sun_family = AF_UNIX; + sprintf(unix_addr.sun_path, "%s%05d", "/var/tmp/", getpid()); +#ifndef linux + len = sizeof(unix_addr.sun_len) + sizeof(unix_addr.sun_family) + + strlen(unix_addr.sun_path) + 1; + unix_addr.sun_len = len; +#else + len = sizeof(unix_addr.sun_family) + + strlen(unix_addr.sun_path) + 1; +#endif /* linux */ + + unlink(unix_addr.sun_path); /* in case it already exists */ + if(bind(fd, (struct sockaddr *) &unix_addr, + sizeof(struct sockaddr_un)) < 0) { + perror("unixif: unix_socket_client: socket"); + return(-1); + } + if(chmod(unix_addr.sun_path, S_IRWXU | S_IRWXO) < 0) { + perror("unixif: unix_socket_client: socket"); + return(-1); + } + + /* fill socket address structure w/server's addr */ + memset(&unix_addr, 0, sizeof(unix_addr)); + unix_addr.sun_family = AF_UNIX; + strcpy(unix_addr.sun_path, name); +#ifndef linux + len = sizeof(unix_addr.sun_len) + sizeof(unix_addr.sun_family) + + strlen(unix_addr.sun_path) + 1; + unix_addr.sun_len = len; +#else + len = sizeof(unix_addr.sun_family) + strlen(unix_addr.sun_path) + 1; +#endif /* linux */ + if(connect(fd, (struct sockaddr *) &unix_addr, + sizeof(struct sockaddr_un)) < 0) { + perror("unixif: unix_socket_client: socket"); + return(-1); + } + return(fd); +} + +/*-----------------------------------------------------------------------------------*/ +static int +unix_socket_server(char *name) +{ + int fd, len; + struct sockaddr_un unix_addr; + + /* create a Unix domain stream socket */ + if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + perror("unixif: unix_socket_server: socket"); + return(-1); + } + + unlink(name); /* in case it already exists */ + + /* fill in socket address structure */ + memset(&unix_addr, 0, sizeof(unix_addr)); + unix_addr.sun_family = AF_UNIX; + strcpy(unix_addr.sun_path, name); +#ifndef linux + len = sizeof(unix_addr.sun_len) + sizeof(unix_addr.sun_family) + + strlen(unix_addr.sun_path) + 1; + unix_addr.sun_len = len; +#else + len = sizeof(unix_addr.sun_family) + + strlen(unix_addr.sun_path) + 1; +#endif /* linux */ + + /* bind the name to the descriptor */ + if(bind(fd, (struct sockaddr *) &unix_addr, + sizeof(struct sockaddr_un)) < 0) { + perror("unixif: unix_socket_server: bind"); + return(-1); + } + + if(chmod(unix_addr.sun_path, S_IRWXU | S_IRWXO) < 0) { + perror("unixif: unix_socket_server: chmod"); + return(-1); + } + + + if(listen(fd, 5) < 0) { /* tell kernel we're a server */ + perror("unixif: unix_socket_server: listen"); + return(-1); + } + + return(fd); +} +/*-----------------------------------------------------------------------------------*/ +static void +unixif_input_handler(void *data) +{ + struct netif *netif; + struct unixif *unixif; + char buf[4096], *bufptr; + int len, plen, rlen; + struct pbuf *p, *q; + + netif = data; + unixif = netif->state; + + len = read(unixif->fd, &plen, sizeof(int)); + if(len == -1) { + perror("unixif_irq_handler: read"); + abort(); + } + + DEBUGF(UNIXIF_DEBUG, ("unixif_irq_handler: len == %d plen == %d bytes\n", len, plen)); + if(len == sizeof(int)) { + + if(plen < 20 || plen > 1500) { + DEBUGF(UNIXIF_DEBUG, ("plen %d!\n", plen)); + return; + } + + len = read(unixif->fd, buf, plen); + if(len == -1) { + perror("unixif_irq_handler: read"); + abort(); + } + DEBUGF(UNIXIF_DEBUG, ("unixif_irq_handler: read %d bytes\n", len)); + p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL); + + if(p != NULL) { + rlen = len; + bufptr = buf; + q = p; + while(rlen > 0) { + bcopy(bufptr, q->payload, rlen > q->len? q->len: rlen); + rlen -= q->len; + bufptr += q->len; + q = q->next; + } + pbuf_realloc(p, len); +#ifdef LINK_STATS + stats.link.recv++; +#endif /* LINK_STATS */ + tcpdump(p); + netif->input(p, netif); + } else { + DEBUGF(UNIXIF_DEBUG, ("unixif_irq_handler: could not allocate pbuf\n")); + } + + + } +} +/*-----------------------------------------------------------------------------------*/ +static void +unixif_thread(void *arg) +{ + struct netif *netif; + struct unixif *unixif; + + DEBUGF(UNIXIF_DEBUG, ("unixif_thread: started.\n")); + + netif = arg; + unixif = netif->state; + + + while(1) { + sys_sem_wait(unixif->sem); + unixif_input_handler(netif); + } + +} +/*-----------------------------------------------------------------------------------*/ +static void +unixif_thread2(void *arg) +{ + struct netif *netif; + struct unixif *unixif; + fd_set fdset; + + DEBUGF(UNIXIF_DEBUG, ("unixif_thread2: started.\n")); + + netif = arg; + unixif = netif->state; + + while(1) { + FD_ZERO(&fdset); + FD_SET(unixif->fd, &fdset); + + if(select(unixif->fd + 1, &fdset, NULL, NULL, NULL) > 0) { + sys_sem_signal(unixif->sem); + } + } +} +/*-----------------------------------------------------------------------------------*/ +static void unixif_output_timeout(void *arg); + +static err_t +unixif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) +{ + struct unixif *unixif; + struct unixif_buf *buf; + unixif = netif->state; + + buf = malloc(sizeof(struct unixif_buf)); + buf->p = p; + buf->len = p->len; + buf->tot_len = p->tot_len; + buf->payload = p->payload; + + if(list_elems(unixif->q) == 0) { + pbuf_ref(p); + list_push(unixif->q, buf); + sys_timeout((double)p->tot_len * 8000.0 / UNIXIF_BPS, unixif_output_timeout, + netif); + + DEBUGF(UNIXIF_DEBUG, ("unixif_output: first on list\n")); + + } else { + pbuf_ref(p); + if(list_push(unixif->q, buf) == 0) { +#ifdef UNIXIF_DROP_FIRST + struct unixif_buf *buf2; + + buf2 = list_pop(unixif->q); + pbuf_free(buf2->p); + free(buf2); + list_push(unixif->q, buf); +#else + free(buf); + pbuf_free(p); + + DEBUGF(UNIXIF_DEBUG, ("unixif_output: drop\n")); + +#endif /* UNIXIF_DROP_FIRST */ +#ifdef LINK_STATS + stats.link.drop++; +#endif /* LINK_STATS */ + + } else { + DEBUGF(UNIXIF_DEBUG, ("unixif_output: on list\n")); + } + + } + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +static void +unixif_output_timeout(void *arg) +{ + struct pbuf *p, *q; + int i, j, len; + unsigned short plen, ptot_len; + struct unixif_buf *buf; + void *payload; + struct netif *netif; + struct unixif *unixif; + char *data; + + netif = arg; + unixif = netif->state; + + DEBUGF(UNIXIF_DEBUG, ("unixif_output_timeout\n")); + + /* buf = unixif->q[0]; + unixif->q[0] = unixif->q[1]; + unixif->q[1] = NULL;*/ + buf = list_pop(unixif->q); + + p = buf->p; + + plen = p->len; + ptot_len = p->tot_len; + payload = p->payload; + + p->len = buf->len; + p->tot_len = buf->tot_len; + p->payload = buf->payload; + + + if(p->tot_len == 0) { + + DEBUGF(UNIXIF_DEBUG, ("p->len!\n")); + abort(); + } + data = malloc(p->tot_len); + + i = 0; + for(q = p; q != NULL; q = q->next) { + for(j = 0; j < q->len; j++) { + data[i] = ((char *)q->payload)[j]; + i++; + } + } + + DEBUGF(UNIXIF_DEBUG, ("unixif_output: sending %d (%d) bytes\n", + p->len, p->tot_len)); + + len = p->tot_len; + if(write(unixif->fd, &len, sizeof(int)) == -1) { + perror("unixif_output: write"); + abort(); + } + + if(write(unixif->fd, data, p->tot_len) == -1) { + perror("unixif_output: write"); + abort(); + } + tcpdump(p); +#ifdef LINK_STATS + stats.link.xmit++; +#endif /* LINK_STATS */ + + free(data); + free(buf); + p->len = plen; + p->tot_len = ptot_len; + p->payload = payload; + + pbuf_free(p); + + /* if(unixif->q[0] != NULL) { + sys_timeout(unixif->q[0]->tot_len * 8000 / UNIXIF_BPS, + unixif_output_timeout, netif); + }*/ + if(list_elems(unixif->q) > 0) { + sys_timeout(((struct unixif_buf *)list_first(unixif->q))->tot_len * + 8000.0 / UNIXIF_BPS, + unixif_output_timeout, netif); + } +} +/*-----------------------------------------------------------------------------------*/ +void +unixif_init_server(struct netif *netif) +{ + int fd, fd2; + struct sockaddr_un addr; + socklen_t len; + struct unixif *unixif; + + fd = unix_socket_server("/tmp/unixif"); + + if(fd == -1) { + perror("unixif_server"); + abort(); + } + DEBUGF(UNIXIF_DEBUG, ("unixif_server: fd %d\n", fd)); + + unixif = malloc(sizeof(struct unixif)); + netif->state = unixif; + netif->name[0] = 'u'; + netif->name[1] = 'n'; + netif->output = unixif_output; + unixif->q = list_new(UNIXIF_QUEUELEN); + + printf("Now run ./simnode.\n"); + len = sizeof(addr); + fd2 = accept(fd, (struct sockaddr *)&addr, &len); + + if(fd2 == -1) { + perror("unixif_accept"); + abort(); + } + + DEBUGF(UNIXIF_DEBUG, ("unixif_accept: %d\n", fd2)); + + unixif->fd = fd2; + unixif->sem = sys_sem_new(0); + sys_thread_new(unixif_thread, netif); + sys_thread_new(unixif_thread2, netif); +} +/*-----------------------------------------------------------------------------------*/ +void +unixif_init_client(struct netif *netif) +{ + struct unixif *unixif; + unixif = malloc(sizeof(struct unixif)); + netif->state = unixif; + netif->name[0] = 'u'; + netif->name[1] = 'n'; + netif->output = unixif_output; + + unixif->fd = unix_socket_client("/tmp/unixif"); + if(unixif->fd == -1) { + perror("unixif_init"); + abort(); + } + unixif->q = list_new(UNIXIF_QUEUELEN); + unixif->sem = sys_sem_new(0); + sys_thread_new(unixif_thread, netif); + sys_thread_new(unixif_thread2, netif); +} +/*-----------------------------------------------------------------------------------*/ + + diff --git a/src/arch/unix/perf.c b/src/arch/unix/perf.c new file mode 100644 index 00000000..009344ac --- /dev/null +++ b/src/arch/unix/perf.c @@ -0,0 +1,64 @@ +/* + * 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 + * + */ + +#include "arch/perf.h" + +#include + +static FILE *f; + +void +perf_print(unsigned long c1l, unsigned long c1h, + unsigned long c2l, unsigned long c2h, + char *key) +{ + unsigned long long start, end; + + start = (unsigned long long)c2h << 32 | c2l; + end = (unsigned long long)c1h << 32 | c1l; + fprintf(f, "%s: %llu\n", key, start - end); + fflush(NULL); +} + +void +perf_print_times(struct tms *start, struct tms *end, char *key) +{ + fprintf(f, "%s: %lu\n", key, end->tms_stime - start->tms_stime); + fflush(NULL); +} + +void +perf_init(char *fname) +{ + f = fopen(fname, "w"); +} + diff --git a/src/arch/unix/sys_arch.c b/src/arch/unix/sys_arch.c new file mode 100644 index 00000000..b6af5ab7 --- /dev/null +++ b/src/arch/unix/sys_arch.c @@ -0,0 +1,453 @@ +/* + * 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 + * + */ + +/* + * Wed Apr 17 16:05:29 EDT 2002 (James Roth) + * + * - Fixed an unlikely sys_thread_new() race condition. + * + * - Made current_thread() work with threads which where + * not created with sys_thread_new(). This includes + * the main thread and threads made with pthread_create(). + * + * - Catch overflows where more than SYS_MBOX_SIZE messages + * are waiting to be read. The sys_mbox_post() routine + * will block until there is more room instead of just + * leaking messages. + */ +#include "lwip/debug.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "lwip/sys.h" +#include "lwip/opt.h" +#include "lwip/stats.h" + +#define UMAX(a, b) ((a) > (b) ? (a) : (b)) + +static struct sys_thread *threads = NULL; +static pthread_mutex_t threads_mutex = PTHREAD_MUTEX_INITIALIZER; + +struct sys_mbox_msg { + struct sys_mbox_msg *next; + void *msg; +}; + +#define SYS_MBOX_SIZE 128 + +struct sys_mbox { + int first, last; + void *msgs[SYS_MBOX_SIZE]; + struct sys_sem *mail; + struct sys_sem *mutex; + int wait_send; +}; + +struct sys_sem { + unsigned int c; + pthread_cond_t cond; + pthread_mutex_t mutex; +}; + +struct sys_thread { + struct sys_thread *next; + struct sys_timeouts timeouts; + pthread_t pthread; +}; + + +static struct timeval starttime; + +static struct sys_sem *sys_sem_new_(u8_t count); +static void sys_sem_free_(struct sys_sem *sem); + +static u16_t cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex, + u16_t timeout); + +/*-----------------------------------------------------------------------------------*/ +static struct sys_thread * +introduce_thread(pthread_t id) +{ + struct sys_thread *thread; + + thread = malloc(sizeof(struct sys_thread)); + + if(thread) { + pthread_mutex_lock(&threads_mutex); + thread->next = threads; + thread->timeouts.next = NULL; + thread->pthread = id; + threads = thread; + pthread_mutex_unlock(&threads_mutex); + } + + return thread; +} +/*-----------------------------------------------------------------------------------*/ +static struct sys_thread * +current_thread(void) +{ + struct sys_thread *st; + pthread_t pt; + pt = pthread_self(); + pthread_mutex_lock(&threads_mutex); + + for(st = threads; st != NULL; st = st->next) { + if(pthread_equal(st->pthread, pt)) { + pthread_mutex_unlock(&threads_mutex); + + return st; + } + } + + pthread_mutex_unlock(&threads_mutex); + + st = introduce_thread(pt); + + if(!st) { + printf("current_thread???\n"); + abort(); + } + + return st; +} +/*-----------------------------------------------------------------------------------*/ +void +sys_thread_new(void (*function)(void *arg), void *arg) +{ + int code; + pthread_t tmp; + struct sys_thread *st = NULL; + + code = pthread_create(&tmp, + NULL, + (void *(*)(void *)) + function, + arg); + + if(0 == code) { + st = introduce_thread(tmp); + } + + if(NULL == st) { + DEBUGF(SYS_DEBUG, ("sys_thread_new: pthread_create %d, st = 0x%x", + code, (int)st)); + abort(); + } +} +/*-----------------------------------------------------------------------------------*/ +struct sys_mbox * +sys_mbox_new() +{ + struct sys_mbox *mbox; + + mbox = malloc(sizeof(struct sys_mbox)); + mbox->first = mbox->last = 0; + mbox->mail = sys_sem_new_(0); + mbox->mutex = sys_sem_new_(1); + mbox->wait_send = 0; + +#ifdef SYS_STATS + stats.sys.mbox.used++; + if(stats.sys.mbox.used > stats.sys.mbox.max) { + stats.sys.mbox.max = stats.sys.mbox.used; + } +#endif /* SYS_STATS */ + + return mbox; +} +/*-----------------------------------------------------------------------------------*/ +void +sys_mbox_free(struct sys_mbox *mbox) +{ + if(mbox != SYS_MBOX_NULL) { +#ifdef SYS_STATS + stats.sys.mbox.used--; +#endif /* SYS_STATS */ + sys_sem_wait(mbox->mutex); + + sys_sem_free_(mbox->mail); + sys_sem_free_(mbox->mutex); + mbox->mail = mbox->mutex = NULL; + /* DEBUGF("sys_mbox_free: mbox 0x%lx\n", mbox); */ + free(mbox); + } +} + +/*-----------------------------------------------------------------------------------*/ +void +sys_mbox_post(struct sys_mbox *mbox, void *msg) +{ + u8_t first; + + sys_sem_wait(mbox->mutex); + + DEBUGF(SYS_DEBUG, ("sys_mbox_post: mbox %p msg %p\n", mbox, msg)); + + while((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE)) { + mbox->wait_send++; + sys_sem_signal(mbox->mutex); + sys_arch_sem_wait(mbox->mail, 0); + sys_arch_sem_wait(mbox->mutex, 0); + mbox->wait_send--; + } + + mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg; + + if(mbox->last == mbox->first) { + first = 1; + } else { + first = 0; + } + + mbox->last++; + + if(first) { + sys_sem_signal(mbox->mail); + } + + sys_sem_signal(mbox->mutex); +} +/*-----------------------------------------------------------------------------------*/ +u16_t +sys_arch_mbox_fetch(struct sys_mbox *mbox, void **msg, u16_t timeout) +{ + u16_t time = 1; + + /* The mutex lock is quick so we don't bother with the timeout + stuff here. */ + sys_arch_sem_wait(mbox->mutex, 0); + + while(mbox->first == mbox->last) { + sys_sem_signal(mbox->mutex); + + /* We block while waiting for a mail to arrive in the mailbox. We + must be prepared to timeout. */ + if(timeout != 0) { + time = sys_arch_sem_wait(mbox->mail, timeout); + + /* If time == 0, the sem_wait timed out, and we return 0. */ + if(time == 0) { + return 0; + } + } else { + sys_arch_sem_wait(mbox->mail, 0); + } + + sys_arch_sem_wait(mbox->mutex, 0); + } + + DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p msg %p\n", mbox, *msg)); + + if(msg != NULL) { + *msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE]; + } + + mbox->first++; + + if(mbox->wait_send) { + sys_sem_signal(mbox->mail); + } + + sys_sem_signal(mbox->mutex); + + return time; +} +/*-----------------------------------------------------------------------------------*/ +struct sys_sem * +sys_sem_new(u8_t count) +{ +#ifdef SYS_STATS + stats.sys.sem.used++; + if(stats.sys.sem.used > stats.sys.sem.max) { + stats.sys.sem.max = stats.sys.sem.used; + } +#endif /* SYS_STATS */ + return sys_sem_new_(count); +} + +/*-----------------------------------------------------------------------------------*/ +static struct sys_sem * +sys_sem_new_(u8_t count) +{ + struct sys_sem *sem; + + sem = malloc(sizeof(struct sys_sem)); + sem->c = count; + + pthread_cond_init(&(sem->cond), NULL); + pthread_mutex_init(&(sem->mutex), NULL); + + return sem; +} + +/*-----------------------------------------------------------------------------------*/ +static u16_t +cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex, u16_t timeout) +{ + int tdiff; + unsigned long sec, usec; + struct timeval rtime1, rtime2; + struct timespec ts; + struct timezone tz; + int retval; + + if(timeout > 0) { + /* Get a timestamp and add the timeout value. */ + gettimeofday(&rtime1, &tz); + sec = rtime1.tv_sec; + usec = rtime1.tv_usec; + usec += timeout % 1000 * 1000; + sec += (int)(timeout / 1000) + (int)(usec / 1000000); + usec = usec % 1000000; + ts.tv_nsec = usec * 1000; + ts.tv_sec = sec; + + retval = pthread_cond_timedwait(cond, mutex, &ts); + + if(retval == ETIMEDOUT) { + return 0; + } else { + /* Calculate for how long we waited for the cond. */ + gettimeofday(&rtime2, &tz); + tdiff = (rtime2.tv_sec - rtime1.tv_sec) * 1000 + + (rtime2.tv_usec - rtime1.tv_usec) / 1000; + + if(tdiff <= 0) { + return 1; + } + + return tdiff; + } + } else { + pthread_cond_wait(cond, mutex); + return 0; + } +} +/*-----------------------------------------------------------------------------------*/ +u16_t +sys_arch_sem_wait(struct sys_sem *sem, u16_t timeout) +{ + u16_t time = 1; + + pthread_mutex_lock(&(sem->mutex)); + while(sem->c <= 0) { + if(timeout > 0) { + time = cond_wait(&(sem->cond), &(sem->mutex), timeout); + + if(time == 0) { + pthread_mutex_unlock(&(sem->mutex)); + return 0; + } + /* pthread_mutex_unlock(&(sem->mutex)); + return time; */ + } else { + cond_wait(&(sem->cond), &(sem->mutex), 0); + } + } + sem->c--; + pthread_mutex_unlock(&(sem->mutex)); + return time; +} +/*-----------------------------------------------------------------------------------*/ +void +sys_sem_signal(struct sys_sem *sem) +{ + pthread_mutex_lock(&(sem->mutex)); + sem->c++; + + if(sem->c > 1) { + sem->c = 1; + } + + pthread_cond_broadcast(&(sem->cond)); + pthread_mutex_unlock(&(sem->mutex)); +} +/*-----------------------------------------------------------------------------------*/ +void +sys_sem_free(struct sys_sem *sem) +{ + if(sem != SYS_SEM_NULL) { +#ifdef SYS_STATS + stats.sys.sem.used--; +#endif /* SYS_STATS */ + sys_sem_free_(sem); + } +} + +/*-----------------------------------------------------------------------------------*/ +static void +sys_sem_free_(struct sys_sem *sem) +{ + pthread_cond_destroy(&(sem->cond)); + pthread_mutex_destroy(&(sem->mutex)); + free(sem); +} +/*-----------------------------------------------------------------------------------*/ +unsigned long +sys_unix_now() +{ + struct timeval tv; + struct timezone tz; + long sec, usec; + unsigned long msec; + gettimeofday(&tv, &tz); + + sec = tv.tv_sec - starttime.tv_sec; + usec = tv.tv_usec - starttime.tv_usec; + msec = sec * 1000 + usec / 1000; + + return msec; +} +/*-----------------------------------------------------------------------------------*/ +void +sys_init() +{ + struct timezone tz; + gettimeofday(&starttime, &tz); +} +/*-----------------------------------------------------------------------------------*/ +struct sys_timeouts * +sys_arch_timeouts(void) +{ + struct sys_thread *thread; + + thread = current_thread(); + return &thread->timeouts; +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/core/inet.c b/src/core/inet.c new file mode 100644 index 00000000..c8d7a852 --- /dev/null +++ b/src/core/inet.c @@ -0,0 +1,162 @@ +/* + * 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 + * + */ + +/*-----------------------------------------------------------------------------------*/ +/* inet.c + * + * Functions common to all TCP/IP modules, such as the Internet checksum and the + * byte order functions. + * + */ +/*-----------------------------------------------------------------------------------*/ + +#include "lwip/debug.h" + +#include "lwip/arch.h" + +#include "lwip/def.h" +#include "lwip/inet.h" + + +/*-----------------------------------------------------------------------------------*/ +static u16_t +lwip_chksum(void *dataptr, int len) +{ + u32_t acc; + + for(acc = 0; len > 1; len -= 2) { + acc += *((u16_t *)dataptr)++; + } + + /* add up any odd byte */ + if(len == 1) { + acc += htons((u16_t)((*(u8_t *)dataptr) & 0xff) << 8); + DEBUGF(INET_DEBUG, ("inet: chksum: odd byte %d\n", *(u8_t *)dataptr)); + } + acc = (acc >> 16) + (acc & 0xffffUL); + + if(acc & 0xffff0000 != 0) { + acc = (acc >> 16) + (acc & 0xffffUL); + } + + return (u16_t)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, u16_t proto_len) +{ + 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 & 0xff) << 8) | ((acc & 0xff00UL) >> 8); + } + } + + 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); + } + return ~(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 ~(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 & 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); +} + + +/*-----------------------------------------------------------------------------------*/ diff --git a/src/core/inet6.c b/src/core/inet6.c new file mode 100644 index 00000000..028f0670 --- /dev/null +++ b/src/core/inet6.c @@ -0,0 +1,168 @@ +/* + * 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 + * + */ + +/*-----------------------------------------------------------------------------------*/ +/* inet6.c + * + * Functions common to all TCP/IP modules, such as the Internet checksum and the + * byte order functions. + * + */ +/*-----------------------------------------------------------------------------------*/ + +#include "lwip/debug.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); +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/core/ipv4/icmp.c b/src/core/ipv4/icmp.c new file mode 100644 index 00000000..1ba58fc4 --- /dev/null +++ b/src/core/ipv4/icmp.c @@ -0,0 +1,199 @@ +/* + * 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 + * + */ + +/* Some ICMP messages should be passed to the transport protocols. This + is not implemented. */ + +#include "lwip/debug.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; + u16_t hlen; + +#ifdef ICMP_STATS + ++stats.icmp.recv; +#endif /* ICMP_STATS */ + + + iphdr = p->payload; + hlen = IPH_HL(iphdr) * 4/sizeof(u8_t); + pbuf_header(p, -hlen); + + type = *((u8_t *)p->payload); + + switch(type) { + case ICMP_ECHO: + if(ip_addr_isbroadcast(&iphdr->dest, &inp->netmask) || + ip_addr_ismulticast(&iphdr->dest)) { + DEBUGF(ICMP_DEBUG, ("Smurf.\n")); +#ifdef ICMP_STATS + ++stats.icmp.err; +#endif /* ICMP_STATS */ + pbuf_free(p); + return; + } + DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); + DEBUGF(DEMO_DEBUG, ("Pong!\n")); + if(p->tot_len < sizeof(struct icmp_echo_hdr)) { + DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); + pbuf_free(p); +#ifdef ICMP_STATS + ++stats.icmp.lenerr; +#endif /* ICMP_STATS */ + + return; + } + iecho = p->payload; + if(inet_chksum_pbuf(p) != 0) { + DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); + pbuf_free(p); +#ifdef ICMP_STATS + ++stats.icmp.chkerr; +#endif /* ICMP_STATS */ + 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); + } +#ifdef ICMP_STATS + ++stats.icmp.xmit; +#endif /* ICMP_STATS */ + + pbuf_header(p, hlen); + ip_output_if(p, &(iphdr->src), IP_HDRINCL, + IPH_TTL(iphdr), IP_PROTO_ICMP, inp); + break; + default: + DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type not supported.\n")); +#ifdef ICMP_STATS + ++stats.icmp.proterr; + ++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_TRANSPORT, 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); + + bcopy(p->payload, (char *)q->payload + 8, IP_HLEN + 8); + + /* calculate checksum */ + idur->chksum = 0; + idur->chksum = inet_chksum(idur, q->len); +#ifdef ICMP_STATS + ++stats.icmp.xmit; +#endif /* ICMP_STATS */ + + ip_output(q, NULL, &(iphdr->src), + ICMP_TTL, 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_TRANSPORT, 8 + IP_HLEN + 8, PBUF_RAM); + + iphdr = p->payload; +#if ICMP_DEBUG + DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); + ip_addr_debug_print(&(iphdr->src)); + DEBUGF(ICMP_DEBUG, (" to ")); + ip_addr_debug_print(&(iphdr->dest)); + DEBUGF(ICMP_DEBUG, ("\n")); +#endif /* ICMP_DEBNUG */ + + tehdr = q->payload; + ICMPH_TYPE_SET(tehdr, ICMP_TE); + ICMPH_CODE_SET(tehdr, t); + + /* copy fields from original packet */ + bcopy((char *)p->payload, (char *)q->payload + 8, IP_HLEN + 8); + + /* calculate checksum */ + tehdr->chksum = 0; + tehdr->chksum = inet_chksum(tehdr, q->len); +#ifdef ICMP_STATS + ++stats.icmp.xmit; +#endif /* ICMP_STATS */ + ip_output(q, NULL, &(iphdr->src), + ICMP_TTL, IP_PROTO_ICMP); + pbuf_free(q); +} + +#endif /* IP_FORWARDING > 0 */ + + + + + + + diff --git a/src/core/ipv4/ip.c b/src/core/ipv4/ip.c new file mode 100644 index 00000000..d3d06f23 --- /dev/null +++ b/src/core/ipv4/ip.c @@ -0,0 +1,700 @@ +/* + * 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 + * + */ + + +/*-----------------------------------------------------------------------------------*/ +/* ip.c + * + * This is the code for the IP layer. + * + */ +/*-----------------------------------------------------------------------------------*/ + +#include "lwip/debug.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" + +#if LWIP_DHCP +#include "lwip/dhcp.h" +#endif /* LWIP_DHCP */ + +/*-----------------------------------------------------------------------------------*/ +/* ip_init: + * + * Initializes the IP layer. + */ +/*-----------------------------------------------------------------------------------*/ +void +ip_init(void) +{ +} +/*-----------------------------------------------------------------------------------*/ +/* ip_lookup: + * + * An experimental feature that will be changed in future versions. Do + * not depend on it yet... + */ +/*-----------------------------------------------------------------------------------*/ +#ifdef LWIP_DEBUG +u8_t +ip_lookup(void *header, struct netif *inp) +{ + struct ip_hdr *iphdr; + + iphdr = header; + + /* Refuse anything that isn't IPv4. */ + if(IPH_V(iphdr) != 4) { + return 0; + } + + /* Immediately accept/decline packets that are fragments or has + options. */ +#if IP_REASSEMBLY == 0 + /* if((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { + return 0; + }*/ +#endif /* IP_REASSEMBLY == 0 */ + +#if IP_OPTIONS == 0 + if(IPH_HL(iphdr) != 5) { + return 0; + } +#endif /* IP_OPTIONS == 0 */ + + switch(IPH_PROTO(iphdr)) { +#if LWIP_UDP > 0 + case IP_PROTO_UDP: + return udp_lookup(iphdr, inp); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP > 0 + case IP_PROTO_TCP: + return 1; +#endif /* LWIP_TCP */ + case IP_PROTO_ICMP: + return 1; + break; + default: + return 0; + } +} +#endif /* LWIP_DEBUG */ +/*-----------------------------------------------------------------------------------*/ +/* 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_maskcmp(dest, &(netif->ip_addr), &(netif->netmask))) { + return netif; + } + } + + return netif_default; +} +#if IP_FORWARD +/*-----------------------------------------------------------------------------------*/ +/* 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 *inp) +{ + static struct netif *netif; + + PERF_START; + + if((netif = ip_route((struct ip_addr *)&(iphdr->dest))) == NULL) { + + DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%lx found\n", + iphdr->dest.addr)); + + return; + } + + /* Don't forward packets onto the same network interface on which + they arrived. */ + if(netif == inp) { + DEBUGF(IP_DEBUG, ("ip_forward: not forward packets back on incoming interface.\n")); + + return; + } + + /* Decrement TTL and send ICMP if ttl == 0. */ + IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); + 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); + } + return; + } + + /* Incremental update of 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)); + } + + DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%lx\n", + iphdr->dest.addr)); + +#ifdef IP_STATS + ++stats.ip.fw; + ++stats.ip.xmit; +#endif /* IP_STATS */ + + PERF_STOP("ip_forward"); + + netif->output(netif, p, (struct ip_addr *)&(iphdr->dest)); +} +#endif /* IP_FORWARD */ +/*-----------------------------------------------------------------------------------*/ +/* ip_reass: + * + * Tries to reassemble a fragmented IP packet. + */ +/*-----------------------------------------------------------------------------------*/ +#define IP_REASSEMBLY 1 +#define IP_REASS_BUFSIZE 5760 +#define IP_REASS_MAXAGE 10 + +#if IP_REASSEMBLY +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; + +static struct pbuf * +ip_reass(struct pbuf *p) +{ + struct pbuf *q; + struct ip_hdr *fraghdr, *iphdr; + u16_t offset, len; + u16_t i; + + 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) { + DEBUGF(IP_REASS_DEBUG, ("ip_reass: new packet\n")); + bcopy(fraghdr, iphdr, IP_HLEN); + ip_reasstmr = IP_REASS_MAXAGE; + ip_reassflags = 0; + /* Clear the bitmap. */ + bzero(ip_reassbitmap, 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)) { + DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching old packet\n")); + /* 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) { + DEBUGF(IP_REASS_DEBUG, ("ip_reass: fragment outside of buffer (%d:%d/%d).\n", + offset, offset + len, IP_REASS_BUFSIZE)); + ip_reasstmr = 0; + goto nullreturn; + } + + /* Copy the fragment into the reassembly buffer, at the right + offset. */ + DEBUGF(IP_REASS_DEBUG, ("ip_reass: copying with offset %d into %d:%d\n", + offset, IP_HLEN + offset, IP_HLEN + offset + len)); + bcopy((u8_t *)fraghdr + IPH_HL(fraghdr) * 4, + &ip_reassbuf[IP_HLEN + offset], len); + + /* Update the bitmap. */ + if(offset / (8 * 8) == (offset + len) / (8 * 8)) { + 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]; + 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; + 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) { + 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]) { + 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. */ + 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. */ + 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 + avaliable data in the pbuf is given by the q->len + variable. */ + DEBUGF(IP_REASS_DEBUG, ("ip_reass: bcopy from %p (%d) to %p, %d bytes\n", + &ip_reassbuf[i], i, q->payload, q->len > ip_reasslen - i? ip_reasslen - i: q->len)); + bcopy(&ip_reassbuf[i], q->payload, + q->len > ip_reasslen - i? ip_reasslen - i: q->len); + i += q->len; + } + } + DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", p)); + return p; + } + } + + nullreturn: + pbuf_free(p); + return NULL; +} +#endif /* IP_REASSEMBLY */ +/*-----------------------------------------------------------------------------------*/ +/* 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. + */ +/*-----------------------------------------------------------------------------------*/ +err_t +ip_input(struct pbuf *p, struct netif *inp) { + static struct ip_hdr *iphdr; + static struct netif *netif; + static u8_t hl; + + + +#ifdef IP_STATS + ++stats.ip.recv; +#endif /* IP_STATS */ + + /* identify the IP header */ + iphdr = p->payload; + if(IPH_V(iphdr) != 4) { + DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number %d\n", IPH_V(iphdr))); +#if IP_DEBUG + ip_debug_print(p); +#endif /* IP_DEBUG */ + pbuf_free(p); +#ifdef IP_STATS + ++stats.ip.err; + ++stats.ip.drop; +#endif /* IP_STATS */ + return ERR_OK; + } + + hl = IPH_HL(iphdr); + + if(hl * 4 > p->len) { + DEBUGF(IP_DEBUG, ("IP packet dropped due to too short packet %d\n", p->len)); + + pbuf_free(p); +#ifdef IP_STATS + ++stats.ip.lenerr; + ++stats.ip.drop; +#endif /* IP_STATS */ + return ERR_OK; + } + + /* verify checksum */ + if(inet_chksum(iphdr, hl * 4) != 0) { + + DEBUGF(IP_DEBUG, ("IP packet dropped due to failing checksum 0x%x\n", inet_chksum(iphdr, hl * 4))); +#if IP_DEBUG + ip_debug_print(p); +#endif /* IP_DEBUG */ + pbuf_free(p); +#ifdef IP_STATS + ++stats.ip.chkerr; + ++stats.ip.drop; +#endif /* IP_STATS */ + return ERR_OK; + } + + /* 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))); + + /* is this packet for us? */ + for(netif = netif_list; netif != NULL; netif = netif->next) { + + 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))); + + if(ip_addr_isany(&(netif->ip_addr)) || + ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) || + (ip_addr_isbroadcast(&(iphdr->dest), &(netif->netmask)) && + ip_addr_maskcmp(&(iphdr->dest), &(netif->ip_addr), &(netif->netmask))) || + ip_addr_cmp(&(iphdr->dest), IP_ADDR_BROADCAST)) { + break; + } + } + +#if LWIP_DHCP + /* If a DHCP packet has arrived on the interface, we pass it up the + stack regardless of destination IP address. The reason is that + DHCP replies are sent to the IP adress that will be given to this + node (as recommended by RFC 1542 section 3.1.1, referred by RFC + 2131). */ + if(IPH_PROTO(iphdr) == IP_PROTO_UDP && + ((struct udp_hdr *)((u8_t *)iphdr + IPH_HL(iphdr) * 4/sizeof(u8_t)))->src == + DHCP_SERVER_PORT) { + netif = inp; + } +#endif /* LWIP_DHCP */ + + if(netif == NULL) { + /* packet not for us, route or discard */ + DEBUGF(IP_DEBUG, ("ip_input: packet not for us.\n")); +#if IP_FORWARD + if(!ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask))) { + ip_forward(p, iphdr, inp); + } +#endif /* IP_FORWARD */ + pbuf_free(p); + return ERR_OK; + } + +#if IP_REASSEMBLY + if((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { + p = ip_reass(p); + if(p == NULL) { + return ERR_OK; + } + iphdr = p->payload; + } +#else /* IP_REASSEMBLY */ + if((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { + pbuf_free(p); + DEBUGF(IP_DEBUG, ("IP packet dropped since it was fragmented (0x%x).\n", + ntohs(IPH_OFFSET(iphdr)))); +#ifdef IP_STATS + ++stats.ip.opterr; + ++stats.ip.drop; +#endif /* IP_STATS */ + return ERR_OK; + } +#endif /* IP_REASSEMBLY */ + +#if IP_OPTIONS == 0 + if(hl * 4 > IP_HLEN) { + DEBUGF(IP_DEBUG, ("IP packet dropped since there were IP options.\n")); + + pbuf_free(p); +#ifdef IP_STATS + ++stats.ip.opterr; + ++stats.ip.drop; +#endif /* IP_STATS */ + return ERR_OK; + } +#endif /* IP_OPTIONS == 0 */ + + + /* send to upper layers */ +#if IP_DEBUG + DEBUGF(IP_DEBUG, ("ip_input: \n")); + ip_debug_print(p); + DEBUGF(IP_DEBUG, ("ip_input: p->len %d p->tot_len %d\n", p->len, p->tot_len)); +#endif /* IP_DEBUG */ + + switch(IPH_PROTO(iphdr)) { +#if LWIP_UDP > 0 + case IP_PROTO_UDP: + udp_input(p, inp); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP > 0 + case IP_PROTO_TCP: + tcp_input(p, inp); + break; +#endif /* LWIP_TCP */ + case IP_PROTO_ICMP: + icmp_input(p, inp); + break; + default: + /* send ICMP destination protocol unreachable unless is was a broadcast */ + if(!ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask)) && + !ip_addr_ismulticast(&(iphdr->dest))) { + p->payload = iphdr; + icmp_dest_unreach(p, ICMP_DUR_PROTO); + } + pbuf_free(p); + + DEBUGF(IP_DEBUG, ("Unsupported transportation protocol %d\n", IPH_PROTO(iphdr))); + +#ifdef IP_STATS + ++stats.ip.proterr; + ++stats.ip.drop; +#endif /* IP_STATS */ + + } + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* 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) +{ + static struct ip_hdr *iphdr; + static u16_t ip_id = 0; + + + + if(dest != IP_HDRINCL) { + if(pbuf_header(p, IP_HLEN)) { + DEBUGF(IP_DEBUG, ("ip_output: not enough room for IP header in pbuf\n")); + +#ifdef IP_STATS + ++stats.ip.err; +#endif /* IP_STATS */ + 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, 0); + 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); + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + } else { + iphdr = p->payload; + dest = &(iphdr->dest); + } + +#ifdef IP_STATS + stats.ip.xmit++; +#endif /* IP_STATS */ + DEBUGF(IP_DEBUG, ("ip_output_if: %c%c ", netif->name[0], netif->name[1])); +#if IP_DEBUG + ip_debug_print(p); +#endif /* IP_DEBUG */ + + + 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) +{ + static struct netif *netif; + + + if((netif = ip_route(dest)) == NULL) { + DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%lx\n", dest->addr)); + +#ifdef IP_STATS + ++stats.ip.rterr; +#endif /* IP_STATS */ + pbuf_free(p); + 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; + u8_t *payload; + + payload = (u8_t *)iphdr + IP_HLEN/sizeof(u8_t); + + DEBUGF(IP_DEBUG, ("IP header:\n")); + DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(IP_DEBUG, ("|%2d |%2d | %2d | %4d | (v, hl, tos, len)\n", + IPH_V(iphdr), + IPH_HL(iphdr), + IPH_TOS(iphdr), + ntohs(IPH_LEN(iphdr)))); + DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(IP_DEBUG, ("| %5d |%d%d%d| %4d | (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)); + DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(IP_DEBUG, ("| %2d | %2d | 0x%04x | (ttl, proto, chksum)\n", + IPH_TTL(iphdr), + IPH_PROTO(iphdr), + ntohs(IPH_CHKSUM(iphdr)))); + DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(IP_DEBUG, ("| %3ld | %3ld | %3ld | %3ld | (src)\n", + ntohl(iphdr->src.addr) >> 24 & 0xff, + ntohl(iphdr->src.addr) >> 16 & 0xff, + ntohl(iphdr->src.addr) >> 8 & 0xff, + ntohl(iphdr->src.addr) & 0xff)); + DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(IP_DEBUG, ("| %3ld | %3ld | %3ld | %3ld | (dest)\n", + ntohl(iphdr->dest.addr) >> 24 & 0xff, + ntohl(iphdr->dest.addr) >> 16 & 0xff, + ntohl(iphdr->dest.addr) >> 8 & 0xff, + ntohl(iphdr->dest.addr) & 0xff)); + DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* IP_DEBUG */ +/*-----------------------------------------------------------------------------------*/ + + + + + diff --git a/src/core/ipv4/ip_addr.c b/src/core/ipv4/ip_addr.c new file mode 100644 index 00000000..fe952544 --- /dev/null +++ b/src/core/ipv4/ip_addr.c @@ -0,0 +1,41 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" +#include "lwip/ip_addr.h" +#include "lwip/inet.h" + +struct ip_addr ip_addr_broadcast = {0xffffffff}; + +/*-----------------------------------------------------------------------------------*/ + +/*-----------------------------------------------------------------------------------*/ diff --git a/src/core/ipv6/README b/src/core/ipv6/README new file mode 100644 index 00000000..36200048 --- /dev/null +++ b/src/core/ipv6/README @@ -0,0 +1 @@ +IPv6 support in lwIP is very experimental. diff --git a/src/core/ipv6/icmp6.c b/src/core/ipv6/icmp6.c new file mode 100644 index 00000000..08a4a853 --- /dev/null +++ b/src/core/ipv6/icmp6.c @@ -0,0 +1,184 @@ +/* + * 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 + * + */ + +/* Some ICMP messages should be passed to the transport protocols. This + is not implemented. */ + +#include "lwip/debug.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 + ++stats.icmp.recv; +#endif /* ICMP_STATS */ + + type = ((char *)p->payload)[0]; + + switch(type) { + case ICMP6_ECHO: + DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); + + if(p->tot_len < sizeof(struct icmp_echo_hdr)) { + DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); + + pbuf_free(p); +#ifdef ICMP_STATS + ++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) { + 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 + ++stats.icmp.chkerr; +#endif /* ICMP_STATS */ + /* return;*/ + } + 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); + } + 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 + ++stats.icmp.xmit; +#endif /* ICMP_STATS */ + + /* DEBUGF("icmp: p->len %d p->tot_len %d\n", p->len, p->tot_len);*/ + ip_output_if(p, &(iphdr->src), IP_HDRINCL, + iphdr->hoplim, IP_PROTO_ICMP, inp); + break; + default: + DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type not supported.\n")); + +#ifdef ICMP_STATS + ++stats.icmp.proterr; + ++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_TRANSPORT, 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; + + bcopy(p->payload, (char *)q->payload + 8, IP_HLEN + 8); + + /* calculate checksum */ + idur->chksum = 0; + idur->chksum = inet_chksum(idur, q->len); +#ifdef ICMP_STATS + ++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; + + DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n")); + + q = pbuf_alloc(PBUF_TRANSPORT, 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 */ + bcopy((char *)p->payload, (char *)q->payload + 8, IP_HLEN + 8); + + /* calculate checksum */ + tehdr->chksum = 0; + tehdr->chksum = inet_chksum(tehdr, q->len); +#ifdef ICMP_STATS + ++stats.icmp.xmit; +#endif /* ICMP_STATS */ + ip_output(q, NULL, + (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP); + pbuf_free(q); +} + + + + + + + + diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c new file mode 100644 index 00000000..60d93901 --- /dev/null +++ b/src/core/ipv6/ip6.c @@ -0,0 +1,386 @@ +/* + * 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 + * + */ + + +/*-----------------------------------------------------------------------------------*/ +/* ip.c + * + * This is the code for the IP layer for IPv6. + * + */ +/*-----------------------------------------------------------------------------------*/ + +#include "lwip/debug.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_maskcmp(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) { + + DEBUGF(IP_DEBUG, ("ip_input: no forwarding route found for ")); +#if IP_DEBUG + ip_addr_debug_print(&(iphdr->dest)); +#endif /* IP_DEBUG */ + 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); + }*/ + + + DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to ")); +#if IP_DEBUG + ip_addr_debug_print(&(iphdr->dest)); +#endif /* IP_DEBUG */ + DEBUGF(IP_DEBUG, ("\n")); + +#ifdef IP_STATS + ++stats.ip.fw; + ++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 + ++stats.ip.recv; +#endif /* IP_STATS */ + + /* identify the IP header */ + iphdr = p->payload; + + + if(iphdr->v != 6) { + 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 + ++stats.ip.err; + ++stats.ip.drop; +#endif /* IP_STATS */ + return; + } + + /* is this packet for us? */ + for(netif = netif_list; netif != NULL; netif = netif->next) { +#if IP_DEBUG + DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest ")); + ip_addr_debug_print(&(iphdr->dest)); + DEBUGF(IP_DEBUG, ("netif->ip_addr ")); + ip_addr_debug_print(&(netif->ip_addr)); + 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 + /* DEBUGF("ip_input: \n"); + ip_debug_print(p); + DEBUGF("ip_input: p->len %d p->tot_len %d\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); + DEBUGF(IP_DEBUG, ("Unsupported transportation protocol %d\n", + iphdr->nexthdr)); + +#ifdef IP_STATS + ++stats.ip.proterr; + ++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 %d tot_len %d\n", p->len, p->tot_len); + if(pbuf_header(p, IP_HLEN)) { + DEBUGF(IP_DEBUG, ("ip_output: not enough room for IP header in pbuf\n")); +#ifdef IP_STATS + ++stats.ip.err; +#endif /* IP_STATS */ + + return ERR_BUF; + } + printf("len %d tot_len %d\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 + ++stats.ip.xmit; +#endif /* IP_STATS */ + + DEBUGF(IP_DEBUG, ("ip_output_if: %c%c (len %d)\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) { + DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%lx\n", dest->addr)); +#ifdef IP_STATS + ++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; + + DEBUGF(IP_DEBUG, ("IP header:\n")); + DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(IP_DEBUG, ("|%2d | %x%x | %x%x | (v, traffic class, flow label)\n", + iphdr->v, + iphdr->tclass1, iphdr->tclass2, + iphdr->flow1, iphdr->flow2)); + DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(IP_DEBUG, ("| %5d | %2d | %2d | (len, nexthdr, hoplim)\n", + ntohs(iphdr->len), + iphdr->nexthdr, + iphdr->hoplim)); + DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (src)\n", + ntohl(iphdr->src.addr[0]) >> 16 & 0xffff, + ntohl(iphdr->src.addr[0]) & 0xffff)); + DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (src)\n", + ntohl(iphdr->src.addr[1]) >> 16 & 0xffff, + ntohl(iphdr->src.addr[1]) & 0xffff)); + DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (src)\n", + ntohl(iphdr->src.addr[2]) >> 16 & 0xffff, + ntohl(iphdr->src.addr[2]) & 0xffff)); + DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (src)\n", + ntohl(iphdr->src.addr[3]) >> 16 & 0xffff, + ntohl(iphdr->src.addr[3]) & 0xffff)); + DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (dest)\n", + ntohl(iphdr->dest.addr[0]) >> 16 & 0xffff, + ntohl(iphdr->dest.addr[0]) & 0xffff)); + DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (dest)\n", + ntohl(iphdr->dest.addr[1]) >> 16 & 0xffff, + ntohl(iphdr->dest.addr[1]) & 0xffff)); + DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (dest)\n", + ntohl(iphdr->dest.addr[2]) >> 16 & 0xffff, + ntohl(iphdr->dest.addr[2]) & 0xffff)); + DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (dest)\n", + ntohl(iphdr->dest.addr[3]) >> 16 & 0xffff, + ntohl(iphdr->dest.addr[3]) & 0xffff)); + DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* IP_DEBUG */ +/*-----------------------------------------------------------------------------------*/ diff --git a/src/core/ipv6/ip6_addr.c b/src/core/ipv6/ip6_addr.c new file mode 100644 index 00000000..f573d141 --- /dev/null +++ b/src/core/ipv6/ip6_addr.c @@ -0,0 +1,91 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" +#include "lwip/ip_addr.h" +#include "lwip/inet.h" + +/*-----------------------------------------------------------------------------------*/ +int +ip_addr_maskcmp(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) +{ + bcopy(src, dest, 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 */ +/*-----------------------------------------------------------------------------------*/ diff --git a/src/core/mem.c b/src/core/mem.c new file mode 100644 index 00000000..1e694eb1 --- /dev/null +++ b/src/core/mem.c @@ -0,0 +1,297 @@ +/* + * 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 + * + */ + +/*-----------------------------------------------------------------------------------*/ +/* mem.c + * + * Memory manager. + * + */ +/*-----------------------------------------------------------------------------------*/ +#include "lwip/debug.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; + u8_t used; +#if MEM_ALIGNMENT == 2 + u8_t dummy; +#endif /* MEM_ALIGNEMNT == 2 */ +}; + +static struct mem *ram_end; +static u8_t ram[MEM_SIZE + sizeof(struct mem) + MEM_ALIGNMENT]; + +#define MIN_SIZE 12 +#define SIZEOF_STRUCT_MEM MEM_ALIGN_SIZE(sizeof(struct mem)) +/*#define SIZEOF_STRUCT_MEM (sizeof(struct mem) + \ + (((sizeof(struct mem) % MEM_ALIGNMENT) == 0)? 0 : \ + (4 - (sizeof(struct mem) % MEM_ALIGNMENT))))*/ + + +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; + + ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram); + ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end); + ASSERT("plug_holes: mem->used == 0", mem->used == 0); + + /* plug hole forward */ + 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; + + bzero(ram, 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; + +#ifdef MEM_STATS + stats.mem.avail = MEM_SIZE; +#endif /* MEM_STATS */ +} +/*-----------------------------------------------------------------------------------*/ +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; +#ifdef MEM_STATS + stats.mem.used += size; + /* if(stats.mem.max < stats.mem.used) { + stats.mem.max = stats.mem.used; + } */ + if(stats.mem.max < ptr2) { + 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]; + } + ASSERT("mem_malloc: !lfree->used", !lfree->used); + } + sys_sem_signal(mem_sem); + ASSERT("mem_malloc: allocated memory not above ram_end.", + (u32_t)mem + SIZEOF_STRUCT_MEM + size <= (u32_t)ram_end); + 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; + } + } + DEBUGF(MEM_DEBUG, ("mem_malloc: could not allocate %d bytes\n", (int)size)); +#ifdef MEM_STATS + ++stats.mem.err; +#endif /* MEM_STATS */ + sys_sem_signal(mem_sem); + return NULL; +} +/*-----------------------------------------------------------------------------------*/ +void +mem_free(void *rmem) +{ + struct mem *mem; + + if(rmem == NULL) { + return; + } + + sys_sem_wait(mem_sem); + + 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) { + DEBUGF(MEM_DEBUG, ("mem_free: illegal memory\n")); +#ifdef MEM_STATS + ++stats.mem.err; +#endif /* MEM_STATS */ + return; + } + mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); + + ASSERT("mem_free: mem->used", mem->used); + + mem->used = 0; + + if(mem < lfree) { + lfree = mem; + } + +#ifdef MEM_STATS + stats.mem.used -= mem->next - ((u8_t *)mem - ram) - SIZEOF_STRUCT_MEM; + +#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); + } + bcopy(rmem, nmem, 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; + + sys_sem_wait(mem_sem); + + 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) { + DEBUGF(MEM_DEBUG, ("mem_free: 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; +#ifdef MEM_STATS + 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; +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/core/memp.c b/src/core/memp.c new file mode 100644 index 00000000..86ada637 --- /dev/null +++ b/src/core/memp.c @@ -0,0 +1,271 @@ +/* + * 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 + * + */ + +#include "lwipopts.h" + +#include "lwip/memp.h" + +#include "lwip/pbuf.h" +#include "lwip/udp.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 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_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_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)))]; + +/*-----------------------------------------------------------------------------------*/ +static sys_sem_t mutex; +/*-----------------------------------------------------------------------------------*/ +#ifdef LWIP_DEBUG +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) + abort(); + } + } + } + return 1; +} +#endif /* LWIP_DEBUG */ +/*-----------------------------------------------------------------------------------*/ +void +memp_init(void) +{ + struct memp *m, *memp; + u16_t i, j; + u16_t size; + +#ifdef MEMP_STATS + for(i = 0; i < MEMP_MAX; ++i) { + stats.memp[i].used = stats.memp[i].max = + stats.memp[i].err = stats.memp[i].reclaimed = 0; + 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; + } + } + + mutex = sys_sem_new(1); + + +} +/*-----------------------------------------------------------------------------------*/ +void * +memp_malloc(memp_t type) +{ + struct memp *memp; + + ASSERT("memp_malloc: type < MEMP_MAX", type < MEMP_MAX); + + memp = memp_tab[type]; + + if(memp != NULL) { + memp_tab[type] = memp->next; + memp->next = NULL; +#ifdef MEMP_STATS + ++stats.memp[type].used; + if(stats.memp[type].used > stats.memp[type].max) { + stats.memp[type].max = stats.memp[type].used; + } +#endif /* MEMP_STATS */ + ASSERT("memp_malloc: memp properly aligned", + ((u32_t)MEM_ALIGN((u8_t *)memp + sizeof(struct memp)) % MEM_ALIGNMENT) == 0); + + return MEM_ALIGN((u8_t *)memp + sizeof(struct memp)); + } else { + DEBUGF(MEMP_DEBUG, ("memp_malloc: out of memory in pool %d\n", type)); +#ifdef MEMP_STATS + ++stats.memp[type].err; +#endif /* MEMP_STATS */ + return NULL; + } +} +/*-----------------------------------------------------------------------------------*/ +void * +memp_mallocp(memp_t type) +{ + void *mem; + sys_sem_wait(mutex); + mem = memp_malloc(type); + sys_sem_signal(mutex); + return mem; +} +/*-----------------------------------------------------------------------------------*/ +#if 0 +void * +memp_realloc(memp_t fromtype, memp_t totype, void *mem) +{ + void *rmem; + u16_t size; + + if(mem == NULL) { + return NULL; + } + + rmem = memp_malloc(totype); + if(rmem != NULL) { + size = memp_sizes[totype]; + if(memp_sizes[fromtype] < size) { + size = memp_sizes[fromtype]; + } + bcopy(mem, rmem, size); + memp_free(fromtype, mem); + } + return rmem; +} +#endif /* 0 */ +/*-----------------------------------------------------------------------------------*/ +void +memp_free(memp_t type, void *mem) +{ + struct memp *memp; + + if(mem == NULL) { + return; + } + memp = (struct memp *)((u8_t *)mem - sizeof(struct memp)); + +#ifdef MEMP_STATS + stats.memp[type].used--; +#endif /* MEMP_STATS */ + + memp->next = memp_tab[type]; + memp_tab[type] = memp; + + ASSERT("memp sanity", memp_sanity()); + + return; +} +/*-----------------------------------------------------------------------------------*/ +void +memp_freep(memp_t type, void *mem) +{ + sys_sem_wait(mutex); + memp_free(type, mem); + sys_sem_signal(mutex); +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/core/netif.c b/src/core/netif.c new file mode 100644 index 00000000..130e6f74 --- /dev/null +++ b/src/core/netif.c @@ -0,0 +1,142 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/netif.h" + +struct netif *netif_list = NULL; +struct netif *netif_default = NULL; + +/*-----------------------------------------------------------------------------------*/ +struct netif * +netif_add(struct ip_addr *ipaddr, struct ip_addr *netmask, + struct ip_addr *gw, + void (* init)(struct netif *netif), + err_t (* input)(struct pbuf *p, struct netif *netif)) +{ + struct netif *netif; + static int netifnum = 0; + + netif = mem_malloc(sizeof(struct netif)); + + if(netif == NULL) { + return NULL; + } + + netif->num = netifnum++; + netif->input = input; + ip_addr_set(&(netif->ip_addr), ipaddr); + ip_addr_set(&(netif->netmask), netmask); + ip_addr_set(&(netif->gw), gw); + + init(netif); + + netif->next = netif_list; + netif_list = netif; +#if NETIF_DEBUG + DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ", + netif->name[0], netif->name[1])); + ip_addr_debug_print(ipaddr); + DEBUGF(NETIF_DEBUG, (" netmask ")); + ip_addr_debug_print(netmask); + DEBUGF(NETIF_DEBUG, (" gw ")); + ip_addr_debug_print(gw); + DEBUGF(NETIF_DEBUG, ("\n")); +#endif /* NETIF_DEBUG */ + return netif; +} +/*-----------------------------------------------------------------------------------*/ +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]) { + DEBUGF(NETIF_DEBUG, ("netif_find: found %s\n", name)); + return netif; + } + } + DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %s\n", name)); + return NULL; +} +/*-----------------------------------------------------------------------------------*/ +void +netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr) +{ + ip_addr_set(&(netif->ip_addr), ipaddr); + DEBUGF(NETIF_DEBUG, ("netif: setting IP address of interface %c%c to %d.%d.%d.%d\n", + netif->name[0], netif->name[1], + (u8_t)(ntohl(ipaddr->addr) >> 24 & 0xff), + (u8_t)(ntohl(ipaddr->addr) >> 16 & 0xff), + (u8_t)(ntohl(ipaddr->addr) >> 8 & 0xff), + (u8_t)(ntohl(ipaddr->addr) & 0xff))); +} +/*-----------------------------------------------------------------------------------*/ +void +netif_set_gw(struct netif *netif, struct ip_addr *gw) +{ + ip_addr_set(&(netif->gw), gw); +} +/*-----------------------------------------------------------------------------------*/ +void +netif_set_netmask(struct netif *netif, struct ip_addr *netmask) +{ + ip_addr_set(&(netif->netmask), netmask); +} +/*-----------------------------------------------------------------------------------*/ +void +netif_set_default(struct netif *netif) +{ + netif_default = netif; + DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", + netif->name[0], netif->name[1])); +} +/*-----------------------------------------------------------------------------------*/ +void +netif_init(void) +{ + netif_list = netif_default = NULL; +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/core/pbuf.c b/src/core/pbuf.c new file mode 100644 index 00000000..bbd73511 --- /dev/null +++ b/src/core/pbuf.c @@ -0,0 +1,597 @@ +/* + * 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 + * + */ + +/*-----------------------------------------------------------------------------------*/ +/* pbuf.c + * + * Functions for the manipulation of pbufs. The pbufs holds all packets in the + * system. + * + */ +/*-----------------------------------------------------------------------------------*/ +#include "lwip/debug.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" + +static u8_t pbuf_pool_memory[(PBUF_POOL_SIZE * MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE + sizeof(struct pbuf)))]; +static volatile u8_t pbuf_pool_free_lock, pbuf_pool_alloc_lock; +static sys_sem_t pbuf_pool_free_sem; +static struct pbuf *pbuf_pool = NULL; +static struct pbuf *pbuf_pool_alloc_cache = NULL; +static struct pbuf *pbuf_pool_free_cache = NULL; + +/*-----------------------------------------------------------------------------------*/ +/* pbuf_init(): + * + * 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; + u16_t i; + + pbuf_pool = (struct pbuf *)&pbuf_pool_memory[0]; + ASSERT("pbuf_init: pool aligned", (long)pbuf_pool % MEM_ALIGNMENT == 0); + +#ifdef PBUF_STATS + 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))); + 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; + + pbuf_pool_alloc_lock = 0; + pbuf_pool_free_lock = 0; + pbuf_pool_free_sem = sys_sem_new(1); + +} +/*-----------------------------------------------------------------------------------*/ +/* The following two functions are only called from pbuf_alloc(). */ +/*-----------------------------------------------------------------------------------*/ +static struct pbuf * +pbuf_pool_alloc(void) +{ + struct pbuf *p = NULL; + + /* First, see if there are pbufs in the cache. */ + if(pbuf_pool_alloc_cache) { + p = pbuf_pool_alloc_cache; + if(p) { + pbuf_pool_alloc_cache = p->next; + } + } else { + /* 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) { +#ifdef PBUF_STATS + ++stats.pbuf.alloc_locked; +#endif /* PBUF_STATS */ + return NULL; + } + pbuf_pool_alloc_lock = 1; + if(!pbuf_pool_free_lock) { + p = pbuf_pool; + if(p) { + pbuf_pool = p->next; + } +#ifdef PBUF_STATS + } else { + ++stats.pbuf.alloc_locked; +#endif /* PBUF_STATS */ + } + pbuf_pool_alloc_lock = 0; + } + +#ifdef PBUF_STATS + if(p != NULL) { + ++stats.pbuf.used; + if(stats.pbuf.used > stats.pbuf.max) { + stats.pbuf.max = stats.pbuf.used; + } + } +#endif /* PBUF_STATS */ + + return p; +} +/*-----------------------------------------------------------------------------------*/ +static void +pbuf_pool_free(struct pbuf *p) +{ + struct pbuf *q; + +#ifdef PBUF_STATS + for(q = p; q != NULL; q = q->next) { + --stats.pbuf.used; + } +#endif /* PBUF_STATS */ + + if(pbuf_pool_alloc_cache == NULL) { + pbuf_pool_alloc_cache = p; + } else { + for(q = pbuf_pool_alloc_cache; q->next != NULL; q = q->next); + q->next = p; + } +} +/*-----------------------------------------------------------------------------------*/ +/* pbuf_alloc(): + * + * Allocates a pbuf at protocol layer l. 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). The + * flag 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. + * * RBUF_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. + * * PBUF_ROOL: the pbuf is allocated as a pbuf chain, with pbufs from + * the pbuf pool that is allocated during pbuf_init(). + */ +/*-----------------------------------------------------------------------------------*/ +struct pbuf * +pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag) +{ + struct pbuf *p, *q, *r; + u16_t offset; + s32_t rsize; + + offset = 0; + switch(l) { + case PBUF_TRANSPORT: + offset += PBUF_TRANSPORT_HLEN; + /* FALLTHROUGH */ + case PBUF_IP: + offset += PBUF_IP_HLEN; + offset += PBUF_LINK_HLEN; + /* FALLTHROUGH */ + case PBUF_LINK: + break; + case PBUF_RAW: + break; + default: + 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(); + if(p == NULL) { +#ifdef PBUF_STATS + ++stats.pbuf.err; +#endif /* PBUF_STATS */ + return NULL; + } + p->next = NULL; + + /* Set the payload pointer so that it points offset bytes into + pbuf data memory. */ + p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset))); + + /* The total length of the pbuf is the requested size. */ + p->tot_len = size; + + /* Set the length of the first pbuf is the chain. */ + p->len = size > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: size; + + p->flags = PBUF_FLAG_POOL; + + /* Allocate the tail of the pbuf chain. */ + r = p; + rsize = size - p->len; + while(rsize > 0) { + q = pbuf_pool_alloc(); + if(q == NULL) { + DEBUGF(PBUF_DEBUG, ("pbuf_alloc: Out of pbufs in pool,\n")); +#ifdef PBUF_STATS + ++stats.pbuf.err; +#endif /* PBUF_STATS */ + pbuf_pool_free(p); + return NULL; + } + q->next = NULL; + r->next = q; + q->len = rsize > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rsize; + q->flags = PBUF_FLAG_POOL; + q->payload = (void *)((u8_t *)q + sizeof(struct pbuf)); + r = q; + q->ref = 1; + q = q->next; + rsize -= PBUF_POOL_BUFSIZE; + } + r->next = NULL; + + ASSERT("pbuf_alloc: pbuf->payload properly aligned", + ((u32_t)p->payload % MEM_ALIGNMENT) == 0); + 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) + size + offset)); + 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 = size; + p->next = NULL; + p->flags = PBUF_FLAG_RAM; + + ASSERT("pbuf_alloc: pbuf->payload properly aligned", + ((u32_t)p->payload % MEM_ALIGNMENT) == 0); + break; + case PBUF_ROM: + /* If the pbuf should point to ROM, we only need to allocate + memory for the pbuf structure. */ + p = memp_mallocp(MEMP_PBUF); + if(p == NULL) { + return NULL; + } + p->payload = NULL; + p->len = p->tot_len = size; + p->next = NULL; + p->flags = PBUF_FLAG_ROM; + break; + default: + ASSERT("pbuf_alloc: erroneous flag", 0); + return NULL; + } + p->ref = 1; + return p; +} +/*-----------------------------------------------------------------------------------*/ +/* pbuf_refresh(): + * + * Moves free buffers from the pbuf_pool_free_cache to the pbuf_pool + * list (if possible). + * + */ +/*-----------------------------------------------------------------------------------*/ +void +pbuf_refresh(void) +{ + struct pbuf *p; + + sys_sem_wait(pbuf_pool_free_sem); + + if(pbuf_pool_free_cache != NULL) { + pbuf_pool_free_lock = 1; + if(!pbuf_pool_alloc_lock) { + if(pbuf_pool == NULL) { + pbuf_pool = pbuf_pool_free_cache; + } else { + for(p = pbuf_pool; p->next != NULL; p = p->next); + p->next = pbuf_pool_free_cache; + } + pbuf_pool_free_cache = NULL; +#ifdef PBUF_STATS + } else { + ++stats.pbuf.refresh_locked; +#endif /* PBUF_STATS */ + } + + pbuf_pool_free_lock = 0; + } + + sys_sem_signal(pbuf_pool_free_sem); +} +#define PBUF_POOL_FREE(p) do { \ + sys_sem_wait(pbuf_pool_free_sem); \ + p->next = pbuf_pool_free_cache; \ + pbuf_pool_free_cache = p; \ + sys_sem_signal(pbuf_pool_free_sem); \ + } while(0) +/*-----------------------------------------------------------------------------------*/ +/* pbuf_realloc: + * + * Reallocates the memory for a pbuf. If the pbuf is in ROM, this as + * simple as to adjust the ->tot_len and ->len fields. If the pbuf is + * a pbuf chain, as it might be with both pbufs in dynamically + * allocated RAM and for pbufs from the pbuf pool, we have to step + * through the chain until we find the new endpoint in the pbuf chain. + * Then the pbuf that is right on the endpoint is resized and any + * further pbufs on the chain are deallocated. + */ +/*-----------------------------------------------------------------------------------*/ +void +pbuf_realloc(struct pbuf *p, u16_t size) +{ + struct pbuf *q, *r; + u16_t rsize; + + ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL || + p->flags == PBUF_FLAG_ROM || + p->flags == PBUF_FLAG_RAM); + + + if(p->tot_len <= size) { + return; + } + + switch(p->flags) { + case PBUF_FLAG_POOL: + /* First, step over any pbufs that should still be in the chain. */ + rsize = size; + q = p; + while(rsize > q->len) { + rsize -= q->len; + q = q->next; + } + /* Adjust the length of the pbuf that will be halved. */ + q->len = rsize; + + /* And deallocate any left over pbufs. */ + r = q->next; + q->next = NULL; + q = r; + while(q != NULL) { + r = q->next; + PBUF_POOL_FREE(q); +#ifdef PBUF_STATS + --stats.pbuf.used; +#endif /* PBUF_STATS */ + q = r; + } + break; + case PBUF_FLAG_ROM: + p->len = size; + break; + case PBUF_FLAG_RAM: + /* First, step over the pbufs that should still be in the chain. */ + rsize = size; + q = p; + while(rsize > q->len) { + rsize -= q->len; + q = q->next; + } + if(q->flags == PBUF_FLAG_RAM) { + /* Reallocate and adjust the length of the pbuf that will be halved. */ + mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rsize); + } + + q->len = rsize; + + /* And deallocate any left over pbufs. */ + r = q->next; + q->next = NULL; + q = r; + while(q != NULL) { + r = q->next; + pbuf_free(q); + q = r; + } + break; + } + p->tot_len = size; + + pbuf_refresh(); +} +/*-----------------------------------------------------------------------------------*/ +/* pbuf_header(): + * + * Adjusts the ->payload pointer so that space for a header appears in + * the pbuf. Also, the ->tot_len and ->len fields are adjusted. + */ +/*-----------------------------------------------------------------------------------*/ +u8_t +pbuf_header(struct pbuf *p, s16_t header_size) +{ + void *payload; + + if(p->flags & PBUF_FLAG_ROM) { + return 1; + } + + payload = p->payload; + p->payload = (u8_t *)p->payload - header_size/sizeof(u8_t); + + DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%d)\n", payload, p->payload, header_size)); + + if((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) { + DEBUGF(PBUF_DEBUG, ("pbuf_header: failed %p %p\n", + (u8_t *)p->payload, + (u8_t *)p + sizeof(struct pbuf))); + p->payload = payload; + return 1; + } + p->len += header_size; + p->tot_len += header_size; + + return 0; +} +/*-----------------------------------------------------------------------------------*/ +/* pbuf_free(): + * + * Decrements the reference count and deallocates the pbuf if the + * reference count is zero. If the pbuf is a chain all pbufs in the + * chain are deallocated. + */ +/*-----------------------------------------------------------------------------------*/ +u8_t +pbuf_free(struct pbuf *p) +{ + struct pbuf *q; + u8_t count = 0; + + if(p == NULL) { + return 0; + } + + PERF_START; + + ASSERT("pbuf_free: sane flags", p->flags == PBUF_FLAG_POOL || + p->flags == PBUF_FLAG_ROM || + p->flags == PBUF_FLAG_RAM); + + ASSERT("pbuf_free: p->ref > 0", p->ref > 0); + + /* Decrement reference count. */ + p->ref--; + + q = NULL; + /* If reference count == 0, actually deallocate pbuf. */ + if(p->ref == 0) { + + while(p != NULL) { + /* Check if this is 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)); + q = p->next; + PBUF_POOL_FREE(p); +#ifdef PBUF_STATS + --stats.pbuf.used; +#endif /* PBUF_STATS */ + } else if(p->flags == PBUF_FLAG_ROM) { + q = p->next; + memp_freep(MEMP_PBUF, p); + } else { + q = p->next; + mem_free(p); + } + p = q; + ++count; + } + pbuf_refresh(); + } + + PERF_STOP("pbuf_free"); + + return count; +} +/*-----------------------------------------------------------------------------------*/ +/* pbuf_clen(): + * + * Returns the length of the pbuf chain. + */ +/*-----------------------------------------------------------------------------------*/ +u8_t +pbuf_clen(struct pbuf *p) +{ + u8_t len; + + if(p == NULL) { + return 0; + } + + for(len = 0; p != NULL; p = p->next) { + ++len; + } + return len; +} +/*-----------------------------------------------------------------------------------*/ +/* pbuf_ref(): + * + * Increments the reference count of the pbuf. + */ +/*-----------------------------------------------------------------------------------*/ +void +pbuf_ref(struct pbuf *p) +{ + if(p == NULL) { + return; + } + ++(p->ref); +} +/*-----------------------------------------------------------------------------------*/ +/* pbuf_chain(): + * + * Chains the two pbufs h and t together. The ->tot_len field of the + * first pbuf (h) is adjusted. + */ +/*-----------------------------------------------------------------------------------*/ +void +pbuf_chain(struct pbuf *h, struct pbuf *t) +{ + struct pbuf *p; + + if(t == NULL) { + return; + } + for(p = h; p->next != NULL; p = p->next); + p->next = t; + h->tot_len += t->tot_len; +} +/*-----------------------------------------------------------------------------------*/ +/* pbuf_dechain(): + * + * Adjusts the ->tot_len field of the pbuf and returns the tail (if + * any) of the pbuf chain. + */ +/*-----------------------------------------------------------------------------------*/ +struct pbuf * +pbuf_dechain(struct pbuf *p) +{ + struct pbuf *q; + + q = p->next; + if (q != NULL) { + q->tot_len = p->tot_len - p->len; + } + p->tot_len = p->len; + p->next = NULL; + return q; +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/core/stats.c b/src/core/stats.c new file mode 100644 index 00000000..8992e983 --- /dev/null +++ b/src/core/stats.c @@ -0,0 +1,54 @@ +/* + * 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 + * + */ + + +#include "lwip/debug.h" +#include "lwip/opt.h" + +#include "lwip/def.h" + +#include "lwip/stats.h" +#include "lwip/mem.h" + + +#ifdef STATS +struct stats_ stats; +#endif /* STATS */ +/*-----------------------------------------------------------------------------------*/ +void +stats_init(void) +{ +#ifdef STATS + bzero(&stats, sizeof(struct stats_)); +#endif /* STATS */ +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/core/sys.c b/src/core/sys.c new file mode 100644 index 00000000..011607cc --- /dev/null +++ b/src/core/sys.c @@ -0,0 +1,187 @@ +/* + * 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 + * + */ + +#include "lwip/debug.h" + +#include "lwip/sys.h" +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/memp.h" + +#ifndef NO_SYS +/*-----------------------------------------------------------------------------------*/ +void +sys_mbox_fetch(sys_mbox_t mbox, void **msg) +{ + u16_t time; + struct sys_timeouts *timeouts; + struct sys_timeout *tmptimeout; + sys_timeout_handler h; + void *arg; + + + again: + timeouts = sys_arch_timeouts(); + + if(timeouts->next == NULL) { + 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 = 0; + } + + if(time == 0) { + /* If time == 0, 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); + h(arg); + + /* We try again to fetch a message from the mbox. */ + goto again; + } else { + /* If time > 0, a message was received before the timeout + occured. The time variable is set to the number of + microseconds 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) +{ + u16_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->next == NULL) { + sys_arch_sem_wait(sem, 0); + } else { + if(timeouts->next->time > 0) { + time = sys_arch_sem_wait(sem, timeouts->next->time); + } else { + time = 0; + } + + if(time == 0) { + /* If time == 0, 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); + h(arg); + + + /* We try again to fetch a message from the mbox. */ + goto again; + } else { + /* If time > 0, a message was received before the timeout + occured. The time variable is set to the number of + microseconds we waited for the message. */ + if(time <= timeouts->next->time) { + timeouts->next->time -= time; + } else { + timeouts->next->time = 0; + } + } + + } +} +/*-----------------------------------------------------------------------------------*/ +void +sys_timeout(u16_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(); + + 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; + } + } + } + +} +/*-----------------------------------------------------------------------------------*/ +#endif /* NO_SYS */ diff --git a/src/core/tcp.c b/src/core/tcp.c new file mode 100644 index 00000000..8b0b1617 --- /dev/null +++ b/src/core/tcp.c @@ -0,0 +1,1158 @@ +/* + * 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 + * + */ + +/*-----------------------------------------------------------------------------------*/ +/* tcp.c + * + * This file contains common functions for the TCP implementation, such as functinos + * for manipulating the data structures and the TCP timer functions. TCP functions + * related to input and output is found in tcp_input.c and tcp_output.c respectively. + * + */ +/*-----------------------------------------------------------------------------------*/ + +#include "lwip/debug.h" + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" + +#include "lwip/tcp.h" + +/* Incremented every coarse grained timer shot + (typically every 500 ms, determined by TCP_COARSE_TIMEOUT). */ +u32_t tcp_ticks; +const u8_t tcp_backoff[13] = + { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; + +/* The TCP PCB lists. */ +struct tcp_pcb_listen *tcp_listen_pcbs; /* List of all TCP PCBs in LISTEN state. */ +struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a + state in which they accept or send + data. */ +struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ + +struct tcp_pcb *tcp_tmp_pcb; + +#define MIN(x,y) (x) < (y)? (x): (y) + +static u8_t tcp_timer; + +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_init(): + * + * Initializes the TCP layer. + */ +/*-----------------------------------------------------------------------------------*/ +void +tcp_init(void) +{ + /* Clear globals. */ + tcp_listen_pcbs = NULL; + tcp_active_pcbs = NULL; + tcp_tw_pcbs = NULL; + tcp_tmp_pcb = NULL; + + /* initialize timer */ + tcp_ticks = 0; + tcp_timer = 0; + +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_tmr(): + * + * Called periodically to dispatch TCP timers. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +tcp_tmr(void) +{ + ++tcp_timer; + if(tcp_timer == 10) { + tcp_timer = 0; + } + + if(tcp_timer & 1) { + /* Call tcp_fasttmr() every 200 ms, i.e., every other timer + tcp_tmr() is called. */ + tcp_fasttmr(); + } + if(tcp_timer == 0 || tcp_timer == 5) { + /* Call tcp_slowtmr() every 500 ms, i.e., every fifth timer + tcp_tmr() is called. */ + tcp_slowtmr(); + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_close(): + * + * Closes the connection held by the PCB. + * + */ +/*-----------------------------------------------------------------------------------*/ +err_t +tcp_close(struct tcp_pcb *pcb) +{ + err_t err; + +#if TCP_DEBUG + DEBUGF(TCP_DEBUG, ("tcp_close: closing in state ")); + tcp_debug_print_state(pcb->state); + DEBUGF(TCP_DEBUG, ("\n")); +#endif /* TCP_DEBUG */ + switch(pcb->state) { + case LISTEN: + err = ERR_OK; + tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs, pcb); + memp_free(MEMP_TCP_PCB_LISTEN, pcb); + pcb = NULL; + break; + case SYN_SENT: + err = ERR_OK; + tcp_pcb_remove(&tcp_active_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + pcb = NULL; + break; + case SYN_RCVD: + err = tcp_send_ctrl(pcb, TCP_FIN); + if(err == ERR_OK) { + pcb->state = FIN_WAIT_1; + } + break; + case ESTABLISHED: + err = tcp_send_ctrl(pcb, TCP_FIN); + if(err == ERR_OK) { + pcb->state = FIN_WAIT_1; + } + break; + case CLOSE_WAIT: + err = tcp_send_ctrl(pcb, TCP_FIN); + if(err == ERR_OK) { + pcb->state = LAST_ACK; + } + break; + default: + /* Has already been closed, do nothing. */ + err = ERR_OK; + pcb = NULL; + break; + } + + if(pcb != NULL && err == ERR_OK) { + err = tcp_output(pcb); + } + return err; +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_abort() + * + * Aborts a connection by sending a RST to the remote host and deletes + * the local protocol control block. This is done when a connection is + * killed because of shortage of memory. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +tcp_abort(struct tcp_pcb *pcb) +{ + u32_t seqno, ackno; + u16_t remote_port, local_port; + struct ip_addr remote_ip, local_ip; +#if LWIP_CALLBACK_API + void (* errf)(void *arg, err_t err); +#endif /* LWIP_CALLBACK_API */ + void *errf_arg; + + + /* Figure out on which TCP PCB list we are, and remove us. If we + are in an active state, call the receive function associated with + the PCB with a NULL argument, and send an RST to the remote end. */ + if(pcb->state == TIME_WAIT) { + tcp_pcb_remove(&tcp_tw_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + } else { + seqno = pcb->snd_nxt; + ackno = pcb->rcv_nxt; + ip_addr_set(&local_ip, &(pcb->local_ip)); + ip_addr_set(&remote_ip, &(pcb->remote_ip)); + local_port = pcb->local_port; + remote_port = pcb->remote_port; +#if LWIP_CALLBACK_API + errf = pcb->errf; +#endif /* LWIP_CALLBACK_API */ + errf_arg = pcb->callback_arg; + tcp_pcb_remove(&tcp_active_pcbs, pcb); + if(pcb->unacked != NULL) { + tcp_segs_free(pcb->unacked); + } + if(pcb->unsent != NULL) { + tcp_segs_free(pcb->unsent); + } +#if TCP_QUEUE_OOSEQ + if(pcb->ooseq != NULL) { + tcp_segs_free(pcb->ooseq); + } +#endif /* TCP_QUEUE_OOSEQ */ + memp_free(MEMP_TCP_PCB, pcb); + TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); + DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RST\n")); + tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port); + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_bind(): + * + * Binds the connection to a local portnumber and IP address. If the + * IP address is not given (i.e., ipaddr == NULL), the IP address of + * the outgoing network interface is used instead. + * + */ +/*-----------------------------------------------------------------------------------*/ +err_t +tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +{ + struct tcp_pcb *cpcb; + + /* Check if the address already is in use. */ + for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs; + cpcb != NULL; cpcb = cpcb->next) { + if(cpcb->local_port == port) { + if(ip_addr_isany(&(cpcb->local_ip)) || + ip_addr_isany(ipaddr) || + ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { + return ERR_USE; + } + } + } + for(cpcb = tcp_active_pcbs; + cpcb != NULL; cpcb = cpcb->next) { + if(cpcb->local_port == port) { + if(ip_addr_isany(&(cpcb->local_ip)) || + ip_addr_isany(ipaddr) || + ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { + return ERR_USE; + } + } + } + if(!ip_addr_isany(ipaddr)) { + pcb->local_ip = *ipaddr; + } + pcb->local_port = port; + DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %d\n", port)); + return ERR_OK; +} +#if LWIP_CALLBACK_API +static err_t +tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) +{ + return ERR_ABRT; +} +#endif /* LWIP_CALLBACK_API */ +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_listen(): + * + * Set the state of the connection to be LISTEN, which means that it + * is able to accept incoming connections. The protocol control block + * is reallocated in order to consume less memory. Setting the + * connection to LISTEN is an irreversible process. + * + */ +/*-----------------------------------------------------------------------------------*/ +struct tcp_pcb * +tcp_listen(struct tcp_pcb *pcb) +{ + struct tcp_pcb_listen *lpcb; + + lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN); + if(lpcb == NULL) { + return NULL; + } + lpcb->callback_arg = pcb->callback_arg; + lpcb->local_port = pcb->local_port; + ip_addr_set(&lpcb->local_ip, &pcb->local_ip); + memp_free(MEMP_TCP_PCB, pcb); +#if LWIP_CALLBACK_API + lpcb->accept = tcp_accept_null; +#endif /* LWIP_CALLBACK_API */ + TCP_REG((struct tcp_pcb **)&tcp_listen_pcbs, (struct tcp_pcb *)lpcb); + return (struct tcp_pcb *)lpcb; +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_recved(): + * + * This function should be called by the application when it has + * processed the data. The purpose is to advertise a larger window + * when the data has been processed. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +tcp_recved(struct tcp_pcb *pcb, u16_t len) +{ + pcb->rcv_wnd += len; + if(pcb->rcv_wnd > TCP_WND) { + pcb->rcv_wnd = TCP_WND; + } + if(!(pcb->flags & TF_ACK_DELAY) && + !(pcb->flags & TF_ACK_NOW)) { + tcp_ack(pcb); + } + DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %d bytes, wnd %u (%u).\n", + len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd)); +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_new_port(): + * + * A nastly hack featuring 'goto' statements that allocates a + * new TCP local port. + */ +/*-----------------------------------------------------------------------------------*/ +static u16_t +tcp_new_port(void) +{ + struct tcp_pcb *pcb; + static u16_t port = 4096; + + again: + if(++port > 0x7fff) { + port = 4096; + } + + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if(pcb->local_port == port) { + goto again; + } + } + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + if(pcb->local_port == port) { + goto again; + } + } + for(pcb = (struct tcp_pcb *)tcp_listen_pcbs; pcb != NULL; pcb = pcb->next) { + if(pcb->local_port == port) { + goto again; + } + } + return port; +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_connect(): + * + * Connects to another host. The function given as the "connected" + * argument will be called when the connection has been established. + * + */ +/*-----------------------------------------------------------------------------------*/ +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)) +{ + u32_t optdata; + err_t ret; + u32_t iss; + + DEBUGF(TCP_DEBUG, ("tcp_connect to port %d\n", port)); + if(ipaddr != NULL) { + pcb->remote_ip = *ipaddr; + } else { + return ERR_VAL; + } + pcb->remote_port = port; + if(pcb->local_port == 0) { + pcb->local_port = tcp_new_port(); + } + iss = tcp_next_iss(); + pcb->rcv_nxt = 0; + pcb->snd_nxt = iss; + pcb->lastack = iss - 1; + pcb->snd_lbb = iss - 1; + pcb->rcv_wnd = TCP_WND; + pcb->snd_wnd = TCP_WND; + pcb->mss = TCP_MSS; + pcb->cwnd = 1; + pcb->ssthresh = pcb->mss * 10; + pcb->state = SYN_SENT; +#if LWIP_CALLBACK_API + pcb->connected = connected; +#endif /* LWIP_CALLBACK_API */ + TCP_REG(&tcp_active_pcbs, pcb); + + /* Build an MSS option */ + optdata = HTONL(((u32_t)2 << 24) | + ((u32_t)4 << 16) | + (((u32_t)pcb->mss / 256) << 8) | + (pcb->mss & 255)); + + ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4); + if(ret == ERR_OK) { + tcp_output(pcb); + } + return ret; +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_slowtmr(): + * + * Called every 500 ms and implements the retransmission timer and the timer that + * removes PCBs that have been in TIME-WAIT for enough time. It also increments + * various timers such as the inactivity timer in each PCB. + */ +/*-----------------------------------------------------------------------------------*/ +void +tcp_slowtmr(void) +{ + struct tcp_pcb *pcb, *pcb2, *prev; + u32_t eff_wnd; + u8_t pcb_remove; /* flag if a PCB should be removed */ + err_t err; + + ++tcp_ticks; + + /* Steps through all of the active PCBs. */ + prev = NULL; + pcb = tcp_active_pcbs; + while(pcb != NULL) { + ASSERT("tcp_timer_coarse: active pcb->state != CLOSED", pcb->state != CLOSED); + ASSERT("tcp_timer_coarse: active pcb->state != LISTEN", pcb->state != LISTEN); + ASSERT("tcp_timer_coarse: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); + + pcb_remove = 0; + + if(pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) { + ++pcb_remove; + } else if(pcb->nrtx == TCP_MAXRTX) { + ++pcb_remove; + } else { + ++pcb->rtime; + if(pcb->unacked != NULL && pcb->rtime >= pcb->rto) { + + /* Time for a retransmission. */ + DEBUGF(TCP_RTO_DEBUG, ("tcp_timer_coarse: rtime %ld pcb->rto %d\n", + tcp_ticks - pcb->rtime, pcb->rto)); + + /* Double retransmission time-out unless we are trying to + connect to somebody (i.e., we are in SYN_SENT). */ + /* if(pcb->state != SYN_SENT) { + pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx]; + }*/ + + tcp_rexmit(pcb); + + /* Reduce congestion window and ssthresh. */ + eff_wnd = MIN(pcb->cwnd, pcb->snd_wnd); + pcb->ssthresh = eff_wnd >> 1; + if(pcb->ssthresh < pcb->mss) { + pcb->ssthresh = pcb->mss * 2; + } + pcb->cwnd = pcb->mss; + + DEBUGF(TCP_CWND_DEBUG, ("tcp_rexmit_seg: cwnd %u ssthresh %u\n", + pcb->cwnd, pcb->ssthresh)); + } + } + + /* Check if this PCB has stayed too long in FIN-WAIT-2 */ + if(pcb->state == FIN_WAIT_2) { + if((u32_t)(tcp_ticks - pcb->tmr) > + TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) { + ++pcb_remove; + } + } + + /* If this PCB has queued out of sequence data, but has been + inactive for too long, will drop the data (it will eventually + be retransmitted). */ +#if TCP_QUEUE_OOSEQ + if(pcb->ooseq != NULL && + (u32_t)tcp_ticks - pcb->tmr >= + pcb->rto * TCP_OOSEQ_TIMEOUT) { + tcp_segs_free(pcb->ooseq); + pcb->ooseq = NULL; + } +#endif /* TCP_QUEUE_OOSEQ */ + + /* Check if this PCB has stayed too long in SYN-RCVD */ + if(pcb->state == SYN_RCVD) { + if((u32_t)(tcp_ticks - pcb->tmr) > + TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { + ++pcb_remove; + } + } + + + /* If the PCB should be removed, do it. */ + if(pcb_remove) { + tcp_pcb_purge(pcb); + /* Remove PCB from tcp_active_pcbs list. */ + if(prev != NULL) { + ASSERT("tcp_timer_coarse: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); + prev->next = pcb->next; + } else { + /* This PCB was the first. */ + ASSERT("tcp_timer_coarse: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); + tcp_active_pcbs = pcb->next; + } + + TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT); + /* if(pcb->errf != NULL) { + pcb->errf(pcb->callback_arg, ERR_ABRT); + }*/ + + pcb2 = pcb->next; + memp_free(MEMP_TCP_PCB, pcb); + pcb = pcb2; + } else { + + /* We check if we should poll the connection. */ + ++pcb->polltmr; + if(pcb->polltmr >= pcb->pollinterval) { + pcb->polltmr = 0; + TCP_EVENT_POLL(pcb, err); + /* pcb->poll(pcb->callback_arg, pcb);*/ + if(err == ERR_OK) { + tcp_output(pcb); + } + } + + prev = pcb; + pcb = pcb->next; + } + } + + + /* Steps through all of the TIME-WAIT PCBs. */ + prev = NULL; + pcb = tcp_tw_pcbs; + while(pcb != NULL) { + ASSERT("tcp_timer_coarse: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + pcb_remove = 0; + + /* Check if this PCB has stayed long enough in TIME-WAIT */ + if((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { + ++pcb_remove; + } + + + + /* If the PCB should be removed, do it. */ + if(pcb_remove) { + tcp_pcb_purge(pcb); + /* Remove PCB from tcp_tw_pcbs list. */ + if(prev != NULL) { + ASSERT("tcp_timer_coarse: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); + prev->next = pcb->next; + } else { + /* This PCB was the first. */ + ASSERT("tcp_timer_coarse: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); + tcp_tw_pcbs = pcb->next; + } + pcb2 = pcb->next; + memp_free(MEMP_TCP_PCB, pcb); + pcb = pcb2; + } else { + prev = pcb; + pcb = pcb->next; + } + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_fasttmr(): + * + * Is called every TCP_FINE_TIMEOUT (100 ms) and sends delayed ACKs. + */ +/*-----------------------------------------------------------------------------------*/ +void +tcp_fasttmr(void) +{ + struct tcp_pcb *pcb; + + /* send delayed ACKs */ + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if(pcb->flags & TF_ACK_DELAY) { + DEBUGF(TCP_DEBUG, ("tcp_timer_fine: delayed ACK\n")); + tcp_ack_now(pcb); + pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); + } + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_segs_free(): + * + * Deallocates a list of TCP segments (tcp_seg structures). + * + */ +/*-----------------------------------------------------------------------------------*/ +u8_t +tcp_segs_free(struct tcp_seg *seg) +{ + u8_t count = 0; + struct tcp_seg *next; + again: + if(seg != NULL) { + next = seg->next; + count += tcp_seg_free(seg); + seg = next; + goto again; + } + return count; +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_seg_free(): + * + * Frees a TCP segment. + * + */ +/*-----------------------------------------------------------------------------------*/ +u8_t +tcp_seg_free(struct tcp_seg *seg) +{ + u8_t count = 0; + + if(seg != NULL) { + if(seg->p == NULL) { + memp_free(MEMP_TCP_SEG, seg); + } else { + count = pbuf_free(seg->p); +#if TCP_DEBUG + seg->p = NULL; +#endif /* TCP_DEBUG */ + memp_free(MEMP_TCP_SEG, seg); + } + } + return count; +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_setprio(): + * + * Sets the priority of a connection. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +tcp_setprio(struct tcp_pcb *pcb, u8_t prio) +{ + pcb->prio = prio; +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_seg_copy(): + * + * Returns a copy of the given TCP segment. + * + */ +/*-----------------------------------------------------------------------------------*/ +struct tcp_seg * +tcp_seg_copy(struct tcp_seg *seg) +{ + struct tcp_seg *cseg; + + cseg = memp_malloc(MEMP_TCP_SEG); + if(cseg == NULL) { + return NULL; + } + bcopy(seg, cseg, sizeof(struct tcp_seg)); + pbuf_ref(cseg->p); + return cseg; +} +/*-----------------------------------------------------------------------------------*/ +#if LWIP_CALLBACK_API +static err_t +tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + arg = arg; + if(p != NULL) { + pbuf_free(p); + } else if(err == ERR_OK) { + return tcp_close(pcb); + } + return ERR_OK; +} +#endif /* LWIP_CALLBACK_API */ +/*-----------------------------------------------------------------------------------*/ +static void +tcp_kill_prio(u8_t prio) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + u8_t mprio; + + + mprio = TCP_PRIO_MAX; + + /* We kill the oldest active connection that has lower priority than + prio. */ + inactivity = 0; + inactive = NULL; + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if(pcb->prio <= prio && + pcb->prio <= mprio && + (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + mprio = pcb->prio; + } + } + if(inactive != NULL) { + DEBUGF(TCP_DEBUG, ("tcp_mem_reclaim: killing oldest PCB 0x%p (%ld)\n", + inactive, inactivity)); + tcp_abort(inactive); + } +} + +/*-----------------------------------------------------------------------------------*/ +static void +tcp_kill_timewait(void) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + + inactivity = 0; + inactive = NULL; + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + if((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + } + } + if(inactive != NULL) { + DEBUGF(TCP_DEBUG, ("tcp_mem_reclaim: killing oldest TIME-WAIT PCB 0x%p (%ld)\n", + inactive, inactivity)); + tcp_abort(inactive); + } +} + +/*-----------------------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------------------*/ +struct tcp_pcb * +tcp_alloc(u8_t prio) +{ + struct tcp_pcb *pcb; + u32_t iss; + + pcb = memp_malloc(MEMP_TCP_PCB); + if(pcb == NULL) { + /* Try killing oldest connection in TIME-WAIT. */ + DEBUGF(TCP_DEBUG, ("tcp_new: killing off oldest TIME-WAIT connection\n")); + tcp_kill_timewait(); + pcb = memp_malloc(MEMP_TCP_PCB); + if(pcb == NULL) { + tcp_kill_prio(prio); + pcb = memp_malloc(MEMP_TCP_PCB); + } + } + if(pcb != NULL) { + bzero(pcb, sizeof(struct tcp_pcb)); + pcb->prio = TCP_PRIO_NORMAL; + pcb->snd_buf = TCP_SND_BUF; + pcb->snd_queuelen = 0; + pcb->rcv_wnd = TCP_WND; + pcb->mss = TCP_MSS; + pcb->rto = 3000 / TCP_SLOW_INTERVAL; + pcb->sa = 0; + pcb->sv = 3000 / TCP_SLOW_INTERVAL; + pcb->rtime = 0; + pcb->cwnd = 1; + iss = tcp_next_iss(); + pcb->snd_wl2 = iss; + pcb->snd_nxt = iss; + pcb->snd_max = iss; + pcb->lastack = iss; + pcb->snd_lbb = iss; + pcb->tmr = tcp_ticks; + + pcb->polltmr = 0; + +#if LWIP_CALLBACK_API + pcb->recv = tcp_recv_null; +#endif /* LWIP_CALLBACK_API */ + } + return pcb; +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_new(): + * + * Creates a new TCP protocol control block but doesn't place it on + * any of the TCP PCB lists. + * + */ +/*-----------------------------------------------------------------------------------*/ +struct tcp_pcb * +tcp_new(void) +{ + return tcp_alloc(TCP_PRIO_NORMAL); +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_arg(): + * + * Used to specify the argument that should be passed callback + * functions. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +tcp_arg(struct tcp_pcb *pcb, void *arg) +{ + pcb->callback_arg = arg; +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_recv(): + * + * Used to specify the function that should be called when a TCP + * connection receives data. + * + */ +/*-----------------------------------------------------------------------------------*/ +#if LWIP_CALLBACK_API +void +tcp_recv(struct tcp_pcb *pcb, + err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)) +{ + pcb->recv = recv; +} +#endif /* LWIP_CALLBACK_API */ +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_sent(): + * + * Used to specify the function that should be called when TCP data + * has been successfully delivered to the remote host. + * + */ +/*-----------------------------------------------------------------------------------*/ +#if LWIP_CALLBACK_API +void +tcp_sent(struct tcp_pcb *pcb, + err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len)) +{ + pcb->sent = sent; +} +#endif /* LWIP_CALLBACK_API */ +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_err(): + * + * Used to specify the function that should be called when a fatal error + * has occured on the connection. + * + */ +/*-----------------------------------------------------------------------------------*/ +#if LWIP_CALLBACK_API +void +tcp_err(struct tcp_pcb *pcb, + void (* errf)(void *arg, err_t err)) +{ + pcb->errf = errf; +} +#endif /* LWIP_CALLBACK_API */ +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_poll(): + * + * Used to specify the function that should be called periodically + * from TCP. The interval is specified in terms of the TCP coarse + * timer interval, which is called twice a second. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +tcp_poll(struct tcp_pcb *pcb, + err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval) +{ +#if LWIP_CALLBACK_API + pcb->poll = poll; +#endif /* LWIP_CALLBACK_API */ + pcb->pollinterval = interval; +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_accept(): + * + * Used for specifying the function that should be called when a + * LISTENing connection has been connected to another host. + * + */ +/*-----------------------------------------------------------------------------------*/ +#if LWIP_CALLBACK_API +void +tcp_accept(struct tcp_pcb *pcb, + err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)) +{ + ((struct tcp_pcb_listen *)pcb)->accept = accept; +} +#endif /* LWIP_CALLBACK_API */ +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_pcb_purge(): + * + * Purges a TCP PCB. Removes any buffered data and frees the buffer memory. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +tcp_pcb_purge(struct tcp_pcb *pcb) +{ + if(pcb->state != CLOSED && + pcb->state != TIME_WAIT && + pcb->state != LISTEN) { + + DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); + +#if TCP_DEBUG + if(pcb->unsent != NULL) { + DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n")); + } + if(pcb->unacked != NULL) { + DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); + } + if(pcb->ooseq != NULL) { + DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); + } +#endif /* TCP_DEBUG */ + tcp_segs_free(pcb->unsent); +#if TCP_QUEUE_OOSEQ + tcp_segs_free(pcb->ooseq); +#endif /* TCP_QUEUE_OOSEQ */ + tcp_segs_free(pcb->unacked); + pcb->unacked = pcb->unsent = +#if TCP_QUEUE_OOSEQ + pcb->ooseq = +#endif /* TCP_QUEUE_OOSEQ */ + NULL; + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_pcb_remove(): + * + * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) +{ + TCP_RMV(pcblist, pcb); + + tcp_pcb_purge(pcb); + + /* if there is an outstanding delayed ACKs, send it */ + if(pcb->state != TIME_WAIT && + pcb->state != LISTEN && + pcb->flags & TF_ACK_DELAY) { + pcb->flags |= TF_ACK_NOW; + tcp_output(pcb); + } + pcb->state = CLOSED; + + ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane()); +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_next_iss(): + * + * Calculates a new initial sequence number for new connections. + * + */ +/*-----------------------------------------------------------------------------------*/ +u32_t +tcp_next_iss(void) +{ + static u32_t iss = 6510; + + iss += tcp_ticks; /* XXX */ + return iss; +} +/*-----------------------------------------------------------------------------------*/ +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +void +tcp_debug_print(struct tcp_hdr *tcphdr) +{ + DEBUGF(TCP_DEBUG, ("TCP header:\n")); + DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(TCP_DEBUG, ("| %04x | %04x | (src port, dest port)\n", + tcphdr->src, tcphdr->dest)); + DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(TCP_DEBUG, ("| %08lu | (seq no)\n", + tcphdr->seqno)); + DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(TCP_DEBUG, ("| %08lu | (ack no)\n", + tcphdr->ackno)); + DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(TCP_DEBUG, ("| %2d | |%d%d%d%d%d| %5d | (offset, flags (", + TCPH_FLAGS(tcphdr) >> 4 & 1, + TCPH_FLAGS(tcphdr) >> 4 & 1, + TCPH_FLAGS(tcphdr) >> 3 & 1, + TCPH_FLAGS(tcphdr) >> 2 & 1, + TCPH_FLAGS(tcphdr) >> 1 & 1, + TCPH_FLAGS(tcphdr) & 1, + tcphdr->wnd)); + tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); + DEBUGF(TCP_DEBUG, ("), win)\n")); + DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(TCP_DEBUG, ("| 0x%04x | %5d | (chksum, urgp)\n", + ntohs(tcphdr->chksum), ntohs(tcphdr->urgp))); + DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); +} +/*-----------------------------------------------------------------------------------*/ +void +tcp_debug_print_state(enum tcp_state s) +{ + DEBUGF(TCP_DEBUG, ("State: ")); + switch(s) { + case CLOSED: + DEBUGF(TCP_DEBUG, ("CLOSED\n")); + break; + case LISTEN: + DEBUGF(TCP_DEBUG, ("LISTEN\n")); + break; + case SYN_SENT: + DEBUGF(TCP_DEBUG, ("SYN_SENT\n")); + break; + case SYN_RCVD: + DEBUGF(TCP_DEBUG, ("SYN_RCVD\n")); + break; + case ESTABLISHED: + DEBUGF(TCP_DEBUG, ("ESTABLISHED\n")); + break; + case FIN_WAIT_1: + DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n")); + break; + case FIN_WAIT_2: + DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n")); + break; + case CLOSE_WAIT: + DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n")); + break; + case CLOSING: + DEBUGF(TCP_DEBUG, ("CLOSING\n")); + break; + case LAST_ACK: + DEBUGF(TCP_DEBUG, ("LAST_ACK\n")); + break; + case TIME_WAIT: + DEBUGF(TCP_DEBUG, ("TIME_WAIT\n")); + break; + } +} +/*-----------------------------------------------------------------------------------*/ +void +tcp_debug_print_flags(u8_t flags) +{ + if(flags & TCP_FIN) { + DEBUGF(TCP_DEBUG, ("FIN ")); + } + if(flags & TCP_SYN) { + DEBUGF(TCP_DEBUG, ("SYN ")); + } + if(flags & TCP_RST) { + DEBUGF(TCP_DEBUG, ("RST ")); + } + if(flags & TCP_PSH) { + DEBUGF(TCP_DEBUG, ("PSH ")); + } + if(flags & TCP_ACK) { + DEBUGF(TCP_DEBUG, ("ACK ")); + } + if(flags & TCP_URG) { + DEBUGF(TCP_DEBUG, ("URG ")); + } +} +/*-----------------------------------------------------------------------------------*/ +void +tcp_debug_print_pcbs(void) +{ + struct tcp_pcb *pcb; + DEBUGF(TCP_DEBUG, ("Active PCB states:\n")); + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + DEBUGF(TCP_DEBUG, ("Local port %d, foreign port %d snd_nxt %lu rcv_nxt %lu ", + pcb->local_port, pcb->remote_port, + pcb->snd_nxt, pcb->rcv_nxt)); + tcp_debug_print_state(pcb->state); + } + DEBUGF(TCP_DEBUG, ("Listen PCB states:\n")); + for(pcb = (struct tcp_pcb *)tcp_listen_pcbs; pcb != NULL; pcb = pcb->next) { + DEBUGF(TCP_DEBUG, ("Local port %d, foreign port %d snd_nxt %lu rcv_nxt %lu ", + pcb->local_port, pcb->remote_port, + pcb->snd_nxt, pcb->rcv_nxt)); + tcp_debug_print_state(pcb->state); + } + DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n")); + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + DEBUGF(TCP_DEBUG, ("Local port %d, foreign port %d snd_nxt %lu rcv_nxt %lu ", + pcb->local_port, pcb->remote_port, + pcb->snd_nxt, pcb->rcv_nxt)); + tcp_debug_print_state(pcb->state); + } +} +/*-----------------------------------------------------------------------------------*/ +int +tcp_pcbs_sane(void) +{ + struct tcp_pcb *pcb; + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED); + ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN); + ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); + } + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + } + return 1; +} +#endif /* TCP_DEBUG */ +/*-----------------------------------------------------------------------------------*/ + + + + + + + + + diff --git a/src/core/tcp_input.c b/src/core/tcp_input.c new file mode 100644 index 00000000..4bfd251c --- /dev/null +++ b/src/core/tcp_input.c @@ -0,0 +1,1122 @@ +/* + * 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 + * + */ + +/*-----------------------------------------------------------------------------------*/ +/* tcp_input.c + * + * The input processing functions of TCP. + * + * These functions are generally called in the order (ip_input() ->) tcp_input() -> + * tcp_process() -> tcp_receive() (-> application). + * + */ +/*-----------------------------------------------------------------------------------*/ + +#include "lwip/debug.h" + +#include "lwip/def.h" +#include "lwip/opt.h" + +#include "lwip/netif.h" +#include "lwip/mem.h" +#include "lwip/memp.h" + +#include "lwip/inet.h" +#include "lwip/tcp.h" + +#include "lwip/stats.h" + +#include "arch/perf.h" + +/* These variables are global to all functions involved in the input + processing of TCP segments. They are set by the tcp_input() + function. */ +static struct tcp_seg inseg; +static struct tcp_hdr *tcphdr; +static struct ip_hdr *iphdr; +static u32_t seqno, ackno; +static u8_t flags; +static u16_t tcplen; + +static u8_t recv_flags; +static struct pbuf *recv_data; + +struct tcp_pcb *tcp_input_pcb; + +/* Forward declarations. */ +static err_t tcp_process(struct tcp_pcb *pcb); +static void tcp_receive(struct tcp_pcb *pcb); +static void tcp_parseopt(struct tcp_pcb *pcb); + +static err_t tcp_listen_input(struct tcp_pcb_listen *pcb); +static err_t tcp_timewait_input(struct tcp_pcb *pcb); + +/*-----------------------------------------------------------------------------------*/ +/* tcp_input: + * + * The initial input processing of TCP. It verifies the TCP header, demultiplexes + * the segment between the PCBs and passes it on to tcp_process(), which implements + * the TCP finite state machine. This function is called by the IP layer (in + * ip_input()). + */ +/*-----------------------------------------------------------------------------------*/ +void +tcp_input(struct pbuf *p, struct netif *inp) +{ + struct tcp_pcb *pcb, *prev; + struct tcp_pcb_listen *lpcb; + u8_t offset; + err_t err; + + + PERF_START; + + +#ifdef TCP_STATS + ++stats.tcp.recv; +#endif /* TCP_STATS */ + + iphdr = p->payload; + tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4/sizeof(u8_t)); + + pbuf_header(p, -(IPH_HL(iphdr) * 4/sizeof(u8_t))); + + /* Don't even process incoming broadcasts/multicasts. */ + if(ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask)) || + ip_addr_ismulticast(&(iphdr->dest))) { + pbuf_free(p); + return; + } + + + /* Verify TCP checksum. */ + if(inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), + (struct ip_addr *)&(iphdr->dest), + IP_PROTO_TCP, p->tot_len) != 0) { + DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04x\n", inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), + (struct ip_addr *)&(iphdr->dest), + IP_PROTO_TCP, p->tot_len))); +#if TCP_DEBUG + tcp_debug_print(tcphdr); +#endif /* TCP_DEBUG */ +#ifdef TCP_STATS + ++stats.tcp.chkerr; + ++stats.tcp.drop; +#endif /* TCP_STATS */ + + pbuf_free(p); + return; + } + + + /* Move the payload pointer in the pbuf so that it points to the + TCP data instead of the TCP header. */ + offset = TCPH_OFFSET(tcphdr) >> 4; + pbuf_header(p, -(offset * 4)); + + /* Convert fields in TCP header to host byte order. */ + tcphdr->src = ntohs(tcphdr->src); + tcphdr->dest = ntohs(tcphdr->dest); + seqno = tcphdr->seqno = ntohl(tcphdr->seqno); + ackno = tcphdr->ackno = ntohl(tcphdr->ackno); + tcphdr->wnd = ntohs(tcphdr->wnd); + + flags = TCPH_FLAGS(tcphdr) & TCP_FLAGS; + tcplen = p->tot_len + ((flags & TCP_FIN || flags & TCP_SYN)? 1: 0); + + /* Demultiplex an incoming segment. First, we check if it is destined + for an active connection. */ + prev = NULL; + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); + ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); + ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); + if(pcb->remote_port == tcphdr->src && + pcb->local_port == tcphdr->dest && + ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) && + ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) { + + /* Move this PCB to the front of the list so that subsequent + lookups will be faster (we exploit locality in TCP segment + arrivals). */ + ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb); + if(prev != NULL) { + prev->next = pcb->next; + pcb->next = tcp_active_pcbs; + tcp_active_pcbs = pcb; + } + ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); + break; + } + prev = pcb; + } + + if(pcb == NULL) { + /* If it did not go to an active connection, we check the connections + in the TIME-WAIT state. */ + + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + if(pcb->remote_port == tcphdr->src && + pcb->local_port == tcphdr->dest && + ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) && + ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) { + /* We don't really care enough to move this PCB to the front + of the list since we are not very likely to receive that + many segments for connections in TIME-WAIT. */ + DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n")); + tcp_timewait_input(pcb); + pbuf_free(p); + return; + } + } + + /* Finally, if we still did not get a match, we check all PCBs that + are LISTENing for incomming connections. */ + prev = NULL; + for(lpcb = tcp_listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + if((ip_addr_isany(&(lpcb->local_ip)) || + ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) && + lpcb->local_port == tcphdr->dest) { + /* Move this PCB to the front of the list so that subsequent + lookups will be faster (we exploit locality in TCP segment + arrivals). */ + if(prev != NULL) { + ((struct tcp_pcb_listen *)prev)->next = lpcb->next; + lpcb->next = tcp_listen_pcbs; + tcp_listen_pcbs = lpcb; + } + + DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); + tcp_listen_input(lpcb); + pbuf_free(p); + return; + } + prev = (struct tcp_pcb *)lpcb; + } + } + +#if TCP_INPUT_DEBUG + DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags ")); + tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); + DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n")); +#endif /* TCP_INPUT_DEBUG */ + + + if(pcb != NULL) { + /* The incoming segment belongs to a connection. */ +#if TCP_INPUT_DEBUG +#if TCP_DEBUG + tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ +#endif /* TCP_INPUT_DEBUG */ + + /* Set up a tcp_seg structure. */ + inseg.next = NULL; + inseg.len = p->tot_len; + inseg.dataptr = p->payload; + inseg.p = p; + inseg.tcphdr = tcphdr; + + recv_data = NULL; + recv_flags = 0; + + tcp_input_pcb = pcb; + err = tcp_process(pcb); + tcp_input_pcb = NULL; + /* A return value of ERR_ABRT means that tcp_abort() was called + and that the pcb has been freed. If so, we don't do anything. */ + if(err != ERR_ABRT) { + if(recv_flags & TF_RESET) { + /* TF_RESET means that the connection was reset by the other + end. We then call the error callback to inform the + application that the connection is dead before we + deallocate the PCB. */ + TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST); + tcp_pcb_remove(&tcp_active_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + } else if(recv_flags & TF_CLOSED) { + /* The connection has been closed and we will deallocate the + PCB. */ + tcp_pcb_remove(&tcp_active_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + } else { + err = ERR_OK; + /* If the application has registered a "sent" function to be + called when new send buffer space is avaliable, we call it + now. */ + if(pcb->acked > 0) { + TCP_EVENT_SENT(pcb, pcb->acked, err); + } + + if(recv_data != NULL) { + /* Notify application that data has been received. */ + TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); + } + + /* If a FIN segment was received, we call the callback + function with a NULL buffer to indicate EOF. */ + if(recv_flags & TF_GOT_FIN) { + TCP_EVENT_RECV(pcb, NULL, ERR_OK, err); + } + /* If there were no errors, we try to send something out. */ + if(err == ERR_OK) { + tcp_output(pcb); + } + } + } + + + /* We deallocate the incoming pbuf. If it was buffered by the + application, the application should have called pbuf_ref() to + increase the reference counter in the pbuf. If so, the buffer + isn't actually deallocated by the call to pbuf_free(), only the + reference count is decreased. */ + pbuf_free(inseg.p); +#if TCP_INPUT_DEBUG +#if TCP_DEBUG + tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ +#endif /* TCP_INPUT_DEBUG */ + + } else { + /* If no matching PCB was found, send a TCP RST (reset) to the + sender. */ + DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); + if(!(TCPH_FLAGS(tcphdr) & TCP_RST)) { +#ifdef TCP_STATS + ++stats.tcp.proterr; + ++stats.tcp.drop; +#endif /* TCP_STATS */ + tcp_rst(ackno, seqno + tcplen, + &(iphdr->dest), &(iphdr->src), + tcphdr->dest, tcphdr->src); + } + pbuf_free(p); + } + + ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); + PERF_STOP("tcp_input"); +} +/*-----------------------------------------------------------------------------------*/ +/* tcp_listen_input(): + * + * Called by tcp_input() when a segment arrives for a listening + * connection. + */ +/*-----------------------------------------------------------------------------------*/ +static err_t +tcp_listen_input(struct tcp_pcb_listen *pcb) +{ + struct tcp_pcb *npcb; + u32_t optdata; + + /* In the LISTEN state, we check for incoming SYN segments, + creates a new PCB, and responds with a SYN|ACK. */ + if(flags & TCP_ACK) { + /* For incoming segments with the ACK flag set, respond with a + RST. */ + DEBUGF(TCP_RST_DEBUG, ("tcp_process: ACK in LISTEN, sending reset\n")); + tcp_rst(ackno + 1, seqno + tcplen, + &(iphdr->dest), &(iphdr->src), + tcphdr->dest, tcphdr->src); + } else if(flags & TCP_SYN) { + DEBUGF(DEMO_DEBUG, ("TCP connection request %d -> %d.\n", tcphdr->src, tcphdr->dest)); + npcb = tcp_alloc(pcb->prio); + /* If a new PCB could not be created (probably due to lack of memory), + we don't do anything, but rely on the sender will retransmit the + SYN at a time when we have more memory avaliable. */ + if(npcb == NULL) { + DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); +#ifdef TCP_STATS + ++stats.tcp.memerr; +#endif /* TCP_STATS */ + return ERR_MEM; + } + /* Set up the new PCB. */ + ip_addr_set(&(npcb->local_ip), &(iphdr->dest)); + npcb->local_port = pcb->local_port; + ip_addr_set(&(npcb->remote_ip), &(iphdr->src)); + npcb->remote_port = tcphdr->src; + npcb->state = SYN_RCVD; + npcb->rcv_nxt = seqno + 1; + npcb->snd_wnd = tcphdr->wnd; + npcb->ssthresh = npcb->snd_wnd; + npcb->snd_wl1 = seqno; + npcb->callback_arg = pcb->callback_arg; +#if LWIP_CALLBACK_API + npcb->accept = pcb->accept; +#endif /* LWIP_CALLBACK_API */ + + /* Register the new PCB so that we can begin receiving segments + for it. */ + TCP_REG(&tcp_active_pcbs, npcb); + + /* Parse any options in the SYN. */ + tcp_parseopt(npcb); + + /* Build an MSS option. */ + optdata = HTONL(((u32_t)2 << 24) | + ((u32_t)4 << 16) | + (((u32_t)npcb->mss / 256) << 8) | + (npcb->mss & 255)); + /* Send a SYN|ACK together with the MSS option. */ + tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, (u8_t *)&optdata, 4); + return tcp_output(npcb); + } + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +/* tcp_timewait_input(): + * + * Called by tcp_input() when a segment arrives for a connection in + * TIME_WAIT. + */ +/*-----------------------------------------------------------------------------------*/ +static err_t +tcp_timewait_input(struct tcp_pcb *pcb) +{ + if(TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) { + pcb->rcv_nxt = seqno + tcplen; + } + if(tcplen > 0) { + tcp_ack_now(pcb); + } + return tcp_output(pcb); +} +/*-----------------------------------------------------------------------------------*/ +/* tcp_process + * + * Implements the TCP state machine. Called by tcp_input. In some + * states tcp_receive() is called to receive data. The tcp_seg + * argument will be freed by the caller (tcp_input()) unless the + * recv_data pointer in the pcb is set. + */ +/*-----------------------------------------------------------------------------------*/ +static err_t +tcp_process(struct tcp_pcb *pcb) +{ + struct tcp_seg *rseg; + u8_t acceptable = 0; + err_t err; + + + err = ERR_OK; + + /* Process incoming RST segments. */ + if(flags & TCP_RST) { + /* First, determine if the reset is acceptable. */ + if(pcb->state == SYN_SENT) { + if(ackno == pcb->snd_nxt) { + acceptable = 1; + } + } else { + if(TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) && + TCP_SEQ_LEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) { + acceptable = 1; + } + } + + if(acceptable) { + DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); + ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); + recv_flags = TF_RESET; + pcb->flags &= ~TF_ACK_DELAY; + return ERR_RST; + } else { + DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %lu rcv_nxt %lu\n", + seqno, pcb->rcv_nxt)); + DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %lu rcv_nxt %lu\n", + seqno, pcb->rcv_nxt)); + return ERR_OK; + } + } + + /* Update the PCB (in)activity timer. */ + pcb->tmr = tcp_ticks; + + /* Do different things depending on the TCP state. */ + switch(pcb->state) { + case SYN_SENT: + DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %lu pcb->snd_nxt %lu unacked %lu\n", ackno, + pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno))); + if(flags & (TCP_ACK | TCP_SYN) && + ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) { + pcb->rcv_nxt = seqno + 1; + pcb->lastack = ackno; + pcb->snd_wnd = pcb->snd_wl1 = tcphdr->wnd; + pcb->state = ESTABLISHED; + pcb->cwnd = pcb->mss; + --pcb->snd_queuelen; + DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %d\n", pcb->snd_queuelen)); + rseg = pcb->unacked; + pcb->unacked = rseg->next; + tcp_seg_free(rseg); + + /* Parse any options in the SYNACK. */ + tcp_parseopt(pcb); + + /* Call the user specified function to call when sucessfully + connected. */ + TCP_EVENT_CONNECTED(pcb, ERR_OK, err); + tcp_ack(pcb); + } + break; + case SYN_RCVD: + if(flags & TCP_ACK && + !(flags & TCP_RST)) { + if(TCP_SEQ_LT(pcb->lastack, ackno) && + TCP_SEQ_LEQ(ackno, pcb->snd_nxt)) { + pcb->state = ESTABLISHED; + DEBUGF(DEMO_DEBUG, ("TCP connection established %d -> %d.\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + ASSERT("pcb->accept != NULL", pcb->accept != NULL); + /* Call the accept function. */ + TCP_EVENT_ACCEPT(pcb, ERR_OK, err); + if(err != ERR_OK) { + /* If the accept function returns with an error, we abort + the connection. */ + tcp_abort(pcb); + return ERR_ABRT; + } + /* If there was any data contained within this ACK, + we'd better pass it on to the application as well. */ + tcp_receive(pcb); + pcb->cwnd = pcb->mss; + } + } + break; + case CLOSE_WAIT: + /* FALLTHROUGH */ + case ESTABLISHED: + tcp_receive(pcb); + if(flags & TCP_FIN) { + tcp_ack_now(pcb); + pcb->state = CLOSE_WAIT; + } + break; + case FIN_WAIT_1: + tcp_receive(pcb); + if(flags & TCP_FIN) { + if(flags & TCP_ACK && ackno == pcb->snd_nxt) { + DEBUGF(DEMO_DEBUG, + ("TCP connection closed %d -> %d.\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_ack_now(pcb); + tcp_pcb_purge(pcb); + TCP_RMV(&tcp_active_pcbs, pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } else { + tcp_ack_now(pcb); + pcb->state = CLOSING; + } + } else if(flags & TCP_ACK && ackno == pcb->snd_nxt) { + pcb->state = FIN_WAIT_2; + } + break; + case FIN_WAIT_2: + tcp_receive(pcb); + if(flags & TCP_FIN) { + DEBUGF(DEMO_DEBUG, ("TCP connection closed %d -> %d.\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_ack_now(pcb); + tcp_pcb_purge(pcb); + TCP_RMV(&tcp_active_pcbs, pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } + break; + case CLOSING: + tcp_receive(pcb); + if(flags & TCP_ACK && ackno == pcb->snd_nxt) { + DEBUGF(DEMO_DEBUG, ("TCP connection closed %d -> %d.\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_ack_now(pcb); + tcp_pcb_purge(pcb); + TCP_RMV(&tcp_active_pcbs, pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } + break; + case LAST_ACK: + tcp_receive(pcb); + if(flags & TCP_ACK && ackno == pcb->snd_nxt) { + DEBUGF(DEMO_DEBUG, ("TCP connection closed %d -> %d.\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + pcb->state = CLOSED; + recv_flags = TF_CLOSED; + } + break; + default: + break; + } + + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +/* tcp_receive: + * + * Called by tcp_process. Checks if the given segment is an ACK for outstanding + * data, and if so frees the memory of the buffered data. Next, is places the + * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment + * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until + * i it has been removed from the buffer. + * + * If the incoming segment constitutes an ACK for a segment that was used for RTT + * estimation, the RTT is estimated here as well. + */ +/*-----------------------------------------------------------------------------------*/ +static void +tcp_receive(struct tcp_pcb *pcb) +{ + struct tcp_seg *next, *prev, *cseg; + struct pbuf *p; + s32_t off; + int m; + + + if(flags & TCP_ACK) { + /* Update window. */ + if(TCP_SEQ_LT(pcb->snd_wl1, seqno) || + (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || + (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) { + pcb->snd_wnd = tcphdr->wnd; + pcb->snd_wl1 = seqno; + pcb->snd_wl2 = ackno; + DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %lu\n", pcb->snd_wnd)); +#if TCP_WND_DEBUG + } else { + if(pcb->snd_wnd != tcphdr->wnd) { + DEBUGF(TCP_WND_DEBUG, ("tcp_receive: no window update lastack %lu snd_max %lu ackno %lu wl1 %lu seqno %lu wl2 %lu\n", + pcb->lastack, pcb->snd_max, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); + } +#endif /* TCP_WND_DEBUG */ + } + + + if(pcb->lastack == ackno) { + ++pcb->dupacks; + if(pcb->dupacks >= 3 && pcb->unacked != NULL) { + if(!(pcb->flags & TF_INFR)) { + /* This is fast retransmit. Retransmit the first unacked segment. */ + DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %d (%lu), fast retransmit %lu\n", + pcb->dupacks, pcb->lastack, + ntohl(pcb->unacked->tcphdr->seqno))); + tcp_rexmit(pcb); + /* Set ssthresh to max (FlightSize / 2, 2*SMSS) */ + pcb->ssthresh = UMAX((pcb->snd_max - + pcb->lastack) / 2, + 2 * pcb->mss); + + pcb->cwnd = pcb->ssthresh + 3 * pcb->mss; + pcb->flags |= TF_INFR; + } else { + /* Inflate the congestion window, but not if it means that + the value overflows. */ + if(pcb->cwnd + pcb->mss > pcb->cwnd) { + pcb->cwnd += pcb->mss; + } + + } + } + } else if(TCP_SEQ_LT(pcb->lastack, ackno) && + TCP_SEQ_LEQ(ackno, pcb->snd_max)) { + /* We come here when the ACK acknowledges new data. */ + + /* Reset the "IN Fast Retransmit" flag, since we are no longer + in fast retransmit. Also reset the congestion window to the + slow start threshold. */ + if(pcb->flags & TF_INFR) { + pcb->flags &= ~TF_INFR; + pcb->cwnd = pcb->ssthresh; + } + + /* Reset the number of retransmissions. */ + pcb->nrtx = 0; + + /* Reset the retransmission time-out. */ + pcb->rto = (pcb->sa >> 3) + pcb->sv; + + /* Update the send buffer space. */ + pcb->acked = ackno - pcb->lastack; + pcb->snd_buf += pcb->acked; + + /* Reset the fast retransmit variables. */ + pcb->dupacks = 0; + pcb->lastack = ackno; + + /* Update the congestion control variables (cwnd and + ssthresh). */ + if(pcb->state >= ESTABLISHED) { + if(pcb->cwnd < pcb->ssthresh) { + if(pcb->cwnd + pcb->mss > pcb->cwnd) { + pcb->cwnd += pcb->mss; + } + DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %u\n", pcb->cwnd)); + } else { + if(pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd > pcb->cwnd) { + pcb->cwnd += pcb->mss * pcb->mss / pcb->cwnd; + } + DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %u\n", pcb->cwnd)); + } + } + DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %lu, unacked->seqno %lu:%lu\n", + ackno, + pcb->unacked != NULL? + ntohl(pcb->unacked->tcphdr->seqno): 0, + pcb->unacked != NULL? + ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0)); + + /* Remove segment from the unacknowledged list if the incoming + ACK acknowlegdes them. */ + while(pcb->unacked != NULL && + TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) + + TCP_TCPLEN(pcb->unacked), ackno)) { + DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %lu:%lu from pcb->unacked\n", + ntohl(pcb->unacked->tcphdr->seqno), + ntohl(pcb->unacked->tcphdr->seqno) + + TCP_TCPLEN(pcb->unacked))); + + next = pcb->unacked; + pcb->unacked = pcb->unacked->next; + + DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %d ... ", pcb->snd_queuelen)); + pcb->snd_queuelen -= pbuf_clen(next->p); + tcp_seg_free(next); + + DEBUGF(TCP_QLEN_DEBUG, ("%d (after freeing unacked)\n", pcb->snd_queuelen)); +#ifdef LWIP_DEBUG + if(pcb->snd_queuelen != 0) { + ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL || + pcb->unsent != NULL); + } +#endif /* LWIP_DEBUG */ + } + pcb->polltmr = 0; + } + + /* We go through the ->unsent list to see if any of the segments + on the list are acknowledged by the ACK. This may seem + strange since an "unsent" segment shouldn't be acked. The + rationale is that lwIP puts all outstanding segments on the + ->unsent list after a retransmission, so these segments may + in fact have been sent once. */ + while(pcb->unsent != NULL && + TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), + ackno) && + TCP_SEQ_LEQ(ackno, pcb->snd_max)) { + DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %lu:%lu from pcb->unsent\n", + ntohl(pcb->unsent->tcphdr->seqno), + ntohl(pcb->unsent->tcphdr->seqno) + + TCP_TCPLEN(pcb->unsent))); + + next = pcb->unsent; + pcb->unsent = pcb->unsent->next; + DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %d ... ", pcb->snd_queuelen)); + pcb->snd_queuelen -= pbuf_clen(next->p); + tcp_seg_free(next); + DEBUGF(TCP_QLEN_DEBUG, ("%d (after freeing unsent)\n", pcb->snd_queuelen)); +#ifdef LWIP_DEBUG + if(pcb->snd_queuelen != 0) { + ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL || + pcb->unsent != NULL); + } +#endif /* LWIP_DEBUG */ + + if(pcb->unsent != NULL) { + pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno); + } + } + + /* End of ACK for new data processing. */ + + DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %d rtseq %lu ackno %lu\n", + pcb->rttest, pcb->rtseq, ackno)); + + /* RTT estimation calculations. This is done by checking if the + incoming segment acknowledges the segment we use to take a + round-trip time measurement. */ + if(pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) { + m = tcp_ticks - pcb->rttest; + + DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %d ticks (%d msec).\n", + m, m * TCP_SLOW_INTERVAL)); + + /* This is taken directly from VJs original code in his paper */ + m = m - (pcb->sa >> 3); + pcb->sa += m; + if(m < 0) { + m = -m; + } + m = m - (pcb->sv >> 2); + pcb->sv += m; + pcb->rto = (pcb->sa >> 3) + pcb->sv; + + DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %d (%d miliseconds)\n", + pcb->rto, pcb->rto * TCP_SLOW_INTERVAL)); + + pcb->rttest = 0; + } + } + + /* If the incoming segment contains data, we must process it + further. */ + if(tcplen > 0) { + /* This code basically does three things: + + +) If the incoming segment contains data that is the next + in-sequence data, this data is passed to the application. This + might involve trimming the first edge of the data. The rcv_nxt + variable and the advertised window are adjusted. + + +) If the incoming segment has data that is above the next + sequence number expected (->rcv_nxt), the segment is placed on + the ->ooseq queue. This is done by finding the appropriate + place in the ->ooseq queue (which is ordered by sequence + number) and trim the segment in both ends if needed. An + immediate ACK is sent to indicate that we received an + out-of-sequence segment. + + +) Finally, we check if the first segment on the ->ooseq queue + now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If + rcv_nxt > ooseq->seqno, we must trim the first edge of the + segment on ->ooseq before we adjust rcv_nxt. The data in the + segments that are now on sequence are chained onto the + incoming segment so that we only need to call the application + once. + */ + + /* First, we check if we must trim the first edge. We have to do + this if the sequence number of the incoming segment is less + than rcv_nxt, and the sequence number plus the length of the + segment is larger than rcv_nxt. */ + if(TCP_SEQ_LT(seqno, pcb->rcv_nxt) && + TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) { + /* Trimming the first edge is done by pushing the payload + pointer in the pbuf downwards. This is somewhat tricky since + we do not want to discard the full contents of the pbuf up to + the new starting point of the data since we have to keep the + TCP header which is present in the first pbuf in the chain. + + What is done is really quite a nasty hack: the first pbuf in + the pbuf chain is pointed to by inseg.p. Since we need to be + able to deallocate the whole pbuf, we cannot change this + inseg.p pointer to point to any of the later pbufs in the + chain. Instead, we point the ->payload pointer in the first + pbuf to data in one of the later pbufs. We also set the + inseg.data pointer to point to the right place. This way, the + ->p pointer will still point to the first pbuf, but the + ->p->payload pointer will point to data in another pbuf. + + After we are done with adjusting the pbuf pointers we must + adjust the ->data pointer in the seg and the segment + length.*/ + off = pcb->rcv_nxt - seqno; + if(inseg.p->len < off) { + p = inseg.p; + while(p->len < off) { + off -= p->len; + inseg.p->tot_len -= p->len; + p->len = 0; + p = p->next; + } + pbuf_header(p, -off); + } else { + pbuf_header(inseg.p, -off); + } + inseg.dataptr = inseg.p->payload; + inseg.len -= pcb->rcv_nxt - seqno; + inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; + } + + /* The sequence number must be within the window (above rcv_nxt + and below rcv_nxt + rcv_wnd) in order to be further + processed. */ + if(TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) && + TCP_SEQ_LT(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) { + if(pcb->rcv_nxt == seqno) { + /* The incoming segment is the next in sequence. We check if + we have to trim the end of the segment and update rcv_nxt + and pass the data to the application. */ +#if TCP_QUEUE_OOSEQ + if(pcb->ooseq != NULL && + TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) { + /* We have to trim the second edge of the incoming + segment. */ + inseg.len = pcb->ooseq->tcphdr->seqno - seqno; + pbuf_realloc(inseg.p, inseg.len); + } +#endif /* TCP_QUEUE_OOSEQ */ + + tcplen = TCP_TCPLEN(&inseg); + + pcb->rcv_nxt += tcplen; + + /* Update the receiver's (our) window. */ + if(pcb->rcv_wnd < tcplen) { + pcb->rcv_wnd = 0; + } else { + pcb->rcv_wnd -= tcplen; + } + + /* If there is data in the segment, we make preparations to + pass this up to the application. The ->recv_data variable + is used for holding the pbuf that goes to the + application. The code for reassembling out-of-sequence data + chains its data on this pbuf as well. + + If the segment was a FIN, we set the TF_GOT_FIN flag that will + be used to indicate to the application that the remote side has + closed its end of the connection. */ + if(inseg.p->tot_len > 0) { + recv_data = inseg.p; + /* Since this pbuf now is the responsibility of the + application, we delete our reference to it so that we won't + (mistakingly) deallocate it. */ + inseg.p = NULL; + } + if(TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { + DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.")); + recv_flags = TF_GOT_FIN; + } + +#if TCP_QUEUE_OOSEQ + /* We now check if we have segments on the ->ooseq queue that + is now in sequence. */ + while(pcb->ooseq != NULL && + pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { + + cseg = pcb->ooseq; + seqno = pcb->ooseq->tcphdr->seqno; + + pcb->rcv_nxt += TCP_TCPLEN(cseg); + if(pcb->rcv_wnd < TCP_TCPLEN(cseg)) { + pcb->rcv_wnd = 0; + } else { + pcb->rcv_wnd -= TCP_TCPLEN(cseg); + } + if(cseg->p->tot_len > 0) { + /* Chain this pbuf onto the pbuf that we will pass to + the application. */ + if(pcb->recv_data) { + pbuf_chain(pcb->recv_data, cseg->p); + } else { + pcb->recv_data = cseg->p; + } + cseg->p = NULL; + } + if(flags & TCP_FIN) { + DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.")); + recv_flags = TF_GOT_FIN; + } + + + pcb->ooseq = cseg->next; + tcp_seg_free(cseg); + } +#endif /* TCP_QUEUE_OOSEQ */ + + + /* Acknowledge the segment(s). */ + tcp_ack(pcb); + + } else { + /* We get here if the incoming segment is out-of-sequence. */ + tcp_ack_now(pcb); +#if TCP_QUEUE_OOSEQ + /* We queue the segment on the ->ooseq queue. */ + if(pcb->ooseq == NULL) { + pcb->ooseq = tcp_seg_copy(&inseg); + } else { + /* If the queue is not empty, we walk through the queue and + try to find a place where the sequence number of the + incoming segment is between the sequence numbers of the + previous and the next segment on the ->ooseq queue. That is + the place where we put the incoming segment. If needed, we + trim the second edges of the previous and the incoming + segment so that it will fit into the sequence. + + If the incoming segment has the same sequence number as a + segment on the ->ooseq queue, we discard the segment that + contains less data. */ + + prev = NULL; + for(next = pcb->ooseq; next != NULL; next = next->next) { + if(seqno == next->tcphdr->seqno) { + /* The sequence number of the incoming segment is the + same as the sequence number of the segment on + ->ooseq. We check the lengths to see which one to + discard. */ + if(inseg.len > next->len) { + /* The incoming segment is larger than the old + segment. We replace the old segment with the new + one. */ + cseg = tcp_seg_copy(&inseg); + if(cseg != NULL) { + cseg->next = next->next; + if(prev != NULL) { + prev->next = cseg; + } else { + pcb->ooseq = cseg; + } + } + break; + } else { + /* Either the lenghts are the same or the incoming + segment was smaller than the old one; in either + case, we ditch the incoming segment. */ + break; + } + } else { + if(prev == NULL) { + if(TCP_SEQ_LT(seqno, next->tcphdr->seqno)) { + /* The sequence number of the incoming segment is lower + than the sequence number of the first segment on the + queue. We put the incoming segment first on the + queue. */ + + if(TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) { + /* We need to trim the incoming segment. */ + inseg.len = next->tcphdr->seqno - seqno; + pbuf_realloc(inseg.p, inseg.len); + } + cseg = tcp_seg_copy(&inseg); + if(cseg != NULL) { + cseg->next = next; + pcb->ooseq = cseg; + } + break; + } + } else if(TCP_SEQ_LT(prev->tcphdr->seqno, seqno) && + TCP_SEQ_LT(seqno, next->tcphdr->seqno)) { + /* The sequence number of the incoming segment is in + between the sequence numbers of the previous and + the next segment on ->ooseq. We trim and insert the + incoming segment and trim the previous segment, if + needed. */ + if(TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) { + /* We need to trim the incoming segment. */ + inseg.len = next->tcphdr->seqno - seqno; + pbuf_realloc(inseg.p, inseg.len); + } + + cseg = tcp_seg_copy(&inseg); + if(cseg != NULL) { + cseg->next = next; + prev->next = cseg; + if(TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { + /* We need to trim the prev segment. */ + prev->len = seqno - prev->tcphdr->seqno; + pbuf_realloc(prev->p, prev->len); + } + } + break; + } + /* If the "next" segment is the last segment on the + ooseq queue, we add the incoming segment to the end + of the list. */ + if(next->next == NULL && + TCP_SEQ_GT(seqno, next->tcphdr->seqno)) { + next->next = tcp_seg_copy(&inseg); + if(next->next != NULL) { + if(TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) { + /* We need to trim the last segment. */ + next->len = seqno - next->tcphdr->seqno; + pbuf_realloc(next->p, next->len); + } + } + break; + } + } + prev = next; + } + } +#endif /* TCP_QUEUE_OOSEQ */ + + } + } + } else { + /* Segments with length 0 is taken care of here. Segments that + fall out of the window are ACKed. */ + if(TCP_SEQ_GT(pcb->rcv_nxt, seqno) || + TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) { + tcp_ack_now(pcb); + } + } +} +/*-----------------------------------------------------------------------------------*/ +/* + * tcp_parseopt: + * + * Parses the options contained in the incoming segment. (Code taken + * from uIP with only small changes.) + * + */ +/*-----------------------------------------------------------------------------------*/ +static void +tcp_parseopt(struct tcp_pcb *pcb) +{ + u8_t c; + u8_t *opts, opt; + u16_t mss; + + opts = (u8_t *)tcphdr + TCP_HLEN; + + /* Parse the TCP MSS option, if present. */ + if((TCPH_OFFSET(tcphdr) & 0xf0) > 0x50) { + for(c = 0; c < ((TCPH_OFFSET(tcphdr) >> 4) - 5) << 2 ;) { + opt = opts[c]; + if(opt == 0x00) { + /* End of options. */ + break; + } else if(opt == 0x01) { + ++c; + /* NOP option. */ + } else if(opt == 0x02 && + opts[c + 1] == 0x04) { + /* An MSS option with the right option length. */ + mss = (opts[c + 2] << 8) | opts[c + 3]; + pcb->mss = mss > TCP_MSS? TCP_MSS: mss; + + /* And we are done processing options. */ + break; + } else { + if(opts[c + 1] == 0) { + /* If the length field is zero, the options are malformed + and we don't process them further. */ + break; + } + /* All other options have a length field, so that we easily + can skip past them. */ + c += opts[c + 1]; + } + } + } +} +/*-----------------------------------------------------------------------------------*/ + diff --git a/src/core/tcp_output.c b/src/core/tcp_output.c new file mode 100644 index 00000000..afabd149 --- /dev/null +++ b/src/core/tcp_output.c @@ -0,0 +1,589 @@ +/* + * 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 + * + */ + +/*-----------------------------------------------------------------------------------*/ +/* tcp_output.c + * + * The output functions of TCP. + * + */ +/*-----------------------------------------------------------------------------------*/ + +#include "lwip/debug.h" + +#include "lwip/def.h" +#include "lwip/opt.h" + +#include "arch/lib.h" + +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/sys.h" + +#include "lwip/netif.h" + +#include "lwip/inet.h" +#include "lwip/tcp.h" + +#include "lwip/stats.h" + + +#define MIN(x,y) (x) < (y)? (x): (y) + + + +/* 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) +{ + return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0); + +} +/*-----------------------------------------------------------------------------------*/ +err_t +tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy) +{ + if(pcb->state == SYN_SENT || + pcb->state == SYN_RCVD || + pcb->state == ESTABLISHED || + pcb->state == CLOSE_WAIT) { + if(len > 0) { + return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0); + } + return ERR_OK; + } else { + return ERR_CONN; + } +} +/*-----------------------------------------------------------------------------------*/ +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; + u32_t left, seqno; + u16_t seglen; + void *ptr; + u8_t queuelen; + + left = len; + ptr = arg; + + if(len > pcb->snd_buf) { + DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: too much data %d\n", len)); + return ERR_MEM; + } + + seqno = pcb->snd_lbb; + + queue = NULL; + DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d\n", pcb->snd_queuelen)); + queuelen = pcb->snd_queuelen; + if(queuelen >= TCP_SND_QUEUELEN) { + DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: too long queue %d (max %d)\n", queuelen, TCP_SND_QUEUELEN)); + goto memerr; + } + +#ifdef LWIP_DEBUG + if(pcb->snd_queuelen != 0) { + ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || + pcb->unsent != NULL); + } +#endif /* LWIP_DEBUG */ + + seg = NULL; + seglen = 0; + + while(queue == NULL || left > 0) { + + 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) { + DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for tcp_seg\n")); + goto memerr; + } + seg->next = NULL; + seg->p = NULL; + + + if(queue == NULL) { + queue = seg; + } else { + for(useg = queue; useg->next != NULL; useg = useg->next); + useg->next = 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. */ + if(optdata != NULL) { + if((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { + goto memerr; + } + ++queuelen; + seg->dataptr = seg->p->payload; + } else if(copy) { + if((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) { + DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for pbuf copy\n")); + goto memerr; + } + ++queuelen; + if(arg != NULL) { + bcopy(ptr, seg->p->payload, seglen); + } + seg->dataptr = seg->p->payload; + } else { + /* Do not copy the data. */ + if((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) { + DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for pbuf non-copy\n")); + goto memerr; + } + ++queuelen; + p->payload = ptr; + seg->dataptr = ptr; + if((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) { + pbuf_free(p); + DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for header pbuf\n")); + goto memerr; + } + ++queuelen; + pbuf_chain(seg->p, p); + } + if(queuelen > TCP_SND_QUEUELEN) { + DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: queue too long %d (%d)\n", queuelen, TCP_SND_QUEUELEN)); + goto memerr; + } + + seg->len = seglen; + /* if((flags & TCP_SYN) || (flags & TCP_FIN)) { + ++seg->len; + }*/ + + /* build TCP header */ + if(pbuf_header(seg->p, TCP_HLEN)) { + + DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: no room for TCP header in pbuf.\n")); + +#ifdef TCP_STATS + ++stats.tcp.err; +#endif /* TCP_STATS */ + 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 */ + + if(optdata == NULL) { + TCPH_OFFSET_SET(seg->tcphdr, 5 << 4); + } else { + TCPH_OFFSET_SET(seg->tcphdr, (5 + optlen / 4) << 4); + /* Copy options into data portion of segment. + Options can thus only be sent in non data carrying + segments such as SYN|ACK. */ + bcopy(optdata, seg->dataptr, optlen); + } + DEBUGF(TCP_OUTPUT_DEBUG, ("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); + } + + + /* Go to the last segment on the ->unsent queue. */ + if(pcb->unsent == NULL) { + useg = NULL; + } else { + for(useg = pcb->unsent; useg->next != NULL; useg = useg->next); + } + + /* 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)) && + useg->len + queue->len <= pcb->mss) { + /* Remove TCP header from first segment. */ + pbuf_header(queue->p, -TCP_HLEN); + pbuf_chain(useg->p, queue->p); + useg->len += queue->len; + useg->next = queue->next; + + DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: chaining, new len %u\n", useg->len)); + if(seg == queue) { + seg = NULL; + } + memp_free(MEMP_TCP_SEG, queue); + } else { + if(useg == NULL) { + pcb->unsent = queue; + + } else { + useg->next = queue; + } + } + if((flags & TCP_SYN) || (flags & TCP_FIN)) { + ++len; + } + pcb->snd_lbb += len; + pcb->snd_buf -= len; + pcb->snd_queuelen = queuelen; + DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (after enqueued)\n", pcb->snd_queuelen)); +#ifdef LWIP_DEBUG + if(pcb->snd_queuelen != 0) { + ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || + pcb->unsent != NULL); + + } +#endif /* LWIP_DEBUG */ + + /* 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_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_PSH); + } + + return ERR_OK; + memerr: +#ifdef TCP_STATS + ++stats.tcp.memerr; +#endif /* TCP_STATS */ + + if(queue != NULL) { + tcp_segs_free(queue); + } +#ifdef LWIP_DEBUG + if(pcb->snd_queuelen != 0) { + ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || + pcb->unsent != NULL); + + } +#endif /* LWIP_DEBUG */ + DEBUGF(TCP_QLEN_DEBUG, ("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 = MIN(pcb->snd_wnd, pcb->cwnd); + + + seg = pcb->unsent; + + /* If the TF_ACK_NOW flag is set, we check if there is data that is + to be sent. If data is to be sent out, we'll just piggyback our + acknowledgement with the outgoing segment. If no data will be + sent (either because the ->unsent queue is empty or because the + window doesn't allow it) we'll have to construct an empty ACK + segment and send it. */ + if(pcb->flags & TF_ACK_NOW && + (seg == NULL || + ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { + pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); + p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM); + if(p == NULL) { + DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: (ACK) could not allocate pbuf\n")); + return ERR_BUF; + } + DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: sending ACK for %lu\n", pcb->rcv_nxt)); + if(pbuf_header(p, TCP_HLEN)) { + DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: (ACK) no room for TCP header in pbuf.\n")); + +#ifdef TCP_STATS + ++stats.tcp.err; +#endif /* TCP_STATS */ + pbuf_free(p); + return ERR_BUF; + } + + 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_OFFSET_SET(tcphdr, 5 << 4); + + tcphdr->chksum = 0; + tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip), + IP_PROTO_TCP, p->tot_len); + + ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), TCP_TTL, + IP_PROTO_TCP); + pbuf_free(p); + + return ERR_OK; + } + +#if TCP_OUTPUT_DEBUG + if(seg == NULL) { + DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", pcb->unsent)); + } +#endif /* TCP_OUTPUT_DEBUG */ +#if TCP_CWND_DEBUG + if(seg == NULL) { + 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 { + 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 */ + + while(seg != NULL && + ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { + pcb->rtime = 0; +#if TCP_CWND_DEBUG + 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_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(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; + if(pcb->unacked == NULL) { + pcb->unacked = seg; + + + } else { + for(useg = pcb->unacked; useg->next != NULL; useg = useg->next); + useg->next = seg; + } + /* seg->rtime = 0;*/ + } else { + tcp_seg_free(seg); + } + seg = pcb->unsent; + } + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +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 { + 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); + + DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %lu\n", pcb->rtseq)); + } + 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; + seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, + &(pcb->local_ip), + &(pcb->remote_ip), + IP_PROTO_TCP, seg->p->tot_len); +#ifdef TCP_STATS + ++stats.tcp.xmit; +#endif /* TCP_STATS */ + + ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), TCP_TTL, + 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_TRANSPORT, 0, PBUF_RAM); + if(p == NULL) { + if(p == NULL) { + DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); + return; + } + } + if(pbuf_header(p, TCP_HLEN)) { + DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_send_data: no room for TCP header in pbuf.\n")); + +#ifdef TCP_STATS + ++stats.tcp.err; +#endif /* TCP_STATS */ + 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_OFFSET_SET(tcphdr, 5 << 4); + + tcphdr->chksum = 0; + tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip, + IP_PROTO_TCP, p->tot_len); + +#ifdef TCP_STATS + ++stats.tcp.xmit; +#endif /* TCP_STATS */ + ip_output(p, local_ip, remote_ip, TCP_TTL, IP_PROTO_TCP); + pbuf_free(p); + DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %lu ackno %lu.\n", seqno, ackno)); +} +/*-----------------------------------------------------------------------------------*/ +void +tcp_rexmit(struct tcp_pcb *pcb) +{ + struct tcp_seg *seg; + + if(pcb->unacked == NULL) { + return; + } + + /* Move all unacked segments to the unsent queue. */ + for(seg = pcb->unacked; seg->next != NULL; seg = seg->next); + + seg->next = pcb->unsent; + pcb->unsent = pcb->unacked; + + pcb->unacked = NULL; + + + pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno); + + ++pcb->nrtx; + pcb->rtime = 0; + + /* Don't take any rtt measurements after retransmitting. */ + pcb->rttest = 0; + + /* Do the actual retransmission. */ + tcp_output(pcb); + +} + + + + + + + + + + diff --git a/src/core/udp.c b/src/core/udp.c new file mode 100644 index 00000000..ef014922 --- /dev/null +++ b/src/core/udp.c @@ -0,0 +1,453 @@ +/* + * 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 + * + */ + +/*-----------------------------------------------------------------------------------*/ +/* udp.c + * + * The code for the User Datagram Protocol UDP. + * + */ +/*-----------------------------------------------------------------------------------*/ +#include "lwip/debug.h" + +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/inet.h" +#include "lwip/netif.h" +#include "lwip/udp.h" +#include "lwip/icmp.h" + +#include "lwip/stats.h" + +#include "arch/perf.h" + +/*-----------------------------------------------------------------------------------*/ + +/* The list of UDP PCBs. */ +#if LWIP_UDP +static struct udp_pcb *udp_pcbs = NULL; + +static struct udp_pcb *pcb_cache = NULL; +#endif /* LWIP_UDP */ + +#if UDP_DEBUG +int udp_debug_print(struct udp_hdr *udphdr); +#endif /* UDP_DEBUG */ + +/*-----------------------------------------------------------------------------------*/ +void +udp_init(void) +{ + udp_pcbs = pcb_cache = NULL; +} + +#if LWIP_UDP +/*-----------------------------------------------------------------------------------*/ +/* udp_lookup: + * + * An experimental feature that will be changed in future versions. Do + * not depend on it yet... + */ +/*-----------------------------------------------------------------------------------*/ +#ifdef LWIP_DEBUG +u8_t +udp_lookup(struct ip_hdr *iphdr, struct netif *inp) +{ + struct udp_pcb *pcb; + struct udp_hdr *udphdr; + u16_t src, dest; + + PERF_START; + + udphdr = (struct udp_hdr *)(u8_t *)iphdr + IPH_HL(iphdr) * 4/sizeof(u8_t); + + src = NTOHS(udphdr->src); + dest = NTOHS(udphdr->dest); + + pcb = pcb_cache; + if(pcb != NULL && + pcb->remote_port == src && + pcb->local_port == dest && + (ip_addr_isany(&pcb->remote_ip) || + ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) && + (ip_addr_isany(&pcb->local_ip) || + ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { + return 1; + } else { + for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { + if(pcb->remote_port == src && + pcb->local_port == dest && + (ip_addr_isany(&pcb->remote_ip) || + ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) && + (ip_addr_isany(&pcb->local_ip) || + ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { + pcb_cache = pcb; + break; + } + } + + if(pcb == NULL) { + for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { + if(pcb->local_port == dest && + (ip_addr_isany(&pcb->remote_ip) || + ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) && + (ip_addr_isany(&pcb->local_ip) || + ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { + break; + } + } + } + } + + PERF_STOP("udp_lookup"); + + if(pcb != NULL) { + return 1; + } else { + return 1; + } +} +#endif /* LWIP_DEBUG */ +/*-----------------------------------------------------------------------------------*/ +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; + + PERF_START; + +#ifdef UDP_STATS + ++stats.udp.recv; +#endif /* UDP_STATS */ + + iphdr = p->payload; + + pbuf_header(p, -(UDP_HLEN + IPH_HL(iphdr) * 4)); + + udphdr = (struct udp_hdr *)((u8_t *)p->payload - UDP_HLEN); + + DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %d\n", p->tot_len)); + + src = NTOHS(udphdr->src); + dest = NTOHS(udphdr->dest); + +#if UDP_DEBUG + udp_debug_print(udphdr); +#endif /* UDP_DEBUG */ + + /* Demultiplex packet. First, go for a perfect match. */ + for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { + DEBUGF(UDP_DEBUG, ("udp_input: pcb local port %d (dgram %d)\n", + pcb->local_port, ntohs(udphdr->dest))); + if(pcb->remote_port == src && + pcb->local_port == dest && + (ip_addr_isany(&pcb->remote_ip) || + ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) && + (ip_addr_isany(&pcb->local_ip) || + ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { + break; + } + } + + if(pcb == NULL) { + for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { + DEBUGF(UDP_DEBUG, ("udp_input: pcb local port %d (dgram %d)\n", + pcb->local_port, dest)); + if(pcb->local_port == dest && + (ip_addr_isany(&pcb->remote_ip) || + ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) && + (ip_addr_isany(&pcb->local_ip) || + ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { + 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)) {*/ + if(pcb != NULL) { + DEBUGF(UDP_DEBUG, ("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(inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), + (struct ip_addr *)&(iphdr->dest), + IP_PROTO_UDPLITE, ntohs(udphdr->len)) != 0) { + DEBUGF(UDP_DEBUG, ("udp_input: UDP Lite datagram discarded due to failing checksum\n")); +#ifdef UDP_STATS + ++stats.udp.chkerr; + ++stats.udp.drop; +#endif /* UDP_STATS */ + pbuf_free(p); + goto end; + } + } else { + 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) { + DEBUGF(UDP_DEBUG, ("udp_input: UDP datagram discarded due to failing checksum\n")); + +#ifdef UDP_STATS + ++stats.udp.chkerr; + ++stats.udp.drop; +#endif /* UDP_STATS */ + pbuf_free(p); + goto end; + } + } + } + pbuf_header(p, -UDP_HLEN); + if(pcb != NULL) { + pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src); + } else { + DEBUGF(UDP_DEBUG, ("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->netmask) && + !ip_addr_ismulticast(&iphdr->dest)) { + + /* deconvert from host to network byte order */ + udphdr->src = htons(udphdr->src); + udphdr->dest = htons(udphdr->dest); + + /* adjust pbuf pointer */ + p->payload = iphdr; + icmp_dest_unreach(p, ICMP_DUR_PORT); + } +#ifdef UDP_STATS + ++stats.udp.proterr; + ++stats.udp.drop; +#endif /* UDP_STATS */ + pbuf_free(p); + } + } else { + pbuf_free(p); + } + end: + + PERF_STOP("udp_input"); +} +/*-----------------------------------------------------------------------------------*/ +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 *hdr; + + /* hdr will point to the UDP header pbuf if an extra header pbuf has + to be allocated. */ + hdr = NULL; + + if(pbuf_header(p, UDP_HLEN)) { + hdr = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); + if(hdr == NULL) { + return ERR_MEM; + } + pbuf_chain(hdr, p); + p = hdr; + } + + udphdr = p->payload; + udphdr->src = htons(pcb->local_port); + udphdr->dest = htons(pcb->remote_port); + udphdr->chksum = 0x0000; + + if((netif = ip_route(&(pcb->remote_ip))) == NULL) { + DEBUGF(UDP_DEBUG, ("udp_send: No route to 0x%lx\n", pcb->remote_ip.addr)); +#ifdef UDP_STATS + ++stats.udp.rterr; +#endif /* UDP_STATS */ + return ERR_RTE; + } + + if(ip_addr_isany(&pcb->local_ip)) { + src_ip = &(netif->ip_addr); + } else { + src_ip = &(pcb->local_ip); + } + + DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %d\n", p->tot_len)); + + if(pcb->flags & UDP_FLAGS_UDPLITE) { + udphdr->len = htons(pcb->chksum_len); + /* calculate checksum */ + udphdr->chksum = inet_chksum_pseudo(p, src_ip, &(pcb->remote_ip), + IP_PROTO_UDP, pcb->chksum_len); + if(udphdr->chksum == 0x0000) { + udphdr->chksum = 0xffff; + } + err = ip_output_if(p, src_ip, &pcb->remote_ip, UDP_TTL, IP_PROTO_UDPLITE, netif); + } else { + udphdr->len = htons(p->tot_len); + /* calculate checksum */ + if((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { + udphdr->chksum = inet_chksum_pseudo(p, src_ip, &pcb->remote_ip, + IP_PROTO_UDP, p->tot_len); + if(udphdr->chksum == 0x0000) { + udphdr->chksum = 0xffff; + } + } + err = ip_output_if(p, src_ip, &pcb->remote_ip, UDP_TTL, IP_PROTO_UDP, netif); + } + + if(hdr != NULL) { + pbuf_dechain(hdr); + pbuf_free(hdr); + } + +#ifdef UDP_STATS + ++stats.udp.xmit; +#endif /* UDP_STATS */ + return err; +} +/*-----------------------------------------------------------------------------------*/ +err_t +udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +{ + struct udp_pcb *ipcb; + ip_addr_set(&pcb->local_ip, ipaddr); + pcb->local_port = 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; + } + } + /* We need to place the PCB on the list. */ + pcb->next = udp_pcbs; + udp_pcbs = pcb; + + DEBUGF(UDP_DEBUG, ("udp_bind: bound to port %d\n", port)); + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +err_t +udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +{ + struct udp_pcb *ipcb; + ip_addr_set(&pcb->remote_ip, ipaddr); + pcb->remote_port = 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; + } + } + /* We need to place the PCB on the list. */ + pcb->next = udp_pcbs; + udp_pcbs = pcb; + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +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) +{ + pcb->recv = recv; + pcb->recv_arg = recv_arg; +} +/*-----------------------------------------------------------------------------------*/ +void +udp_remove(struct udp_pcb *pcb) +{ + struct udp_pcb *pcb2; + + if(udp_pcbs == pcb) { + udp_pcbs = udp_pcbs->next; + } else for(pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { + if(pcb2->next != NULL && pcb2->next == pcb) { + pcb2->next = pcb->next; + } + } + + memp_free(MEMP_UDP_PCB, pcb); +} +/*-----------------------------------------------------------------------------------*/ +struct udp_pcb * +udp_new(void) { + struct udp_pcb *pcb; + pcb = memp_malloc(MEMP_UDP_PCB); + if(pcb != NULL) { + bzero(pcb, sizeof(struct udp_pcb)); + return pcb; + } + return NULL; + +} +/*-----------------------------------------------------------------------------------*/ +#if UDP_DEBUG +int +udp_debug_print(struct udp_hdr *udphdr) +{ + DEBUGF(UDP_DEBUG, ("UDP header:\n")); + DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(UDP_DEBUG, ("| %5d | %5d | (src port, dest port)\n", + ntohs(udphdr->src), ntohs(udphdr->dest))); + DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); + DEBUGF(UDP_DEBUG, ("| %5d | 0x%04x | (len, chksum)\n", + ntohs(udphdr->len), ntohs(udphdr->chksum))); + DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); + return 0; +} +#endif /* UDP_DEBUG */ +/*-----------------------------------------------------------------------------------*/ +#endif /* LWIP_UDP */ + + + + + + + + + diff --git a/src/include/ipv4/lwip/icmp.h b/src/include/ipv4/lwip/icmp.h new file mode 100644 index 00000000..b096b3cb --- /dev/null +++ b/src/include/ipv4/lwip/icmp.h @@ -0,0 +1,105 @@ +/* + * 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 + * + */ +#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 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); + +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 + +#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__ */ + diff --git a/src/include/ipv4/lwip/inet.h b/src/include/ipv4/lwip/inet.h new file mode 100644 index 00000000..19f5fb4c --- /dev/null +++ b/src/include/ipv4/lwip/inet.h @@ -0,0 +1,105 @@ +/* + * 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 + * + */ +#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); + +#ifdef HTONS +#undef HTONS +#endif /* HTONS */ +#ifdef NTOHS +#undef NTOHS +#endif /* NTOHS */ +#ifdef HTONL +#undef HTONL +#endif /* HTONL */ +#ifdef NTOHL +#undef NTOHL +#endif /* NTOHL */ + +#ifdef htons +#undef htons +#endif /* htons */ +#ifdef htonl +#undef htonl +#endif /* htonl */ +#ifdef ntohs +#undef ntohs +#endif /* ntohs */ +#ifdef ntohl +#undef ntohl +#endif /* ntohl */ + + + +#ifndef HTONS +# if BYTE_ORDER == BIG_ENDIAN +# define HTONS(n) (n) +# else /* BYTE_ORDER == BIG_ENDIAN */ +# define HTONS(n) (((((u16_t)(n) & 0xff)) << 8) | (((u16_t)(n) & 0xff00) >> 8)) +# endif /* BYTE_ORDER == BIG_ENDIAN */ +#endif /* HTONS */ + +#define htons HTONS +#define NTOHS HTONS +#define ntohs htons + + +#ifndef HTONL +# if BYTE_ORDER == BIG_ENDIAN +# define HTONL(n) (n) +# else /* BYTE_ORDER == BIG_ENDIAN */ +# define HTONL(n) (((((u32_t)(n) & 0xff)) << 24) | \ + ((((u32_t)(n) & 0xff00)) << 8) | \ + ((((u32_t)(n) & 0xff0000)) >> 8) | \ + ((((u32_t)(n) & 0xff000000)) >> 24)) +# endif /* BYTE_ORDER == BIG_ENDIAN */ +#endif /* HTONL */ + + +#define htonl HTONL +#define NTOHL HTONL +#define ntohl htonl + +#endif /* __LWIP_INET_H__ */ + diff --git a/src/include/ipv4/lwip/ip.h b/src/include/ipv4/lwip/ip.h new file mode 100644 index 00000000..e8257c90 --- /dev/null +++ b/src/include/ipv4/lwip/ip.h @@ -0,0 +1,119 @@ +/* + * 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 + * + */ +#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/netif.h" + +#include "lwip/err.h" + +void ip_init(void); +u8_t ip_lookup(void *header, struct netif *inp); +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 proto); +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); + +#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 + +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 + +#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) HTONS((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); +#endif /* IP_DEBUG */ + +#endif /* __LWIP_IP_H__ */ + + diff --git a/src/include/ipv4/lwip/ip_addr.h b/src/include/ipv4/lwip/ip_addr.h new file mode 100644 index 00000000..cca1cda2 --- /dev/null +++ b/src/include/ipv4/lwip/ip_addr.h @@ -0,0 +1,89 @@ +/* + * 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 + * + */ +#ifndef __LWIP_IP_ADDR_H__ +#define __LWIP_IP_ADDR_H__ + +#include "lwip/arch.h" + +#define IP_ADDR_ANY 0 + +#define IP_ADDR_BROADCAST (&ip_addr_broadcast) + +PACK_STRUCT_BEGIN +struct ip_addr { + PACK_STRUCT_FIELD(u32_t addr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +extern struct ip_addr ip_addr_broadcast; + +#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) == IP_ADDR_ANY? IP_ADDR_ANY:\ + ((struct ip_addr *)src)->addr) +#define ip_addr_maskcmp(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) + +#define ip_addr_isbroadcast(addr1, mask) (((((addr1)->addr) & ~((mask)->addr)) == \ + (0xffffffff & ~((mask)->addr))) || \ + ((addr1)->addr == 0xffffffff) || \ + ((addr1)->addr == 0x00000000)) + + +#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000)) == ntohl(0xe0000000)) + + +#define ip_addr_debug_print(ipaddr) DEBUGF(LWIP_DEBUG, ("%d.%d.%d.%d", \ + (u8_t)(ntohl((ipaddr)->addr) >> 24) & 0xff, \ + (u8_t)(ntohl((ipaddr)->addr) >> 16) & 0xff, \ + (u8_t)(ntohl((ipaddr)->addr) >> 8) & 0xff, \ + (u8_t)ntohl((ipaddr)->addr) & 0xff)) + + +#define ip4_addr1(ipaddr) ((u8_t)(ntohl((ipaddr)->addr) >> 24) & 0xff) +#define ip4_addr2(ipaddr) ((u8_t)(ntohl((ipaddr)->addr) >> 16) & 0xff) +#define ip4_addr3(ipaddr) ((u8_t)(ntohl((ipaddr)->addr) >> 8) & 0xff) +#define ip4_addr4(ipaddr) ((u8_t)(ntohl((ipaddr)->addr)) & 0xff) +#endif /* __LWIP_IP_ADDR_H__ */ + + + + + + diff --git a/src/include/ipv6/lwip/icmp.h b/src/include/ipv6/lwip/icmp.h new file mode 100644 index 00000000..09fa12ac --- /dev/null +++ b/src/include/ipv6/lwip/icmp.h @@ -0,0 +1,90 @@ +/* + * 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 + * + */ +#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__ */ + diff --git a/src/include/ipv6/lwip/inet.h b/src/include/ipv6/lwip/inet.h new file mode 100644 index 00000000..65c11377 --- /dev/null +++ b/src/include/ipv6/lwip/inet.h @@ -0,0 +1,60 @@ +/* + * 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 + * + */ +#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); + + +#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__ */ + diff --git a/src/include/ipv6/lwip/ip.h b/src/include/ipv6/lwip/ip.h new file mode 100644 index 00000000..2ffc2a94 --- /dev/null +++ b/src/include/ipv6/lwip/ip.h @@ -0,0 +1,96 @@ +/* + * 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 + * + */ +#ifndef __LWIP_IP_H__ +#define __LWIP_IP_H__ + +#include "lwip/debug.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__ */ + + diff --git a/src/include/ipv6/lwip/ip_addr.h b/src/include/ipv6/lwip/ip_addr.h new file mode 100644 index 00000000..5e971f57 --- /dev/null +++ b/src/include/ipv6/lwip/ip_addr.h @@ -0,0 +1,59 @@ +/* + * 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 + * + */ +#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_maskcmp(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__ */ diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h new file mode 100644 index 00000000..9b01cad1 --- /dev/null +++ b/src/include/lwip/api.h @@ -0,0 +1,137 @@ +/* + * 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 + * + */ +#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/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 +}; + +enum netconn_state { + NETCONN_NONE, + NETCONN_WRITE, + NETCONN_ACCEPT, + NETCONN_RECV, + NETCONN_CONNECT, + NETCONN_CLOSE +}; + +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; + } pcb; + err_t err; + sys_mbox_t mbox; + sys_mbox_t recvmbox; + sys_mbox_t acceptmbox; + sys_sem_t sem; +}; + +/* 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); +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); +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_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__ */ + + diff --git a/src/include/lwip/api_msg.h b/src/include/lwip/api_msg.h new file mode 100644 index 00000000..ae941610 --- /dev/null +++ b/src/include/lwip/api_msg.h @@ -0,0 +1,93 @@ +/* + * 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 + * + */ +#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_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__ */ + diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h new file mode 100644 index 00000000..21b3f4bf --- /dev/null +++ b/src/include/lwip/arch.h @@ -0,0 +1,58 @@ +/* + * 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 + * + */ +#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/cpu.h" +#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 */ + +#endif /* __LWIP_ARCH_H__ */ diff --git a/src/include/lwip/debug.h b/src/include/lwip/debug.h new file mode 100644 index 00000000..0a444099 --- /dev/null +++ b/src/include/lwip/debug.h @@ -0,0 +1,136 @@ +/* + * 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 + * + */ +#ifndef __LWIP_DEBUG_H__ +#define __LWIP_DEBUG_H__ + +#ifdef LWIP_DEBUG + +#define ASSERT(x,y) if(!(y)) {printf("Assertion \"%s\" failed at line %d in %s\n", \ + x, __LINE__, __FILE__); fflush(NULL); abort();} + +/* These defines control the amount of debugging output: */ +#define MEM_TRACKING + +#define DEMO_DEBUG 1 + +#define ETHARP_DEBUG 1 + +#define NETIF_DEBUG 0 +#define PBUF_DEBUG 0 +#define DELIF_DEBUG 0 +#define DROPIF_DEBUG 0 +#define TUNIF_DEBUG 0 +#define UNIXIF_DEBUG 0 +#define TAPIF_DEBUG 1 + +#define API_LIB_DEBUG 0 +#define API_MSG_DEBUG 0 +#define SOCKETS_DEBUG 1 +#define ICMP_DEBUG 0 +#define INET_DEBUG 0 +#define IP_DEBUG 1 +#define IP_REASS_DEBUG 1 +#define MEM_DEBUG 0 +#define MEMP_DEBUG 0 +#define SYS_DEBUG 0 +#define TCP_DEBUG 0 +#define TCP_INPUT_DEBUG 0 +#define TCP_FR_DEBUG 0 +#define TCP_RTO_DEBUG 0 +#define TCP_REXMIT_DEBUG 0 +#define TCP_CWND_DEBUG 0 +#define TCP_WND_DEBUG 0 +#define TCP_OUTPUT_DEBUG 0 +#define TCP_RST_DEBUG 0 +#define TCP_QLEN_DEBUG 0 +#define UDP_DEBUG 0 +#define TCPIP_DEBUG 0 +#define TCPDUMP_DEBUG 0 +#define DHCP_DEBUG 1 + +#include +#define DEBUGF(debug, x) do { if(debug){ printf x; } } while(0) + + +#else /* LWIP_DEBUG */ + +/* DEBUG is not defined, so we define null macros for ASSERT and DEBUGF */ + +#define ASSERT(x,y) +#define DEBUGF(debug, x) + +/* And we define those to be zero: */ + +#define DEMO_DEBUG 0 +#define ETHARP_DEBUG 0 +#define NETIF_DEBUG 0 +#define PBUF_DEBUG 0 +#define DELIF_DEBUG 0 +#define DROPIF_DEBUG 0 +#define TUNIF_DEBUG 0 +#define UNIXIF_DEBUG 0 +#define TAPIF_DEBUG 0 +#define API_LIB_DEBUG 0 +#define API_MSG_DEBUG 0 +#define SOCKETS_DEBUG 0 +#define ICMP_DEBUG 0 +#define INET_DEBUG 0 +#define IP_DEBUG 0 +#define IP_REASS_DEBUG 0 +#define MEM_DEBUG 0 +#define MEMP_DEBUG 0 +#define SYS_DEBUG 0 +#define TCP_DEBUG 0 +#define TCP_INPUT_DEBUG 0 +#define TCP_FR_DEBUG 0 +#define TCP_RTO_DEBUG 0 +#define TCP_REXMIT_DEBUG 0 +#define TCP_CWND_DEBUG 0 +#define TCP_WND_DEBUG 0 +#define TCP_OUTPUT_DEBUG 0 +#define TCP_RST_DEBUG 0 +#define TCP_QLEN_DEBUG 0 +#define UDP_DEBUG 0 +#define TCPIP_DEBUG 0 +#define TCPDUMP_DEBUG 0 +#define DHCP_DEBUG 0 + +#endif /* LWIP_DEBUG */ + + +#endif /* __LWIP_DEBUG_H__ */ + + + + + + diff --git a/src/include/lwip/def.h b/src/include/lwip/def.h new file mode 100644 index 00000000..55d1734f --- /dev/null +++ b/src/include/lwip/def.h @@ -0,0 +1,44 @@ +/* + * 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 + * + */ +#ifndef __LWIP_DEF_H__ +#define __LWIP_DEF_H__ + +#define UMAX(a, b) ((a) > (b) ? (a) : (b)) + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#include "arch/lib.h" + +#endif /* __LWIP_DEF_H__ */ + diff --git a/src/include/lwip/err.h b/src/include/lwip/err.h new file mode 100644 index 00000000..bed85fe1 --- /dev/null +++ b/src/include/lwip/err.h @@ -0,0 +1,68 @@ +/* + * 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 + * + */ +#ifndef __LWIP_ERR_H__ +#define __LWIP_ERR_H__ + +#include "lwip/debug.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. */ + + + +#ifdef LWIP_DEBUG +extern char *lwip_strerr(err_t err); +#else +#define lwip_strerr(x) "" +#endif /* LWIP_DEBUG */ +#endif /* __LWIP_ERR_H__ */ diff --git a/src/include/lwip/event.h b/src/include/lwip/event.h new file mode 100644 index 00000000..677cafc5 --- /dev/null +++ b/src/include/lwip/event.h @@ -0,0 +1,29 @@ +#ifndef __LWIP_EVENT_H__ +#define __LWIP_EVENT_H__ + +#include "lwip/opt.h" + +#if LWIP_EVENT_API + +#include "lwip/pbuf.h" + +enum lwip_event { + LWIP_EVENT_ACCEPT, + LWIP_EVENT_SENT, + LWIP_EVENT_RECV, + LWIP_EVENT_CONNECTED, + LWIP_EVENT_POLL, + LWIP_EVENT_ERR +}; + +struct tcp_pcb; + +err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, + enum lwip_event, + struct pbuf *p, + u16_t size, + err_t err); + +#endif /* LWIP_EVENT_API */ + +#endif /* __LWIP_EVENT_H__ */ diff --git a/src/include/lwip/list.h b/src/include/lwip/list.h new file mode 100644 index 00000000..14c14fca --- /dev/null +++ b/src/include/lwip/list.h @@ -0,0 +1,47 @@ +/* + * 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 + * + */ +#ifndef __LWIP_LIST_H__ +#define __LWIP_LIST_H__ + +struct list; + +struct list *list_new(int size); +int list_push(struct list *list, void *elem); +void *list_pop(struct list *list); +int list_remove(struct list *list, void *elem); +void *list_first(struct list *list); +int list_elems(struct list *list); +void list_delete(struct list *list); + +void list_map(struct list *list, void (* func)(void *arg)); + +#endif /* __LWIP_LIST_H__ */ diff --git a/src/include/lwip/mem.h b/src/include/lwip/mem.h new file mode 100644 index 00000000..61b96102 --- /dev/null +++ b/src/include/lwip/mem.h @@ -0,0 +1,60 @@ +/* + * 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 + * + */ +#ifndef __LWIP_MEM_H__ +#define __LWIP_MEM_H__ + +#include "lwip/debug.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); + +#define MEM_ALIGN_SIZE(size) (size + \ + ((((size) % MEM_ALIGNMENT) == 0)? 0 : \ + (MEM_ALIGNMENT - ((size) % MEM_ALIGNMENT)))) + +#define MEM_ALIGN(addr) (void *)MEM_ALIGN_SIZE((mem_ptr_t)addr) + +#endif /* __LWIP_MEM_H__ */ + diff --git a/src/include/lwip/memp.h b/src/include/lwip/memp.h new file mode 100644 index 00000000..5bd78326 --- /dev/null +++ b/src/include/lwip/memp.h @@ -0,0 +1,67 @@ +/* + * 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 + * + */ + +#ifndef __LWIP_MEMP_H__ +#define __LWIP_MEMP_H__ + +#include "lwip/debug.h" +#include "arch/cc.h" +#include "lwipopts.h" + +typedef enum { + MEMP_PBUF, + 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); + +void *memp_mallocp(memp_t type); +void memp_freep(memp_t type, void *mem); + +#endif /* __LWIP_MEMP_H__ */ + diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h new file mode 100644 index 00000000..579b9aad --- /dev/null +++ b/src/include/lwip/netif.h @@ -0,0 +1,97 @@ +/* + * 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 + * + */ +#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" + + +struct netif { + struct netif *next; + u8_t num; + struct ip_addr ip_addr; + struct ip_addr netmask; /* netmask in network byte order */ + struct ip_addr gw; + char hwaddr[6]; + + /* This function is called by the network device driver + when it wants to pass a packet to the TCP/IP stack. */ + err_t (* input)(struct pbuf *p, struct netif *inp); + + /* The following two fields should be filled in by the + initialization function for the device driver. */ + + char name[2]; + /* This function is called by the IP module when it wants + to send a packet on the interface. */ + err_t (* output)(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr); + err_t (* linkoutput)(struct netif *netif, struct pbuf *p); + + /* This field can be set bu the device driver and could point + to state information for the device. */ + void *state; +}; + +/* The list of network interfaces. */ +extern struct netif *netif_list; +extern struct netif *netif_default; + + +/* netif_init() must be called first. */ +void netif_init(void); + +struct netif *netif_add(struct ip_addr *ipaddr, struct ip_addr *netmask, + struct ip_addr *gw, + void (* init)(struct netif *netif), + err_t (* input)(struct pbuf *p, 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); + +#endif /* __LWIP_NETIF_H__ */ diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h new file mode 100644 index 00000000..0c03078d --- /dev/null +++ b/src/include/lwip/opt.h @@ -0,0 +1,102 @@ +/* + * 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 + * + */ +#ifndef __LWIP_OPT_H__ +#define __LWIP_OPT_H__ + +#include "lwipopts.h" + +/* Define some handy default values for configuration parameters. */ + +#ifndef ICMP_TTL +#define ICMP_TTL 255 +#endif + +#ifndef UDP_TTL +#define UDP_TTL 255 +#endif + +#ifndef TCP_TTL +#define TCP_TTL 255 +#endif + +#ifndef TCP_MSS +#define TCP_MSS 128 /* A *very* conservative default. */ +#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 + +#ifndef MEM_ALIGNMENT +#define MEM_ALIGNMENT 1 +#endif + +#ifndef PBUF_POOL_SIZE +#define PBUF_POOL_SIZE 16 +#endif + +#ifndef PBUF_POOL_BUFSIZE +#define PBUF_POOL_BUFSIZE 128 +#endif + +#ifndef PBUF_LINK_HLEN +#define PBUF_LINK_HLEN 0 +#endif + +#ifndef LWIP_UDP +#define LWIP_UDP 1 +#endif + +#ifndef LWIP_TCP +#define LWIP_TCP 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 /* LWIP_CALLBACK_API */ + +#endif /* __LWIP_OPT_H__ */ + + + diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h new file mode 100644 index 00000000..cd1ab02f --- /dev/null +++ b/src/include/lwip/pbuf.h @@ -0,0 +1,152 @@ +/* + * 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 + * + */ +/*-----------------------------------------------------------------------------------*/ +#ifndef __LWIP_PBUF_H__ +#define __LWIP_PBUF_H__ + +#include "lwip/debug.h" +#include "lwip/arch.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_POOL +} pbuf_flag; + +/* Definitions for the pbuf flag field (these are not the flags that + are passed to pbuf_alloc()). */ +#define PBUF_FLAG_RAM 0x00 /* Flags that pbuf data is stored in RAM. */ +#define PBUF_FLAG_ROM 0x01 /* Flags that pbuf data is stored in ROM. */ +#define PBUF_FLAG_POOL 0x02 /* Flags that the pbuf comes from the + pbuf pool. */ + +struct pbuf { + struct pbuf *next; + + /* Pointer to the actual data in the buffer. */ + void *payload; + + /* Total length of buffer + additionally chained buffers. */ + u16_t tot_len; + + /* Length of this buffer. */ + u16_t len; + + /* Flags and reference count. */ + u16_t flags, ref; + +}; + +/* pbuf_init(): + + Initializes the pbuf module. The num parameter determines how many + pbufs that should be allocated to the pbuf pool, and the size + parameter specifies the size of the data allocated to those. */ +void pbuf_init(void); + +/* pbuf_alloc(): + + Allocates a pbuf at protocol layer l. 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). The + flag 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 includesprotocol headers as well. + + * RBUF_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. + + * PBUF_ROOL: the pbuf is allocated as a pbuf chain, with pbufs from + the pbuf pool that is allocated during pbuf_init(). */ +struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag); + +/* pbuf_realloc(): + + Shrinks the pbuf to the size given by the size parameter. + */ +void pbuf_realloc(struct pbuf *p, u16_t size); + +/* pbuf_header(): + + Tries to move the p->payload pointer header_size number of bytes + upward within the pbuf. The return value is non-zero if it + fails. If so, an additional pbuf should be allocated for the header + and it should be chained to the front. */ +u8_t pbuf_header(struct pbuf *p, s16_t header_size); + +/* pbuf_ref(): + + Increments the reference count of the pbuf p. + */ +void pbuf_ref(struct pbuf *p); + +/* pbuf_free(): + + Decrements the reference count and deallocates the pbuf if the + reference count is zero. If the pbuf is a chain all pbufs in the + chain are deallocated. */ +u8_t pbuf_free(struct pbuf *p); + +/* pbuf_clen(): + + Returns the length of the pbuf chain. */ +u8_t pbuf_clen(struct pbuf *p); + +/* pbuf_chain(): + + Chains pbuf t on the end of pbuf h. Pbuf h will have it's tot_len + field adjusted accordingly. Pbuf t should no be used any more after + a call to this function, since pbuf t is now a part of pbuf h. */ +void pbuf_chain(struct pbuf *h, struct pbuf *t); + +/* pbuf_dechain(): + + Picks off the first pbuf from the pbuf chain p. Returns the tail of + the pbuf chain or NULL if the pbuf p was not chained. */ +struct pbuf *pbuf_dechain(struct pbuf *p); + +#endif /* __LWIP_PBUF_H__ */ diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h new file mode 100644 index 00000000..f6baa91e --- /dev/null +++ b/src/include/lwip/sockets.h @@ -0,0 +1,99 @@ +/* + * 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 + * + */ + + +#ifndef __LWIP_SOCKETS_H__ +#define __LWIP_SOCKETS_H__ + +struct in_addr { + u32_t s_addr; +}; + + +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]; +}; + +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 + +#define AF_INET 2 +#define PF_INET AF_INET + +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 + +#define INADDR_ANY 0 +#define INADDR_BROADCAST 0xffffffff + +int lwip_accept(int s, struct sockaddr *addr, int *addrlen); +int lwip_bind(int s, struct sockaddr *name, int namelen); +int lwip_close(int s); +int lwip_connect(int s, struct sockaddr *name, int 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, int *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, int tolen); +int lwip_socket(int domain, int type, int protocol); +int lwip_write(int s, void *dataptr, int size); + +#ifdef LWIP_COMPAT_SOCKETS +#define accept(a,b,c) lwip_accept(a,b,c) +#define bind(a,b,c) lwip_bind(a,b,c) +#define close(s) lwip_close(s) +#define connect(a,b,c) lwip_connect(a,b,c) +#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) +#endif /* LWIP_NO_COMPAT_SOCKETS */ + +#endif /* __LWIP_SOCKETS_H__ */ + diff --git a/src/include/lwip/stats.h b/src/include/lwip/stats.h new file mode 100644 index 00000000..024b9aec --- /dev/null +++ b/src/include/lwip/stats.h @@ -0,0 +1,109 @@ +/* + * 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 + * + */ +#ifndef __LWIP_STATS_H__ +#define __LWIP_STATS_H__ + +#include "lwip/opt.h" +#include "arch/cc.h" + +#include "lwip/memp.h" + +#ifdef 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 { + u16_t avail; + u16_t used; + u16_t max; + u16_t err; + u16_t reclaimed; +}; + +struct stats_pbuf { + u16_t avail; + u16_t used; + u16_t max; + u16_t err; + u16_t reclaimed; + + 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; + 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_ stats; + +#endif /* STATS */ + +void stats_init(void); +#endif /* __LWIP_STATS_H__ */ + + + + diff --git a/src/include/lwip/sys.h b/src/include/lwip/sys.h new file mode 100644 index 00000000..2246d0c8 --- /dev/null +++ b/src/include/lwip/sys.h @@ -0,0 +1,116 @@ +/* + * 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 + * + */ +#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_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) + +#else /* NO_SYS */ + +#include "arch/sys_arch.h" + +typedef void (* sys_timeout_handler)(void *arg); + +struct sys_timeout { + struct sys_timeout *next; + u16_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(u16_t msecs, 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); +u16_t sys_arch_sem_wait(sys_sem_t sem, u16_t timeout); +void sys_sem_free(sys_sem_t sem); +void sys_sem_wait(sys_sem_t sem); + +/* Mailbox functions. */ +sys_mbox_t sys_mbox_new(void); +void sys_mbox_post(sys_mbox_t mbox, void *msg); +u16_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u16_t timeout); +void sys_mbox_free(sys_mbox_t mbox); +void sys_mbox_fetch(sys_mbox_t mbox, void **msg); + +/* Thread functions. */ +void sys_thread_new(void (* thread)(void *arg), void *arg); + +/* 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 */ + +#endif /* __LWIP_SYS_H__ */ diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h new file mode 100644 index 00000000..b8e5cad0 --- /dev/null +++ b/src/include/lwip/tcp.h @@ -0,0 +1,448 @@ +/* + * 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 + * + */ +#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/sys.h" + +#include "lwip/err.h" + +#include "lwip/event.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 100 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); + + + +#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) + +#define TCP_FIN 0x01 +#define TCP_SYN 0x02 +#define TCP_RST 0x04 +#define TCP_PSH 0x08 +#define TCP_ACK 0x10 +#define TCP_URG 0x20 + +#define TCP_FLAGS 0x3f + +/* Length of the TCP header, excluding options. */ +#define TCP_HLEN 20 + +#define TCP_TMR_INTERVAL 100 /* The TCP timer interval in + milliseconds. */ + +#define TCP_FAST_INTERVAL 200 /* the fine grained timeout in + milliseconds */ +#define TCP_SLOW_INTERVAL 500 /* the coarse grained timeout in + milliseconds */ +#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 */ + +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 _offset_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 + +#define TCPH_OFFSET(hdr) (NTOHS((hdr)->_offset_flags) >> 8) +#define TCPH_FLAGS(hdr) (NTOHS((hdr)->_offset_flags) & 0xff) + +#define TCPH_OFFSET_SET(hdr, offset) (hdr)->_offset_flags = HTONS(((offset) << 8) | TCPH_FLAGS(hdr)) +#define TCPH_FLAGS_SET(hdr, flags) (hdr)->_offset_flags = HTONS((TCPH_OFFSET(hdr) << 8) | (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 { + struct tcp_pcb *next; /* for the linked list */ + u8_t prio; + void *callback_arg; + + struct ip_addr local_ip; + u16_t local_port; + + struct ip_addr remote_ip; + u16_t remote_port; + + /* receiver varables */ + u32_t rcv_nxt; /* next seqno expected */ + u16_t rcv_wnd; /* receiver window */ + + enum tcp_state state; /* TCP state */ + + /* Timers */ + u16_t tmr; + u8_t polltmr, pollinterval; + + /* Retransmission timer. */ + u8_t rtime; + + u16_t mss; /* maximum segment size */ + + u8_t flags; +#define TF_ACK_DELAY 0x01U /* Delayed ACK. */ +#define TF_ACK_NOW 0x02U /* Immediate ACK. */ +#define TF_INFR 0x04U /* In fast recovery. */ +#define TF_RESET 0x08U /* Connection was reset. */ +#define TF_CLOSED 0x10U /* Connection was sucessfully closed. */ +#define TF_GOT_FIN 0x20U /* Connection was closed by the remote end. */ + + /* RTT estimation variables. */ + u16_t rttest; /* RTT estimate in 500ms ticks */ + u32_t rtseq; /* sequence number being timed */ + s16_t sa, sv; + + 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; /* Avaliable buffer space for sending (in bytes). */ + u8_t snd_queuelen; /* Avaliable 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 avaliable. */ + 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 */ +}; + +struct tcp_pcb_listen { + struct tcp_pcb_listen *next; /* for the linked list */ + u8_t prio; + void *callback_arg; + + struct ip_addr local_ip; + 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 +#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))) +#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 is used to repressent TCP segments when queued. */ +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); + +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_pcbs_sane() 1 +#endif /* TCP_DEBUG */ + + +/* The TCP PCB lists. */ +extern struct tcp_pcb_listen *tcp_listen_pcbs; /* List of all TCP PCBs in LISTEN state. */ +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. */ + +/* Axoims 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 {\ + 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) { \ + ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != npcb); \ + } \ + ASSERT("TCP_REG: pcb->state != CLOSED", npcb->state != CLOSED); \ + npcb->next = *pcbs; \ + ASSERT("TCP_REG: npcb->next != npcb", npcb->next != npcb); \ + *(pcbs) = npcb; \ + ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + } while(0) +#define TCP_RMV(pcbs, npcb) do { \ + ASSERT("TCP_RMV: pcbs != NULL", *pcbs != NULL); \ + 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; \ + ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + 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; \ + } 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__ */ + + + diff --git a/src/include/lwip/tcpip.h b/src/include/lwip/tcpip.h new file mode 100644 index 00000000..fbd9b879 --- /dev/null +++ b/src/include/lwip/tcpip.h @@ -0,0 +1,60 @@ +/* + * 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 + * + */ +#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); + +enum tcpip_msg_type { + TCPIP_MSG_API, + TCPIP_MSG_INPUT +}; + +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; + } msg; +}; + + +#endif /* __LWIP_TCPIP_H__ */ diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h new file mode 100644 index 00000000..2528376d --- /dev/null +++ b/src/include/lwip/udp.h @@ -0,0 +1,97 @@ +/* + * 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 + * + */ +#ifndef __LWIP_UDP_H__ +#define __LWIP_UDP_H__ + +#include "lwip/arch.h" + +#include "lwip/pbuf.h" +#include "lwip/inet.h" +#include "lwip/ip.h" + +#include "lwip/err.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 0x01 +#define UDP_FLAGS_UDPLITE 0x02 + +struct udp_pcb { + struct udp_pcb *next; + + struct ip_addr local_ip, remote_ip; + u16_t local_port, remote_port; + + u8_t flags; + 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_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_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 is the lower layer interface to UDP. */ +u8_t udp_lookup (struct ip_hdr *iphdr, struct netif *inp); +void udp_input (struct pbuf *p, struct netif *inp); +void udp_init (void); + + +#endif /* __LWIP_UDP_H__ */ + + diff --git a/src/include/netif/etharp.h b/src/include/netif/etharp.h new file mode 100644 index 00000000..5d56d7b0 --- /dev/null +++ b/src/include/netif/etharp.h @@ -0,0 +1,111 @@ +/* + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Swedish Institute + * of Computer Science and its contributors. + * 4. 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 + * + * + */ + +#ifndef __NETIF_ETHARP_H__ +#define __NETIF_ETHARP_H__ + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" + +PACK_STRUCT_BEGIN +struct eth_addr { + PACK_STRUCT_FIELD(u8_t addr[6]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +PACK_STRUCT_BEGIN +struct eth_hdr { + 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 + +#define ARP_TMR_INTERVAL 10000 + +#define ETHTYPE_ARP 0x0806 +#define ETHTYPE_IP 0x0800 + +/* Initializes ARP. */ +void etharp_init(void); + +/* The etharp_tmr() function should be called every ETHARP_TMR_INTERVAL + microseconds (10 seconds). This function is responsible for + expiring old entries in the ARP table. */ +void etharp_tmr(void); + +/* Should be called for all incoming packets of IP kind. The function + does not alter the packet in any way, it just updates the ARP + table. After this function has been called, the normal TCP/IP stack + input function should be called. + + The function may return a pbuf containing a packet that had + previously been queued for transmission. The device driver must + transmit this packet onto the network, and call pbuf_free() for the + pbuf. +*/ +struct pbuf *etharp_ip_input(struct netif *netif, struct pbuf *p); + +/* Should be called for incoming ARP packets. The pbuf in the argument + is freed by this function. If the function returns a pbuf (i.e., + returns non-NULL), that pbuf constitutes an ARP reply and should be + sent out on the Ethernet. + + The driver must call pbuf_free() for the returned pbuf when the + packet has been sent. +*/ +struct pbuf *etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, + struct pbuf *p); + + +/* The etharp_output() function should be called for all outgoing + packets. The pbuf returned by the function should be sent out on + the Ethernet. + + The function prepares the packet for transmission over the Ethernet + by adding an Ethernet header. If there is no IP -> MAC address + mapping, the function will queue the outgoing packet and return an + ARP request. +*/ +struct pbuf *etharp_output(struct netif *netif, struct ip_addr *ipaddr, + struct pbuf *q); + + +#endif /* __NETIF_ARP_H__ */ diff --git a/src/include/netif/ethernetif.h b/src/include/netif/ethernetif.h new file mode 100644 index 00000000..d0ae6905 --- /dev/null +++ b/src/include/netif/ethernetif.h @@ -0,0 +1,39 @@ +/* + * 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 + * + */ +#ifndef __NETIF_ETHERNETIF_H__ +#define __NETIF_ETHERNETIF_H__ + +#include "lwip/netif.h" + +void ethernetif_init(struct netif *netif); + +#endif /* __NETIF_ETHERNETIF_H__ */ diff --git a/src/include/netif/loopif.h b/src/include/netif/loopif.h new file mode 100644 index 00000000..ffc76e9f --- /dev/null +++ b/src/include/netif/loopif.h @@ -0,0 +1,39 @@ +/* + * 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 + * + */ +#ifndef __NETIF_LOOPIF_H__ +#define __NETIF_LOOPIF_H__ + +#include "lwip/netif.h" + +void loopif_init(struct netif *netif); + +#endif /* __NETIF_LOOPIF_H__ */ diff --git a/src/include/netif/tcpdump.h b/src/include/netif/tcpdump.h new file mode 100644 index 00000000..d74b1fee --- /dev/null +++ b/src/include/netif/tcpdump.h @@ -0,0 +1,40 @@ +/* + * 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 + * + */ +#ifndef __NETIF_TCPDUMP_H__ +#define __NETIF_TCPDUMP_H__ + +#include "lwip/pbuf.h" + +void tcpdump_init(void); +void tcpdump(struct pbuf *p); + +#endif /* __NETIF_TCPDUMP_H__ */ diff --git a/src/netif/etharp.c b/src/netif/etharp.c new file mode 100644 index 00000000..b3115890 --- /dev/null +++ b/src/netif/etharp.c @@ -0,0 +1,474 @@ +/* + * 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 + * + * + */ + +#include "lwip/opt.h" +#include "lwip/debug.h" +#include "lwip/inet.h" +#include "netif/etharp.h" +#include "lwip/ip.h" +#include "lwip/stats.h" + +#if LWIP_DHCP +# include "lwip/dhcp.h" +#endif + + +#define ARP_MAXAGE 120 /* 120 * 10 seconds = 20 minutes. */ +#define ARP_MAXPENDING 2 /* 2 * 10 seconds = 20 seconds. */ + +#define HWTYPE_ETHERNET 1 + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +/* MUST be compiled with "pack structs" or equivalent! */ +PACK_STRUCT_BEGIN +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_addr sipaddr); + PACK_STRUCT_FIELD(struct eth_addr dhwaddr); + PACK_STRUCT_FIELD(struct ip_addr dipaddr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +#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)) + +PACK_STRUCT_BEGIN +struct ethip_hdr { + PACK_STRUCT_FIELD(struct eth_hdr eth); + PACK_STRUCT_FIELD(struct ip_hdr ip); +}; +PACK_STRUCT_END + +enum etharp_state { + ETHARP_STATE_EMPTY, + ETHARP_STATE_PENDING, + ETHARP_STATE_STABLE +}; + +struct etharp_entry { + struct ip_addr ipaddr; + struct eth_addr ethaddr; + enum etharp_state state; + struct pbuf *p; + void *payload; + u16_t len, tot_len; + u8_t ctime; +}; + +static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; +static struct etharp_entry arp_table[ARP_TABLE_SIZE]; +static u8_t ctime; + +/*-----------------------------------------------------------------------------------*/ +void +etharp_init(void) +{ + u8_t i; + + for(i = 0; i < ARP_TABLE_SIZE; ++i) { + arp_table[i].state = ETHARP_STATE_EMPTY; + } +} +/*-----------------------------------------------------------------------------------*/ +void +etharp_tmr(void) +{ + u8_t i; + + ++ctime; + for(i = 0; i < ARP_TABLE_SIZE; ++i) { + if(arp_table[i].state == ETHARP_STATE_STABLE && + ctime - arp_table[i].ctime >= ARP_MAXAGE) { + DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %d.\n", i)); + arp_table[i].state = ETHARP_STATE_EMPTY; + } else if(arp_table[i].state == ETHARP_STATE_PENDING && + ctime - arp_table[i].ctime >= ARP_MAXPENDING) { + DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %d - dequeueing %p.\n", i, arp_table[i].p)); + arp_table[i].state = ETHARP_STATE_EMPTY; + pbuf_free(arp_table[i].p); + } + } +} +/*----------------------------------------------------------------------------------*/ +static u8_t +find_arp_entry(void) +{ + u8_t i, j, maxtime; + + /* Try to find an unused entry in the ARP table. */ + for(i = 0; i < ARP_TABLE_SIZE; ++i) { + if(arp_table[i].state == ETHARP_STATE_EMPTY) { + break; + } + } + + /* If no unused entry is found, we try to find the oldest entry and + throw it away. */ + if(i == ARP_TABLE_SIZE) { + maxtime = 0; + j = 0; + for(i = 0; i < ARP_TABLE_SIZE; ++i) { + if(arp_table[i].state == ETHARP_STATE_STABLE && + ctime - arp_table[i].ctime > maxtime) { + maxtime = ctime - arp_table[i].ctime; + j = i; + } + } + i = j; + } + return i; +} +/*-----------------------------------------------------------------------------------*/ +static struct pbuf * +update_arp_entry(struct ip_addr *ipaddr, struct eth_addr *ethaddr) +{ + u8_t i, k; + struct pbuf *p; + struct eth_hdr *ethhdr; + + /* Walk through the ARP mapping table and try to find an entry to + update. If none is found, the IP -> MAC address mapping is + inserted in the ARP table. */ + for(i = 0; i < ARP_TABLE_SIZE; ++i) { + /* Check if the source IP address of the incoming packet matches + the IP address in this ARP table entry. */ + if(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { + + /* First, check those entries that are already in use. */ + if(arp_table[i].state == ETHARP_STATE_STABLE) { + /* An old entry found, update this and return. */ + for(k = 0; k < 6; ++k) { + arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; + } + arp_table[i].ctime = ctime; + return NULL; + } + if(arp_table[i].state == ETHARP_STATE_PENDING) { + /* A pending entry was found, so we fill this in and return + the queued packet (if any). */ + for(k = 0; k < 6; ++k) { + arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; + } + arp_table[i].ctime = ctime; + arp_table[i].state = ETHARP_STATE_STABLE; + p = arp_table[i].p; + if(p != NULL) { + p->payload = arp_table[i].payload; + p->len = arp_table[i].len; + p->tot_len = arp_table[i].tot_len; + arp_table[i].p = NULL; + + ethhdr = p->payload; + + for(k = 0; k < 6; ++k) { + ethhdr->dest.addr[k] = ethaddr->addr[k]; + } + + ethhdr->type = htons(ETHTYPE_IP); + } + return p; + } + } + } + /* We get here if no ARP entry was found. If so, we create one. */ + i = find_arp_entry(); + if(i == ARP_TABLE_SIZE) { + return NULL; + } + + ip_addr_set(&arp_table[i].ipaddr, ipaddr); + for(k = 0; k < 6; ++k) { + arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; + } + arp_table[i].ctime = ctime; + arp_table[i].state = ETHARP_STATE_STABLE; + arp_table[i].p = NULL; + + return NULL; +} +/*-----------------------------------------------------------------------------------*/ +struct pbuf * +etharp_ip_input(struct netif *netif, struct pbuf *p) +{ + struct ethip_hdr *hdr; + + hdr = p->payload; + + /* Only insert/update an entry if the source IP address of the + incoming IP packet comes from a host on the local network. */ + if(!ip_addr_maskcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) { + return NULL; + } + DEBUGF(ETHARP_DEBUG, ("etharp_ip_input: updating ETHARP table.\n")); + return update_arp_entry(&(hdr->ip.src), &(hdr->eth.src)); +} +/*-----------------------------------------------------------------------------------*/ +struct pbuf * +etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) +{ + struct etharp_hdr *hdr; + u8_t i; + + if(p->tot_len < sizeof(struct etharp_hdr)) { + DEBUGF(ETHARP_DEBUG, ("etharp_etharp_input: packet too short (%d/%d)\n", p->tot_len, sizeof(struct etharp_hdr))); + pbuf_free(p); + return NULL; + } + + hdr = p->payload; + + switch(htons(hdr->opcode)) { + case ARP_REQUEST: + /* ARP request. If it asked for our address, we send out a + reply. */ + DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP request\n")); + if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) { + hdr->opcode = htons(ARP_REPLY); + + ip_addr_set(&(hdr->dipaddr), &(hdr->sipaddr)); + ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr)); + + for(i = 0; i < 6; ++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, 6); + + hdr->proto = htons(ETHTYPE_IP); + ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr)); + + hdr->ethhdr.type = htons(ETHTYPE_ARP); + return p; + } + break; + case ARP_REPLY: + /* ARP reply. We insert or update the ARP table. */ + DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP reply\n")); + if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) { +#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) + dhcp_arp_reply(&hdr->sipaddr); +#endif + /* update_arp_entry() will return a pbuf that has previously been + queued waiting for an ARP reply. */ + pbuf_free(p); + p = update_arp_entry(&(hdr->sipaddr), &(hdr->shwaddr)); + + return p; + } + break; + default: + DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: unknown type %d\n", htons(hdr->opcode))); + break; + } + + pbuf_free(p); + return NULL; +} +/*-----------------------------------------------------------------------------------*/ +struct pbuf * +etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) +{ + struct eth_addr *dest, *srcaddr, mcastaddr; + struct eth_hdr *ethhdr; + struct etharp_hdr *hdr; + struct pbuf *p; + u8_t i; + + srcaddr = (struct eth_addr *)netif->hwaddr; + + /* Make room for Ethernet header. */ + if(pbuf_header(q, sizeof(struct eth_hdr)) != 0) { + /* The pbuf_header() call shouldn't fail, and we'll just bail + out if it does.. */ + DEBUGF(ETHARP_DEBUG, ("etharp_output: could not allocate room for header.\n")); +#ifdef LINK_STATS + ++stats.link.lenerr; +#endif /* LINK_STATS */ + return NULL; + } + + + dest = NULL; + /* Construct Ethernet header. Start with looking up deciding which + MAC address to use as a destination address. Broadcasts and + multicasts are special, all other addresses are looked up in the + ARP table. */ + if(ip_addr_isany(ipaddr) || + ip_addr_isbroadcast(ipaddr, &(netif->netmask))) { + dest = (struct eth_addr *)ðbroadcast; + } else if(ip_addr_ismulticast(ipaddr)) { + /* Hash IP multicast address to MAC address. */ + mcastaddr.addr[0] = 0x01; + mcastaddr.addr[1] = 0x0; + mcastaddr.addr[2] = 0x5e; + mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; + mcastaddr.addr[4] = ip4_addr3(ipaddr); + mcastaddr.addr[5] = ip4_addr4(ipaddr); + dest = &mcastaddr; + } else { + if(!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { + /* Use the IP address of the default gateway if the destination + is on the same subnet as we are. */ + ipaddr = &(netif->gw); + } + + /* We try to find a stable mapping. */ + for(i = 0; i < ARP_TABLE_SIZE; ++i) { + if(arp_table[i].state == ETHARP_STATE_STABLE && + ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { + dest = &arp_table[i].ethaddr; + break; + } + } + } + + if(dest == NULL) { + /* No destination address has been found, so we'll have to send + out an ARP request for the IP address. The outgoing packet is + queued unless the queue is full. */ + + /* We check if we are already querying for this address. If so, + we'll bail out. */ + for(i = 0; i < ARP_TABLE_SIZE; ++i) { + if(arp_table[i].state == ETHARP_STATE_PENDING && + ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { + DEBUGF(ETHARP_DEBUG, ("etharp_output: already queued\n")); + return NULL; + } + } + + i = find_arp_entry(); + + /* If all table entries were in pending state, we won't send out any + more ARP requests. We'll just give up. */ + if(i == ARP_TABLE_SIZE) { + return NULL; + } + + /* Now, i is the ARP table entry which we will fill with the new + information. */ + ip_addr_set(&arp_table[i].ipaddr, ipaddr); + /* for(k = 0; k < 6; ++k) { + arp_table[i].ethaddr.addr[k] = dest->addr[k]; + }*/ + arp_table[i].ctime = ctime; + arp_table[i].state = ETHARP_STATE_PENDING; +#if 1 + arp_table[i].p = q; + arp_table[i].payload = q->payload; + arp_table[i].len = q->len; + arp_table[i].tot_len = q->tot_len; + + /* Because the pbuf will be queued, we'll increase the refernce + count. */ + DEBUGF(ETHARP_DEBUG, ("etharp_output: queueing %p\n", q)); + pbuf_ref(q); +#else + arp_table[i].p = NULL; +#endif /* 0 */ + + + /* We allocate a pbuf for the outgoing ARP request packet. */ + p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM); + if(p == NULL) { + /* No ARP request packet could be allocated, so we forget about + the ARP table entry. */ + if(i != ARP_TABLE_SIZE) { + arp_table[i].state = ETHARP_STATE_EMPTY; + /* We decrease the reference count of the queued pbuf (which now + is dequeued). */ + DEBUGF(ETHARP_DEBUG, ("etharp_output: couldn't alloc pbuf for query, dequeueing %p\n", q)); + pbuf_free(q); + } + return NULL; + } + + hdr = p->payload; + + hdr->opcode = htons(ARP_REQUEST); + + for(i = 0; i < 6; ++i) { + hdr->dhwaddr.addr[i] = 0x00; + hdr->shwaddr.addr[i] = srcaddr->addr[i]; + } + + ip_addr_set(&(hdr->dipaddr), ipaddr); + ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr)); + + hdr->hwtype = htons(HWTYPE_ETHERNET); + ARPH_HWLEN_SET(hdr, 6); + + hdr->proto = htons(ETHTYPE_IP); + ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr)); + + for(i = 0; i < 6; ++i) { + hdr->ethhdr.dest.addr[i] = 0xff; + hdr->ethhdr.src.addr[i] = srcaddr->addr[i]; + } + + hdr->ethhdr.type = htons(ETHTYPE_ARP); + return p; + } else { + /* A valid IP->MAC address mapping was found, so we construct the + Ethernet header for the outgoing packet. */ + + ethhdr = q->payload; + + for(i = 0; i < 6; i++) { + ethhdr->dest.addr[i] = dest->addr[i]; + ethhdr->src.addr[i] = srcaddr->addr[i]; + } + + ethhdr->type = htons(ETHTYPE_IP); + + return q; + } + + +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/netif/ethernetif.c b/src/netif/ethernetif.c new file mode 100644 index 00000000..96117b49 --- /dev/null +++ b/src/netif/ethernetif.c @@ -0,0 +1,344 @@ +/* + * 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 + * + */ + +/* + * This file is a skeleton for developing Ethernet network interface + * drivers for lwIP. Add code to the low_level functions and do a + * search-and-replace for the word "ethernetif" to replace it with + * something that better describes your network interface. + */ + +#include "lwip/debug.h" + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" + +#include "netif/arp.h" + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 't' + +struct ethernetif { + struct eth_addr *ethaddr; + /* Add whatever per-interface state that is needed here. */ +}; + +static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; + +/* Forward declarations. */ +static void ethernetif_input(struct netif *netif); +static err_t ethernetif_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr); + +/*-----------------------------------------------------------------------------------*/ +static void +low_level_init(struct netif *netif) +{ + struct ethernetif *ethernetif; + + ethernetif = netif->state; + + /* Obtain MAC address from network interface. */ + ethernetif->ethaddr->addr[0] = ; + ethernetif->ethaddr->addr[1] = ; + ethernetif->ethaddr->addr[2] = ; + + /* Do whatever else is needed to initialize interface. */ +} +/*-----------------------------------------------------------------------------------*/ +/* + * low_level_output(): + * + * Should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + */ +/*-----------------------------------------------------------------------------------*/ + +static err_t +low_level_output(struct ethernetif *ethernetif, struct pbuf *p) +{ + struct pbuf *q; + + initiate transfer(); + + for(q = p; q != NULL; q = q->next) { + /* Send the data from the pbuf to the interface, one pbuf at a + time. The size of the data in each pbuf is kept in the ->len + variable. */ + send data from(q->payload, q->len); + } + + signal that packet should be sent(); + +#ifdef LINK_STATS + stats.link.xmit++; +#endif /* LINK_STATS */ + + return ERR_OK; +} +/*-----------------------------------------------------------------------------------*/ +/* + * low_level_input(): + * + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + */ +/*-----------------------------------------------------------------------------------*/ +static struct pbuf * +low_level_input(struct ethernetif *ethernetif) +{ + struct pbuf *p, *q; + u16_t len; + + /* Obtain the size of the packet and put it into the "len" + variable. */ + len = ; + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL); + + if(p != NULL) { + /* 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 + avaliable data in the pbuf is given by the q->len + variable. */ + read data into(q->payload, q->len); + } + acknowledge that packet has been read(); +#ifdef LINK_STATS + stats.link.recv++; +#endif /* LINK_STATS */ + } else { + drop packet(); +#ifdef LINK_STATS + stats.link.memerr++; + stats.link.drop++; +#endif /* LINK_STATS */ + } + + return p; +} +/*-----------------------------------------------------------------------------------*/ +/* + * ethernetif_output(): + * + * This function is called by the TCP/IP stack when an IP packet + * should be sent. It calls the function called low_level_output() to + * do the actuall transmission of the packet. + * + */ +/*-----------------------------------------------------------------------------------*/ +static err_t +ethernetif_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr) +{ + struct ethernetif *ethernetif; + struct pbuf *q; + struct eth_hdr *ethhdr; + struct eth_addr *dest, mcastaddr; + struct ip_addr *queryaddr; + err_t err; + u8_t i; + + ethernetif = netif->state; + + /* Make room for Ethernet header. */ + if(pbuf_header(p, 14) != 0) { + /* The pbuf_header() call shouldn't fail, but we allocate an extra + pbuf just in case. */ + q = pbuf_alloc(PBUF_LINK, 14, PBUF_RAM); + if(q == NULL) { +#ifdef LINK_STATS + stats.link.drop++; + stats.link.memerr++; +#endif /* LINK_STATS */ + return ERR_MEM; + } + pbuf_chain(q, p); + p = q; + } + + /* Construct Ethernet header. Start with looking up deciding which + MAC address to use as a destination address. Broadcasts and + multicasts are special, all other addresses are looked up in the + ARP table. */ + queryaddr = ipaddr; + if(ip_addr_isany(ipaddr) || + ip_addr_isbroadcast(ipaddr, &(netif->netmask))) { + dest = (struct eth_addr *)ðbroadcast; + } else if(ip_addr_ismulticast(ipaddr)) { + /* Hash IP multicast address to MAC address. */ + mcastaddr.addr[0] = 0x01; + mcastaddr.addr[1] = 0x0; + mcastaddr.addr[2] = 0x5e; + mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; + mcastaddr.addr[4] = ip4_addr3(ipaddr); + mcastaddr.addr[5] = ip4_addr4(ipaddr); + dest = &mcastaddr; + } else { + + if(ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { + /* Use destination IP address if the destination is on the same + subnet as we are. */ + queryaddr = ipaddr; + } else { + /* Otherwise we use the default router as the address to send + the Ethernet frame to. */ + queryaddr = &(netif->gw); + } + dest = arp_lookup(queryaddr); + } + + + /* If the arp_lookup() didn't find an address, we send out an ARP + query for the IP address. */ + if(dest == NULL) { + q = arp_query(netif, ethernetif->ethaddr, queryaddr); + if(q != NULL) { + err = low_level_output(ethernetif, q); + pbuf_free(q); + return err; + } +#ifdef LINK_STATS + stats.link.drop++; + stats.link.memerr++; +#endif /* LINK_STATS */ + return ERR_MEM; + } + ethhdr = p->payload; + + for(i = 0; i < 6; i++) { + ethhdr->dest.addr[i] = dest->addr[i]; + ethhdr->src.addr[i] = ethernetif->ethaddr->addr[i]; + } + + ethhdr->type = htons(ETHTYPE_IP); + + return low_level_output(ethernetif, p); + +} +/*-----------------------------------------------------------------------------------*/ +/* + * ethernetif_input(): + * + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. + * + */ +/*-----------------------------------------------------------------------------------*/ +static void +ethernetif_input(struct netif *netif) +{ + struct ethernetif *ethernetif; + struct eth_hdr *ethhdr; + struct pbuf *p; + + + ethernetif = netif->state; + + p = low_level_input(ethernetif); + + if(p != NULL) { + +#ifdef LINK_STATS + stats.link.recv++; +#endif /* LINK_STATS */ + + ethhdr = p->payload; + + switch(htons(ethhdr->type)) { + case ETHTYPE_IP: + arp_ip_input(netif, p); + pbuf_header(p, -14); + netif->input(p, netif); + break; + case ETHTYPE_ARP: + p = arp_arp_input(netif, ethernetif->ethaddr, p); + if(p != NULL) { + low_level_output(ethernetif, p); + pbuf_free(p); + } + break; + default: + pbuf_free(p); + break; + } + } +} +/*-----------------------------------------------------------------------------------*/ +static void +arp_timer(void *arg) +{ + arp_tmr(); + sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler)arp_timer, NULL); +} +/*-----------------------------------------------------------------------------------*/ +/* + * ethernetif_init(): + * + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +ethernetif_init(struct netif *netif) +{ + struct ethernetif *ethernetif; + + ethernetif = mem_malloc(sizeof(struct ethernetif)); + 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); + arp_init(); + + sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler)arp_timer, NULL); +} +/*-----------------------------------------------------------------------------------*/ diff --git a/src/netif/loopif.c b/src/netif/loopif.c new file mode 100644 index 00000000..e46b7a8e --- /dev/null +++ b/src/netif/loopif.c @@ -0,0 +1,81 @@ +/* + * 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 + * + */ +#include "lwip/debug.h" +#include "lwip/mem.h" +#include "lwip/opt.h" +#include "netif/loopif.h" +#include "netif/tcpdump.h" + +#include "lwip/tcp.h" +#include "lwip/ip.h" + +/*-----------------------------------------------------------------------------------*/ +static err_t +loopif_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr) +{ + struct pbuf *q, *r; + char *ptr; + +#ifdef LWIP_DEBUG + tcpdump(p); +#endif /* LWIP_DEBUG */ + + r = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if(r != NULL) { + ptr = r->payload; + + for(q = p; q != NULL; q = q->next) { + bcopy(q->payload, ptr, q->len); + ptr += q->len; + } + netif->input(r, netif); + return ERR_OK; + } + return ERR_MEM; +} +/*-----------------------------------------------------------------------------------*/ +void +loopif_init(struct netif *netif) +{ + netif->name[0] = 'l'; + netif->name[1] = 'o'; + netif->output = loopif_output; +} +/*-----------------------------------------------------------------------------------*/ + + + + + + + diff --git a/src/netif/tcpdump.c b/src/netif/tcpdump.c new file mode 100644 index 00000000..4db8cce8 --- /dev/null +++ b/src/netif/tcpdump.c @@ -0,0 +1,186 @@ +/* + * 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 + * + */ + +#include + +#include "netif/tcpdump.h" +#include "lwip/ip.h" +#include "lwip/tcp.h" +#include "lwip/udp.h" +#include "lwip/inet.h" + +static FILE *file = NULL; + +/*-----------------------------------------------------------------------------------*/ +void +tcpdump_init(void) +{ + char *fname; + + fname = "/tmp/tcpdump"; + file = fopen(fname, "w"); + if(file == NULL) { + perror("tcpdump_init: fopen"); + } + DEBUGF(TCPDUMP_DEBUG, ("tcpdump: file %s\n", fname)); +} +/*-----------------------------------------------------------------------------------*/ +void +tcpdump(struct pbuf *p) +{ + struct ip_hdr *iphdr; + struct tcp_hdr *tcphdr; + struct udp_hdr *udphdr; + char flags[5]; + int i; + int len; + int offset; + + if(file == NULL) { + return; + } +#ifdef IPv4 + iphdr = p->payload; + switch(IPH_PROTO(iphdr)) { + case IP_PROTO_TCP: + tcphdr = (struct tcp_hdr *)((char *)iphdr + IP_HLEN); + + pbuf_header(p, -IP_HLEN); + if(inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), + (struct ip_addr *)&(iphdr->dest), + IP_PROTO_TCP, p->tot_len) != 0) { + DEBUGF(TCPDUMP_DEBUG, ("tcpdump: IP checksum failed!\n")); + /* fprintf(file, "chksum 0x%lx ", tcphdr->chksum); + tcphdr->chksum = 0; + fprintf(file, "should be 0x%lx ", inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), + (struct ip_addr *)&(iphdr->dest), + IP_PROTO_TCP, p->tot_len));*/ + fprintf(file, "!chksum "); + } + + i = 0; + if(TCPH_FLAGS(tcphdr) & TCP_SYN) { + flags[i++] = 'S'; + } + if(TCPH_FLAGS(tcphdr) & TCP_PSH) { + flags[i++] = 'P'; + } + if(TCPH_FLAGS(tcphdr) & TCP_FIN) { + flags[i++] = 'F'; + } + if(TCPH_FLAGS(tcphdr) & TCP_RST) { + flags[i++] = 'R'; + } + if(i == 0) { + flags[i++] = '.'; + } + flags[i++] = 0; + + + + fprintf(file, "%d.%d.%d.%d.%u > %d.%d.%d.%d.%u: ", + (int)(ntohl(iphdr->src.addr) >> 24) & 0xff, + (int)(ntohl(iphdr->src.addr) >> 16) & 0xff, + (int)(ntohl(iphdr->src.addr) >> 8) & 0xff, + (int)(ntohl(iphdr->src.addr) >> 0) & 0xff, + ntohs(tcphdr->src), + (int)(ntohl(iphdr->dest.addr) >> 24) & 0xff, + (int)(ntohl(iphdr->dest.addr) >> 16) & 0xff, + (int)(ntohl(iphdr->dest.addr) >> 8) & 0xff, + (int)(ntohl(iphdr->dest.addr) >> 0) & 0xff, + ntohs(tcphdr->dest)); + offset = TCPH_OFFSET(tcphdr) >> 4; + + len = ntohs(IPH_LEN(iphdr)) - offset * 4 - IP_HLEN; + if(len != 0 || flags[0] != '.') { + fprintf(file, "%s %lu:%lu(%u) ", + flags, + ntohl(tcphdr->seqno), + ntohl(tcphdr->seqno) + len, + len); + } + if(TCPH_FLAGS(tcphdr) & TCP_ACK) { + fprintf(file, "ack %lu ", + ntohl(tcphdr->ackno)); + } + fprintf(file, "wnd %u\n", + ntohs(tcphdr->wnd)); + + fflush(file); + + pbuf_header(p, IP_HLEN); + break; + + case IP_PROTO_UDP: + udphdr = (struct udp_hdr *)((char *)iphdr + IP_HLEN); + + pbuf_header(p, -IP_HLEN); + if(inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), + (struct ip_addr *)&(iphdr->dest), + IP_PROTO_UDP, p->tot_len) != 0) { + DEBUGF(TCPDUMP_DEBUG, ("tcpdump: IP checksum failed!\n")); + /* fprintf(file, "chksum 0x%lx ", tcphdr->chksum); + tcphdr->chksum = 0; + fprintf(file, "should be 0x%lx ", inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), + (struct ip_addr *)&(iphdr->dest), + IP_PROTO_TCP, p->tot_len));*/ + fprintf(file, "!chksum "); + } + + fprintf(file, "%d.%d.%d.%d.%u > %d.%d.%d.%d.%u: ", + (int)(ntohl(iphdr->src.addr) >> 24) & 0xff, + (int)(ntohl(iphdr->src.addr) >> 16) & 0xff, + (int)(ntohl(iphdr->src.addr) >> 8) & 0xff, + (int)(ntohl(iphdr->src.addr) >> 0) & 0xff, + ntohs(udphdr->src), + (int)(ntohl(iphdr->dest.addr) >> 24) & 0xff, + (int)(ntohl(iphdr->dest.addr) >> 16) & 0xff, + (int)(ntohl(iphdr->dest.addr) >> 8) & 0xff, + (int)(ntohl(iphdr->dest.addr) >> 0) & 0xff, + ntohs(udphdr->dest)); + fprintf(file, "U "); + len = ntohs(IPH_LEN(iphdr)) - sizeof(struct udp_hdr) - IP_HLEN; + fprintf(file, " %d\n", len); + + fflush(file); + + pbuf_header(p, IP_HLEN); + break; + + } +#endif /* IPv4 */ +} +/*-----------------------------------------------------------------------------------*/ + + + +