TCP

150
TCP/IP IMPLEMENTATION IN EMBEDDED SYSTEMS AIM: This program is concerned with the application of TCP/IP in embedded systems. The TCP/IP is used for transferring data between computer and controller via the Ethernet. The process of transferring the message involves a number of layered communication protocols. TCP/IP refers to entire suite of data communications protocols. ARM controller is used to send and receive TCP/IP communication data. code is a high level language used for arm controller programming. The purpose of the program is to design laboratory tool to aid learning of the basic OSI layers in computer networking and application of various data communication protocols on the embedded systems. INTERNET PROTOCOLS : Information is transmitted in packets of binary code on the internet. The code is grouped into octets (bytes) and the bytes are grouped into packets of data. Several internet protocols are required such that the receiver can interpret the data correctly. The following are brief descriptions of internet protocols were implemented for the TELNET. ARP (Address Resolution Protocol): ARP is used to translate IP addresses to link addresses (MAC) and hide these addresses from the upper layers. This protocol maps the IP address to a corresponding MAC address. In general, an ARP module

Transcript of TCP

Page 1: TCP

TCP/IP IMPLEMENTATION IN EMBEDDED SYSTEMSAIM: This program is concerned with the application of TCP/IP in embedded systems. The TCP/IP is used for transferring data between computer and controller via the Ethernet. The process of transferring the message involves a number of layered communication protocols. TCP/IP refers to entire suite of data communications protocols. ARM controller is used to send and receive TCP/IP communication data. code is a high level language used for arm controller programming. The purpose of the program is to design laboratory tool to aid learning of the basic OSI layers in computer networking and application of various data communication protocols on the embedded systems.

INTERNET PROTOCOLS: Information is transmitted in packets of binary code on the internet. The code is grouped into octets (bytes) and the bytes are grouped into packets of data. Several internet protocols are required such that the receiver can interpret the data correctly. The following are brief descriptions of internet protocols were implemented for the TELNET.

ARP (Address Resolution Protocol): ARP is used to translate IP addresses to link addresses (MAC) and hide these addresses from the upper layers. This protocol maps the IP address to a corresponding MAC address. In general, an ARP module is broadcast into the network containing the IP address. If a machine recognizes its IP address in the ARP request, it will return an ARP reply to the inquiring machine containing its MAC address. In essence, a broadcast ARP packet asks “who belongs to this IP address” and the reply from the corresponding machine is “I do and here is my MAC address”. The MAC address of the host machine must be known in order to send it Ethernet packets and thus ARP is needed in this project.The ARP packet structure is shown below with the corresponding numberof bytes for each field:

Page 2: TCP

Field BytesDestination Address 6Source Address 6Ethernet type 2Hardware type 2Protocol type 2Hardware length 1Protocol length 1Op code 2Sending hardware address (MAC) 6Sending protocol address 4Target hardware address 6Target protocol address 4

IP (INTERNET PROTOCOLS):

The IP protocol is a network layer protocol, which permits the exchange of traffic between two host computers. Each computer is assigned an IP address so that the networks can know which computer the packet is addressed to and which computer the packet is from. Protocols such as TCP, UDP and ICMP are encapsulated into IP packets. The IP packet structure is shown in the table below:

Field BytesVersion 4Header Length 4Type of Service 8Total Length 16Identifier 16Flags 3Fragment Offset 13Time to Live 8Protocol 8Header Checksum 16

Page 3: TCP

Source Address 32Destination Address 32Options and Padding VariableData Variable

Since IP is a best effort, connectionless protocol, the tasks of error checking, reliability and flow control are given to upper layers such as TCP. The protocol number field indicates the type of upper layer service required by the data packet.

ICMP (Internet Control Message Protocol): This protocol is used for pinging and for reporting errors in the network. The pinging computer sends an ICMP packet to the destination computer which then echo’s the packet back to the pinging computer. This protocol is used also to provide for some administrative and status messages such as response time. This protocol was implemented on the Telnet mainly for testing purposes. The ICMP packet consists of the IP header and the first 64 bits of the original data. ICMP has a protocol number of 1 in the IP Protocol ID field.

TCP (Transmission Control Protocol): TCP traffic accounts for more than 90% of the internet traffic. It is a interactive connection protocol which deals primarily with end to end reliability, the flow of data in the internet, as well as error checking, retransmission and sequencing. Telnet data sent via TCP and therefore it is the most essential protocol for this project. Functions such as the 3-way handshake synchronization, TCP close connection, checksum, data retransmission and data sequencing were implemented in this project. Many of the other complex protocol functions such as traffic management and multiple connectivity (being able to maintain multiple connections simultaneously) were not implemented since they were redundant for the purposes of this project. TCP has a protocol number of 6 in theIP Protocol ID field. The header fields of TCP

Page 4: TCP

Field BytesSource Port 16Destination Port 16Sequence Number 32Acknowledgment number 32Data offset 4Reserved 6Flags 6Window 16Checksum 16Urgent pointer 16Options VariablePadding VariableData Variable

The first step in establishing a TCP connection is a 3-way handshake which is shown below:1) Client sends a SYN request (SYN flag = 1)2) Host replies with a SYN and an ACK (SYN, ACK =1)3) Client sends an ACK (ACK=1)4) Connection is established

SYN =1, SEQ=100

SYN=1, ACK=101, SEQ=001

ACK=002

After establishing a connection, the host proceeds to send the client data. The steps in which the data is sent is shown below:

500 byte Data, SEQ = 002

ACK = 502

500 byte Data, SEQ = 503

CLIENT HOST

CLIENT HOST

Page 5: TCP

The host sends the data to the client with a starting sequence number.The client responds by replying with an acknowledgement number which is the sum of the number of bytes in the data received and the sequence number. If the client does not receive all of the data sent, the Host TCP will resend the lost bytes starting from the client’s acknowledgement number (e.g. if the ACK in the above diagram is 402 instead of 502, the Host TCP will resend the last 100 bytes of the initial data). If an ACK is not received after a certain amount of time, the host will resend the original data and continue to do so until an ACK is received. There are several ways to inform the client that all the data has been sent and the method used in this web server was simply to set the FIN flag when sending the last packet.

ChecksumThe checksum operations for IP, ICMP, TCP and UDP use the samealgorithm. This algorithm follows the following steps:1) Set checksum field to 02) Calculate 16-bit 1s complement sum of the header which is treated as asequence of 16 bit words3) Store this sum in the checksum field4) At the receiver, calculate 16-bit 1s complement of the header5) Receiver’s checksum is all 1s if the data has not been corrupted

uIP STACK:

The uIP TCP/IP stack is intended to make it possible to communicate using the TCP/IP protocol suite even on small 8-bit micro-controllers. Despite being small and simple, uIP do not require their peers to have complex, full-size stacks, but can communicate with peers running a similarly light-weight stack. The code size is on the order of a few kilobytes and RAM usage can be configured to be as low as a few hundred bytes. Traditional TCP/IP implementations have required far too much resource both in terms of code size and memory usage to be useful in small 8 or 16-bit systems. Code size of a few hundred kilobytes and

Page 6: TCP

RAM requirements of several hundreds of kilobytes have made it impossible to fit the full TCP/IP stack into systems with a few tens of kilobytes of RAM and room for less than 100 kilobytes of code. The uIP implementation is designed to have only the absolute minimal set of features needed for a full TCP/IP stack.

PROGRAM FLOW: Initialize the driver device. Initialize uip stack. Initialize the application.(TELNET). Set destination address, host address, net masking.

