parent
89e4d73289
commit
f0d6d4ef13
File diff suppressed because one or more lines are too long
@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* \defgroup clock Clock interface
|
||||||
|
*
|
||||||
|
* The clock interface is the interface between the \ref timer "timer library"
|
||||||
|
* and the platform specific clock functionality. The clock
|
||||||
|
* interface must be implemented for each platform that uses the \ref
|
||||||
|
* timer "timer library".
|
||||||
|
*
|
||||||
|
* The clock interface does only one this: it measures time. The clock
|
||||||
|
* interface provides a macro, CLOCK_SECOND, which corresponds to one
|
||||||
|
* second of system time.
|
||||||
|
*
|
||||||
|
* \sa \ref timer "Timer library"
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2004, Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* $Id: clock.h,v 1.3 2006/06/11 21:46:39 adam Exp $
|
||||||
|
*/
|
||||||
|
#ifndef __CLOCK_H__
|
||||||
|
#define __CLOCK_H__
|
||||||
|
|
||||||
|
#include "clock-arch.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the clock library.
|
||||||
|
*
|
||||||
|
* This function initializes the clock library and should be called
|
||||||
|
* from the main() function of the system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void clock_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current clock time.
|
||||||
|
*
|
||||||
|
* This function returns the current system clock time.
|
||||||
|
*
|
||||||
|
* \return The current clock time, measured in system ticks.
|
||||||
|
*/
|
||||||
|
clock_time_t clock_time(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A second, measured in system clock time.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifdef CLOCK_CONF_SECOND
|
||||||
|
#define CLOCK_SECOND CLOCK_CONF_SECOND
|
||||||
|
#else
|
||||||
|
#define CLOCK_SECOND (clock_time_t)32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __CLOCK_H__ */
|
||||||
|
|
||||||
|
/** @} */
|
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef __APPS_CONF_H__
|
||||||
|
#define __APPS_CONF_H__
|
||||||
|
|
||||||
|
//Here we include the header file for the application(s) we use in our project.
|
||||||
|
|
||||||
|
//#include "smtp.h"
|
||||||
|
//#include "hello-world.h"
|
||||||
|
//#include "simple-httpd.h"
|
||||||
|
//#include "telnetd.h"
|
||||||
|
//#include "webserver.h"
|
||||||
|
//#include "dhcpc.h"
|
||||||
|
//#include "resolv.h"
|
||||||
|
//#include "webclient.h"
|
||||||
|
|
||||||
|
#endif /*__APPS_CONF_H__*/
|
@ -0,0 +1,43 @@
|
|||||||
|
#include "global-conf.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/sfr_defs.h>
|
||||||
|
|
||||||
|
#include "clock-arch.h"
|
||||||
|
|
||||||
|
//Counted time
|
||||||
|
volatile clock_time_t clock_datetime = 0;
|
||||||
|
|
||||||
|
//Overflow interrupt
|
||||||
|
ISR(TIMER0_OVF_vect)
|
||||||
|
{
|
||||||
|
clock_datetime += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Initialise the clock
|
||||||
|
void clock_init()
|
||||||
|
{
|
||||||
|
//Activate overflow interrupt for timer0
|
||||||
|
TIMSK0 |= (1<<TOIE0);
|
||||||
|
|
||||||
|
//Use prescaler 1024
|
||||||
|
TCCR0B |= ((1<<CS12)|(1<<CS10));
|
||||||
|
|
||||||
|
//Activate interrupts
|
||||||
|
sei();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Return time
|
||||||
|
clock_time_t clock_time()
|
||||||
|
{
|
||||||
|
clock_time_t time;
|
||||||
|
|
||||||
|
cli();
|
||||||
|
time = clock_datetime;
|
||||||
|
sei();
|
||||||
|
|
||||||
|
return time;
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef __CLOCK_ARCH_H__
|
||||||
|
#define __CLOCK_ARCH_H__
|
||||||
|
|
||||||
|
#include "global-conf.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef uint16_t clock_time_t;
|
||||||
|
#define CLOCK_CONF_SECOND (F_CPU / 1024 / 255) //Freqency divided prescaler and counter register size
|
||||||
|
void clock_init(void);
|
||||||
|
clock_time_t clock_time(void);
|
||||||
|
|
||||||
|
#endif /* __CLOCK_ARCH_H__ */
|
@ -0,0 +1,12 @@
|
|||||||
|
//Project specific configurations
|
||||||
|
#ifndef __GLOBAL_CONF_H__
|
||||||
|
#define __GLOBAL_CONF_H__
|
||||||
|
|
||||||
|
//Define frequency
|
||||||
|
// #define F_CPU 12500000UL
|
||||||
|
//
|
||||||
|
|
||||||
|
//Include uip.h gives all the uip configurations in uip-conf.h
|
||||||
|
#include "uip.h"
|
||||||
|
|
||||||
|
#endif /*__GLOBAL_CONF_H__*/
|
@ -0,0 +1,127 @@
|
|||||||
|
#ifndef __UIP_CONF_H__
|
||||||
|
#define __UIP_CONF_H__
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef int uip_tcp_appstate_t;
|
||||||
|
typedef int uip_udp_appstate_t;
|
||||||
|
|
||||||
|
#define UIP_APPCALL TCPCallback
|
||||||
|
#define UIP_UDP_APPCALL TCPCallback
|
||||||
|
|
||||||
|
void UIP_APPCALL(void);
|
||||||
|
void UIP_UDP_APPCALL(void);
|
||||||
|
|
||||||
|
#define UIP_CONF_LLH_LEN 14
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 8 bit datatype
|
||||||
|
*
|
||||||
|
* This typedef defines the 8-bit type used throughout uIP.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
typedef uint8_t u8_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 16 bit datatype
|
||||||
|
*
|
||||||
|
* This typedef defines the 16-bit type used throughout uIP.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
typedef uint16_t u16_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statistics datatype
|
||||||
|
*
|
||||||
|
* This typedef defines the dataype used for keeping statistics in
|
||||||
|
* uIP.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
typedef unsigned short uip_stats_t;
|
||||||
|
|
||||||
|
#define UIP_CONF_IPV6 0
|
||||||
|
#define UIP_ARCH_ADD32 0
|
||||||
|
#define UIP_ARCH_CHKSUM 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of TCP connections.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_CONF_MAX_CONNECTIONS 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of listening TCP ports.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_CONF_MAX_LISTENPORTS 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uIP buffer size.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_CONF_BUFFER_SIZE 1100
|
||||||
|
/**
|
||||||
|
* CPU byte order.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_CONF_BYTE_ORDER UIP_LITTLE_ENDIAN
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logging on or off
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_CONF_LOGGING 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UDP support on or off
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_CONF_UDP 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UDP checksums on or off
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_CONF_UDP_CHECKSUMS 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uIP statistics on or off
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_CONF_STATISTICS 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast support.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_CONF_BROADCAST 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum amount of concurrent UDP connections.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_CONF_UDP_CONNS 1
|
||||||
|
|
||||||
|
//Include app configuration
|
||||||
|
#include "apps-conf.h"
|
||||||
|
|
||||||
|
#endif /* __UIP_CONF_H__ */
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
/** @} */
|
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004-2005, 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 uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* $Id: lc-addrlabels.h,v 1.3 2006/06/12 08:00:30 adam Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \addtogroup lc
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Implementation of local continuations based on the "Labels as
|
||||||
|
* values" feature of gcc
|
||||||
|
* \author
|
||||||
|
* Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* This implementation of local continuations is based on a special
|
||||||
|
* feature of the GCC C compiler called "labels as values". This
|
||||||
|
* feature allows assigning pointers with the address of the code
|
||||||
|
* corresponding to a particular C label.
|
||||||
|
*
|
||||||
|
* For more information, see the GCC documentation:
|
||||||
|
* http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
|
||||||
|
*
|
||||||
|
* Thanks to dividuum for finding the nice local scope label
|
||||||
|
* implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LC_ADDRLABELS_H__
|
||||||
|
#define __LC_ADDRLABELS_H__
|
||||||
|
|
||||||
|
/** \hideinitializer */
|
||||||
|
typedef void * lc_t;
|
||||||
|
|
||||||
|
#define LC_INIT(s) s = NULL
|
||||||
|
|
||||||
|
|
||||||
|
#define LC_RESUME(s) \
|
||||||
|
do { \
|
||||||
|
if(s != NULL) { \
|
||||||
|
goto *s; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define LC_SET(s) \
|
||||||
|
do { ({ __label__ resume; resume: (s) = &&resume; }); }while(0)
|
||||||
|
|
||||||
|
#define LC_END(s)
|
||||||
|
|
||||||
|
#endif /* __LC_ADDRLABELS_H__ */
|
||||||
|
|
||||||
|
/** @} */
|
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004-2005, 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 uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* $Id: lc-switch.h,v 1.2 2006/06/12 08:00:30 adam Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \addtogroup lc
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Implementation of local continuations based on switch() statment
|
||||||
|
* \author Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* This implementation of local continuations uses the C switch()
|
||||||
|
* statement to resume execution of a function somewhere inside the
|
||||||
|
* function's body. The implementation is based on the fact that
|
||||||
|
* switch() statements are able to jump directly into the bodies of
|
||||||
|
* control structures such as if() or while() statmenets.
|
||||||
|
*
|
||||||
|
* This implementation borrows heavily from Simon Tatham's coroutines
|
||||||
|
* implementation in C:
|
||||||
|
* http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LC_SWITCH_H__
|
||||||
|
#define __LC_SWTICH_H__
|
||||||
|
|
||||||
|
/* WARNING! lc implementation using switch() does not work if an
|
||||||
|
LC_SET() is done within another switch() statement! */
|
||||||
|
|
||||||
|
/** \hideinitializer */
|
||||||
|
typedef unsigned short lc_t;
|
||||||
|
|
||||||
|
#define LC_INIT(s) s = 0;
|
||||||
|
|
||||||
|
#define LC_RESUME(s) switch(s) { case 0:
|
||||||
|
|
||||||
|
#define LC_SET(s) s = __LINE__; case __LINE__:
|
||||||
|
|
||||||
|
#define LC_END(s) }
|
||||||
|
|
||||||
|
#endif /* __LC_SWITCH_H__ */
|
||||||
|
|
||||||
|
/** @} */
|
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004-2005, 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 uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* $Id: lc.h,v 1.2 2006/06/12 08:00:30 adam Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \addtogroup pt
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup lc Local continuations
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* Local continuations form the basis for implementing protothreads. A
|
||||||
|
* local continuation can be <i>set</i> in a specific function to
|
||||||
|
* capture the state of the function. After a local continuation has
|
||||||
|
* been set can be <i>resumed</i> in order to restore the state of the
|
||||||
|
* function at the point where the local continuation was set.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file lc.h
|
||||||
|
* Local continuations
|
||||||
|
* \author
|
||||||
|
* Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef DOXYGEN
|
||||||
|
/**
|
||||||
|
* Initialize a local continuation.
|
||||||
|
*
|
||||||
|
* This operation initializes the local continuation, thereby
|
||||||
|
* unsetting any previously set continuation state.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define LC_INIT(lc)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a local continuation.
|
||||||
|
*
|
||||||
|
* The set operation saves the state of the function at the point
|
||||||
|
* where the operation is executed. As far as the set operation is
|
||||||
|
* concerned, the state of the function does <b>not</b> include the
|
||||||
|
* call-stack or local (automatic) variables, but only the program
|
||||||
|
* counter and such CPU registers that needs to be saved.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define LC_SET(lc)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resume a local continuation.
|
||||||
|
*
|
||||||
|
* The resume operation resumes a previously set local continuation, thus
|
||||||
|
* restoring the state in which the function was when the local
|
||||||
|
* continuation was set. If the local continuation has not been
|
||||||
|
* previously set, the resume operation does nothing.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define LC_RESUME(lc)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark the end of local continuation usage.
|
||||||
|
*
|
||||||
|
* The end operation signifies that local continuations should not be
|
||||||
|
* used any more in the function. This operation is not needed for
|
||||||
|
* most implementations of local continuation, but is required by a
|
||||||
|
* few implementations.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define LC_END(lc)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var typedef lc_t;
|
||||||
|
*
|
||||||
|
* The local continuation type.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#endif /* DOXYGEN */
|
||||||
|
|
||||||
|
#ifndef __LC_H__
|
||||||
|
#define __LC_H__
|
||||||
|
|
||||||
|
#ifdef LC_CONF_INCLUDE
|
||||||
|
#include LC_CONF_INCLUDE
|
||||||
|
#else
|
||||||
|
#include "lc-switch.h"
|
||||||
|
#endif /* LC_CONF_INCLUDE */
|
||||||
|
|
||||||
|
#endif /* __LC_H__ */
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
/** @} */
|
@ -0,0 +1,338 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004, Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* $Id: psock.c,v 1.2 2006/06/12 08:00:30 adam Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "uipopt.h"
|
||||||
|
#include "psock.h"
|
||||||
|
#include "uip.h"
|
||||||
|
|
||||||
|
#define STATE_NONE 0
|
||||||
|
#define STATE_ACKED 1
|
||||||
|
#define STATE_READ 2
|
||||||
|
#define STATE_BLOCKED_NEWDATA 3
|
||||||
|
#define STATE_BLOCKED_CLOSE 4
|
||||||
|
#define STATE_BLOCKED_SEND 5
|
||||||
|
#define STATE_DATA_SENT 6
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return value of the buffering functions that indicates that a
|
||||||
|
* buffer was not filled by incoming data.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define BUF_NOT_FULL 0
|
||||||
|
#define BUF_NOT_FOUND 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return value of the buffering functions that indicates that a
|
||||||
|
* buffer was completely filled by incoming data.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define BUF_FULL 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return value of the buffering functions that indicates that an
|
||||||
|
* end-marker byte was found.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define BUF_FOUND 2
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
buf_setup(struct psock_buf *buf,
|
||||||
|
u8_t *bufptr, u16_t bufsize)
|
||||||
|
{
|
||||||
|
buf->ptr = bufptr;
|
||||||
|
buf->left = bufsize;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static u8_t
|
||||||
|
buf_bufdata(struct psock_buf *buf, u16_t len,
|
||||||
|
u8_t **dataptr, u16_t *datalen)
|
||||||
|
{
|
||||||
|
if(*datalen < buf->left) {
|
||||||
|
memcpy(buf->ptr, *dataptr, *datalen);
|
||||||
|
buf->ptr += *datalen;
|
||||||
|
buf->left -= *datalen;
|
||||||
|
*dataptr += *datalen;
|
||||||
|
*datalen = 0;
|
||||||
|
return BUF_NOT_FULL;
|
||||||
|
} else if(*datalen == buf->left) {
|
||||||
|
memcpy(buf->ptr, *dataptr, *datalen);
|
||||||
|
buf->ptr += *datalen;
|
||||||
|
buf->left = 0;
|
||||||
|
*dataptr += *datalen;
|
||||||
|
*datalen = 0;
|
||||||
|
return BUF_FULL;
|
||||||
|
} else {
|
||||||
|
memcpy(buf->ptr, *dataptr, buf->left);
|
||||||
|
buf->ptr += buf->left;
|
||||||
|
*datalen -= buf->left;
|
||||||
|
*dataptr += buf->left;
|
||||||
|
buf->left = 0;
|
||||||
|
return BUF_FULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static u8_t
|
||||||
|
buf_bufto(register struct psock_buf *buf, u8_t endmarker,
|
||||||
|
register u8_t **dataptr, register u16_t *datalen)
|
||||||
|
{
|
||||||
|
u8_t c;
|
||||||
|
while(buf->left > 0 && *datalen > 0) {
|
||||||
|
c = *buf->ptr = **dataptr;
|
||||||
|
++*dataptr;
|
||||||
|
++buf->ptr;
|
||||||
|
--*datalen;
|
||||||
|
--buf->left;
|
||||||
|
|
||||||
|
if(c == endmarker) {
|
||||||
|
return BUF_FOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*datalen == 0) {
|
||||||
|
return BUF_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(*datalen > 0) {
|
||||||
|
c = **dataptr;
|
||||||
|
--*datalen;
|
||||||
|
++*dataptr;
|
||||||
|
|
||||||
|
if(c == endmarker) {
|
||||||
|
return BUF_FOUND | BUF_FULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BUF_FULL;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static char
|
||||||
|
send_data(register struct psock *s)
|
||||||
|
{
|
||||||
|
if(s->state != STATE_DATA_SENT || uip_rexmit()) {
|
||||||
|
if(s->sendlen > uip_mss()) {
|
||||||
|
uip_send(s->sendptr, uip_mss());
|
||||||
|
} else {
|
||||||
|
uip_send(s->sendptr, s->sendlen);
|
||||||
|
}
|
||||||
|
s->state = STATE_DATA_SENT;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static char
|
||||||
|
data_acked(register struct psock *s)
|
||||||
|
{
|
||||||
|
if(s->state == STATE_DATA_SENT && uip_acked()) {
|
||||||
|
if(s->sendlen > uip_mss()) {
|
||||||
|
s->sendlen -= uip_mss();
|
||||||
|
s->sendptr += uip_mss();
|
||||||
|
} else {
|
||||||
|
s->sendptr += s->sendlen;
|
||||||
|
s->sendlen = 0;
|
||||||
|
}
|
||||||
|
s->state = STATE_ACKED;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PT_THREAD(psock_send(register struct psock *s, const char *buf,
|
||||||
|
unsigned int len))
|
||||||
|
{
|
||||||
|
PT_BEGIN(&s->psockpt);
|
||||||
|
|
||||||
|
/* If there is no data to send, we exit immediately. */
|
||||||
|
if(len == 0) {
|
||||||
|
PT_EXIT(&s->psockpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the length of and a pointer to the data that is to be
|
||||||
|
sent. */
|
||||||
|
s->sendptr = buf;
|
||||||
|
s->sendlen = len;
|
||||||
|
|
||||||
|
s->state = STATE_NONE;
|
||||||
|
|
||||||
|
/* We loop here until all data is sent. The s->sendlen variable is
|
||||||
|
updated by the data_sent() function. */
|
||||||
|
while(s->sendlen > 0) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The condition for this PT_WAIT_UNTIL is a little tricky: the
|
||||||
|
* protothread will wait here until all data has been acknowledged
|
||||||
|
* (data_acked() returns true) and until all data has been sent
|
||||||
|
* (send_data() returns true). The two functions data_acked() and
|
||||||
|
* send_data() must be called in succession to ensure that all
|
||||||
|
* data is sent. Therefore the & operator is used instead of the
|
||||||
|
* && operator, which would cause only the data_acked() function
|
||||||
|
* to be called when it returns false.
|
||||||
|
*/
|
||||||
|
PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
s->state = STATE_NONE;
|
||||||
|
|
||||||
|
PT_END(&s->psockpt);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PT_THREAD(psock_generator_send(register struct psock *s,
|
||||||
|
unsigned short (*generate)(void *), void *arg))
|
||||||
|
{
|
||||||
|
PT_BEGIN(&s->psockpt);
|
||||||
|
|
||||||
|
/* Ensure that there is a generator function to call. */
|
||||||
|
if(generate == NULL) {
|
||||||
|
PT_EXIT(&s->psockpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call the generator function to generate the data in the
|
||||||
|
uip_appdata buffer. */
|
||||||
|
s->sendlen = generate(arg);
|
||||||
|
s->sendptr = uip_appdata;
|
||||||
|
|
||||||
|
s->state = STATE_NONE;
|
||||||
|
do {
|
||||||
|
/* Call the generator function again if we are called to perform a
|
||||||
|
retransmission. */
|
||||||
|
if(uip_rexmit()) {
|
||||||
|
generate(arg);
|
||||||
|
}
|
||||||
|
/* Wait until all data is sent and acknowledged. */
|
||||||
|
PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));
|
||||||
|
} while(s->sendlen > 0);
|
||||||
|
|
||||||
|
s->state = STATE_NONE;
|
||||||
|
|
||||||
|
PT_END(&s->psockpt);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
u16_t
|
||||||
|
psock_datalen(struct psock *psock)
|
||||||
|
{
|
||||||
|
return psock->bufsize - psock->buf.left;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
char
|
||||||
|
psock_newdata(struct psock *s)
|
||||||
|
{
|
||||||
|
if(s->readlen > 0) {
|
||||||
|
/* There is data in the uip_appdata buffer that has not yet been
|
||||||
|
read with the PSOCK_READ functions. */
|
||||||
|
return 1;
|
||||||
|
} else if(s->state == STATE_READ) {
|
||||||
|
/* All data in uip_appdata buffer already consumed. */
|
||||||
|
s->state = STATE_BLOCKED_NEWDATA;
|
||||||
|
return 0;
|
||||||
|
} else if(uip_newdata()) {
|
||||||
|
/* There is new data that has not been consumed. */
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
/* There is no new data. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PT_THREAD(psock_readto(register struct psock *psock, unsigned char c))
|
||||||
|
{
|
||||||
|
PT_BEGIN(&psock->psockpt);
|
||||||
|
|
||||||
|
buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
|
||||||
|
|
||||||
|
/* XXX: Should add buf_checkmarker() before do{} loop, if
|
||||||
|
incoming data has been handled while waiting for a write. */
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(psock->readlen == 0) {
|
||||||
|
PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
|
||||||
|
psock->state = STATE_READ;
|
||||||
|
psock->readptr = (u8_t *)uip_appdata;
|
||||||
|
psock->readlen = uip_datalen();
|
||||||
|
}
|
||||||
|
} while((buf_bufto(&psock->buf, c,
|
||||||
|
&psock->readptr,
|
||||||
|
&psock->readlen) & BUF_FOUND) == 0);
|
||||||
|
|
||||||
|
if(psock_datalen(psock) == 0) {
|
||||||
|
psock->state = STATE_NONE;
|
||||||
|
PT_RESTART(&psock->psockpt);
|
||||||
|
}
|
||||||
|
PT_END(&psock->psockpt);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PT_THREAD(psock_readbuf(register struct psock *psock))
|
||||||
|
{
|
||||||
|
PT_BEGIN(&psock->psockpt);
|
||||||
|
|
||||||
|
buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
|
||||||
|
|
||||||
|
/* XXX: Should add buf_checkmarker() before do{} loop, if
|
||||||
|
incoming data has been handled while waiting for a write. */
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(psock->readlen == 0) {
|
||||||
|
PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
|
||||||
|
printf("Waited for newdata\n");
|
||||||
|
psock->state = STATE_READ;
|
||||||
|
psock->readptr = (u8_t *)uip_appdata;
|
||||||
|
psock->readlen = uip_datalen();
|
||||||
|
}
|
||||||
|
} while(buf_bufdata(&psock->buf, psock->bufsize,
|
||||||
|
&psock->readptr,
|
||||||
|
&psock->readlen) != BUF_FULL);
|
||||||
|
|
||||||
|
if(psock_datalen(psock) == 0) {
|
||||||
|
psock->state = STATE_NONE;
|
||||||
|
PT_RESTART(&psock->psockpt);
|
||||||
|
}
|
||||||
|
PT_END(&psock->psockpt);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
psock_init(register struct psock *psock, char *buffer, unsigned int buffersize)
|
||||||
|
{
|
||||||
|
psock->state = STATE_NONE;
|
||||||
|
psock->readlen = 0;
|
||||||
|
psock->bufptr = buffer;
|
||||||
|
psock->bufsize = buffersize;
|
||||||
|
buf_setup(&psock->buf, buffer, buffersize);
|
||||||
|
PT_INIT(&psock->pt);
|
||||||
|
PT_INIT(&psock->psockpt);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
@ -0,0 +1,380 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004, Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* $Id: psock.h,v 1.3 2006/06/12 08:00:30 adam Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup psock Protosockets library
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* The protosocket library provides an interface to the uIP stack that is
|
||||||
|
* similar to the traditional BSD socket interface. Unlike programs
|
||||||
|
* written for the ordinary uIP event-driven interface, programs
|
||||||
|
* written with the protosocket library are executed in a sequential
|
||||||
|
* fashion and does not have to be implemented as explicit state
|
||||||
|
* machines.
|
||||||
|
*
|
||||||
|
* Protosockets only work with TCP connections.
|
||||||
|
*
|
||||||
|
* The protosocket library uses \ref pt protothreads to provide
|
||||||
|
* sequential control flow. This makes the protosockets lightweight in
|
||||||
|
* terms of memory, but also means that protosockets inherits the
|
||||||
|
* functional limitations of protothreads. Each protosocket lives only
|
||||||
|
* within a single function. Automatic variables (stack variables) are
|
||||||
|
* not retained across a protosocket library function call.
|
||||||
|
*
|
||||||
|
* \note Because the protosocket library uses protothreads, local
|
||||||
|
* variables will not always be saved across a call to a protosocket
|
||||||
|
* library function. It is therefore advised that local variables are
|
||||||
|
* used with extreme care.
|
||||||
|
*
|
||||||
|
* The protosocket library provides functions for sending data without
|
||||||
|
* having to deal with retransmissions and acknowledgements, as well
|
||||||
|
* as functions for reading data without having to deal with data
|
||||||
|
* being split across more than one TCP segment.
|
||||||
|
*
|
||||||
|
* Because each protosocket runs as a protothread, the protosocket has to be
|
||||||
|
* started with a call to PSOCK_BEGIN() at the start of the function
|
||||||
|
* in which the protosocket is used. Similarly, the protosocket protothread can
|
||||||
|
* be terminated by a call to PSOCK_EXIT().
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Protosocket library header file
|
||||||
|
* \author
|
||||||
|
* Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PSOCK_H__
|
||||||
|
#define __PSOCK_H__
|
||||||
|
|
||||||
|
#include "uipopt.h"
|
||||||
|
#include "pt.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The structure that holds the state of a buffer.
|
||||||
|
*
|
||||||
|
* This structure holds the state of a uIP buffer. The structure has
|
||||||
|
* no user-visible elements, but is used through the functions
|
||||||
|
* provided by the library.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct psock_buf {
|
||||||
|
u8_t *ptr;
|
||||||
|
unsigned short left;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The representation of a protosocket.
|
||||||
|
*
|
||||||
|
* The protosocket structrure is an opaque structure with no user-visible
|
||||||
|
* elements.
|
||||||
|
*/
|
||||||
|
struct psock {
|
||||||
|
struct pt pt, psockpt; /* Protothreads - one that's using the psock
|
||||||
|
functions, and one that runs inside the
|
||||||
|
psock functions. */
|
||||||
|
const u8_t *sendptr; /* Pointer to the next data to be sent. */
|
||||||
|
u8_t *readptr; /* Pointer to the next data to be read. */
|
||||||
|
|
||||||
|
char *bufptr; /* Pointer to the buffer used for buffering
|
||||||
|
incoming data. */
|
||||||
|
|
||||||
|
u16_t sendlen; /* The number of bytes left to be sent. */
|
||||||
|
u16_t readlen; /* The number of bytes left to be read. */
|
||||||
|
|
||||||
|
struct psock_buf buf; /* The structure holding the state of the
|
||||||
|
input buffer. */
|
||||||
|
unsigned int bufsize; /* The size of the input buffer. */
|
||||||
|
|
||||||
|
unsigned char state; /* The state of the protosocket. */
|
||||||
|
};
|
||||||
|
|
||||||
|
void psock_init(struct psock *psock, char *buffer, unsigned int buffersize);
|
||||||
|
/**
|
||||||
|
* Initialize a protosocket.
|
||||||
|
*
|
||||||
|
* This macro initializes a protosocket and must be called before the
|
||||||
|
* protosocket is used. The initialization also specifies the input buffer
|
||||||
|
* for the protosocket.
|
||||||
|
*
|
||||||
|
* \param psock (struct psock *) A pointer to the protosocket to be
|
||||||
|
* initialized
|
||||||
|
*
|
||||||
|
* \param buffer (char *) A pointer to the input buffer for the
|
||||||
|
* protosocket.
|
||||||
|
*
|
||||||
|
* \param buffersize (unsigned int) The size of the input buffer.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PSOCK_INIT(psock, buffer, buffersize) \
|
||||||
|
psock_init(psock, buffer, buffersize)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the protosocket protothread in a function.
|
||||||
|
*
|
||||||
|
* This macro starts the protothread associated with the protosocket and
|
||||||
|
* must come before other protosocket calls in the function it is used.
|
||||||
|
*
|
||||||
|
* \param psock (struct psock *) A pointer to the protosocket to be
|
||||||
|
* started.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PSOCK_BEGIN(psock) PT_BEGIN(&((psock)->pt))
|
||||||
|
|
||||||
|
PT_THREAD(psock_send(struct psock *psock, const char *buf, unsigned int len));
|
||||||
|
/**
|
||||||
|
* Send data.
|
||||||
|
*
|
||||||
|
* This macro sends data over a protosocket. The protosocket protothread blocks
|
||||||
|
* until all data has been sent and is known to have been received by
|
||||||
|
* the remote end of the TCP connection.
|
||||||
|
*
|
||||||
|
* \param psock (struct psock *) A pointer to the protosocket over which
|
||||||
|
* data is to be sent.
|
||||||
|
*
|
||||||
|
* \param data (char *) A pointer to the data that is to be sent.
|
||||||
|
*
|
||||||
|
* \param datalen (unsigned int) The length of the data that is to be
|
||||||
|
* sent.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PSOCK_SEND(psock, data, datalen) \
|
||||||
|
PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, data, datalen))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Send a null-terminated string.
|
||||||
|
* \param psock Pointer to the protosocket.
|
||||||
|
* \param str The string to be sent.
|
||||||
|
*
|
||||||
|
* This function sends a null-terminated string over the
|
||||||
|
* protosocket.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PSOCK_SEND_STR(psock, str) \
|
||||||
|
PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, str, strlen(str)))
|
||||||
|
|
||||||
|
PT_THREAD(psock_generator_send(struct psock *psock,
|
||||||
|
unsigned short (*f)(void *), void *arg));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Generate data with a function and send it
|
||||||
|
* \param psock Pointer to the protosocket.
|
||||||
|
* \param generator Pointer to the generator function
|
||||||
|
* \param arg Argument to the generator function
|
||||||
|
*
|
||||||
|
* This function generates data and sends it over the
|
||||||
|
* protosocket. This can be used to dynamically generate
|
||||||
|
* data for a transmission, instead of generating the data
|
||||||
|
* in a buffer beforehand. This function reduces the need for
|
||||||
|
* buffer memory. The generator function is implemented by
|
||||||
|
* the application, and a pointer to the function is given
|
||||||
|
* as an argument with the call to PSOCK_GENERATOR_SEND().
|
||||||
|
*
|
||||||
|
* The generator function should place the generated data
|
||||||
|
* directly in the uip_appdata buffer, and return the
|
||||||
|
* length of the generated data. The generator function is
|
||||||
|
* called by the protosocket layer when the data first is
|
||||||
|
* sent, and once for every retransmission that is needed.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PSOCK_GENERATOR_SEND(psock, generator, arg) \
|
||||||
|
PT_WAIT_THREAD(&((psock)->pt), \
|
||||||
|
psock_generator_send(psock, generator, arg))
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a protosocket.
|
||||||
|
*
|
||||||
|
* This macro closes a protosocket and can only be called from within the
|
||||||
|
* protothread in which the protosocket lives.
|
||||||
|
*
|
||||||
|
* \param psock (struct psock *) A pointer to the protosocket that is to
|
||||||
|
* be closed.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PSOCK_CLOSE(psock) uip_close()
|
||||||
|
|
||||||
|
PT_THREAD(psock_readbuf(struct psock *psock));
|
||||||
|
/**
|
||||||
|
* Read data until the buffer is full.
|
||||||
|
*
|
||||||
|
* This macro will block waiting for data and read the data into the
|
||||||
|
* input buffer specified with the call to PSOCK_INIT(). Data is read
|
||||||
|
* until the buffer is full..
|
||||||
|
*
|
||||||
|
* \param psock (struct psock *) A pointer to the protosocket from which
|
||||||
|
* data should be read.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PSOCK_READBUF(psock) \
|
||||||
|
PT_WAIT_THREAD(&((psock)->pt), psock_readbuf(psock))
|
||||||
|
|
||||||
|
PT_THREAD(psock_readto(struct psock *psock, unsigned char c));
|
||||||
|
/**
|
||||||
|
* Read data up to a specified character.
|
||||||
|
*
|
||||||
|
* This macro will block waiting for data and read the data into the
|
||||||
|
* input buffer specified with the call to PSOCK_INIT(). Data is only
|
||||||
|
* read until the specifieed character appears in the data stream.
|
||||||
|
*
|
||||||
|
* \param psock (struct psock *) A pointer to the protosocket from which
|
||||||
|
* data should be read.
|
||||||
|
*
|
||||||
|
* \param c (char) The character at which to stop reading.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PSOCK_READTO(psock, c) \
|
||||||
|
PT_WAIT_THREAD(&((psock)->pt), psock_readto(psock, c))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of the data that was previously read.
|
||||||
|
*
|
||||||
|
* This macro returns the length of the data that was previously read
|
||||||
|
* using PSOCK_READTO() or PSOCK_READ().
|
||||||
|
*
|
||||||
|
* \param psock (struct psock *) A pointer to the protosocket holding the data.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PSOCK_DATALEN(psock) psock_datalen(psock)
|
||||||
|
|
||||||
|
u16_t psock_datalen(struct psock *psock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exit the protosocket's protothread.
|
||||||
|
*
|
||||||
|
* This macro terminates the protothread of the protosocket and should
|
||||||
|
* almost always be used in conjunction with PSOCK_CLOSE().
|
||||||
|
*
|
||||||
|
* \sa PSOCK_CLOSE_EXIT()
|
||||||
|
*
|
||||||
|
* \param psock (struct psock *) A pointer to the protosocket.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PSOCK_EXIT(psock) PT_EXIT(&((psock)->pt))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a protosocket and exit the protosocket's protothread.
|
||||||
|
*
|
||||||
|
* This macro closes a protosocket and exits the protosocket's protothread.
|
||||||
|
*
|
||||||
|
* \param psock (struct psock *) A pointer to the protosocket.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PSOCK_CLOSE_EXIT(psock) \
|
||||||
|
do { \
|
||||||
|
PSOCK_CLOSE(psock); \
|
||||||
|
PSOCK_EXIT(psock); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare the end of a protosocket's protothread.
|
||||||
|
*
|
||||||
|
* This macro is used for declaring that the protosocket's protothread
|
||||||
|
* ends. It must always be used together with a matching PSOCK_BEGIN()
|
||||||
|
* macro.
|
||||||
|
*
|
||||||
|
* \param psock (struct psock *) A pointer to the protosocket.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PSOCK_END(psock) PT_END(&((psock)->pt))
|
||||||
|
|
||||||
|
char psock_newdata(struct psock *s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if new data has arrived on a protosocket.
|
||||||
|
*
|
||||||
|
* This macro is used in conjunction with the PSOCK_WAIT_UNTIL()
|
||||||
|
* macro to check if data has arrived on a protosocket.
|
||||||
|
*
|
||||||
|
* \param psock (struct psock *) A pointer to the protosocket.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PSOCK_NEWDATA(psock) psock_newdata(psock)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait until a condition is true.
|
||||||
|
*
|
||||||
|
* This macro blocks the protothread until the specified condition is
|
||||||
|
* true. The macro PSOCK_NEWDATA() can be used to check if new data
|
||||||
|
* arrives when the protosocket is waiting.
|
||||||
|
*
|
||||||
|
* Typically, this macro is used as follows:
|
||||||
|
*
|
||||||
|
\code
|
||||||
|
PT_THREAD(thread(struct psock *s, struct timer *t))
|
||||||
|
{
|
||||||
|
PSOCK_BEGIN(s);
|
||||||
|
|
||||||
|
PSOCK_WAIT_UNTIL(s, PSOCK_NEWADATA(s) || timer_expired(t));
|
||||||
|
|
||||||
|
if(PSOCK_NEWDATA(s)) {
|
||||||
|
PSOCK_READTO(s, '\n');
|
||||||
|
} else {
|
||||||
|
handle_timed_out(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
PSOCK_END(s);
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \param psock (struct psock *) A pointer to the protosocket.
|
||||||
|
* \param condition The condition to wait for.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PSOCK_WAIT_UNTIL(psock, condition) \
|
||||||
|
PT_WAIT_UNTIL(&((psock)->pt), (condition));
|
||||||
|
|
||||||
|
#define PSOCK_WAIT_THREAD(psock, condition) \
|
||||||
|
PT_WAIT_THREAD(&((psock)->pt), (condition))
|
||||||
|
|
||||||
|
#endif /* __PSOCK_H__ */
|
||||||
|
|
||||||
|
/** @} */
|
@ -0,0 +1,323 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004-2005, 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 uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* $Id: pt.h,v 1.2 2006/06/12 08:00:30 adam Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \addtogroup pt
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Protothreads implementation.
|
||||||
|
* \author
|
||||||
|
* Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PT_H__
|
||||||
|
#define __PT_H__
|
||||||
|
|
||||||
|
#include "lc.h"
|
||||||
|
|
||||||
|
struct pt {
|
||||||
|
lc_t lc;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PT_WAITING 0
|
||||||
|
#define PT_EXITED 1
|
||||||
|
#define PT_ENDED 2
|
||||||
|
#define PT_YIELDED 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name Initialization
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a protothread.
|
||||||
|
*
|
||||||
|
* Initializes a protothread. Initialization must be done prior to
|
||||||
|
* starting to execute the protothread.
|
||||||
|
*
|
||||||
|
* \param pt A pointer to the protothread control structure.
|
||||||
|
*
|
||||||
|
* \sa PT_SPAWN()
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PT_INIT(pt) LC_INIT((pt)->lc)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name Declaration and definition
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declaration of a protothread.
|
||||||
|
*
|
||||||
|
* This macro is used to declare a protothread. All protothreads must
|
||||||
|
* be declared with this macro.
|
||||||
|
*
|
||||||
|
* \param name_args The name and arguments of the C function
|
||||||
|
* implementing the protothread.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PT_THREAD(name_args) char name_args
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare the start of a protothread inside the C function
|
||||||
|
* implementing the protothread.
|
||||||
|
*
|
||||||
|
* This macro is used to declare the starting point of a
|
||||||
|
* protothread. It should be placed at the start of the function in
|
||||||
|
* which the protothread runs. All C statements above the PT_BEGIN()
|
||||||
|
* invokation will be executed each time the protothread is scheduled.
|
||||||
|
*
|
||||||
|
* \param pt A pointer to the protothread control structure.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare the end of a protothread.
|
||||||
|
*
|
||||||
|
* This macro is used for declaring that a protothread ends. It must
|
||||||
|
* always be used together with a matching PT_BEGIN() macro.
|
||||||
|
*
|
||||||
|
* \param pt A pointer to the protothread control structure.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \
|
||||||
|
PT_INIT(pt); return PT_ENDED; }
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name Blocked wait
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block and wait until condition is true.
|
||||||
|
*
|
||||||
|
* This macro blocks the protothread until the specified condition is
|
||||||
|
* true.
|
||||||
|
*
|
||||||
|
* \param pt A pointer to the protothread control structure.
|
||||||
|
* \param condition The condition.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PT_WAIT_UNTIL(pt, condition) \
|
||||||
|
do { \
|
||||||
|
LC_SET((pt)->lc); \
|
||||||
|
if(!(condition)) { \
|
||||||
|
return PT_WAITING; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block and wait while condition is true.
|
||||||
|
*
|
||||||
|
* This function blocks and waits while condition is true. See
|
||||||
|
* PT_WAIT_UNTIL().
|
||||||
|
*
|
||||||
|
* \param pt A pointer to the protothread control structure.
|
||||||
|
* \param cond The condition.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond))
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name Hierarchical protothreads
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block and wait until a child protothread completes.
|
||||||
|
*
|
||||||
|
* This macro schedules a child protothread. The current protothread
|
||||||
|
* will block until the child protothread completes.
|
||||||
|
*
|
||||||
|
* \note The child protothread must be manually initialized with the
|
||||||
|
* PT_INIT() function before this function is used.
|
||||||
|
*
|
||||||
|
* \param pt A pointer to the protothread control structure.
|
||||||
|
* \param thread The child protothread with arguments
|
||||||
|
*
|
||||||
|
* \sa PT_SPAWN()
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spawn a child protothread and wait until it exits.
|
||||||
|
*
|
||||||
|
* This macro spawns a child protothread and waits until it exits. The
|
||||||
|
* macro can only be used within a protothread.
|
||||||
|
*
|
||||||
|
* \param pt A pointer to the protothread control structure.
|
||||||
|
* \param child A pointer to the child protothread's control structure.
|
||||||
|
* \param thread The child protothread with arguments
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PT_SPAWN(pt, child, thread) \
|
||||||
|
do { \
|
||||||
|
PT_INIT((child)); \
|
||||||
|
PT_WAIT_THREAD((pt), (thread)); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name Exiting and restarting
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restart the protothread.
|
||||||
|
*
|
||||||
|
* This macro will block and cause the running protothread to restart
|
||||||
|
* its execution at the place of the PT_BEGIN() call.
|
||||||
|
*
|
||||||
|
* \param pt A pointer to the protothread control structure.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PT_RESTART(pt) \
|
||||||
|
do { \
|
||||||
|
PT_INIT(pt); \
|
||||||
|
return PT_WAITING; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exit the protothread.
|
||||||
|
*
|
||||||
|
* This macro causes the protothread to exit. If the protothread was
|
||||||
|
* spawned by another protothread, the parent protothread will become
|
||||||
|
* unblocked and can continue to run.
|
||||||
|
*
|
||||||
|
* \param pt A pointer to the protothread control structure.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PT_EXIT(pt) \
|
||||||
|
do { \
|
||||||
|
PT_INIT(pt); \
|
||||||
|
return PT_EXITED; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name Calling a protothread
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule a protothread.
|
||||||
|
*
|
||||||
|
* This function shedules a protothread. The return value of the
|
||||||
|
* function is non-zero if the protothread is running or zero if the
|
||||||
|
* protothread has exited.
|
||||||
|
*
|
||||||
|
* \param f The call to the C function implementing the protothread to
|
||||||
|
* be scheduled
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PT_SCHEDULE(f) ((f) == PT_WAITING)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name Yielding from a protothread
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Yield from the current protothread.
|
||||||
|
*
|
||||||
|
* This function will yield the protothread, thereby allowing other
|
||||||
|
* processing to take place in the system.
|
||||||
|
*
|
||||||
|
* \param pt A pointer to the protothread control structure.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PT_YIELD(pt) \
|
||||||
|
do { \
|
||||||
|
PT_YIELD_FLAG = 0; \
|
||||||
|
LC_SET((pt)->lc); \
|
||||||
|
if(PT_YIELD_FLAG == 0) { \
|
||||||
|
return PT_YIELDED; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Yield from the protothread until a condition occurs.
|
||||||
|
* \param pt A pointer to the protothread control structure.
|
||||||
|
* \param cond The condition.
|
||||||
|
*
|
||||||
|
* This function will yield the protothread, until the
|
||||||
|
* specified condition evaluates to true.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define PT_YIELD_UNTIL(pt, cond) \
|
||||||
|
do { \
|
||||||
|
PT_YIELD_FLAG = 0; \
|
||||||
|
LC_SET((pt)->lc); \
|
||||||
|
if((PT_YIELD_FLAG == 0) || !(cond)) { \
|
||||||
|
return PT_YIELDED; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#endif /* __PT_H__ */
|
||||||
|
|
||||||
|
/** @} */
|
@ -0,0 +1,127 @@
|
|||||||
|
/**
|
||||||
|
* \addtogroup timer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Timer library implementation.
|
||||||
|
* \author
|
||||||
|
* Adam Dunkels <adam@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2004, Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* $Id: timer.c,v 1.2 2006/06/12 08:00:30 adam Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "clock.h"
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Set a timer.
|
||||||
|
*
|
||||||
|
* This function is used to set a timer for a time sometime in the
|
||||||
|
* future. The function timer_expired() will evaluate to true after
|
||||||
|
* the timer has expired.
|
||||||
|
*
|
||||||
|
* \param t A pointer to the timer
|
||||||
|
* \param interval The interval before the timer expires.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
timer_set(struct timer *t, clock_time_t interval)
|
||||||
|
{
|
||||||
|
t->interval = interval;
|
||||||
|
t->start = clock_time();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Reset the timer with the same interval.
|
||||||
|
*
|
||||||
|
* This function resets the timer with the same interval that was
|
||||||
|
* given to the timer_set() function. The start point of the interval
|
||||||
|
* is the exact time that the timer last expired. Therefore, this
|
||||||
|
* function will cause the timer to be stable over time, unlike the
|
||||||
|
* timer_rester() function.
|
||||||
|
*
|
||||||
|
* \param t A pointer to the timer.
|
||||||
|
*
|
||||||
|
* \sa timer_restart()
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
timer_reset(struct timer *t)
|
||||||
|
{
|
||||||
|
t->start += t->interval;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Restart the timer from the current point in time
|
||||||
|
*
|
||||||
|
* This function restarts a timer with the same interval that was
|
||||||
|
* given to the timer_set() function. The timer will start at the
|
||||||
|
* current time.
|
||||||
|
*
|
||||||
|
* \note A periodic timer will drift if this function is used to reset
|
||||||
|
* it. For preioric timers, use the timer_reset() function instead.
|
||||||
|
*
|
||||||
|
* \param t A pointer to the timer.
|
||||||
|
*
|
||||||
|
* \sa timer_reset()
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
timer_restart(struct timer *t)
|
||||||
|
{
|
||||||
|
t->start = clock_time();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Check if a timer has expired.
|
||||||
|
*
|
||||||
|
* This function tests if a timer has expired and returns true or
|
||||||
|
* false depending on its status.
|
||||||
|
*
|
||||||
|
* \param t A pointer to the timer
|
||||||
|
*
|
||||||
|
* \return Non-zero if the timer has expired, zero otherwise.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
timer_expired(struct timer *t)
|
||||||
|
{
|
||||||
|
return (clock_time_t)(clock_time() - t->start) >= (clock_time_t)t->interval;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/** @} */
|
@ -0,0 +1,86 @@
|
|||||||
|
/**
|
||||||
|
* \defgroup timer Timer library
|
||||||
|
*
|
||||||
|
* The timer library provides functions for setting, resetting and
|
||||||
|
* restarting timers, and for checking if a timer has expired. An
|
||||||
|
* application must "manually" check if its timers have expired; this
|
||||||
|
* is not done automatically.
|
||||||
|
*
|
||||||
|
* A timer is declared as a \c struct \c timer and all access to the
|
||||||
|
* timer is made by a pointer to the declared timer.
|
||||||
|
*
|
||||||
|
* \note The timer library uses the \ref clock "Clock library" to
|
||||||
|
* measure time. Intervals should be specified in the format used by
|
||||||
|
* the clock library.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Timer library header file.
|
||||||
|
* \author
|
||||||
|
* Adam Dunkels <adam@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2004, Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* $Id: timer.h,v 1.3 2006/06/11 21:46:39 adam Exp $
|
||||||
|
*/
|
||||||
|
#ifndef __TIMER_H__
|
||||||
|
#define __TIMER_H__
|
||||||
|
|
||||||
|
#include "clock.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A timer.
|
||||||
|
*
|
||||||
|
* This structure is used for declaring a timer. The timer must be set
|
||||||
|
* with timer_set() before it can be used.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
struct timer {
|
||||||
|
clock_time_t start;
|
||||||
|
clock_time_t interval;
|
||||||
|
};
|
||||||
|
|
||||||
|
void timer_set(struct timer *t, clock_time_t interval);
|
||||||
|
void timer_reset(struct timer *t);
|
||||||
|
void timer_restart(struct timer *t);
|
||||||
|
int timer_expired(struct timer *t);
|
||||||
|
|
||||||
|
#endif /* __TIMER_H__ */
|
||||||
|
|
||||||
|
/** @} */
|
@ -0,0 +1,532 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004, Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* $Id: uip-fw.c,v 1.2 2006/06/12 08:00:30 adam Exp $
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \addtogroup uip
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup uipfw uIP packet forwarding
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* uIP packet forwarding.
|
||||||
|
* \author Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* This file implements a number of simple functions which do packet
|
||||||
|
* forwarding over multiple network interfaces with uIP.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "uip.h"
|
||||||
|
#include "uip_arch.h"
|
||||||
|
#include "uip-fw.h"
|
||||||
|
|
||||||
|
#include <string.h> /* for memcpy() */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The list of registered network interfaces.
|
||||||
|
*/
|
||||||
|
static struct uip_fw_netif *netifs = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A pointer to the default network interface.
|
||||||
|
*/
|
||||||
|
static struct uip_fw_netif *defaultnetif = NULL;
|
||||||
|
|
||||||
|
struct tcpip_hdr {
|
||||||
|
/* IP header. */
|
||||||
|
u8_t vhl,
|
||||||
|
tos;
|
||||||
|
u16_t len,
|
||||||
|
ipid,
|
||||||
|
ipoffset;
|
||||||
|
u8_t ttl,
|
||||||
|
proto;
|
||||||
|
u16_t ipchksum;
|
||||||
|
u16_t srcipaddr[2],
|
||||||
|
destipaddr[2];
|
||||||
|
|
||||||
|
/* TCP header. */
|
||||||
|
u16_t srcport,
|
||||||
|
destport;
|
||||||
|
u8_t seqno[4],
|
||||||
|
ackno[4],
|
||||||
|
tcpoffset,
|
||||||
|
flags,
|
||||||
|
wnd[2];
|
||||||
|
u16_t tcpchksum;
|
||||||
|
u8_t urgp[2];
|
||||||
|
u8_t optdata[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct icmpip_hdr {
|
||||||
|
/* IP header. */
|
||||||
|
u8_t vhl,
|
||||||
|
tos,
|
||||||
|
len[2],
|
||||||
|
ipid[2],
|
||||||
|
ipoffset[2],
|
||||||
|
ttl,
|
||||||
|
proto;
|
||||||
|
u16_t ipchksum;
|
||||||
|
u16_t srcipaddr[2],
|
||||||
|
destipaddr[2];
|
||||||
|
/* ICMP (echo) header. */
|
||||||
|
u8_t type, icode;
|
||||||
|
u16_t icmpchksum;
|
||||||
|
u16_t id, seqno;
|
||||||
|
u8_t payload[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ICMP ECHO. */
|
||||||
|
#define ICMP_ECHO 8
|
||||||
|
|
||||||
|
/* ICMP TIME-EXCEEDED. */
|
||||||
|
#define ICMP_TE 11
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pointer to the TCP/IP headers of the packet in the uip_buf buffer.
|
||||||
|
*/
|
||||||
|
#define BUF ((struct tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pointer to the ICMP/IP headers of the packet in the uip_buf buffer.
|
||||||
|
*/
|
||||||
|
#define ICMPBUF ((struct icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Certain fields of an IP packet that are used for identifying
|
||||||
|
* duplicate packets.
|
||||||
|
*/
|
||||||
|
struct fwcache_entry {
|
||||||
|
u16_t timer;
|
||||||
|
|
||||||
|
u16_t srcipaddr[2];
|
||||||
|
u16_t destipaddr[2];
|
||||||
|
u16_t ipid;
|
||||||
|
u8_t proto;
|
||||||
|
u8_t unused;
|
||||||
|
|
||||||
|
#if notdef
|
||||||
|
u16_t payload[2];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if UIP_REASSEMBLY > 0
|
||||||
|
u16_t len, offset;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The number of packets to remember when looking for duplicates.
|
||||||
|
*/
|
||||||
|
#ifdef UIP_CONF_FWCACHE_SIZE
|
||||||
|
#define FWCACHE_SIZE UIP_CONF_FWCACHE_SIZE
|
||||||
|
#else
|
||||||
|
#define FWCACHE_SIZE 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A cache of packet header fields which are used for
|
||||||
|
* identifying duplicate packets.
|
||||||
|
*/
|
||||||
|
static struct fwcache_entry fwcache[FWCACHE_SIZE];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \internal
|
||||||
|
* The time that a packet cache is active.
|
||||||
|
*/
|
||||||
|
#define FW_TIME 20
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Initialize the uIP packet forwarding module.
|
||||||
|
*/
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_fw_init(void)
|
||||||
|
{
|
||||||
|
struct uip_fw_netif *t;
|
||||||
|
defaultnetif = NULL;
|
||||||
|
while(netifs != NULL) {
|
||||||
|
t = netifs;
|
||||||
|
netifs = netifs->next;
|
||||||
|
t->next = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* \internal
|
||||||
|
* Check if an IP address is within the network defined by an IP
|
||||||
|
* address and a netmask.
|
||||||
|
*
|
||||||
|
* \param ipaddr The IP address to be checked.
|
||||||
|
* \param netipaddr The IP address of the network.
|
||||||
|
* \param netmask The netmask of the network.
|
||||||
|
*
|
||||||
|
* \return Non-zero if IP address is in network, zero otherwise.
|
||||||
|
*/
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
static unsigned char
|
||||||
|
ipaddr_maskcmp(u16_t *ipaddr, u16_t *netipaddr, u16_t *netmask)
|
||||||
|
{
|
||||||
|
return (ipaddr[0] & netmask [0]) == (netipaddr[0] & netmask[0]) &&
|
||||||
|
(ipaddr[1] & netmask[1]) == (netipaddr[1] & netmask[1]);
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* \internal
|
||||||
|
* Send out an ICMP TIME-EXCEEDED message.
|
||||||
|
*
|
||||||
|
* This function replaces the packet in the uip_buf buffer with the
|
||||||
|
* ICMP packet.
|
||||||
|
*/
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
time_exceeded(void)
|
||||||
|
{
|
||||||
|
u16_t tmp16;
|
||||||
|
|
||||||
|
/* We don't send out ICMP errors for ICMP messages. */
|
||||||
|
if(ICMPBUF->proto == UIP_PROTO_ICMP) {
|
||||||
|
uip_len = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Copy fields from packet header into payload of this ICMP packet. */
|
||||||
|
memcpy(&(ICMPBUF->payload[0]), ICMPBUF, 28);
|
||||||
|
|
||||||
|
/* Set the ICMP type and code. */
|
||||||
|
ICMPBUF->type = ICMP_TE;
|
||||||
|
ICMPBUF->icode = 0;
|
||||||
|
|
||||||
|
/* Calculate the ICMP checksum. */
|
||||||
|
ICMPBUF->icmpchksum = 0;
|
||||||
|
ICMPBUF->icmpchksum = ~uip_chksum((u16_t *)&(ICMPBUF->type), 36);
|
||||||
|
|
||||||
|
/* Set the IP destination address to be the source address of the
|
||||||
|
original packet. */
|
||||||
|
tmp16= BUF->destipaddr[0];
|
||||||
|
BUF->destipaddr[0] = BUF->srcipaddr[0];
|
||||||
|
BUF->srcipaddr[0] = tmp16;
|
||||||
|
tmp16 = BUF->destipaddr[1];
|
||||||
|
BUF->destipaddr[1] = BUF->srcipaddr[1];
|
||||||
|
BUF->srcipaddr[1] = tmp16;
|
||||||
|
|
||||||
|
/* Set our IP address as the source address. */
|
||||||
|
BUF->srcipaddr[0] = uip_hostaddr[0];
|
||||||
|
BUF->srcipaddr[1] = uip_hostaddr[1];
|
||||||
|
|
||||||
|
/* The size of the ICMP time exceeded packet is 36 + the size of the
|
||||||
|
IP header (20) = 56. */
|
||||||
|
uip_len = 56;
|
||||||
|
ICMPBUF->len[0] = 0;
|
||||||
|
ICMPBUF->len[1] = uip_len;
|
||||||
|
|
||||||
|
/* Fill in the other fields in the IP header. */
|
||||||
|
ICMPBUF->vhl = 0x45;
|
||||||
|
ICMPBUF->tos = 0;
|
||||||
|
ICMPBUF->ipoffset[0] = ICMPBUF->ipoffset[1] = 0;
|
||||||
|
ICMPBUF->ttl = UIP_TTL;
|
||||||
|
ICMPBUF->proto = UIP_PROTO_ICMP;
|
||||||
|
|
||||||
|
/* Calculate IP checksum. */
|
||||||
|
ICMPBUF->ipchksum = 0;
|
||||||
|
ICMPBUF->ipchksum = ~(uip_ipchksum());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* \internal
|
||||||
|
* Register a packet in the forwarding cache so that it won't be
|
||||||
|
* forwarded again.
|
||||||
|
*/
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
fwcache_register(void)
|
||||||
|
{
|
||||||
|
struct fwcache_entry *fw;
|
||||||
|
int i, oldest;
|
||||||
|
|
||||||
|
oldest = FW_TIME;
|
||||||
|
fw = NULL;
|
||||||
|
|
||||||
|
/* Find the oldest entry in the cache. */
|
||||||
|
for(i = 0; i < FWCACHE_SIZE; ++i) {
|
||||||
|
if(fwcache[i].timer == 0) {
|
||||||
|
fw = &fwcache[i];
|
||||||
|
break;
|
||||||
|
} else if(fwcache[i].timer <= oldest) {
|
||||||
|
fw = &fwcache[i];
|
||||||
|
oldest = fwcache[i].timer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fw->timer = FW_TIME;
|
||||||
|
fw->ipid = BUF->ipid;
|
||||||
|
fw->srcipaddr[0] = BUF->srcipaddr[0];
|
||||||
|
fw->srcipaddr[1] = BUF->srcipaddr[1];
|
||||||
|
fw->destipaddr[0] = BUF->destipaddr[0];
|
||||||
|
fw->destipaddr[1] = BUF->destipaddr[1];
|
||||||
|
fw->proto = BUF->proto;
|
||||||
|
#if notdef
|
||||||
|
fw->payload[0] = BUF->srcport;
|
||||||
|
fw->payload[1] = BUF->destport;
|
||||||
|
#endif
|
||||||
|
#if UIP_REASSEMBLY > 0
|
||||||
|
fw->len = BUF->len;
|
||||||
|
fw->offset = BUF->ipoffset;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* \internal
|
||||||
|
* Find a network interface for the IP packet in uip_buf.
|
||||||
|
*/
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
static struct uip_fw_netif *
|
||||||
|
find_netif(void)
|
||||||
|
{
|
||||||
|
struct uip_fw_netif *netif;
|
||||||
|
|
||||||
|
/* Walk through every network interface to check for a match. */
|
||||||
|
for(netif = netifs; netif != NULL; netif = netif->next) {
|
||||||
|
if(ipaddr_maskcmp(BUF->destipaddr, netif->ipaddr,
|
||||||
|
netif->netmask)) {
|
||||||
|
/* If there was a match, we break the loop. */
|
||||||
|
return netif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If no matching netif was found, we use default netif. */
|
||||||
|
return defaultnetif;
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Output an IP packet on the correct network interface.
|
||||||
|
*
|
||||||
|
* The IP packet should be present in the uip_buf buffer and its
|
||||||
|
* length in the global uip_len variable.
|
||||||
|
*
|
||||||
|
* \retval UIP_FW_ZEROLEN Indicates that a zero-length packet
|
||||||
|
* transmission was attempted and that no packet was sent.
|
||||||
|
*
|
||||||
|
* \retval UIP_FW_NOROUTE No suitable network interface could be found
|
||||||
|
* for the outbound packet, and the packet was not sent.
|
||||||
|
*
|
||||||
|
* \return The return value from the actual network interface output
|
||||||
|
* function is passed unmodified as a return value.
|
||||||
|
*/
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
u8_t
|
||||||
|
uip_fw_output(void)
|
||||||
|
{
|
||||||
|
struct uip_fw_netif *netif;
|
||||||
|
|
||||||
|
if(uip_len == 0) {
|
||||||
|
return UIP_FW_ZEROLEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
fwcache_register();
|
||||||
|
|
||||||
|
#if UIP_BROADCAST
|
||||||
|
/* Link local broadcasts go out on all interfaces. */
|
||||||
|
if(/*BUF->proto == UIP_PROTO_UDP &&*/
|
||||||
|
BUF->destipaddr[0] == 0xffff &&
|
||||||
|
BUF->destipaddr[1] == 0xffff) {
|
||||||
|
if(defaultnetif != NULL) {
|
||||||
|
defaultnetif->output();
|
||||||
|
}
|
||||||
|
for(netif = netifs; netif != NULL; netif = netif->next) {
|
||||||
|
netif->output();
|
||||||
|
}
|
||||||
|
return UIP_FW_OK;
|
||||||
|
}
|
||||||
|
#endif /* UIP_BROADCAST */
|
||||||
|
|
||||||
|
netif = find_netif();
|
||||||
|
/* printf("uip_fw_output: netif %p ->output %p len %d\n", netif,
|
||||||
|
netif->output,
|
||||||
|
uip_len);*/
|
||||||
|
|
||||||
|
if(netif == NULL) {
|
||||||
|
return UIP_FW_NOROUTE;
|
||||||
|
}
|
||||||
|
/* If we now have found a suitable network interface, we call its
|
||||||
|
output function to send out the packet. */
|
||||||
|
return netif->output();
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Forward an IP packet in the uip_buf buffer.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* \return UIP_FW_FORWARDED if the packet was forwarded, UIP_FW_LOCAL if
|
||||||
|
* the packet should be processed locally.
|
||||||
|
*/
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
u8_t
|
||||||
|
uip_fw_forward(void)
|
||||||
|
{
|
||||||
|
struct fwcache_entry *fw;
|
||||||
|
|
||||||
|
/* First check if the packet is destined for ourselves and return 0
|
||||||
|
to indicate that the packet should be processed locally. */
|
||||||
|
if(BUF->destipaddr[0] == uip_hostaddr[0] &&
|
||||||
|
BUF->destipaddr[1] == uip_hostaddr[1]) {
|
||||||
|
return UIP_FW_LOCAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we use ping IP address configuration, and our IP address is
|
||||||
|
not yet configured, we should intercept all ICMP echo packets. */
|
||||||
|
#if UIP_PINGADDRCONF
|
||||||
|
if((uip_hostaddr[0] | uip_hostaddr[1]) == 0 &&
|
||||||
|
BUF->proto == UIP_PROTO_ICMP &&
|
||||||
|
ICMPBUF->type == ICMP_ECHO) {
|
||||||
|
return UIP_FW_LOCAL;
|
||||||
|
}
|
||||||
|
#endif /* UIP_PINGADDRCONF */
|
||||||
|
|
||||||
|
/* Check if the packet is in the forwarding cache already, and if so
|
||||||
|
we drop it. */
|
||||||
|
|
||||||
|
for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) {
|
||||||
|
if(fw->timer != 0 &&
|
||||||
|
#if UIP_REASSEMBLY > 0
|
||||||
|
fw->len == BUF->len &&
|
||||||
|
fw->offset == BUF->ipoffset &&
|
||||||
|
#endif
|
||||||
|
fw->ipid == BUF->ipid &&
|
||||||
|
fw->srcipaddr[0] == BUF->srcipaddr[0] &&
|
||||||
|
fw->srcipaddr[1] == BUF->srcipaddr[1] &&
|
||||||
|
fw->destipaddr[0] == BUF->destipaddr[0] &&
|
||||||
|
fw->destipaddr[1] == BUF->destipaddr[1] &&
|
||||||
|
#if notdef
|
||||||
|
fw->payload[0] == BUF->srcport &&
|
||||||
|
fw->payload[1] == BUF->destport &&
|
||||||
|
#endif
|
||||||
|
fw->proto == BUF->proto) {
|
||||||
|
/* Drop packet. */
|
||||||
|
return UIP_FW_FORWARDED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the TTL reaches zero we produce an ICMP time exceeded message
|
||||||
|
in the uip_buf buffer and forward that packet back to the sender
|
||||||
|
of the packet. */
|
||||||
|
if(BUF->ttl <= 1) {
|
||||||
|
/* No time exceeded for broadcasts and multicasts! */
|
||||||
|
if(BUF->destipaddr[0] == 0xffff && BUF->destipaddr[1] == 0xffff) {
|
||||||
|
return UIP_FW_LOCAL;
|
||||||
|
}
|
||||||
|
time_exceeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decrement the TTL (time-to-live) value in the IP header */
|
||||||
|
BUF->ttl = BUF->ttl - 1;
|
||||||
|
|
||||||
|
/* Update the IP checksum. */
|
||||||
|
if(BUF->ipchksum >= HTONS(0xffff - 0x0100)) {
|
||||||
|
BUF->ipchksum = BUF->ipchksum + HTONS(0x0100) + 1;
|
||||||
|
} else {
|
||||||
|
BUF->ipchksum = BUF->ipchksum + HTONS(0x0100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uip_len > 0) {
|
||||||
|
uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN];
|
||||||
|
uip_fw_output();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UIP_BROADCAST
|
||||||
|
if(BUF->destipaddr[0] == 0xffff && BUF->destipaddr[1] == 0xffff) {
|
||||||
|
return UIP_FW_LOCAL;
|
||||||
|
}
|
||||||
|
#endif /* UIP_BROADCAST */
|
||||||
|
|
||||||
|
/* Return non-zero to indicate that the packet was forwarded and that no
|
||||||
|
other processing should be made. */
|
||||||
|
return UIP_FW_FORWARDED;
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Register a network interface with the forwarding module.
|
||||||
|
*
|
||||||
|
* \param netif A pointer to the network interface that is to be
|
||||||
|
* registered.
|
||||||
|
*/
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_fw_register(struct uip_fw_netif *netif)
|
||||||
|
{
|
||||||
|
netif->next = netifs;
|
||||||
|
netifs = netif;
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Register a default network interface.
|
||||||
|
*
|
||||||
|
* All packets that don't go out on any of the other interfaces will
|
||||||
|
* be routed to the default interface.
|
||||||
|
*
|
||||||
|
* \param netif A pointer to the network interface that is to be
|
||||||
|
* registered.
|
||||||
|
*/
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_fw_default(struct uip_fw_netif *netif)
|
||||||
|
{
|
||||||
|
defaultnetif = netif;
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Perform periodic processing.
|
||||||
|
*/
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_fw_periodic(void)
|
||||||
|
{
|
||||||
|
struct fwcache_entry *fw;
|
||||||
|
for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) {
|
||||||
|
if(fw->timer > 0) {
|
||||||
|
--fw->timer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------------------------------*/
|
@ -0,0 +1,176 @@
|
|||||||
|
/**
|
||||||
|
* \addtogroup uipfw
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* uIP packet forwarding header file.
|
||||||
|
* \author Adam Dunkels <adam@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2004, Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* $Id: uip-fw.h,v 1.2 2006/06/12 08:00:30 adam Exp $
|
||||||
|
*/
|
||||||
|
#ifndef __UIP_FW_H__
|
||||||
|
#define __UIP_FW_H__
|
||||||
|
|
||||||
|
#include "uip.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of a uIP network interface.
|
||||||
|
*/
|
||||||
|
struct uip_fw_netif {
|
||||||
|
struct uip_fw_netif *next; /**< Pointer to the next interface when
|
||||||
|
linked in a list. */
|
||||||
|
u16_t ipaddr[2]; /**< The IP address of this interface. */
|
||||||
|
u16_t netmask[2]; /**< The netmask of the interface. */
|
||||||
|
u8_t (* output)(void);
|
||||||
|
/**< A pointer to the function that
|
||||||
|
sends a packet. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intantiating macro for a uIP network interface.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
\code
|
||||||
|
struct uip_fw_netif slipnetif =
|
||||||
|
{UIP_FW_NETIF(192,168,76,1, 255,255,255,0, slip_output)};
|
||||||
|
\endcode
|
||||||
|
* \param ip1,ip2,ip3,ip4 The IP address of the network interface.
|
||||||
|
*
|
||||||
|
* \param nm1,nm2,nm3,nm4 The netmask of the network interface.
|
||||||
|
*
|
||||||
|
* \param outputfunc A pointer to the output function of the network interface.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_FW_NETIF(ip1,ip2,ip3,ip4, nm1,nm2,nm3,nm4, outputfunc) \
|
||||||
|
NULL, \
|
||||||
|
{HTONS((ip1 << 8) | ip2), HTONS((ip3 << 8) | ip4)}, \
|
||||||
|
{HTONS((nm1 << 8) | nm2), HTONS((nm3 << 8) | nm4)}, \
|
||||||
|
outputfunc
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the IP address of a network interface.
|
||||||
|
*
|
||||||
|
* \param netif A pointer to the uip_fw_netif structure for the network interface.
|
||||||
|
*
|
||||||
|
* \param addr A pointer to an IP address.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_fw_setipaddr(netif, addr) \
|
||||||
|
do { (netif)->ipaddr[0] = ((u16_t *)(addr))[0]; \
|
||||||
|
(netif)->ipaddr[1] = ((u16_t *)(addr))[1]; } while(0)
|
||||||
|
/**
|
||||||
|
* Set the netmask of a network interface.
|
||||||
|
*
|
||||||
|
* \param netif A pointer to the uip_fw_netif structure for the network interface.
|
||||||
|
*
|
||||||
|
* \param addr A pointer to an IP address representing the netmask.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_fw_setnetmask(netif, addr) \
|
||||||
|
do { (netif)->netmask[0] = ((u16_t *)(addr))[0]; \
|
||||||
|
(netif)->netmask[1] = ((u16_t *)(addr))[1]; } while(0)
|
||||||
|
|
||||||
|
void uip_fw_init(void);
|
||||||
|
u8_t uip_fw_forward(void);
|
||||||
|
u8_t uip_fw_output(void);
|
||||||
|
void uip_fw_register(struct uip_fw_netif *netif);
|
||||||
|
void uip_fw_default(struct uip_fw_netif *netif);
|
||||||
|
void uip_fw_periodic(void);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A non-error message that indicates that a packet should be
|
||||||
|
* processed locally.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_FW_LOCAL 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A non-error message that indicates that something went OK.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_FW_OK 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A non-error message that indicates that a packet was forwarded.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_FW_FORWARDED 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A non-error message that indicates that a zero-length packet
|
||||||
|
* transmission was attempted, and that no packet was sent.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_FW_ZEROLEN 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An error message that indicates that a packet that was too large
|
||||||
|
* for the outbound network interface was detected.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_FW_TOOLARGE 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An error message that indicates that no suitable interface could be
|
||||||
|
* found for an outbound packet.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_FW_NOROUTE 4
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An error message that indicates that a packet that should be
|
||||||
|
* forwarded or output was dropped.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_FW_DROPPED 5
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __UIP_FW_H__ */
|
||||||
|
|
||||||
|
/** @} */
|
@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006, 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 uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* $Id: uip-neighbor.c,v 1.2 2006/06/12 08:00:30 adam Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Database of link-local neighbors, used by IPv6 code and
|
||||||
|
* to be used by a future ARP code rewrite.
|
||||||
|
* \author
|
||||||
|
* Adam Dunkels <adam@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "uip-neighbor.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MAX_TIME 128
|
||||||
|
|
||||||
|
#ifdef UIP_NEIGHBOR_CONF_ENTRIES
|
||||||
|
#define ENTRIES UIP_NEIGHBOR_CONF_ENTRIES
|
||||||
|
#else /* UIP_NEIGHBOR_CONF_ENTRIES */
|
||||||
|
#define ENTRIES 8
|
||||||
|
#endif /* UIP_NEIGHBOR_CONF_ENTRIES */
|
||||||
|
|
||||||
|
struct neighbor_entry {
|
||||||
|
uip_ipaddr_t ipaddr;
|
||||||
|
struct uip_neighbor_addr addr;
|
||||||
|
u8_t time;
|
||||||
|
};
|
||||||
|
static struct neighbor_entry entries[ENTRIES];
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_neighbor_init(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < ENTRIES; ++i) {
|
||||||
|
entries[i].time = MAX_TIME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_neighbor_periodic(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < ENTRIES; ++i) {
|
||||||
|
if(entries[i].time < MAX_TIME) {
|
||||||
|
entries[i].time++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_neighbor_add(uip_ipaddr_t ipaddr, struct uip_neighbor_addr *addr)
|
||||||
|
{
|
||||||
|
int i, oldest;
|
||||||
|
u8_t oldest_time;
|
||||||
|
|
||||||
|
printf("Adding neighbor with link address %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||||
|
addr->addr.addr[0], addr->addr.addr[1], addr->addr.addr[2], addr->addr.addr[3],
|
||||||
|
addr->addr.addr[4], addr->addr.addr[5]);
|
||||||
|
|
||||||
|
/* Find the first unused entry or the oldest used entry. */
|
||||||
|
oldest_time = 0;
|
||||||
|
oldest = 0;
|
||||||
|
for(i = 0; i < ENTRIES; ++i) {
|
||||||
|
if(entries[i].time == MAX_TIME) {
|
||||||
|
oldest = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(uip_ipaddr_cmp(entries[i].ipaddr, addr)) {
|
||||||
|
oldest = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(entries[i].time > oldest_time) {
|
||||||
|
oldest = i;
|
||||||
|
oldest_time = entries[i].time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use the oldest or first free entry (either pointed to by the
|
||||||
|
"oldest" variable). */
|
||||||
|
entries[oldest].time = 0;
|
||||||
|
uip_ipaddr_copy(entries[oldest].ipaddr, ipaddr);
|
||||||
|
memcpy(&entries[oldest].addr, addr, sizeof(struct uip_neighbor_addr));
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static struct neighbor_entry *
|
||||||
|
find_entry(uip_ipaddr_t ipaddr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < ENTRIES; ++i) {
|
||||||
|
if(uip_ipaddr_cmp(entries[i].ipaddr, ipaddr)) {
|
||||||
|
return &entries[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_neighbor_update(uip_ipaddr_t ipaddr)
|
||||||
|
{
|
||||||
|
struct neighbor_entry *e;
|
||||||
|
|
||||||
|
e = find_entry(ipaddr);
|
||||||
|
if(e != NULL) {
|
||||||
|
e->time = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
struct uip_neighbor_addr *
|
||||||
|
uip_neighbor_lookup(uip_ipaddr_t ipaddr)
|
||||||
|
{
|
||||||
|
struct neighbor_entry *e;
|
||||||
|
|
||||||
|
e = find_entry(ipaddr);
|
||||||
|
if(e != NULL) {
|
||||||
|
/* printf("Lookup neighbor with link address %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||||
|
e->addr.addr.addr[0], e->addr.addr.addr[1], e->addr.addr.addr[2], e->addr.addr.addr[3],
|
||||||
|
e->addr.addr.addr[4], e->addr.addr.addr[5]);*/
|
||||||
|
|
||||||
|
return &e->addr;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006, 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 uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* $Id: uip-neighbor.h,v 1.2 2006/06/12 08:00:30 adam Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Header file for database of link-local neighbors, used by
|
||||||
|
* IPv6 code and to be used by future ARP code.
|
||||||
|
* \author
|
||||||
|
* Adam Dunkels <adam@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UIP_NEIGHBOR_H__
|
||||||
|
#define __UIP_NEIGHBOR_H__
|
||||||
|
|
||||||
|
#include "uip.h"
|
||||||
|
|
||||||
|
struct uip_neighbor_addr {
|
||||||
|
#if UIP_NEIGHBOR_CONF_ADDRTYPE
|
||||||
|
UIP_NEIGHBOR_CONF_ADDRTYPE addr;
|
||||||
|
#else
|
||||||
|
struct uip_eth_addr addr;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
void uip_neighbor_init(void);
|
||||||
|
void uip_neighbor_add(uip_ipaddr_t ipaddr, struct uip_neighbor_addr *addr);
|
||||||
|
void uip_neighbor_update(uip_ipaddr_t ipaddr);
|
||||||
|
struct uip_neighbor_addr *uip_neighbor_lookup(uip_ipaddr_t ipaddr);
|
||||||
|
void uip_neighbor_periodic(void);
|
||||||
|
|
||||||
|
#endif /* __UIP-NEIGHBOR_H__ */
|
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004, Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* $Id: uip-split.c,v 1.2 2006/06/12 08:00:30 adam Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "uip-split.h"
|
||||||
|
#include "uip.h"
|
||||||
|
#include "uip-fw.h"
|
||||||
|
#include "uip_arch.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_split_output(void)
|
||||||
|
{
|
||||||
|
u16_t tcplen, len1, len2;
|
||||||
|
|
||||||
|
/* We only try to split maximum sized TCP segments. */
|
||||||
|
if(BUF->proto == UIP_PROTO_TCP &&
|
||||||
|
uip_len == UIP_BUFSIZE - UIP_LLH_LEN) {
|
||||||
|
|
||||||
|
tcplen = uip_len - UIP_TCPIP_HLEN;
|
||||||
|
/* Split the segment in two. If the original packet length was
|
||||||
|
odd, we make the second packet one byte larger. */
|
||||||
|
len1 = len2 = tcplen / 2;
|
||||||
|
if(len1 + len2 < tcplen) {
|
||||||
|
++len2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the first packet. This is done by altering the length
|
||||||
|
field of the IP header and updating the checksums. */
|
||||||
|
uip_len = len1 + UIP_TCPIP_HLEN;
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
/* For IPv6, the IP length field does not include the IPv6 IP header
|
||||||
|
length. */
|
||||||
|
BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
|
||||||
|
BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
BUF->len[0] = uip_len >> 8;
|
||||||
|
BUF->len[1] = uip_len & 0xff;
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
/* Recalculate the TCP checksum. */
|
||||||
|
BUF->tcpchksum = 0;
|
||||||
|
BUF->tcpchksum = ~(uip_tcpchksum());
|
||||||
|
|
||||||
|
#if !UIP_CONF_IPV6
|
||||||
|
/* Recalculate the IP checksum. */
|
||||||
|
BUF->ipchksum = 0;
|
||||||
|
BUF->ipchksum = ~(uip_ipchksum());
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
/* Transmit the first packet. */
|
||||||
|
/* uip_fw_output();*/
|
||||||
|
tcpip_output();
|
||||||
|
|
||||||
|
/* Now, create the second packet. To do this, it is not enough to
|
||||||
|
just alter the length field, but we must also update the TCP
|
||||||
|
sequence number and point the uip_appdata to a new place in
|
||||||
|
memory. This place is detemined by the length of the first
|
||||||
|
packet (len1). */
|
||||||
|
uip_len = len2 + UIP_TCPIP_HLEN;
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
/* For IPv6, the IP length field does not include the IPv6 IP header
|
||||||
|
length. */
|
||||||
|
BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
|
||||||
|
BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
BUF->len[0] = uip_len >> 8;
|
||||||
|
BUF->len[1] = uip_len & 0xff;
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
/* uip_appdata += len1;*/
|
||||||
|
memcpy(uip_appdata, (u8_t *)uip_appdata + len1, len2);
|
||||||
|
|
||||||
|
uip_add32(BUF->seqno, len1);
|
||||||
|
BUF->seqno[0] = uip_acc32[0];
|
||||||
|
BUF->seqno[1] = uip_acc32[1];
|
||||||
|
BUF->seqno[2] = uip_acc32[2];
|
||||||
|
BUF->seqno[3] = uip_acc32[3];
|
||||||
|
|
||||||
|
/* Recalculate the TCP checksum. */
|
||||||
|
BUF->tcpchksum = 0;
|
||||||
|
BUF->tcpchksum = ~(uip_tcpchksum());
|
||||||
|
|
||||||
|
#if !UIP_CONF_IPV6
|
||||||
|
/* Recalculate the IP checksum. */
|
||||||
|
BUF->ipchksum = 0;
|
||||||
|
BUF->ipchksum = ~(uip_ipchksum());
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
/* Transmit the second packet. */
|
||||||
|
/* uip_fw_output();*/
|
||||||
|
tcpip_output();
|
||||||
|
} else {
|
||||||
|
/* uip_fw_output();*/
|
||||||
|
tcpip_output();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004, Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
* $Id: uip-split.h,v 1.2 2006/06/12 08:00:30 adam Exp $
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \addtogroup uip
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup uipsplit uIP TCP throughput booster hack
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* The basic uIP TCP implementation only allows each TCP connection to
|
||||||
|
* have a single TCP segment in flight at any given time. Because of
|
||||||
|
* the delayed ACK algorithm employed by most TCP receivers, uIP's
|
||||||
|
* limit on the amount of in-flight TCP segments seriously reduces the
|
||||||
|
* maximum achievable throughput for sending data from uIP.
|
||||||
|
*
|
||||||
|
* The uip-split module is a hack which tries to remedy this
|
||||||
|
* situation. By splitting maximum sized outgoing TCP segments into
|
||||||
|
* two, the delayed ACK algorithm is not invoked at TCP
|
||||||
|
* receivers. This improves the throughput when sending data from uIP
|
||||||
|
* by orders of magnitude.
|
||||||
|
*
|
||||||
|
* The uip-split module uses the uip-fw module (uIP IP packet
|
||||||
|
* forwarding) for sending packets. Therefore, the uip-fw module must
|
||||||
|
* be set up with the appropriate network interfaces for this module
|
||||||
|
* to work.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Module for splitting outbound TCP segments in two to avoid the
|
||||||
|
* delayed ACK throughput degradation.
|
||||||
|
* \author
|
||||||
|
* Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UIP_SPLIT_H__
|
||||||
|
#define __UIP_SPLIT_H__
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle outgoing packets.
|
||||||
|
*
|
||||||
|
* This function inspects an outgoing packet in the uip_buf buffer and
|
||||||
|
* sends it out using the uip_fw_output() function. If the packet is a
|
||||||
|
* full-sized TCP segment it will be split into two segments and
|
||||||
|
* transmitted separately. This function should be called instead of
|
||||||
|
* the actual device driver output function, or the uip_fw_output()
|
||||||
|
* function.
|
||||||
|
*
|
||||||
|
* The headers of the outgoing packet is assumed to be in the uip_buf
|
||||||
|
* buffer and the payload is assumed to be wherever uip_appdata
|
||||||
|
* points. The length of the outgoing packet is assumed to be in the
|
||||||
|
* uip_len variable.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void uip_split_output(void);
|
||||||
|
|
||||||
|
#endif /* __UIP_SPLIT_H__ */
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
/** @} */
|
@ -0,0 +1,1897 @@
|
|||||||
|
#define DEBUG_PRINTF(...) /*printf(__VA_ARGS__)*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup uip The uIP TCP/IP stack
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* uIP is an implementation of the TCP/IP protocol stack intended for
|
||||||
|
* small 8-bit and 16-bit microcontrollers.
|
||||||
|
*
|
||||||
|
* uIP provides the necessary protocols for Internet communication,
|
||||||
|
* with a very small code footprint and RAM requirements - the uIP
|
||||||
|
* code size is on the order of a few kilobytes and RAM usage is on
|
||||||
|
* the order of a few hundred bytes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* The uIP TCP/IP stack code.
|
||||||
|
* \author Adam Dunkels <adam@dunkels.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2003, Adam Dunkels.
|
||||||
|
* 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 uIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* $Id: uip.c,v 1.65 2006/06/11 21:46:39 adam Exp $
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* uIP is a small implementation of the IP, UDP and TCP protocols (as
|
||||||
|
* well as some basic ICMP stuff). The implementation couples the IP,
|
||||||
|
* UDP, TCP and the application layers very tightly. To keep the size
|
||||||
|
* of the compiled code down, this code frequently uses the goto
|
||||||
|
* statement. While it would be possible to break the uip_process()
|
||||||
|
* function into many smaller functions, this would increase the code
|
||||||
|
* size because of the overhead of parameter passing and the fact that
|
||||||
|
* the optimier would not be as efficient.
|
||||||
|
*
|
||||||
|
* The principle is that we have a small buffer, called the uip_buf,
|
||||||
|
* in which the device driver puts an incoming packet. The TCP/IP
|
||||||
|
* stack parses the headers in the packet, and calls the
|
||||||
|
* application. If the remote host has sent data to the application,
|
||||||
|
* this data is present in the uip_buf and the application read the
|
||||||
|
* data from there. It is up to the application to put this data into
|
||||||
|
* a byte stream if needed. The application will not be fed with data
|
||||||
|
* that is out of sequence.
|
||||||
|
*
|
||||||
|
* If the application whishes to send data to the peer, it should put
|
||||||
|
* its data into the uip_buf. The uip_appdata pointer points to the
|
||||||
|
* first available byte. The TCP/IP stack will calculate the
|
||||||
|
* checksums, and fill in the necessary header fields and finally send
|
||||||
|
* the packet back to the peer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "uip.h"
|
||||||
|
#include "uipopt.h"
|
||||||
|
#include "uip_arch.h"
|
||||||
|
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
#include "uip-neighbor.h"
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Variable definitions. */
|
||||||
|
|
||||||
|
|
||||||
|
/* The IP address of this host. If it is defined to be fixed (by
|
||||||
|
setting UIP_FIXEDADDR to 1 in uipopt.h), the address is set
|
||||||
|
here. Otherwise, the address */
|
||||||
|
#if UIP_FIXEDADDR > 0
|
||||||
|
const uip_ipaddr_t uip_hostaddr =
|
||||||
|
{HTONS((UIP_IPADDR0 << 8) | UIP_IPADDR1),
|
||||||
|
HTONS((UIP_IPADDR2 << 8) | UIP_IPADDR3)};
|
||||||
|
const uip_ipaddr_t uip_draddr =
|
||||||
|
{HTONS((UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1),
|
||||||
|
HTONS((UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3)};
|
||||||
|
const uip_ipaddr_t uip_netmask =
|
||||||
|
{HTONS((UIP_NETMASK0 << 8) | UIP_NETMASK1),
|
||||||
|
HTONS((UIP_NETMASK2 << 8) | UIP_NETMASK3)};
|
||||||
|
#else
|
||||||
|
uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;
|
||||||
|
#endif /* UIP_FIXEDADDR */
|
||||||
|
|
||||||
|
static const uip_ipaddr_t all_ones_addr =
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
{0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff};
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
{0xffff,0xffff};
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
static const uip_ipaddr_t all_zeroes_addr =
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000};
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
{0x0000,0x0000};
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
|
||||||
|
#if UIP_FIXEDETHADDR
|
||||||
|
const struct uip_eth_addr uip_ethaddr = {{UIP_ETHADDR0,
|
||||||
|
UIP_ETHADDR1,
|
||||||
|
UIP_ETHADDR2,
|
||||||
|
UIP_ETHADDR3,
|
||||||
|
UIP_ETHADDR4,
|
||||||
|
UIP_ETHADDR5}};
|
||||||
|
#else
|
||||||
|
struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef UIP_CONF_EXTERNAL_BUFFER
|
||||||
|
u8_t uip_buf[UIP_BUFSIZE + 2]; /* The packet buffer that contains
|
||||||
|
incoming packets. */
|
||||||
|
#endif /* UIP_CONF_EXTERNAL_BUFFER */
|
||||||
|
|
||||||
|
void *uip_appdata; /* The uip_appdata pointer points to
|
||||||
|
application data. */
|
||||||
|
void *uip_sappdata; /* The uip_appdata pointer points to
|
||||||
|
the application data which is to
|
||||||
|
be sent. */
|
||||||
|
#if UIP_URGDATA > 0
|
||||||
|
void *uip_urgdata; /* The uip_urgdata pointer points to
|
||||||
|
urgent data (out-of-band data), if
|
||||||
|
present. */
|
||||||
|
u16_t uip_urglen, uip_surglen;
|
||||||
|
#endif /* UIP_URGDATA > 0 */
|
||||||
|
|
||||||
|
u16_t uip_len, uip_slen;
|
||||||
|
/* The uip_len is either 8 or 16 bits,
|
||||||
|
depending on the maximum packet
|
||||||
|
size. */
|
||||||
|
|
||||||
|
u8_t uip_flags; /* The uip_flags variable is used for
|
||||||
|
communication between the TCP/IP stack
|
||||||
|
and the application program. */
|
||||||
|
struct uip_conn *uip_conn; /* uip_conn always points to the current
|
||||||
|
connection. */
|
||||||
|
|
||||||
|
struct uip_conn uip_conns[UIP_CONNS];
|
||||||
|
/* The uip_conns array holds all TCP
|
||||||
|
connections. */
|
||||||
|
u16_t uip_listenports[UIP_LISTENPORTS];
|
||||||
|
/* The uip_listenports list all currently
|
||||||
|
listning ports. */
|
||||||
|
#if UIP_UDP
|
||||||
|
struct uip_udp_conn *uip_udp_conn;
|
||||||
|
struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
|
||||||
|
#endif /* UIP_UDP */
|
||||||
|
|
||||||
|
static u16_t ipid; /* Ths ipid variable is an increasing
|
||||||
|
number that is used for the IP ID
|
||||||
|
field. */
|
||||||
|
|
||||||
|
void uip_setipid(u16_t id) { ipid = id; }
|
||||||
|
|
||||||
|
static u8_t iss[4]; /* The iss variable is used for the TCP
|
||||||
|
initial sequence number. */
|
||||||
|
|
||||||
|
#if UIP_ACTIVE_OPEN
|
||||||
|
static u16_t lastport; /* Keeps track of the last port used for
|
||||||
|
a new connection. */
|
||||||
|
#endif /* UIP_ACTIVE_OPEN */
|
||||||
|
|
||||||
|
/* Temporary variables. */
|
||||||
|
u8_t uip_acc32[4];
|
||||||
|
static u8_t c, opt;
|
||||||
|
static u16_t tmp16;
|
||||||
|
|
||||||
|
/* Structures and definitions. */
|
||||||
|
#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_CTL 0x3f
|
||||||
|
|
||||||
|
#define TCP_OPT_END 0 /* End of TCP options list */
|
||||||
|
#define TCP_OPT_NOOP 1 /* "No-operation" TCP option */
|
||||||
|
#define TCP_OPT_MSS 2 /* Maximum segment size TCP option */
|
||||||
|
|
||||||
|
#define TCP_OPT_MSS_LEN 4 /* Length of TCP MSS option. */
|
||||||
|
|
||||||
|
#define ICMP_ECHO_REPLY 0
|
||||||
|
#define ICMP_ECHO 8
|
||||||
|
|
||||||
|
#define ICMP6_ECHO_REPLY 129
|
||||||
|
#define ICMP6_ECHO 128
|
||||||
|
#define ICMP6_NEIGHBOR_SOLICITATION 135
|
||||||
|
#define ICMP6_NEIGHBOR_ADVERTISEMENT 136
|
||||||
|
|
||||||
|
#define ICMP6_FLAG_S (1 << 6)
|
||||||
|
|
||||||
|
#define ICMP6_OPTION_SOURCE_LINK_ADDRESS 1
|
||||||
|
#define ICMP6_OPTION_TARGET_LINK_ADDRESS 2
|
||||||
|
|
||||||
|
|
||||||
|
/* Macros. */
|
||||||
|
#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
|
||||||
|
#define FBUF ((struct uip_tcpip_hdr *)&uip_reassbuf[0])
|
||||||
|
#define ICMPBUF ((struct uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
|
||||||
|
#define UDPBUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
|
||||||
|
|
||||||
|
|
||||||
|
#if UIP_STATISTICS == 1
|
||||||
|
struct uip_stats uip_stat;
|
||||||
|
#define UIP_STAT(s) s
|
||||||
|
#else
|
||||||
|
#define UIP_STAT(s)
|
||||||
|
#endif /* UIP_STATISTICS == 1 */
|
||||||
|
|
||||||
|
#if UIP_LOGGING == 1
|
||||||
|
#include <stdio.h>
|
||||||
|
void uip_log(char *msg);
|
||||||
|
#define UIP_LOG(m) uip_log(m)
|
||||||
|
#else
|
||||||
|
#define UIP_LOG(m)
|
||||||
|
#endif /* UIP_LOGGING == 1 */
|
||||||
|
|
||||||
|
#if ! UIP_ARCH_ADD32
|
||||||
|
void
|
||||||
|
uip_add32(u8_t *op32, u16_t op16)
|
||||||
|
{
|
||||||
|
uip_acc32[3] = op32[3] + (op16 & 0xff);
|
||||||
|
uip_acc32[2] = op32[2] + (op16 >> 8);
|
||||||
|
uip_acc32[1] = op32[1];
|
||||||
|
uip_acc32[0] = op32[0];
|
||||||
|
|
||||||
|
if(uip_acc32[2] < (op16 >> 8)) {
|
||||||
|
++uip_acc32[1];
|
||||||
|
if(uip_acc32[1] == 0) {
|
||||||
|
++uip_acc32[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(uip_acc32[3] < (op16 & 0xff)) {
|
||||||
|
++uip_acc32[2];
|
||||||
|
if(uip_acc32[2] == 0) {
|
||||||
|
++uip_acc32[1];
|
||||||
|
if(uip_acc32[1] == 0) {
|
||||||
|
++uip_acc32[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* UIP_ARCH_ADD32 */
|
||||||
|
|
||||||
|
#if ! UIP_ARCH_CHKSUM
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static u16_t
|
||||||
|
chksum(u16_t sum, const u8_t *data, u16_t len)
|
||||||
|
{
|
||||||
|
u16_t t;
|
||||||
|
const u8_t *dataptr;
|
||||||
|
const u8_t *last_byte;
|
||||||
|
|
||||||
|
dataptr = data;
|
||||||
|
last_byte = data + len - 1;
|
||||||
|
|
||||||
|
while(dataptr < last_byte) { /* At least two more bytes */
|
||||||
|
t = (dataptr[0] << 8) + dataptr[1];
|
||||||
|
sum += t;
|
||||||
|
if(sum < t) {
|
||||||
|
sum++; /* carry */
|
||||||
|
}
|
||||||
|
dataptr += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dataptr == last_byte) {
|
||||||
|
t = (dataptr[0] << 8) + 0;
|
||||||
|
sum += t;
|
||||||
|
if(sum < t) {
|
||||||
|
sum++; /* carry */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return sum in host byte order. */
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
u16_t
|
||||||
|
uip_chksum(u16_t *data, u16_t len)
|
||||||
|
{
|
||||||
|
return htons(chksum(0, (u8_t *)data, len));
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
#ifndef UIP_ARCH_IPCHKSUM
|
||||||
|
u16_t
|
||||||
|
uip_ipchksum(void)
|
||||||
|
{
|
||||||
|
u16_t sum;
|
||||||
|
|
||||||
|
sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN);
|
||||||
|
DEBUG_PRINTF("uip_ipchksum: sum 0x%04x\n", sum);
|
||||||
|
return (sum == 0) ? 0xffff : htons(sum);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static u16_t
|
||||||
|
upper_layer_chksum(u8_t proto)
|
||||||
|
{
|
||||||
|
u16_t upper_layer_len;
|
||||||
|
u16_t sum;
|
||||||
|
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]);
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN;
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
/* First sum pseudoheader. */
|
||||||
|
|
||||||
|
/* IP protocol and length fields. This addition cannot carry. */
|
||||||
|
sum = upper_layer_len + proto;
|
||||||
|
/* Sum IP source and destination addresses. */
|
||||||
|
sum = chksum(sum, (u8_t *)&BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t));
|
||||||
|
|
||||||
|
/* Sum TCP header and data. */
|
||||||
|
sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN],
|
||||||
|
upper_layer_len);
|
||||||
|
|
||||||
|
return (sum == 0) ? 0xffff : htons(sum);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
u16_t
|
||||||
|
uip_icmp6chksum(void)
|
||||||
|
{
|
||||||
|
return upper_layer_chksum(UIP_PROTO_ICMP6);
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
u16_t
|
||||||
|
uip_tcpchksum(void)
|
||||||
|
{
|
||||||
|
return upper_layer_chksum(UIP_PROTO_TCP);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
#if UIP_UDP_CHECKSUMS
|
||||||
|
u16_t
|
||||||
|
uip_udpchksum(void)
|
||||||
|
{
|
||||||
|
return upper_layer_chksum(UIP_PROTO_UDP);
|
||||||
|
}
|
||||||
|
#endif /* UIP_UDP_CHECKSUMS */
|
||||||
|
#endif /* UIP_ARCH_CHKSUM */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_init(void)
|
||||||
|
{
|
||||||
|
for(c = 0; c < UIP_LISTENPORTS; ++c) {
|
||||||
|
uip_listenports[c] = 0;
|
||||||
|
}
|
||||||
|
for(c = 0; c < UIP_CONNS; ++c) {
|
||||||
|
uip_conns[c].tcpstateflags = UIP_CLOSED;
|
||||||
|
}
|
||||||
|
#if UIP_ACTIVE_OPEN
|
||||||
|
lastport = 1024;
|
||||||
|
#endif /* UIP_ACTIVE_OPEN */
|
||||||
|
|
||||||
|
#if UIP_UDP
|
||||||
|
for(c = 0; c < UIP_UDP_CONNS; ++c) {
|
||||||
|
uip_udp_conns[c].lport = 0;
|
||||||
|
}
|
||||||
|
#endif /* UIP_UDP */
|
||||||
|
|
||||||
|
|
||||||
|
/* IPv4 initialization. */
|
||||||
|
#if UIP_FIXEDADDR == 0
|
||||||
|
/* uip_hostaddr[0] = uip_hostaddr[1] = 0;*/
|
||||||
|
#endif /* UIP_FIXEDADDR */
|
||||||
|
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
#if UIP_ACTIVE_OPEN
|
||||||
|
struct uip_conn *
|
||||||
|
uip_connect(uip_ipaddr_t *ripaddr, u16_t rport)
|
||||||
|
{
|
||||||
|
register struct uip_conn *conn, *cconn;
|
||||||
|
|
||||||
|
/* Find an unused local port. */
|
||||||
|
again:
|
||||||
|
++lastport;
|
||||||
|
|
||||||
|
if(lastport >= 32000) {
|
||||||
|
lastport = 4096;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if this port is already in use, and if so try to find
|
||||||
|
another one. */
|
||||||
|
for(c = 0; c < UIP_CONNS; ++c) {
|
||||||
|
conn = &uip_conns[c];
|
||||||
|
if(conn->tcpstateflags != UIP_CLOSED &&
|
||||||
|
conn->lport == htons(lastport)) {
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conn = 0;
|
||||||
|
for(c = 0; c < UIP_CONNS; ++c) {
|
||||||
|
cconn = &uip_conns[c];
|
||||||
|
if(cconn->tcpstateflags == UIP_CLOSED) {
|
||||||
|
conn = cconn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(cconn->tcpstateflags == UIP_TIME_WAIT) {
|
||||||
|
if(conn == 0 ||
|
||||||
|
cconn->timer > conn->timer) {
|
||||||
|
conn = cconn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(conn == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->tcpstateflags = UIP_SYN_SENT;
|
||||||
|
|
||||||
|
conn->snd_nxt[0] = iss[0];
|
||||||
|
conn->snd_nxt[1] = iss[1];
|
||||||
|
conn->snd_nxt[2] = iss[2];
|
||||||
|
conn->snd_nxt[3] = iss[3];
|
||||||
|
|
||||||
|
conn->initialmss = conn->mss = UIP_TCP_MSS;
|
||||||
|
|
||||||
|
conn->len = 1; /* TCP length of the SYN is one. */
|
||||||
|
conn->nrtx = 0;
|
||||||
|
conn->timer = 1; /* Send the SYN next time around. */
|
||||||
|
conn->rto = UIP_RTO;
|
||||||
|
conn->sa = 0;
|
||||||
|
conn->sv = 16; /* Initial value of the RTT variance. */
|
||||||
|
conn->lport = htons(lastport);
|
||||||
|
conn->rport = rport;
|
||||||
|
uip_ipaddr_copy(&conn->ripaddr, ripaddr);
|
||||||
|
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
#endif /* UIP_ACTIVE_OPEN */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
#if UIP_UDP
|
||||||
|
struct uip_udp_conn *
|
||||||
|
uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport)
|
||||||
|
{
|
||||||
|
register struct uip_udp_conn *conn;
|
||||||
|
|
||||||
|
/* Find an unused local port. */
|
||||||
|
again:
|
||||||
|
++lastport;
|
||||||
|
|
||||||
|
if(lastport >= 32000) {
|
||||||
|
lastport = 4096;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(c = 0; c < UIP_UDP_CONNS; ++c) {
|
||||||
|
if(uip_udp_conns[c].lport == htons(lastport)) {
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
conn = 0;
|
||||||
|
for(c = 0; c < UIP_UDP_CONNS; ++c) {
|
||||||
|
if(uip_udp_conns[c].lport == 0) {
|
||||||
|
conn = &uip_udp_conns[c];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(conn == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->lport = HTONS(lastport);
|
||||||
|
conn->rport = rport;
|
||||||
|
if(ripaddr == NULL) {
|
||||||
|
memset(conn->ripaddr, 0, sizeof(uip_ipaddr_t));
|
||||||
|
} else {
|
||||||
|
uip_ipaddr_copy(&conn->ripaddr, ripaddr);
|
||||||
|
}
|
||||||
|
conn->ttl = UIP_TTL;
|
||||||
|
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
#endif /* UIP_UDP */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_unlisten(u16_t port)
|
||||||
|
{
|
||||||
|
for(c = 0; c < UIP_LISTENPORTS; ++c) {
|
||||||
|
if(uip_listenports[c] == port) {
|
||||||
|
uip_listenports[c] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_listen(u16_t port)
|
||||||
|
{
|
||||||
|
for(c = 0; c < UIP_LISTENPORTS; ++c) {
|
||||||
|
if(uip_listenports[c] == 0) {
|
||||||
|
uip_listenports[c] = port;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* XXX: IP fragment reassembly: not well-tested. */
|
||||||
|
|
||||||
|
#if UIP_REASSEMBLY && !UIP_CONF_IPV6
|
||||||
|
#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
|
||||||
|
static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
|
||||||
|
static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
|
||||||
|
static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,
|
||||||
|
0x0f, 0x07, 0x03, 0x01};
|
||||||
|
static u16_t uip_reasslen;
|
||||||
|
static u8_t uip_reassflags;
|
||||||
|
#define UIP_REASS_FLAG_LASTFRAG 0x01
|
||||||
|
static u8_t uip_reasstmr;
|
||||||
|
|
||||||
|
#define IP_MF 0x20
|
||||||
|
|
||||||
|
static u8_t
|
||||||
|
uip_reass(void)
|
||||||
|
{
|
||||||
|
u16_t offset, len;
|
||||||
|
u16_t i;
|
||||||
|
|
||||||
|
/* 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(uip_reasstmr == 0) {
|
||||||
|
memcpy(uip_reassbuf, &BUF->vhl, UIP_IPH_LEN);
|
||||||
|
uip_reasstmr = UIP_REASS_MAXAGE;
|
||||||
|
uip_reassflags = 0;
|
||||||
|
/* Clear the bitmap. */
|
||||||
|
memset(uip_reassbitmap, 0, sizeof(uip_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(BUF->srcipaddr[0] == FBUF->srcipaddr[0] &&
|
||||||
|
BUF->srcipaddr[1] == FBUF->srcipaddr[1] &&
|
||||||
|
BUF->destipaddr[0] == FBUF->destipaddr[0] &&
|
||||||
|
BUF->destipaddr[1] == FBUF->destipaddr[1] &&
|
||||||
|
BUF->ipid[0] == FBUF->ipid[0] &&
|
||||||
|
BUF->ipid[1] == FBUF->ipid[1]) {
|
||||||
|
|
||||||
|
len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4;
|
||||||
|
offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8;
|
||||||
|
|
||||||
|
/* If the offset or the offset + fragment length overflows the
|
||||||
|
reassembly buffer, we discard the entire packet. */
|
||||||
|
if(offset > UIP_REASS_BUFSIZE ||
|
||||||
|
offset + len > UIP_REASS_BUFSIZE) {
|
||||||
|
uip_reasstmr = 0;
|
||||||
|
goto nullreturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the fragment into the reassembly buffer, at the right
|
||||||
|
offset. */
|
||||||
|
memcpy(&uip_reassbuf[UIP_IPH_LEN + offset],
|
||||||
|
(char *)BUF + (int)((BUF->vhl & 0x0f) * 4),
|
||||||
|
len);
|
||||||
|
|
||||||
|
/* Update the bitmap. */
|
||||||
|
if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
|
||||||
|
/* If the two endpoints are in the same byte, we only update
|
||||||
|
that byte. */
|
||||||
|
|
||||||
|
uip_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. */
|
||||||
|
uip_reassbitmap[offset / (8 * 8)] |=
|
||||||
|
bitmap_bits[(offset / 8 ) & 7];
|
||||||
|
for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
|
||||||
|
uip_reassbitmap[i] = 0xff;
|
||||||
|
}
|
||||||
|
uip_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((BUF->ipoffset[0] & IP_MF) == 0) {
|
||||||
|
uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
|
||||||
|
uip_reasslen = offset + len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
|
||||||
|
/* Check all bytes up to and including all but the last byte in
|
||||||
|
the bitmap. */
|
||||||
|
for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
|
||||||
|
if(uip_reassbitmap[i] != 0xff) {
|
||||||
|
goto nullreturn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Check the last byte in the bitmap. It should contain just the
|
||||||
|
right amount of bits. */
|
||||||
|
if(uip_reassbitmap[uip_reasslen / (8 * 8)] !=
|
||||||
|
(u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) {
|
||||||
|
goto nullreturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
uip_reasstmr = 0;
|
||||||
|
memcpy(BUF, FBUF, uip_reasslen);
|
||||||
|
|
||||||
|
/* Pretend to be a "normal" (i.e., not fragmented) IP packet
|
||||||
|
from now on. */
|
||||||
|
BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
|
||||||
|
BUF->len[0] = uip_reasslen >> 8;
|
||||||
|
BUF->len[1] = uip_reasslen & 0xff;
|
||||||
|
BUF->ipchksum = 0;
|
||||||
|
BUF->ipchksum = ~(uip_ipchksum());
|
||||||
|
|
||||||
|
return uip_reasslen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nullreturn:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* UIP_REASSEMBLY */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
uip_add_rcv_nxt(u16_t n)
|
||||||
|
{
|
||||||
|
uip_add32(uip_conn->rcv_nxt, n);
|
||||||
|
uip_conn->rcv_nxt[0] = uip_acc32[0];
|
||||||
|
uip_conn->rcv_nxt[1] = uip_acc32[1];
|
||||||
|
uip_conn->rcv_nxt[2] = uip_acc32[2];
|
||||||
|
uip_conn->rcv_nxt[3] = uip_acc32[3];
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_process(u8_t flag)
|
||||||
|
{
|
||||||
|
register struct uip_conn *uip_connr = uip_conn;
|
||||||
|
|
||||||
|
#if UIP_UDP
|
||||||
|
if(flag == UIP_UDP_SEND_CONN) {
|
||||||
|
goto udp_send;
|
||||||
|
}
|
||||||
|
#endif /* UIP_UDP */
|
||||||
|
|
||||||
|
uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN];
|
||||||
|
|
||||||
|
/* Check if we were invoked because of a poll request for a
|
||||||
|
particular connection. */
|
||||||
|
if(flag == UIP_POLL_REQUEST) {
|
||||||
|
if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED &&
|
||||||
|
!uip_outstanding(uip_connr)) {
|
||||||
|
uip_flags = UIP_POLL;
|
||||||
|
UIP_APPCALL();
|
||||||
|
goto appsend;
|
||||||
|
}
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
/* Check if we were invoked because of the perodic timer fireing. */
|
||||||
|
} else if(flag == UIP_TIMER) {
|
||||||
|
#if UIP_REASSEMBLY
|
||||||
|
if(uip_reasstmr != 0) {
|
||||||
|
--uip_reasstmr;
|
||||||
|
}
|
||||||
|
#endif /* UIP_REASSEMBLY */
|
||||||
|
/* Increase the initial sequence number. */
|
||||||
|
if(++iss[3] == 0) {
|
||||||
|
if(++iss[2] == 0) {
|
||||||
|
if(++iss[1] == 0) {
|
||||||
|
++iss[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset the length variables. */
|
||||||
|
uip_len = 0;
|
||||||
|
uip_slen = 0;
|
||||||
|
|
||||||
|
/* Check if the connection is in a state in which we simply wait
|
||||||
|
for the connection to time out. If so, we increase the
|
||||||
|
connection's timer and remove the connection if it times
|
||||||
|
out. */
|
||||||
|
if(uip_connr->tcpstateflags == UIP_TIME_WAIT ||
|
||||||
|
uip_connr->tcpstateflags == UIP_FIN_WAIT_2) {
|
||||||
|
++(uip_connr->timer);
|
||||||
|
if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
|
||||||
|
uip_connr->tcpstateflags = UIP_CLOSED;
|
||||||
|
}
|
||||||
|
} else if(uip_connr->tcpstateflags != UIP_CLOSED) {
|
||||||
|
/* If the connection has outstanding data, we increase the
|
||||||
|
connection's timer and see if it has reached the RTO value
|
||||||
|
in which case we retransmit. */
|
||||||
|
if(uip_outstanding(uip_connr)) {
|
||||||
|
if(uip_connr->timer-- == 0) {
|
||||||
|
if(uip_connr->nrtx == UIP_MAXRTX ||
|
||||||
|
((uip_connr->tcpstateflags == UIP_SYN_SENT ||
|
||||||
|
uip_connr->tcpstateflags == UIP_SYN_RCVD) &&
|
||||||
|
uip_connr->nrtx == UIP_MAXSYNRTX)) {
|
||||||
|
uip_connr->tcpstateflags = UIP_CLOSED;
|
||||||
|
|
||||||
|
/* We call UIP_APPCALL() with uip_flags set to
|
||||||
|
UIP_TIMEDOUT to inform the application that the
|
||||||
|
connection has timed out. */
|
||||||
|
uip_flags = UIP_TIMEDOUT;
|
||||||
|
UIP_APPCALL();
|
||||||
|
|
||||||
|
/* We also send a reset packet to the remote host. */
|
||||||
|
BUF->flags = TCP_RST | TCP_ACK;
|
||||||
|
goto tcp_send_nodata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exponential backoff. */
|
||||||
|
uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4?
|
||||||
|
4:
|
||||||
|
uip_connr->nrtx);
|
||||||
|
++(uip_connr->nrtx);
|
||||||
|
|
||||||
|
/* Ok, so we need to retransmit. We do this differently
|
||||||
|
depending on which state we are in. In ESTABLISHED, we
|
||||||
|
call upon the application so that it may prepare the
|
||||||
|
data for the retransmit. In SYN_RCVD, we resend the
|
||||||
|
SYNACK that we sent earlier and in LAST_ACK we have to
|
||||||
|
retransmit our FINACK. */
|
||||||
|
UIP_STAT(++uip_stat.tcp.rexmit);
|
||||||
|
switch(uip_connr->tcpstateflags & UIP_TS_MASK) {
|
||||||
|
case UIP_SYN_RCVD:
|
||||||
|
/* In the SYN_RCVD state, we should retransmit our
|
||||||
|
SYNACK. */
|
||||||
|
goto tcp_send_synack;
|
||||||
|
|
||||||
|
#if UIP_ACTIVE_OPEN
|
||||||
|
case UIP_SYN_SENT:
|
||||||
|
/* In the SYN_SENT state, we retransmit out SYN. */
|
||||||
|
BUF->flags = 0;
|
||||||
|
goto tcp_send_syn;
|
||||||
|
#endif /* UIP_ACTIVE_OPEN */
|
||||||
|
|
||||||
|
case UIP_ESTABLISHED:
|
||||||
|
/* In the ESTABLISHED state, we call upon the application
|
||||||
|
to do the actual retransmit after which we jump into
|
||||||
|
the code for sending out the packet (the apprexmit
|
||||||
|
label). */
|
||||||
|
uip_flags = UIP_REXMIT;
|
||||||
|
UIP_APPCALL();
|
||||||
|
goto apprexmit;
|
||||||
|
|
||||||
|
case UIP_FIN_WAIT_1:
|
||||||
|
case UIP_CLOSING:
|
||||||
|
case UIP_LAST_ACK:
|
||||||
|
/* In all these states we should retransmit a FINACK. */
|
||||||
|
goto tcp_send_finack;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) {
|
||||||
|
/* If there was no need for a retransmission, we poll the
|
||||||
|
application for new data. */
|
||||||
|
uip_flags = UIP_POLL;
|
||||||
|
UIP_APPCALL();
|
||||||
|
goto appsend;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
#if UIP_UDP
|
||||||
|
if(flag == UIP_UDP_TIMER) {
|
||||||
|
if(uip_udp_conn->lport != 0) {
|
||||||
|
uip_conn = NULL;
|
||||||
|
uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
|
||||||
|
uip_len = uip_slen = 0;
|
||||||
|
uip_flags = UIP_POLL;
|
||||||
|
UIP_UDP_APPCALL();
|
||||||
|
goto udp_send;
|
||||||
|
} else {
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This is where the input processing starts. */
|
||||||
|
UIP_STAT(++uip_stat.ip.recv);
|
||||||
|
|
||||||
|
/* Start of IP input header processing code. */
|
||||||
|
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
/* Check validity of the IP header. */
|
||||||
|
if((BUF->vtc & 0xf0) != 0x60) { /* IP version and header length. */
|
||||||
|
UIP_STAT(++uip_stat.ip.drop);
|
||||||
|
UIP_STAT(++uip_stat.ip.vhlerr);
|
||||||
|
UIP_LOG("ipv6: invalid version.");
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
/* Check validity of the IP header. */
|
||||||
|
if(BUF->vhl != 0x45) { /* IP version and header length. */
|
||||||
|
UIP_STAT(++uip_stat.ip.drop);
|
||||||
|
UIP_STAT(++uip_stat.ip.vhlerr);
|
||||||
|
UIP_LOG("ip: invalid version or header length.");
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
/* Check the size of the packet. If the size reported to us in
|
||||||
|
uip_len is smaller the size reported in the IP header, we assume
|
||||||
|
that the packet has been corrupted in transit. If the size of
|
||||||
|
uip_len is larger than the size reported in the IP packet header,
|
||||||
|
the packet has been padded and we set uip_len to the correct
|
||||||
|
value.. */
|
||||||
|
|
||||||
|
if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) {
|
||||||
|
uip_len = (BUF->len[0] << 8) + BUF->len[1];
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
uip_len += 40; /* The length reported in the IPv6 header is the
|
||||||
|
length of the payload that follows the
|
||||||
|
header. However, uIP uses the uip_len variable
|
||||||
|
for holding the size of the entire packet,
|
||||||
|
including the IP header. For IPv4 this is not a
|
||||||
|
problem as the length field in the IPv4 header
|
||||||
|
contains the length of the entire packet. But
|
||||||
|
for IPv6 we need to add the size of the IPv6
|
||||||
|
header (40 bytes). */
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
} else {
|
||||||
|
UIP_LOG("ip: packet shorter than reported in IP header.");
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !UIP_CONF_IPV6
|
||||||
|
/* Check the fragment flag. */
|
||||||
|
if((BUF->ipoffset[0] & 0x3f) != 0 ||
|
||||||
|
BUF->ipoffset[1] != 0) {
|
||||||
|
#if UIP_REASSEMBLY
|
||||||
|
uip_len = uip_reass();
|
||||||
|
if(uip_len == 0) {
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
#else /* UIP_REASSEMBLY */
|
||||||
|
UIP_STAT(++uip_stat.ip.drop);
|
||||||
|
UIP_STAT(++uip_stat.ip.fragerr);
|
||||||
|
UIP_LOG("ip: fragment dropped.");
|
||||||
|
goto drop;
|
||||||
|
#endif /* UIP_REASSEMBLY */
|
||||||
|
}
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
if(uip_ipaddr_cmp(uip_hostaddr, all_zeroes_addr)) {
|
||||||
|
/* If we are configured to use ping IP address configuration and
|
||||||
|
hasn't been assigned an IP address yet, we accept all ICMP
|
||||||
|
packets. */
|
||||||
|
#if UIP_PINGADDRCONF && !UIP_CONF_IPV6
|
||||||
|
if(BUF->proto == UIP_PROTO_ICMP) {
|
||||||
|
UIP_LOG("ip: possible ping config packet received.");
|
||||||
|
goto icmp_input;
|
||||||
|
} else {
|
||||||
|
UIP_LOG("ip: packet dropped since no address assigned.");
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
#endif /* UIP_PINGADDRCONF */
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* If IP broadcast support is configured, we check for a broadcast
|
||||||
|
UDP packet, which may be destined to us. */
|
||||||
|
#if UIP_BROADCAST
|
||||||
|
DEBUG_PRINTF("UDP IP checksum 0x%04x\n", uip_ipchksum());
|
||||||
|
if(BUF->proto == UIP_PROTO_UDP &&
|
||||||
|
uip_ipaddr_cmp(BUF->destipaddr, all_ones_addr)
|
||||||
|
/*&&
|
||||||
|
uip_ipchksum() == 0xffff*/) {
|
||||||
|
goto udp_input;
|
||||||
|
}
|
||||||
|
#endif /* UIP_BROADCAST */
|
||||||
|
|
||||||
|
/* Check if the packet is destined for our IP address. */
|
||||||
|
#if !UIP_CONF_IPV6
|
||||||
|
if(!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr)) {
|
||||||
|
UIP_STAT(++uip_stat.ip.drop);
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
/* For IPv6, packet reception is a little trickier as we need to
|
||||||
|
make sure that we listen to certain multicast addresses (all
|
||||||
|
hosts multicast address, and the solicited-node multicast
|
||||||
|
address) as well. However, we will cheat here and accept all
|
||||||
|
multicast packets that are sent to the ff02::/16 addresses. */
|
||||||
|
if(!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr) &&
|
||||||
|
BUF->destipaddr[0] != HTONS(0xff02)) {
|
||||||
|
UIP_STAT(++uip_stat.ip.drop);
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !UIP_CONF_IPV6
|
||||||
|
if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header
|
||||||
|
checksum. */
|
||||||
|
UIP_STAT(++uip_stat.ip.drop);
|
||||||
|
UIP_STAT(++uip_stat.ip.chkerr);
|
||||||
|
UIP_LOG("ip: bad checksum.");
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
if(BUF->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so,
|
||||||
|
proceed with TCP input
|
||||||
|
processing. */
|
||||||
|
goto tcp_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UIP_UDP
|
||||||
|
if(BUF->proto == UIP_PROTO_UDP) {
|
||||||
|
goto udp_input;
|
||||||
|
}
|
||||||
|
#endif /* UIP_UDP */
|
||||||
|
|
||||||
|
#if !UIP_CONF_IPV6
|
||||||
|
/* ICMPv4 processing code follows. */
|
||||||
|
if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
|
||||||
|
here. */
|
||||||
|
UIP_STAT(++uip_stat.ip.drop);
|
||||||
|
UIP_STAT(++uip_stat.ip.protoerr);
|
||||||
|
UIP_LOG("ip: neither tcp nor icmp.");
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UIP_PINGADDRCONF
|
||||||
|
icmp_input:
|
||||||
|
#endif /* UIP_PINGADDRCONF */
|
||||||
|
UIP_STAT(++uip_stat.icmp.recv);
|
||||||
|
|
||||||
|
/* ICMP echo (i.e., ping) processing. This is simple, we only change
|
||||||
|
the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
|
||||||
|
checksum before we return the packet. */
|
||||||
|
if(ICMPBUF->type != ICMP_ECHO) {
|
||||||
|
UIP_STAT(++uip_stat.icmp.drop);
|
||||||
|
UIP_STAT(++uip_stat.icmp.typeerr);
|
||||||
|
UIP_LOG("icmp: not icmp echo.");
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we are configured to use ping IP address assignment, we use
|
||||||
|
the destination IP address of this ping packet and assign it to
|
||||||
|
ourself. */
|
||||||
|
#if UIP_PINGADDRCONF
|
||||||
|
if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
|
||||||
|
uip_hostaddr[0] = BUF->destipaddr[0];
|
||||||
|
uip_hostaddr[1] = BUF->destipaddr[1];
|
||||||
|
}
|
||||||
|
#endif /* UIP_PINGADDRCONF */
|
||||||
|
|
||||||
|
ICMPBUF->type = ICMP_ECHO_REPLY;
|
||||||
|
|
||||||
|
if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) {
|
||||||
|
ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1;
|
||||||
|
} else {
|
||||||
|
ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Swap IP addresses. */
|
||||||
|
uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr);
|
||||||
|
uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
|
||||||
|
|
||||||
|
UIP_STAT(++uip_stat.icmp.sent);
|
||||||
|
goto send;
|
||||||
|
|
||||||
|
/* End of IPv4 input header processing code. */
|
||||||
|
#else /* !UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
/* This is IPv6 ICMPv6 processing code. */
|
||||||
|
DEBUG_PRINTF("icmp6_input: length %d\n", uip_len);
|
||||||
|
|
||||||
|
if(BUF->proto != UIP_PROTO_ICMP6) { /* We only allow ICMPv6 packets from
|
||||||
|
here. */
|
||||||
|
UIP_STAT(++uip_stat.ip.drop);
|
||||||
|
UIP_STAT(++uip_stat.ip.protoerr);
|
||||||
|
UIP_LOG("ip: neither tcp nor icmp6.");
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIP_STAT(++uip_stat.icmp.recv);
|
||||||
|
|
||||||
|
/* If we get a neighbor solicitation for our address we should send
|
||||||
|
a neighbor advertisement message back. */
|
||||||
|
if(ICMPBUF->type == ICMP6_NEIGHBOR_SOLICITATION) {
|
||||||
|
if(uip_ipaddr_cmp(ICMPBUF->icmp6data, uip_hostaddr)) {
|
||||||
|
|
||||||
|
if(ICMPBUF->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS) {
|
||||||
|
/* Save the sender's address in our neighbor list. */
|
||||||
|
uip_neighbor_add(ICMPBUF->srcipaddr, &(ICMPBUF->options[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We should now send a neighbor advertisement back to where the
|
||||||
|
neighbor solicication came from. */
|
||||||
|
ICMPBUF->type = ICMP6_NEIGHBOR_ADVERTISEMENT;
|
||||||
|
ICMPBUF->flags = ICMP6_FLAG_S; /* Solicited flag. */
|
||||||
|
|
||||||
|
ICMPBUF->reserved1 = ICMPBUF->reserved2 = ICMPBUF->reserved3 = 0;
|
||||||
|
|
||||||
|
uip_ipaddr_copy(ICMPBUF->destipaddr, ICMPBUF->srcipaddr);
|
||||||
|
uip_ipaddr_copy(ICMPBUF->srcipaddr, uip_hostaddr);
|
||||||
|
ICMPBUF->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS;
|
||||||
|
ICMPBUF->options[1] = 1; /* Options length, 1 = 8 bytes. */
|
||||||
|
memcpy(&(ICMPBUF->options[2]), &uip_ethaddr, sizeof(uip_ethaddr));
|
||||||
|
ICMPBUF->icmpchksum = 0;
|
||||||
|
ICMPBUF->icmpchksum = ~uip_icmp6chksum();
|
||||||
|
goto send;
|
||||||
|
|
||||||
|
}
|
||||||
|
goto drop;
|
||||||
|
} else if(ICMPBUF->type == ICMP6_ECHO) {
|
||||||
|
/* ICMP echo (i.e., ping) processing. This is simple, we only
|
||||||
|
change the ICMP type from ECHO to ECHO_REPLY and update the
|
||||||
|
ICMP checksum before we return the packet. */
|
||||||
|
|
||||||
|
ICMPBUF->type = ICMP6_ECHO_REPLY;
|
||||||
|
|
||||||
|
uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr);
|
||||||
|
uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
|
||||||
|
ICMPBUF->icmpchksum = 0;
|
||||||
|
ICMPBUF->icmpchksum = ~uip_icmp6chksum();
|
||||||
|
|
||||||
|
UIP_STAT(++uip_stat.icmp.sent);
|
||||||
|
goto send;
|
||||||
|
} else {
|
||||||
|
DEBUG_PRINTF("Unknown icmp6 message type %d\n", ICMPBUF->type);
|
||||||
|
UIP_STAT(++uip_stat.icmp.drop);
|
||||||
|
UIP_STAT(++uip_stat.icmp.typeerr);
|
||||||
|
UIP_LOG("icmp: unknown ICMP message.");
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End of IPv6 ICMP processing. */
|
||||||
|
|
||||||
|
#endif /* !UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
#if UIP_UDP
|
||||||
|
/* UDP input processing. */
|
||||||
|
udp_input:
|
||||||
|
/* UDP processing is really just a hack. We don't do anything to the
|
||||||
|
UDP/IP headers, but let the UDP application do all the hard
|
||||||
|
work. If the application sets uip_slen, it has a packet to
|
||||||
|
send. */
|
||||||
|
#if UIP_UDP_CHECKSUMS
|
||||||
|
uip_len = uip_len - UIP_IPUDPH_LEN;
|
||||||
|
uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
|
||||||
|
if(UDPBUF->udpchksum != 0 && uip_udpchksum() != 0xffff) {
|
||||||
|
UIP_STAT(++uip_stat.udp.drop);
|
||||||
|
UIP_STAT(++uip_stat.udp.chkerr);
|
||||||
|
UIP_LOG("udp: bad checksum.");
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
#else /* UIP_UDP_CHECKSUMS */
|
||||||
|
uip_len = uip_len - UIP_IPUDPH_LEN;
|
||||||
|
#endif /* UIP_UDP_CHECKSUMS */
|
||||||
|
|
||||||
|
/* Demultiplex this UDP packet between the UDP "connections". */
|
||||||
|
for(uip_udp_conn = &uip_udp_conns[0];
|
||||||
|
uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS];
|
||||||
|
++uip_udp_conn) {
|
||||||
|
/* If the local UDP port is non-zero, the connection is considered
|
||||||
|
to be used. If so, the local port number is checked against the
|
||||||
|
destination port number in the received packet. If the two port
|
||||||
|
numbers match, the remote port number is checked if the
|
||||||
|
connection is bound to a remote port. Finally, if the
|
||||||
|
connection is bound to a remote IP address, the source IP
|
||||||
|
address of the packet is checked. */
|
||||||
|
if(uip_udp_conn->lport != 0 &&
|
||||||
|
UDPBUF->destport == uip_udp_conn->lport &&
|
||||||
|
(uip_udp_conn->rport == 0 ||
|
||||||
|
UDPBUF->srcport == uip_udp_conn->rport) &&
|
||||||
|
(uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_zeroes_addr) ||
|
||||||
|
uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_ones_addr) ||
|
||||||
|
uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) {
|
||||||
|
goto udp_found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UIP_LOG("udp: no matching connection found");
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
udp_found:
|
||||||
|
uip_conn = NULL;
|
||||||
|
uip_flags = UIP_NEWDATA;
|
||||||
|
uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
|
||||||
|
uip_slen = 0;
|
||||||
|
UIP_UDP_APPCALL();
|
||||||
|
udp_send:
|
||||||
|
if(uip_slen == 0) {
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
uip_len = uip_slen + UIP_IPUDPH_LEN;
|
||||||
|
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
/* For IPv6, the IP length field does not include the IPv6 IP header
|
||||||
|
length. */
|
||||||
|
BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
|
||||||
|
BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
BUF->len[0] = (uip_len >> 8);
|
||||||
|
BUF->len[1] = (uip_len & 0xff);
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
BUF->ttl = uip_udp_conn->ttl;
|
||||||
|
BUF->proto = UIP_PROTO_UDP;
|
||||||
|
|
||||||
|
UDPBUF->udplen = HTONS(uip_slen + UIP_UDPH_LEN);
|
||||||
|
UDPBUF->udpchksum = 0;
|
||||||
|
|
||||||
|
BUF->srcport = uip_udp_conn->lport;
|
||||||
|
BUF->destport = uip_udp_conn->rport;
|
||||||
|
|
||||||
|
uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
|
||||||
|
uip_ipaddr_copy(BUF->destipaddr, uip_udp_conn->ripaddr);
|
||||||
|
|
||||||
|
uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
|
||||||
|
|
||||||
|
#if UIP_UDP_CHECKSUMS
|
||||||
|
/* Calculate UDP checksum. */
|
||||||
|
UDPBUF->udpchksum = ~(uip_udpchksum());
|
||||||
|
if(UDPBUF->udpchksum == 0) {
|
||||||
|
UDPBUF->udpchksum = 0xffff;
|
||||||
|
}
|
||||||
|
#endif /* UIP_UDP_CHECKSUMS */
|
||||||
|
|
||||||
|
goto ip_send_nolen;
|
||||||
|
#endif /* UIP_UDP */
|
||||||
|
|
||||||
|
/* TCP input processing. */
|
||||||
|
tcp_input:
|
||||||
|
UIP_STAT(++uip_stat.tcp.recv);
|
||||||
|
|
||||||
|
/* Start of TCP input header processing code. */
|
||||||
|
|
||||||
|
if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP
|
||||||
|
checksum. */
|
||||||
|
UIP_STAT(++uip_stat.tcp.drop);
|
||||||
|
UIP_STAT(++uip_stat.tcp.chkerr);
|
||||||
|
UIP_LOG("tcp: bad checksum.");
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Demultiplex this segment. */
|
||||||
|
/* First check any active connections. */
|
||||||
|
for(uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1];
|
||||||
|
++uip_connr) {
|
||||||
|
if(uip_connr->tcpstateflags != UIP_CLOSED &&
|
||||||
|
BUF->destport == uip_connr->lport &&
|
||||||
|
BUF->srcport == uip_connr->rport &&
|
||||||
|
uip_ipaddr_cmp(BUF->srcipaddr, uip_connr->ripaddr)) {
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we didn't find and active connection that expected the packet,
|
||||||
|
either this packet is an old duplicate, or this is a SYN packet
|
||||||
|
destined for a connection in LISTEN. If the SYN flag isn't set,
|
||||||
|
it is an old packet and we send a RST. */
|
||||||
|
if((BUF->flags & TCP_CTL) != TCP_SYN) {
|
||||||
|
goto reset;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp16 = BUF->destport;
|
||||||
|
/* Next, check listening connections. */
|
||||||
|
for(c = 0; c < UIP_LISTENPORTS; ++c) {
|
||||||
|
if(tmp16 == uip_listenports[c])
|
||||||
|
goto found_listen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No matching connection found, so we send a RST packet. */
|
||||||
|
UIP_STAT(++uip_stat.tcp.synrst);
|
||||||
|
reset:
|
||||||
|
|
||||||
|
/* We do not send resets in response to resets. */
|
||||||
|
if(BUF->flags & TCP_RST) {
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIP_STAT(++uip_stat.tcp.rst);
|
||||||
|
|
||||||
|
BUF->flags = TCP_RST | TCP_ACK;
|
||||||
|
uip_len = UIP_IPTCPH_LEN;
|
||||||
|
BUF->tcpoffset = 5 << 4;
|
||||||
|
|
||||||
|
/* Flip the seqno and ackno fields in the TCP header. */
|
||||||
|
c = BUF->seqno[3];
|
||||||
|
BUF->seqno[3] = BUF->ackno[3];
|
||||||
|
BUF->ackno[3] = c;
|
||||||
|
|
||||||
|
c = BUF->seqno[2];
|
||||||
|
BUF->seqno[2] = BUF->ackno[2];
|
||||||
|
BUF->ackno[2] = c;
|
||||||
|
|
||||||
|
c = BUF->seqno[1];
|
||||||
|
BUF->seqno[1] = BUF->ackno[1];
|
||||||
|
BUF->ackno[1] = c;
|
||||||
|
|
||||||
|
c = BUF->seqno[0];
|
||||||
|
BUF->seqno[0] = BUF->ackno[0];
|
||||||
|
BUF->ackno[0] = c;
|
||||||
|
|
||||||
|
/* We also have to increase the sequence number we are
|
||||||
|
acknowledging. If the least significant byte overflowed, we need
|
||||||
|
to propagate the carry to the other bytes as well. */
|
||||||
|
if(++BUF->ackno[3] == 0) {
|
||||||
|
if(++BUF->ackno[2] == 0) {
|
||||||
|
if(++BUF->ackno[1] == 0) {
|
||||||
|
++BUF->ackno[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Swap port numbers. */
|
||||||
|
tmp16 = BUF->srcport;
|
||||||
|
BUF->srcport = BUF->destport;
|
||||||
|
BUF->destport = tmp16;
|
||||||
|
|
||||||
|
/* Swap IP addresses. */
|
||||||
|
uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr);
|
||||||
|
uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
|
||||||
|
|
||||||
|
/* And send out the RST packet! */
|
||||||
|
goto tcp_send_noconn;
|
||||||
|
|
||||||
|
/* This label will be jumped to if we matched the incoming packet
|
||||||
|
with a connection in LISTEN. In that case, we should create a new
|
||||||
|
connection and send a SYNACK in return. */
|
||||||
|
found_listen:
|
||||||
|
/* First we check if there are any connections avaliable. Unused
|
||||||
|
connections are kept in the same table as used connections, but
|
||||||
|
unused ones have the tcpstate set to CLOSED. Also, connections in
|
||||||
|
TIME_WAIT are kept track of and we'll use the oldest one if no
|
||||||
|
CLOSED connections are found. Thanks to Eddie C. Dost for a very
|
||||||
|
nice algorithm for the TIME_WAIT search. */
|
||||||
|
uip_connr = 0;
|
||||||
|
for(c = 0; c < UIP_CONNS; ++c) {
|
||||||
|
if(uip_conns[c].tcpstateflags == UIP_CLOSED) {
|
||||||
|
uip_connr = &uip_conns[c];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(uip_conns[c].tcpstateflags == UIP_TIME_WAIT) {
|
||||||
|
if(uip_connr == 0 ||
|
||||||
|
uip_conns[c].timer > uip_connr->timer) {
|
||||||
|
uip_connr = &uip_conns[c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uip_connr == 0) {
|
||||||
|
/* All connections are used already, we drop packet and hope that
|
||||||
|
the remote end will retransmit the packet at a time when we
|
||||||
|
have more spare connections. */
|
||||||
|
UIP_STAT(++uip_stat.tcp.syndrop);
|
||||||
|
UIP_LOG("tcp: found no unused connections.");
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
uip_conn = uip_connr;
|
||||||
|
|
||||||
|
/* Fill in the necessary fields for the new connection. */
|
||||||
|
uip_connr->rto = uip_connr->timer = UIP_RTO;
|
||||||
|
uip_connr->sa = 0;
|
||||||
|
uip_connr->sv = 4;
|
||||||
|
uip_connr->nrtx = 0;
|
||||||
|
uip_connr->lport = BUF->destport;
|
||||||
|
uip_connr->rport = BUF->srcport;
|
||||||
|
uip_ipaddr_copy(uip_connr->ripaddr, BUF->srcipaddr);
|
||||||
|
uip_connr->tcpstateflags = UIP_SYN_RCVD;
|
||||||
|
|
||||||
|
uip_connr->snd_nxt[0] = iss[0];
|
||||||
|
uip_connr->snd_nxt[1] = iss[1];
|
||||||
|
uip_connr->snd_nxt[2] = iss[2];
|
||||||
|
uip_connr->snd_nxt[3] = iss[3];
|
||||||
|
uip_connr->len = 1;
|
||||||
|
|
||||||
|
/* rcv_nxt should be the seqno from the incoming packet + 1. */
|
||||||
|
uip_connr->rcv_nxt[3] = BUF->seqno[3];
|
||||||
|
uip_connr->rcv_nxt[2] = BUF->seqno[2];
|
||||||
|
uip_connr->rcv_nxt[1] = BUF->seqno[1];
|
||||||
|
uip_connr->rcv_nxt[0] = BUF->seqno[0];
|
||||||
|
uip_add_rcv_nxt(1);
|
||||||
|
|
||||||
|
/* Parse the TCP MSS option, if present. */
|
||||||
|
if((BUF->tcpoffset & 0xf0) > 0x50) {
|
||||||
|
for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
|
||||||
|
opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
|
||||||
|
if(opt == TCP_OPT_END) {
|
||||||
|
/* End of options. */
|
||||||
|
break;
|
||||||
|
} else if(opt == TCP_OPT_NOOP) {
|
||||||
|
++c;
|
||||||
|
/* NOP option. */
|
||||||
|
} else if(opt == TCP_OPT_MSS &&
|
||||||
|
uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
|
||||||
|
/* An MSS option with the right option length. */
|
||||||
|
tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
|
||||||
|
(u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c];
|
||||||
|
uip_connr->initialmss = uip_connr->mss =
|
||||||
|
tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
|
||||||
|
|
||||||
|
/* And we are done processing options. */
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
/* All other options have a length field, so that we easily
|
||||||
|
can skip past them. */
|
||||||
|
if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
|
||||||
|
/* If the length field is zero, the options are malformed
|
||||||
|
and we don't process them further. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Our response will be a SYNACK. */
|
||||||
|
#if UIP_ACTIVE_OPEN
|
||||||
|
tcp_send_synack:
|
||||||
|
BUF->flags = TCP_ACK;
|
||||||
|
|
||||||
|
tcp_send_syn:
|
||||||
|
BUF->flags |= TCP_SYN;
|
||||||
|
#else /* UIP_ACTIVE_OPEN */
|
||||||
|
tcp_send_synack:
|
||||||
|
BUF->flags = TCP_SYN | TCP_ACK;
|
||||||
|
#endif /* UIP_ACTIVE_OPEN */
|
||||||
|
|
||||||
|
/* We send out the TCP Maximum Segment Size option with our
|
||||||
|
SYNACK. */
|
||||||
|
BUF->optdata[0] = TCP_OPT_MSS;
|
||||||
|
BUF->optdata[1] = TCP_OPT_MSS_LEN;
|
||||||
|
BUF->optdata[2] = (UIP_TCP_MSS) / 256;
|
||||||
|
BUF->optdata[3] = (UIP_TCP_MSS) & 255;
|
||||||
|
uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN;
|
||||||
|
BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4;
|
||||||
|
goto tcp_send;
|
||||||
|
|
||||||
|
/* This label will be jumped to if we found an active connection. */
|
||||||
|
found:
|
||||||
|
uip_conn = uip_connr;
|
||||||
|
uip_flags = 0;
|
||||||
|
/* We do a very naive form of TCP reset processing; we just accept
|
||||||
|
any RST and kill our connection. We should in fact check if the
|
||||||
|
sequence number of this reset is wihtin our advertised window
|
||||||
|
before we accept the reset. */
|
||||||
|
if(BUF->flags & TCP_RST) {
|
||||||
|
uip_connr->tcpstateflags = UIP_CLOSED;
|
||||||
|
UIP_LOG("tcp: got reset, aborting connection.");
|
||||||
|
uip_flags = UIP_ABORT;
|
||||||
|
UIP_APPCALL();
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
/* Calculated the length of the data, if the application has sent
|
||||||
|
any data to us. */
|
||||||
|
c = (BUF->tcpoffset >> 4) << 2;
|
||||||
|
/* uip_len will contain the length of the actual TCP data. This is
|
||||||
|
calculated by subtracing the length of the TCP header (in
|
||||||
|
c) and the length of the IP header (20 bytes). */
|
||||||
|
uip_len = uip_len - c - UIP_IPH_LEN;
|
||||||
|
|
||||||
|
/* First, check if the sequence number of the incoming packet is
|
||||||
|
what we're expecting next. If not, we send out an ACK with the
|
||||||
|
correct numbers in. */
|
||||||
|
if(!(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) &&
|
||||||
|
((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) {
|
||||||
|
if((uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) &&
|
||||||
|
(BUF->seqno[0] != uip_connr->rcv_nxt[0] ||
|
||||||
|
BUF->seqno[1] != uip_connr->rcv_nxt[1] ||
|
||||||
|
BUF->seqno[2] != uip_connr->rcv_nxt[2] ||
|
||||||
|
BUF->seqno[3] != uip_connr->rcv_nxt[3])) {
|
||||||
|
goto tcp_send_ack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next, check if the incoming segment acknowledges any outstanding
|
||||||
|
data. If so, we update the sequence number, reset the length of
|
||||||
|
the outstanding data, calculate RTT estimations, and reset the
|
||||||
|
retransmission timer. */
|
||||||
|
if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) {
|
||||||
|
uip_add32(uip_connr->snd_nxt, uip_connr->len);
|
||||||
|
|
||||||
|
if(BUF->ackno[0] == uip_acc32[0] &&
|
||||||
|
BUF->ackno[1] == uip_acc32[1] &&
|
||||||
|
BUF->ackno[2] == uip_acc32[2] &&
|
||||||
|
BUF->ackno[3] == uip_acc32[3]) {
|
||||||
|
/* Update sequence number. */
|
||||||
|
uip_connr->snd_nxt[0] = uip_acc32[0];
|
||||||
|
uip_connr->snd_nxt[1] = uip_acc32[1];
|
||||||
|
uip_connr->snd_nxt[2] = uip_acc32[2];
|
||||||
|
uip_connr->snd_nxt[3] = uip_acc32[3];
|
||||||
|
|
||||||
|
|
||||||
|
/* Do RTT estimation, unless we have done retransmissions. */
|
||||||
|
if(uip_connr->nrtx == 0) {
|
||||||
|
signed char m;
|
||||||
|
m = uip_connr->rto - uip_connr->timer;
|
||||||
|
/* This is taken directly from VJs original code in his paper */
|
||||||
|
m = m - (uip_connr->sa >> 3);
|
||||||
|
uip_connr->sa += m;
|
||||||
|
if(m < 0) {
|
||||||
|
m = -m;
|
||||||
|
}
|
||||||
|
m = m - (uip_connr->sv >> 2);
|
||||||
|
uip_connr->sv += m;
|
||||||
|
uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
|
||||||
|
|
||||||
|
}
|
||||||
|
/* Set the acknowledged flag. */
|
||||||
|
uip_flags = UIP_ACKDATA;
|
||||||
|
/* Reset the retransmission timer. */
|
||||||
|
uip_connr->timer = uip_connr->rto;
|
||||||
|
|
||||||
|
/* Reset length of outstanding data. */
|
||||||
|
uip_connr->len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do different things depending on in what state the connection is. */
|
||||||
|
switch(uip_connr->tcpstateflags & UIP_TS_MASK) {
|
||||||
|
/* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
|
||||||
|
implemented, since we force the application to close when the
|
||||||
|
peer sends a FIN (hence the application goes directly from
|
||||||
|
ESTABLISHED to LAST_ACK). */
|
||||||
|
case UIP_SYN_RCVD:
|
||||||
|
/* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
|
||||||
|
we are waiting for an ACK that acknowledges the data we sent
|
||||||
|
out the last time. Therefore, we want to have the UIP_ACKDATA
|
||||||
|
flag set. If so, we enter the ESTABLISHED state. */
|
||||||
|
if(uip_flags & UIP_ACKDATA) {
|
||||||
|
uip_connr->tcpstateflags = UIP_ESTABLISHED;
|
||||||
|
uip_flags = UIP_CONNECTED;
|
||||||
|
uip_connr->len = 0;
|
||||||
|
if(uip_len > 0) {
|
||||||
|
uip_flags |= UIP_NEWDATA;
|
||||||
|
uip_add_rcv_nxt(uip_len);
|
||||||
|
}
|
||||||
|
uip_slen = 0;
|
||||||
|
UIP_APPCALL();
|
||||||
|
goto appsend;
|
||||||
|
}
|
||||||
|
goto drop;
|
||||||
|
#if UIP_ACTIVE_OPEN
|
||||||
|
case UIP_SYN_SENT:
|
||||||
|
/* In SYN_SENT, we wait for a SYNACK that is sent in response to
|
||||||
|
our SYN. The rcv_nxt is set to sequence number in the SYNACK
|
||||||
|
plus one, and we send an ACK. We move into the ESTABLISHED
|
||||||
|
state. */
|
||||||
|
if((uip_flags & UIP_ACKDATA) &&
|
||||||
|
(BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) {
|
||||||
|
|
||||||
|
/* Parse the TCP MSS option, if present. */
|
||||||
|
if((BUF->tcpoffset & 0xf0) > 0x50) {
|
||||||
|
for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
|
||||||
|
opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c];
|
||||||
|
if(opt == TCP_OPT_END) {
|
||||||
|
/* End of options. */
|
||||||
|
break;
|
||||||
|
} else if(opt == TCP_OPT_NOOP) {
|
||||||
|
++c;
|
||||||
|
/* NOP option. */
|
||||||
|
} else if(opt == TCP_OPT_MSS &&
|
||||||
|
uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
|
||||||
|
/* An MSS option with the right option length. */
|
||||||
|
tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
|
||||||
|
uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
|
||||||
|
uip_connr->initialmss =
|
||||||
|
uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
|
||||||
|
|
||||||
|
/* And we are done processing options. */
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
/* All other options have a length field, so that we easily
|
||||||
|
can skip past them. */
|
||||||
|
if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
|
||||||
|
/* If the length field is zero, the options are malformed
|
||||||
|
and we don't process them further. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uip_connr->tcpstateflags = UIP_ESTABLISHED;
|
||||||
|
uip_connr->rcv_nxt[0] = BUF->seqno[0];
|
||||||
|
uip_connr->rcv_nxt[1] = BUF->seqno[1];
|
||||||
|
uip_connr->rcv_nxt[2] = BUF->seqno[2];
|
||||||
|
uip_connr->rcv_nxt[3] = BUF->seqno[3];
|
||||||
|
uip_add_rcv_nxt(1);
|
||||||
|
uip_flags = UIP_CONNECTED | UIP_NEWDATA;
|
||||||
|
uip_connr->len = 0;
|
||||||
|
uip_len = 0;
|
||||||
|
uip_slen = 0;
|
||||||
|
UIP_APPCALL();
|
||||||
|
goto appsend;
|
||||||
|
}
|
||||||
|
/* Inform the application that the connection failed */
|
||||||
|
uip_flags = UIP_ABORT;
|
||||||
|
UIP_APPCALL();
|
||||||
|
/* The connection is closed after we send the RST */
|
||||||
|
uip_conn->tcpstateflags = UIP_CLOSED;
|
||||||
|
goto reset;
|
||||||
|
#endif /* UIP_ACTIVE_OPEN */
|
||||||
|
|
||||||
|
case UIP_ESTABLISHED:
|
||||||
|
/* In the ESTABLISHED state, we call upon the application to feed
|
||||||
|
data into the uip_buf. If the UIP_ACKDATA flag is set, the
|
||||||
|
application should put new data into the buffer, otherwise we are
|
||||||
|
retransmitting an old segment, and the application should put that
|
||||||
|
data into the buffer.
|
||||||
|
|
||||||
|
If the incoming packet is a FIN, we should close the connection on
|
||||||
|
this side as well, and we send out a FIN and enter the LAST_ACK
|
||||||
|
state. We require that there is no outstanding data; otherwise the
|
||||||
|
sequence numbers will be screwed up. */
|
||||||
|
|
||||||
|
if(BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
|
||||||
|
if(uip_outstanding(uip_connr)) {
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
uip_add_rcv_nxt(1 + uip_len);
|
||||||
|
uip_flags |= UIP_CLOSE;
|
||||||
|
if(uip_len > 0) {
|
||||||
|
uip_flags |= UIP_NEWDATA;
|
||||||
|
}
|
||||||
|
UIP_APPCALL();
|
||||||
|
uip_connr->len = 1;
|
||||||
|
uip_connr->tcpstateflags = UIP_LAST_ACK;
|
||||||
|
uip_connr->nrtx = 0;
|
||||||
|
tcp_send_finack:
|
||||||
|
BUF->flags = TCP_FIN | TCP_ACK;
|
||||||
|
goto tcp_send_nodata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the URG flag. If this is set, the segment carries urgent
|
||||||
|
data that we must pass to the application. */
|
||||||
|
if((BUF->flags & TCP_URG) != 0) {
|
||||||
|
#if UIP_URGDATA > 0
|
||||||
|
uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1];
|
||||||
|
if(uip_urglen > uip_len) {
|
||||||
|
/* There is more urgent data in the next segment to come. */
|
||||||
|
uip_urglen = uip_len;
|
||||||
|
}
|
||||||
|
uip_add_rcv_nxt(uip_urglen);
|
||||||
|
uip_len -= uip_urglen;
|
||||||
|
uip_urgdata = uip_appdata;
|
||||||
|
uip_appdata += uip_urglen;
|
||||||
|
} else {
|
||||||
|
uip_urglen = 0;
|
||||||
|
#else /* UIP_URGDATA > 0 */
|
||||||
|
uip_appdata = ((char *)uip_appdata) + ((BUF->urgp[0] << 8) | BUF->urgp[1]);
|
||||||
|
uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1];
|
||||||
|
#endif /* UIP_URGDATA > 0 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If uip_len > 0 we have TCP data in the packet, and we flag this
|
||||||
|
by setting the UIP_NEWDATA flag and update the sequence number
|
||||||
|
we acknowledge. If the application has stopped the dataflow
|
||||||
|
using uip_stop(), we must not accept any data packets from the
|
||||||
|
remote host. */
|
||||||
|
if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
|
||||||
|
uip_flags |= UIP_NEWDATA;
|
||||||
|
uip_add_rcv_nxt(uip_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the available buffer space advertised by the other end
|
||||||
|
is smaller than the initial MSS for this connection. If so, we
|
||||||
|
set the current MSS to the window size to ensure that the
|
||||||
|
application does not send more data than the other end can
|
||||||
|
handle.
|
||||||
|
|
||||||
|
If the remote host advertises a zero window, we set the MSS to
|
||||||
|
the initial MSS so that the application will send an entire MSS
|
||||||
|
of data. This data will not be acknowledged by the receiver,
|
||||||
|
and the application will retransmit it. This is called the
|
||||||
|
"persistent timer" and uses the retransmission mechanim.
|
||||||
|
*/
|
||||||
|
tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1];
|
||||||
|
if(tmp16 > uip_connr->initialmss ||
|
||||||
|
tmp16 == 0) {
|
||||||
|
tmp16 = uip_connr->initialmss;
|
||||||
|
}
|
||||||
|
uip_connr->mss = tmp16;
|
||||||
|
|
||||||
|
/* If this packet constitutes an ACK for outstanding data (flagged
|
||||||
|
by the UIP_ACKDATA flag, we should call the application since it
|
||||||
|
might want to send more data. If the incoming packet had data
|
||||||
|
from the peer (as flagged by the UIP_NEWDATA flag), the
|
||||||
|
application must also be notified.
|
||||||
|
|
||||||
|
When the application is called, the global variable uip_len
|
||||||
|
contains the length of the incoming data. The application can
|
||||||
|
access the incoming data through the global pointer
|
||||||
|
uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN
|
||||||
|
bytes into the uip_buf array.
|
||||||
|
|
||||||
|
If the application wishes to send any data, this data should be
|
||||||
|
put into the uip_appdata and the length of the data should be
|
||||||
|
put into uip_len. If the application don't have any data to
|
||||||
|
send, uip_len must be set to 0. */
|
||||||
|
if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
|
||||||
|
uip_slen = 0;
|
||||||
|
UIP_APPCALL();
|
||||||
|
|
||||||
|
appsend:
|
||||||
|
|
||||||
|
if(uip_flags & UIP_ABORT) {
|
||||||
|
uip_slen = 0;
|
||||||
|
uip_connr->tcpstateflags = UIP_CLOSED;
|
||||||
|
BUF->flags = TCP_RST | TCP_ACK;
|
||||||
|
goto tcp_send_nodata;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uip_flags & UIP_CLOSE) {
|
||||||
|
uip_slen = 0;
|
||||||
|
uip_connr->len = 1;
|
||||||
|
uip_connr->tcpstateflags = UIP_FIN_WAIT_1;
|
||||||
|
uip_connr->nrtx = 0;
|
||||||
|
BUF->flags = TCP_FIN | TCP_ACK;
|
||||||
|
goto tcp_send_nodata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If uip_slen > 0, the application has data to be sent. */
|
||||||
|
if(uip_slen > 0) {
|
||||||
|
|
||||||
|
/* If the connection has acknowledged data, the contents of
|
||||||
|
the ->len variable should be discarded. */
|
||||||
|
if((uip_flags & UIP_ACKDATA) != 0) {
|
||||||
|
uip_connr->len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the ->len variable is non-zero the connection has
|
||||||
|
already data in transit and cannot send anymore right
|
||||||
|
now. */
|
||||||
|
if(uip_connr->len == 0) {
|
||||||
|
|
||||||
|
/* The application cannot send more than what is allowed by
|
||||||
|
the mss (the minumum of the MSS and the available
|
||||||
|
window). */
|
||||||
|
if(uip_slen > uip_connr->mss) {
|
||||||
|
uip_slen = uip_connr->mss;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remember how much data we send out now so that we know
|
||||||
|
when everything has been acknowledged. */
|
||||||
|
uip_connr->len = uip_slen;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* If the application already had unacknowledged data, we
|
||||||
|
make sure that the application does not send (i.e.,
|
||||||
|
retransmit) out more than it previously sent out. */
|
||||||
|
uip_slen = uip_connr->len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uip_connr->nrtx = 0;
|
||||||
|
apprexmit:
|
||||||
|
uip_appdata = uip_sappdata;
|
||||||
|
|
||||||
|
/* If the application has data to be sent, or if the incoming
|
||||||
|
packet had new data in it, we must send out a packet. */
|
||||||
|
if(uip_slen > 0 && uip_connr->len > 0) {
|
||||||
|
/* Add the length of the IP and TCP headers. */
|
||||||
|
uip_len = uip_connr->len + UIP_TCPIP_HLEN;
|
||||||
|
/* We always set the ACK flag in response packets. */
|
||||||
|
BUF->flags = TCP_ACK | TCP_PSH;
|
||||||
|
/* Send the packet. */
|
||||||
|
goto tcp_send_noopts;
|
||||||
|
}
|
||||||
|
/* If there is no data to send, just send out a pure ACK if
|
||||||
|
there is newdata. */
|
||||||
|
if(uip_flags & UIP_NEWDATA) {
|
||||||
|
uip_len = UIP_TCPIP_HLEN;
|
||||||
|
BUF->flags = TCP_ACK;
|
||||||
|
goto tcp_send_noopts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goto drop;
|
||||||
|
case UIP_LAST_ACK:
|
||||||
|
/* We can close this connection if the peer has acknowledged our
|
||||||
|
FIN. This is indicated by the UIP_ACKDATA flag. */
|
||||||
|
if(uip_flags & UIP_ACKDATA) {
|
||||||
|
uip_connr->tcpstateflags = UIP_CLOSED;
|
||||||
|
uip_flags = UIP_CLOSE;
|
||||||
|
UIP_APPCALL();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UIP_FIN_WAIT_1:
|
||||||
|
/* The application has closed the connection, but the remote host
|
||||||
|
hasn't closed its end yet. Thus we do nothing but wait for a
|
||||||
|
FIN from the other side. */
|
||||||
|
if(uip_len > 0) {
|
||||||
|
uip_add_rcv_nxt(uip_len);
|
||||||
|
}
|
||||||
|
if(BUF->flags & TCP_FIN) {
|
||||||
|
if(uip_flags & UIP_ACKDATA) {
|
||||||
|
uip_connr->tcpstateflags = UIP_TIME_WAIT;
|
||||||
|
uip_connr->timer = 0;
|
||||||
|
uip_connr->len = 0;
|
||||||
|
} else {
|
||||||
|
uip_connr->tcpstateflags = UIP_CLOSING;
|
||||||
|
}
|
||||||
|
uip_add_rcv_nxt(1);
|
||||||
|
uip_flags = UIP_CLOSE;
|
||||||
|
UIP_APPCALL();
|
||||||
|
goto tcp_send_ack;
|
||||||
|
} else if(uip_flags & UIP_ACKDATA) {
|
||||||
|
uip_connr->tcpstateflags = UIP_FIN_WAIT_2;
|
||||||
|
uip_connr->len = 0;
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
if(uip_len > 0) {
|
||||||
|
goto tcp_send_ack;
|
||||||
|
}
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
case UIP_FIN_WAIT_2:
|
||||||
|
if(uip_len > 0) {
|
||||||
|
uip_add_rcv_nxt(uip_len);
|
||||||
|
}
|
||||||
|
if(BUF->flags & TCP_FIN) {
|
||||||
|
uip_connr->tcpstateflags = UIP_TIME_WAIT;
|
||||||
|
uip_connr->timer = 0;
|
||||||
|
uip_add_rcv_nxt(1);
|
||||||
|
uip_flags = UIP_CLOSE;
|
||||||
|
UIP_APPCALL();
|
||||||
|
goto tcp_send_ack;
|
||||||
|
}
|
||||||
|
if(uip_len > 0) {
|
||||||
|
goto tcp_send_ack;
|
||||||
|
}
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
case UIP_TIME_WAIT:
|
||||||
|
goto tcp_send_ack;
|
||||||
|
|
||||||
|
case UIP_CLOSING:
|
||||||
|
if(uip_flags & UIP_ACKDATA) {
|
||||||
|
uip_connr->tcpstateflags = UIP_TIME_WAIT;
|
||||||
|
uip_connr->timer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
|
||||||
|
/* We jump here when we are ready to send the packet, and just want
|
||||||
|
to set the appropriate TCP sequence numbers in the TCP header. */
|
||||||
|
tcp_send_ack:
|
||||||
|
BUF->flags = TCP_ACK;
|
||||||
|
tcp_send_nodata:
|
||||||
|
uip_len = UIP_IPTCPH_LEN;
|
||||||
|
tcp_send_noopts:
|
||||||
|
BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4;
|
||||||
|
tcp_send:
|
||||||
|
/* We're done with the input processing. We are now ready to send a
|
||||||
|
reply. Our job is to fill in all the fields of the TCP and IP
|
||||||
|
headers before calculating the checksum and finally send the
|
||||||
|
packet. */
|
||||||
|
BUF->ackno[0] = uip_connr->rcv_nxt[0];
|
||||||
|
BUF->ackno[1] = uip_connr->rcv_nxt[1];
|
||||||
|
BUF->ackno[2] = uip_connr->rcv_nxt[2];
|
||||||
|
BUF->ackno[3] = uip_connr->rcv_nxt[3];
|
||||||
|
|
||||||
|
BUF->seqno[0] = uip_connr->snd_nxt[0];
|
||||||
|
BUF->seqno[1] = uip_connr->snd_nxt[1];
|
||||||
|
BUF->seqno[2] = uip_connr->snd_nxt[2];
|
||||||
|
BUF->seqno[3] = uip_connr->snd_nxt[3];
|
||||||
|
|
||||||
|
BUF->proto = UIP_PROTO_TCP;
|
||||||
|
|
||||||
|
BUF->srcport = uip_connr->lport;
|
||||||
|
BUF->destport = uip_connr->rport;
|
||||||
|
|
||||||
|
uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
|
||||||
|
uip_ipaddr_copy(BUF->destipaddr, uip_connr->ripaddr);
|
||||||
|
|
||||||
|
if(uip_connr->tcpstateflags & UIP_STOPPED) {
|
||||||
|
/* If the connection has issued uip_stop(), we advertise a zero
|
||||||
|
window so that the remote host will stop sending data. */
|
||||||
|
BUF->wnd[0] = BUF->wnd[1] = 0;
|
||||||
|
} else {
|
||||||
|
BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
|
||||||
|
BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp_send_noconn:
|
||||||
|
BUF->ttl = UIP_TTL;
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
/* For IPv6, the IP length field does not include the IPv6 IP header
|
||||||
|
length. */
|
||||||
|
BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
|
||||||
|
BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
BUF->len[0] = (uip_len >> 8);
|
||||||
|
BUF->len[1] = (uip_len & 0xff);
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
BUF->urgp[0] = BUF->urgp[1] = 0;
|
||||||
|
|
||||||
|
/* Calculate TCP checksum. */
|
||||||
|
BUF->tcpchksum = 0;
|
||||||
|
BUF->tcpchksum = ~(uip_tcpchksum());
|
||||||
|
|
||||||
|
ip_send_nolen:
|
||||||
|
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
BUF->vtc = 0x60;
|
||||||
|
BUF->tcflow = 0x00;
|
||||||
|
BUF->flow = 0x00;
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
BUF->vhl = 0x45;
|
||||||
|
BUF->tos = 0;
|
||||||
|
BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
|
||||||
|
++ipid;
|
||||||
|
BUF->ipid[0] = ipid >> 8;
|
||||||
|
BUF->ipid[1] = ipid & 0xff;
|
||||||
|
/* Calculate IP checksum. */
|
||||||
|
BUF->ipchksum = 0;
|
||||||
|
BUF->ipchksum = ~(uip_ipchksum());
|
||||||
|
DEBUG_PRINTF("uip ip_send_nolen: chkecum 0x%04x\n", uip_ipchksum());
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
UIP_STAT(++uip_stat.tcp.sent);
|
||||||
|
send:
|
||||||
|
DEBUG_PRINTF("Sending packet with length %d (%d)\n", uip_len,
|
||||||
|
(BUF->len[0] << 8) | BUF->len[1]);
|
||||||
|
|
||||||
|
UIP_STAT(++uip_stat.ip.sent);
|
||||||
|
/* Return and let the caller do the actual transmission. */
|
||||||
|
uip_flags = 0;
|
||||||
|
return;
|
||||||
|
drop:
|
||||||
|
uip_len = 0;
|
||||||
|
uip_flags = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
u16_t
|
||||||
|
htons(u16_t val)
|
||||||
|
{
|
||||||
|
return HTONS(val);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_send(const void *data, int len)
|
||||||
|
{
|
||||||
|
if(len > 0) {
|
||||||
|
uip_slen = len;
|
||||||
|
if(data != uip_sappdata) {
|
||||||
|
memcpy(uip_sappdata, (data), uip_slen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** @} */
|
@ -0,0 +1,1601 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* \addtogroup uip
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Header file for the uIP TCP/IP stack.
|
||||||
|
* \author Adam Dunkels <adam@dunkels.com>
|
||||||
|
*
|
||||||
|
* The uIP TCP/IP stack header file contains definitions for a number
|
||||||
|
* of C macros that are used by uIP programs as well as internal uIP
|
||||||
|
* structures, TCP/IP header structures and function declarations.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2003, Adam Dunkels.
|
||||||
|
* 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 uIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* $Id: uip.h,v 1.40 2006/06/08 07:12:07 adam Exp $
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UIP_H__
|
||||||
|
#define __UIP_H__
|
||||||
|
|
||||||
|
#include "uipopt.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repressentation of an IP address.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef u16_t uip_ip4addr_t[2];
|
||||||
|
typedef u16_t uip_ip6addr_t[8];
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
typedef uip_ip6addr_t uip_ipaddr_t;
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
typedef uip_ip4addr_t uip_ipaddr_t;
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* First, the functions that should be called from the
|
||||||
|
* system. Initialization, the periodic timer and incoming packets are
|
||||||
|
* handled by the following three functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup uipconffunc uIP configuration functions
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* The uIP configuration functions are used for setting run-time
|
||||||
|
* parameters in uIP such as IP addresses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the IP address of this host.
|
||||||
|
*
|
||||||
|
* The IP address is represented as a 4-byte array where the first
|
||||||
|
* octet of the IP address is put in the first member of the 4-byte
|
||||||
|
* array.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
\code
|
||||||
|
|
||||||
|
uip_ipaddr_t addr;
|
||||||
|
|
||||||
|
uip_ipaddr(&addr, 192,168,1,2);
|
||||||
|
uip_sethostaddr(&addr);
|
||||||
|
|
||||||
|
\endcode
|
||||||
|
* \param addr A pointer to an IP address of type uip_ipaddr_t;
|
||||||
|
*
|
||||||
|
* \sa uip_ipaddr()
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_sethostaddr(addr) uip_ipaddr_copy(uip_hostaddr, (addr))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the IP address of this host.
|
||||||
|
*
|
||||||
|
* The IP address is represented as a 4-byte array where the first
|
||||||
|
* octet of the IP address is put in the first member of the 4-byte
|
||||||
|
* array.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
\code
|
||||||
|
uip_ipaddr_t hostaddr;
|
||||||
|
|
||||||
|
uip_gethostaddr(&hostaddr);
|
||||||
|
\endcode
|
||||||
|
* \param addr A pointer to a uip_ipaddr_t variable that will be
|
||||||
|
* filled in with the currently configured IP address.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_gethostaddr(addr) uip_ipaddr_copy((addr), uip_hostaddr)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default router's IP address.
|
||||||
|
*
|
||||||
|
* \param addr A pointer to a uip_ipaddr_t variable containing the IP
|
||||||
|
* address of the default router.
|
||||||
|
*
|
||||||
|
* \sa uip_ipaddr()
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_setdraddr(addr) uip_ipaddr_copy(uip_draddr, (addr))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the netmask.
|
||||||
|
*
|
||||||
|
* \param addr A pointer to a uip_ipaddr_t variable containing the IP
|
||||||
|
* address of the netmask.
|
||||||
|
*
|
||||||
|
* \sa uip_ipaddr()
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_setnetmask(addr) uip_ipaddr_copy(uip_netmask, (addr))
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default router's IP address.
|
||||||
|
*
|
||||||
|
* \param addr A pointer to a uip_ipaddr_t variable that will be
|
||||||
|
* filled in with the IP address of the default router.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_getdraddr(addr) uip_ipaddr_copy((addr), uip_draddr)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the netmask.
|
||||||
|
*
|
||||||
|
* \param addr A pointer to a uip_ipaddr_t variable that will be
|
||||||
|
* filled in with the value of the netmask.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_getnetmask(addr) uip_ipaddr_copy((addr), uip_netmask)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup uipinit uIP initialization functions
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* The uIP initialization functions are used for booting uIP.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uIP initialization function.
|
||||||
|
*
|
||||||
|
* This function should be called at boot up to initilize the uIP
|
||||||
|
* TCP/IP stack.
|
||||||
|
*/
|
||||||
|
void uip_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uIP initialization function.
|
||||||
|
*
|
||||||
|
* This function may be used at boot time to set the initial ip_id.
|
||||||
|
*/
|
||||||
|
void uip_setipid(u16_t id);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup uipdevfunc uIP device driver functions
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* These functions are used by a network device driver for interacting
|
||||||
|
* with uIP.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process an incoming packet.
|
||||||
|
*
|
||||||
|
* This function should be called when the device driver has received
|
||||||
|
* a packet from the network. The packet from the device driver must
|
||||||
|
* be present in the uip_buf buffer, and the length of the packet
|
||||||
|
* should be placed in the uip_len variable.
|
||||||
|
*
|
||||||
|
* When the function returns, there may be an outbound packet placed
|
||||||
|
* in the uip_buf packet buffer. If so, the uip_len variable is set to
|
||||||
|
* the length of the packet. If no packet is to be sent out, the
|
||||||
|
* uip_len variable is set to 0.
|
||||||
|
*
|
||||||
|
* The usual way of calling the function is presented by the source
|
||||||
|
* code below.
|
||||||
|
\code
|
||||||
|
uip_len = devicedriver_poll();
|
||||||
|
if(uip_len > 0) {
|
||||||
|
uip_input();
|
||||||
|
if(uip_len > 0) {
|
||||||
|
devicedriver_send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \note If you are writing a uIP device driver that needs ARP
|
||||||
|
* (Address Resolution Protocol), e.g., when running uIP over
|
||||||
|
* Ethernet, you will need to call the uIP ARP code before calling
|
||||||
|
* this function:
|
||||||
|
\code
|
||||||
|
#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
|
||||||
|
uip_len = ethernet_devicedrver_poll();
|
||||||
|
if(uip_len > 0) {
|
||||||
|
if(BUF->type == HTONS(UIP_ETHTYPE_IP)) {
|
||||||
|
uip_arp_ipin();
|
||||||
|
uip_input();
|
||||||
|
if(uip_len > 0) {
|
||||||
|
uip_arp_out();
|
||||||
|
ethernet_devicedriver_send();
|
||||||
|
}
|
||||||
|
} else if(BUF->type == HTONS(UIP_ETHTYPE_ARP)) {
|
||||||
|
uip_arp_arpin();
|
||||||
|
if(uip_len > 0) {
|
||||||
|
ethernet_devicedriver_send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_input() uip_process(UIP_DATA)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Periodic processing for a connection identified by its number.
|
||||||
|
*
|
||||||
|
* This function does the necessary periodic processing (timers,
|
||||||
|
* polling) for a uIP TCP conneciton, and should be called when the
|
||||||
|
* periodic uIP timer goes off. It should be called for every
|
||||||
|
* connection, regardless of whether they are open of closed.
|
||||||
|
*
|
||||||
|
* When the function returns, it may have an outbound packet waiting
|
||||||
|
* for service in the uIP packet buffer, and if so the uip_len
|
||||||
|
* variable is set to a value larger than zero. The device driver
|
||||||
|
* should be called to send out the packet.
|
||||||
|
*
|
||||||
|
* The ususal way of calling the function is through a for() loop like
|
||||||
|
* this:
|
||||||
|
\code
|
||||||
|
for(i = 0; i < UIP_CONNS; ++i) {
|
||||||
|
uip_periodic(i);
|
||||||
|
if(uip_len > 0) {
|
||||||
|
devicedriver_send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \note If you are writing a uIP device driver that needs ARP
|
||||||
|
* (Address Resolution Protocol), e.g., when running uIP over
|
||||||
|
* Ethernet, you will need to call the uip_arp_out() function before
|
||||||
|
* calling the device driver:
|
||||||
|
\code
|
||||||
|
for(i = 0; i < UIP_CONNS; ++i) {
|
||||||
|
uip_periodic(i);
|
||||||
|
if(uip_len > 0) {
|
||||||
|
uip_arp_out();
|
||||||
|
ethernet_devicedriver_send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \param conn The number of the connection which is to be periodically polled.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_periodic(conn) do { uip_conn = &uip_conns[conn]; \
|
||||||
|
uip_process(UIP_TIMER); } while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define uip_conn_active(conn) (uip_conns[conn].tcpstateflags != UIP_CLOSED)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform periodic processing for a connection identified by a pointer
|
||||||
|
* to its structure.
|
||||||
|
*
|
||||||
|
* Same as uip_periodic() but takes a pointer to the actual uip_conn
|
||||||
|
* struct instead of an integer as its argument. This function can be
|
||||||
|
* used to force periodic processing of a specific connection.
|
||||||
|
*
|
||||||
|
* \param conn A pointer to the uip_conn struct for the connection to
|
||||||
|
* be processed.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_periodic_conn(conn) do { uip_conn = conn; \
|
||||||
|
uip_process(UIP_TIMER); } while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reuqest that a particular connection should be polled.
|
||||||
|
*
|
||||||
|
* Similar to uip_periodic_conn() but does not perform any timer
|
||||||
|
* processing. The application is polled for new data.
|
||||||
|
*
|
||||||
|
* \param conn A pointer to the uip_conn struct for the connection to
|
||||||
|
* be processed.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_poll_conn(conn) do { uip_conn = conn; \
|
||||||
|
uip_process(UIP_POLL_REQUEST); } while (0)
|
||||||
|
|
||||||
|
|
||||||
|
#if UIP_UDP
|
||||||
|
/**
|
||||||
|
* Periodic processing for a UDP connection identified by its number.
|
||||||
|
*
|
||||||
|
* This function is essentially the same as uip_periodic(), but for
|
||||||
|
* UDP connections. It is called in a similar fashion as the
|
||||||
|
* uip_periodic() function:
|
||||||
|
\code
|
||||||
|
for(i = 0; i < UIP_UDP_CONNS; i++) {
|
||||||
|
uip_udp_periodic(i);
|
||||||
|
if(uip_len > 0) {
|
||||||
|
devicedriver_send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \note As for the uip_periodic() function, special care has to be
|
||||||
|
* taken when using uIP together with ARP and Ethernet:
|
||||||
|
\code
|
||||||
|
for(i = 0; i < UIP_UDP_CONNS; i++) {
|
||||||
|
uip_udp_periodic(i);
|
||||||
|
if(uip_len > 0) {
|
||||||
|
uip_arp_out();
|
||||||
|
ethernet_devicedriver_send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \param conn The number of the UDP connection to be processed.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_udp_periodic(conn) do { uip_udp_conn = &uip_udp_conns[conn]; \
|
||||||
|
uip_process(UIP_UDP_TIMER); } while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Periodic processing for a UDP connection identified by a pointer to
|
||||||
|
* its structure.
|
||||||
|
*
|
||||||
|
* Same as uip_udp_periodic() but takes a pointer to the actual
|
||||||
|
* uip_conn struct instead of an integer as its argument. This
|
||||||
|
* function can be used to force periodic processing of a specific
|
||||||
|
* connection.
|
||||||
|
*
|
||||||
|
* \param conn A pointer to the uip_udp_conn struct for the connection
|
||||||
|
* to be processed.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_udp_periodic_conn(conn) do { uip_udp_conn = conn; \
|
||||||
|
uip_process(UIP_UDP_TIMER); } while (0)
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* UIP_UDP */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The uIP packet buffer.
|
||||||
|
*
|
||||||
|
* The uip_buf array is used to hold incoming and outgoing
|
||||||
|
* packets. The device driver should place incoming data into this
|
||||||
|
* buffer. When sending data, the device driver should read the link
|
||||||
|
* level headers and the TCP/IP headers from this buffer. The size of
|
||||||
|
* the link level headers is configured by the UIP_LLH_LEN define.
|
||||||
|
*
|
||||||
|
* \note The application data need not be placed in this buffer, so
|
||||||
|
* the device driver must read it from the place pointed to by the
|
||||||
|
* uip_appdata pointer as illustrated by the following example:
|
||||||
|
\code
|
||||||
|
void
|
||||||
|
devicedriver_send(void)
|
||||||
|
{
|
||||||
|
hwsend(&uip_buf[0], UIP_LLH_LEN);
|
||||||
|
if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
|
||||||
|
hwsend(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN);
|
||||||
|
} else {
|
||||||
|
hwsend(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN);
|
||||||
|
hwsend(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
extern u8_t uip_buf[UIP_BUFSIZE+2];
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Functions that are used by the uIP application program. Opening and
|
||||||
|
* closing connections, sending and receiving data, etc. is all
|
||||||
|
* handled by the functions below.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \defgroup uipappfunc uIP application functions
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* Functions used by an application running of top of uIP.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start listening to the specified port.
|
||||||
|
*
|
||||||
|
* \note Since this function expects the port number in network byte
|
||||||
|
* order, a conversion using HTONS() or htons() is necessary.
|
||||||
|
*
|
||||||
|
\code
|
||||||
|
uip_listen(HTONS(80));
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \param port A 16-bit port number in network byte order.
|
||||||
|
*/
|
||||||
|
void uip_listen(u16_t port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop listening to the specified port.
|
||||||
|
*
|
||||||
|
* \note Since this function expects the port number in network byte
|
||||||
|
* order, a conversion using HTONS() or htons() is necessary.
|
||||||
|
*
|
||||||
|
\code
|
||||||
|
uip_unlisten(HTONS(80));
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \param port A 16-bit port number in network byte order.
|
||||||
|
*/
|
||||||
|
void uip_unlisten(u16_t port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to a remote host using TCP.
|
||||||
|
*
|
||||||
|
* This function is used to start a new connection to the specified
|
||||||
|
* port on the specied host. It allocates a new connection identifier,
|
||||||
|
* sets the connection to the SYN_SENT state and sets the
|
||||||
|
* retransmission timer to 0. This will cause a TCP SYN segment to be
|
||||||
|
* sent out the next time this connection is periodically processed,
|
||||||
|
* which usually is done within 0.5 seconds after the call to
|
||||||
|
* uip_connect().
|
||||||
|
*
|
||||||
|
* \note This function is avaliable only if support for active open
|
||||||
|
* has been configured by defining UIP_ACTIVE_OPEN to 1 in uipopt.h.
|
||||||
|
*
|
||||||
|
* \note Since this function requires the port number to be in network
|
||||||
|
* byte order, a conversion using HTONS() or htons() is necessary.
|
||||||
|
*
|
||||||
|
\code
|
||||||
|
uip_ipaddr_t ipaddr;
|
||||||
|
|
||||||
|
uip_ipaddr(&ipaddr, 192,168,1,2);
|
||||||
|
uip_connect(&ipaddr, HTONS(80));
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \param ripaddr The IP address of the remote hot.
|
||||||
|
*
|
||||||
|
* \param port A 16-bit port number in network byte order.
|
||||||
|
*
|
||||||
|
* \return A pointer to the uIP connection identifier for the new connection,
|
||||||
|
* or NULL if no connection could be allocated.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct uip_conn *uip_connect(uip_ipaddr_t *ripaddr, u16_t port);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \internal
|
||||||
|
*
|
||||||
|
* Check if a connection has outstanding (i.e., unacknowledged) data.
|
||||||
|
*
|
||||||
|
* \param conn A pointer to the uip_conn structure for the connection.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_outstanding(conn) ((conn)->len)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send data on the current connection.
|
||||||
|
*
|
||||||
|
* This function is used to send out a single segment of TCP
|
||||||
|
* data. Only applications that have been invoked by uIP for event
|
||||||
|
* processing can send data.
|
||||||
|
*
|
||||||
|
* The amount of data that actually is sent out after a call to this
|
||||||
|
* funcion is determined by the maximum amount of data TCP allows. uIP
|
||||||
|
* will automatically crop the data so that only the appropriate
|
||||||
|
* amount of data is sent. The function uip_mss() can be used to query
|
||||||
|
* uIP for the amount of data that actually will be sent.
|
||||||
|
*
|
||||||
|
* \note This function does not guarantee that the sent data will
|
||||||
|
* arrive at the destination. If the data is lost in the network, the
|
||||||
|
* application will be invoked with the uip_rexmit() event being
|
||||||
|
* set. The application will then have to resend the data using this
|
||||||
|
* function.
|
||||||
|
*
|
||||||
|
* \param data A pointer to the data which is to be sent.
|
||||||
|
*
|
||||||
|
* \param len The maximum amount of data bytes to be sent.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
void uip_send(const void *data, int len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of any incoming data that is currently avaliable (if avaliable)
|
||||||
|
* in the uip_appdata buffer.
|
||||||
|
*
|
||||||
|
* The test function uip_data() must first be used to check if there
|
||||||
|
* is any data available at all.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
/*void uip_datalen(void);*/
|
||||||
|
#define uip_datalen() uip_len
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of any out-of-band data (urgent data) that has arrived
|
||||||
|
* on the connection.
|
||||||
|
*
|
||||||
|
* \note The configuration parameter UIP_URGDATA must be set for this
|
||||||
|
* function to be enabled.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_urgdatalen() uip_urglen
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the current connection.
|
||||||
|
*
|
||||||
|
* This function will close the current connection in a nice way.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_close() (uip_flags = UIP_CLOSE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abort the current connection.
|
||||||
|
*
|
||||||
|
* This function will abort (reset) the current connection, and is
|
||||||
|
* usually used when an error has occured that prevents using the
|
||||||
|
* uip_close() function.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_abort() (uip_flags = UIP_ABORT)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the sending host to stop sending data.
|
||||||
|
*
|
||||||
|
* This function will close our receiver's window so that we stop
|
||||||
|
* receiving data for the current connection.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_stop() (uip_conn->tcpstateflags |= UIP_STOPPED)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find out if the current connection has been previously stopped with
|
||||||
|
* uip_stop().
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_stopped(conn) ((conn)->tcpstateflags & UIP_STOPPED)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restart the current connection, if is has previously been stopped
|
||||||
|
* with uip_stop().
|
||||||
|
*
|
||||||
|
* This function will open the receiver's window again so that we
|
||||||
|
* start receiving data for the current connection.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_restart() do { uip_flags |= UIP_NEWDATA; \
|
||||||
|
uip_conn->tcpstateflags &= ~UIP_STOPPED; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
/* uIP tests that can be made to determine in what state the current
|
||||||
|
connection is, and what the application function should do. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the current connection a UDP connection?
|
||||||
|
*
|
||||||
|
* This function checks whether the current connection is a UDP connection.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define uip_udpconnection() (uip_conn == NULL)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is new incoming data available?
|
||||||
|
*
|
||||||
|
* Will reduce to non-zero if there is new data for the application
|
||||||
|
* present at the uip_appdata pointer. The size of the data is
|
||||||
|
* avaliable through the uip_len variable.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_newdata() (uip_flags & UIP_NEWDATA)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has previously sent data been acknowledged?
|
||||||
|
*
|
||||||
|
* Will reduce to non-zero if the previously sent data has been
|
||||||
|
* acknowledged by the remote host. This means that the application
|
||||||
|
* can send new data.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_acked() (uip_flags & UIP_ACKDATA)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has the connection just been connected?
|
||||||
|
*
|
||||||
|
* Reduces to non-zero if the current connection has been connected to
|
||||||
|
* a remote host. This will happen both if the connection has been
|
||||||
|
* actively opened (with uip_connect()) or passively opened (with
|
||||||
|
* uip_listen()).
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_connected() (uip_flags & UIP_CONNECTED)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has the connection been closed by the other end?
|
||||||
|
*
|
||||||
|
* Is non-zero if the connection has been closed by the remote
|
||||||
|
* host. The application may then do the necessary clean-ups.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_closed() (uip_flags & UIP_CLOSE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has the connection been aborted by the other end?
|
||||||
|
*
|
||||||
|
* Non-zero if the current connection has been aborted (reset) by the
|
||||||
|
* remote host.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_aborted() (uip_flags & UIP_ABORT)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has the connection timed out?
|
||||||
|
*
|
||||||
|
* Non-zero if the current connection has been aborted due to too many
|
||||||
|
* retransmissions.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_timedout() (uip_flags & UIP_TIMEDOUT)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do we need to retransmit previously data?
|
||||||
|
*
|
||||||
|
* Reduces to non-zero if the previously sent data has been lost in
|
||||||
|
* the network, and the application should retransmit it. The
|
||||||
|
* application should send the exact same data as it did the last
|
||||||
|
* time, using the uip_send() function.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_rexmit() (uip_flags & UIP_REXMIT)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the connection being polled by uIP?
|
||||||
|
*
|
||||||
|
* Is non-zero if the reason the application is invoked is that the
|
||||||
|
* current connection has been idle for a while and should be
|
||||||
|
* polled.
|
||||||
|
*
|
||||||
|
* The polling event can be used for sending data without having to
|
||||||
|
* wait for the remote host to send data.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_poll() (uip_flags & UIP_POLL)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the initial maxium segment size (MSS) of the current
|
||||||
|
* connection.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_initialmss() (uip_conn->initialmss)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current maxium segment size that can be sent on the current
|
||||||
|
* connection.
|
||||||
|
*
|
||||||
|
* The current maxiumum segment size that can be sent on the
|
||||||
|
* connection is computed from the receiver's window and the MSS of
|
||||||
|
* the connection (which also is available by calling
|
||||||
|
* uip_initialmss()).
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_mss() (uip_conn->mss)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up a new UDP connection.
|
||||||
|
*
|
||||||
|
* This function sets up a new UDP connection. The function will
|
||||||
|
* automatically allocate an unused local port for the new
|
||||||
|
* connection. However, another port can be chosen by using the
|
||||||
|
* uip_udp_bind() call, after the uip_udp_new() function has been
|
||||||
|
* called.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
\code
|
||||||
|
uip_ipaddr_t addr;
|
||||||
|
struct uip_udp_conn *c;
|
||||||
|
|
||||||
|
uip_ipaddr(&addr, 192,168,2,1);
|
||||||
|
c = uip_udp_new(&addr, HTONS(12345));
|
||||||
|
if(c != NULL) {
|
||||||
|
uip_udp_bind(c, HTONS(12344));
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
* \param ripaddr The IP address of the remote host.
|
||||||
|
*
|
||||||
|
* \param rport The remote port number in network byte order.
|
||||||
|
*
|
||||||
|
* \return The uip_udp_conn structure for the new connection or NULL
|
||||||
|
* if no connection could be allocated.
|
||||||
|
*/
|
||||||
|
struct uip_udp_conn *uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removed a UDP connection.
|
||||||
|
*
|
||||||
|
* \param conn A pointer to the uip_udp_conn structure for the connection.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_udp_remove(conn) (conn)->lport = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a UDP connection to a local port.
|
||||||
|
*
|
||||||
|
* \param conn A pointer to the uip_udp_conn structure for the
|
||||||
|
* connection.
|
||||||
|
*
|
||||||
|
* \param port The local port number, in network byte order.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_udp_bind(conn, port) (conn)->lport = port
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a UDP datagram of length len on the current connection.
|
||||||
|
*
|
||||||
|
* This function can only be called in response to a UDP event (poll
|
||||||
|
* or newdata). The data must be present in the uip_buf buffer, at the
|
||||||
|
* place pointed to by the uip_appdata pointer.
|
||||||
|
*
|
||||||
|
* \param len The length of the data in the uip_buf buffer.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_udp_send(len) uip_send((char *)uip_appdata, len)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/* uIP convenience and converting functions. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup uipconvfunc uIP conversion functions
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* These functions can be used for converting between different data
|
||||||
|
* formats used by uIP.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an IP address from four bytes.
|
||||||
|
*
|
||||||
|
* This function constructs an IP address of the type that uIP handles
|
||||||
|
* internally from four bytes. The function is handy for specifying IP
|
||||||
|
* addresses to use with e.g. the uip_connect() function.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
\code
|
||||||
|
uip_ipaddr_t ipaddr;
|
||||||
|
struct uip_conn *c;
|
||||||
|
|
||||||
|
uip_ipaddr(&ipaddr, 192,168,1,2);
|
||||||
|
c = uip_connect(&ipaddr, HTONS(80));
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \param addr A pointer to a uip_ipaddr_t variable that will be
|
||||||
|
* filled in with the IP address.
|
||||||
|
*
|
||||||
|
* \param addr0 The first octet of the IP address.
|
||||||
|
* \param addr1 The second octet of the IP address.
|
||||||
|
* \param addr2 The third octet of the IP address.
|
||||||
|
* \param addr3 The forth octet of the IP address.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_ipaddr(addr, addr0,addr1,addr2,addr3) do { \
|
||||||
|
((u16_t *)(addr))[0] = HTONS(((addr0) << 8) | (addr1)); \
|
||||||
|
((u16_t *)(addr))[1] = HTONS(((addr2) << 8) | (addr3)); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an IPv6 address from eight 16-bit words.
|
||||||
|
*
|
||||||
|
* This function constructs an IPv6 address.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_ip6addr(addr, addr0,addr1,addr2,addr3,addr4,addr5,addr6,addr7) do { \
|
||||||
|
((u16_t *)(addr))[0] = HTONS((addr0)); \
|
||||||
|
((u16_t *)(addr))[1] = HTONS((addr1)); \
|
||||||
|
((u16_t *)(addr))[2] = HTONS((addr2)); \
|
||||||
|
((u16_t *)(addr))[3] = HTONS((addr3)); \
|
||||||
|
((u16_t *)(addr))[4] = HTONS((addr4)); \
|
||||||
|
((u16_t *)(addr))[5] = HTONS((addr5)); \
|
||||||
|
((u16_t *)(addr))[6] = HTONS((addr6)); \
|
||||||
|
((u16_t *)(addr))[7] = HTONS((addr7)); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy an IP address to another IP address.
|
||||||
|
*
|
||||||
|
* Copies an IP address from one place to another.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
\code
|
||||||
|
uip_ipaddr_t ipaddr1, ipaddr2;
|
||||||
|
|
||||||
|
uip_ipaddr(&ipaddr1, 192,16,1,2);
|
||||||
|
uip_ipaddr_copy(&ipaddr2, &ipaddr1);
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \param dest The destination for the copy.
|
||||||
|
* \param src The source from where to copy.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#if !UIP_CONF_IPV6
|
||||||
|
#define uip_ipaddr_copy(dest, src) do { \
|
||||||
|
((u16_t *)dest)[0] = ((u16_t *)src)[0]; \
|
||||||
|
((u16_t *)dest)[1] = ((u16_t *)src)[1]; \
|
||||||
|
} while(0)
|
||||||
|
#else /* !UIP_CONF_IPV6 */
|
||||||
|
#define uip_ipaddr_copy(dest, src) memcpy(dest, src, sizeof(uip_ip6addr_t))
|
||||||
|
#endif /* !UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two IP addresses
|
||||||
|
*
|
||||||
|
* Compares two IP addresses.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
\code
|
||||||
|
uip_ipaddr_t ipaddr1, ipaddr2;
|
||||||
|
|
||||||
|
uip_ipaddr(&ipaddr1, 192,16,1,2);
|
||||||
|
if(uip_ipaddr_cmp(&ipaddr2, &ipaddr1)) {
|
||||||
|
printf("They are the same");
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \param addr1 The first IP address.
|
||||||
|
* \param addr2 The second IP address.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#if !UIP_CONF_IPV6
|
||||||
|
#define uip_ipaddr_cmp(addr1, addr2) (((u16_t *)addr1)[0] == ((u16_t *)addr2)[0] && \
|
||||||
|
((u16_t *)addr1)[1] == ((u16_t *)addr2)[1])
|
||||||
|
#else /* !UIP_CONF_IPV6 */
|
||||||
|
#define uip_ipaddr_cmp(addr1, addr2) (memcmp(addr1, addr2, sizeof(uip_ip6addr_t)) == 0)
|
||||||
|
#endif /* !UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two IP addresses with netmasks
|
||||||
|
*
|
||||||
|
* Compares two IP addresses with netmasks. The masks are used to mask
|
||||||
|
* out the bits that are to be compared.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
\code
|
||||||
|
uip_ipaddr_t ipaddr1, ipaddr2, mask;
|
||||||
|
|
||||||
|
uip_ipaddr(&mask, 255,255,255,0);
|
||||||
|
uip_ipaddr(&ipaddr1, 192,16,1,2);
|
||||||
|
uip_ipaddr(&ipaddr2, 192,16,1,3);
|
||||||
|
if(uip_ipaddr_maskcmp(&ipaddr1, &ipaddr2, &mask)) {
|
||||||
|
printf("They are the same");
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \param addr1 The first IP address.
|
||||||
|
* \param addr2 The second IP address.
|
||||||
|
* \param mask The netmask.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_ipaddr_maskcmp(addr1, addr2, mask) \
|
||||||
|
(((((u16_t *)addr1)[0] & ((u16_t *)mask)[0]) == \
|
||||||
|
(((u16_t *)addr2)[0] & ((u16_t *)mask)[0])) && \
|
||||||
|
((((u16_t *)addr1)[1] & ((u16_t *)mask)[1]) == \
|
||||||
|
(((u16_t *)addr2)[1] & ((u16_t *)mask)[1])))
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mask out the network part of an IP address.
|
||||||
|
*
|
||||||
|
* Masks out the network part of an IP address, given the address and
|
||||||
|
* the netmask.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
\code
|
||||||
|
uip_ipaddr_t ipaddr1, ipaddr2, netmask;
|
||||||
|
|
||||||
|
uip_ipaddr(&ipaddr1, 192,16,1,2);
|
||||||
|
uip_ipaddr(&netmask, 255,255,255,0);
|
||||||
|
uip_ipaddr_mask(&ipaddr2, &ipaddr1, &netmask);
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* In the example above, the variable "ipaddr2" will contain the IP
|
||||||
|
* address 192.168.1.0.
|
||||||
|
*
|
||||||
|
* \param dest Where the result is to be placed.
|
||||||
|
* \param src The IP address.
|
||||||
|
* \param mask The netmask.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_ipaddr_mask(dest, src, mask) do { \
|
||||||
|
((u16_t *)dest)[0] = ((u16_t *)src)[0] & ((u16_t *)mask)[0]; \
|
||||||
|
((u16_t *)dest)[1] = ((u16_t *)src)[1] & ((u16_t *)mask)[1]; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pick the first octet of an IP address.
|
||||||
|
*
|
||||||
|
* Picks out the first octet of an IP address.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
\code
|
||||||
|
uip_ipaddr_t ipaddr;
|
||||||
|
u8_t octet;
|
||||||
|
|
||||||
|
uip_ipaddr(&ipaddr, 1,2,3,4);
|
||||||
|
octet = uip_ipaddr1(&ipaddr);
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* In the example above, the variable "octet" will contain the value 1.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_ipaddr1(addr) (htons(((u16_t *)(addr))[0]) >> 8)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pick the second octet of an IP address.
|
||||||
|
*
|
||||||
|
* Picks out the second octet of an IP address.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
\code
|
||||||
|
uip_ipaddr_t ipaddr;
|
||||||
|
u8_t octet;
|
||||||
|
|
||||||
|
uip_ipaddr(&ipaddr, 1,2,3,4);
|
||||||
|
octet = uip_ipaddr2(&ipaddr);
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* In the example above, the variable "octet" will contain the value 2.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_ipaddr2(addr) (htons(((u16_t *)(addr))[0]) & 0xff)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pick the third octet of an IP address.
|
||||||
|
*
|
||||||
|
* Picks out the third octet of an IP address.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
\code
|
||||||
|
uip_ipaddr_t ipaddr;
|
||||||
|
u8_t octet;
|
||||||
|
|
||||||
|
uip_ipaddr(&ipaddr, 1,2,3,4);
|
||||||
|
octet = uip_ipaddr3(&ipaddr);
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* In the example above, the variable "octet" will contain the value 3.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_ipaddr3(addr) (htons(((u16_t *)(addr))[1]) >> 8)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pick the fourth octet of an IP address.
|
||||||
|
*
|
||||||
|
* Picks out the fourth octet of an IP address.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
\code
|
||||||
|
uip_ipaddr_t ipaddr;
|
||||||
|
u8_t octet;
|
||||||
|
|
||||||
|
uip_ipaddr(&ipaddr, 1,2,3,4);
|
||||||
|
octet = uip_ipaddr4(&ipaddr);
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* In the example above, the variable "octet" will contain the value 4.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_ipaddr4(addr) (htons(((u16_t *)(addr))[1]) & 0xff)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert 16-bit quantity from host byte order to network byte order.
|
||||||
|
*
|
||||||
|
* This macro is primarily used for converting constants from host
|
||||||
|
* byte order to network byte order. For converting variables to
|
||||||
|
* network byte order, use the htons() function instead.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifndef HTONS
|
||||||
|
# if UIP_BYTE_ORDER == UIP_BIG_ENDIAN
|
||||||
|
# define HTONS(n) (n)
|
||||||
|
# else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
|
||||||
|
# define HTONS(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8))
|
||||||
|
# endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
|
||||||
|
#else
|
||||||
|
#error "HTONS already defined!"
|
||||||
|
#endif /* HTONS */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert 16-bit quantity from host byte order to network byte order.
|
||||||
|
*
|
||||||
|
* This function is primarily used for converting variables from host
|
||||||
|
* byte order to network byte order. For converting constants to
|
||||||
|
* network byte order, use the HTONS() macro instead.
|
||||||
|
*/
|
||||||
|
#ifndef htons
|
||||||
|
u16_t htons(u16_t val);
|
||||||
|
#endif /* htons */
|
||||||
|
#ifndef ntohs
|
||||||
|
#define ntohs htons
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer to the application data in the packet buffer.
|
||||||
|
*
|
||||||
|
* This pointer points to the application data when the application is
|
||||||
|
* called. If the application wishes to send data, the application may
|
||||||
|
* use this space to write the data into before calling uip_send().
|
||||||
|
*/
|
||||||
|
extern void *uip_appdata;
|
||||||
|
|
||||||
|
#if UIP_URGDATA > 0
|
||||||
|
/* u8_t *uip_urgdata:
|
||||||
|
*
|
||||||
|
* This pointer points to any urgent data that has been received. Only
|
||||||
|
* present if compiled with support for urgent data (UIP_URGDATA).
|
||||||
|
*/
|
||||||
|
extern void *uip_urgdata;
|
||||||
|
#endif /* UIP_URGDATA > 0 */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup uipdrivervars Variables used in uIP device drivers
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* uIP has a few global variables that are used in device drivers for
|
||||||
|
* uIP.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of the packet in the uip_buf buffer.
|
||||||
|
*
|
||||||
|
* The global variable uip_len holds the length of the packet in the
|
||||||
|
* uip_buf buffer.
|
||||||
|
*
|
||||||
|
* When the network device driver calls the uIP input function,
|
||||||
|
* uip_len should be set to the length of the packet in the uip_buf
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* When sending packets, the device driver should use the contents of
|
||||||
|
* the uip_len variable to determine the length of the outgoing
|
||||||
|
* packet.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
extern u16_t uip_len;
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#if UIP_URGDATA > 0
|
||||||
|
extern u16_t uip_urglen, uip_surglen;
|
||||||
|
#endif /* UIP_URGDATA > 0 */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of a uIP TCP connection.
|
||||||
|
*
|
||||||
|
* The uip_conn structure is used for identifying a connection. All
|
||||||
|
* but one field in the structure are to be considered read-only by an
|
||||||
|
* application. The only exception is the appstate field whos purpose
|
||||||
|
* is to let the application store application-specific state (e.g.,
|
||||||
|
* file pointers) for the connection. The type of this field is
|
||||||
|
* configured in the "uipopt.h" header file.
|
||||||
|
*/
|
||||||
|
struct uip_conn {
|
||||||
|
uip_ipaddr_t ripaddr; /**< The IP address of the remote host. */
|
||||||
|
|
||||||
|
u16_t lport; /**< The local TCP port, in network byte order. */
|
||||||
|
u16_t rport; /**< The local remote TCP port, in network byte
|
||||||
|
order. */
|
||||||
|
|
||||||
|
u8_t rcv_nxt[4]; /**< The sequence number that we expect to
|
||||||
|
receive next. */
|
||||||
|
u8_t snd_nxt[4]; /**< The sequence number that was last sent by
|
||||||
|
us. */
|
||||||
|
u16_t len; /**< Length of the data that was previously sent. */
|
||||||
|
u16_t mss; /**< Current maximum segment size for the
|
||||||
|
connection. */
|
||||||
|
u16_t initialmss; /**< Initial maximum segment size for the
|
||||||
|
connection. */
|
||||||
|
u8_t sa; /**< Retransmission time-out calculation state
|
||||||
|
variable. */
|
||||||
|
u8_t sv; /**< Retransmission time-out calculation state
|
||||||
|
variable. */
|
||||||
|
u8_t rto; /**< Retransmission time-out. */
|
||||||
|
u8_t tcpstateflags; /**< TCP state and flags. */
|
||||||
|
u8_t timer; /**< The retransmission timer. */
|
||||||
|
u8_t nrtx; /**< The number of retransmissions for the last
|
||||||
|
segment sent. */
|
||||||
|
|
||||||
|
/** The application state. */
|
||||||
|
uip_tcp_appstate_t appstate;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer to the current TCP connection.
|
||||||
|
*
|
||||||
|
* The uip_conn pointer can be used to access the current TCP
|
||||||
|
* connection.
|
||||||
|
*/
|
||||||
|
extern struct uip_conn *uip_conn;
|
||||||
|
/* The array containing all uIP connections. */
|
||||||
|
extern struct uip_conn uip_conns[UIP_CONNS];
|
||||||
|
/**
|
||||||
|
* \addtogroup uiparch
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 4-byte array used for the 32-bit sequence number calculations.
|
||||||
|
*/
|
||||||
|
extern u8_t uip_acc32[4];
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
|
||||||
|
#if UIP_UDP
|
||||||
|
/**
|
||||||
|
* Representation of a uIP UDP connection.
|
||||||
|
*/
|
||||||
|
struct uip_udp_conn {
|
||||||
|
uip_ipaddr_t ripaddr; /**< The IP address of the remote peer. */
|
||||||
|
u16_t lport; /**< The local port number in network byte order. */
|
||||||
|
u16_t rport; /**< The remote port number in network byte order. */
|
||||||
|
u8_t ttl; /**< Default time-to-live. */
|
||||||
|
|
||||||
|
/** The application state. */
|
||||||
|
uip_udp_appstate_t appstate;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current UDP connection.
|
||||||
|
*/
|
||||||
|
extern struct uip_udp_conn *uip_udp_conn;
|
||||||
|
extern struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
|
||||||
|
#endif /* UIP_UDP */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The structure holding the TCP/IP statistics that are gathered if
|
||||||
|
* UIP_STATISTICS is set to 1.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct uip_stats {
|
||||||
|
struct {
|
||||||
|
uip_stats_t drop; /**< Number of dropped packets at the IP
|
||||||
|
layer. */
|
||||||
|
uip_stats_t recv; /**< Number of received packets at the IP
|
||||||
|
layer. */
|
||||||
|
uip_stats_t sent; /**< Number of sent packets at the IP
|
||||||
|
layer. */
|
||||||
|
uip_stats_t vhlerr; /**< Number of packets dropped due to wrong
|
||||||
|
IP version or header length. */
|
||||||
|
uip_stats_t hblenerr; /**< Number of packets dropped due to wrong
|
||||||
|
IP length, high byte. */
|
||||||
|
uip_stats_t lblenerr; /**< Number of packets dropped due to wrong
|
||||||
|
IP length, low byte. */
|
||||||
|
uip_stats_t fragerr; /**< Number of packets dropped since they
|
||||||
|
were IP fragments. */
|
||||||
|
uip_stats_t chkerr; /**< Number of packets dropped due to IP
|
||||||
|
checksum errors. */
|
||||||
|
uip_stats_t protoerr; /**< Number of packets dropped since they
|
||||||
|
were neither ICMP, UDP nor TCP. */
|
||||||
|
} ip; /**< IP statistics. */
|
||||||
|
struct {
|
||||||
|
uip_stats_t drop; /**< Number of dropped ICMP packets. */
|
||||||
|
uip_stats_t recv; /**< Number of received ICMP packets. */
|
||||||
|
uip_stats_t sent; /**< Number of sent ICMP packets. */
|
||||||
|
uip_stats_t typeerr; /**< Number of ICMP packets with a wrong
|
||||||
|
type. */
|
||||||
|
} icmp; /**< ICMP statistics. */
|
||||||
|
struct {
|
||||||
|
uip_stats_t drop; /**< Number of dropped TCP segments. */
|
||||||
|
uip_stats_t recv; /**< Number of recived TCP segments. */
|
||||||
|
uip_stats_t sent; /**< Number of sent TCP segments. */
|
||||||
|
uip_stats_t chkerr; /**< Number of TCP segments with a bad
|
||||||
|
checksum. */
|
||||||
|
uip_stats_t ackerr; /**< Number of TCP segments with a bad ACK
|
||||||
|
number. */
|
||||||
|
uip_stats_t rst; /**< Number of recevied TCP RST (reset) segments. */
|
||||||
|
uip_stats_t rexmit; /**< Number of retransmitted TCP segments. */
|
||||||
|
uip_stats_t syndrop; /**< Number of dropped SYNs due to too few
|
||||||
|
connections was avaliable. */
|
||||||
|
uip_stats_t synrst; /**< Number of SYNs for closed ports,
|
||||||
|
triggering a RST. */
|
||||||
|
} tcp; /**< TCP statistics. */
|
||||||
|
#if UIP_UDP
|
||||||
|
struct {
|
||||||
|
uip_stats_t drop; /**< Number of dropped UDP segments. */
|
||||||
|
uip_stats_t recv; /**< Number of recived UDP segments. */
|
||||||
|
uip_stats_t sent; /**< Number of sent UDP segments. */
|
||||||
|
uip_stats_t chkerr; /**< Number of UDP segments with a bad
|
||||||
|
checksum. */
|
||||||
|
} udp; /**< UDP statistics. */
|
||||||
|
#endif /* UIP_UDP */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The uIP TCP/IP statistics.
|
||||||
|
*
|
||||||
|
* This is the variable in which the uIP TCP/IP statistics are gathered.
|
||||||
|
*/
|
||||||
|
extern struct uip_stats uip_stat;
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* All the stuff below this point is internal to uIP and should not be
|
||||||
|
* used directly by an application or by a device driver.
|
||||||
|
*/
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* u8_t uip_flags:
|
||||||
|
*
|
||||||
|
* When the application is called, uip_flags will contain the flags
|
||||||
|
* that are defined in this file. Please read below for more
|
||||||
|
* infomation.
|
||||||
|
*/
|
||||||
|
extern u8_t uip_flags;
|
||||||
|
|
||||||
|
/* The following flags may be set in the global variable uip_flags
|
||||||
|
before calling the application callback. The UIP_ACKDATA,
|
||||||
|
UIP_NEWDATA, and UIP_CLOSE flags may both be set at the same time,
|
||||||
|
whereas the others are mutualy exclusive. Note that these flags
|
||||||
|
should *NOT* be accessed directly, but only through the uIP
|
||||||
|
functions/macros. */
|
||||||
|
|
||||||
|
#define UIP_ACKDATA 1 /* Signifies that the outstanding data was
|
||||||
|
acked and the application should send
|
||||||
|
out new data instead of retransmitting
|
||||||
|
the last data. */
|
||||||
|
#define UIP_NEWDATA 2 /* Flags the fact that the peer has sent
|
||||||
|
us new data. */
|
||||||
|
#define UIP_REXMIT 4 /* Tells the application to retransmit the
|
||||||
|
data that was last sent. */
|
||||||
|
#define UIP_POLL 8 /* Used for polling the application, to
|
||||||
|
check if the application has data that
|
||||||
|
it wants to send. */
|
||||||
|
#define UIP_CLOSE 16 /* The remote host has closed the
|
||||||
|
connection, thus the connection has
|
||||||
|
gone away. Or the application signals
|
||||||
|
that it wants to close the
|
||||||
|
connection. */
|
||||||
|
#define UIP_ABORT 32 /* The remote host has aborted the
|
||||||
|
connection, thus the connection has
|
||||||
|
gone away. Or the application signals
|
||||||
|
that it wants to abort the
|
||||||
|
connection. */
|
||||||
|
#define UIP_CONNECTED 64 /* We have got a connection from a remote
|
||||||
|
host and have set up a new connection
|
||||||
|
for it, or an active connection has
|
||||||
|
been successfully established. */
|
||||||
|
|
||||||
|
#define UIP_TIMEDOUT 128 /* The connection has been aborted due to
|
||||||
|
too many retransmissions. */
|
||||||
|
|
||||||
|
/* uip_process(flag):
|
||||||
|
*
|
||||||
|
* The actual uIP function which does all the work.
|
||||||
|
*/
|
||||||
|
void uip_process(u8_t flag);
|
||||||
|
|
||||||
|
/* The following flags are passed as an argument to the uip_process()
|
||||||
|
function. They are used to distinguish between the two cases where
|
||||||
|
uip_process() is called. It can be called either because we have
|
||||||
|
incoming data that should be processed, or because the periodic
|
||||||
|
timer has fired. These values are never used directly, but only in
|
||||||
|
the macrose defined in this file. */
|
||||||
|
|
||||||
|
#define UIP_DATA 1 /* Tells uIP that there is incoming
|
||||||
|
data in the uip_buf buffer. The
|
||||||
|
length of the data is stored in the
|
||||||
|
global variable uip_len. */
|
||||||
|
#define UIP_TIMER 2 /* Tells uIP that the periodic timer
|
||||||
|
has fired. */
|
||||||
|
#define UIP_POLL_REQUEST 3 /* Tells uIP that a connection should
|
||||||
|
be polled. */
|
||||||
|
#define UIP_UDP_SEND_CONN 4 /* Tells uIP that a UDP datagram
|
||||||
|
should be constructed in the
|
||||||
|
uip_buf buffer. */
|
||||||
|
#if UIP_UDP
|
||||||
|
#define UIP_UDP_TIMER 5
|
||||||
|
#endif /* UIP_UDP */
|
||||||
|
|
||||||
|
/* The TCP states used in the uip_conn->tcpstateflags. */
|
||||||
|
#define UIP_CLOSED 0
|
||||||
|
#define UIP_SYN_RCVD 1
|
||||||
|
#define UIP_SYN_SENT 2
|
||||||
|
#define UIP_ESTABLISHED 3
|
||||||
|
#define UIP_FIN_WAIT_1 4
|
||||||
|
#define UIP_FIN_WAIT_2 5
|
||||||
|
#define UIP_CLOSING 6
|
||||||
|
#define UIP_TIME_WAIT 7
|
||||||
|
#define UIP_LAST_ACK 8
|
||||||
|
#define UIP_TS_MASK 15
|
||||||
|
|
||||||
|
#define UIP_STOPPED 16
|
||||||
|
|
||||||
|
/* The TCP and IP headers. */
|
||||||
|
struct uip_tcpip_hdr {
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
/* IPv6 header. */
|
||||||
|
u8_t vtc,
|
||||||
|
tcflow;
|
||||||
|
u16_t flow;
|
||||||
|
u8_t len[2];
|
||||||
|
u8_t proto, ttl;
|
||||||
|
uip_ip6addr_t srcipaddr, destipaddr;
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
/* IPv4 header. */
|
||||||
|
u8_t vhl,
|
||||||
|
tos,
|
||||||
|
len[2],
|
||||||
|
ipid[2],
|
||||||
|
ipoffset[2],
|
||||||
|
ttl,
|
||||||
|
proto;
|
||||||
|
u16_t ipchksum;
|
||||||
|
u16_t srcipaddr[2],
|
||||||
|
destipaddr[2];
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
/* TCP header. */
|
||||||
|
u16_t srcport,
|
||||||
|
destport;
|
||||||
|
u8_t seqno[4],
|
||||||
|
ackno[4],
|
||||||
|
tcpoffset,
|
||||||
|
flags,
|
||||||
|
wnd[2];
|
||||||
|
u16_t tcpchksum;
|
||||||
|
u8_t urgp[2];
|
||||||
|
u8_t optdata[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The ICMP and IP headers. */
|
||||||
|
struct uip_icmpip_hdr {
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
/* IPv6 header. */
|
||||||
|
u8_t vtc,
|
||||||
|
tcf;
|
||||||
|
u16_t flow;
|
||||||
|
u8_t len[2];
|
||||||
|
u8_t proto, ttl;
|
||||||
|
uip_ip6addr_t srcipaddr, destipaddr;
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
/* IPv4 header. */
|
||||||
|
u8_t vhl,
|
||||||
|
tos,
|
||||||
|
len[2],
|
||||||
|
ipid[2],
|
||||||
|
ipoffset[2],
|
||||||
|
ttl,
|
||||||
|
proto;
|
||||||
|
u16_t ipchksum;
|
||||||
|
u16_t srcipaddr[2],
|
||||||
|
destipaddr[2];
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
/* ICMP (echo) header. */
|
||||||
|
u8_t type, icode;
|
||||||
|
u16_t icmpchksum;
|
||||||
|
#if !UIP_CONF_IPV6
|
||||||
|
u16_t id, seqno;
|
||||||
|
#else /* !UIP_CONF_IPV6 */
|
||||||
|
u8_t flags, reserved1, reserved2, reserved3;
|
||||||
|
u8_t icmp6data[16];
|
||||||
|
u8_t options[1];
|
||||||
|
#endif /* !UIP_CONF_IPV6 */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* The UDP and IP headers. */
|
||||||
|
struct uip_udpip_hdr {
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
/* IPv6 header. */
|
||||||
|
u8_t vtc,
|
||||||
|
tcf;
|
||||||
|
u16_t flow;
|
||||||
|
u8_t len[2];
|
||||||
|
u8_t proto, ttl;
|
||||||
|
uip_ip6addr_t srcipaddr, destipaddr;
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
/* IP header. */
|
||||||
|
u8_t vhl,
|
||||||
|
tos,
|
||||||
|
len[2],
|
||||||
|
ipid[2],
|
||||||
|
ipoffset[2],
|
||||||
|
ttl,
|
||||||
|
proto;
|
||||||
|
u16_t ipchksum;
|
||||||
|
u16_t srcipaddr[2],
|
||||||
|
destipaddr[2];
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
|
/* UDP header. */
|
||||||
|
u16_t srcport,
|
||||||
|
destport;
|
||||||
|
u16_t udplen;
|
||||||
|
u16_t udpchksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The buffer size available for user data in the \ref uip_buf buffer.
|
||||||
|
*
|
||||||
|
* This macro holds the available size for user data in the \ref
|
||||||
|
* uip_buf buffer. The macro is intended to be used for checking
|
||||||
|
* bounds of available user data.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
\code
|
||||||
|
snprintf(uip_appdata, UIP_APPDATA_SIZE, "%u\n", i);
|
||||||
|
\endcode
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_APPDATA_SIZE (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN)
|
||||||
|
|
||||||
|
|
||||||
|
#define UIP_PROTO_ICMP 1
|
||||||
|
#define UIP_PROTO_TCP 6
|
||||||
|
#define UIP_PROTO_UDP 17
|
||||||
|
#define UIP_PROTO_ICMP6 58
|
||||||
|
|
||||||
|
/* Header sizes. */
|
||||||
|
#if UIP_CONF_IPV6
|
||||||
|
#define UIP_IPH_LEN 40
|
||||||
|
#else /* UIP_CONF_IPV6 */
|
||||||
|
#define UIP_IPH_LEN 20 /* Size of IP header */
|
||||||
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
#define UIP_UDPH_LEN 8 /* Size of UDP header */
|
||||||
|
#define UIP_TCPH_LEN 20 /* Size of TCP header */
|
||||||
|
#define UIP_IPUDPH_LEN (UIP_UDPH_LEN + UIP_IPH_LEN) /* Size of IP +
|
||||||
|
UDP
|
||||||
|
header */
|
||||||
|
#define UIP_IPTCPH_LEN (UIP_TCPH_LEN + UIP_IPH_LEN) /* Size of IP +
|
||||||
|
TCP
|
||||||
|
header */
|
||||||
|
#define UIP_TCPIP_HLEN UIP_IPTCPH_LEN
|
||||||
|
|
||||||
|
|
||||||
|
#if UIP_FIXEDADDR
|
||||||
|
extern const uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr;
|
||||||
|
#else /* UIP_FIXEDADDR */
|
||||||
|
extern uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr;
|
||||||
|
#endif /* UIP_FIXEDADDR */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of a 48-bit Ethernet address.
|
||||||
|
*/
|
||||||
|
struct uip_eth_addr {
|
||||||
|
u8_t addr[6];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the Internet checksum over a buffer.
|
||||||
|
*
|
||||||
|
* The Internet checksum is the one's complement of the one's
|
||||||
|
* complement sum of all 16-bit words in the buffer.
|
||||||
|
*
|
||||||
|
* See RFC1071.
|
||||||
|
*
|
||||||
|
* \param buf A pointer to the buffer over which the checksum is to be
|
||||||
|
* computed.
|
||||||
|
*
|
||||||
|
* \param len The length of the buffer over which the checksum is to
|
||||||
|
* be computed.
|
||||||
|
*
|
||||||
|
* \return The Internet checksum of the buffer.
|
||||||
|
*/
|
||||||
|
u16_t uip_chksum(u16_t *buf, u16_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the IP header checksum of the packet header in uip_buf.
|
||||||
|
*
|
||||||
|
* The IP header checksum is the Internet checksum of the 20 bytes of
|
||||||
|
* the IP header.
|
||||||
|
*
|
||||||
|
* \return The IP header checksum of the IP header in the uip_buf
|
||||||
|
* buffer.
|
||||||
|
*/
|
||||||
|
u16_t uip_ipchksum(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the TCP checksum of the packet in uip_buf and uip_appdata.
|
||||||
|
*
|
||||||
|
* The TCP checksum is the Internet checksum of data contents of the
|
||||||
|
* TCP segment, and a pseudo-header as defined in RFC793.
|
||||||
|
*
|
||||||
|
* \return The TCP checksum of the TCP segment in uip_buf and pointed
|
||||||
|
* to by uip_appdata.
|
||||||
|
*/
|
||||||
|
u16_t uip_tcpchksum(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the UDP checksum of the packet in uip_buf and uip_appdata.
|
||||||
|
*
|
||||||
|
* The UDP checksum is the Internet checksum of data contents of the
|
||||||
|
* UDP segment, and a pseudo-header as defined in RFC768.
|
||||||
|
*
|
||||||
|
* \return The UDP checksum of the UDP segment in uip_buf and pointed
|
||||||
|
* to by uip_appdata.
|
||||||
|
*/
|
||||||
|
u16_t uip_udpchksum(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __UIP_H__ */
|
||||||
|
|
||||||
|
|
||||||
|
/** @} */
|
@ -0,0 +1,138 @@
|
|||||||
|
/**
|
||||||
|
* \addtogroup uip
|
||||||
|
* {@
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup uiparch Architecture specific uIP functions
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* The functions in the architecture specific module implement the IP
|
||||||
|
* check sum and 32-bit additions.
|
||||||
|
*
|
||||||
|
* The IP checksum calculation is the most computationally expensive
|
||||||
|
* operation in the TCP/IP stack and it therefore pays off to
|
||||||
|
* implement this in efficient assembler. The purpose of the uip-arch
|
||||||
|
* module is to let the checksum functions to be implemented in
|
||||||
|
* architecture specific assembler.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Declarations of architecture specific functions.
|
||||||
|
* \author Adam Dunkels <adam@dunkels.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001, Adam Dunkels.
|
||||||
|
* 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 uIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* $Id: uip_arch.h,v 1.2 2006/06/07 09:15:19 adam Exp $
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UIP_ARCH_H__
|
||||||
|
#define __UIP_ARCH_H__
|
||||||
|
|
||||||
|
#include "uip.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Carry out a 32-bit addition.
|
||||||
|
*
|
||||||
|
* Because not all architectures for which uIP is intended has native
|
||||||
|
* 32-bit arithmetic, uIP uses an external C function for doing the
|
||||||
|
* required 32-bit additions in the TCP protocol processing. This
|
||||||
|
* function should add the two arguments and place the result in the
|
||||||
|
* global variable uip_acc32.
|
||||||
|
*
|
||||||
|
* \note The 32-bit integer pointed to by the op32 parameter and the
|
||||||
|
* result in the uip_acc32 variable are in network byte order (big
|
||||||
|
* endian).
|
||||||
|
*
|
||||||
|
* \param op32 A pointer to a 4-byte array representing a 32-bit
|
||||||
|
* integer in network byte order (big endian).
|
||||||
|
*
|
||||||
|
* \param op16 A 16-bit integer in host byte order.
|
||||||
|
*/
|
||||||
|
void uip_add32(u8_t *op32, u16_t op16);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the Internet checksum over a buffer.
|
||||||
|
*
|
||||||
|
* The Internet checksum is the one's complement of the one's
|
||||||
|
* complement sum of all 16-bit words in the buffer.
|
||||||
|
*
|
||||||
|
* See RFC1071.
|
||||||
|
*
|
||||||
|
* \note This function is not called in the current version of uIP,
|
||||||
|
* but future versions might make use of it.
|
||||||
|
*
|
||||||
|
* \param buf A pointer to the buffer over which the checksum is to be
|
||||||
|
* computed.
|
||||||
|
*
|
||||||
|
* \param len The length of the buffer over which the checksum is to
|
||||||
|
* be computed.
|
||||||
|
*
|
||||||
|
* \return The Internet checksum of the buffer.
|
||||||
|
*/
|
||||||
|
u16_t uip_chksum(u16_t *buf, u16_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the IP header checksum of the packet header in uip_buf.
|
||||||
|
*
|
||||||
|
* The IP header checksum is the Internet checksum of the 20 bytes of
|
||||||
|
* the IP header.
|
||||||
|
*
|
||||||
|
* \return The IP header checksum of the IP header in the uip_buf
|
||||||
|
* buffer.
|
||||||
|
*/
|
||||||
|
u16_t uip_ipchksum(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the TCP checksum of the packet in uip_buf and uip_appdata.
|
||||||
|
*
|
||||||
|
* The TCP checksum is the Internet checksum of data contents of the
|
||||||
|
* TCP segment, and a pseudo-header as defined in RFC793.
|
||||||
|
*
|
||||||
|
* \note The uip_appdata pointer that points to the packet data may
|
||||||
|
* point anywhere in memory, so it is not possible to simply calculate
|
||||||
|
* the Internet checksum of the contents of the uip_buf buffer.
|
||||||
|
*
|
||||||
|
* \return The TCP checksum of the TCP segment in uip_buf and pointed
|
||||||
|
* to by uip_appdata.
|
||||||
|
*/
|
||||||
|
u16_t uip_tcpchksum(void);
|
||||||
|
|
||||||
|
u16_t uip_udpchksum(void);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#endif /* __UIP_ARCH_H__ */
|
@ -0,0 +1,423 @@
|
|||||||
|
/**
|
||||||
|
* \addtogroup uip
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup uiparp uIP Address Resolution Protocol
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* The Address Resolution Protocol ARP is used for mapping between IP
|
||||||
|
* addresses and link level addresses such as the Ethernet MAC
|
||||||
|
* addresses. ARP uses broadcast queries to ask for the link level
|
||||||
|
* address of a known IP address and the host which is configured with
|
||||||
|
* the IP address for which the query was meant, will respond with its
|
||||||
|
* link level address.
|
||||||
|
*
|
||||||
|
* \note This ARP implementation only supports Ethernet.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Implementation of the ARP Address Resolution Protocol.
|
||||||
|
* \author Adam Dunkels <adam@dunkels.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2003, Adam Dunkels.
|
||||||
|
* 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 uIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* $Id: uip_arp.c,v 1.8 2006/06/02 23:36:21 adam Exp $
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "uip_arp.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct arp_hdr {
|
||||||
|
struct uip_eth_hdr ethhdr;
|
||||||
|
u16_t hwtype;
|
||||||
|
u16_t protocol;
|
||||||
|
u8_t hwlen;
|
||||||
|
u8_t protolen;
|
||||||
|
u16_t opcode;
|
||||||
|
struct uip_eth_addr shwaddr;
|
||||||
|
u16_t sipaddr[2];
|
||||||
|
struct uip_eth_addr dhwaddr;
|
||||||
|
u16_t dipaddr[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ethip_hdr {
|
||||||
|
struct uip_eth_hdr ethhdr;
|
||||||
|
/* IP header. */
|
||||||
|
u8_t vhl,
|
||||||
|
tos,
|
||||||
|
len[2],
|
||||||
|
ipid[2],
|
||||||
|
ipoffset[2],
|
||||||
|
ttl,
|
||||||
|
proto;
|
||||||
|
u16_t ipchksum;
|
||||||
|
u16_t srcipaddr[2],
|
||||||
|
destipaddr[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ARP_REQUEST 1
|
||||||
|
#define ARP_REPLY 2
|
||||||
|
|
||||||
|
#define ARP_HWTYPE_ETH 1
|
||||||
|
|
||||||
|
struct arp_entry {
|
||||||
|
u16_t ipaddr[2];
|
||||||
|
struct uip_eth_addr ethaddr;
|
||||||
|
u8_t time;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct uip_eth_addr broadcast_ethaddr =
|
||||||
|
{{0xff,0xff,0xff,0xff,0xff,0xff}};
|
||||||
|
static const u16_t broadcast_ipaddr[2] = {0xffff,0xffff};
|
||||||
|
|
||||||
|
static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
|
||||||
|
static u16_t ipaddr[2];
|
||||||
|
static u8_t i, c;
|
||||||
|
|
||||||
|
static u8_t arptime;
|
||||||
|
static u8_t tmpage;
|
||||||
|
|
||||||
|
#define BUF ((struct arp_hdr *)&uip_buf[0])
|
||||||
|
#define IPBUF ((struct ethip_hdr *)&uip_buf[0])
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Initialize the ARP module.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_arp_init(void)
|
||||||
|
{
|
||||||
|
for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
|
||||||
|
memset(arp_table[i].ipaddr, 0, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Periodic ARP processing function.
|
||||||
|
*
|
||||||
|
* This function performs periodic timer processing in the ARP module
|
||||||
|
* and should be called at regular intervals. The recommended interval
|
||||||
|
* is 10 seconds between the calls.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_arp_timer(void)
|
||||||
|
{
|
||||||
|
struct arp_entry *tabptr;
|
||||||
|
|
||||||
|
++arptime;
|
||||||
|
for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
|
||||||
|
tabptr = &arp_table[i];
|
||||||
|
if((tabptr->ipaddr[0] | tabptr->ipaddr[1]) != 0 &&
|
||||||
|
arptime - tabptr->time >= UIP_ARP_MAXAGE) {
|
||||||
|
memset(tabptr->ipaddr, 0, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr)
|
||||||
|
{
|
||||||
|
register struct arp_entry *tabptr;
|
||||||
|
/* 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 < UIP_ARPTAB_SIZE; ++i) {
|
||||||
|
|
||||||
|
tabptr = &arp_table[i];
|
||||||
|
/* Only check those entries that are actually in use. */
|
||||||
|
if(tabptr->ipaddr[0] != 0 &&
|
||||||
|
tabptr->ipaddr[1] != 0) {
|
||||||
|
|
||||||
|
/* Check if the source IP address of the incoming packet matches
|
||||||
|
the IP address in this ARP table entry. */
|
||||||
|
if(ipaddr[0] == tabptr->ipaddr[0] &&
|
||||||
|
ipaddr[1] == tabptr->ipaddr[1]) {
|
||||||
|
|
||||||
|
/* An old entry found, update this and return. */
|
||||||
|
memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
|
||||||
|
tabptr->time = arptime;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here, no existing ARP table entry was found, so we
|
||||||
|
create one. */
|
||||||
|
|
||||||
|
/* First, we try to find an unused entry in the ARP table. */
|
||||||
|
for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
|
||||||
|
tabptr = &arp_table[i];
|
||||||
|
if(tabptr->ipaddr[0] == 0 &&
|
||||||
|
tabptr->ipaddr[1] == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If no unused entry is found, we try to find the oldest entry and
|
||||||
|
throw it away. */
|
||||||
|
if(i == UIP_ARPTAB_SIZE) {
|
||||||
|
tmpage = 0;
|
||||||
|
c = 0;
|
||||||
|
for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
|
||||||
|
tabptr = &arp_table[i];
|
||||||
|
if(arptime - tabptr->time > tmpage) {
|
||||||
|
tmpage = arptime - tabptr->time;
|
||||||
|
c = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i = c;
|
||||||
|
tabptr = &arp_table[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now, i is the ARP table entry which we will fill with the new
|
||||||
|
information. */
|
||||||
|
memcpy(tabptr->ipaddr, ipaddr, 4);
|
||||||
|
memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
|
||||||
|
tabptr->time = arptime;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* ARP processing for incoming IP packets
|
||||||
|
*
|
||||||
|
* This function should be called by the device driver when an IP
|
||||||
|
* packet has been received. The function will check if the address is
|
||||||
|
* in the ARP cache, and if so the ARP cache entry will be
|
||||||
|
* refreshed. If no ARP cache entry was found, a new one is created.
|
||||||
|
*
|
||||||
|
* This function expects an IP packet with a prepended Ethernet header
|
||||||
|
* in the uip_buf[] buffer, and the length of the packet in the global
|
||||||
|
* variable uip_len.
|
||||||
|
*/
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
#if 0
|
||||||
|
void
|
||||||
|
uip_arp_ipin(void)
|
||||||
|
{
|
||||||
|
uip_len -= sizeof(struct uip_eth_hdr);
|
||||||
|
|
||||||
|
/* Only insert/update an entry if the source IP address of the
|
||||||
|
incoming IP packet comes from a host on the local network. */
|
||||||
|
if((IPBUF->srcipaddr[0] & uip_netmask[0]) !=
|
||||||
|
(uip_hostaddr[0] & uip_netmask[0])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if((IPBUF->srcipaddr[1] & uip_netmask[1]) !=
|
||||||
|
(uip_hostaddr[1] & uip_netmask[1])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif /* 0 */
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* ARP processing for incoming ARP packets.
|
||||||
|
*
|
||||||
|
* This function should be called by the device driver when an ARP
|
||||||
|
* packet has been received. The function will act differently
|
||||||
|
* depending on the ARP packet type: if it is a reply for a request
|
||||||
|
* that we previously sent out, the ARP cache will be filled in with
|
||||||
|
* the values from the ARP reply. If the incoming ARP packet is an ARP
|
||||||
|
* request for our IP address, an ARP reply packet is created and put
|
||||||
|
* into the uip_buf[] buffer.
|
||||||
|
*
|
||||||
|
* When the function returns, the value of the global variable uip_len
|
||||||
|
* indicates whether the device driver should send out a packet or
|
||||||
|
* not. If uip_len is zero, no packet should be sent. If uip_len is
|
||||||
|
* non-zero, it contains the length of the outbound packet that is
|
||||||
|
* present in the uip_buf[] buffer.
|
||||||
|
*
|
||||||
|
* This function expects an ARP packet with a prepended Ethernet
|
||||||
|
* header in the uip_buf[] buffer, and the length of the packet in the
|
||||||
|
* global variable uip_len.
|
||||||
|
*/
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_arp_arpin(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(uip_len < sizeof(struct arp_hdr)) {
|
||||||
|
uip_len = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uip_len = 0;
|
||||||
|
|
||||||
|
switch(BUF->opcode) {
|
||||||
|
case HTONS(ARP_REQUEST):
|
||||||
|
/* ARP request. If it asked for our address, we send out a
|
||||||
|
reply. */
|
||||||
|
if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) {
|
||||||
|
/* First, we register the one who made the request in our ARP
|
||||||
|
table, since it is likely that we will do more communication
|
||||||
|
with this host in the future. */
|
||||||
|
uip_arp_update(BUF->sipaddr, &BUF->shwaddr);
|
||||||
|
|
||||||
|
/* The reply opcode is 2. */
|
||||||
|
BUF->opcode = HTONS(2);
|
||||||
|
|
||||||
|
memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6);
|
||||||
|
memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
|
||||||
|
memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
|
||||||
|
memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6);
|
||||||
|
|
||||||
|
BUF->dipaddr[0] = BUF->sipaddr[0];
|
||||||
|
BUF->dipaddr[1] = BUF->sipaddr[1];
|
||||||
|
BUF->sipaddr[0] = uip_hostaddr[0];
|
||||||
|
BUF->sipaddr[1] = uip_hostaddr[1];
|
||||||
|
|
||||||
|
BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);
|
||||||
|
uip_len = sizeof(struct arp_hdr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HTONS(ARP_REPLY):
|
||||||
|
/* ARP reply. We insert or update the ARP table if it was meant
|
||||||
|
for us. */
|
||||||
|
if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) {
|
||||||
|
uip_arp_update(BUF->sipaddr, &BUF->shwaddr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Prepend Ethernet header to an outbound IP packet and see if we need
|
||||||
|
* to send out an ARP request.
|
||||||
|
*
|
||||||
|
* This function should be called before sending out an IP packet. The
|
||||||
|
* function checks the destination IP address of the IP packet to see
|
||||||
|
* what Ethernet MAC address that should be used as a destination MAC
|
||||||
|
* address on the Ethernet.
|
||||||
|
*
|
||||||
|
* If the destination IP address is in the local network (determined
|
||||||
|
* by logical ANDing of netmask and our IP address), the function
|
||||||
|
* checks the ARP cache to see if an entry for the destination IP
|
||||||
|
* address is found. If so, an Ethernet header is prepended and the
|
||||||
|
* function returns. If no ARP cache entry is found for the
|
||||||
|
* destination IP address, the packet in the uip_buf[] is replaced by
|
||||||
|
* an ARP request packet for the IP address. The IP packet is dropped
|
||||||
|
* and it is assumed that they higher level protocols (e.g., TCP)
|
||||||
|
* eventually will retransmit the dropped packet.
|
||||||
|
*
|
||||||
|
* If the destination IP address is not on the local network, the IP
|
||||||
|
* address of the default router is used instead.
|
||||||
|
*
|
||||||
|
* When the function returns, a packet is present in the uip_buf[]
|
||||||
|
* buffer, and the length of the packet is in the global variable
|
||||||
|
* uip_len.
|
||||||
|
*/
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_arp_out(void)
|
||||||
|
{
|
||||||
|
struct arp_entry *tabptr;
|
||||||
|
|
||||||
|
/* Find the destination IP address in the ARP table and construct
|
||||||
|
the Ethernet header. If the destination IP addres isn't on the
|
||||||
|
local network, we use the default router's IP address instead.
|
||||||
|
|
||||||
|
If not ARP table entry is found, we overwrite the original IP
|
||||||
|
packet with an ARP request for the IP address. */
|
||||||
|
|
||||||
|
/* First check if destination is a local broadcast. */
|
||||||
|
if(uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr)) {
|
||||||
|
memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6);
|
||||||
|
} else {
|
||||||
|
/* Check if the destination address is on the local network. */
|
||||||
|
if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask)) {
|
||||||
|
/* Destination address was not on the local network, so we need to
|
||||||
|
use the default router's IP address instead of the destination
|
||||||
|
address when determining the MAC address. */
|
||||||
|
uip_ipaddr_copy(ipaddr, uip_draddr);
|
||||||
|
} else {
|
||||||
|
/* Else, we use the destination IP address. */
|
||||||
|
uip_ipaddr_copy(ipaddr, IPBUF->destipaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
|
||||||
|
tabptr = &arp_table[i];
|
||||||
|
if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(i == UIP_ARPTAB_SIZE) {
|
||||||
|
/* The destination address was not in our ARP table, so we
|
||||||
|
overwrite the IP packet with an ARP request. */
|
||||||
|
|
||||||
|
memset(BUF->ethhdr.dest.addr, 0xff, 6);
|
||||||
|
memset(BUF->dhwaddr.addr, 0x00, 6);
|
||||||
|
memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
|
||||||
|
memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
|
||||||
|
|
||||||
|
uip_ipaddr_copy(BUF->dipaddr, ipaddr);
|
||||||
|
uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr);
|
||||||
|
BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */
|
||||||
|
BUF->hwtype = HTONS(ARP_HWTYPE_ETH);
|
||||||
|
BUF->protocol = HTONS(UIP_ETHTYPE_IP);
|
||||||
|
BUF->hwlen = 6;
|
||||||
|
BUF->protolen = 4;
|
||||||
|
BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);
|
||||||
|
|
||||||
|
uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN];
|
||||||
|
|
||||||
|
uip_len = sizeof(struct arp_hdr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build an ethernet header. */
|
||||||
|
memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6);
|
||||||
|
}
|
||||||
|
memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
|
||||||
|
|
||||||
|
IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP);
|
||||||
|
|
||||||
|
uip_len += sizeof(struct uip_eth_hdr);
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
/** @} */
|
@ -0,0 +1,144 @@
|
|||||||
|
/**
|
||||||
|
* \addtogroup uip
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \addtogroup uiparp
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Macros and definitions for the ARP module.
|
||||||
|
* \author Adam Dunkels <adam@dunkels.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2003, Adam Dunkels.
|
||||||
|
* 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 uIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* $Id: uip_arp.h,v 1.5 2006/06/11 21:46:39 adam Exp $
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UIP_ARP_H__
|
||||||
|
#define __UIP_ARP_H__
|
||||||
|
|
||||||
|
#include "uip.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern struct uip_eth_addr uip_ethaddr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Ethernet header.
|
||||||
|
*/
|
||||||
|
struct uip_eth_hdr {
|
||||||
|
struct uip_eth_addr dest;
|
||||||
|
struct uip_eth_addr src;
|
||||||
|
u16_t type;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define UIP_ETHTYPE_ARP 0x0806
|
||||||
|
#define UIP_ETHTYPE_IP 0x0800
|
||||||
|
#define UIP_ETHTYPE_IP6 0x86dd
|
||||||
|
|
||||||
|
|
||||||
|
/* The uip_arp_init() function must be called before any of the other
|
||||||
|
ARP functions. */
|
||||||
|
void uip_arp_init(void);
|
||||||
|
|
||||||
|
/* The uip_arp_ipin() function should be called whenever an IP packet
|
||||||
|
arrives from the Ethernet. This function refreshes the ARP table or
|
||||||
|
inserts a new mapping if none exists. The function assumes that an
|
||||||
|
IP packet with an Ethernet header is present in the uip_buf buffer
|
||||||
|
and that the length of the packet is in the uip_len variable. */
|
||||||
|
/*void uip_arp_ipin(void);*/
|
||||||
|
#define uip_arp_ipin()
|
||||||
|
|
||||||
|
/* The uip_arp_arpin() should be called when an ARP packet is received
|
||||||
|
by the Ethernet driver. This function also assumes that the
|
||||||
|
Ethernet frame is present in the uip_buf buffer. When the
|
||||||
|
uip_arp_arpin() function returns, the contents of the uip_buf
|
||||||
|
buffer should be sent out on the Ethernet if the uip_len variable
|
||||||
|
is > 0. */
|
||||||
|
void uip_arp_arpin(void);
|
||||||
|
|
||||||
|
/* The uip_arp_out() function should be called when an IP packet
|
||||||
|
should be sent out on the Ethernet. This function creates an
|
||||||
|
Ethernet header before the IP header in the uip_buf buffer. The
|
||||||
|
Ethernet header will have the correct Ethernet MAC destination
|
||||||
|
address filled in if an ARP table entry for the destination IP
|
||||||
|
address (or the IP address of the default router) is present. If no
|
||||||
|
such table entry is found, the IP packet is overwritten with an ARP
|
||||||
|
request and we rely on TCP to retransmit the packet that was
|
||||||
|
overwritten. In any case, the uip_len variable holds the length of
|
||||||
|
the Ethernet frame that should be transmitted. */
|
||||||
|
void uip_arp_out(void);
|
||||||
|
|
||||||
|
/* The uip_arp_timer() function should be called every ten seconds. It
|
||||||
|
is responsible for flushing old entries in the ARP table. */
|
||||||
|
void uip_arp_timer(void);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \addtogroup uipconffunc
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifiy the Ethernet MAC address.
|
||||||
|
*
|
||||||
|
* The ARP code needs to know the MAC address of the Ethernet card in
|
||||||
|
* order to be able to respond to ARP queries and to generate working
|
||||||
|
* Ethernet headers.
|
||||||
|
*
|
||||||
|
* \note This macro only specifies the Ethernet MAC address to the ARP
|
||||||
|
* code. It cannot be used to change the MAC address of the Ethernet
|
||||||
|
* card.
|
||||||
|
*
|
||||||
|
* \param eaddr A pointer to a struct uip_eth_addr containing the
|
||||||
|
* Ethernet MAC address of the Ethernet card.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define uip_setethaddr(eaddr) do {uip_ethaddr.addr[0] = eaddr.addr[0]; \
|
||||||
|
uip_ethaddr.addr[1] = eaddr.addr[1];\
|
||||||
|
uip_ethaddr.addr[2] = eaddr.addr[2];\
|
||||||
|
uip_ethaddr.addr[3] = eaddr.addr[3];\
|
||||||
|
uip_ethaddr.addr[4] = eaddr.addr[4];\
|
||||||
|
uip_ethaddr.addr[5] = eaddr.addr[5];} while(0)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#endif /* __UIP_ARP_H__ */
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2004, Adam Dunkels and the 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 uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* $Id: uiplib.c,v 1.2 2006/06/12 08:00:31 adam Exp $
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "uip.h"
|
||||||
|
#include "uiplib.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
unsigned char
|
||||||
|
uiplib_ipaddrconv(char *addrstr, unsigned char *ipaddr)
|
||||||
|
{
|
||||||
|
unsigned char tmp;
|
||||||
|
char c;
|
||||||
|
unsigned char i, j;
|
||||||
|
|
||||||
|
tmp = 0;
|
||||||
|
|
||||||
|
for(i = 0; i < 4; ++i) {
|
||||||
|
j = 0;
|
||||||
|
do {
|
||||||
|
c = *addrstr;
|
||||||
|
++j;
|
||||||
|
if(j > 4) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(c == '.' || c == 0) {
|
||||||
|
*ipaddr = tmp;
|
||||||
|
++ipaddr;
|
||||||
|
tmp = 0;
|
||||||
|
} else if(c >= '0' && c <= '9') {
|
||||||
|
tmp = (tmp * 10) + (c - '0');
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
++addrstr;
|
||||||
|
} while(c != '.' && c != 0);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Various uIP library functions.
|
||||||
|
* \author
|
||||||
|
* Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2002, Adam Dunkels.
|
||||||
|
* 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 uIP TCP/IP stack
|
||||||
|
*
|
||||||
|
* $Id: uiplib.h,v 1.1 2006/06/07 09:15:19 adam Exp $
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __UIPLIB_H__
|
||||||
|
#define __UIPLIB_H__
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \addtogroup uipconvfunc
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a textual representation of an IP address to a numerical representation.
|
||||||
|
*
|
||||||
|
* This function takes a textual representation of an IP address in
|
||||||
|
* the form a.b.c.d and converts it into a 4-byte array that can be
|
||||||
|
* used by other uIP functions.
|
||||||
|
*
|
||||||
|
* \param addrstr A pointer to a string containing the IP address in
|
||||||
|
* textual form.
|
||||||
|
*
|
||||||
|
* \param addr A pointer to a 4-byte array that will be filled in with
|
||||||
|
* the numerical representation of the address.
|
||||||
|
*
|
||||||
|
* \retval 0 If the IP address could not be parsed.
|
||||||
|
* \retval Non-zero If the IP address was parsed.
|
||||||
|
*/
|
||||||
|
unsigned char uiplib_ipaddrconv(char *addrstr, unsigned char *addr);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#endif /* __UIPLIB_H__ */
|
@ -0,0 +1,539 @@
|
|||||||
|
/**
|
||||||
|
* \defgroup uipopt Configuration options for uIP
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* uIP is configured using the per-project configuration file
|
||||||
|
* uipopt.h. This file contains all compile-time options for uIP and
|
||||||
|
* should be tweaked to match each specific project. The uIP
|
||||||
|
* distribution contains a documented example "uipopt.h" that can be
|
||||||
|
* copied and modified for each project.
|
||||||
|
*
|
||||||
|
* \note Most of the configuration options in the uipopt.h should not
|
||||||
|
* be changed, but rather the per-project uip-conf.h file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Configuration options for uIP.
|
||||||
|
* \author Adam Dunkels <adam@dunkels.com>
|
||||||
|
*
|
||||||
|
* This file is used for tweaking various configuration options for
|
||||||
|
* uIP. You should make a copy of this file into one of your project's
|
||||||
|
* directories instead of editing this example "uipopt.h" file that
|
||||||
|
* comes with the uIP distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2003, Adam Dunkels.
|
||||||
|
* 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 uIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* $Id: uipopt.h,v 1.4 2006/06/12 08:00:31 adam Exp $
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UIPOPT_H__
|
||||||
|
#define __UIPOPT_H__
|
||||||
|
|
||||||
|
#ifndef UIP_LITTLE_ENDIAN
|
||||||
|
#define UIP_LITTLE_ENDIAN 3412
|
||||||
|
#endif /* UIP_LITTLE_ENDIAN */
|
||||||
|
#ifndef UIP_BIG_ENDIAN
|
||||||
|
#define UIP_BIG_ENDIAN 1234
|
||||||
|
#endif /* UIP_BIG_ENDIAN */
|
||||||
|
|
||||||
|
#include "uip-conf.h"
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name Static configuration options
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* These configuration options can be used for setting the IP address
|
||||||
|
* settings statically, but only if UIP_FIXEDADDR is set to 1. The
|
||||||
|
* configuration options for a specific node includes IP address,
|
||||||
|
* netmask and default router as well as the Ethernet address. The
|
||||||
|
* netmask, default router and Ethernet address are appliciable only
|
||||||
|
* if uIP should be run over Ethernet.
|
||||||
|
*
|
||||||
|
* All of these should be changed to suit your project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if uIP should use a fixed IP address or not.
|
||||||
|
*
|
||||||
|
* If uIP should use a fixed IP address, the settings are set in the
|
||||||
|
* uipopt.h file. If not, the macros uip_sethostaddr(),
|
||||||
|
* uip_setdraddr() and uip_setnetmask() should be used instead.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_FIXEDADDR 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ping IP address asignment.
|
||||||
|
*
|
||||||
|
* uIP uses a "ping" packets for setting its own IP address if this
|
||||||
|
* option is set. If so, uIP will start with an empty IP address and
|
||||||
|
* the destination IP address of the first incoming "ping" (ICMP echo)
|
||||||
|
* packet will be used for setting the hosts IP address.
|
||||||
|
*
|
||||||
|
* \note This works only if UIP_FIXEDADDR is 0.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifdef UIP_CONF_PINGADDRCONF
|
||||||
|
#define UIP_PINGADDRCONF UIP_CONF_PINGADDRCONF
|
||||||
|
#else /* UIP_CONF_PINGADDRCONF */
|
||||||
|
#define UIP_PINGADDRCONF 0
|
||||||
|
#endif /* UIP_CONF_PINGADDRCONF */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies if the uIP ARP module should be compiled with a fixed
|
||||||
|
* Ethernet MAC address or not.
|
||||||
|
*
|
||||||
|
* If this configuration option is 0, the macro uip_setethaddr() can
|
||||||
|
* be used to specify the Ethernet address at run-time.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_FIXEDETHADDR 0
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* \name IP configuration options
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* The IP TTL (time to live) of IP packets sent by uIP.
|
||||||
|
*
|
||||||
|
* This should normally not be changed.
|
||||||
|
*/
|
||||||
|
#define UIP_TTL 64
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn on support for IP packet reassembly.
|
||||||
|
*
|
||||||
|
* uIP supports reassembly of fragmented IP packets. This features
|
||||||
|
* requires an additonal amount of RAM to hold the reassembly buffer
|
||||||
|
* and the reassembly code size is approximately 700 bytes. The
|
||||||
|
* reassembly buffer is of the same size as the uip_buf buffer
|
||||||
|
* (configured by UIP_BUFSIZE).
|
||||||
|
*
|
||||||
|
* \note IP packet reassembly is not heavily tested.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_REASSEMBLY 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum time an IP fragment should wait in the reassembly
|
||||||
|
* buffer before it is dropped.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define UIP_REASS_MAXAGE 40
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* \name UDP configuration options
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles wether UDP support should be compiled in or not.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifdef UIP_CONF_UDP
|
||||||
|
#define UIP_UDP UIP_CONF_UDP
|
||||||
|
#else /* UIP_CONF_UDP */
|
||||||
|
#define UIP_UDP 0
|
||||||
|
#endif /* UIP_CONF_UDP */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles if UDP checksums should be used or not.
|
||||||
|
*
|
||||||
|
* \note Support for UDP checksums is currently not included in uIP,
|
||||||
|
* so this option has no function.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifdef UIP_CONF_UDP_CHECKSUMS
|
||||||
|
#define UIP_UDP_CHECKSUMS UIP_CONF_UDP_CHECKSUMS
|
||||||
|
#else
|
||||||
|
#define UIP_UDP_CHECKSUMS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum amount of concurrent UDP connections.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifdef UIP_CONF_UDP_CONNS
|
||||||
|
#define UIP_UDP_CONNS UIP_CONF_UDP_CONNS
|
||||||
|
#else /* UIP_CONF_UDP_CONNS */
|
||||||
|
#define UIP_UDP_CONNS 10
|
||||||
|
#endif /* UIP_CONF_UDP_CONNS */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the function that should be called when UDP datagrams arrive.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* \name TCP configuration options
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if support for opening connections from uIP should be
|
||||||
|
* compiled in.
|
||||||
|
*
|
||||||
|
* If the applications that are running on top of uIP for this project
|
||||||
|
* do not need to open outgoing TCP connections, this configration
|
||||||
|
* option can be turned off to reduce the code size of uIP.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_ACTIVE_OPEN 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of simultaneously open TCP connections.
|
||||||
|
*
|
||||||
|
* Since the TCP connections are statically allocated, turning this
|
||||||
|
* configuration knob down results in less RAM used. Each TCP
|
||||||
|
* connection requires approximatly 30 bytes of memory.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifndef UIP_CONF_MAX_CONNECTIONS
|
||||||
|
#define UIP_CONNS 10
|
||||||
|
#else /* UIP_CONF_MAX_CONNECTIONS */
|
||||||
|
#define UIP_CONNS UIP_CONF_MAX_CONNECTIONS
|
||||||
|
#endif /* UIP_CONF_MAX_CONNECTIONS */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of simultaneously listening TCP ports.
|
||||||
|
*
|
||||||
|
* Each listening TCP port requires 2 bytes of memory.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifndef UIP_CONF_MAX_LISTENPORTS
|
||||||
|
#define UIP_LISTENPORTS 20
|
||||||
|
#else /* UIP_CONF_MAX_LISTENPORTS */
|
||||||
|
#define UIP_LISTENPORTS UIP_CONF_MAX_LISTENPORTS
|
||||||
|
#endif /* UIP_CONF_MAX_LISTENPORTS */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if support for TCP urgent data notification should be
|
||||||
|
* compiled in.
|
||||||
|
*
|
||||||
|
* Urgent data (out-of-band data) is a rarely used TCP feature that
|
||||||
|
* very seldom would be required.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#define UIP_URGDATA 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The initial retransmission timeout counted in timer pulses.
|
||||||
|
*
|
||||||
|
* This should not be changed.
|
||||||
|
*/
|
||||||
|
#define UIP_RTO 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of times a segment should be retransmitted
|
||||||
|
* before the connection should be aborted.
|
||||||
|
*
|
||||||
|
* This should not be changed.
|
||||||
|
*/
|
||||||
|
#define UIP_MAXRTX 8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of times a SYN segment should be retransmitted
|
||||||
|
* before a connection request should be deemed to have been
|
||||||
|
* unsuccessful.
|
||||||
|
*
|
||||||
|
* This should not need to be changed.
|
||||||
|
*/
|
||||||
|
#define UIP_MAXSYNRTX 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The TCP maximum segment size.
|
||||||
|
*
|
||||||
|
* This is should not be to set to more than
|
||||||
|
* UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN.
|
||||||
|
*/
|
||||||
|
#define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the advertised receiver's window.
|
||||||
|
*
|
||||||
|
* Should be set low (i.e., to the size of the uip_buf buffer) is the
|
||||||
|
* application is slow to process incoming data, or high (32768 bytes)
|
||||||
|
* if the application processes data quickly.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifndef UIP_CONF_RECEIVE_WINDOW
|
||||||
|
#define UIP_RECEIVE_WINDOW UIP_TCP_MSS
|
||||||
|
#else
|
||||||
|
#define UIP_RECEIVE_WINDOW UIP_CONF_RECEIVE_WINDOW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How long a connection should stay in the TIME_WAIT state.
|
||||||
|
*
|
||||||
|
* This configiration option has no real implication, and it should be
|
||||||
|
* left untouched.
|
||||||
|
*/
|
||||||
|
#define UIP_TIME_WAIT_TIMEOUT 120
|
||||||
|
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* \name ARP configuration options
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the ARP table.
|
||||||
|
*
|
||||||
|
* This option should be set to a larger value if this uIP node will
|
||||||
|
* have many connections from the local network.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifdef UIP_CONF_ARPTAB_SIZE
|
||||||
|
#define UIP_ARPTAB_SIZE UIP_CONF_ARPTAB_SIZE
|
||||||
|
#else
|
||||||
|
#define UIP_ARPTAB_SIZE 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maxium age of ARP table entries measured in 10ths of seconds.
|
||||||
|
*
|
||||||
|
* An UIP_ARP_MAXAGE of 120 corresponds to 20 minutes (BSD
|
||||||
|
* default).
|
||||||
|
*/
|
||||||
|
#define UIP_ARP_MAXAGE 120
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name General configuration options
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the uIP packet buffer.
|
||||||
|
*
|
||||||
|
* The uIP packet buffer should not be smaller than 60 bytes, and does
|
||||||
|
* not need to be larger than 1500 bytes. Lower size results in lower
|
||||||
|
* TCP throughput, larger size results in higher TCP throughput.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifndef UIP_CONF_BUFFER_SIZE
|
||||||
|
#define UIP_BUFSIZE 400
|
||||||
|
#else /* UIP_CONF_BUFFER_SIZE */
|
||||||
|
#define UIP_BUFSIZE UIP_CONF_BUFFER_SIZE
|
||||||
|
#endif /* UIP_CONF_BUFFER_SIZE */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if statistics support should be compiled in.
|
||||||
|
*
|
||||||
|
* The statistics is useful for debugging and to show the user.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifndef UIP_CONF_STATISTICS
|
||||||
|
#define UIP_STATISTICS 0
|
||||||
|
#else /* UIP_CONF_STATISTICS */
|
||||||
|
#define UIP_STATISTICS UIP_CONF_STATISTICS
|
||||||
|
#endif /* UIP_CONF_STATISTICS */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if logging of certain events should be compiled in.
|
||||||
|
*
|
||||||
|
* This is useful mostly for debugging. The function uip_log()
|
||||||
|
* must be implemented to suit the architecture of the project, if
|
||||||
|
* logging is turned on.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifndef UIP_CONF_LOGGING
|
||||||
|
#define UIP_LOGGING 0
|
||||||
|
#else /* UIP_CONF_LOGGING */
|
||||||
|
#define UIP_LOGGING UIP_CONF_LOGGING
|
||||||
|
#endif /* UIP_CONF_LOGGING */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast support.
|
||||||
|
*
|
||||||
|
* This flag configures IP broadcast support. This is useful only
|
||||||
|
* together with UDP.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef UIP_CONF_BROADCAST
|
||||||
|
#define UIP_BROADCAST 0
|
||||||
|
#else /* UIP_CONF_BROADCAST */
|
||||||
|
#define UIP_BROADCAST UIP_CONF_BROADCAST
|
||||||
|
#endif /* UIP_CONF_BROADCAST */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print out a uIP log message.
|
||||||
|
*
|
||||||
|
* This function must be implemented by the module that uses uIP, and
|
||||||
|
* is called by uIP whenever a log message is generated.
|
||||||
|
*/
|
||||||
|
void uip_log(char *msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The link level header length.
|
||||||
|
*
|
||||||
|
* This is the offset into the uip_buf where the IP header can be
|
||||||
|
* found. For Ethernet, this should be set to 14. For SLIP, this
|
||||||
|
* should be set to 0.
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifdef UIP_CONF_LLH_LEN
|
||||||
|
#define UIP_LLH_LEN UIP_CONF_LLH_LEN
|
||||||
|
#else /* UIP_CONF_LLH_LEN */
|
||||||
|
#define UIP_LLH_LEN 14
|
||||||
|
#endif /* UIP_CONF_LLH_LEN */
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* \name CPU architecture configuration
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* The CPU architecture configuration is where the endianess of the
|
||||||
|
* CPU on which uIP is to be run is specified. Most CPUs today are
|
||||||
|
* little endian, and the most notable exception are the Motorolas
|
||||||
|
* which are big endian. The BYTE_ORDER macro should be changed to
|
||||||
|
* reflect the CPU architecture on which uIP is to be run.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The byte order of the CPU architecture on which uIP is to be run.
|
||||||
|
*
|
||||||
|
* This option can be either BIG_ENDIAN (Motorola byte order) or
|
||||||
|
* LITTLE_ENDIAN (Intel byte order).
|
||||||
|
*
|
||||||
|
* \hideinitializer
|
||||||
|
*/
|
||||||
|
#ifdef UIP_CONF_BYTE_ORDER
|
||||||
|
#define UIP_BYTE_ORDER UIP_CONF_BYTE_ORDER
|
||||||
|
#else /* UIP_CONF_BYTE_ORDER */
|
||||||
|
#define UIP_BYTE_ORDER UIP_LITTLE_ENDIAN
|
||||||
|
#endif /* UIP_CONF_BYTE_ORDER */
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name Appication specific configurations
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* An uIP application is implemented using a single application
|
||||||
|
* function that is called by uIP whenever a TCP/IP event occurs. The
|
||||||
|
* name of this function must be registered with uIP at compile time
|
||||||
|
* using the UIP_APPCALL definition.
|
||||||
|
*
|
||||||
|
* uIP applications can store the application state within the
|
||||||
|
* uip_conn structure by specifying the type of the application
|
||||||
|
* structure by typedef:ing the type uip_tcp_appstate_t and uip_udp_appstate_t.
|
||||||
|
*
|
||||||
|
* The file containing the definitions must be included in the
|
||||||
|
* uipopt.h file.
|
||||||
|
*
|
||||||
|
* The following example illustrates how this can look.
|
||||||
|
\code
|
||||||
|
|
||||||
|
void httpd_appcall(void);
|
||||||
|
#define UIP_APPCALL httpd_appcall
|
||||||
|
|
||||||
|
struct httpd_state {
|
||||||
|
u8_t state;
|
||||||
|
u16_t count;
|
||||||
|
char *dataptr;
|
||||||
|
char *script;
|
||||||
|
};
|
||||||
|
typedef struct httpd_state uip_tcp_appstate_t
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var #define UIP_APPCALL
|
||||||
|
*
|
||||||
|
* The name of the application function that uIP should call in
|
||||||
|
* response to TCP/IP events.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var typedef uip_tcp_appstate_t
|
||||||
|
*
|
||||||
|
* The type of the application state that is to be stored in the
|
||||||
|
* uip_conn structure. This usually is typedef:ed to a struct holding
|
||||||
|
* application state information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var typedef uip_udp_appstate_t
|
||||||
|
*
|
||||||
|
* The type of the application state that is to be stored in the
|
||||||
|
* uip_conn structure. This usually is typedef:ed to a struct holding
|
||||||
|
* application state information.
|
||||||
|
*/
|
||||||
|
/** @} */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#endif /* __UIPOPT_H__ */
|
@ -0,0 +1,330 @@
|
|||||||
|
/*
|
||||||
|
LUFA Library
|
||||||
|
Copyright (C) Dean Camera, 2010.
|
||||||
|
|
||||||
|
dean [at] fourwalledcubicle [dot] com
|
||||||
|
www.fourwalledcubicle.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||||
|
|
||||||
|
Permission to use, copy, modify, distribute, and sell this
|
||||||
|
software and its documentation for any purpose is hereby granted
|
||||||
|
without fee, provided that the above copyright notice appear in
|
||||||
|
all copies and that both that the copyright notice and this
|
||||||
|
permission notice and warranty disclaimer appear in supporting
|
||||||
|
documentation, and that the name of the author not be used in
|
||||||
|
advertising or publicity pertaining to distribution of the
|
||||||
|
software without specific, written prior permission.
|
||||||
|
|
||||||
|
The author disclaim all warranties with regard to this
|
||||||
|
software, including all implied warranties of merchantability
|
||||||
|
and fitness. In no event shall the author be liable for any
|
||||||
|
special, indirect or consequential damages or any damages
|
||||||
|
whatsoever resulting from loss of use, data or profits, whether
|
||||||
|
in an action of contract, negligence or other tortious action,
|
||||||
|
arising out of or in connection with the use or performance of
|
||||||
|
this software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
*
|
||||||
|
* Main source file for the Webserver project. This file contains the main tasks of
|
||||||
|
* the demo and is responsible for the initial application hardware configuration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Webserver.h"
|
||||||
|
|
||||||
|
/** LUFA RNDIS Class driver interface configuration and state information. This structure is
|
||||||
|
* passed to all RNDIS Class driver functions, so that multiple instances of the same class
|
||||||
|
* within a device can be differentiated from one another.
|
||||||
|
*/
|
||||||
|
USB_ClassInfo_RNDIS_Host_t Ethernet_RNDIS_Interface =
|
||||||
|
{
|
||||||
|
.Config =
|
||||||
|
{
|
||||||
|
.DataINPipeNumber = 1,
|
||||||
|
.DataINPipeDoubleBank = false,
|
||||||
|
|
||||||
|
.DataOUTPipeNumber = 2,
|
||||||
|
.DataOUTPipeDoubleBank = false,
|
||||||
|
|
||||||
|
.NotificationPipeNumber = 3,
|
||||||
|
.NotificationPipeDoubleBank = false,
|
||||||
|
|
||||||
|
.HostMaxPacketSize = UIP_CONF_BUFFER_SIZE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
volatile uint8_t uIPManagementTimeout;
|
||||||
|
|
||||||
|
/** ISR for the management of the connection management timeout counter */
|
||||||
|
ISR(TIMER0_COMPA_vect, ISR_BLOCK)
|
||||||
|
{
|
||||||
|
if (uIPManagementTimeout)
|
||||||
|
uIPManagementTimeout--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPCallback(void)
|
||||||
|
{
|
||||||
|
printf("Callback!\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Main program entry point. This routine configures the hardware required by the application, then
|
||||||
|
* enters a loop to run the application tasks in sequence.
|
||||||
|
*/
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
SetupHardware();
|
||||||
|
|
||||||
|
puts_P(PSTR(ESC_FG_CYAN "RNDIS Host Demo running.\r\n" ESC_FG_WHITE));
|
||||||
|
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
switch (USB_HostState)
|
||||||
|
{
|
||||||
|
case HOST_STATE_Addressed:
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
|
||||||
|
|
||||||
|
uint16_t ConfigDescriptorSize;
|
||||||
|
uint8_t ConfigDescriptorData[512];
|
||||||
|
|
||||||
|
if (USB_Host_GetDeviceConfigDescriptor(1, &ConfigDescriptorSize, ConfigDescriptorData,
|
||||||
|
sizeof(ConfigDescriptorData)) != HOST_GETCONFIG_Successful)
|
||||||
|
{
|
||||||
|
printf("Error Retrieving Configuration Descriptor.\r\n");
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||||
|
USB_HostState = HOST_STATE_WaitForDeviceRemoval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RNDIS_Host_ConfigurePipes(&Ethernet_RNDIS_Interface,
|
||||||
|
ConfigDescriptorSize, ConfigDescriptorData) != RNDIS_ENUMERROR_NoError)
|
||||||
|
{
|
||||||
|
printf("Attached Device Not a Valid RNDIS Class Device.\r\n");
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||||
|
USB_HostState = HOST_STATE_WaitForDeviceRemoval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (USB_Host_SetDeviceConfiguration(1) != HOST_SENDCONTROL_Successful)
|
||||||
|
{
|
||||||
|
printf("Error Setting Device Configuration.\r\n");
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||||
|
USB_HostState = HOST_STATE_WaitForDeviceRemoval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RNDIS_Host_InitializeDevice(&Ethernet_RNDIS_Interface) != HOST_SENDCONTROL_Successful)
|
||||||
|
{
|
||||||
|
printf("Error Initializing Device.\r\n");
|
||||||
|
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||||
|
USB_HostState = HOST_STATE_WaitForDeviceRemoval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Device Max Transfer Size: %lu bytes.\r\n", Ethernet_RNDIS_Interface.State.DeviceMaxPacketSize);
|
||||||
|
|
||||||
|
uint32_t PacketFilter = (REMOTE_NDIS_PACKET_DIRECTED | REMOTE_NDIS_PACKET_BROADCAST | REMOTE_NDIS_PACKET_ALL_MULTICAST);
|
||||||
|
if (RNDIS_Host_SetRNDISProperty(&Ethernet_RNDIS_Interface, OID_GEN_CURRENT_PACKET_FILTER,
|
||||||
|
&PacketFilter, sizeof(PacketFilter)) != HOST_SENDCONTROL_Successful)
|
||||||
|
{
|
||||||
|
printf("Error Setting Device Packet Filter.\r\n");
|
||||||
|
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||||
|
USB_HostState = HOST_STATE_WaitForDeviceRemoval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct uip_eth_addr MACAddress;
|
||||||
|
if (RNDIS_Host_QueryRNDISProperty(&Ethernet_RNDIS_Interface, OID_802_3_CURRENT_ADDRESS,
|
||||||
|
&MACAddress, sizeof(MACAddress)) != HOST_SENDCONTROL_Successful)
|
||||||
|
{
|
||||||
|
printf("Error Getting MAC Address.\r\n");
|
||||||
|
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||||
|
USB_HostState = HOST_STATE_WaitForDeviceRemoval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("MAC Address: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\r\n",
|
||||||
|
MACAddress.addr[0], MACAddress.addr[1], MACAddress.addr[2],
|
||||||
|
MACAddress.addr[3], MACAddress.addr[4], MACAddress.addr[5]);
|
||||||
|
|
||||||
|
uip_setethaddr(MACAddress);
|
||||||
|
|
||||||
|
printf("RNDIS Device Enumerated.\r\n");
|
||||||
|
USB_HostState = HOST_STATE_Configured;
|
||||||
|
break;
|
||||||
|
case HOST_STATE_Configured:
|
||||||
|
ProcessIncommingPacket();
|
||||||
|
ManageConnections();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
RNDIS_Host_USBTask(&Ethernet_RNDIS_Interface);
|
||||||
|
USB_USBTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessIncommingPacket(void)
|
||||||
|
{
|
||||||
|
if (RNDIS_Host_IsPacketReceived(&Ethernet_RNDIS_Interface))
|
||||||
|
{
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
|
||||||
|
|
||||||
|
/* Read the incomming packet straight into the UIP packet buffer */
|
||||||
|
RNDIS_Host_ReadPacket(&Ethernet_RNDIS_Interface, &uip_buf, &uip_len);
|
||||||
|
|
||||||
|
printf("RECEIVED PACKET (%d):\r\n", uip_len);
|
||||||
|
for (uint16_t i = 0; i < uip_len; i++)
|
||||||
|
printf("0x%02X ", uip_buf[i]);
|
||||||
|
printf("\r\n\r\n");
|
||||||
|
|
||||||
|
#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
|
||||||
|
|
||||||
|
if (BUF->type == HTONS(UIP_ETHTYPE_IP))
|
||||||
|
{
|
||||||
|
/* Filter packet by MAC destination */
|
||||||
|
uip_arp_ipin();
|
||||||
|
|
||||||
|
/* Process incomming packet */
|
||||||
|
uip_input();
|
||||||
|
|
||||||
|
/* Add destination MAC to outgoing packet */
|
||||||
|
if (uip_len > 0)
|
||||||
|
uip_arp_out();
|
||||||
|
}
|
||||||
|
else if (BUF->type == HTONS(UIP_ETHTYPE_ARP))
|
||||||
|
{
|
||||||
|
/* Process ARP packet */
|
||||||
|
uip_arp_arpin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If a response was generated, send it */
|
||||||
|
if (uip_len > 0)
|
||||||
|
RNDIS_Host_SendPacket(&Ethernet_RNDIS_Interface, &uip_buf, uip_len);
|
||||||
|
|
||||||
|
printf("SENT PACKET (%d):\r\n", uip_len);
|
||||||
|
for (uint16_t i = 0; i < uip_len; i++)
|
||||||
|
printf("0x%02X ", uip_buf[i]);
|
||||||
|
printf("\r\n\r\n");
|
||||||
|
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManageConnections(void)
|
||||||
|
{
|
||||||
|
if (!(uIPManagementTimeout))
|
||||||
|
{
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < UIP_CONNS; i++)
|
||||||
|
{
|
||||||
|
/* Run periodic connection management for each connection */
|
||||||
|
uip_periodic(i);
|
||||||
|
|
||||||
|
/* If a response was generated, send it */
|
||||||
|
if (uip_len > 0)
|
||||||
|
RNDIS_Host_SendPacket(&Ethernet_RNDIS_Interface, &uip_buf, uip_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
uip_arp_timer();
|
||||||
|
|
||||||
|
uIPManagementTimeout = 250;
|
||||||
|
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Configures the board hardware and chip peripherals for the demo's functionality. */
|
||||||
|
void SetupHardware(void)
|
||||||
|
{
|
||||||
|
/* Disable watchdog if enabled by bootloader/fuses */
|
||||||
|
MCUSR &= ~(1 << WDRF);
|
||||||
|
wdt_disable();
|
||||||
|
|
||||||
|
/* Disable clock division */
|
||||||
|
clock_prescale_set(clock_div_1);
|
||||||
|
|
||||||
|
/* Hardware Initialization */
|
||||||
|
SerialStream_Init(9600, false);
|
||||||
|
LEDs_Init();
|
||||||
|
USB_Init();
|
||||||
|
|
||||||
|
/* Millisecond timer initialization for managing the command timeout counter */
|
||||||
|
OCR0A = ((F_CPU / 64) / 1000);
|
||||||
|
TCCR0A = (1 << WGM01);
|
||||||
|
TCCR0B = ((1 << CS01) | (1 << CS00));
|
||||||
|
|
||||||
|
/* uIP Stack Initialization */
|
||||||
|
uip_init();
|
||||||
|
|
||||||
|
uip_ipaddr_t IPAddress, Netmask, GatewayIPAddress;
|
||||||
|
uip_ipaddr(&IPAddress, 192, 168, 1, 10);
|
||||||
|
uip_ipaddr(&Netmask, 0xFF, 0xFF, 0xFF, 0x00);
|
||||||
|
uip_ipaddr(&GatewayIPAddress, 192, 168, 1, 1);
|
||||||
|
uip_sethostaddr(&IPAddress);
|
||||||
|
uip_setnetmask(&Netmask);
|
||||||
|
uip_setdraddr(&GatewayIPAddress);
|
||||||
|
|
||||||
|
/* HTTP Webserver Initialization */
|
||||||
|
uip_listen(HTONS(80));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Event handler for the USB_DeviceAttached event. This indicates that a device has been attached to the host, and
|
||||||
|
* starts the library USB task to begin the enumeration and USB management process.
|
||||||
|
*/
|
||||||
|
void EVENT_USB_Host_DeviceAttached(void)
|
||||||
|
{
|
||||||
|
puts_P(PSTR("Device Attached.\r\n"));
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Event handler for the USB_DeviceUnattached event. This indicates that a device has been removed from the host, and
|
||||||
|
* stops the library USB task management process.
|
||||||
|
*/
|
||||||
|
void EVENT_USB_Host_DeviceUnattached(void)
|
||||||
|
{
|
||||||
|
puts_P(PSTR("\r\nDevice Unattached.\r\n"));
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Event handler for the USB_DeviceEnumerationComplete event. This indicates that a device has been successfully
|
||||||
|
* enumerated by the host and is now ready to be used by the application.
|
||||||
|
*/
|
||||||
|
void EVENT_USB_Host_DeviceEnumerationComplete(void)
|
||||||
|
{
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Event handler for the USB_HostError event. This indicates that a hardware error occurred while in host mode. */
|
||||||
|
void EVENT_USB_Host_HostError(const uint8_t ErrorCode)
|
||||||
|
{
|
||||||
|
USB_ShutDown();
|
||||||
|
|
||||||
|
printf_P(PSTR(ESC_FG_RED "Host Mode Error\r\n"
|
||||||
|
" -- Error Code %d\r\n" ESC_FG_WHITE), ErrorCode);
|
||||||
|
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||||
|
for(;;);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Event handler for the USB_DeviceEnumerationFailed event. This indicates that a problem occurred while
|
||||||
|
* enumerating an attached USB device.
|
||||||
|
*/
|
||||||
|
void EVENT_USB_Host_DeviceEnumerationFailed(const uint8_t ErrorCode, const uint8_t SubErrorCode)
|
||||||
|
{
|
||||||
|
printf_P(PSTR(ESC_FG_RED "Dev Enum Error\r\n"
|
||||||
|
" -- Error Code %d\r\n"
|
||||||
|
" -- Sub Error Code %d\r\n"
|
||||||
|
" -- In State %d\r\n" ESC_FG_WHITE), ErrorCode, SubErrorCode, USB_HostState);
|
||||||
|
|
||||||
|
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
LUFA Library
|
||||||
|
Copyright (C) Dean Camera, 2010.
|
||||||
|
|
||||||
|
dean [at] fourwalledcubicle [dot] com
|
||||||
|
www.fourwalledcubicle.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||||
|
|
||||||
|
Permission to use, copy, modify, distribute, and sell this
|
||||||
|
software and its documentation for any purpose is hereby granted
|
||||||
|
without fee, provided that the above copyright notice appear in
|
||||||
|
all copies and that both that the copyright notice and this
|
||||||
|
permission notice and warranty disclaimer appear in supporting
|
||||||
|
documentation, and that the name of the author not be used in
|
||||||
|
advertising or publicity pertaining to distribution of the
|
||||||
|
software without specific, written prior permission.
|
||||||
|
|
||||||
|
The author disclaim all warranties with regard to this
|
||||||
|
software, including all implied warranties of merchantability
|
||||||
|
and fitness. In no event shall the author be liable for any
|
||||||
|
special, indirect or consequential damages or any damages
|
||||||
|
whatsoever resulting from loss of use, data or profits, whether
|
||||||
|
in an action of contract, negligence or other tortious action,
|
||||||
|
arising out of or in connection with the use or performance of
|
||||||
|
this software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
*
|
||||||
|
* Header file for RNDISEthernetHost.c.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RNDIS_HOST_H_
|
||||||
|
#define _RNDIS_HOST_H_
|
||||||
|
|
||||||
|
/* Includes: */
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/wdt.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include <avr/power.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <LUFA/Version.h>
|
||||||
|
#include <LUFA/Drivers/Misc/TerminalCodes.h>
|
||||||
|
#include <LUFA/Drivers/Peripheral/SerialStream.h>
|
||||||
|
#include <LUFA/Drivers/Board/LEDs.h>
|
||||||
|
#include <LUFA/Drivers/USB/USB.h>
|
||||||
|
#include <LUFA/Drivers/USB/Class/RNDIS.h>
|
||||||
|
|
||||||
|
#include <uip.h>
|
||||||
|
#include <uip_arp.h>
|
||||||
|
|
||||||
|
/* Macros: */
|
||||||
|
/** LED mask for the library LED driver, to indicate that the USB interface is not ready. */
|
||||||
|
#define LEDMASK_USB_NOTREADY LEDS_LED1
|
||||||
|
|
||||||
|
/** LED mask for the library LED driver, to indicate that the USB interface is enumerating. */
|
||||||
|
#define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3)
|
||||||
|
|
||||||
|
/** LED mask for the library LED driver, to indicate that the USB interface is ready. */
|
||||||
|
#define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4)
|
||||||
|
|
||||||
|
/** LED mask for the library LED driver, to indicate that an error has occurred in the USB interface. */
|
||||||
|
#define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3)
|
||||||
|
|
||||||
|
/** LED mask for the library LED driver, to indicate that the USB interface is busy. */
|
||||||
|
#define LEDMASK_USB_BUSY LEDS_LED2
|
||||||
|
|
||||||
|
/* Function Prototypes: */
|
||||||
|
void SetupHardware(void);
|
||||||
|
void ProcessIncommingPacket(void);
|
||||||
|
void ManageConnections(void);
|
||||||
|
void TCPCallback(void);
|
||||||
|
|
||||||
|
void EVENT_USB_Host_HostError(const uint8_t ErrorCode);
|
||||||
|
void EVENT_USB_Host_DeviceAttached(void);
|
||||||
|
void EVENT_USB_Host_DeviceUnattached(void);
|
||||||
|
void EVENT_USB_Host_DeviceEnumerationFailed(const uint8_t ErrorCode, const uint8_t SubErrorCode);
|
||||||
|
void EVENT_USB_Host_DeviceEnumerationComplete(void);
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,742 @@
|
|||||||
|
# Hey Emacs, this is a -*- makefile -*-
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
|
||||||
|
# >> Modified for use with the LUFA project. <<
|
||||||
|
#
|
||||||
|
# Released to the Public Domain
|
||||||
|
#
|
||||||
|
# Additional material for this makefile was written by:
|
||||||
|
# Peter Fleury
|
||||||
|
# Tim Henigan
|
||||||
|
# Colin O'Flynn
|
||||||
|
# Reiner Patommel
|
||||||
|
# Markus Pfaff
|
||||||
|
# Sander Pool
|
||||||
|
# Frederik Rouleau
|
||||||
|
# Carlos Lamas
|
||||||
|
# Dean Camera
|
||||||
|
# Opendous Inc.
|
||||||
|
# Denver Gingerich
|
||||||
|
#
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# On command line:
|
||||||
|
#
|
||||||
|
# make all = Make software.
|
||||||
|
#
|
||||||
|
# make clean = Clean out built project files.
|
||||||
|
#
|
||||||
|
# make coff = Convert ELF to AVR COFF.
|
||||||
|
#
|
||||||
|
# make extcoff = Convert ELF to AVR Extended COFF.
|
||||||
|
#
|
||||||
|
# make program = Download the hex file to the device, using avrdude.
|
||||||
|
# Please customize the avrdude settings below first!
|
||||||
|
#
|
||||||
|
# make dfu = Download the hex file to the device, using dfu-programmer (must
|
||||||
|
# have dfu-programmer installed).
|
||||||
|
#
|
||||||
|
# make flip = Download the hex file to the device, using Atmel FLIP (must
|
||||||
|
# have Atmel FLIP installed).
|
||||||
|
#
|
||||||
|
# make dfu-ee = Download the eeprom file to the device, using dfu-programmer
|
||||||
|
# (must have dfu-programmer installed).
|
||||||
|
#
|
||||||
|
# make flip-ee = Download the eeprom file to the device, using Atmel FLIP
|
||||||
|
# (must have Atmel FLIP installed).
|
||||||
|
#
|
||||||
|
# make doxygen = Generate DoxyGen documentation for the project (must have
|
||||||
|
# DoxyGen installed)
|
||||||
|
#
|
||||||
|
# make debug = Start either simulavr or avarice as specified for debugging,
|
||||||
|
# with avr-gdb or avr-insight as the front end for debugging.
|
||||||
|
#
|
||||||
|
# make filename.s = Just compile filename.c into the assembler code only.
|
||||||
|
#
|
||||||
|
# make filename.i = Create a preprocessed source file for use in submitting
|
||||||
|
# bug reports to the GCC project.
|
||||||
|
#
|
||||||
|
# To rebuild project do "make clean" then "make all".
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
# MCU name
|
||||||
|
MCU = at90usb1287
|
||||||
|
|
||||||
|
|
||||||
|
# Target board (see library "Board Types" documentation, USER or blank for projects not requiring
|
||||||
|
# LUFA board drivers). If USER is selected, put custom board drivers in a directory called
|
||||||
|
# "Board" inside the application directory.
|
||||||
|
BOARD = USBKEY
|
||||||
|
|
||||||
|
|
||||||
|
# Processor frequency.
|
||||||
|
# This will define a symbol, F_CPU, in all source code files equal to the
|
||||||
|
# processor frequency in Hz. You can then use this symbol in your source code to
|
||||||
|
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
|
||||||
|
# automatically to create a 32-bit value in your source code.
|
||||||
|
#
|
||||||
|
# This will be an integer division of F_CLOCK below, as it is sourced by
|
||||||
|
# F_CLOCK after it has run through any CPU prescalers. Note that this value
|
||||||
|
# does not *change* the processor frequency - it should merely be updated to
|
||||||
|
# reflect the processor speed set externally so that the code can use accurate
|
||||||
|
# software delays.
|
||||||
|
F_CPU = 8000000
|
||||||
|
|
||||||
|
|
||||||
|
# Input clock frequency.
|
||||||
|
# This will define a symbol, F_CLOCK, in all source code files equal to the
|
||||||
|
# input clock frequency (before any prescaling is performed) in Hz. This value may
|
||||||
|
# differ from F_CPU if prescaling is used on the latter, and is required as the
|
||||||
|
# raw input clock is fed directly to the PLL sections of the AVR for high speed
|
||||||
|
# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
|
||||||
|
# at the end, this will be done automatically to create a 32-bit value in your
|
||||||
|
# source code.
|
||||||
|
#
|
||||||
|
# If no clock division is performed on the input clock inside the AVR (via the
|
||||||
|
# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
|
||||||
|
F_CLOCK = $(F_CPU)
|
||||||
|
|
||||||
|
|
||||||
|
# Output format. (can be srec, ihex, binary)
|
||||||
|
FORMAT = ihex
|
||||||
|
|
||||||
|
|
||||||
|
# Target file name (without extension).
|
||||||
|
TARGET = Webserver
|
||||||
|
|
||||||
|
|
||||||
|
# Object files directory
|
||||||
|
# To put object files in current directory, use a dot (.), do NOT make
|
||||||
|
# this an empty or blank macro!
|
||||||
|
OBJDIR = .
|
||||||
|
|
||||||
|
|
||||||
|
# Path to the LUFA library
|
||||||
|
LUFA_PATH = ../../../
|
||||||
|
|
||||||
|
|
||||||
|
# LUFA library compile-time options
|
||||||
|
LUFA_OPTS += -D USB_HOST_ONLY
|
||||||
|
LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
|
||||||
|
|
||||||
|
|
||||||
|
# List C source files here. (C dependencies are automatically generated.)
|
||||||
|
SRC = $(TARGET).c \
|
||||||
|
$(LUFA_PATH)/LUFA/Drivers/Peripheral/SerialStream.c \
|
||||||
|
$(LUFA_PATH)/LUFA/Drivers/Peripheral/Serial.c \
|
||||||
|
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \
|
||||||
|
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c \
|
||||||
|
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c \
|
||||||
|
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/HostChapter9.c \
|
||||||
|
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/LowLevel.c \
|
||||||
|
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Pipe.c \
|
||||||
|
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/Events.c \
|
||||||
|
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \
|
||||||
|
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c \
|
||||||
|
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c \
|
||||||
|
$(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/RNDIS.c \
|
||||||
|
$(LUFA_PATH)/LUFA/Drivers/USB/Class/Host/RNDIS.c \
|
||||||
|
Lib/uip/uip.c \
|
||||||
|
Lib/uip/uip_arp.c \
|
||||||
|
Lib/uip/uiplib.c \
|
||||||
|
Lib/uip/psock.c \
|
||||||
|
Lib/uip/timer.c \
|
||||||
|
Lib/uip/uip-neighbor.c \
|
||||||
|
|
||||||
|
|
||||||
|
# List C++ source files here. (C dependencies are automatically generated.)
|
||||||
|
CPPSRC =
|
||||||
|
|
||||||
|
|
||||||
|
# List Assembler source files here.
|
||||||
|
# Make them always end in a capital .S. Files ending in a lowercase .s
|
||||||
|
# will not be considered source files but generated files (assembler
|
||||||
|
# output from the compiler), and will be deleted upon "make clean"!
|
||||||
|
# Even though the DOS/Win* filesystem matches both .s and .S the same,
|
||||||
|
# it will preserve the spelling of the filenames, and gcc itself does
|
||||||
|
# care about how the name is spelled on its command-line.
|
||||||
|
ASRC =
|
||||||
|
|
||||||
|
|
||||||
|
# Optimization level, can be [0, 1, 2, 3, s].
|
||||||
|
# 0 = turn off optimization. s = optimize for size.
|
||||||
|
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
|
||||||
|
OPT = s
|
||||||
|
|
||||||
|
|
||||||
|
# Debugging format.
|
||||||
|
# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
|
||||||
|
# AVR Studio 4.10 requires dwarf-2.
|
||||||
|
# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
|
||||||
|
DEBUG = dwarf-2
|
||||||
|
|
||||||
|
|
||||||
|
# List any extra directories to look for include files here.
|
||||||
|
# Each directory must be seperated by a space.
|
||||||
|
# Use forward slashes for directory separators.
|
||||||
|
# For a directory that has spaces, enclose it in quotes.
|
||||||
|
EXTRAINCDIRS = $(LUFA_PATH)/ Lib/uip/ Lib/uip/conf/
|
||||||
|
|
||||||
|
|
||||||
|
# Compiler flag to set the C Standard level.
|
||||||
|
# c89 = "ANSI" C
|
||||||
|
# gnu89 = c89 plus GCC extensions
|
||||||
|
# c99 = ISO C99 standard (not yet fully implemented)
|
||||||
|
# gnu99 = c99 plus GCC extensions
|
||||||
|
CSTANDARD = -std=gnu99
|
||||||
|
|
||||||
|
|
||||||
|
# Place -D or -U options here for C sources
|
||||||
|
CDEFS = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) $(LUFA_OPTS)
|
||||||
|
|
||||||
|
|
||||||
|
# Place -D or -U options here for ASM sources
|
||||||
|
ADEFS = -DF_CPU=$(F_CPU)
|
||||||
|
|
||||||
|
|
||||||
|
# Place -D or -U options here for C++ sources
|
||||||
|
CPPDEFS = -DF_CPU=$(F_CPU)UL
|
||||||
|
#CPPDEFS += -D__STDC_LIMIT_MACROS
|
||||||
|
#CPPDEFS += -D__STDC_CONSTANT_MACROS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Compiler Options C ----------------
|
||||||
|
# -g*: generate debugging information
|
||||||
|
# -O*: optimization level
|
||||||
|
# -f...: tuning, see GCC manual and avr-libc documentation
|
||||||
|
# -Wall...: warning level
|
||||||
|
# -Wa,...: tell GCC to pass this to the assembler.
|
||||||
|
# -adhlns...: create assembler listing
|
||||||
|
CFLAGS = -g$(DEBUG)
|
||||||
|
CFLAGS += $(CDEFS)
|
||||||
|
CFLAGS += -O$(OPT)
|
||||||
|
CFLAGS += -funsigned-char
|
||||||
|
CFLAGS += -funsigned-bitfields
|
||||||
|
CFLAGS += -ffunction-sections
|
||||||
|
CFLAGS += -fno-inline-small-functions
|
||||||
|
CFLAGS += -fpack-struct
|
||||||
|
CFLAGS += -fshort-enums
|
||||||
|
CFLAGS += -Wall
|
||||||
|
CFLAGS += -Wstrict-prototypes
|
||||||
|
CFLAGS += -Wundef
|
||||||
|
#CFLAGS += -fno-unit-at-a-time
|
||||||
|
#CFLAGS += -Wunreachable-code
|
||||||
|
#CFLAGS += -Wsign-compare
|
||||||
|
CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst)
|
||||||
|
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
|
||||||
|
CFLAGS += $(CSTANDARD)
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Compiler Options C++ ----------------
|
||||||
|
# -g*: generate debugging information
|
||||||
|
# -O*: optimization level
|
||||||
|
# -f...: tuning, see GCC manual and avr-libc documentation
|
||||||
|
# -Wall...: warning level
|
||||||
|
# -Wa,...: tell GCC to pass this to the assembler.
|
||||||
|
# -adhlns...: create assembler listing
|
||||||
|
CPPFLAGS = -g$(DEBUG)
|
||||||
|
CPPFLAGS += $(CPPDEFS)
|
||||||
|
CPPFLAGS += -O$(OPT)
|
||||||
|
CPPFLAGS += -funsigned-char
|
||||||
|
CPPFLAGS += -funsigned-bitfields
|
||||||
|
CPPFLAGS += -fpack-struct
|
||||||
|
CPPFLAGS += -fshort-enums
|
||||||
|
CPPFLAGS += -fno-exceptions
|
||||||
|
CPPFLAGS += -Wall
|
||||||
|
CFLAGS += -Wundef
|
||||||
|
#CPPFLAGS += -mshort-calls
|
||||||
|
#CPPFLAGS += -fno-unit-at-a-time
|
||||||
|
#CPPFLAGS += -Wstrict-prototypes
|
||||||
|
#CPPFLAGS += -Wunreachable-code
|
||||||
|
#CPPFLAGS += -Wsign-compare
|
||||||
|
CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)
|
||||||
|
CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
|
||||||
|
#CPPFLAGS += $(CSTANDARD)
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Assembler Options ----------------
|
||||||
|
# -Wa,...: tell GCC to pass this to the assembler.
|
||||||
|
# -adhlns: create listing
|
||||||
|
# -gstabs: have the assembler create line number information; note that
|
||||||
|
# for use in COFF files, additional information about filenames
|
||||||
|
# and function names needs to be present in the assembler source
|
||||||
|
# files -- see avr-libc docs [FIXME: not yet described there]
|
||||||
|
# -listing-cont-lines: Sets the maximum number of continuation lines of hex
|
||||||
|
# dump that will be displayed for a given single line of source input.
|
||||||
|
ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Library Options ----------------
|
||||||
|
# Minimalistic printf version
|
||||||
|
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
|
||||||
|
|
||||||
|
# Floating point printf version (requires MATH_LIB = -lm below)
|
||||||
|
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
|
||||||
|
|
||||||
|
# If this is left blank, then it will use the Standard printf version.
|
||||||
|
PRINTF_LIB =
|
||||||
|
#PRINTF_LIB = $(PRINTF_LIB_MIN)
|
||||||
|
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
|
||||||
|
|
||||||
|
|
||||||
|
# Minimalistic scanf version
|
||||||
|
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
|
||||||
|
|
||||||
|
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
|
||||||
|
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
|
||||||
|
|
||||||
|
# If this is left blank, then it will use the Standard scanf version.
|
||||||
|
SCANF_LIB =
|
||||||
|
#SCANF_LIB = $(SCANF_LIB_MIN)
|
||||||
|
#SCANF_LIB = $(SCANF_LIB_FLOAT)
|
||||||
|
|
||||||
|
|
||||||
|
MATH_LIB = -lm
|
||||||
|
|
||||||
|
|
||||||
|
# List any extra directories to look for libraries here.
|
||||||
|
# Each directory must be seperated by a space.
|
||||||
|
# Use forward slashes for directory separators.
|
||||||
|
# For a directory that has spaces, enclose it in quotes.
|
||||||
|
EXTRALIBDIRS =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- External Memory Options ----------------
|
||||||
|
|
||||||
|
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
|
||||||
|
# used for variables (.data/.bss) and heap (malloc()).
|
||||||
|
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
|
||||||
|
|
||||||
|
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
|
||||||
|
# only used for heap (malloc()).
|
||||||
|
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
|
||||||
|
|
||||||
|
EXTMEMOPTS =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Linker Options ----------------
|
||||||
|
# -Wl,...: tell GCC to pass this to linker.
|
||||||
|
# -Map: create map file
|
||||||
|
# --cref: add cross reference to map file
|
||||||
|
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
|
||||||
|
LDFLAGS += -Wl,--relax
|
||||||
|
LDFLAGS += -Wl,--gc-sections
|
||||||
|
LDFLAGS += $(EXTMEMOPTS)
|
||||||
|
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
|
||||||
|
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
|
||||||
|
#LDFLAGS += -T linker_script.x
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Programming Options (avrdude) ----------------
|
||||||
|
|
||||||
|
# Programming hardware: alf avr910 avrisp bascom bsd
|
||||||
|
# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500
|
||||||
|
#
|
||||||
|
# Type: avrdude -c ?
|
||||||
|
# to get a full listing.
|
||||||
|
#
|
||||||
|
AVRDUDE_PROGRAMMER = jtagmkII
|
||||||
|
|
||||||
|
# com1 = serial port. Use lpt1 to connect to parallel port.
|
||||||
|
AVRDUDE_PORT = usb
|
||||||
|
|
||||||
|
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
|
||||||
|
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
|
||||||
|
|
||||||
|
|
||||||
|
# Uncomment the following if you want avrdude's erase cycle counter.
|
||||||
|
# Note that this counter needs to be initialized first using -Yn,
|
||||||
|
# see avrdude manual.
|
||||||
|
#AVRDUDE_ERASE_COUNTER = -y
|
||||||
|
|
||||||
|
# Uncomment the following if you do /not/ wish a verification to be
|
||||||
|
# performed after programming the device.
|
||||||
|
#AVRDUDE_NO_VERIFY = -V
|
||||||
|
|
||||||
|
# Increase verbosity level. Please use this when submitting bug
|
||||||
|
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
|
||||||
|
# to submit bug reports.
|
||||||
|
#AVRDUDE_VERBOSE = -v -v
|
||||||
|
|
||||||
|
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
|
||||||
|
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
|
||||||
|
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
|
||||||
|
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Debugging Options ----------------
|
||||||
|
|
||||||
|
# For simulavr only - target MCU frequency.
|
||||||
|
DEBUG_MFREQ = $(F_CPU)
|
||||||
|
|
||||||
|
# Set the DEBUG_UI to either gdb or insight.
|
||||||
|
# DEBUG_UI = gdb
|
||||||
|
DEBUG_UI = insight
|
||||||
|
|
||||||
|
# Set the debugging back-end to either avarice, simulavr.
|
||||||
|
DEBUG_BACKEND = avarice
|
||||||
|
#DEBUG_BACKEND = simulavr
|
||||||
|
|
||||||
|
# GDB Init Filename.
|
||||||
|
GDBINIT_FILE = __avr_gdbinit
|
||||||
|
|
||||||
|
# When using avarice settings for the JTAG
|
||||||
|
JTAG_DEV = /dev/com1
|
||||||
|
|
||||||
|
# Debugging port used to communicate between GDB / avarice / simulavr.
|
||||||
|
DEBUG_PORT = 4242
|
||||||
|
|
||||||
|
# Debugging host used to communicate between GDB / avarice / simulavr, normally
|
||||||
|
# just set to localhost unless doing some sort of crazy debugging when
|
||||||
|
# avarice is running on a different computer.
|
||||||
|
DEBUG_HOST = localhost
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
# Define programs and commands.
|
||||||
|
SHELL = sh
|
||||||
|
CC = avr-gcc
|
||||||
|
OBJCOPY = avr-objcopy
|
||||||
|
OBJDUMP = avr-objdump
|
||||||
|
SIZE = avr-size
|
||||||
|
AR = avr-ar rcs
|
||||||
|
NM = avr-nm
|
||||||
|
AVRDUDE = avrdude
|
||||||
|
REMOVE = rm -f
|
||||||
|
REMOVEDIR = rm -rf
|
||||||
|
COPY = cp
|
||||||
|
WINSHELL = cmd
|
||||||
|
|
||||||
|
# Define Messages
|
||||||
|
# English
|
||||||
|
MSG_ERRORS_NONE = Errors: none
|
||||||
|
MSG_BEGIN = -------- begin --------
|
||||||
|
MSG_END = -------- end --------
|
||||||
|
MSG_SIZE_BEFORE = Size before:
|
||||||
|
MSG_SIZE_AFTER = Size after:
|
||||||
|
MSG_COFF = Converting to AVR COFF:
|
||||||
|
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
|
||||||
|
MSG_FLASH = Creating load file for Flash:
|
||||||
|
MSG_EEPROM = Creating load file for EEPROM:
|
||||||
|
MSG_EXTENDED_LISTING = Creating Extended Listing:
|
||||||
|
MSG_SYMBOL_TABLE = Creating Symbol Table:
|
||||||
|
MSG_LINKING = Linking:
|
||||||
|
MSG_COMPILING = Compiling C:
|
||||||
|
MSG_COMPILING_CPP = Compiling C++:
|
||||||
|
MSG_ASSEMBLING = Assembling:
|
||||||
|
MSG_CLEANING = Cleaning project:
|
||||||
|
MSG_CREATING_LIBRARY = Creating library:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Define all object files.
|
||||||
|
OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)
|
||||||
|
|
||||||
|
# Define all listing files.
|
||||||
|
LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)
|
||||||
|
|
||||||
|
|
||||||
|
# Compiler flags to generate dependency files.
|
||||||
|
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
|
||||||
|
|
||||||
|
|
||||||
|
# Combine all necessary flags and optional flags.
|
||||||
|
# Add target processor to flags.
|
||||||
|
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
|
||||||
|
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
|
||||||
|
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Default target.
|
||||||
|
all: begin gccversion sizebefore build checkinvalidevents showliboptions showtarget sizeafter end
|
||||||
|
|
||||||
|
# Change the build target to build a HEX file or a library.
|
||||||
|
build: elf hex eep lss sym
|
||||||
|
#build: lib
|
||||||
|
|
||||||
|
|
||||||
|
elf: $(TARGET).elf
|
||||||
|
hex: $(TARGET).hex
|
||||||
|
eep: $(TARGET).eep
|
||||||
|
lss: $(TARGET).lss
|
||||||
|
sym: $(TARGET).sym
|
||||||
|
LIBNAME=lib$(TARGET).a
|
||||||
|
lib: $(LIBNAME)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Eye candy.
|
||||||
|
# AVR Studio 3.x does not check make's exit code but relies on
|
||||||
|
# the following magic strings to be generated by the compile job.
|
||||||
|
begin:
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_BEGIN)
|
||||||
|
|
||||||
|
end:
|
||||||
|
@echo $(MSG_END)
|
||||||
|
@echo
|
||||||
|
|
||||||
|
|
||||||
|
# Display size of file.
|
||||||
|
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
|
||||||
|
ELFSIZE = $(SIZE) $(MCU_FLAG) $(FORMAT_FLAG) $(TARGET).elf
|
||||||
|
MCU_FLAG = $(shell $(SIZE) --help | grep -- --mcu > /dev/null && echo --mcu=$(MCU) )
|
||||||
|
FORMAT_FLAG = $(shell $(SIZE) --help | grep -- --format=.*avr > /dev/null && echo --format=avr )
|
||||||
|
|
||||||
|
sizebefore:
|
||||||
|
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
|
||||||
|
2>/dev/null; echo; fi
|
||||||
|
|
||||||
|
sizeafter:
|
||||||
|
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
|
||||||
|
2>/dev/null; echo; fi
|
||||||
|
|
||||||
|
$(LUFA_PATH)/LUFA/LUFA_Events.lst:
|
||||||
|
@make -C $(LUFA_PATH)/LUFA/ LUFA_Events.lst
|
||||||
|
|
||||||
|
checkinvalidevents: $(LUFA_PATH)/LUFA/LUFA_Events.lst
|
||||||
|
@echo
|
||||||
|
@echo Checking for invalid events...
|
||||||
|
@$(shell) avr-nm $(OBJ) | sed -n -e 's/^.*EVENT_/EVENT_/p' | \
|
||||||
|
grep -F -v --file=$(LUFA_PATH)/LUFA/LUFA_Events.lst > InvalidEvents.tmp || true
|
||||||
|
@sed -n -e 's/^/ WARNING - INVALID EVENT NAME: /p' InvalidEvents.tmp
|
||||||
|
@if test -s InvalidEvents.tmp; then exit 1; fi
|
||||||
|
|
||||||
|
showliboptions:
|
||||||
|
@echo
|
||||||
|
@echo ---- Compile Time Library Options ----
|
||||||
|
@for i in $(LUFA_OPTS:-D%=%); do \
|
||||||
|
echo $$i; \
|
||||||
|
done
|
||||||
|
@echo --------------------------------------
|
||||||
|
|
||||||
|
showtarget:
|
||||||
|
@echo
|
||||||
|
@echo --------- Target Information ---------
|
||||||
|
@echo AVR Model: $(MCU)
|
||||||
|
@echo Board: $(BOARD)
|
||||||
|
@echo Clock: $(F_CPU)Hz CPU, $(F_CLOCK)Hz Master
|
||||||
|
@echo --------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
# Display compiler version information.
|
||||||
|
gccversion :
|
||||||
|
@$(CC) --version
|
||||||
|
|
||||||
|
|
||||||
|
# Program the device.
|
||||||
|
program: $(TARGET).hex $(TARGET).eep
|
||||||
|
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
|
||||||
|
|
||||||
|
flip: $(TARGET).hex
|
||||||
|
batchisp -hardware usb -device $(MCU) -operation erase f
|
||||||
|
batchisp -hardware usb -device $(MCU) -operation loadbuffer $(TARGET).hex program
|
||||||
|
batchisp -hardware usb -device $(MCU) -operation start reset 0
|
||||||
|
|
||||||
|
dfu: $(TARGET).hex
|
||||||
|
dfu-programmer $(MCU) erase
|
||||||
|
dfu-programmer $(MCU) flash --debug 1 $(TARGET).hex
|
||||||
|
dfu-programmer $(MCU) reset
|
||||||
|
|
||||||
|
flip-ee: $(TARGET).hex $(TARGET).eep
|
||||||
|
$(COPY) $(TARGET).eep $(TARGET)eep.hex
|
||||||
|
batchisp -hardware usb -device $(MCU) -operation memory EEPROM erase
|
||||||
|
batchisp -hardware usb -device $(MCU) -operation memory EEPROM loadbuffer $(TARGET)eep.hex program
|
||||||
|
batchisp -hardware usb -device $(MCU) -operation start reset 0
|
||||||
|
$(REMOVE) $(TARGET)eep.hex
|
||||||
|
|
||||||
|
dfu-ee: $(TARGET).hex $(TARGET).eep
|
||||||
|
dfu-programmer $(MCU) flash-eeprom --debug 1 --suppress-bootloader-mem $(TARGET).eep
|
||||||
|
dfu-programmer $(MCU) reset
|
||||||
|
|
||||||
|
|
||||||
|
# Generate avr-gdb config/init file which does the following:
|
||||||
|
# define the reset signal, load the target file, connect to target, and set
|
||||||
|
# a breakpoint at main().
|
||||||
|
gdb-config:
|
||||||
|
@$(REMOVE) $(GDBINIT_FILE)
|
||||||
|
@echo define reset >> $(GDBINIT_FILE)
|
||||||
|
@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
|
||||||
|
@echo end >> $(GDBINIT_FILE)
|
||||||
|
@echo file $(TARGET).elf >> $(GDBINIT_FILE)
|
||||||
|
@echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
|
||||||
|
ifeq ($(DEBUG_BACKEND),simulavr)
|
||||||
|
@echo load >> $(GDBINIT_FILE)
|
||||||
|
endif
|
||||||
|
@echo break main >> $(GDBINIT_FILE)
|
||||||
|
|
||||||
|
debug: gdb-config $(TARGET).elf
|
||||||
|
ifeq ($(DEBUG_BACKEND), avarice)
|
||||||
|
@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
|
||||||
|
@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
|
||||||
|
$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
|
||||||
|
@$(WINSHELL) /c pause
|
||||||
|
|
||||||
|
else
|
||||||
|
@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
|
||||||
|
$(DEBUG_MFREQ) --port $(DEBUG_PORT)
|
||||||
|
endif
|
||||||
|
@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
||||||
|
COFFCONVERT = $(OBJCOPY) --debugging
|
||||||
|
COFFCONVERT += --change-section-address .data-0x800000
|
||||||
|
COFFCONVERT += --change-section-address .bss-0x800000
|
||||||
|
COFFCONVERT += --change-section-address .noinit-0x800000
|
||||||
|
COFFCONVERT += --change-section-address .eeprom-0x810000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
coff: $(TARGET).elf
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_COFF) $(TARGET).cof
|
||||||
|
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
|
||||||
|
|
||||||
|
|
||||||
|
extcoff: $(TARGET).elf
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
|
||||||
|
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Create final output files (.hex, .eep) from ELF output file.
|
||||||
|
%.hex: %.elf
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_FLASH) $@
|
||||||
|
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
|
||||||
|
|
||||||
|
%.eep: %.elf
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_EEPROM) $@
|
||||||
|
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
||||||
|
--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
|
||||||
|
|
||||||
|
# Create extended listing file from ELF output file.
|
||||||
|
%.lss: %.elf
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_EXTENDED_LISTING) $@
|
||||||
|
$(OBJDUMP) -h -z -S $< > $@
|
||||||
|
|
||||||
|
# Create a symbol table from ELF output file.
|
||||||
|
%.sym: %.elf
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_SYMBOL_TABLE) $@
|
||||||
|
$(NM) -n $< > $@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Create library from object files.
|
||||||
|
.SECONDARY : $(TARGET).a
|
||||||
|
.PRECIOUS : $(OBJ)
|
||||||
|
%.a: $(OBJ)
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_CREATING_LIBRARY) $@
|
||||||
|
$(AR) $@ $(OBJ)
|
||||||
|
|
||||||
|
|
||||||
|
# Link: create ELF output file from object files.
|
||||||
|
.SECONDARY : $(TARGET).elf
|
||||||
|
.PRECIOUS : $(OBJ)
|
||||||
|
%.elf: $(OBJ)
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_LINKING) $@
|
||||||
|
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
|
||||||
|
# Compile: create object files from C source files.
|
||||||
|
$(OBJDIR)/%.o : %.c
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_COMPILING) $<
|
||||||
|
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
# Compile: create object files from C++ source files.
|
||||||
|
$(OBJDIR)/%.o : %.cpp
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_COMPILING_CPP) $<
|
||||||
|
$(CC) -c $(ALL_CPPFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
# Compile: create assembler files from C source files.
|
||||||
|
%.s : %.c
|
||||||
|
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
# Compile: create assembler files from C++ source files.
|
||||||
|
%.s : %.cpp
|
||||||
|
$(CC) -S $(ALL_CPPFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
# Assemble: create object files from assembler source files.
|
||||||
|
$(OBJDIR)/%.o : %.S
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_ASSEMBLING) $<
|
||||||
|
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
# Create preprocessed source for use in sending a bug report.
|
||||||
|
%.i : %.c
|
||||||
|
$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
# Target: clean project.
|
||||||
|
clean: begin clean_list clean_binary end
|
||||||
|
|
||||||
|
clean_binary:
|
||||||
|
$(REMOVE) $(TARGET).hex
|
||||||
|
|
||||||
|
clean_list:
|
||||||
|
@echo $(MSG_CLEANING)
|
||||||
|
$(REMOVE) $(TARGET).eep
|
||||||
|
$(REMOVE) $(TARGET)eep.hex
|
||||||
|
$(REMOVE) $(TARGET).cof
|
||||||
|
$(REMOVE) $(TARGET).elf
|
||||||
|
$(REMOVE) $(TARGET).map
|
||||||
|
$(REMOVE) $(TARGET).sym
|
||||||
|
$(REMOVE) $(TARGET).lss
|
||||||
|
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o)
|
||||||
|
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst)
|
||||||
|
$(REMOVE) $(SRC:.c=.s)
|
||||||
|
$(REMOVE) $(SRC:.c=.d)
|
||||||
|
$(REMOVE) $(SRC:.c=.i)
|
||||||
|
$(REMOVE) InvalidEvents.tmp
|
||||||
|
$(REMOVEDIR) .dep
|
||||||
|
|
||||||
|
doxygen:
|
||||||
|
@echo Generating Project Documentation...
|
||||||
|
@doxygen Doxygen.conf
|
||||||
|
@echo Documentation Generation Complete.
|
||||||
|
|
||||||
|
clean_doxygen:
|
||||||
|
rm -rf Documentation
|
||||||
|
|
||||||
|
# Create object files directory
|
||||||
|
$(shell mkdir $(OBJDIR) 2>/dev/null)
|
||||||
|
|
||||||
|
|
||||||
|
# Include the dependency files.
|
||||||
|
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
|
||||||
|
|
||||||
|
|
||||||
|
# Listing of phony targets.
|
||||||
|
.PHONY : all checkinvalidevents showliboptions \
|
||||||
|
showtarget begin finish end sizebefore sizeafter \
|
||||||
|
gccversion build elf hex eep lss sym coff extcoff \
|
||||||
|
program dfu flip flip-ee dfu-ee clean debug \
|
||||||
|
clean_list clean_binary gdb-config doxygen
|
Loading…
Reference in new issue