Check if packet has arrived from the network. If a packet has arrived, the input handler function, uip_input(), should be invoked by the main control loop. The input handler function will never block, but will return at once. When it returns, the stack or the application for which the incoming packet was intended may have produced one or more reply packets which should be sent out. If so, the network device driver should be called to send out these packets.

Check if periodic timeout has occurred. Periodic timeouts are used to drive TCP mechanisms that depend on timers, such as delayed acknowledgments, retransmissions and round-trip time estimations. When the main control loop infers that the periodic timer should fire, it should invoke the timer handler function uip_periodic (). Because the TCP/IP stack may perform retransmissions when dealing with a timer event, the network device driver should called to send out the packets that may have been produced.

APPLICATION: (TELNET)

The function starts with dealing with any error conditions that might have happened by checking if uip_aborted () or uip_timedout () are true. If so, the appropriate error function is called. Also, if the

Page 7: TCP

connection has been closed, the closed () function is called to the it deal with the event. Next, the function checks if the connection has just been established by checking if uip_connected () is true. The connected() function is called and is supposed to do whatever needs to be done when the connection is established, such as initializing the application state for the connection. Since it may be the case that data should be sent out, the send data () function is called to deal with the outgoing data.

PROCEDURE: Download the program and execute it. Open the Vi-RtSim. Select TCP/IP and set the

address is 192.168.150. Click the connect button the connection was

established. Computer receives an acknowledgment from

controller to computer. Controller sent out the data (message) from board to

pc. Then we can send the data from pc to board. The receiving data displayed in a serial port.

(Baud rate 19200).

PROGRAM:MAIN.C

#include "includes.h"#include "Ne2000.h"#include "delay.h"#define BUF ((struct uip_eth_hdr *)&uip_buf[0]) //UIP_BUF INITIALISED

Page 8: TCP

LPC_SysControl_MAMConfig_t MamConfig = {MAM_CONFIG,MAM_CYCLES};

void uip_log (char *m){ // printf("uIP log message: %s\n", m);}#undef DEBUG#define DEBUG 1

#define MAM_MODE 2#define MAM_FETCH 3

#define VPBDIV_VAL 1//#define VPBDIV_VAL0/*

SCB*/#define MEMMAP_BOOT_LOADER_MODE 0 // Interrupt vectors are re-mapped to Boot Block.#define MEMMAP_USER_FLASH_MODE (1<<0) // Interrupt vectors are not re-mapped and reside in Flash.#define MEMMAP_USER_RAM_MODE (1<<1) // Interrupt vectors are re-mapped to Static RAM.

void putchar(unsigned char ch){ if (ch=='\n')

{

while (!(U0LSR&0x20)); //wait until Transmit Holding Register is empty

U0THR='\r'; //then store to Transmit Holding Register

}

Page 9: TCP

while (!(U0LSR&0x20)) {} //wait until Transmit Holding Register is empty

U0THR=ch;}

static void systemInit(void){

PLLCON = 0X00;// --- setup and enable the MAM (Memory Accelerator Module) ---// a. start change by turning of the MAM (redundant)MAMCR = 0;// b. set MAM-Fetch cycle to 3 cclk as recommended for >40MHzMAMTIM = MAM_FETCH;// c. enable MAMMAMCR = MAM_MODE;// --- set VPB speed ---APBDIV = VPBDIV_VAL;// --- map INT-vector ---

MEMMAP = MEMMAP_USER_FLASH_MODE;

}

void main() { int i; systemInit(); /* init PLL, MAM etc. */ IO0DIR = 0XFFFFEFFC; // IO0SET = 0XFFFFFFFF; IO1DIR = 0XFFFFfFFf; IO1SET = 0XFFFFFFFF; PINSEL2 = 0X00002030; IO2DIR = 0XFFFFFFFF; PLLCON=0X00; APBDIV=0X01; PINSEL0=0x00000055; U0LCR=0x83;

Page 10: TCP

U0DLL=0x41&0xFF; U0DLM=0x41>>8; U0LCR=0x03 ; IO1SET = 0X00000001;uip_ipaddr_t ipaddr;struct timer periodic_timer, arp_timer; tapdev_init(); //HARDWRAE INITIALISED uip_init(); //INITIALIZE THE UIP STACK AND LISTEN PORTS uip_ipaddr(ipaddr, 192,168,1,150); //SET HOST ADDR uip_sethostaddr(ipaddr); uip_ipaddr(ipaddr, 192,168,1,1); //SET DESTINATION ADDR uip_setdraddr(ipaddr); uip_ipaddr(ipaddr, 255,255,255,0); //SET NET MAS uip_setnetmask(ipaddr);telnetd_init(); //INITIALIZE THE TELNET PORT

while(1) { uip_len = tapdev_read(); //CHECK whether the device driver should send out a packet or not if(uip_len > 0) //SEND OUT A PACKET { if(BUF->type == htons(UIP_ETHTYPE_IP)) //ETHERNET TYPE IS IP OR NOT {

uip_arp_ipin(); //ARP processing for incoming ARP packets. uip_input(); //Process an incoming packet.

if(uip_len > 0) //check incoming packets {

uip_arp_out();//Prepend Ethernet header to an outbound IP packet and see if we need to send out an ARP request tapdev_send(); //send the packet to driver

} } else if(BUF->type == htons(UIP_ETHTYPE_ARP)) //ethernet type is arp { uip_arp_arpin();////ARP processing for incoming ARP packets.

Page 11: TCP

if(uip_len > 0) { tapdev_send(); //send the data

} } } else if(timer_expired(&periodic_timer)) //no packets in a buffer { timer_reset(&periodic_timer); for(i = 0; i < UIP_CONNS; i++) //check the connections are open or not { uip_periodic(i);//Periodic processing for a connection identified by its number if(uip_len > 0) //packets are aVAILABLE IN BUFFER { uip_arp_out(); //SEND OUT ARP REQUEST tapdev_send(); //DATA SEND TO DEVICE DRIVER } }

/* Call the ARP timer function every 10 seconds. */ if(timer_expired(&arp_timer)) { timer_reset(&arp_timer); uip_arp_timer(); ///eriodic timer processing in the ARP module and should be called at regular intervals. //The recommended interval is 10 seconds between the calls } } }}CLOCK ARCH.C

#include "clock-arch.h"#include "board.h"#include "LPC_Timer.h"

Page 12: TCP

LPC_Timer_Config_t Timer0Config, Timer1Config;volatile clock_time_t Ticks;

unsigned int Tim0Per, TickSysFlag;

/************************************************************************* * Function Name: TIM0_IntrHandler * Parameters: void *arg * * Return: none * * Description: TIM0 interrupt handler * *************************************************************************/void TIM0_IntrHandler (void *arg){ ++Ticks; T0IR_bit.MR1INT = 1; // clear the interrupt flag}/************************************************************************* * Function Name: TIMER_Init * Parameters: LPC_TimerChannel_t DevNum * unsigned int precision -- the timer precision (Unit: us), general setting is 10 us * Return: int * 0: success * non-zero: error number * Description: Initialize Timer, Set the PR register that represents the precision of timer. * *************************************************************************/int TIMER_Init(LPC_TimerChannel_t DevNum, unsigned long precision){int i;

Timer0Config.Precision = precision;

Timer0Config.Prescaler = (precision * SYS_GetFpclk()) / 1000000;

Page 13: TCP

T0IR=0xFF; // Disable counting T0TCR=0; // Clear timer counter T0TC=0; // PR = Prescaler - 1 T0PR= Timer0Config.Prescaler - 1; // Clear prescaler timer counter T0PC=0; // Reset Compare modules T0MCR=0; T0MR0=0; T0MR1=0; T0MR2=0; T0MR3=0; // Reset Capture modules T0CCR=0; // Reset External Compare module T0EMR=0; return 0;}/************************************************************************* * Function Name: TIMER_GetPrescaler * Parameters: LPC_TimerChannel_t DevNum * Return: unsigned int * * Description: Return prescaler value * *************************************************************************/

/************************************************************************* * Function Name: TIMER_Reset * Parameters: LPC_TimerChannel_t DevNum * Return: int * 0: success * non-zero: error number * Description: When next pclk arrives, only the TC and PC will be reset.

Page 14: TCP

* While the other registers remain unchanged. * *************************************************************************/

/************************************************************************* * Function Name: TIMER_Start * Parameters: LPC_TimerChannel_t DevNum * Return: int * 0: success * non-zero: error number * Description: Starts (enables) the Timer * *************************************************************************//********************************************************************** * Function Name: TIMER_Stop * Parameters: LPC_TimerChannel_t DevNum * Return: int * 0: success * non-zero: error number * Description: Just stops the Timer (disable it), all registers remain unchanged. * *************************************************************************/

/************************************************************************* * Function Name: TIMER_GetREGValue_CR * Parameters: LPC_TimerChannel_t DevNum * int CRNum * Return: unsigned long * * Description: Get CR register value * *************************************************************************/

/************************************************************************* * Function Name: TIMER_CheckIntSrc * Parameters: LPC_TimerChannel_t DevNum * Return: unsigned long * TIMERMR0...3Int | TIMERCR0...3Int

Page 15: TCP

* * Description: Get Timer interrupt Type * *************************************************************************/unsigned long TIMER_CheckIntType(LPC_TimerChannel_t DevNum){ switch (DevNum) { case TIMER0: return (T0IR & 0xFF); case TIMER1: return (T1IR & 0xFF); default: return (unsigned long)-1; }}/************************************************************************* * Function Name: RTC_ClearInt * Parameters: LPC_TimerChannel_t DevNum * int IntType * * Return: unsigned long * 0: sucess * 1: fail * * Description: Clear Timer interrupt. * *************************************************************************/unsigned long TIMER_ClearInt(LPC_TimerChannel_t DevNum, int IntType){ if (IntType<1 || IntType>0xFF) return 1;

switch (DevNum) { case TIMER0: T0IR = (IntType & 0xFF); break; case TIMER1: T1IR = (IntType & 0xFF);

Page 16: TCP

break; default: return 1; } return 0;}/************************************************************************* * Function Name: T0ISR * Parameters: none * Return: none * * Description: TIMER0 interrupt subroutine * *************************************************************************/void TIMER0_ISR (){int IntStatus; IntStatus = TIMER_CheckIntType(TIMER0); TIMER_ClearInt(TIMER0, IntStatus);

/* Match Register Interrupts */ if (IntStatus & TIMERMR0Int) { (Timer0Config.MatchCH[0].Fnpr)((void *)Timer0Config.MatchCH[0].FnprArg); }

if (IntStatus & TIMERMR1Int) { (Timer0Config.MatchCH[1].Fnpr)((void *)Timer0Config.MatchCH[1].FnprArg); }

if (IntStatus & TIMERMR2Int) { (Timer0Config.MatchCH[2].Fnpr)((void *)Timer0Config.MatchCH[2].FnprArg); }

if (IntStatus & TIMERMR3Int)

Page 17: TCP

{ (Timer0Config.MatchCH[3].Fnpr)((void *)Timer0Config.MatchCH[3].FnprArg); }

/* Capture Register Interrupts */ if (IntStatus & TIMERCR0Int) { Timer0Config.CaptureCH[0].CPValue = TIMER_GetREGValue_CR(TIMER0, CPCH0); (Timer0Config.CaptureCH[0].Fnpr)((void *)Timer0Config.CaptureCH[0].FnprArg); }

if (IntStatus & TIMERCR1Int) { Timer0Config.CaptureCH[1].CPValue = TIMER_GetREGValue_CR(TIMER0, CPCH1); (Timer0Config.CaptureCH[1].Fnpr)((void *)Timer0Config.CaptureCH[1].FnprArg); }

if (IntStatus & TIMERCR2Int) { Timer0Config.CaptureCH[2].CPValue = TIMER_GetREGValue_CR(TIMER0, CPCH2); (Timer0Config.CaptureCH[2].Fnpr)((void *)Timer0Config.CaptureCH[2].FnprArg); }

if (IntStatus & TIMERCR3Int) { Timer0Config.CaptureCH[3].CPValue = TIMER_GetREGValue_CR(TIMER0, CPCH3); (Timer0Config.CaptureCH[3].Fnpr)((void *)Timer0Config.CaptureCH[3].FnprArg); } VICVectAddr = 0; // Clear interrupt in VIC.}

Page 18: TCP

/************************************************************************* * Function Name: T1ISR * Parameters: none * Return: none * * Description: TIMER1 interrupt subroutine * *************************************************************************/

/************************************************************************* * Function Name: clock_init * Parameters: none * * Return: none * * Description: Timer init * *************************************************************************/void clock_init(void){ Ticks = 0; // Init Timer0 TIMER_Init(TIMER0, TIMER_PRECISION);

// Registered TIMER0 interrupt handler VIC_SetVectoredIRQ(TIMER0_ISR,VIC_Slot0,VIC_TIMER0); VIC_EnableInt(1<<VIC_TIMER0);

// Set Timer, Match channel, Action, time period and corresponding ISR function TIMER_SetMatchAction(TIMER0, CH1, TimerAction_Interrupt | TimerAction_ResetTimer , 1sec_T0/TICK_PER_SECOND, TIM0_IntrHandler, (void *)&TickSysFlag, DONOTHING);

TIMER_Start(TIMER0);}/************************************************************************* * Function Name: clock_init

Page 19: TCP

* Parameters: none * * Return: none * * Description: The current clock time, measured in system ticks * *************************************************************************/clock_time_t clock_time(void){ return(Ticks);}

MODULES: LPC SYSCTRL.C/************************************************************************* * * Used with ICCARM and AARM. * * (c) Copyright IAR Systems 2003 * * File name : lpc_sysctrl.c * Description : Define API for system init * * History : * 1. Date: August 17, 2004 * Author: Shawn Zhang * Description: Create the basic function * * 2. Date : Oct 7, 2004 * Author : Stanimir Bonev * Description : Modify some function and interface * * 3. Date : June 16, 2006 * Author : Todor Atanasov * Description : Setting the EXTMODE and EXTPOLAR registers added. * * $Revision: 30870 $ **************************************************************************/

Page 20: TCP

#include "lpc_sysctrl.h"

LPC_Syscontrol_Config_t SysConfig;

/************************************************************************* * Function Name: SYS_Init * Parameters: unsigned long Fosc * unsigned long Fcclk * LPC_SysControl_VPBDiv_t VPBDivider * LPC_SysControl_RemapMode_t RemapMode * bool MAMEnable * LPC_SysControl_MAMConfig_t *pMAMConfig * unsigned long PortDir0 * unsigned long Port0 * unsigned long PortDir1 * unsigned long Port1 * * Return: int * 0: success * non-zero: error number * * Description: Initialize the whole system, setting MEMMAP, VPB, whether enable PLL, * whether enable MAM * *************************************************************************/int SYS_Init (unsigned long Fosc, unsigned long Fcclk, LPC_SysControl_VPBDiv_t VPBDivider, LPC_SysControl_RemapMode_t RemapMode, bool MAMEnable, LPC_SysControl_MAMConfig_t *pMAMConfig, unsigned long PortDir0, unsigned long Port0, unsigned long PortDir1, unsigned long Port1){unsigned long M, P_min, P_max, P, i;int Pflag = 0, PLLflag = 0;

// Check vaild if ( Fosc<Fosc_MIN || Fosc>Fosc_MAX) return 1; if ( Fcclk<Fcclk_MIN || Fcclk>Fcclk_MAX)

Page 21: TCP

return 1; if (Fcclk < Fosc) return 1; else if (Fcclk > Fosc) { // Calculate PLL's value M & P if need M = Fcclk / Fosc; P_min = Fcco_MIN / (2*Fcclk) + 1; P_max = Fcco_MAX / (2*Fcclk); for (i=P_min; i<=P_max; i++) { if ((i ==1) || (i==2) ||(i==4) || (i==8)) { P=i; Pflag = 1; break; } } if (!Pflag) return 1; PLLflag = 1; } // Set globe variable SysConfig.Fosc = Fosc; SysConfig.Fcclk = Fcclk;

// Changing the EXT MODE and Polarity is done this way because of a problem.// Please refer to ERRATA SHEET(LPC2129,LPC2129/00) from 17, May, 2006 APBDIV = 0; EXTMODE = 0x000C; APBDIV = 0; EXTPOLAR = 0; APBDIV = 0; APBDIV_bit.APBDIV = VPBDIV1;

switch(VPBDivider) { case VPBDIV4: SysConfig.Fpclk= Fcclk / 4;

Page 22: TCP

break; case VPBDIV1: SysConfig.Fpclk= Fcclk; break; case VPBDIV2: SysConfig.Fpclk= Fcclk / 2; break; default: return 1; } SysConfig.VPBDivider = VPBDivider; SysConfig.RemapMode = RemapMode;

SysConfig.MAMEnable = MAMEnable;

if (MAMEnable) { SysConfig.MAMConfig.Mode = pMAMConfig->Mode; SysConfig.MAMConfig.Cycle= pMAMConfig->Cycle; }

#ifndef LPC2148 // Do MAM if(MAMEnable) { MAMCR_bit.MODECTRL = 0; MAMCR_bit.MODECTRL = pMAMConfig->Mode; MAMTIM_bit.CYCLES = pMAMConfig->Cycle; } else MAMCR_bit.MODECTRL = 0;#endif

// Do PLL if (PLLflag) { PLLCFG_bit.MSEL = M-1; // Set M & P switch(P) { case 1: PLLCFG_bit.PSEL = 0;

Page 23: TCP

break; case 2: PLLCFG_bit.PSEL = 0x1; break; case 4: PLLCFG_bit.PSEL = 0x2; break; case 8: PLLCFG_bit.PSEL = 0x3; break; default: return 1; } PLLCON_bit.PLLE = true; // Enable PLL

// Interrups must be disabled PLLFEED = PLLFEED_DATA1; PLLFEED = PLLFEED_DATA2;

while (!PLLSTAT_bit.PLOCK); // Wait PLL lock

PLLCON_bit.PLLC = true; // Connect PLL PLLFEED = PLLFEED_DATA1; PLLFEED = PLLFEED_DATA2; } else { PLLCON_bit.PLLC = false; PLLCON_bit.PLLE = false; PLLFEED = PLLFEED_DATA1; PLLFEED = PLLFEED_DATA2; } // Do VPB APBDIV_bit.APBDIV = VPBDivider;

// Do MEMAMP MEMMAP_bit.MAP = SysConfig.RemapMode;

// Set GIO PINSEL0 = PINSEL1 = 0;

Page 24: TCP

IO0SET = Port0; IO0CLR = ~Port0; IO0DIR = PortDir0; IO1SET = Port1; IO1CLR = ~Port1; IO1DIR = PortDir1; return 0;}

/************************************************************************* * Function Name: SYS_GetFpclk * Parameters: void * Return: int * 0: success * non-zero: error number * Description: Get Fpclk * *************************************************************************/unsigned int SYS_GetFpclk (void){ return SysConfig.Fpclk;}

/************************************************************************* * Function Name: PM_SetMode * Parameters: LPC_SysControl_PMMode_t Mode -- PM_STANDARD ,PM_IDLE or PM_POWERDOWN * Return: int * 0: success * non-zero: error number * Description: Set power manage mode * *************************************************************************/int PM_SetMode (LPC_SysControl_PMMode_t Mode){ PCON = Mode & 0x3; return 0;}

/*************************************************************************

Page 25: TCP

* Function Name: PM_OpenPeripheral * Parameters: lpc_uint32 DevType * Return: int * 0: success * non-zero: error number * Description: Open specifical peripheral * *************************************************************************/int PM_OpenPeripheral (unsigned int DevType){ PCONP |= DevType; return 0;}

/************************************************************************* * Function Name: PM_ClosePeripheral * Parameters: lpc_uint32 DevType * Return: int * 0: success * non-zero: error number * Description: Close specifical peripheral * *************************************************************************/int PM_ClosePeripheral (unsigned int DevType){ PCONP &= (~DevType); return 0;}

/************************************************************************* * Function Name: EXTINT_Init * Parameters: LPC_SysControl_ExtInt_Channel_t ExtIntNum * bool WakeupEnable * * Return: int * 0 : success * non-zero : error number * Description: Set External Interrupt *

Page 26: TCP

*************************************************************************/int EXTINT_Init (LPC_SysControl_ExtInt_Channel_t ExtIntNum, bool WakeupEnable){ switch(ExtIntNum) { case EXTINT0: // Assign pin to Ext Interrup logic PINSEL1_bit.P0_16 = 1; // Clear interrupt flag EXTINT_bit.EINT0 = 1; // Set Wakeup if (WakeupEnable) EXTWAKE_bit.EXTWAKE0 = 1; else EXTWAKE_bit.EXTWAKE0 = 0; break; case EXTINT1: // Assign pin to Ext Interrup logic PINSEL0_bit.P0_14 = 1; // Clear interrupt flag EXTINT_bit.EINT1 = 1; // Set Wakeup if (WakeupEnable) EXTWAKE_bit.EXTWAKE1 = 1; else EXTWAKE_bit.EXTWAKE1 = 0; break; case EXTINT2: // Assign pin to Ext Interrup logic PINSEL0_bit.P0_15 = 1; // Clear interrupt flag EXTINT_bit.EINT2 = 1; // Set Wakeup if (WakeupEnable) EXTWAKE_bit.EXTWAKE2 = 1; else EXTWAKE_bit.EXTWAKE2 = 0; break; case RTCWAKE:

Page 27: TCP

default: return 1; } return 0;}LPCVIC.C/************************************************************************* * * Used with ICCARM and AARM. * * (c) Copyright IAR Systems 2003 * * File name : LPC_Vic.h * Description : Define API for VIC * * History : * 1. Date: July 8th, 2004 * Author: Wilson Liu * Description: Create the basic function * * 2. Date: August 4th, 2004 * Author: Shawn Zhang * Description: Clean up the functions. Support nonvector interrupt at first. * * 3. Date : Oct 11, 2004 * Author : Stanimir Bonev * Description : Modify some function and interface * * $Revision: 30870 $ **************************************************************************/

#include "LPC_Vic.h"

/************************************************************************* * Function Name: VIC_SetProtectionMode * Parameters: LPC_Vic_ProtectionMode_t ProtectionType * Return: void *

Page 28: TCP

* Description: According to the parameter:- ProtectionType to decide the VIC * access mode (privileged mode | user or privileged mode). * *************************************************************************/void VIC_SetProtectionMode(LPC_Vic_ProtectionMode_t ProtectionType){ VICProtection_bit.PROTECT = ProtectionType; return;}

/************************************************************************* * Function Name: VIC_GetProtectionMode * Parameters: void * Return: LPC_Vic_ProtectionMode_t * * Description: Get the VIC access mode (privileged mode | user or privileged mode). * *************************************************************************/LPC_Vic_ProtectionMode_t VIC_GetProtectionMode(void){LPC_Vic_ProtectionMode_t ProtectionType;

if (VICProtection & 0x1) ProtectionType = PrivilegedMode; else ProtectionType = UserandPrivilegedMode;

return(ProtectionType);}

/************************************************************************* * Function Name: VIC_Init * Parameters: void * Return: void * * Description: Initialize VIC *

Page 29: TCP

*************************************************************************/void VIC_Init(void){ // Assign all interrupt channels to IRQ VICIntSelect = 0; // Diasable all interrupts VICIntEnClear = 0xFFFFFFFF; // Clear all software interrutps VICSoftIntClear = 0xFFFFFFFF; // VIC registers can be accessed in User or privileged mode VICProtection = 0; // Clear interrupt VICVectAddr = 0; // Clear address of the Interrupt Service routine (ISR) for non-vectored IRQs. VICDefVectAddr = 0;

// Clear address of the Interrupt Service routine (ISR) for vectored IRQs. VICVectAddr0 = \ VICVectAddr1 = \ VICVectAddr2 = \ VICVectAddr3 = \ VICVectAddr4 = \ VICVectAddr5 = \ VICVectAddr6 = \ VICVectAddr7 = \ VICVectAddr8 = \ VICVectAddr9 = \ VICVectAddr10 = \ VICVectAddr11 = \ VICVectAddr12 = \ VICVectAddr13 = \ VICVectAddr14 = \ VICVectAddr15 = 0;

// Disable all vectored IRQ slots VICVectCntl0 = \ VICVectCntl1 = \ VICVectCntl2 = \ VICVectCntl3 = \

Page 30: TCP

VICVectCntl4 = \ VICVectCntl5 = \ VICVectCntl6 = \ VICVectCntl7 = \ VICVectCntl8 = \ VICVectCntl9 = \ VICVectCntl10 = \ VICVectCntl11 = \ VICVectCntl12 = \ VICVectCntl13 = \ VICVectCntl14 = \ VICVectCntl15 = 0;}

/************************************************************************* * Function Name: VIC_GetIRQStatus * Parameters: void * Return: unsigned int * * Description: Get IRQ Status of VIC. Return register VICIRQSTATUS's value. * If some IRQ interrupt request is enabled, then the corresponding * bit of VICIRQSTATUS is set. * *************************************************************************/unsigned int VIC_GetIRQStatus(void){ return(VICIRQStatus);}

/************************************************************************* * Function Name: VIC_GetFIQStatus * Parameters: void * Return: unsigned int * * Description: Get FIQ Status of VIC. Return register VICFIQSTATUS's value. * If some FIQ interrupt request is enabled, then the corresponding * bit of VICFIQSTATUS is set. If more that one interrupt request * is assigned as FIQ, then invoking this function can decide which

Page 31: TCP

* one or ones is/are the request source(s). * *************************************************************************/unsigned int VIC_GetFIQStatus(void){ return(VICFIQStatus);}

/************************************************************************* * Function Name: VIC_EnableInt * Parameters: lpc_uint32 IntType * Return: void * * Description: Enable specific interrupt * *************************************************************************/void VIC_EnableInt(unsigned int IntType){ VICIntEnable |= IntType;}

/************************************************************************* * Function Name: VIC_DisableInt * Parameters: unsigned int IntType * Return: void * * Description: Disable specific interrupt * *************************************************************************/void VIC_DisableInt(unsigned int IntType){ VICIntEnClear |= IntType;}

/************************************************************************* * Function Name: VIC_EnableNonVectoredIRQ * Parameters: pIRQSub - Non Vectored IRQ Sub address * Return: void * * Description: Set VICDefVectAddr to be the IRQ Sub address.

Page 32: TCP

* *************************************************************************/void VIC_EnableNonVectoredIRQ(void(*pIRQSub)()){ VICDefVectAddr = (unsigned int)pIRQSub;}

/************************************************************************* * Function Name: VIC_DisableNonVectoredIRQ * Parameters: void * Return: void * * Description: set VICDefVectAddr to be reset value (NULL). * *************************************************************************/void VIC_DisableNonVectoredIRQ(void){ VICDefVectAddr = NULL;}

/************************************************************************* * Function Name: VIC_SetVectoredIRQ * Parameters: void(*pIRQSub)() * LPC_VicIrqSlots_t VicIrqSlot * unsigned int VicIntSouce * * Return: void * * Description: Init vectored inerrutps * *************************************************************************/void VIC_SetVectoredIRQ(void(*pIRQSub)(), LPC_VicIrqSlots_t VicIrqSlot, unsigned int VicIntSource){unsigned long volatile *pReg; // load base address of vectored address registers pReg = &VICVectAddr0; // Set Address of callback function to corresponding Slot *(pReg+VicIrqSlot) = (unsigned long)pIRQSub; // load base address of ctrl registers

Page 33: TCP

pReg = &VICVectCntl0; // Set source channel and enable the slot *(pReg+VicIrqSlot) = VicIntSource | 0x20; // Clear FIQ select bit VICIntSelect &= ~(1<<VicIntSource);}

/************************************************************************* * Function Name: VIC_SetFastInt * Parameters: lpc_uint32 IntType * Return: void * * Description: Enable FIQ interrupt * *************************************************************************/void VIC_EnaFastInt(unsigned int FastIntMask){ VICIntSelect |= FastIntMask;}

/************************************************************************* * Function Name: VIC_DisFastInt * Parameters: lpc_uint32 IntType * Return: void * * Description: Disable FIQ interrupt * *************************************************************************/void VIC_DisFastInt(unsigned int FastIntMask){ VICIntSelect &= ~FastIntMask;}

RTL8019AS.C

#include "ne2000.h"#include "uip.h"#include "config.h"#include "uipopt.h"#include "delay.h"

Page 34: TCP

/* 8390 Network Interface Controller (NIC) page0 register offsets */#define CMDR 0x00 /*command register for read & write */#define PSTART 0x01 /* page start register for write */#define PSTOP 0x02 /* page stop register for write */#define BNRY 0x03 /* boundary reg for rd and wr */#define TPSR 0x04 /* tx start page start reg for wr */#define TXSTAT TPSR#define TBCR0 0x05 /* tx byte count 0 reg for wr */#define TBCR1 0x06 /* tx byte count 1 reg for wr */#define ISR 0x07 /* interrupt status reg for rd and wr */#define RSAR0 0x08 /* low byte of remote start addr */#define RSAR1 0x09 /* hi byte of remote start addr */#define RBCR0 0x0A /* remote byte count reg 0 for wr */#define RBCR1 0x0B /* remote byte count reg 1 for wr */#define RCR 0x0C /* rx configuration reg for wr */#define TCR 0x0D /* tx configuration reg for wr */#define DCR 0x0E /* data configuration reg for wr */#define IMR 0x0F /* interrupt mask reg for wr */

/* NIC page 1 register offsets */#define PAR0 0x01 /* physical addr reg 0 for rd and wr */#define CURRP 0x07 /* current page reg for rd and wr */#define MAR0 0x08 /* multicast addr reg 0 for rd and WR */

/* NIC RAM definitions */#define RAMPAGES 0x20 /* Total number of 256-byte RAM pages */#define TXSTART 0x40 /* Tx buffer start page - NE2000 mode */#define RXSTART (TXSTART+TXPAGES) /* Rx buffer start page */#define RXSTOP (TXSTART+RAMPAGES-1) /* Last Rx buffer page */#define DCRVAL 0x48 /* Value for data config reg */ /* 8-bit DMA, big-endian, 1 DMA, Normal */#define RXPAGES (RXSTOP - RXSTART)

#define Reg00 CMDR /* command register for read & write */#define Reg01 PSTART /* page start register for write */#define Reg02 PSTOP /* page stop register for write */

Page 35: TCP

#define Reg03 BNRY /* boundary reg for rd and wr */#define Reg04 TPSR /* tx start page start reg for wr */#define Reg05 TBCR0 /* tx byte count 0 reg for wr */#define Reg06 TBCR1 /* tx byte count 1 reg for wr */#define Reg07 ISR /* interrupt status reg for rd and wr */#define Reg08 RSAR0 /* low byte of remote start addr */#define Reg09 RSAR1 /* hi byte of remote start addr */#define Reg0a RBCR0 /* remote byte count reg 0 for wr */#define Reg0b RBCR1 /* remote byte count reg 1 for wr */#define Reg0c RCR /* rx configuration reg for wr */#define Reg0d TCR /* tx configuration reg for wr */#define Reg0e DCR /* data configuration reg for wr */#define Reg0f IMR /* interrupt mask reg for wr */

#define Reg10 0x10 //REMOTE DMA PORT#define Reg18 0x18 //RESET PORT

u8_t bnry;u8_t curr;

u8_t Tx_Buff_Sel=0;

union EthernetFrameBuf RxdNetBuff;

void Delay_MS(u16_t ms_number){

u8_t i;u16_t j;for(j = 0;j < ms_number;j++)for(i = 0;i < 229;i++);

}

/*************************************************************************************************

Page 36: TCP

READ THE DATA FROM THE RDMA REGISTER **************************************************************************************************/

static u8_t NICGet(u8_t reg) { u8_t val;

long int du,writed;char readdata;

IO0DIR = 0XFFFFEFFC; //OUTPUT DIR writed = (reg << 0x07); //MOVE THE ADDRESS REGISTER TO

ADDRESS PORTwrited =((writed & 0x007f8f80) | 0x00004000 | 0X00000030); //

Address Mask| PSEN MASK | RD-1WR-1RST-0IO0PIN = (0x007f8000) | writed ; IO0DIR = 0XFF806FFc; //input dir for data bus (P0.15-

P0.22)IO0CLR = 0X00000010; //ACTIVATE IO READ REQUEST

READ P0.4--0du = IO0PIN;

du = (du & 0x007f8000);readdata = (du >>15) & 0x000000ff; //GET THE DATA FROM THE

DATA BUS (P0.15--P0.22)IO0SET = 0x00000010; //DE ACTIVATE IO READ

REQUEST READ P0.4--1delay();return (readdata);

}/**************************************************************************************

WRITE THE DATA TO RDMA PORT REGISTER***************************************************************************************/void NICPut(u8_t reg, u8_t val) { long int write_data= 0x0,write_datam= 0x0;

Page 37: TCP

IO0DIR = 0XFFFFEFFc; // all outputDelay_1ms(1);write_data = (reg << 0x07); //MOVE THE ADRESS TO ADDRESS

PORTwrite_data =((write_data & 0x00000f80) | 0x00004000 |

0X00000030);write_datam = ((write_data & 0x00000f80) | 0x00004000 |

0X00000030);IO0DIR = 0XFFFFEFFc; // all outputwrite_data = (val << 15); // WRITE THE DATA TO SPECIFIED

REGISTER USING DATA BUSwrite_data = ((write_data & 0x007f8000) | 0x00004000 | 0X00000010

| write_datam); //Data with WR pulseIO0PIN = write_data;Delay_1ms(5);IO0CLR = 0X00000020; //ACTIVATE IO WRITE REQUEST

WR=0(P0.5)Delay_1ms(5);IO0SET = 0x00000020; //DE ACTIVATE IO WRITE REQUESR

WR=1 (P0.5)}void page(u8_t pagenumber){

u8_t temp;

temp=NICGet(Reg00);//READ THE COMMAND REGISTERtemp=temp&0x3B ;pagenumber=pagenumber <<6;//PAGE NUMBER SELECTION BIT

IS PS0,PS1 (CR REGISTER 6TH & 7TH BIT)temp=temp | pagenumber;

NICPut(Reg00, temp); //WRITE THE DATA TO CR REGISTER SELECT THE PAGES}

/*************************************************************************************RESET THE DRIVER**********************************************************************************/static void NICReset(void){unsigned int test,i;

NICPut(Reg00,0x62);

Page 38: TCP

NICPut(Reg01,0x45);

i=NICGet(Reg01);printf("\n \r readdaera %x",i);

IO0SET = 0x00000070; //RST,WR,RD= 111Delay_1ms(2);IO0CLR = 0x00000040; //RST,WR,RD= 011delay1();

test =NICGet(Reg18); // READ THE RESET PORT REGISTERprintf("\n\r Before Reset : %x",test);NICPut(Reg18,test); // READ THE RESET PORT REGISTERdelay1();test =NICGet(ISR); // READ THE STATUS OF NIC(DEVICE)printf("\n\r After Reset : %x",test);

if ((test & 0x80) == 0x80) //CHECK THE DRIVER IS RESET STATE OR NOT

printf("\n\r Reset successful");else

{printf("\n\r\t>>NIU Reset Failed [or] Hardware Not Found !!!");while(1);}

//SET_NIC_READ();}

/***************************************************************************SET THE PAGE NUMBER. IT HAVE 4 PAGES PAGE0,PAGE1,PAGE2,PAGE3****************************************************************************/

/**********************************************************************************SET THE MAC ID(MEDIA ACCESS CONTROL ID)**********************************************************************************/void SetMacID(void){

page(1); //SELECT PAGE 1

Page 39: TCP

NICPut(Reg01, UIP_ETHADDR0);// PHYSICAL ADDRESS REGISTERS (01H-06H)

NICPut(Reg02, UIP_ETHADDR1); //THESE NODE CONTAIN MY ETHERNET ADDRESS

NICPut(Reg03, UIP_ETHADDR2);NICPut(Reg04, UIP_ETHADDR3);NICPut(Reg05, UIP_ETHADDR4);NICPut(Reg06, UIP_ETHADDR5);page(0); //SELECT PAG0

}/****************************************************************************SEND THE DATA TO N /W****************************************************************************/u8_t tapdev_send(void){

u8_t i; u16_t ii;

page(0); //SELECT PAGE0if(uip_len<60) //COMPARE THE LENGTH OF THE PACKET

uip_len=60;if(uip_len> UIP_BUFSIZE)

return 0 ;NICPut(Reg09,0x40) ; //set the start address of the remote dma

NICPut(Reg08,0x00); NICPut(Reg0b,uip_len>>8); //set the data byte counts of dmaNICPut(Reg0a,uip_len&0xff);NICPut(Reg00,0x12); //remote write in dma register

for(ii = 0; ii < 40 + UIP_LLH_LEN; ii++) { NICPut(Reg10,uip_buf[ii]); //write the data to rdma port }

for(; ii < uip_len;ii++) { NICPut(Reg10, uip_appdata[ii - 40 - UIP_LLH_LEN]); //write the application data to rdma port }

NICPut(Reg0b,0x00); //initialize data byte counts of dma.NICPut(Reg0a,0x00);

Page 40: TCP

NICPut(Reg00,0x22); //complete remote dmaNICPut(Reg07,0xff);

NICPut(Reg04,0x40); //sets the start page address of the packet to the transmitted.

NICPut(Reg06,uip_len>>8); //set the byte counts of the packet to be transmitted//high byte counter

NICPut(Reg05,uip_len&0xff); //low byte counterNICPut(Reg07,0xff); //communication completedNICPut(Reg00,0x3e); //to sendpacket;

return(1);

}/***************************************************************************RECEIVE THE DATA FRROM N/W****************************************************************************/u16_t tapdev_read(){

u8_t i;u16_t ii;

page(0); //SELECT PAGE 0bnry=NICGet(Reg03); //READ THE BOUNDRY REGISTER FOR

POINT OUT THE LAST RECIVE BUFFER REGISTERpage(1); //SELECT PAGE 1curr=NICGet(Reg07); //READ THE page address of the first receive

buffer page to be used for //a packet reception

page(0); //SELECT PAGE1if((curr==0)) return(0);bnry=bnry++;if(bnry>0x7f)bnry=0x4c; if(bnry!=curr) { page(0);

NICPut(Reg09,bnry); //WRITE THE STAR ADDRESS NICPut(Reg08,0x00);

Page 41: TCP

NICPut(Reg0b,0x00); NICPut(Reg0a,18); //seT the data byte counts of remote

DMA NICPut(Reg00,0x0a); //REMOTE READ AND START

COMMAND

for(i=0;i<18;i++) { RxdNetBuff.bytes.bytebuf[i]=NICGet(Reg10);//READ THE

REMOTE DATA PORT

}

NICPut(Reg0b,0x00); ///INITIALISE the data byte counts of remote DMA

NICPut(Reg0a,0x00); // NICPut(Reg00,0x22); //COMPLLTE THE PROCESS

RxdNetBuff.EtherFrame.length=RxdNetBuff.EtherFrame.length-4;

if(((RxdNetBuff.bytes.bytebuf[0]&0x01)==0)||(RxdNetBuff.bytes.bytebuf[1]>0x7f)

||(RxdNetBuff.bytes.bytebuf[1]<0x4c)||(RxdNetBuff.bytes.bytebuf[3]>0x06)) {

page(1);curr=NICGet(Reg07); //page1page(0); //Çл»»Øpage0

bnry = curr -1; if(bnry < 0x4c) bnry =0x7f; NICPut(Reg03,bnry); //write to bnry

NICPut(Reg07,0xff);return(0);

}//=============================================

else

Page 42: TCP

{

if(((RxdNetBuff.EtherFrame.NextProtocal1==0x08)&&(RxdNetBuff.EtherFrame.NextProtocal2==0x00))||

((RxdNetBuff.EtherFrame.NextProtocal1==0x08)&&(RxdNetBuff.EtherFrame.NextProtocal2==0x06)))

{ if(RxdNetBuff.EtherFrame.length > UIP_BUFSIZE)

return (0); // frame too big;

NICPut(Reg09,bnry); //read page address high

NICPut(Reg08,4); //read page address low

NICPut(Reg0b,RxdNetBuff.bytes.bytebuf[3]); //read count high

NICPut(Reg0a,RxdNetBuff.bytes.bytebuf[2]); //read count low;

NICPut(Reg00,0x0a); //read dma

for(ii=0;ii<RxdNetBuff.EtherFrame.length;ii++) {

uip_buf[ii]=NICGet(Reg10);}

NICPut(Reg0b,0x00); //read count high NICPut(Reg0a,0x00); //read count low; NICPut(Reg00,0x22); }

bnry=RxdNetBuff.bytes.bytebuf[1]-1; if(bnry<0x4c) {bnry=0x7f;} NICPut(Reg03,bnry); //write to bnry NICPut(Reg07,0xff);

Page 43: TCP

return(RxdNetBuff.EtherFrame.length); //have new packet

} }

return(0);}

/************************************************************************INITIALISE THE DEVICE*************************************************************************/void tapdev_init(void){ u8_t i;

NICReset();

Delay_MS(60);

NICPut(Reg00,0x21); //START

Delay_MS(250);

page(0); //SET PAQGE 0NICPut(Reg0a,0x00); //INITIALISE the data byte counts of remote

DMA NICPut(Reg0b,0x00); NICPut(Reg0c,0xe0); //received packets are checked for address

match, //physical destination address must match the node address programmed

NICPut(Reg0d,0xe2); //CRC generator for transmitter and a CRC checker for //receiver BOTH BITS ARE ENABLED. AND LOOKBACK ENABLE

NICPut(Reg01,0x4c); //sets the start page address of the receive buffer ring

NICPut(Reg02,0x80); // Stop register sets the stop page address of the receive buffer

Page 44: TCP

//SHOULD NOT EXCEED THE VALUE 0X80NICPut(Reg03,0x4); //indicating the last receive buffer page the

host has readNICPut(Reg04,0x40); //sets the start page address of the packet to

the transmittedNICPut(Reg07,0xff); // COMPLETE THE PROCESSNICPut(Reg0f,0x00); //All bits correspond to the bits in the ISR

register. POWER UP=all 0s. Setting individual //bits will enable the corresponding interrupts.

NICPut(Reg0e,0xc8); //FIFO threshold select.SEND PACKET COMMAND EXECUTED

page(1); //SET THE PAGE 1NICPut(Reg07,0x4d);//register points to the page address of the first

receive buffer page to be used for //a packet reception for ( i = 0; i < 8; i++ ) NICPut(Reg08+i, 0xff);//provide filtering bits of multicast addresses hashed by the CRC logic

NICPut(Reg00,0x22);

SetMacID(); //SET MEDIA ACCESS CONTROL ID

page(0);NICPut(Reg0c,0xcc); //physical destination address must match the

node address programmed //packets with multicast destination address are

accepted.packets with multicast destination address are accepted. //Packets with broadcast destination address are accepted. //packets with length fewer than 64 bytes are rejected // packets with receive errors are rejected. NICPut(Reg0d,0xe0);//TRANSMIT CONFIGURATION REGISTER

NICPut(Reg00,0x22); NICPut(Reg07,0xff); //STATUS OF THE NIC

}

Uip stackUip.c

Page 45: TCP

#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 <[email protected]> */

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

Page 46: TCP

* OR IMPLIED 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 30870 2009-07-05 10:16:16Z anderslu $ * */

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

Page 47: TCP

* 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>#include "cs8900a.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 > 0const 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)};

Page 48: TCP

#elseuip_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_FIXEDETHADDRconst struct uip_eth_addr uip_ethaddr = {{UIP_ETHADDR0,

UIP_ETHADDR1, UIP_ETHADDR2, UIP_ETHADDR3, UIP_ETHADDR4, UIP_ETHADDR5}};

#elsestruct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}};#endif

#ifndef UIP_CONF_EXTERNAL_BUFFER#pragma data_alignment=4u8_t uip_buf[UIP_BUFSIZE + 2]; /* The packet buffer that contains

incoming packets. */#endif /* UIP_CONF_EXTERNAL_BUFFER */

u8_t *uip_appdata; /* The uip_appdata pointer points to application data. */

u8_t *uip_sappdata; /* The uip_appdata pointer points to the application data which is to be sent. */

Page 49: TCP

#if UIP_URGDATA > 0void *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 packetsize. */

u8_t uip_flags; /* The uip_flags variable is used forcommunication between the TCP/IP stackand the application program. */

struct uip_conn *uip_conn; /* uip_conn always points to the currentconnection. */

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

static u16_t ipid; /* Ths ipid variable is an increasingnumber that is used for the IP IDfield. */

void uip_setipid(u16_t id) { ipid = id; }

static u8_t iss[4]; /* The iss variable is used for the TCPinitial sequence number. */

#if UIP_ACTIVE_OPENstatic u16_t lastport; /* Keeps track of the last port used for

a new connection. */#endif /* UIP_ACTIVE_OPEN */

Page 50: TCP

/* 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])

Page 51: TCP

#if UIP_STATISTICS == 1struct uip_stats uip_stat;#define UIP_STAT(s) s#else#define UIP_STAT(s)#endif /* UIP_STATISTICS == 1 */

#if UIP_LOGGING == 1

void uip_log(char *msg);#define UIP_LOG(m) uip_log(m)#else#define UIP_LOG(m)#endif /* UIP_LOGGING == 1 */

#if ! UIP_ARCH_ADD32voiduip_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]; }

Page 52: TCP

} }}

#endif /* UIP_ARCH_ADD32 */

#if ! UIP_ARCH_CHKSUM/*---------------------------------------------------------------------------*/static u16_tchksum(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

Page 53: TCP

uip_chksum(u16_t *data, u16_t len){ return htons(chksum(0, (u8_t *)data, len));}/*---------------------------------------------------------------------------*/#ifndef UIP_ARCH_IPCHKSUMu16_tuip_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_tupper_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);

Page 54: TCP

return (sum == 0) ? 0xffff : htons(sum);}/*---------------------------------------------------------------------------*/#if UIP_CONF_IPV6u16_tuip_icmp6chksum(void){ return upper_layer_chksum(UIP_PROTO_ICMP6);

}#endif /* UIP_CONF_IPV6 *//*---------------------------------------------------------------------------*/u16_tuip_tcpchksum(void){ return upper_layer_chksum(UIP_PROTO_TCP);}/*---------------------------------------------------------------------------*/

#endif /* UIP_ARCH_CHKSUM *//*---------------------------------------------------------------------------*/voiduip_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 */

/* IPv4 initialization. */#if UIP_FIXEDADDR == 0

Page 55: TCP

/* uip_hostaddr[0] = uip_hostaddr[1] = 0;*/#endif /* UIP_FIXEDADDR */

}/*---------------------------------------------------------------------------*/#if UIP_ACTIVE_OPENstruct 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;

Page 56: TCP

} } }

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

/*---------------------------------------------------------------------------*/voiduip_unlisten(u16_t port){ for(c = 0; c < UIP_LISTENPORTS; ++c) { if(uip_listenports[c] == port) { uip_listenports[c] = 0; return;

Page 57: TCP

} }}/*---------------------------------------------------------------------------*/voiduip_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 0x01static u8_t uip_reasstmr;

#define IP_MF 0x20

static u8_tuip_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) {

Page 58: TCP

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)] |=

Page 59: TCP

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)] !=

Page 60: TCP

(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 voiduip_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];}/*---------------------------------------------------------------------------*/voiduip_process(u8_t flag){

Page 61: TCP

register struct uip_conn *uip_connr = uip_conn;

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;

Page 62: TCP

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

Page 63: TCP

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

Page 64: TCP

uip_flags = UIP_POLL;UIP_APPCALL();goto appsend;

} } goto drop; }

/* 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); printf("Test: Place 1"); //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); // printf("Test: Place 2"); //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.. */

Page 65: TCP

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); //printf("Test: Place 3"); //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

Page 66: TCP

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); // printf("It is not for our IP address"); 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)) {

Page 67: TCP

UIP_STAT(++uip_stat.ip.drop); //printf("UIP_IPv6"); 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); //printf("Test: Place 3"); //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); //printf("Test: Place 4"); //UIP_LOG("ip: neither tcp nor icmp."); goto drop;

Page 68: TCP

}

#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);

Page 69: TCP

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); // printf("Test: Place 5"); // 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);

Page 70: TCP

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:

Page 71: TCP

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

Page 72: TCP

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

Page 73: TCP

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,

Page 74: TCP

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;

Page 75: TCP

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) {

Page 76: TCP

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];

Page 77: TCP

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

Page 78: TCP

#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

Page 79: TCP

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;

Page 80: TCP

/* 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 thepeer sends a FIN (hence the application goes directly fromESTABLISHED 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;

Page 81: TCP

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 {

Page 82: TCP

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

Page 83: TCP

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

Page 84: TCP

uip_appdata = (u8_t *)((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.

Page 85: TCP

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;

Page 86: TCP

}

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

Page 87: TCP

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;

Page 88: TCP

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;

Page 89: TCP

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

Page 90: TCP

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);

Page 91: TCP

/* Return and let the caller do the actual transmission. */ uip_flags = 0; return; drop: uip_len = 0; uip_flags = 0; return;}/*---------------------------------------------------------------------------*/u16_thtons(u16_t val){ return HTONS(val);}/*---------------------------------------------------------------------------*/voiduip_send(const void *data, int len){ if(len > 0) { uip_slen = len; if(data != uip_sappdata) { memcpy((void *)uip_sappdata, (data), uip_slen); } }}/** @} */Uip_arp.c/** * \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

Page 92: TCP

* 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 <[email protected]> * */

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

Page 93: TCP

* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 30870 2009-07-05 10:16:16Z anderslu $ * */

#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,

Page 94: TCP

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

Page 95: TCP

/*-----------------------------------------------------------------------------------*/voiduip_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. * *//*-----------------------------------------------------------------------------------*/voiduip_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 voiduip_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

Page 96: TCP

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) {

Page 97: TCP

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 0voiduip_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])) {

Page 98: TCP

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. *//*-----------------------------------------------------------------------------------*/voiduip_arp_arpin(void){

if(uip_len < sizeof(struct arp_hdr)) { uip_len = 0;

Page 99: TCP

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; }

Page 100: TCP

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. *//*-----------------------------------------------------------------------------------*/voiduip_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

Page 101: TCP

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;

Page 102: TCP

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);}/*-----------------------------------------------------------------------------------*/

/** @} *//** @} */Time.c/** * \addtogroup timer * @{ */

/** * \file * Timer library implementation. * \author * Adam Dunkels <[email protected]> */

/* * Copyright (c) 2004, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without

Page 103: TCP

* 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 <[email protected]> * * $Id: timer.c 30870 2009-07-05 10:16:16Z anderslu $ */

Page 104: TCP

#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. * */voidtimer_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() */voidtimer_reset(struct timer *t){ t->start += t->interval;

Page 105: TCP

}/*---------------------------------------------------------------------------*//** * 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() */voidtimer_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. * */inttimer_expired(struct timer *t){ return (clock_time_t)(clock_time() - t->start) >= (clock_time_t)t->interval;}/*---------------------------------------------------------------------------*/

Page 106: TCP

/** @} */

Page 107: TCP