# HG changeset patch # User Matt Johnston # Date 1347033233 -28800 # Node ID 56d09a0969b530ca0cabf83198e1c5b5e0997a7f # Parent 5c8404549cc0baaa3e01bc9fd3ef62d367162ae6 Import uIP and the PPP implementation from https://code.google.com/p/avrusbmodem/ diff -r 5c8404549cc0 -r 56d09a0969b5 network/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/Makefile Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,6 @@ +all: test + +SOURCES=timer.c uip.c test.c + +test: $(SOURCES) + gcc -o $@ $^ -Wall diff -r 5c8404549cc0 -r 56d09a0969b5 network/PPP.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/PPP.c Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,1426 @@ +/* + LUFA Powered Wireless 3G Modem Host + + Copyright (C) Mike Alexander, 2010. + Copyright (C) Dean Camera, 2010. +*/ + +/* + Copyright 2010 Mike Alexander (mike [at] mikealex [dot] com) + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +#define INCLUDE_FROM_PPP_C +#include "PPP.h" + +static uint8_t OutgoingPacketID; // Unique packet ID +static PPP_Phases_t PPP_Phase; // PPP negotiation phases +static PPP_States_t LCP_State; // Each phase has a number of states +static PPP_States_t PAP_State; +static PPP_States_t IPCP_State; +static PPP_Packet_t* OutgoingPacket; // Pointer to the outgoing packet +static PPP_Packet_t* IncomingPacket; // Pointer to the incoming packet +static uint16_t CurrentProtocol; // Type of the last received packet +static uint8_t RestartCount; +static uint16_t LinkTimer; +static bool TimerOn; +static bool MarkForNAK; +static bool MarkForREJ; +static uint8_t OutgoingPacketBuffer[OUTGOING_PACKET_BUFFER_SIZE]; // Buffer to store the outgoing packet in + +PPP_Packet_t* dummy; + + +void PPP_InitPPP(void) +{ + PPP_Phase = PPP_PHASE_Dead; + TimerOn = false; +} + +void PPP_StartLink(void) +{ + OutgoingPacket = NULL; + CurrentProtocol = NONE; + TimerOn = false; + LinkTimer = 0; + uip_len = 0; + RestartCount = MAX_RESTARTS; + MarkForNAK = MarkForREJ = false; + OutgoingPacketID = -1; + OutgoingPacket = IncomingPacket = NULL; + LCP_State = PPP_STATE_Initial; + PAP_State = PPP_STATE_Initial; + IPCP_State = PPP_STATE_Initial; + PPP_Phase = PPP_PHASE_Establish; + PPP_ManageState(PPP_EVENT_Open, &LCP_State, PPP_LAYER_Physical); + PPP_ManageState(PPP_EVENT_Up, &LCP_State, PPP_LAYER_Physical); +} + +// Called every 10ms. Send events to the state machine every 3 seconds if the timer is currently running +void PPP_LinkTimer(void) +{ + if (!TimerOn || LinkTimer++ < 300) + return; + + if (RestartCount > 0) + { + Debug_Print("Timer+\r\n"); + + switch(PPP_Phase) + { + case PPP_PHASE_Establish: + PPP_ManageState(PPP_EVENT_TOPlus, &LCP_State, PPP_LAYER_Physical); + break; + + case PPP_PHASE_Authenticate: + PPP_ManageState(PPP_EVENT_TOPlus, &PAP_State, PPP_LAYER_Authentication); + break; + + case PPP_PHASE_Network: + PPP_ManageState(PPP_EVENT_TOPlus, &IPCP_State, PPP_LAYER_Network); + break; + + default: + break; + } + } + else + { + Debug_Print("Timer-\r\n"); + + switch(PPP_Phase) + { + case PPP_PHASE_Establish: + PPP_ManageState(PPP_EVENT_TOMinus, &LCP_State, PPP_LAYER_Physical); + break; + + case PPP_PHASE_Authenticate: + PPP_ManageState(PPP_EVENT_TOMinus, &PAP_State, PPP_LAYER_Authentication); + break; + + case PPP_PHASE_Network: + PPP_ManageState(PPP_EVENT_TOMinus, &IPCP_State, PPP_LAYER_Network); + break; + + default: + break; + } + } + + LinkTimer = 0; // Reset Timer +} + +void PPP_ManageLink(void) +{ + if (PPP_Phase == PPP_PHASE_Dead) + return; + + uint16_t ReadProtocol = network_read(); // Don't mess with CurrentProtocol in case we get 0 (No data) back + + if (ReadProtocol == 0) + return; + + CurrentProtocol = ReadProtocol; + IncomingPacket = (PPP_Packet_t*)uip_buf; // Map the incoming data to a packet + + Debug_Print("Got "); + + switch (CurrentProtocol) + { + case LCP: + Debug_Print("LCP "); + + switch(IncomingPacket->Code) + { + case REQ: + Debug_Print("REQ\r\n"); + + MarkForNAK = MarkForREJ = false; + + // List of options that we can support. If any other options come in, we have to REJ them + const uint8_t SupportedOptions[] = {LCP_OPTION_Maximum_Receive_Unit, + LCP_OPTION_Magic_Number, + LCP_OPTION_Async_Control_Character_Map, + LCP_OPTION_Authentication_Protocol, + LCP_OPTION_Protocol_Field_Compression, + LCP_OPTION_Address_and_Control_Field_Compression}; + + if ((MarkForREJ = PPP_TestForREJ(SupportedOptions, sizeof(SupportedOptions)))) // Check that we can support all the options the other end wants to use + { + PPP_ManageState(PPP_EVENT_RCRMinus, &LCP_State, PPP_LAYER_Physical); + break; + } + + static PPP_Option_t Option3 = {.Type = 0x03, .Length = 4, .Data = {0xc0, 0x23}}; + + if ((MarkForNAK = PPP_TestForNAK(&Option3))) // Check that the authentication protocol = PAP (0xc023) + { + PPP_ManageState(PPP_EVENT_RCRMinus, &LCP_State, PPP_LAYER_Physical); + break; + } + + PPP_ManageState(PPP_EVENT_RCRPlus, &LCP_State, PPP_LAYER_Physical); + break; + + case ACK: + Debug_Print("ACK\r\n"); + + if (IncomingPacket->PacketID != OutgoingPacketID) + { + Debug_Print("Out of sync\r\n"); + break; + } + + PPP_ManageState(PPP_EVENT_RCA, &LCP_State, PPP_LAYER_Physical); + break; + + case NAK: + Debug_Print("NAK\r\n"); + + if (IncomingPacket->PacketID != OutgoingPacketID) + { + Debug_Print("Out of sync\r\n"); + break; + } + + PPP_ProcessNAK(); + PPP_ManageState(PPP_EVENT_RCN, &LCP_State, PPP_LAYER_Physical); + break; + + case REJ: + Debug_Print("REJ\r\n"); + + if (IncomingPacket->PacketID != OutgoingPacketID) + { + Debug_Print("Out of sync\r\n"); + break; + } + + PPP_ProcessREJ(); + PPP_ManageState(PPP_EVENT_RCN, &LCP_State, PPP_LAYER_Physical); + break; + + case DISC: + case ECHOREQ: + case ECHOREPLY: + Debug_Print("DISC\r\n"); + PPP_ManageState(PPP_EVENT_RXR, &LCP_State, PPP_LAYER_Physical); + break; + + case TERMREQ: + Debug_Print("TERM\r\n"); + PPP_ManageState(PPP_EVENT_RTR, &LCP_State, PPP_LAYER_Physical); + break; + + case CODEREJ: + case PROTREJ: + Debug_Print("CODE/PROTREJ\r\n"); + PPP_ManageState(PPP_EVENT_RXJMinus, &LCP_State, PPP_LAYER_Physical); + break; + + default: + Debug_Print("unknown\r\n"); + PPP_ManageState(PPP_EVENT_RUC, &LCP_State, PPP_LAYER_Physical); + break; + } + break; + + case PAP: + Debug_Print("PAP "); + + switch(IncomingPacket->Code) + { + case REQ: + Debug_Print("REQ\r\n"); + PPP_ManageState(PPP_EVENT_RCRPlus, &PAP_State, PPP_LAYER_Authentication); + break; + + case ACK: + Debug_Print("ACK\r\n"); + PPP_ManageState(PPP_EVENT_RCRPlus, &PAP_State, PPP_LAYER_Authentication); // The host never sends a Configure request for PAP, but we need it to move the state machine to completion. So, fake it. + PPP_ManageState(PPP_EVENT_RCA, &PAP_State, PPP_LAYER_Authentication); + break; + } + break; + + case IPCP: + Debug_Print("IPCP "); + + switch(IncomingPacket->Code) + { + case REQ: + Debug_Print("REQ\r\n"); + + MarkForNAK = MarkForREJ = false; + + // List of options that we can support. If any other options come in, we have to REJ them + uint8_t SupportedOptions[] = {IPCP_OPTION_IP_address, IPCP_OPTION_Primary_DNS, IPCP_OPTION_Secondary_DNS}; + + if ((MarkForREJ = PPP_TestForREJ(SupportedOptions, sizeof(SupportedOptions)))) + { + PPP_ManageState(PPP_EVENT_RCRMinus, &IPCP_State, PPP_LAYER_Network); + break; + } + + PPP_ManageState(PPP_EVENT_RCRPlus, &IPCP_State, PPP_LAYER_Network); + break; + + case ACK: + Debug_Print("ACK\r\n"); + + if (IncomingPacket->PacketID != OutgoingPacketID) + { + Debug_Print("Out of sync\r\n"); + break; + } + + IPAddr1 = IncomingPacket->Options[0].Data[0]; // Store address for use in IP packets. + IPAddr2 = IncomingPacket->Options[0].Data[1]; // Assumption is that Option 3 is the first option, which it + IPAddr3 = IncomingPacket->Options[0].Data[2]; // should be as the PPP spec states that implementations should + IPAddr4 = IncomingPacket->Options[0].Data[3]; // not reorder packets, and we sent out a REQ with option 3 first + + PPP_ManageState(PPP_EVENT_RCA, &IPCP_State, PPP_LAYER_Network); + break; + + case NAK: + Debug_Print("NAK\r\n"); + if (IncomingPacket->PacketID != OutgoingPacketID) + { + Debug_Print("Out of sync\r\n"); + break; + } + + PPP_ProcessNAK(); + PPP_ManageState(PPP_EVENT_RCN, &IPCP_State, PPP_LAYER_Network); + break; + + case REJ: + Debug_Print("REJ\r\n"); + + if (IncomingPacket->PacketID != OutgoingPacketID) + { + Debug_Print("Out of sync\r\n"); + break; + } + + PPP_ProcessREJ(); + PPP_ManageState(PPP_EVENT_RCN, &IPCP_State, PPP_LAYER_Network); + break; + } + break; + + case IP: + TCPIP_GotNewPacket(); + break; + + default: + Debug_Print("unknown protocol: 0x"); + Debug_PrintHex(CurrentProtocol / 256); Debug_PrintHex(CurrentProtocol & 255); + Debug_Print("\r\n"); + break; + } +} + + +// Either create a new OutgoingPacket, or if we've just received a NAK or REJ we will have already changed the OutgoingPacket so just send that +static void Send_Configure_Request(void) +{ + Debug_Print("Send Configure Request\r\n"); + + switch(PPP_Phase) + { + case PPP_PHASE_Establish: + if (OutgoingPacket == NULL) // Create a new packet + { + // When we send a REQ, we want to make sure that the other end supports these options +// static PPP_Option_t Option1 = {.Type = LCP_OPTION_Maximum_Receive_Unit, .Length = 4, .Data = {0x5, 0xa0}}; + static PPP_Option_t Option2 = {.Type = LCP_OPTION_Async_Control_Character_Map, .Length = 6, .Data = {0x0, 0x0, 0x0, 0x0}}; + static PPP_Option_t Option5 = {.Type = LCP_OPTION_Magic_Number, .Length = 6, .Data = {0x27, 0xf5, 0x46, 0xa1}}; + static PPP_Option_t Option7 = {.Type = LCP_OPTION_Protocol_Field_Compression, .Length = 2}; + static PPP_Option_t Option8 = {.Type = LCP_OPTION_Address_and_Control_Field_Compression, .Length = 2}; + static PPP_Option_t OptionD = {.Type = LCP_OPTION_Callback, .Length = 3, .Data = {0x6}}; + + //PPP_AddOption(OutgoingPacket, &Option1); + PPP_AddOption(&Option2); + PPP_AddOption(&Option5); + PPP_AddOption(&Option7); + PPP_AddOption(&Option8); + PPP_AddOption(&OptionD); + OutgoingPacket->Code = REQ; + CurrentProtocol = LCP; + } + break; + + case PPP_PHASE_Authenticate: + if (OutgoingPacket == NULL) // Create a new packet + { + static PPP_Option_t Option0 = {.Type = 0x00, .Length = 2}; + + PPP_AddOption(&Option0); + OutgoingPacket->Options[0].Type = 0x00; // No User Name + OutgoingPacket->Options[0].Length = 0x00; // No Password + OutgoingPacket->Code = REQ; + CurrentProtocol = PAP; + } + break; + + case PPP_PHASE_Network: + if (OutgoingPacket == NULL) // Create a new packet + { + // When we send a REQ, we want to make sure that the other end supports these options + static PPP_Option_t Option3 = {.Type = IPCP_OPTION_IP_address, .Length = 6, .Data = {0, 0, 0, 0}}; + static PPP_Option_t Option81 = {.Type = IPCP_OPTION_Primary_DNS, .Length = 6, .Data = {0, 0, 0, 0}}; + static PPP_Option_t Option83 = {.Type = IPCP_OPTION_Secondary_DNS, .Length = 6, .Data = {0, 0, 0, 0}}; + + PPP_AddOption(&Option3); // Make sure Option3 is first + PPP_AddOption(&Option81); + PPP_AddOption(&Option83); + OutgoingPacket->Code = REQ; + CurrentProtocol = IPCP; + } + break; + + default: + break; + } + + OutgoingPacket->PacketID = ++OutgoingPacketID; // Every new REQ Packet going out gets a new ID + RestartCount--; // Decrement the count before we restart the layer + uip_len = uip_ntohs(OutgoingPacket->Length); + memcpy(uip_buf, OutgoingPacket, uip_len); // Copy the outgoing packet to the buffer for sending + + network_send(CurrentProtocol); // Send either the new packet or the modified packet +} + + +// We change the incoming packet code to send an ACK to the remote end, and re-use all the data from the incoming packet +static void Send_Configure_Ack(void) +{ + Debug_Print("Send Configure ACK\r\n"); + + IncomingPacket->Code = ACK; + network_send(CurrentProtocol); +} + +// We change the incoming packet code to send a NAK or REJ to the remote end. The incoming packet has already been altered to show which options to NAK/REJ +static void Send_Configure_Nak_Rej(void) +{ + if (MarkForNAK) + { + Debug_Print("Send Configure NAK\r\n"); + IncomingPacket->Code = NAK; + } + else if (MarkForREJ) + { + Debug_Print("Send Configure REJ\r\n"); + IncomingPacket->Code = REJ; + } + else + { + return; + } + + uip_len = uip_ntohs(IncomingPacket->Length); + network_send(CurrentProtocol); +} + +// Send a TERM to the remote end. +static void Send_Terminate_Request(void) +{ + Debug_Print("Send Terminate Request\r\n"); + + OutgoingPacket = (PPP_Packet_t*)uip_buf; // Build the outgoing packet in uip_buf + CurrentProtocol = LCP; + OutgoingPacket->Code = TERMREQ; + OutgoingPacket->Length = UIP_HTONS(sizeof(PPP_Packet_t)); + OutgoingPacket->PacketID = ++OutgoingPacketID; // Every new REQ Packet going out gets a new ID + + RestartCount--; + + uip_len = uip_ntohs(OutgoingPacket->Length); + network_send(CurrentProtocol); // Send the packet +} + +// Send a TERM ACK to the remote end. +static void Send_Terminate_Ack(void) +{ + Debug_Print("Send Terminate ACK\r\n"); + + IncomingPacket->Code = TERMREPLY; + network_send(CurrentProtocol); +} + +// Send a REJ to the remote end. +static void Send_Code_Reject(void) +{ + Debug_Print("Send Code Reject\r\n"); + + IncomingPacket->Code = CODEREJ; + network_send(CurrentProtocol); +} + +// Send an ECHO to the remote end. +static void Send_Echo_Reply(void) +{ + Debug_Print("Send Echo Reply\r\n"); + + IncomingPacket->Code = ECHOREPLY; + network_send(CurrentProtocol); +} + +// Called by the state machine when the current layer comes up. Use this to start the next layer up. +static void This_Layer_Up(PPP_Layers_t Layer) +{ + CurrentProtocol = NONE; + OutgoingPacket = NULL; // Clear the outgoing packet + + switch(Layer) + { + case PPP_LAYER_Physical: + Debug_Print("**LCP Up**\r\n"); + PPP_Phase = PPP_PHASE_Authenticate; + OutgoingPacketID = -1; + PPP_ManageState(PPP_EVENT_Open, &PAP_State, PPP_LAYER_Authentication); + PPP_ManageState(PPP_EVENT_Up, &PAP_State, PPP_LAYER_Authentication); + break; + + case PPP_LAYER_Authentication: + Debug_Print("**PAP Up**\r\n"); + PPP_Phase = PPP_PHASE_Network; + OutgoingPacketID = -1; + PPP_ManageState(PPP_EVENT_Open, &IPCP_State, PPP_LAYER_Network); + PPP_ManageState(PPP_EVENT_Up, &IPCP_State, PPP_LAYER_Network); + break; + + case PPP_LAYER_Network: + Debug_Print("**IPCP Up**\r\n"); + ConnectedState = LINKMANAGEMENT_STATE_InitializeTCPStack; + break; + + default: + break; + } +} + +// Called by the state machine when a layer goes down. Use this to stop the next layer up +static void This_Layer_Down(PPP_Layers_t Layer) +{ + OutgoingPacket = NULL; // Clear the outgoing packet + + switch(Layer) + { + case PPP_LAYER_Physical: + Debug_Print("**LCP Down**\r\n"); + PPP_ManageState(PPP_EVENT_Down, &PAP_State, PPP_LAYER_Authentication); + PPP_Phase = PPP_PHASE_Establish; + break; + + case PPP_LAYER_Authentication: + Debug_Print("**PAP Down**\r\n"); + PPP_ManageState(PPP_EVENT_Down, &IPCP_State, PPP_LAYER_Network); + break; + + case PPP_LAYER_Network: + Debug_Print("**IPCP Down**\r\n"); + break; + + default: + break; + } +} + +// Called by the state machine when the current layer starts +static void This_Layer_Started(PPP_Layers_t Layer) +{ + switch(Layer) + { + case PPP_LAYER_Physical: + Debug_Print("**LCP Started**\r\n"); + break; + + case PPP_LAYER_Authentication: + Debug_Print("**PAP Started**\r\n"); + break; + + case PPP_LAYER_Network: + Debug_Print("**IPCP Started**\r\n"); + break; + + default: + break; + } +} + +// Called by the state machine when the current layer finishes +static void This_Layer_Finished(PPP_Layers_t Layer) +{ + switch(Layer) + { + case PPP_LAYER_Physical: + Debug_Print("**LCP Finished**\r\n"); + break; + + case PPP_LAYER_Authentication: + Debug_Print("**PAP Finished**\r\n"); + break; + + case PPP_LAYER_Network: + Debug_Print("**IPCP Finished**\r\n"); + break; + + default: + break; + } + + Debug_Print("**Rebooting**\r\n"); + Reboot(); +} + + +// We get a NAK if our outbound Configure Request contains valid options, but the values are wrong. So we adjust our values for when the next Configure Request is sent +static void PPP_ProcessNAK(void) +{ + PPP_Option_t* CurrentOption = NULL; + + while ((CurrentOption = PPP_GetNextOption(IncomingPacket, CurrentOption)) != NULL) // Scan options in NAK packet + { + if (PPP_CheckForOption(CurrentOption)) + PPP_ChangeOption(OutgoingPacket, CurrentOption); // If the NAK'd option is already in the outgoing packet then change the existing option + else + PPP_AddOption(CurrentOption); // Otherwise add it + } +} + +// We get a REJ if our outbound Configure Request contains any options not acceptable to the remote end. So we remove those options. +static void PPP_ProcessREJ(void) +{ + PPP_Option_t* CurrentOption = NULL; + + while ((CurrentOption = PPP_GetNextOption(IncomingPacket, CurrentOption)) != NULL) // Scan options in REJ packet + PPP_RemoveOption(OutgoingPacket, CurrentOption->Type); // Remove the options(s) we don't want +} + +// Test to see if the incoming packet contains any options we can't support If so, take out all good options and leave the bad ones to be sent out in the REJ +static bool PPP_TestForREJ(const uint8_t Options[], + const uint8_t NumOptions) +{ + PPP_Option_t* CurrentOption = NULL; + bool FoundBadOption = false; + bool ThisOptionOK; + + while ((CurrentOption = PPP_GetNextOption(IncomingPacket, CurrentOption)) != NULL) // Scan incoming options + { + ThisOptionOK = false; + + for (uint8_t i = 0; i < NumOptions; i++) + { + if (CurrentOption->Type == Options[i]) + { + ThisOptionOK = true; + break; + } + } + + if (!ThisOptionOK) + FoundBadOption = true; + } + + if (!FoundBadOption) // No bad options. Return, leaving the packet untouched + return false; + + // We found some bad options, so now we need to go through the packet and remove all others, leaving the bad options to be sent out in the REJ + while ((CurrentOption = PPP_GetNextOption(IncomingPacket, CurrentOption)) != NULL) + { + for (uint8_t i = 0; i < NumOptions; i++) + { + if (CurrentOption->Type == Options[i]) + { + PPP_RemoveOption(IncomingPacket, CurrentOption->Type); + CurrentOption = NULL; // Start again. Easier than moving back (as next option has now moved into place of current option) + break; + } + } + } + + return true; +} + +// Test to see if the incoming packet contains an option with values that we can't accept +static bool PPP_TestForNAK(const PPP_Option_t* const Option) +{ + PPP_Option_t* CurrentOption = NULL; + bool FoundBadOption = false; + + while ((CurrentOption = PPP_GetNextOption(IncomingPacket, CurrentOption)) != NULL) // Scan options in receiver buffer + { + if (CurrentOption->Type == Option->Type) + { + for (uint8_t i = 0; i < Option->Length - 2; i++) + { + if (CurrentOption->Data[i] != Option->Data[i]) + FoundBadOption = true; + } + } + } + + if (!FoundBadOption) // No bad option. Return, leaving the packet untouched + return false; + + // We found a bad option, so now we need to go through the packet and remove all others, leaving the bad option to be sent out in the NAK + // and change the bad option to have a value that we can support + while ((CurrentOption = PPP_GetNextOption(IncomingPacket, CurrentOption)) != NULL) + { + if (CurrentOption->Type == Option->Type) + { + PPP_ChangeOption(IncomingPacket, Option); + } + else + { + PPP_RemoveOption(IncomingPacket, CurrentOption->Type); + CurrentOption = NULL; // Start again. Easier than moving back (as next option has now moved into place of current option) + } + } + + return true; +} + + +///////////////////////////// +// Packet Helper functions // +///////////////////////////// + +// Check if the given option is in the outgoing packet +static bool PPP_CheckForOption(const PPP_Option_t* const Option) +{ + PPP_Option_t* CurrentOption = NULL; + + while ((CurrentOption = PPP_GetNextOption(OutgoingPacket, CurrentOption)) != NULL) // Scan options in the packet + { + if (CurrentOption->Type == Option->Type) + return true; + } + + return false; +} + +// Add the given option to the end of the outgoing packet and adjust the size of the packet +static void PPP_AddOption(const PPP_Option_t* const Option) +{ + uint16_t OldPacketLength, NewPacketLength; + + if (OutgoingPacket == NULL) + { + OutgoingPacket = (PPP_Packet_t*)&OutgoingPacketBuffer; + OldPacketLength = sizeof(PPP_Packet_t); // If we're creating a new empty packet + } + else + OldPacketLength = uip_ntohs(OutgoingPacket->Length); // If the packet already exists + + NewPacketLength = OldPacketLength + Option->Length; + + if (NewPacketLength > OUTGOING_PACKET_BUFFER_SIZE) + { + Debug_Print("*** Packet overflow ***\r\n"); + return; + } + + memcpy((void*)OutgoingPacket + OldPacketLength, Option, Option->Length); // Add the new option + + OutgoingPacket->Length = uip_htons(NewPacketLength); +} + +// Try and find the option in the packet, and if it exists, change its value to that in the passed-in option (assumes the option lengths are the same) +static void PPP_ChangeOption(PPP_Packet_t* const ThisPacket, + const PPP_Option_t* const Option) +{ + PPP_Option_t* CurrentOption = NULL; + + while ((CurrentOption = PPP_GetNextOption(ThisPacket, CurrentOption)) != NULL) // Scan options in the packet + { + if (CurrentOption->Type == Option->Type) + memcpy(CurrentOption->Data, Option->Data, Option->Length - 2); // Copy the data portion of the option (not Type or Length) + } +} + +// Try and find the option in the packet, and if it exists remove it and adjust the size of the packet +static void PPP_RemoveOption(PPP_Packet_t* const ThisPacket, + const uint8_t Type) +{ + PPP_Option_t* CurrentOption = NULL; + PPP_Option_t* NextOption = NULL; + + while ((CurrentOption = PPP_GetNextOption(ThisPacket, CurrentOption)) != NULL) // Scan the options in the packet + { + if (CurrentOption->Type == Type) // Is it the packet we want to remove? + { + NextOption = PPP_GetNextOption(ThisPacket, CurrentOption); // Find the next option in the packet + uint8_t OptionLength = CurrentOption->Length; // Save the Option Length as the memcpy will change CurrentOption->Length + + if (NextOption != NULL) // If it's not the last option in the packet ... + { + uint16_t LenToCopy = uip_ntohs(ThisPacket->Length) - ((void*)CurrentOption - (void*)ThisPacket) - OptionLength; + memcpy(CurrentOption, NextOption, LenToCopy); // ... move all further options forward + } + + ThisPacket->Length = uip_htons(uip_ntohs(ThisPacket->Length) - OptionLength); // Adjust the length + } + } +} + +// Get the next option in the packet from the option that is passed in. Return NULL if last packet +static PPP_Option_t* PPP_GetNextOption(const PPP_Packet_t* const ThisPacket, + const PPP_Option_t* const CurrentOption) +{ + PPP_Option_t* NextOption; + + if (CurrentOption == NULL) + NextOption = (PPP_Option_t*)ThisPacket->Options; // First option + else + NextOption = (PPP_Option_t*)((uint8_t*)CurrentOption + CurrentOption->Length); + + // Check that we haven't overrun the end of the packet + if (((void*)NextOption - (void*)ThisPacket->Options) < (uip_ntohs(ThisPacket->Length) - 4)) + return NextOption; + else + return NULL; +} + + + +///////////////////////////////////////////////////////////////////////////////////////// +// The main PPP state machine - following RFC1661 - http://tools.ietf.org/html/rfc1661 // +///////////////////////////////////////////////////////////////////////////////////////// + +static void PPP_ManageState(const PPP_Events_t Event, + PPP_States_t* const State, + PPP_Layers_t const Layer) +{ + switch (*State) + { + case PPP_STATE_Initial: + + switch (Event) + { + case PPP_EVENT_Up: + *State = PPP_STATE_Closed; + break; + + case PPP_EVENT_Open: + *State = PPP_STATE_Starting; + This_Layer_Started(Layer); + break; + + case PPP_EVENT_Close: + *State = PPP_STATE_Initial; + break; + + case PPP_EVENT_TOPlus: + case PPP_EVENT_TOMinus: + break; + + default: + Debug_Print("Illegal Event\r\n"); + break; + } + break; + + case PPP_STATE_Starting: + + switch (Event) + { + case PPP_EVENT_Up: + *State = PPP_STATE_Req_Sent; + RestartCount = MAX_RESTARTS; + LinkTimer = 0; + TimerOn = true; + Send_Configure_Request(); + break; + + case PPP_EVENT_Open: + *State = PPP_STATE_Starting; + break; + + case PPP_EVENT_Close: + *State = PPP_STATE_Initial; + This_Layer_Finished(Layer); + break; + + case PPP_EVENT_TOPlus: + case PPP_EVENT_TOMinus: + break; + + default: + Debug_Print("Illegal Event\r\n"); + break; + } + break; + + case PPP_STATE_Closed: + + switch (Event) + { + case PPP_EVENT_Down: + *State = PPP_STATE_Initial; + break; + + case PPP_EVENT_Open: + *State = PPP_STATE_Req_Sent; + RestartCount = MAX_RESTARTS; + LinkTimer = 0; + TimerOn = true; + Send_Configure_Request(); + break; + + case PPP_EVENT_Close: + case PPP_EVENT_RTA: + case PPP_EVENT_RXJPlus: + case PPP_EVENT_RXR: + *State = PPP_STATE_Closed; + break; + + case PPP_EVENT_RCRPlus: + case PPP_EVENT_RCRMinus: + case PPP_EVENT_RCA: + case PPP_EVENT_RCN: + *State = PPP_STATE_Closed; + Send_Terminate_Ack(); + break; + + case PPP_EVENT_TOPlus: + case PPP_EVENT_TOMinus: + break; + + default: + Debug_Print("Illegal Event\r\n"); + break; + } + break; + + case PPP_STATE_Stopped: + + switch (Event) + { + case PPP_EVENT_Down: + *State = PPP_STATE_Starting; + This_Layer_Started(Layer); + break; + + case PPP_EVENT_Open: + *State = PPP_STATE_Stopped; + break; + + case PPP_EVENT_Close: + *State = PPP_STATE_Closed; + break; + + case PPP_EVENT_RCRPlus: + *State = PPP_STATE_Ack_Sent; + RestartCount = MAX_RESTARTS; + LinkTimer = 0; + TimerOn = true; + Send_Configure_Request(); + Send_Configure_Ack(); + break; + + case PPP_EVENT_RCRMinus: + *State = PPP_STATE_Req_Sent; + RestartCount = MAX_RESTARTS; + LinkTimer = 0; + TimerOn = true; + Send_Configure_Request(); + Send_Configure_Nak_Rej(); + break; + + case PPP_EVENT_RCA: + case PPP_EVENT_RCN: + case PPP_EVENT_RTR: + *State = PPP_STATE_Stopped; + Send_Terminate_Ack(); + break; + + case PPP_EVENT_RTA: + case PPP_EVENT_RXJPlus: + case PPP_EVENT_RXR: + *State = PPP_STATE_Stopped; + break; + + case PPP_EVENT_RUC: + *State = PPP_STATE_Stopped; + Send_Code_Reject(); + break; + + case PPP_EVENT_RXJMinus: + *State = PPP_STATE_Stopped; + This_Layer_Finished(Layer); + break; + + case PPP_EVENT_TOPlus: + case PPP_EVENT_TOMinus: + break; + + default: + Debug_Print("Illegal Event\r\n"); + break; + } + break; + + case PPP_STATE_Closing: + + switch (Event) + { + case PPP_EVENT_Down: + TimerOn = false; + *State = PPP_STATE_Initial; + break; + + case PPP_EVENT_Open: + *State = PPP_STATE_Stopping; + break; + + case PPP_EVENT_Close: + *State = PPP_STATE_Closing; + break; + + case PPP_EVENT_TOPlus: + Send_Terminate_Request(); + *State = PPP_STATE_Closing; + break; + + case PPP_EVENT_TOMinus: + *State = PPP_STATE_Closed; + TimerOn = false; + This_Layer_Finished(Layer); + break; + + case PPP_EVENT_RCRPlus: + case PPP_EVENT_RCRMinus: + case PPP_EVENT_RCA: + case PPP_EVENT_RCN: + case PPP_EVENT_RXJPlus: + case PPP_EVENT_RXR: + *State = PPP_STATE_Closing; + break; + + case PPP_EVENT_RTR: + *State = PPP_STATE_Closing; + Send_Terminate_Ack(); + break; + + case PPP_EVENT_RTA: + case PPP_EVENT_RXJMinus: + *State = PPP_STATE_Closed; + TimerOn = false; + This_Layer_Finished(Layer); + break; + + case PPP_EVENT_RUC: + *State = PPP_STATE_Closing; + Send_Code_Reject(); + break; + + default: + Debug_Print("Illegal Event\r\n"); + break; + } + break; + + case PPP_STATE_Stopping: + + switch (Event) + { + case PPP_EVENT_Down: + *State = PPP_STATE_Starting; + TimerOn = false; + break; + + case PPP_EVENT_Open: + *State = PPP_STATE_Stopping; + break; + + case PPP_EVENT_Close: + *State = PPP_STATE_Closing; + break; + + case PPP_EVENT_TOPlus: + Send_Terminate_Request(); + *State = PPP_STATE_Stopping; + break; + + case PPP_EVENT_TOMinus: + This_Layer_Finished(Layer); + TimerOn = false; + *State = PPP_STATE_Stopped; + break; + + case PPP_EVENT_RCRPlus: + case PPP_EVENT_RCRMinus: + case PPP_EVENT_RCA: + case PPP_EVENT_RCN: + case PPP_EVENT_RXJPlus: + case PPP_EVENT_RXR: + *State = PPP_STATE_Stopping; + break; + + case PPP_EVENT_RTR: + Send_Terminate_Ack(); + *State = PPP_STATE_Stopping; + break; + + case PPP_EVENT_RTA: + case PPP_EVENT_RXJMinus: + This_Layer_Finished(Layer); + TimerOn = false; + *State = PPP_STATE_Stopped; + break; + + case PPP_EVENT_RUC: + Send_Code_Reject(); + *State = PPP_STATE_Stopping; + break; + + default: + Debug_Print("Illegal Event\r\n"); + break; + } + break; + + case PPP_STATE_Req_Sent: + + switch (Event) + { + case PPP_EVENT_Down: + *State = PPP_STATE_Starting; + TimerOn = false; + break; + + case PPP_EVENT_Open: + case PPP_EVENT_RTA: + case PPP_EVENT_RXJPlus: + case PPP_EVENT_RXR: + *State = PPP_STATE_Req_Sent; + break; + + case PPP_EVENT_Close: + RestartCount = MAX_RESTARTS; + LinkTimer = 0; + Send_Terminate_Request(); + *State = PPP_STATE_Closing; + break; + + case PPP_EVENT_TOPlus: + Send_Configure_Request(); + *State = PPP_STATE_Req_Sent; + break; + + case PPP_EVENT_TOMinus: + This_Layer_Finished(Layer); + TimerOn = false; + *State = PPP_STATE_Stopped; + break; + + case PPP_EVENT_RCRPlus: + if (Layer != PPP_LAYER_Authentication) // We faked a Configure request for PAP. So no need to answer it if we're in the authentication phase + Send_Configure_Ack(); + + *State = PPP_STATE_Ack_Sent; + break; + + case PPP_EVENT_RCRMinus: + Send_Configure_Nak_Rej(); + *State = PPP_STATE_Req_Sent; + break; + + case PPP_EVENT_RCA: + RestartCount = MAX_RESTARTS; + LinkTimer = 0; + *State = PPP_STATE_Ack_Rcvd; + break; + + case PPP_EVENT_RCN: + RestartCount = MAX_RESTARTS; + LinkTimer = 0; + Send_Configure_Request(); + *State = PPP_STATE_Req_Sent; + break; + + case PPP_EVENT_RTR: + Send_Terminate_Ack(); + *State = PPP_STATE_Req_Sent; + break; + + case PPP_EVENT_RUC: + Send_Code_Reject(); + *State = PPP_STATE_Req_Sent; + break; + + case PPP_EVENT_RXJMinus: + This_Layer_Finished(Layer); + TimerOn = false; + *State = PPP_STATE_Stopped; + break; + + default: + Debug_Print("Illegal Event\r\n"); + break; + } + break; + + case PPP_STATE_Ack_Rcvd: + + switch (Event) + { + case PPP_EVENT_Down: + *State = PPP_STATE_Starting; + TimerOn = false; + break; + + case PPP_EVENT_Open: + case PPP_EVENT_RXR: + *State = PPP_STATE_Ack_Rcvd; + break; + + case PPP_EVENT_Close: + RestartCount = MAX_RESTARTS; + LinkTimer = 0; + Send_Terminate_Request(); + *State = PPP_STATE_Closing; + break; + + case PPP_EVENT_TOPlus: + case PPP_EVENT_RCA: + case PPP_EVENT_RCN: + Send_Configure_Request(); + *State = PPP_STATE_Req_Sent; + break; + + case PPP_EVENT_TOMinus: + This_Layer_Finished(Layer); + TimerOn = false; + *State = PPP_STATE_Stopped; + break; + + case PPP_EVENT_RCRPlus: + Send_Configure_Ack(); + This_Layer_Up(Layer); + TimerOn = false; + *State = PPP_STATE_Opened; + break; + + case PPP_EVENT_RCRMinus: + Send_Configure_Nak_Rej(); + *State = PPP_STATE_Ack_Rcvd; + break; + + case PPP_EVENT_RTR: + Send_Terminate_Ack(); + *State = PPP_STATE_Req_Sent; + break; + + case PPP_EVENT_RTA: + case PPP_EVENT_RXJPlus: + Send_Terminate_Ack(); + *State = PPP_STATE_Req_Sent; + break; + + case PPP_EVENT_RUC: + Send_Code_Reject(); + *State = PPP_STATE_Ack_Rcvd; + break; + + case PPP_EVENT_RXJMinus: + This_Layer_Finished(Layer); + TimerOn = false; + *State = PPP_STATE_Stopped; + break; + + default: + Debug_Print("Illegal Event\r\n"); + break; + } + break; + + case PPP_STATE_Ack_Sent: + + switch (Event) + { + case PPP_EVENT_Down: + *State = PPP_STATE_Starting; + TimerOn = false; + break; + + case PPP_EVENT_Open: + case PPP_EVENT_RTA: + case PPP_EVENT_RXJPlus: + case PPP_EVENT_RXR: + *State = PPP_STATE_Ack_Sent; + break; + + case PPP_EVENT_Close: + RestartCount = MAX_RESTARTS; + LinkTimer = 0; + Send_Terminate_Request(); + *State = PPP_STATE_Closing; + break; + + case PPP_EVENT_TOPlus: + Send_Configure_Request(); + *State = PPP_STATE_Ack_Sent; + break; + + case PPP_EVENT_TOMinus: + This_Layer_Finished(Layer); + TimerOn = false; + *State = PPP_STATE_Stopped; + break; + + case PPP_EVENT_RCRPlus: + Send_Configure_Ack(); + *State = PPP_STATE_Ack_Sent; + break; + + case PPP_EVENT_RCRMinus: + Send_Configure_Nak_Rej(); + *State = PPP_STATE_Req_Sent; + break; + + case PPP_EVENT_RCA: + RestartCount = MAX_RESTARTS; + LinkTimer = 0; + TimerOn = false; + This_Layer_Up(Layer); + *State = PPP_STATE_Opened; + break; + + case PPP_EVENT_RCN: + RestartCount = MAX_RESTARTS; + LinkTimer = 0; + Send_Configure_Request(); + *State = PPP_STATE_Ack_Sent; + break; + + case PPP_EVENT_RTR: + Send_Terminate_Ack(); + *State = PPP_STATE_Req_Sent; + break; + + case PPP_EVENT_RUC: + Send_Code_Reject(); + *State = PPP_STATE_Ack_Sent; + break; + + case PPP_EVENT_RXJMinus: + This_Layer_Finished(Layer); + TimerOn = false; + *State = PPP_STATE_Stopped; + break; + + default: + Debug_Print("Illegal Event\r\n"); + break; + } + break; + + case PPP_STATE_Opened: + + switch (Event) + { + case PPP_EVENT_Down: + This_Layer_Down(Layer); + *State = PPP_STATE_Starting; + break; + + case PPP_EVENT_Open: + case PPP_EVENT_RXJPlus: + *State = PPP_STATE_Opened; + break; + + case PPP_EVENT_Close: + This_Layer_Down(Layer); + RestartCount = MAX_RESTARTS; + LinkTimer = 0; + TimerOn = true; + Send_Terminate_Request(); + *State = PPP_STATE_Closing; + break; + + case PPP_EVENT_RCRPlus: + This_Layer_Down(Layer); + TimerOn = true; + Send_Configure_Request(); + Send_Configure_Ack(); + *State = PPP_STATE_Ack_Sent; + break; + + case PPP_EVENT_RCRMinus: + This_Layer_Down(Layer); + TimerOn = true; + Send_Configure_Request(); + Send_Configure_Nak_Rej(); + *State = PPP_STATE_Req_Sent; + break; + + case PPP_EVENT_RCA: + case PPP_EVENT_RCN: + case PPP_EVENT_RTA: + This_Layer_Down(Layer); + TimerOn = true; + Send_Configure_Request(); + *State = PPP_STATE_Req_Sent; + break; + + case PPP_EVENT_RTR: + This_Layer_Down(Layer); + RestartCount = 0; + LinkTimer = 0; + TimerOn = true; + Send_Terminate_Ack(); + *State = PPP_STATE_Stopping; + break; + + case PPP_EVENT_RUC: + Send_Code_Reject(); + *State = PPP_STATE_Opened; + break; + + case PPP_EVENT_RXJMinus: + This_Layer_Down(Layer); + RestartCount = MAX_RESTARTS; + LinkTimer = 0; + TimerOn = true; + Send_Terminate_Request(); + *State = PPP_STATE_Stopping; + break; + + case PPP_EVENT_RXR: + Send_Echo_Reply(); + *State = PPP_STATE_Opened; + break; + + default: + Debug_Print("Illegal Event\r\n"); + break; + } + break; + + default: + break; + } +} diff -r 5c8404549cc0 -r 56d09a0969b5 network/PPP.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/PPP.h Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,196 @@ +/* + LUFA Powered Wireless 3G Modem Host + + Copyright (C) Mike Alexander, 2010. + Copyright (C) Dean Camera, 2010. +*/ + +/* + Copyright 2010 Mike Alexander (mike [at] mikealex [dot] com) + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +#ifndef _PPP_H_ +#define _PPP_H_ + + /* Includes: */ + #include + #include + #include + + #include "LinkManagement.h" + #include "Lib/RingBuff.h" + #include "Lib/Debug.h" + + /* Enums: */ + + typedef enum + { + PPP_LAYER_Physical, + PPP_LAYER_Authentication, + PPP_LAYER_Network, + } PPP_Layers_t; + + typedef enum + { + PPP_PHASE_Dead, + PPP_PHASE_Establish, + PPP_PHASE_Authenticate, + PPP_PHASE_Network, + PPP_PHASE_Terminate + } PPP_Phases_t; + + typedef enum + { + PPP_STATE_Initial, + PPP_STATE_Starting, + PPP_STATE_Closed, + PPP_STATE_Stopped, + PPP_STATE_Closing, + PPP_STATE_Stopping, + PPP_STATE_Req_Sent, + PPP_STATE_Ack_Rcvd, + PPP_STATE_Ack_Sent, + PPP_STATE_Opened + } PPP_States_t; + + typedef enum + { + PPP_EVENT_Up, + PPP_EVENT_Down, + PPP_EVENT_Open, + PPP_EVENT_Close, + PPP_EVENT_TOPlus, + PPP_EVENT_TOMinus, + PPP_EVENT_RCRPlus, + PPP_EVENT_RCRMinus, + PPP_EVENT_RCA, + PPP_EVENT_RCN, + PPP_EVENT_RTR, + PPP_EVENT_RTA, + PPP_EVENT_RUC, + PPP_EVENT_RXJPlus, + PPP_EVENT_RXJMinus, + PPP_EVENT_RXR + } PPP_Events_t; + + /* Type Defines: */ + typedef struct + { + uint8_t Type; + uint8_t Length; + uint8_t Data[]; + } PPP_Option_t; + + typedef struct + { + uint8_t Code; + uint8_t PacketID; + uint16_t Length; + PPP_Option_t Options[]; + } PPP_Packet_t; + + /* Macros: */ + #define CALC_CRC16(crcvalue, c) _crc_ccitt_update(crcvalue, c); + + // Defines for LCP Negotiation Codes + #define REQ 1 // Request options list for PPP negotiations + #define ACK 2 // Acknowledge options list for PPP negotiations + #define NAK 3 // Not acknowledged options list for PPP negotiations + #define REJ 4 // Reject options list for PPP negotiations + #define TERMREQ 5 // Termination request for LCP to close connection + #define TERMREPLY 6 // Termination reply + #define CODEREJ 7 // Code reject + #define PROTREJ 8 // Protocol reject + #define ECHOREQ 9 // Echo Request + #define ECHOREPLY 10 // Echo Reply + #define DISC 11 // Discard request + + // Packet Types (Protocols) + #define IP 0x0021 // Internet Protocol packet + #define IPCP 0x8021 // Internet Protocol Configure Protocol packet + #define LCP 0xC021 // Link Configure Protocol packet + #define PAP 0xC023 // Password Authentication Protocol packet + #define CHAP 0xC223 // Challenge Handshake Authentication Protocol packet + #define NONE 0x0000 + + #define LCP_OPTION_Maximum_Receive_Unit 0x1 // LCP Option 1 + #define LCP_OPTION_Async_Control_Character_Map 0x2 // LCP Option 2 + #define LCP_OPTION_Authentication_Protocol 0x3 // LCP Option 3 + #define LCP_OPTION_Quality_Protocol 0x4 // LCP Option 4 + #define LCP_OPTION_Magic_Number 0x5 // LCP Option 5 + #define LCP_OPTION_Reserved 0x6 // LCP Option 6 + #define LCP_OPTION_Protocol_Field_Compression 0x7 // LCP Option 7 + #define LCP_OPTION_Address_and_Control_Field_Compression 0x8 // LCP Option 8 + #define LCP_OPTION_Callback 0xd // LCP Option D + + #define IPCP_OPTION_IP_Compression_Protocol 0x2 // IPCP Option 2 + #define IPCP_OPTION_IP_address 0x3 // IPCP Option 3 + #define IPCP_OPTION_Primary_DNS 0x81 // IPCP Option 81 + #define IPCP_OPTION_Secondary_DNS 0x83 // IPCP Option 83 + + #define MAX_RESTARTS 5 + #define OUTGOING_PACKET_BUFFER_SIZE 48 + + /* External Variables: */ + extern uint8_t ConnectedState; + + /* Function Prototypes: */ + void PPP_ManageLink(void); + void PPP_InitPPP(void); + void PPP_LinkTimer(void); + void PPP_LinkUp(void); + void PPP_LinkOpen(void); + void PPP_StartLink(void); + + #if defined(INCLUDE_FROM_PPP_C) + static PPP_Option_t* PPP_GetNextOption(const PPP_Packet_t* const ThisPacket, + const PPP_Option_t* const CurrentOption); + static void PPP_RemoveOption(PPP_Packet_t* const ThisPacket, + const uint8_t Type); + static void PPP_AddOption(const PPP_Option_t*); + static bool PPP_CheckForOption(const PPP_Option_t*); + static void PPP_ChangeOption(PPP_Packet_t* const ThisPacket, + const PPP_Option_t* const Option); + static void PPP_ProcessNAK(void); + static void PPP_ProcessREJ(void); + static bool PPP_TestForNAK(const PPP_Option_t* const Option); + static bool PPP_TestForREJ(const uint8_t Options[], + const uint8_t NumOptions); + static void PPP_ManageState(const PPP_Events_t Event, + PPP_States_t* const State, + PPP_Layers_t const Layer); + static void Send_Configure_Request(void); + static void Send_Configure_Ack(void); + static void Send_Configure_Nak_Rej(void); + static void Send_Terminate_Request(void); + static void Send_Terminate_Ack(void); + static void Send_Code_Reject(void); + static void Send_Echo_Reply(void); + static void This_Layer_Up(PPP_Layers_t Layer); + static void This_Layer_Down(PPP_Layers_t Layer); + static void This_Layer_Started(PPP_Layers_t Layer); + static void This_Layer_Finished(PPP_Layers_t Layer); + #endif + +#endif + + diff -r 5c8404549cc0 -r 56d09a0969b5 network/TCPIP.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/TCPIP.c Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,206 @@ +/* + LUFA Powered Wireless 3G Modem Host + + Copyright (C) Mike Alexander, 2010. + Copyright (C) Dean Camera, 2010. +*/ + +/* + Copyright 2010 Mike Alexander (mike [at] mikealex [dot] com) + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +#define INCLUDE_FROM_TCPIP_C +#include "TCPIP.h" + +uint8_t IPAddr1, IPAddr2, IPAddr3, IPAddr4; +static uip_ipaddr_t RemoteIPAddress; +static struct uip_conn* TCPConnection; +static struct timer Periodic_Timer; + +bool TCPIP_Connect(void) +{ + // Connect to the remote machine (www.example.com) + uip_ipaddr(&RemoteIPAddress, 192, 0, 32, 10); + TCPConnection = uip_connect(&RemoteIPAddress, UIP_HTONS(80)); + + if (TCPConnection != NULL) + { + Debug_Print("Connecting to host\r\n"); + return true; + } + else + { + Debug_Print("Failed to Connect\r\n"); + return false; + } +} + +void TCPIP_TCPCallback(void) +{ + if (uip_acked()) + Debug_Print("[ACK] "); + + if (uip_newdata()) + { + Debug_Print("New Data:\r\n"); + TCPIP_QueueData(uip_appdata, uip_datalen()); + + if (TCPIP_IsDataQueueFull()) + uip_stop(); + } + + if (uip_connected()) + { + Debug_Print("Connected - Maximum Segment Size: 0x"); Debug_PrintHex(uip_mss() / 256); Debug_PrintHex(uip_mss() & 255); + Debug_Print("\r\n"); + } + + if (uip_closed()) + { + Debug_Print("Closed - Reconnecting..."); + _delay_ms(1000); + ConnectedState = LINKMANAGEMENT_STATE_ConnectToRemoteHost; + } + + if (uip_aborted()) + { + Debug_Print("Aborted - Reconnecting... "); + _delay_ms(1000); + ConnectedState = LINKMANAGEMENT_STATE_ConnectToRemoteHost; + } + + if (uip_timedout()) + { + Debug_Print("Timeout - Reconnecting..."); + uip_abort(); + _delay_ms(1000); + ConnectedState = LINKMANAGEMENT_STATE_ConnectToRemoteHost; + } + + if (uip_poll() && (SystemTicks > 3000)) + { + SystemTicks = 0; + + Debug_Print("\r\nSending GET\r\n"); + TCPIP_SendGET(); + } + + if (uip_rexmit()) + { + Debug_Print("\r\nRetransmit GET\r\n"); + TCPIP_SendGET(); + } + + if (uip_poll() && uip_stopped(TCPConnection)) + { + if (!(TCPIP_IsDataQueueFull())) + uip_restart(); + } +} + +static void TCPIP_SendGET(void) +{ + const char GETRequest[] = "GET / HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "Connection: Keep-Alive\r\n\r\n"; + + uip_send(GETRequest, strlen(GETRequest)); +} + +static void TCPIP_QueueData(const char* Data, + const uint16_t Length) +{ + if (Length > 0) + WatchdogTicks = 0; // Reset the timeout counter + + for (uint16_t i = 0; i < Length; i++) + putchar(Data[i]); + + Debug_Print("\r\n"); +} + +static bool TCPIP_IsDataQueueFull(void) +{ + return false; +} + +void TCPIP_InitializeTCPStack(void) +{ + Debug_Print("Init TCP Stack\r\n"); + + // Periodic Connection Timer Initialization + timer_set(&Periodic_Timer, CLOCK_SECOND / 2); + + // uIP Initialization + network_init(); + clock_init(); + uip_init(); + + // Set this machine's IP address + uip_ipaddr_t LocalIPAddress; + uip_ipaddr(&LocalIPAddress, IPAddr1, IPAddr2, IPAddr3, IPAddr4); + uip_sethostaddr(&LocalIPAddress); + + ConnectedState = LINKMANAGEMENT_STATE_ConnectToRemoteHost; + SystemTicks = 2000; // Make the first CONNECT happen straight away +} + +void TCPIP_ConnectToRemoteHost(void) +{ + if (SystemTicks > 1000) // Try to connect every 1 second + { + SystemTicks = 0; + + if (TCPIP_Connect()) + { + SystemTicks = 3001; // Make the first GET happen straight away + uip_len = 0; + ConnectedState = LINKMANAGEMENT_STATE_ManageTCPConnection; + } + } +} + +void TCPIP_GotNewPacket(void) +{ + uip_input(); // Call the TCP/IP stack with the new packet + + if (uip_len > 0) // If the above function invocation resulted in data that should be sent out + network_send(IP); // on the network, the global variable uip_len is set to a value > 0. +} + +void TCPIP_TCPIPTask(void) +{ + if (timer_expired(&Periodic_Timer)) + { + timer_reset(&Periodic_Timer); + + Debug_PrintChar('*'); + + for (uint8_t i = 0; i < UIP_CONNS; i++) + { + uip_periodic(i); + + if (uip_len > 0) // If the above function invocation resulted in data that should be sent out on the network, + network_send(IP); //the global variable uip_len is set to a value > 0. + } + } +} diff -r 5c8404549cc0 -r 56d09a0969b5 network/TCPIP.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/TCPIP.h Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,64 @@ +/* + LUFA Powered Wireless 3G Modem Host + + Copyright (C) Mike Alexander, 2010. + Copyright (C) Dean Camera, 2010. +*/ + +/* + Copyright 2010 Mike Alexander (mike [at] mikealex [dot] com) + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for TCPIP.c. + */ + +#ifndef _TCPIP_H_ +#define _TCPIP_H_ + + /* Includes: */ + #include + #include + #include "Lib/Debug.h" + + /* External Variables: */ + extern uint8_t ConnectedState; + extern uint8_t WatchdogTicks; + extern uint16_t SystemTicks; + + /* Function Prototypes: */ + void TCPIP_TCPIPTask(void); + void TCPIP_InitializeTCPStack(void); + void TCPIP_ConnectToRemoteHost(void); + void TCPIP_GotNewPacket(void); + void TCPIP_TCPCallback(void); + + #if defined(INCLUDE_FROM_TCPIP_C) + static void TCPIP_SendGET(void); + static void TCPIP_QueueData(const char* Data, + const uint16_t Length); + static bool TCPIP_IsDataQueueFull(void); + static bool TCPIP_Connect(void); + #endif + +#endif diff -r 5c8404549cc0 -r 56d09a0969b5 network/clock.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/clock.c Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include + +#include "clock.h" + +//Counted time +volatile clock_time_t clock_datetime = 0; + +//Overflow interrupt +ISR(TIMER0_COMPA_vect) +{ + clock_datetime += 1; +} + +//Initialise the clock +void clock_init() +{ + // 10ms tick interval + OCR0A = ((F_CPU / 1024) / 100); + TCCR0A = (1 << WGM01); + TCCR0B = ((1 << CS02) | (1 << CS00)); + TIMSK0 = (1 << OCIE0A); +} + +//Return time +clock_time_t clock_time() +{ + clock_time_t time; + + ATOMIC_BLOCK(ATOMIC_FORCEON) + { + time = clock_datetime; + } + + return time; +} diff -r 5c8404549cc0 -r 56d09a0969b5 network/clock.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/clock.h Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,11 @@ +#ifndef __CLOCK_ARCH_H__ +#define __CLOCK_ARCH_H__ + +#include + +typedef uint16_t clock_time_t; +#define CLOCK_SECOND 100 +void clock_init(void); +clock_time_t clock_time(void); + +#endif /* __CLOCK_ARCH_H__ */ diff -r 5c8404549cc0 -r 56d09a0969b5 network/network.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network.c Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,256 @@ +#define INCLUDE_FROM_NETWORK_C +#include "network.h" + +static bool Escape = false; +static uint8_t PacketState = PACKET_STATE_NULL; +static uint16_t PacketProtocol = 0; +static uint16_t PacketLength = 0; +static uint16_t CurrentChecksum, OneBackChecksum, TwoBackChecksum; + + +// Framed packet looks like: +// Framing: 0x7e +// Address: 0xff +// Control: 0x03 +// Protocol: 0xnn 0xnn +// Information: 0xnn 0xnn 0xnn 0xnn ... +// Checksum: 0xnn 0xnn +// Framing: 0x7e +// +// If Address-and-Control-Field-Compression is switched on then the remote end is allowed to leave out the 0xff 0x03 in the header +// If Protocol-Field-Compression is switched on and the protocol < 0x00ff then the remote end is allowed to leave out the initial 0x00 in the protocol field. +// We can check for Protocol-Field-Compression by seeing if the first byte of the protocol is odd (the first byte of a full two-byte protocol value must be even). + +uint16_t network_read(void) +{ + RingBuff_Elements_t c; + + while (Modem_ReceiveBuffer.Elements) + { + c = Buffer_GetElement(&Modem_ReceiveBuffer); + + switch (PacketState) + { + case PACKET_STATE_NULL: + if (c == 0x7e) // New Packet + { + PacketState = PACKET_STATE_INHEADER; // We're now in the header + PacketLength = 0; + CurrentChecksum = 0xffff; // Start new checksum + } + break; + + case PACKET_STATE_INHEADER: + if (c == 0x7d) // Escaped character. Set flag and process next time around + { + Escape = true; + continue; + } + else if (Escape) // Escaped character. Process now. + { + Escape = false; + c = (c ^ 0x20); + } + + if (PacketLength == 1 && c != 0xff) // Should be 0xff. If not then Address-and-Control-Field-Compression is switched on + { + PacketLength += 2; // Adjust the length as if the 0xff 0x03 was there + } + + if (PacketLength == 3) + { + if (c & 1) // Should be even. If it's odd then Protocol-Field-Compression is switched on + { + PacketProtocol = 0x00; // Add in the initial 0x00 + PacketLength++; // Adjust the length as if the 0x00 was there + } + else + PacketProtocol = c * 256; // Store the MSB of the protocol + } + + if (PacketLength == 4) // End of header + { + PacketProtocol |= c; // Store the LSB of the protocol + PacketLength = -1; // This will be incremented to 0 at the end of this loop + Escape = false; + PacketState = PACKET_STATE_INBODY; // We're now in the body + } + + CurrentChecksum = CALC_CRC16(CurrentChecksum, c); // Calculate checksum + break; + + case PACKET_STATE_INBODY: + if (c == 0x7e) // End of packet + { + uip_len = PacketLength - 2; // Strip off the checksum and framing + Escape = false; + PacketState = PACKET_STATE_NULL; // Back to waiting for a header + + Debug_Print("\r\nReceive "); + DumpPacket(); + + if (~TwoBackChecksum == (*(uip_buf + PacketLength - 1) * 256 + *(uip_buf + PacketLength - 2))) + return PacketProtocol; + else + Debug_Print("Bad CRC\r\n"); + } + else + { + if (c == 0x7d) // Escaped character. Set flag and process next time around + { + Escape = true; + continue; + } + else if (Escape) // Escaped character. Process now. + { + Escape = false; + c = (c ^ 0x20); + } + + *(uip_buf + PacketLength) = c; // Store the character in the buffer + + TwoBackChecksum = OneBackChecksum; // Keep a rolling count of the last 3 checksums + OneBackChecksum = CurrentChecksum; // Eventually we need to see if the checksum is valid + CurrentChecksum = CALC_CRC16(CurrentChecksum, c); // and we need the one two back (as the current one includes the checksum itself) + } + break; + } + + PacketLength++; // Increment the length of the received packet + } + + return 0; // No data or packet not complete yet +} + +void network_send(uint16_t protocol) +{ + unsigned int checksum = 0xffff; + + PacketProtocol = protocol; + PacketState = PACKET_STATE_NULL; + + Debug_Print("\r\nSend "); + DumpPacket(); + + // Send out the packet with HDLC-like framing - see http://tools.ietf.org/html/rfc1662 + + // Start with the framing flag + Buffer_StoreElement(&Modem_SendBuffer, 0x7e); + + // Address + Buffer_StoreElement(&Modem_SendBuffer, 0xff); + checksum = CALC_CRC16(checksum, 0xff); + + // Control + Buffer_StoreElement(&Modem_SendBuffer, 0x03); + checksum = CALC_CRC16(checksum, 0x03); + + // Protocol + Buffer_StoreElement(&Modem_SendBuffer, protocol / 256); + checksum = CALC_CRC16(checksum, protocol / 256); + + Buffer_StoreElement(&Modem_SendBuffer, protocol & 255); + checksum = CALC_CRC16(checksum, protocol & 255); + + // Add the information, escaping it as necessary + for (uint16_t i = 0; i < uip_len; i++) + { + if (*(uip_buf + i) < 0x20 || *(uip_buf + i) == 0x7d || *(uip_buf + i) == 0x7e) + { + Buffer_StoreElement(&Modem_SendBuffer, 0x7d); + Buffer_StoreElement(&Modem_SendBuffer, *(uip_buf + i) ^ 0x20); + } + else + { + Buffer_StoreElement(&Modem_SendBuffer, *(uip_buf + i)); + } + + checksum = CALC_CRC16(checksum, *(uip_buf + i)); + + if (Modem_SendBuffer.Elements == BUFF_STATICSIZE) // Periodically flush the buffer to the modem + USBManagement_SendReceivePipes(); + } + + // Add the checksum to the end of the packet, escaping it as necessary + checksum = ~checksum; + + if ((checksum & 255) < 0x20 || (checksum & 255) == 0x7d || (checksum & 255) == 0x7e) + { + Buffer_StoreElement(&Modem_SendBuffer, 0x7d); + Buffer_StoreElement(&Modem_SendBuffer, (checksum & 255) ^ 0x20); + } + else + { + Buffer_StoreElement(&Modem_SendBuffer, checksum & 255); // Insert checksum MSB + } + + if ((checksum / 256) < 0x20 || (checksum / 256) == 0x7d || (checksum / 256) == 0x7e) + { + Buffer_StoreElement(&Modem_SendBuffer, 0x7d); + Buffer_StoreElement(&Modem_SendBuffer, (checksum / 256) ^ 0x20); + } + else + { + Buffer_StoreElement(&Modem_SendBuffer, checksum / 256); // Insert checksum LSB + } + + Buffer_StoreElement(&Modem_SendBuffer, 0x7e); // Framing + + uip_len = 0; + + USBManagement_SendReceivePipes(); // Flush the rest of the buffer +} + +void network_init(void) +{ + //Initialise the device + PacketState = PACKET_STATE_NULL; + Escape = false; + uip_len = 0; +} + +void DumpPacket(void) +{ + int i, j; + + if (!DebugModeEnabled) + return; + + Debug_Print("(Protocol = 0x"); + Debug_PrintHex(PacketProtocol / 256); Debug_PrintHex(PacketProtocol & 255); + Debug_Print("):\r\n"); + + for (i = 0; i < uip_len; i += 16) + { + Debug_PrintHex(i / 256); Debug_PrintHex(i & 255); Debug_Print(": "); + + for (j = 0; j < 16; j++) + { + if ((i + j) >= uip_len) + break; + + Debug_PrintHex(*(uip_buf + i + j)); + Debug_PrintChar(' '); + } + + Debug_Print("\r\n "); + + for (j = 0; j < 16; j++) + { + if ((i + j) >= uip_len) + break; + + if (*(uip_buf + i + j) >= 0x20 && *(uip_buf + i + j) <= 0x7e) + { + Debug_PrintChar(' '); + Debug_PrintChar(*(uip_buf + i + j)); + Debug_PrintChar(' '); + } + else + Debug_Print(" . "); + + } + + Debug_Print("\r\n"); + } +} diff -r 5c8404549cc0 -r 56d09a0969b5 network/network.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network.h Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,44 @@ +/* + * Simple common network interface that all network drivers should implement. + */ + +#ifndef __NETWORK_H__ +#define __NETWORK_H__ + + #include + #include + + #include + + #include "USBModem.h" + #include "Lib/RingBuff.h" + + /* External Variables: */ + extern RingBuff_t Modem_SendBuffer; + extern RingBuff_t Modem_ReceiveBuffer; + extern bool DebugModeEnabled; + + /* Enums: */ + enum Packet_States_t + { + PACKET_STATE_NULL = 0, + PACKET_STATE_INHEADER = 1, + PACKET_STATE_INBODY = 2, + }; + + /* Function Prototypes: */ + void network_init(void); + uint16_t network_read(void); + void network_send(uint16_t protocol); + + #if defined(INCLUDE_FROM_NETWORK_C) + static void DumpPacket(void); + #endif + + /*Sets the MAC address of the device*/ + //void network_set_MAC(uint8_t* mac); + + /*Gets the MAC address of the device*/ + //void network_get_MAC(uint8_t* mac); + +#endif /* __NETWORK_H__ */ diff -r 5c8404549cc0 -r 56d09a0969b5 network/tags --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/tags Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,522 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ +!_TAG_PROGRAM_NAME Exuberant Ctags // +!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ +!_TAG_PROGRAM_VERSION 5.8 // +BUF uip.c /^#define BUF /;" d file: +CCIF uip.h /^#define CCIF$/;" d +CLOCK_SECOND clock.h /^#define CLOCK_SECOND /;" d +CurrentChecksum network.c /^static uint16_t CurrentChecksum, OneBackChecksum, TwoBackChecksum;$/;" v file: +DEBUG_PRINTF uip.c /^#define DEBUG_PRINTF(/;" d file: +DumpPacket network.c /^void DumpPacket(void)$/;" f +Escape network.c /^static bool Escape = false;$/;" v file: +FBUF uip.c /^#define FBUF /;" d file: +ICMP6_ECHO uip.c /^#define ICMP6_ECHO /;" d file: +ICMP6_ECHO_REPLY uip.c /^#define ICMP6_ECHO_REPLY /;" d file: +ICMP6_FLAG_S uip.c /^#define ICMP6_FLAG_S /;" d file: +ICMP6_NEIGHBOR_ADVERTISEMENT uip.c /^#define ICMP6_NEIGHBOR_ADVERTISEMENT /;" d file: +ICMP6_NEIGHBOR_SOLICITATION uip.c /^#define ICMP6_NEIGHBOR_SOLICITATION /;" d file: +ICMP6_OPTION_SOURCE_LINK_ADDRESS uip.c /^#define ICMP6_OPTION_SOURCE_LINK_ADDRESS /;" d file: +ICMP6_OPTION_TARGET_LINK_ADDRESS uip.c /^#define ICMP6_OPTION_TARGET_LINK_ADDRESS /;" d file: +ICMPBUF uip.c /^#define ICMPBUF /;" d file: +ICMP_DEST_UNREACHABLE uip.c /^#define ICMP_DEST_UNREACHABLE /;" d file: +ICMP_ECHO uip.c /^#define ICMP_ECHO /;" d file: +ICMP_ECHO_REPLY uip.c /^#define ICMP_ECHO_REPLY /;" d file: +ICMP_PORT_UNREACHABLE uip.c /^#define ICMP_PORT_UNREACHABLE /;" d file: +INCLUDE_FROM_NETWORK_C network.c /^#define INCLUDE_FROM_NETWORK_C$/;" d file: +IP_MF uip.c /^#define IP_MF /;" d file: +ISR clock.c /^ISR(TIMER0_COMPA_vect)$/;" f +MIN uip.c /^#define MIN(/;" d file: +OneBackChecksum network.c /^static uint16_t CurrentChecksum, OneBackChecksum, TwoBackChecksum;$/;" v file: +PACKET_STATE_INBODY network.h /^ PACKET_STATE_INBODY = 2,$/;" e enum:Packet_States_t +PACKET_STATE_INHEADER network.h /^ PACKET_STATE_INHEADER = 1,$/;" e enum:Packet_States_t +PACKET_STATE_NULL network.h /^ PACKET_STATE_NULL = 0,$/;" e enum:Packet_States_t +PacketLength network.c /^static uint16_t PacketLength = 0;$/;" v file: +PacketProtocol network.c /^static uint16_t PacketProtocol = 0;$/;" v file: +PacketState network.c /^static uint8_t PacketState = PACKET_STATE_NULL;$/;" v file: +Packet_States_t network.h /^ enum Packet_States_t$/;" g +RESERVED uipopt.h /^ uint8_t RESERVED;$/;" m struct:__anon7 +RESERVED uipopt.h /^ uint8_t RESERVED;$/;" m struct:__anon8 +SICSLOWPAN_CONF_COMPRESSION uipopt.h /^#define SICSLOWPAN_CONF_COMPRESSION /;" d +SICSLOWPAN_CONF_FRAG uipopt.h /^#define SICSLOWPAN_CONF_FRAG /;" d +SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS uipopt.h /^#define SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS /;" d +SICSLOWPAN_REASS_MAXAGE uipopt.h /^#define SICSLOWPAN_REASS_MAXAGE /;" d +SOURCES Makefile /^SOURCES=timer.c uip.c test.c $/;" m +TCP_ACK uip.c /^#define TCP_ACK /;" d file: +TCP_CTL uip.c /^#define TCP_CTL /;" d file: +TCP_FIN uip.c /^#define TCP_FIN /;" d file: +TCP_OPT_END uip.c /^#define TCP_OPT_END /;" d file: +TCP_OPT_MSS uip.c /^#define TCP_OPT_MSS /;" d file: +TCP_OPT_MSS_LEN uip.c /^#define TCP_OPT_MSS_LEN /;" d file: +TCP_OPT_NOOP uip.c /^#define TCP_OPT_NOOP /;" d file: +TCP_PSH uip.c /^#define TCP_PSH /;" d file: +TCP_RST uip.c /^#define TCP_RST /;" d file: +TCP_SYN uip.c /^#define TCP_SYN /;" d file: +TCP_URG uip.c /^#define TCP_URG /;" d file: +TwoBackChecksum network.c /^static uint16_t CurrentChecksum, OneBackChecksum, TwoBackChecksum;$/;" v file: +UDPBUF uip.c /^#define UDPBUF /;" d file: +UIP_802154_LONGADDR_LEN uip.h /^#define UIP_802154_LONGADDR_LEN /;" d +UIP_802154_SHORTADDR_LEN uip.h /^#define UIP_802154_SHORTADDR_LEN /;" d +UIP_ABORT uip.h /^#define UIP_ABORT /;" d +UIP_ACKDATA uip.h /^#define UIP_ACKDATA /;" d +UIP_ACTIVE_OPEN uipopt.h /^#define UIP_ACTIVE_OPEN /;" d +UIP_APPCALL uipopt.h /^#define UIP_APPCALL /;" d +UIP_APPDATA_PTR uip.h /^#define UIP_APPDATA_PTR /;" d +UIP_APPDATA_SIZE uip.h /^#define UIP_APPDATA_SIZE /;" d +UIP_ARPTAB_SIZE uipopt.h /^#define UIP_ARPTAB_SIZE /;" d +UIP_ARP_MAXAGE uipopt.h /^#define UIP_ARP_MAXAGE /;" d +UIP_BIG_ENDIAN uipopt.h /^#define UIP_BIG_ENDIAN /;" d +UIP_BROADCAST uipopt.h /^#define UIP_BROADCAST /;" d +UIP_BUFSIZE uipopt.h /^#define UIP_BUFSIZE /;" d +UIP_BYTE_ORDER uipopt.h /^#define UIP_BYTE_ORDER /;" d +UIP_CLOSE uip.h /^#define UIP_CLOSE /;" d +UIP_CLOSED uip.h /^#define UIP_CLOSED /;" d +UIP_CLOSING uip.h /^#define UIP_CLOSING /;" d +UIP_CONF_IPV6 uipopt.h /^#define UIP_CONF_IPV6 /;" d +UIP_CONF_IPV6_CHECKS uipopt.h /^#define UIP_CONF_IPV6_CHECKS /;" d +UIP_CONF_IPV6_QUEUE_PKT uipopt.h /^#define UIP_CONF_IPV6_QUEUE_PKT /;" d +UIP_CONF_IPV6_REASSEMBLY uipopt.h /^#define UIP_CONF_IPV6_REASSEMBLY /;" d +UIP_CONF_ND6_MAX_DEFROUTERS uipopt.h /^#define UIP_CONF_ND6_MAX_DEFROUTERS /;" d +UIP_CONF_ND6_MAX_NEIGHBORS uipopt.h /^#define UIP_CONF_ND6_MAX_NEIGHBORS /;" d +UIP_CONF_ND6_MAX_PREFIXES uipopt.h /^#define UIP_CONF_ND6_MAX_PREFIXES /;" d +UIP_CONF_NETIF_MAX_ADDRESSES uipopt.h /^#define UIP_CONF_NETIF_MAX_ADDRESSES /;" d +UIP_CONNECTED uip.h /^#define UIP_CONNECTED /;" d +UIP_CONNS uipopt.h /^#define UIP_CONNS /;" d +UIP_DATA uip.h /^#define UIP_DATA /;" d +UIP_DEFAULT_PREFIX_LEN uipopt.h /^#define UIP_DEFAULT_PREFIX_LEN /;" d +UIP_ESTABLISHED uip.h /^#define UIP_ESTABLISHED /;" d +UIP_EXT_HDR_BITMAP_AH uip.h /^#define UIP_EXT_HDR_BITMAP_AH /;" d +UIP_EXT_HDR_BITMAP_DESTO1 uip.h /^#define UIP_EXT_HDR_BITMAP_DESTO1 /;" d +UIP_EXT_HDR_BITMAP_DESTO2 uip.h /^#define UIP_EXT_HDR_BITMAP_DESTO2 /;" d +UIP_EXT_HDR_BITMAP_ESP uip.h /^#define UIP_EXT_HDR_BITMAP_ESP /;" d +UIP_EXT_HDR_BITMAP_FRAG uip.h /^#define UIP_EXT_HDR_BITMAP_FRAG /;" d +UIP_EXT_HDR_BITMAP_HBHO uip.h /^#define UIP_EXT_HDR_BITMAP_HBHO /;" d +UIP_EXT_HDR_BITMAP_ROUTING uip.h /^#define UIP_EXT_HDR_BITMAP_ROUTING /;" d +UIP_EXT_HDR_OPT_PAD1 uip.h /^#define UIP_EXT_HDR_OPT_PAD1 /;" d +UIP_EXT_HDR_OPT_PADN uip.h /^#define UIP_EXT_HDR_OPT_PADN /;" d +UIP_FIN_WAIT_1 uip.h /^#define UIP_FIN_WAIT_1 /;" d +UIP_FIN_WAIT_2 uip.h /^#define UIP_FIN_WAIT_2 /;" d +UIP_FIXEDADDR uipopt.h /^#define UIP_FIXEDADDR /;" d +UIP_FIXEDETHADDR uipopt.h /^#define UIP_FIXEDETHADDR /;" d +UIP_FRAGH_LEN uip.h /^#define UIP_FRAGH_LEN /;" d +UIP_HTONL uip.h /^# define UIP_HTONL(/;" d +UIP_HTONS uip.h /^# define UIP_HTONS(/;" d +UIP_ICMPH_LEN uip.h /^#define UIP_ICMPH_LEN /;" d +UIP_IPH_LEN uip.h /^#define UIP_IPH_LEN /;" d +UIP_IPICMPH_LEN uip.h /^#define UIP_IPICMPH_LEN /;" d +UIP_IPTCPH_LEN uip.h /^#define UIP_IPTCPH_LEN /;" d +UIP_IPUDPH_LEN uip.h /^#define UIP_IPUDPH_LEN /;" d +UIP_LAST_ACK uip.h /^#define UIP_LAST_ACK /;" d +UIP_LINK_MTU uipopt.h /^#define UIP_LINK_MTU /;" d +UIP_LISTENPORTS uipopt.h /^#define UIP_LISTENPORTS /;" d +UIP_LITTLE_ENDIAN uipopt.h /^#define UIP_LITTLE_ENDIAN /;" d +UIP_LLADDR_LEN uip.h /^#define UIP_LLADDR_LEN /;" d +UIP_LLH_LEN uipopt.h /^#define UIP_LLH_LEN /;" d +UIP_LLIPH_LEN uip.h /^#define UIP_LLIPH_LEN /;" d +UIP_LLPREF_LEN uip.h /^#define UIP_LLPREF_LEN /;" d +UIP_LOG uip.c /^#define UIP_LOG(/;" d file: +UIP_LOGGING uipopt.h /^#define UIP_LOGGING /;" d +UIP_MAXRTX uipopt.h /^#define UIP_MAXRTX /;" d +UIP_MAXSYNRTX uipopt.h /^#define UIP_MAXSYNRTX /;" d +UIP_NEWDATA uip.h /^#define UIP_NEWDATA /;" d +UIP_PINGADDRCONF uipopt.h /^#define UIP_PINGADDRCONF /;" d +UIP_POLL uip.h /^#define UIP_POLL /;" d +UIP_POLL_REQUEST uip.h /^#define UIP_POLL_REQUEST /;" d +UIP_PROTO_DESTO uip.h /^#define UIP_PROTO_DESTO /;" d +UIP_PROTO_FRAG uip.h /^#define UIP_PROTO_FRAG /;" d +UIP_PROTO_HBHO uip.h /^#define UIP_PROTO_HBHO /;" d +UIP_PROTO_ICMP uip.h /^#define UIP_PROTO_ICMP /;" d +UIP_PROTO_ICMP6 uip.h /^#define UIP_PROTO_ICMP6 /;" d +UIP_PROTO_NONE uip.h /^#define UIP_PROTO_NONE /;" d +UIP_PROTO_ROUTING uip.h /^#define UIP_PROTO_ROUTING /;" d +UIP_PROTO_TCP uip.h /^#define UIP_PROTO_TCP /;" d +UIP_PROTO_UDP uip.h /^#define UIP_PROTO_UDP /;" d +UIP_REASSEMBLY uipopt.h /^#define UIP_REASSEMBLY /;" d +UIP_REASS_BUFSIZE uip.c /^#define UIP_REASS_BUFSIZE /;" d file: +UIP_REASS_FLAG_LASTFRAG uip.c /^#define UIP_REASS_FLAG_LASTFRAG /;" d file: +UIP_REASS_MAXAGE uipopt.h /^#define UIP_REASS_MAXAGE /;" d +UIP_RECEIVE_WINDOW uipopt.h /^#define UIP_RECEIVE_WINDOW /;" d +UIP_REXMIT uip.h /^#define UIP_REXMIT /;" d +UIP_RTO uipopt.h /^#define UIP_RTO /;" d +UIP_STAT uip.c /^#define UIP_STAT(/;" d file: +UIP_STAT uip.h /^#define UIP_STAT(/;" d +UIP_STATISTICS uipopt.h /^#define UIP_STATISTICS /;" d +UIP_STOPPED uip.h /^#define UIP_STOPPED /;" d +UIP_SYN_RCVD uip.h /^#define UIP_SYN_RCVD /;" d +UIP_SYN_SENT uip.h /^#define UIP_SYN_SENT /;" d +UIP_TCP uipopt.h /^#define UIP_TCP /;" d +UIP_TCPH_LEN uip.h /^#define UIP_TCPH_LEN /;" d +UIP_TCPIP_HLEN uip.h /^#define UIP_TCPIP_HLEN /;" d +UIP_TCP_MSS uipopt.h /^#define UIP_TCP_MSS /;" d +UIP_TIMEDOUT uip.h /^#define UIP_TIMEDOUT /;" d +UIP_TIMER uip.h /^#define UIP_TIMER /;" d +UIP_TIME_WAIT uip.h /^#define UIP_TIME_WAIT /;" d +UIP_TIME_WAIT_TIMEOUT uipopt.h /^#define UIP_TIME_WAIT_TIMEOUT /;" d +UIP_TS_MASK uip.h /^#define UIP_TS_MASK /;" d +UIP_TTL uipopt.h /^#define UIP_TTL /;" d +UIP_UDP uipopt.h /^#define UIP_UDP /;" d +UIP_UDPH_LEN uip.h /^#define UIP_UDPH_LEN /;" d +UIP_UDP_CHECKSUMS uipopt.h /^#define UIP_UDP_CHECKSUMS /;" d +UIP_UDP_CONNS uipopt.h /^#define UIP_UDP_CONNS /;" d +UIP_UDP_SEND_CONN uip.h /^#define UIP_UDP_SEND_CONN /;" d +UIP_UDP_TIMER uip.h /^#define UIP_UDP_TIMER /;" d +UIP_URGDATA uipopt.h /^#define UIP_URGDATA /;" d +__CLOCK_ARCH_H__ clock.h /^#define __CLOCK_ARCH_H__$/;" d +__NETWORK_H__ network.h /^#define __NETWORK_H__$/;" d +__TIMER_H__ timer.h /^#define __TIMER_H__$/;" d +__UIPOPT_H__ uipopt.h /^#define __UIPOPT_H__$/;" d +__UIP_H__ uip.h /^#define __UIP_H__$/;" d +ackerr uip.h /^ uip_stats_t ackerr; \/**< Number of TCP segments with a bad ACK$/;" m struct:uip_stats::__anon4 +ackno uip.h /^ ackno[4],$/;" m struct:uip_tcpip_hdr +ackno uip.h /^ u8_t ackno[4];$/;" m struct:uip_tcp_hdr +addr uip.h /^ u8_t addr[2];$/;" m struct:uip_802154_shortaddr +addr uip.h /^ u8_t addr[6];$/;" m struct:uip_80211_addr +addr uip.h /^ u8_t addr[6];$/;" m struct:uip_eth_addr +addr uip.h /^ u8_t addr[8];$/;" m struct:uip_802154_longaddr +appstate uip.h /^ uip_icmp6_appstate_t appstate;$/;" m struct:uip_icmp6_conn +appstate uip.h /^ uip_tcp_appstate_t appstate;$/;" m struct:uip_conn +appstate uip.h /^ uip_udp_appstate_t appstate;$/;" m struct:uip_udp_conn +bitmap_bits uip.c /^static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,$/;" v file: +c uip.c /^static u8_t c, opt;$/;" v file: +chkerr uip.h /^ uip_stats_t chkerr; \/**< Number of ICMP packets with a bad$/;" m struct:uip_stats::__anon3 +chkerr uip.h /^ uip_stats_t chkerr; \/**< Number of TCP segments with a bad$/;" m struct:uip_stats::__anon4 +chkerr uip.h /^ uip_stats_t chkerr; \/**< Number of UDP segments with a bad$/;" m struct:uip_stats::__anon5 +chkerr uip.h /^ uip_stats_t chkerr; \/**< Number of packets dropped due to IP$/;" m struct:uip_stats::__anon2 +chksum uip.c /^chksum(u16_t sum, const u8_t *data, u16_t len)$/;" f file: +clock_datetime clock.c /^volatile clock_time_t clock_datetime = 0;$/;" v +clock_init clock.c /^void clock_init()$/;" f +clock_time clock.c /^clock_time_t clock_time()$/;" f +clock_time_t clock.h /^typedef uint16_t clock_time_t;$/;" t +destipaddr uip.h /^ uip_ip6addr_t srcipaddr, destipaddr;$/;" m struct:uip_icmpip_hdr +destipaddr uip.h /^ uip_ip6addr_t srcipaddr, destipaddr;$/;" m struct:uip_ip_hdr +destipaddr uip.h /^ uip_ip6addr_t srcipaddr, destipaddr;$/;" m struct:uip_tcpip_hdr +destipaddr uip.h /^ uip_ip6addr_t srcipaddr, destipaddr;$/;" m struct:uip_udpip_hdr +destport uip.h /^ destport;$/;" m struct:uip_tcpip_hdr +destport uip.h /^ destport;$/;" m struct:uip_udpip_hdr +destport uip.h /^ u16_t destport;$/;" m struct:uip_tcp_hdr +destport uip.h /^ u16_t destport;$/;" m struct:uip_udp_hdr +drop uip.h /^ uip_stats_t drop; \/**< Number of dropped ICMP packets. *\/$/;" m struct:uip_stats::__anon3 +drop uip.h /^ uip_stats_t drop; \/**< Number of dropped ND6 packets. *\/$/;" m struct:uip_stats::__anon6 +drop uip.h /^ uip_stats_t drop; \/**< Number of dropped TCP segments. *\/$/;" m struct:uip_stats::__anon4 +drop uip.h /^ uip_stats_t drop; \/**< Number of dropped UDP segments. *\/$/;" m struct:uip_stats::__anon5 +drop uip.h /^ uip_stats_t drop; \/**< Number of dropped packets at the IP$/;" m struct:uip_stats::__anon2 +flags uip.h /^ flags,$/;" m struct:uip_tcpip_hdr +flags uip.h /^ u8_t flags;$/;" m struct:uip_tcp_hdr +flow uip.h /^ u16_t flow;$/;" m struct:uip_icmpip_hdr +flow uip.h /^ u16_t flow;$/;" m struct:uip_ip_hdr +flow uip.h /^ u16_t flow;$/;" m struct:uip_tcpip_hdr +flow uip.h /^ u16_t flow;$/;" m struct:uip_udpip_hdr +forwarded uip.h /^ uip_stats_t forwarded;\/**< Number of forwarded packets at the IP $/;" m struct:uip_stats::__anon2 +fragerr uip.h /^ uip_stats_t fragerr; \/**< Number of packets dropped since they$/;" m struct:uip_stats::__anon2 +hblenerr uip.h /^ uip_stats_t hblenerr; \/**< Number of packets dropped due to wrong$/;" m struct:uip_stats::__anon2 +icmp uip.h /^ } icmp; \/**< ICMP statistics. *\/$/;" m struct:uip_stats typeref:struct:uip_stats::__anon3 +icmpchksum uip.h /^ u16_t icmpchksum;$/;" m struct:uip_icmp_hdr +icmpchksum uip.h /^ u16_t icmpchksum;$/;" m struct:uip_icmpip_hdr +icode uip.h /^ u8_t type, icode;$/;" m struct:uip_icmp_hdr +icode uip.h /^ u8_t type, icode;$/;" m struct:uip_icmpip_hdr +id uip.h /^ u16_t id, seqno;$/;" m struct:uip_icmp_hdr +id uip.h /^ u16_t id, seqno;$/;" m struct:uip_icmpip_hdr +id uip.h /^ u32_t id;$/;" m struct:uip_frag_hdr +init uip.h /^ void (*init)(void);$/;" m struct:uip_fallback_interface +initialmss uip.h /^ u16_t initialmss; \/**< Initial maximum segment size for the$/;" m struct:uip_conn +interval timer.h /^ clock_time_t interval;$/;" m struct:timer +ip uip.h /^ } ip; \/**< IP statistics. *\/$/;" m struct:uip_stats typeref:struct:uip_stats::__anon2 +ipid uip.c /^static u16_t ipid; \/* Ths ipid variable is an increasing$/;" v file: +iss uip.c /^static u8_t iss[4]; \/* The iss variable is used for the TCP$/;" v file: +lastport uip.c /^static u16_t lastport; \/* Keeps track of the last port used for$/;" v file: +lblenerr uip.h /^ uip_stats_t lblenerr; \/**< Number of packets dropped due to wrong$/;" m struct:uip_stats::__anon2 +len uip.h /^ u16_t len; \/**< Length of the data that was previously sent. *\/$/;" m struct:uip_conn +len uip.h /^ u8_t len;$/;" m struct:uip_desto_hdr +len uip.h /^ u8_t len;$/;" m struct:uip_ext_hdr +len uip.h /^ u8_t len;$/;" m struct:uip_ext_hdr_opt +len uip.h /^ u8_t len;$/;" m struct:uip_hbho_hdr +len uip.h /^ u8_t len;$/;" m struct:uip_routing_hdr +len uip.h /^ u8_t len[2];$/;" m struct:uip_icmpip_hdr +len uip.h /^ u8_t len[2];$/;" m struct:uip_ip_hdr +len uip.h /^ u8_t len[2];$/;" m struct:uip_tcpip_hdr +len uip.h /^ u8_t len[2];$/;" m struct:uip_udpip_hdr +lport uip.h /^ u16_t lport; \/**< The local TCP port, in network byte order. *\/$/;" m struct:uip_conn +lport uip.h /^ u16_t lport; \/**< The local port number in network byte order. *\/$/;" m struct:uip_udp_conn +main test.c /^int main(int argc, char ** argv)$/;" f +mss uip.h /^ u16_t mss; \/**< Current maximum segment size for the$/;" m struct:uip_conn +nd6 uip.h /^ } nd6;$/;" m struct:uip_stats typeref:struct:uip_stats::__anon6 +network_init network.c /^void network_init(void)$/;" f +network_read network.c /^uint16_t network_read(void)$/;" f +network_send network.c /^void network_send(uint16_t protocol)$/;" f +next uip.h /^ u8_t next;$/;" m struct:uip_desto_hdr +next uip.h /^ u8_t next;$/;" m struct:uip_ext_hdr +next uip.h /^ u8_t next;$/;" m struct:uip_frag_hdr +next uip.h /^ u8_t next;$/;" m struct:uip_hbho_hdr +next uip.h /^ u8_t next;$/;" m struct:uip_routing_hdr +nrtx uip.h /^ u8_t nrtx; \/**< The number of retransmissions for the last$/;" m struct:uip_conn +offsetresmore uip.h /^ u16_t offsetresmore;$/;" m struct:uip_frag_hdr +opt uip.c /^static u8_t c, opt;$/;" v file: +opt_len uip.h /^ u8_t opt_len;$/;" m struct:uip_ext_hdr_opt_padn +opt_type uip.h /^ u8_t opt_type;$/;" m struct:uip_ext_hdr_opt_padn +optdata uip.h /^ u8_t optdata[4];$/;" m struct:uip_tcp_hdr +optdata uip.h /^ u8_t optdata[4];$/;" m struct:uip_tcpip_hdr +output uip.h /^ void (*output)(void);$/;" m struct:uip_fallback_interface +payload uip.h /^ u8_t payload[1];$/;" m struct:uip_icmpip_hdr +proto uip.h /^ u8_t proto, ttl;$/;" m struct:uip_icmpip_hdr +proto uip.h /^ u8_t proto, ttl;$/;" m struct:uip_ip_hdr +proto uip.h /^ u8_t proto, ttl;$/;" m struct:uip_tcpip_hdr +proto uip.h /^ u8_t proto, ttl;$/;" m struct:uip_udpip_hdr +protoerr uip.h /^ uip_stats_t protoerr; \/**< Number of packets dropped since they$/;" m struct:uip_stats::__anon2 +rcv_nxt uip.h /^ u8_t rcv_nxt[4]; \/**< The sequence number that we expect to$/;" m struct:uip_conn +recv uip.h /^ uip_stats_t recv; \/**< Number of received ICMP packets. *\/$/;" m struct:uip_stats::__anon3 +recv uip.h /^ uip_stats_t recv; \/**< Number of received packets at the IP$/;" m struct:uip_stats::__anon2 +recv uip.h /^ uip_stats_t recv; \/**< Number of recived ND6 packets *\/$/;" m struct:uip_stats::__anon6 +recv uip.h /^ uip_stats_t recv; \/**< Number of recived TCP segments. *\/$/;" m struct:uip_stats::__anon4 +recv uip.h /^ uip_stats_t recv; \/**< Number of recived UDP segments. *\/$/;" m struct:uip_stats::__anon5 +res uip.h /^ u8_t res;$/;" m struct:uip_frag_hdr +rexmit uip.h /^ uip_stats_t rexmit; \/**< Number of retransmitted TCP segments. *\/$/;" m struct:uip_stats::__anon4 +ripaddr uip.h /^ uip_ipaddr_t ripaddr; \/**< The IP address of the remote host. *\/$/;" m struct:uip_conn +ripaddr uip.h /^ uip_ipaddr_t ripaddr; \/**< The IP address of the remote peer. *\/$/;" m struct:uip_udp_conn +routing_type uip.h /^ u8_t routing_type;$/;" m struct:uip_routing_hdr +rport uip.h /^ u16_t rport; \/**< The local remote TCP port, in network byte$/;" m struct:uip_conn +rport uip.h /^ u16_t rport; \/**< The remote port number in network byte order. *\/$/;" m struct:uip_udp_conn +rst uip.h /^ uip_stats_t rst; \/**< Number of recevied TCP RST (reset) segments. *\/$/;" m struct:uip_stats::__anon4 +rto uip.h /^ u8_t rto; \/**< Retransmission time-out. *\/$/;" m struct:uip_conn +sa uip.h /^ u8_t sa; \/**< Retransmission time-out calculation state$/;" m struct:uip_conn +seg_left uip.h /^ u8_t seg_left;$/;" m struct:uip_routing_hdr +sent uip.h /^ uip_stats_t sent; \/**< Number of sent ICMP packets. *\/$/;" m struct:uip_stats::__anon3 +sent uip.h /^ uip_stats_t sent; \/**< Number of sent ND6 packets *\/$/;" m struct:uip_stats::__anon6 +sent uip.h /^ uip_stats_t sent; \/**< Number of sent TCP segments. *\/$/;" m struct:uip_stats::__anon4 +sent uip.h /^ uip_stats_t sent; \/**< Number of sent UDP segments. *\/$/;" m struct:uip_stats::__anon5 +sent uip.h /^ uip_stats_t sent; \/**< Number of sent packets at the IP$/;" m struct:uip_stats::__anon2 +seqno uip.h /^ u16_t id, seqno;$/;" m struct:uip_icmp_hdr +seqno uip.h /^ u16_t id, seqno;$/;" m struct:uip_icmpip_hdr +seqno uip.h /^ u8_t seqno[4],$/;" m struct:uip_tcpip_hdr +seqno uip.h /^ u8_t seqno[4];$/;" m struct:uip_tcp_hdr +snd_nxt uip.h /^ u8_t snd_nxt[4]; \/**< The sequence number that was last sent by$/;" m struct:uip_conn +srcipaddr uip.h /^ uip_ip6addr_t srcipaddr, destipaddr;$/;" m struct:uip_icmpip_hdr +srcipaddr uip.h /^ uip_ip6addr_t srcipaddr, destipaddr;$/;" m struct:uip_ip_hdr +srcipaddr uip.h /^ uip_ip6addr_t srcipaddr, destipaddr;$/;" m struct:uip_tcpip_hdr +srcipaddr uip.h /^ uip_ip6addr_t srcipaddr, destipaddr;$/;" m struct:uip_udpip_hdr +srcport uip.h /^ u16_t srcport,$/;" m struct:uip_tcpip_hdr +srcport uip.h /^ u16_t srcport,$/;" m struct:uip_udpip_hdr +srcport uip.h /^ u16_t srcport;$/;" m struct:uip_tcp_hdr +srcport uip.h /^ u16_t srcport;$/;" m struct:uip_udp_hdr +start timer.h /^ clock_time_t start;$/;" m struct:timer +sv uip.h /^ u8_t sv; \/**< Retransmission time-out calculation state$/;" m struct:uip_conn +syndrop uip.h /^ uip_stats_t syndrop; \/**< Number of dropped SYNs due to too few$/;" m struct:uip_stats::__anon4 +synrst uip.h /^ uip_stats_t synrst; \/**< Number of SYNs for closed ports,$/;" m struct:uip_stats::__anon4 +tcf uip.h /^ tcf;$/;" m struct:uip_icmpip_hdr +tcf uip.h /^ tcf;$/;" m struct:uip_udpip_hdr +tcflow uip.h /^ tcflow;$/;" m struct:uip_tcpip_hdr +tcflow uip.h /^ u8_t tcflow;$/;" m struct:uip_ip_hdr +tcp uip.h /^ } tcp; \/**< TCP statistics. *\/$/;" m struct:uip_stats typeref:struct:uip_stats::__anon4 +tcpchksum uip.h /^ u16_t tcpchksum;$/;" m struct:uip_tcp_hdr +tcpchksum uip.h /^ u16_t tcpchksum;$/;" m struct:uip_tcpip_hdr +tcpoffset uip.h /^ tcpoffset,$/;" m struct:uip_tcpip_hdr +tcpoffset uip.h /^ u8_t tcpoffset;$/;" m struct:uip_tcp_hdr +tcpstateflags uip.h /^ u8_t tcpstateflags; \/**< TCP state and flags. *\/$/;" m struct:uip_conn +timer timer.h /^struct timer {$/;" s +timer uip.h /^ u8_t timer; \/**< The retransmission timer. *\/$/;" m struct:uip_conn +timer_expired timer.c /^timer_expired(struct timer *t)$/;" f +timer_reset timer.c /^timer_reset(struct timer *t)$/;" f +timer_restart timer.c /^timer_restart(struct timer *t)$/;" f +timer_set timer.c /^timer_set(struct timer *t, clock_time_t interval)$/;" f +tmp16 uip.c /^static u16_t tmp16;$/;" v file: +ttl uip.h /^ u8_t ttl; \/**< Default time-to-live. *\/$/;" m struct:uip_udp_conn +ttl uip.h /^ u8_t proto, ttl;$/;" m struct:uip_icmpip_hdr +ttl uip.h /^ u8_t proto, ttl;$/;" m struct:uip_ip_hdr +ttl uip.h /^ u8_t proto, ttl;$/;" m struct:uip_tcpip_hdr +ttl uip.h /^ u8_t proto, ttl;$/;" m struct:uip_udpip_hdr +type uip.h /^ u8_t type, icode;$/;" m struct:uip_icmp_hdr +type uip.h /^ u8_t type, icode;$/;" m struct:uip_icmpip_hdr +type uip.h /^ u8_t type;$/;" m struct:uip_ext_hdr_opt +typeerr uip.h /^ uip_stats_t typeerr; \/**< Number of ICMP packets with a wrong$/;" m struct:uip_stats::__anon3 +u16 uip.h /^ u16_t u16[2];$/;" m union:uip_ip4addr_t +u16 uip.h /^ u16_t u16[8];$/;" m union:uip_ip6addr_t +u16_t uipopt.h /^typedef uint16_t u16_t;$/;" t +u32 uip.h /^ uint32_t u32[(UIP_BUFSIZE + 3) \/ 4];$/;" m union:__anon1 +u32_t uipopt.h /^typedef uint32_t u32_t;$/;" t +u8 uip.h /^ u8_t u8[16]; \/* Initializer, must come first!!! *\/$/;" m union:uip_ip6addr_t +u8 uip.h /^ u8_t u8[4]; \/* Initializer, must come first!!! *\/$/;" m union:uip_ip4addr_t +u8 uip.h /^ uint8_t u8[UIP_BUFSIZE];$/;" m union:__anon1 +u8_t uipopt.h /^typedef uint8_t u8_t;$/;" t +udp uip.h /^ } udp; \/**< UDP statistics. *\/$/;" m struct:uip_stats typeref:struct:uip_stats::__anon5 +udpchksum uip.h /^ u16_t udpchksum;$/;" m struct:uip_udp_hdr +udpchksum uip.h /^ u16_t udpchksum;$/;" m struct:uip_udpip_hdr +udplen uip.h /^ u16_t udplen;$/;" m struct:uip_udp_hdr +udplen uip.h /^ u16_t udplen;$/;" m struct:uip_udpip_hdr +uip_80211_addr uip.h /^typedef struct uip_80211_addr {$/;" s +uip_80211_addr uip.h /^} uip_80211_addr;$/;" t typeref:struct:uip_80211_addr +uip_802154_longaddr uip.h /^typedef struct uip_802154_longaddr {$/;" s +uip_802154_longaddr uip.h /^} uip_802154_longaddr;$/;" t typeref:struct:uip_802154_longaddr +uip_802154_shortaddr uip.h /^typedef struct uip_802154_shortaddr {$/;" s +uip_802154_shortaddr uip.h /^} uip_802154_shortaddr;$/;" t typeref:struct:uip_802154_shortaddr +uip_abort uip.h /^#define uip_abort(/;" d +uip_aborted uip.h /^#define uip_aborted(/;" d +uip_acc32 uip.c /^u8_t uip_acc32[4];$/;" v +uip_acked uip.h /^#define uip_acked(/;" d +uip_add32 uip.c /^uip_add32(u8_t *op32, u16_t op16)$/;" f +uip_add_rcv_nxt uip.c /^uip_add_rcv_nxt(u16_t n)$/;" f file: +uip_aligned_buf uip.c /^uip_buf_t uip_aligned_buf;$/;" v +uip_all_zeroes_addr uip.c /^const uip_ipaddr_t uip_all_zeroes_addr = { { 0x0, \/* rest is 0 *\/ } };$/;" v +uip_appdata uip.c /^void *uip_appdata; \/* The uip_appdata pointer points to$/;" v +uip_are_solicited_bytes_equal uip.h /^#define uip_are_solicited_bytes_equal(/;" d +uip_broadcast_addr uip.c /^const uip_ipaddr_t uip_broadcast_addr =$/;" v +uip_buf uip.h /^#define uip_buf /;" d +uip_buf_t uip.h /^} uip_buf_t;$/;" t typeref:union:__anon1 +uip_chksum uip.c /^uip_chksum(u16_t *data, u16_t len)$/;" f +uip_close uip.h /^#define uip_close(/;" d +uip_closed uip.h /^#define uip_closed(/;" d +uip_conn uip.c /^struct uip_conn *uip_conn; \/* uip_conn always points to the current$/;" v typeref:struct:uip_conn +uip_conn uip.h /^struct uip_conn {$/;" s +uip_conn_active uip.h /^#define uip_conn_active(/;" d +uip_connect uip.c /^uip_connect(uip_ipaddr_t *ripaddr, u16_t rport)$/;" f +uip_connected uip.h /^#define uip_connected(/;" d +uip_conns uip.c /^struct uip_conn uip_conns[UIP_CONNS];$/;" v typeref:struct:uip_conn +uip_create_linklocal_allnodes_mcast uip.h /^#define uip_create_linklocal_allnodes_mcast(/;" d +uip_create_linklocal_allrouters_mcast uip.h /^#define uip_create_linklocal_allrouters_mcast(/;" d +uip_create_linklocal_prefix uip.h /^#define uip_create_linklocal_prefix(/;" d +uip_create_solicited_node uip.h /^#define uip_create_solicited_node(/;" d +uip_create_unspecified uip.h /^#define uip_create_unspecified(/;" d +uip_datalen uip.h /^#define uip_datalen(/;" d +uip_desto_hdr uip.h /^typedef struct uip_desto_hdr {$/;" s +uip_desto_hdr uip.h /^} uip_desto_hdr;$/;" t typeref:struct:uip_desto_hdr +uip_draddr uip.c /^const uip_ipaddr_t uip_draddr =$/;" v +uip_draddr uip.c /^uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;$/;" v +uip_eth_addr uip.h /^typedef struct uip_eth_addr {$/;" s +uip_eth_addr uip.h /^} uip_eth_addr;$/;" t typeref:struct:uip_eth_addr +uip_ethaddr uip.c /^const struct uip_eth_addr uip_ethaddr = {{UIP_ETHADDR0,$/;" v typeref:struct:uip_eth_addr +uip_ethaddr uip.c /^struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}};$/;" v typeref:struct:uip_eth_addr +uip_ext_hdr uip.h /^typedef struct uip_ext_hdr {$/;" s +uip_ext_hdr uip.h /^} uip_ext_hdr;$/;" t typeref:struct:uip_ext_hdr +uip_ext_hdr_opt uip.h /^typedef struct uip_ext_hdr_opt {$/;" s +uip_ext_hdr_opt uip.h /^} uip_ext_hdr_opt;$/;" t typeref:struct:uip_ext_hdr_opt +uip_ext_hdr_opt_padn uip.h /^typedef struct uip_ext_hdr_opt_padn {$/;" s +uip_ext_hdr_opt_padn uip.h /^} uip_ext_hdr_opt_padn;$/;" t typeref:struct:uip_ext_hdr_opt_padn +uip_fallback_interface uip.h /^struct uip_fallback_interface {$/;" s +uip_flags uip.c /^u8_t uip_flags; \/* The uip_flags variable is used for$/;" v +uip_frag_hdr uip.h /^typedef struct uip_frag_hdr {$/;" s +uip_frag_hdr uip.h /^} uip_frag_hdr;$/;" t typeref:struct:uip_frag_hdr +uip_getdraddr uip.h /^#define uip_getdraddr(/;" d +uip_gethostaddr uip.h /^#define uip_gethostaddr(/;" d +uip_getnetmask uip.h /^#define uip_getnetmask(/;" d +uip_hbho_hdr uip.h /^typedef struct uip_hbho_hdr {$/;" s +uip_hbho_hdr uip.h /^} uip_hbho_hdr;$/;" t typeref:struct:uip_hbho_hdr +uip_hostaddr uip.c /^const uip_ipaddr_t uip_hostaddr =$/;" v +uip_hostaddr uip.c /^uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;$/;" v +uip_htonl uip.c /^uip_htonl(u32_t val)$/;" f +uip_htons uip.c /^uip_htons(u16_t val)$/;" f +uip_icmp6_conn uip.h /^struct uip_icmp6_conn {$/;" s +uip_icmp6chksum uip.c /^uip_icmp6chksum(void)$/;" f +uip_icmp_hdr uip.h /^struct uip_icmp_hdr {$/;" s +uip_icmpip_hdr uip.h /^struct uip_icmpip_hdr {$/;" s +uip_init uip.c /^uip_init(void)$/;" f +uip_initialmss uip.h /^#define uip_initialmss(/;" d +uip_input uip.h /^#define uip_input(/;" d +uip_ip4addr_t uip.h /^typedef union uip_ip4addr_t {$/;" u +uip_ip4addr_t uip.h /^} uip_ip4addr_t;$/;" t typeref:union:uip_ip4addr_t +uip_ip6addr uip.h /^#define uip_ip6addr(/;" d +uip_ip6addr_t uip.h /^typedef union uip_ip6addr_t {$/;" u +uip_ip6addr_t uip.h /^} uip_ip6addr_t;$/;" t typeref:union:uip_ip6addr_t +uip_ip6addr_u8 uip.h /^#define uip_ip6addr_u8(/;" d +uip_ip_hdr uip.h /^struct uip_ip_hdr {$/;" s +uip_ipaddr uip.h /^#define uip_ipaddr(/;" d +uip_ipaddr1 uip.h /^#define uip_ipaddr1(/;" d +uip_ipaddr2 uip.h /^#define uip_ipaddr2(/;" d +uip_ipaddr3 uip.h /^#define uip_ipaddr3(/;" d +uip_ipaddr4 uip.h /^#define uip_ipaddr4(/;" d +uip_ipaddr_cmp uip.h /^#define uip_ipaddr_cmp(/;" d +uip_ipaddr_copy uip.h /^#define uip_ipaddr_copy(/;" d +uip_ipaddr_mask uip.h /^#define uip_ipaddr_mask(/;" d +uip_ipaddr_maskcmp uip.h /^#define uip_ipaddr_maskcmp(/;" d +uip_ipaddr_prefixcmp uip.h /^#define uip_ipaddr_prefixcmp(/;" d +uip_ipaddr_t uip.h /^typedef uip_ip4addr_t uip_ipaddr_t;$/;" t +uip_ipaddr_t uip.h /^typedef uip_ip6addr_t uip_ipaddr_t;$/;" t +uip_ipaddr_to_quad uip.h /^#define uip_ipaddr_to_quad(/;" d +uip_ipchksum uip.c /^uip_ipchksum(void)$/;" f +uip_is_addr_link_local uip.h /^#define uip_is_addr_link_local(/;" d +uip_is_addr_linklocal uip.h /^#define uip_is_addr_linklocal(/;" d +uip_is_addr_linklocal_allnodes_mcast uip.h /^#define uip_is_addr_linklocal_allnodes_mcast(/;" d +uip_is_addr_linklocal_allrouters_mcast uip.h /^#define uip_is_addr_linklocal_allrouters_mcast(/;" d +uip_is_addr_loopback uip.h /^#define uip_is_addr_loopback(/;" d +uip_is_addr_mac_addr_based uip.h /^#define uip_is_addr_mac_addr_based(/;" d +uip_is_addr_mcast uip.h /^#define uip_is_addr_mcast(/;" d +uip_is_addr_solicited_node uip.h /^#define uip_is_addr_solicited_node(/;" d +uip_is_addr_unspecified uip.h /^#define uip_is_addr_unspecified(/;" d +uip_is_mcast_group_id_all_nodes uip.h /^#define uip_is_mcast_group_id_all_nodes(/;" d +uip_is_mcast_group_id_all_routers uip.h /^#define uip_is_mcast_group_id_all_routers(/;" d +uip_l2_l3_hdr_len uip.h /^#define uip_l2_l3_hdr_len /;" d +uip_l2_l3_icmp_hdr_len uip.h /^#define uip_l2_l3_icmp_hdr_len /;" d +uip_l3_hdr_len uip.h /^#define uip_l3_hdr_len /;" d +uip_l3_icmp_hdr_len uip.h /^#define uip_l3_icmp_hdr_len /;" d +uip_len uip.c /^u16_t uip_len, uip_slen;$/;" v +uip_listen uip.c /^uip_listen(u16_t port)$/;" f +uip_listenports uip.c /^u16_t uip_listenports[UIP_LISTENPORTS];$/;" v +uip_lladdr_t uip.h /^typedef uip_80211_addr uip_lladdr_t;$/;" t +uip_lladdr_t uip.h /^typedef uip_802154_longaddr uip_lladdr_t;$/;" t +uip_lladdr_t uip.h /^typedef uip_eth_addr uip_lladdr_t;$/;" t +uip_mss uip.h /^#define uip_mss(/;" d +uip_netmask uip.c /^const uip_ipaddr_t uip_netmask =$/;" v +uip_netmask uip.c /^uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;$/;" v +uip_newdata uip.h /^#define uip_newdata(/;" d +uip_ntohl uip.h /^#define uip_ntohl /;" d +uip_ntohs uip.h /^#define uip_ntohs /;" d +uip_outstanding uip.h /^#define uip_outstanding(/;" d +uip_periodic uip.h /^#define uip_periodic(/;" d +uip_periodic_conn uip.h /^#define uip_periodic_conn(/;" d +uip_poll uip.h /^#define uip_poll(/;" d +uip_poll_conn uip.h /^#define uip_poll_conn(/;" d +uip_process uip.c /^uip_process(u8_t flag)$/;" f +uip_reass uip.c /^uip_reass(void)$/;" f file: +uip_reassbitmap uip.c /^static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE \/ (8 * 8)];$/;" v file: +uip_reassbuf uip.c /^static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];$/;" v file: +uip_reassflags uip.c /^static u8_t uip_reassflags;$/;" v file: +uip_reasslen uip.c /^static u16_t uip_reasslen;$/;" v file: +uip_reasstmr uip.c /^static u8_t uip_reasstmr;$/;" v file: +uip_restart uip.h /^#define uip_restart(/;" d +uip_rexmit uip.h /^#define uip_rexmit(/;" d +uip_routing_hdr uip.h /^typedef struct uip_routing_hdr {$/;" s +uip_routing_hdr uip.h /^} uip_routing_hdr;$/;" t typeref:struct:uip_routing_hdr +uip_sappdata uip.c /^void *uip_sappdata; \/* The uip_appdata pointer points to$/;" v +uip_send uip.c /^uip_send(const void *data, int len)$/;" f +uip_setdraddr uip.h /^#define uip_setdraddr(/;" d +uip_sethostaddr uip.h /^#define uip_sethostaddr(/;" d +uip_setipid uip.c /^void uip_setipid(u16_t id) { ipid = id; }$/;" f +uip_setnetmask uip.h /^#define uip_setnetmask(/;" d +uip_slen uip.c /^u16_t uip_len, uip_slen;$/;" v +uip_stat uip.c /^struct uip_stats uip_stat;$/;" v typeref:struct:uip_stats +uip_stats uip.h /^struct uip_stats {$/;" s +uip_stats_t uipopt.h /^typedef uint32_t uip_stats_t;$/;" t +uip_stop uip.h /^#define uip_stop(/;" d +uip_stopped uip.h /^#define uip_stopped(/;" d +uip_surglen uip.c /^u16_t uip_urglen, uip_surglen;$/;" v +uip_tcp_appstate_t uipopt.h /^} uip_tcp_appstate_t;$/;" t typeref:struct:__anon7 +uip_tcp_hdr uip.h /^struct uip_tcp_hdr {$/;" s +uip_tcpchksum uip.c /^uip_tcpchksum(void)$/;" f +uip_tcpip_hdr uip.h /^struct uip_tcpip_hdr {$/;" s +uip_timedout uip.h /^#define uip_timedout(/;" d +uip_udp_appstate_t uipopt.h /^} uip_udp_appstate_t;$/;" t typeref:struct:__anon8 +uip_udp_bind uip.h /^#define uip_udp_bind(/;" d +uip_udp_conn uip.c /^struct uip_udp_conn *uip_udp_conn;$/;" v typeref:struct:uip_udp_conn +uip_udp_conn uip.h /^struct uip_udp_conn {$/;" s +uip_udp_conns uip.c /^struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];$/;" v typeref:struct:uip_udp_conn +uip_udp_hdr uip.h /^struct uip_udp_hdr {$/;" s +uip_udp_new uip.c /^uip_udp_new(const uip_ipaddr_t *ripaddr, u16_t rport)$/;" f +uip_udp_periodic uip.h /^#define uip_udp_periodic(/;" d +uip_udp_periodic_conn uip.h /^#define uip_udp_periodic_conn(/;" d +uip_udp_remove uip.h /^#define uip_udp_remove(/;" d +uip_udp_send uip.h /^#define uip_udp_send(/;" d +uip_udpchksum uip.c /^uip_udpchksum(void)$/;" f +uip_udpconnection uip.h /^#define uip_udpconnection(/;" d +uip_udpip_hdr uip.h /^struct uip_udpip_hdr {$/;" s +uip_unlisten uip.c /^uip_unlisten(u16_t port)$/;" f +uip_urgdata uip.c /^void *uip_urgdata; \/* The uip_urgdata pointer points to$/;" v +uip_urgdatalen uip.h /^#define uip_urgdatalen(/;" d +uip_urglen uip.c /^u16_t uip_urglen, uip_surglen;$/;" v +upper_layer_chksum uip.c /^upper_layer_chksum(u8_t proto)$/;" f file: +urgp uip.h /^ u8_t urgp[2];$/;" m struct:uip_tcp_hdr +urgp uip.h /^ u8_t urgp[2];$/;" m struct:uip_tcpip_hdr +vhlerr uip.h /^ uip_stats_t vhlerr; \/**< Number of packets dropped due to wrong$/;" m struct:uip_stats::__anon2 +vtc uip.h /^ u8_t vtc,$/;" m struct:uip_icmpip_hdr +vtc uip.h /^ u8_t vtc,$/;" m struct:uip_tcpip_hdr +vtc uip.h /^ u8_t vtc,$/;" m struct:uip_udpip_hdr +vtc uip.h /^ u8_t vtc;$/;" m struct:uip_ip_hdr +wnd uip.h /^ wnd[2];$/;" m struct:uip_tcpip_hdr +wnd uip.h /^ u8_t wnd[2];$/;" m struct:uip_tcp_hdr diff -r 5c8404549cc0 -r 56d09a0969b5 network/test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/test.c Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,18 @@ +#include +#include "uip.h" +#include "clock.h" + +// clock.c +clock_time_t +clock_time(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + + return tv.tv_sec % 65536; +} + +int main(int argc, char ** argv) +{ + return 0; +} diff -r 5c8404549cc0 -r 56d09a0969b5 network/timer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/timer.c Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,127 @@ +/** + * \addtogroup timer + * @{ + */ + +/** + * \file + * Timer library implementation. + * \author + * Adam Dunkels + */ + +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: timer.c,v 1.2 2006/06/12 08:00:30 adam Exp $ + */ + +#include "clock.h" +#include "timer.h" + +/*---------------------------------------------------------------------------*/ +/** + * Set a timer. + * + * This function is used to set a timer for a time sometime in the + * future. The function timer_expired() will evaluate to true after + * the timer has expired. + * + * \param t A pointer to the timer + * \param interval The interval before the timer expires. + * + */ +void +timer_set(struct timer *t, clock_time_t interval) +{ + t->interval = interval; + t->start = clock_time(); +} +/*---------------------------------------------------------------------------*/ +/** + * Reset the timer with the same interval. + * + * This function resets the timer with the same interval that was + * given to the timer_set() function. The start point of the interval + * is the exact time that the timer last expired. Therefore, this + * function will cause the timer to be stable over time, unlike the + * timer_rester() function. + * + * \param t A pointer to the timer. + * + * \sa timer_restart() + */ +void +timer_reset(struct timer *t) +{ + t->start += t->interval; +} +/*---------------------------------------------------------------------------*/ +/** + * Restart the timer from the current point in time + * + * This function restarts a timer with the same interval that was + * given to the timer_set() function. The timer will start at the + * current time. + * + * \note A periodic timer will drift if this function is used to reset + * it. For preioric timers, use the timer_reset() function instead. + * + * \param t A pointer to the timer. + * + * \sa timer_reset() + */ +void +timer_restart(struct timer *t) +{ + t->start = clock_time(); +} +/*---------------------------------------------------------------------------*/ +/** + * Check if a timer has expired. + * + * This function tests if a timer has expired and returns true or + * false depending on its status. + * + * \param t A pointer to the timer + * + * \return Non-zero if the timer has expired, zero otherwise. + * + */ +int +timer_expired(struct timer *t) +{ + return (clock_time_t)(clock_time() - t->start) >= (clock_time_t)t->interval; +} +/*---------------------------------------------------------------------------*/ + +/** @} */ diff -r 5c8404549cc0 -r 56d09a0969b5 network/timer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/timer.h Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,86 @@ +/** + * \defgroup timer Timer library + * + * The timer library provides functions for setting, resetting and + * restarting timers, and for checking if a timer has expired. An + * application must "manually" check if its timers have expired; this + * is not done automatically. + * + * A timer is declared as a \c struct \c timer and all access to the + * timer is made by a pointer to the declared timer. + * + * \note The timer library uses the \ref clock "Clock library" to + * measure time. Intervals should be specified in the format used by + * the clock library. + * + * @{ + */ + + +/** + * \file + * Timer library header file. + * \author + * Adam Dunkels + */ + +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: timer.h,v 1.3 2006/06/11 21:46:39 adam Exp $ + */ +#ifndef __TIMER_H__ +#define __TIMER_H__ + +#include "clock.h" + +/** + * A timer. + * + * This structure is used for declaring a timer. The timer must be set + * with timer_set() before it can be used. + * + * \hideinitializer + */ +struct timer { + clock_time_t start; + clock_time_t interval; +}; + +void timer_set(struct timer *t, clock_time_t interval); +void timer_reset(struct timer *t); +void timer_restart(struct timer *t); +int timer_expired(struct timer *t); + +#endif /* __TIMER_H__ */ + +/** @} */ diff -r 5c8404549cc0 -r 56d09a0969b5 network/uip.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/uip.c Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,1969 @@ +#define DEBUG_PRINTF(...) /*printf(__VA_ARGS__)*/ + +/** + * \addtogroup uip + * @{ + */ + +/** + * \file + * The uIP TCP/IP stack code. + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip.c,v 1.30 2010/10/19 18:29:04 adamdunkels Exp $ + * + */ + +/* + * uIP is a small implementation of the IP, UDP and TCP protocols (as + * well as some basic ICMP stuff). The implementation couples the IP, + * UDP, TCP and the application layers very tightly. To keep the size + * of the compiled code down, this code frequently uses the goto + * statement. While it would be possible to break the uip_process() + * function into many smaller functions, this would increase the code + * size because of the overhead of parameter passing and the fact that + * the optimier would not be as efficient. + * + * The principle is that we have a small buffer, called the uip_buf, + * in which the device driver puts an incoming packet. The TCP/IP + * stack parses the headers in the packet, and calls the + * application. If the remote host has sent data to the application, + * this data is present in the uip_buf and the application read the + * data from there. It is up to the application to put this data into + * a byte stream if needed. The application will not be fed with data + * that is out of sequence. + * + * If the application whishes to send data to the peer, it should put + * its data into the uip_buf. The uip_appdata pointer points to the + * first available byte. The TCP/IP stack will calculate the + * checksums, and fill in the necessary header fields and finally send + * the packet back to the peer. +*/ + +#include "uip.h" +#include "uipopt.h" +//#include "net/uip_arp.h" +//#include "net/uip_arch.h" + +#if !UIP_CONF_IPV6 /* If UIP_CONF_IPV6 is defined, we compile the + uip6.c file instead of this one. Therefore + this #ifndef removes the entire compilation + output of the uip.c file */ + + +#if UIP_CONF_IPV6 +#include "net/uip-neighbor.h" +#endif /* UIP_CONF_IPV6 */ + +#include + +/*---------------------------------------------------------------------------*/ +/* Variable definitions. */ + + +/* The IP address of this host. If it is defined to be fixed (by + setting UIP_FIXEDADDR to 1 in uipopt.h), the address is set + here. Otherwise, the address */ +#if UIP_FIXEDADDR > 0 +const uip_ipaddr_t uip_hostaddr = + { UIP_IPADDR0, UIP_IPADDR1, UIP_IPADDR2, UIP_IPADDR3 }; +const uip_ipaddr_t uip_draddr = + { UIP_DRIPADDR0, UIP_DRIPADDR1, UIP_DRIPADDR2, UIP_DRIPADDR3 }; +const uip_ipaddr_t uip_netmask = + { UIP_NETMASK0, UIP_NETMASK1, UIP_NETMASK2, UIP_NETMASK3 }; +#else +uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask; +#endif /* UIP_FIXEDADDR */ + +const uip_ipaddr_t uip_broadcast_addr = +#if UIP_CONF_IPV6 + { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } }; +#else /* UIP_CONF_IPV6 */ + { { 0xff, 0xff, 0xff, 0xff } }; +#endif /* UIP_CONF_IPV6 */ +const uip_ipaddr_t uip_all_zeroes_addr = { { 0x0, /* rest is 0 */ } }; + +#if UIP_FIXEDETHADDR +const struct uip_eth_addr uip_ethaddr = {{UIP_ETHADDR0, + UIP_ETHADDR1, + UIP_ETHADDR2, + UIP_ETHADDR3, + UIP_ETHADDR4, + UIP_ETHADDR5}}; +#else +struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}}; +#endif + +/* The packet buffer that contains incoming packets. */ +uip_buf_t uip_aligned_buf; + +void *uip_appdata; /* The uip_appdata pointer points to + application data. */ +void *uip_sappdata; /* The uip_appdata pointer points to + the application data which is to + be sent. */ +#if UIP_URGDATA > 0 +void *uip_urgdata; /* The uip_urgdata pointer points to + urgent data (out-of-band data), if + present. */ +u16_t uip_urglen, uip_surglen; +#endif /* UIP_URGDATA > 0 */ + +u16_t uip_len, uip_slen; + /* The uip_len is either 8 or 16 bits, + depending on the maximum packet + size. */ + +u8_t uip_flags; /* The uip_flags variable is used for + communication between the TCP/IP stack + and the application program. */ +struct uip_conn *uip_conn; /* uip_conn always points to the current + connection. */ + +struct uip_conn uip_conns[UIP_CONNS]; + /* The uip_conns array holds all TCP + connections. */ +u16_t uip_listenports[UIP_LISTENPORTS]; + /* The uip_listenports list all currently + listning ports. */ +#if UIP_UDP +struct uip_udp_conn *uip_udp_conn; +struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; +#endif /* UIP_UDP */ + +static u16_t ipid; /* Ths ipid variable is an increasing + number that is used for the IP ID + field. */ + +void uip_setipid(u16_t id) { ipid = id; } + +static u8_t iss[4]; /* The iss variable is used for the TCP + initial sequence number. */ + +#if UIP_ACTIVE_OPEN || UIP_UDP +static u16_t lastport; /* Keeps track of the last port used for + a new connection. */ +#endif /* UIP_ACTIVE_OPEN || UIP_UDP */ + +/* 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 ICMP_DEST_UNREACHABLE 3 +#define ICMP_PORT_UNREACHABLE 3 + +#define ICMP6_ECHO_REPLY 129 +#define ICMP6_ECHO 128 +#define ICMP6_NEIGHBOR_SOLICITATION 135 +#define ICMP6_NEIGHBOR_ADVERTISEMENT 136 + +#define ICMP6_FLAG_S (1 << 6) + +#define ICMP6_OPTION_SOURCE_LINK_ADDRESS 1 +#define ICMP6_OPTION_TARGET_LINK_ADDRESS 2 + + +/* Macros. */ +#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define FBUF ((struct uip_tcpip_hdr *)&uip_reassbuf[0]) +#define ICMPBUF ((struct uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define UDPBUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN]) + + +#if UIP_STATISTICS == 1 +struct uip_stats uip_stat; +#define UIP_STAT(s) s +#else +#define UIP_STAT(s) +#endif /* UIP_STATISTICS == 1 */ + +#if UIP_LOGGING == 1 +#include +void uip_log(char *msg); +#define UIP_LOG(m) uip_log(m) +#else +#define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +#if ! UIP_ARCH_ADD32 +void +uip_add32(u8_t *op32, u16_t op16) +{ + uip_acc32[3] = op32[3] + (op16 & 0xff); + uip_acc32[2] = op32[2] + (op16 >> 8); + uip_acc32[1] = op32[1]; + uip_acc32[0] = op32[0]; + + if(uip_acc32[2] < (op16 >> 8)) { + ++uip_acc32[1]; + if(uip_acc32[1] == 0) { + ++uip_acc32[0]; + } + } + + + if(uip_acc32[3] < (op16 & 0xff)) { + ++uip_acc32[2]; + if(uip_acc32[2] == 0) { + ++uip_acc32[1]; + if(uip_acc32[1] == 0) { + ++uip_acc32[0]; + } + } + } +} + +#endif /* UIP_ARCH_ADD32 */ + +#if ! UIP_ARCH_CHKSUM +/*---------------------------------------------------------------------------*/ +static u16_t +chksum(u16_t sum, const u8_t *data, u16_t len) +{ + u16_t t; + const u8_t *dataptr; + const u8_t *last_byte; + + dataptr = data; + last_byte = data + len - 1; + + while(dataptr < last_byte) { /* At least two more bytes */ + t = (dataptr[0] << 8) + dataptr[1]; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + dataptr += 2; + } + + if(dataptr == last_byte) { + t = (dataptr[0] << 8) + 0; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + } + + /* Return sum in host byte order. */ + return sum; +} +/*---------------------------------------------------------------------------*/ +u16_t +uip_chksum(u16_t *data, u16_t len) +{ + return uip_htons(chksum(0, (u8_t *)data, len)); +} +/*---------------------------------------------------------------------------*/ +#ifndef UIP_ARCH_IPCHKSUM +u16_t +uip_ipchksum(void) +{ + u16_t sum; + + sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); + DEBUG_PRINTF("uip_ipchksum: sum 0x%04x\n", sum); + return (sum == 0) ? 0xffff : uip_htons(sum); +} +#endif +/*---------------------------------------------------------------------------*/ +static u16_t +upper_layer_chksum(u8_t proto) +{ + u16_t upper_layer_len; + u16_t sum; + +#if UIP_CONF_IPV6 + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]); +#else /* UIP_CONF_IPV6 */ + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN; +#endif /* UIP_CONF_IPV6 */ + + /* First sum pseudoheader. */ + + /* IP protocol and length fields. This addition cannot carry. */ + sum = upper_layer_len + proto; + /* Sum IP source and destination addresses. */ + sum = chksum(sum, (u8_t *)&BUF->srcipaddr, 2 * sizeof(uip_ipaddr_t)); + + /* Sum TCP header and data. */ + sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], + upper_layer_len); + + return (sum == 0) ? 0xffff : uip_htons(sum); +} +/*---------------------------------------------------------------------------*/ +#if UIP_CONF_IPV6 +u16_t +uip_icmp6chksum(void) +{ + return upper_layer_chksum(UIP_PROTO_ICMP6); + +} +#endif /* UIP_CONF_IPV6 */ +/*---------------------------------------------------------------------------*/ +u16_t +uip_tcpchksum(void) +{ + return upper_layer_chksum(UIP_PROTO_TCP); +} +/*---------------------------------------------------------------------------*/ +#if UIP_UDP_CHECKSUMS +u16_t +uip_udpchksum(void) +{ + return upper_layer_chksum(UIP_PROTO_UDP); +} +#endif /* UIP_UDP_CHECKSUMS */ +#endif /* UIP_ARCH_CHKSUM */ +/*---------------------------------------------------------------------------*/ +void +uip_init(void) +{ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + uip_listenports[c] = 0; + } + for(c = 0; c < UIP_CONNS; ++c) { + uip_conns[c].tcpstateflags = UIP_CLOSED; + } +#if UIP_ACTIVE_OPEN || UIP_UDP + lastport = 1024; +#endif /* UIP_ACTIVE_OPEN || UIP_UDP */ + +#if UIP_UDP + for(c = 0; c < UIP_UDP_CONNS; ++c) { + uip_udp_conns[c].lport = 0; + } +#endif /* UIP_UDP */ + + + /* IPv4 initialization. */ +#if UIP_FIXEDADDR == 0 + /* uip_hostaddr[0] = uip_hostaddr[1] = 0;*/ +#endif /* UIP_FIXEDADDR */ + +} +/*---------------------------------------------------------------------------*/ +#if UIP_ACTIVE_OPEN +struct uip_conn * +uip_connect(uip_ipaddr_t *ripaddr, u16_t rport) +{ + register struct uip_conn *conn, *cconn; + + /* Find an unused local port. */ + again: + ++lastport; + + if(lastport >= 32000) { + lastport = 4096; + } + + /* Check if this port is already in use, and if so try to find + another one. */ + for(c = 0; c < UIP_CONNS; ++c) { + conn = &uip_conns[c]; + if(conn->tcpstateflags != UIP_CLOSED && + conn->lport == uip_htons(lastport)) { + goto again; + } + } + + conn = 0; + for(c = 0; c < UIP_CONNS; ++c) { + cconn = &uip_conns[c]; + if(cconn->tcpstateflags == UIP_CLOSED) { + conn = cconn; + break; + } + if(cconn->tcpstateflags == UIP_TIME_WAIT) { + if(conn == 0 || + cconn->timer > conn->timer) { + conn = cconn; + } + } + } + + if(conn == 0) { + return 0; + } + + conn->tcpstateflags = UIP_SYN_SENT; + + conn->snd_nxt[0] = iss[0]; + conn->snd_nxt[1] = iss[1]; + conn->snd_nxt[2] = iss[2]; + conn->snd_nxt[3] = iss[3]; + + conn->initialmss = conn->mss = UIP_TCP_MSS; + + conn->len = 1; /* TCP length of the SYN is one. */ + conn->nrtx = 0; + conn->timer = 1; /* Send the SYN next time around. */ + conn->rto = UIP_RTO; + conn->sa = 0; + conn->sv = 16; /* Initial value of the RTT variance. */ + conn->lport = uip_htons(lastport); + conn->rport = rport; + uip_ipaddr_copy(&conn->ripaddr, ripaddr); + + return conn; +} +#endif /* UIP_ACTIVE_OPEN */ +/*---------------------------------------------------------------------------*/ +#if UIP_UDP +struct uip_udp_conn * +uip_udp_new(const uip_ipaddr_t *ripaddr, u16_t rport) +{ + register struct uip_udp_conn *conn; + + /* Find an unused local port. */ + again: + ++lastport; + + if(lastport >= 32000) { + lastport = 4096; + } + + for(c = 0; c < UIP_UDP_CONNS; ++c) { + if(uip_udp_conns[c].lport == uip_htons(lastport)) { + goto again; + } + } + + + conn = 0; + for(c = 0; c < UIP_UDP_CONNS; ++c) { + if(uip_udp_conns[c].lport == 0) { + conn = &uip_udp_conns[c]; + break; + } + } + + if(conn == 0) { + return 0; + } + + conn->lport = UIP_HTONS(lastport); + conn->rport = rport; + if(ripaddr == NULL) { + memset(&conn->ripaddr, 0, sizeof(uip_ipaddr_t)); + } else { + uip_ipaddr_copy(&conn->ripaddr, ripaddr); + } + conn->ttl = UIP_TTL; + + return conn; +} +#endif /* UIP_UDP */ +/*---------------------------------------------------------------------------*/ +void +uip_unlisten(u16_t port) +{ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + if(uip_listenports[c] == port) { + uip_listenports[c] = 0; + return; + } + } +} +/*---------------------------------------------------------------------------*/ +void +uip_listen(u16_t port) +{ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + if(uip_listenports[c] == 0) { + uip_listenports[c] = port; + return; + } + } +} +/*---------------------------------------------------------------------------*/ +/* XXX: IP fragment reassembly: not well-tested. */ + +#if UIP_REASSEMBLY && !UIP_CONF_IPV6 +#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN) +static u8_t uip_reassbuf[UIP_REASS_BUFSIZE]; +static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)]; +static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f, + 0x0f, 0x07, 0x03, 0x01}; +static u16_t uip_reasslen; +static u8_t uip_reassflags; +#define UIP_REASS_FLAG_LASTFRAG 0x01 +static u8_t uip_reasstmr; + +#define IP_MF 0x20 + +static u8_t +uip_reass(void) +{ + u16_t offset, len; + u16_t i; + + /* If ip_reasstmr is zero, no packet is present in the buffer, so we + write the IP header of the fragment into the reassembly + buffer. The timer is updated with the maximum age. */ + if(uip_reasstmr == 0) { + memcpy(uip_reassbuf, &BUF->vhl, UIP_IPH_LEN); + uip_reasstmr = UIP_REASS_MAXAGE; + uip_reassflags = 0; + /* Clear the bitmap. */ + memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap)); + } + + /* Check if the incoming fragment matches the one currently present + in the reasembly buffer. If so, we proceed with copying the + fragment into the buffer. */ + if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] && + BUF->srcipaddr[1] == FBUF->srcipaddr[1] && + BUF->destipaddr[0] == FBUF->destipaddr[0] && + BUF->destipaddr[1] == FBUF->destipaddr[1] && + BUF->ipid[0] == FBUF->ipid[0] && + BUF->ipid[1] == FBUF->ipid[1]) { + + len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4; + offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8; + + /* If the offset or the offset + fragment length overflows the + reassembly buffer, we discard the entire packet. */ + if(offset > UIP_REASS_BUFSIZE || + offset + len > UIP_REASS_BUFSIZE) { + uip_reasstmr = 0; + goto nullreturn; + } + + /* Copy the fragment into the reassembly buffer, at the right + offset. */ + memcpy(&uip_reassbuf[UIP_IPH_LEN + offset], + (char *)BUF + (int)((BUF->vhl & 0x0f) * 4), + len); + + /* Update the bitmap. */ + if(offset / (8 * 8) == (offset + len) / (8 * 8)) { + /* If the two endpoints are in the same byte, we only update + that byte. */ + + uip_reassbitmap[offset / (8 * 8)] |= + bitmap_bits[(offset / 8 ) & 7] & + ~bitmap_bits[((offset + len) / 8 ) & 7]; + } else { + /* If the two endpoints are in different bytes, we update the + bytes in the endpoints and fill the stuff inbetween with + 0xff. */ + uip_reassbitmap[offset / (8 * 8)] |= + bitmap_bits[(offset / 8 ) & 7]; + for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) { + uip_reassbitmap[i] = 0xff; + } + uip_reassbitmap[(offset + len) / (8 * 8)] |= + ~bitmap_bits[((offset + len) / 8 ) & 7]; + } + + /* If this fragment has the More Fragments flag set to zero, we + know that this is the last fragment, so we can calculate the + size of the entire packet. We also set the + IP_REASS_FLAG_LASTFRAG flag to indicate that we have received + the final fragment. */ + + if((BUF->ipoffset[0] & IP_MF) == 0) { + uip_reassflags |= UIP_REASS_FLAG_LASTFRAG; + uip_reasslen = offset + len; + } + + /* Finally, we check if we have a full packet in the buffer. We do + this by checking if we have the last fragment and if all bits + in the bitmap are set. */ + if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) { + /* Check all bytes up to and including all but the last byte in + the bitmap. */ + for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) { + if(uip_reassbitmap[i] != 0xff) { + goto nullreturn; + } + } + /* Check the last byte in the bitmap. It should contain just the + right amount of bits. */ + if(uip_reassbitmap[uip_reasslen / (8 * 8)] != + (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) { + goto nullreturn; + } + + /* If we have come this far, we have a full packet in the + buffer, so we allocate a pbuf and copy the packet into it. We + also reset the timer. */ + uip_reasstmr = 0; + memcpy(BUF, FBUF, uip_reasslen); + + /* Pretend to be a "normal" (i.e., not fragmented) IP packet + from now on. */ + BUF->ipoffset[0] = BUF->ipoffset[1] = 0; + BUF->len[0] = uip_reasslen >> 8; + BUF->len[1] = uip_reasslen & 0xff; + BUF->ipchksum = 0; + BUF->ipchksum = ~(uip_ipchksum()); + + return uip_reasslen; + } + } + + nullreturn: + return 0; +} +#endif /* UIP_REASSEMBLY */ +/*---------------------------------------------------------------------------*/ +static void +uip_add_rcv_nxt(u16_t n) +{ + uip_add32(uip_conn->rcv_nxt, n); + uip_conn->rcv_nxt[0] = uip_acc32[0]; + uip_conn->rcv_nxt[1] = uip_acc32[1]; + uip_conn->rcv_nxt[2] = uip_acc32[2]; + uip_conn->rcv_nxt[3] = uip_acc32[3]; +} +/*---------------------------------------------------------------------------*/ +void +uip_process(u8_t flag) +{ + register struct uip_conn *uip_connr = uip_conn; + +#if UIP_UDP + if(flag == UIP_UDP_SEND_CONN) { + goto udp_send; + } +#endif /* UIP_UDP */ + + uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN]; + + /* Check if we were invoked because of a poll request for a + particular connection. */ + if(flag == UIP_POLL_REQUEST) { + if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED && + !uip_outstanding(uip_connr)) { + uip_flags = UIP_POLL; + UIP_APPCALL(); + goto appsend; +#if UIP_ACTIVE_OPEN + } else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) { + /* In the SYN_SENT state, we retransmit out SYN. */ + BUF->flags = 0; + goto tcp_send_syn; +#endif /* UIP_ACTIVE_OPEN */ + } + goto drop; + + /* Check if we were invoked because of the perodic timer fireing. */ + } else if(flag == UIP_TIMER) { +#if UIP_REASSEMBLY + if(uip_reasstmr != 0) { + --uip_reasstmr; + } +#endif /* UIP_REASSEMBLY */ + /* Increase the initial sequence number. */ + if(++iss[3] == 0) { + if(++iss[2] == 0) { + if(++iss[1] == 0) { + ++iss[0]; + } + } + } + + /* Reset the length variables. */ + uip_len = 0; + uip_slen = 0; + + /* Check if the connection is in a state in which we simply wait + for the connection to time out. If so, we increase the + connection's timer and remove the connection if it times + out. */ + if(uip_connr->tcpstateflags == UIP_TIME_WAIT || + uip_connr->tcpstateflags == UIP_FIN_WAIT_2) { + ++(uip_connr->timer); + if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) { + uip_connr->tcpstateflags = UIP_CLOSED; + } + } else if(uip_connr->tcpstateflags != UIP_CLOSED) { + /* If the connection has outstanding data, we increase the + connection's timer and see if it has reached the RTO value + in which case we retransmit. */ + + if(uip_outstanding(uip_connr)) { + if(uip_connr->timer-- == 0) { + if(uip_connr->nrtx == UIP_MAXRTX || + ((uip_connr->tcpstateflags == UIP_SYN_SENT || + uip_connr->tcpstateflags == UIP_SYN_RCVD) && + uip_connr->nrtx == UIP_MAXSYNRTX)) { + uip_connr->tcpstateflags = UIP_CLOSED; + + /* We call UIP_APPCALL() with uip_flags set to + UIP_TIMEDOUT to inform the application that the + connection has timed out. */ + uip_flags = UIP_TIMEDOUT; + UIP_APPCALL(); + + /* We also send a reset packet to the remote host. */ + BUF->flags = TCP_RST | TCP_ACK; + goto tcp_send_nodata; + } + + /* Exponential backoff. */ + uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4? + 4: + uip_connr->nrtx); + ++(uip_connr->nrtx); + + /* Ok, so we need to retransmit. We do this differently + depending on which state we are in. In ESTABLISHED, we + call upon the application so that it may prepare the + data for the retransmit. In SYN_RCVD, we resend the + SYNACK that we sent earlier and in LAST_ACK we have to + retransmit our FINACK. */ + UIP_STAT(++uip_stat.tcp.rexmit); + switch(uip_connr->tcpstateflags & UIP_TS_MASK) { + case UIP_SYN_RCVD: + /* In the SYN_RCVD state, we should retransmit our + SYNACK. */ + goto tcp_send_synack; + +#if UIP_ACTIVE_OPEN + case UIP_SYN_SENT: + /* In the SYN_SENT state, we retransmit out SYN. */ + BUF->flags = 0; + goto tcp_send_syn; +#endif /* UIP_ACTIVE_OPEN */ + + case UIP_ESTABLISHED: + /* In the ESTABLISHED state, we call upon the application + to do the actual retransmit after which we jump into + the code for sending out the packet (the apprexmit + label). */ + uip_flags = UIP_REXMIT; + UIP_APPCALL(); + goto apprexmit; + + case UIP_FIN_WAIT_1: + case UIP_CLOSING: + case UIP_LAST_ACK: + /* In all these states we should retransmit a FINACK. */ + goto tcp_send_finack; + + } + } + } else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) { + /* If there was no need for a retransmission, we poll the + application for new data. */ + uip_flags = UIP_POLL; + UIP_APPCALL(); + goto appsend; + } + } + goto drop; + } +#if UIP_UDP + if(flag == UIP_UDP_TIMER) { + if(uip_udp_conn->lport != 0) { + uip_conn = NULL; + uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + uip_len = uip_slen = 0; + uip_flags = UIP_POLL; + UIP_UDP_APPCALL(); + goto udp_send; + } else { + goto drop; + } + } +#endif + + /* This is where the input processing starts. */ + UIP_STAT(++uip_stat.ip.recv); + + /* Start of IP input header processing code. */ + +#if UIP_CONF_IPV6 + /* Check validity of the IP header. */ + if((BUF->vtc & 0xf0) != 0x60) { /* IP version and header length. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.vhlerr); + UIP_LOG("ipv6: invalid version."); + goto drop; + } +#else /* UIP_CONF_IPV6 */ + /* Check validity of the IP header. */ + if(BUF->vhl != 0x45) { /* IP version and header length. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.vhlerr); + UIP_LOG("ip: invalid version or header length."); + goto drop; + } +#endif /* UIP_CONF_IPV6 */ + + /* Check the size of the packet. If the size reported to us in + uip_len is smaller the size reported in the IP header, we assume + that the packet has been corrupted in transit. If the size of + uip_len is larger than the size reported in the IP packet header, + the packet has been padded and we set uip_len to the correct + value.. */ + + if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) { + uip_len = (BUF->len[0] << 8) + BUF->len[1]; +#if UIP_CONF_IPV6 + uip_len += 40; /* The length reported in the IPv6 header is the + length of the payload that follows the + header. However, uIP uses the uip_len variable + for holding the size of the entire packet, + including the IP header. For IPv4 this is not a + problem as the length field in the IPv4 header + contains the length of the entire packet. But + for IPv6 we need to add the size of the IPv6 + header (40 bytes). */ +#endif /* UIP_CONF_IPV6 */ + } else { + UIP_LOG("ip: packet shorter than reported in IP header."); + goto drop; + } + +#if !UIP_CONF_IPV6 + /* Check the fragment flag. */ + if((BUF->ipoffset[0] & 0x3f) != 0 || + BUF->ipoffset[1] != 0) { +#if UIP_REASSEMBLY + uip_len = uip_reass(); + if(uip_len == 0) { + goto drop; + } +#else /* UIP_REASSEMBLY */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.fragerr); + UIP_LOG("ip: fragment dropped."); + goto drop; +#endif /* UIP_REASSEMBLY */ + } +#endif /* UIP_CONF_IPV6 */ + + if(uip_ipaddr_cmp(&uip_hostaddr, &uip_all_zeroes_addr)) { + /* If we are configured to use ping IP address configuration and + hasn't been assigned an IP address yet, we accept all ICMP + packets. */ +#if UIP_PINGADDRCONF && !UIP_CONF_IPV6 + if(BUF->proto == UIP_PROTO_ICMP) { + UIP_LOG("ip: possible ping config packet received."); + goto icmp_input; + } else { + UIP_LOG("ip: packet dropped since no address assigned."); + goto drop; + } +#endif /* UIP_PINGADDRCONF */ + + } else { + /* If IP broadcast support is configured, we check for a broadcast + UDP packet, which may be destined to us. */ +#if UIP_BROADCAST + DEBUG_PRINTF("UDP IP checksum 0x%04x\n", uip_ipchksum()); + if(BUF->proto == UIP_PROTO_UDP && + (uip_ipaddr_cmp(&BUF->destipaddr, &uip_broadcast_addr) || + (BUF->destipaddr.u8[0] & 224) == 224)) { /* XXX this is a + hack to be able + to receive UDP + multicast + packets. We check + for the bit + pattern of the + multicast + prefix. */ + goto udp_input; + } +#endif /* UIP_BROADCAST */ + + /* Check if the packet is destined for our IP address. */ +#if !UIP_CONF_IPV6 + if(!uip_ipaddr_cmp(&BUF->destipaddr, &uip_hostaddr)) { + UIP_STAT(++uip_stat.ip.drop); + goto drop; + } +#else /* UIP_CONF_IPV6 */ + /* For IPv6, packet reception is a little trickier as we need to + make sure that we listen to certain multicast addresses (all + hosts multicast address, and the solicited-node multicast + address) as well. However, we will cheat here and accept all + multicast packets that are sent to the ff02::/16 addresses. */ + if(!uip_ipaddr_cmp(&BUF->destipaddr, &uip_hostaddr) && + BUF->destipaddr.u16[0] != UIP_HTONS(0xff02)) { + UIP_STAT(++uip_stat.ip.drop); + goto drop; + } +#endif /* UIP_CONF_IPV6 */ + } + +#if !UIP_CONF_IPV6 + if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header + checksum. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.chkerr); + UIP_LOG("ip: bad checksum."); + goto drop; + } +#endif /* UIP_CONF_IPV6 */ + + if(BUF->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so, + proceed with TCP input + processing. */ + goto tcp_input; + } + +#if UIP_UDP + if(BUF->proto == UIP_PROTO_UDP) { + goto udp_input; + } +#endif /* UIP_UDP */ + +#if !UIP_CONF_IPV6 + /* ICMPv4 processing code follows. */ + if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from + here. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.protoerr); + UIP_LOG("ip: neither tcp nor icmp."); + goto drop; + } + +#if UIP_PINGADDRCONF + icmp_input: +#endif /* UIP_PINGADDRCONF */ + UIP_STAT(++uip_stat.icmp.recv); + + /* ICMP echo (i.e., ping) processing. This is simple, we only change + the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP + checksum before we return the packet. */ + if(ICMPBUF->type != ICMP_ECHO) { + UIP_STAT(++uip_stat.icmp.drop); + UIP_STAT(++uip_stat.icmp.typeerr); + UIP_LOG("icmp: not icmp echo."); + goto drop; + } + + /* If we are configured to use ping IP address assignment, we use + the destination IP address of this ping packet and assign it to + ourself. */ +#if UIP_PINGADDRCONF + if(uip_ipaddr_cmp(&uip_hostaddr, &uip_all_zeroes_addr)) { + uip_hostaddr = BUF->destipaddr; + } +#endif /* UIP_PINGADDRCONF */ + + ICMPBUF->type = ICMP_ECHO_REPLY; + + if(ICMPBUF->icmpchksum >= UIP_HTONS(0xffff - (ICMP_ECHO << 8))) { + ICMPBUF->icmpchksum += UIP_HTONS(ICMP_ECHO << 8) + 1; + } else { + ICMPBUF->icmpchksum += UIP_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); + BUF->ttl = UIP_TTL; + goto ip_send_nolen; + + /* End of IPv4 input header processing code. */ +#else /* !UIP_CONF_IPV6 */ + + /* This is IPv6 ICMPv6 processing code. */ + DEBUG_PRINTF("icmp6_input: length %d\n", uip_len); + + if(BUF->proto != UIP_PROTO_ICMP6) { /* We only allow ICMPv6 packets from + here. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.protoerr); + UIP_LOG("ip: neither tcp nor icmp6."); + goto drop; + } + + UIP_STAT(++uip_stat.icmp.recv); + + /* If we get a neighbor solicitation for our address we should send + a neighbor advertisement message back. */ + if(ICMPBUF->type == ICMP6_NEIGHBOR_SOLICITATION) { + if(uip_ipaddr_cmp(&ICMPBUF->icmp6data, &uip_hostaddr)) { + + if(ICMPBUF->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS) { + /* Save the sender's address in our neighbor list. */ + uip_neighbor_add(&ICMPBUF->srcipaddr, &(ICMPBUF->options[2])); + } + + /* We should now send a neighbor advertisement back to where the + neighbor solicication came from. */ + ICMPBUF->type = ICMP6_NEIGHBOR_ADVERTISEMENT; + ICMPBUF->flags = ICMP6_FLAG_S; /* Solicited flag. */ + + ICMPBUF->reserved1 = ICMPBUF->reserved2 = ICMPBUF->reserved3 = 0; + + uip_ipaddr_copy(&ICMPBUF->destipaddr, &ICMPBUF->srcipaddr); + uip_ipaddr_copy(&ICMPBUF->srcipaddr, &uip_hostaddr); + ICMPBUF->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS; + ICMPBUF->options[1] = 1; /* Options length, 1 = 8 bytes. */ + memcpy(&(ICMPBUF->options[2]), &uip_ethaddr, sizeof(uip_ethaddr)); + ICMPBUF->icmpchksum = 0; + ICMPBUF->icmpchksum = ~uip_icmp6chksum(); + + goto send; + + } + goto drop; + } else if(ICMPBUF->type == ICMP6_ECHO) { + /* ICMP echo (i.e., ping) processing. This is simple, we only + change the ICMP type from ECHO to ECHO_REPLY and update the + ICMP checksum before we return the packet. */ + + ICMPBUF->type = ICMP6_ECHO_REPLY; + + uip_ipaddr_copy(&BUF->destipaddr, &BUF->srcipaddr); + uip_ipaddr_copy(&BUF->srcipaddr, &uip_hostaddr); + ICMPBUF->icmpchksum = 0; + ICMPBUF->icmpchksum = ~uip_icmp6chksum(); + + UIP_STAT(++uip_stat.icmp.sent); + goto send; + } else { + DEBUG_PRINTF("Unknown icmp6 message type %d\n", ICMPBUF->type); + UIP_STAT(++uip_stat.icmp.drop); + UIP_STAT(++uip_stat.icmp.typeerr); + UIP_LOG("icmp: unknown ICMP message."); + goto drop; + } + + /* End of IPv6 ICMP processing. */ + +#endif /* !UIP_CONF_IPV6 */ + +#if UIP_UDP + /* UDP input processing. */ + udp_input: + /* UDP processing is really just a hack. We don't do anything to the + UDP/IP headers, but let the UDP application do all the hard + work. If the application sets uip_slen, it has a packet to + send. */ +#if UIP_UDP_CHECKSUMS + uip_len = uip_len - UIP_IPUDPH_LEN; + uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + if(UDPBUF->udpchksum != 0 && uip_udpchksum() != 0xffff) { + UIP_STAT(++uip_stat.udp.drop); + UIP_STAT(++uip_stat.udp.chkerr); + UIP_LOG("udp: bad checksum."); + goto drop; + } +#else /* UIP_UDP_CHECKSUMS */ + uip_len = uip_len - UIP_IPUDPH_LEN; +#endif /* UIP_UDP_CHECKSUMS */ + + /* Make sure that the UDP destination port number is not zero. */ + if(UDPBUF->destport == 0) { + UIP_LOG("udp: zero port."); + goto drop; + } + + /* 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, &uip_all_zeroes_addr) || + uip_ipaddr_cmp(&uip_udp_conn->ripaddr, &uip_broadcast_addr) || + uip_ipaddr_cmp(&BUF->srcipaddr, &uip_udp_conn->ripaddr))) { + goto udp_found; + } + } + UIP_LOG("udp: no matching connection found"); +#if UIP_CONF_ICMP_DEST_UNREACH && !UIP_CONF_IPV6 + /* Copy fields from packet header into payload of this ICMP packet. */ + memcpy(&(ICMPBUF->payload[0]), ICMPBUF, UIP_IPH_LEN + 8); + + /* Set the ICMP type and code. */ + ICMPBUF->type = ICMP_DEST_UNREACHABLE; + ICMPBUF->icode = ICMP_PORT_UNREACHABLE; + + /* Calculate the ICMP checksum. */ + ICMPBUF->icmpchksum = 0; + ICMPBUF->icmpchksum = ~uip_chksum((u16_t *)&(ICMPBUF->type), 36); + + /* Set the IP destination address to be the source address of the + original packet. */ + uip_ipaddr_copy(&BUF->destipaddr, &BUF->srcipaddr); + + /* Set our IP address as the source address. */ + uip_ipaddr_copy(&BUF->srcipaddr, &uip_hostaddr); + + /* The size of the ICMP destination unreachable packet is 36 + the + size of the IP header (20) = 56. */ + uip_len = 36 + UIP_IPH_LEN; + ICMPBUF->len[0] = 0; + ICMPBUF->len[1] = (u8_t)uip_len; + ICMPBUF->ttl = UIP_TTL; + ICMPBUF->proto = UIP_PROTO_ICMP; + + goto ip_send_nolen; +#else /* UIP_CONF_ICMP_DEST_UNREACH */ + goto drop; +#endif /* UIP_CONF_ICMP_DEST_UNREACH */ + + 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 = UIP_HTONS(uip_slen + UIP_UDPH_LEN); + UDPBUF->udpchksum = 0; + + BUF->srcport = uip_udp_conn->lport; + BUF->destport = uip_udp_conn->rport; + + uip_ipaddr_copy(&BUF->srcipaddr, &uip_hostaddr); + uip_ipaddr_copy(&BUF->destipaddr, &uip_udp_conn->ripaddr); + + uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN]; + +#if UIP_UDP_CHECKSUMS + /* Calculate UDP checksum. */ + UDPBUF->udpchksum = ~(uip_udpchksum()); + if(UDPBUF->udpchksum == 0) { + UDPBUF->udpchksum = 0xffff; + } +#endif /* UIP_UDP_CHECKSUMS */ + + goto ip_send_nolen; +#endif /* UIP_UDP */ + + /* TCP input processing. */ + tcp_input: + UIP_STAT(++uip_stat.tcp.recv); + + /* Start of TCP input header processing code. */ + + if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP + checksum. */ + UIP_STAT(++uip_stat.tcp.drop); + UIP_STAT(++uip_stat.tcp.chkerr); + UIP_LOG("tcp: bad checksum."); + goto drop; + } + + /* Make sure that the TCP port number is not zero. */ + if(BUF->destport == 0 || BUF->srcport == 0) { + UIP_LOG("tcp: zero port."); + goto drop; + } + + /* Demultiplex this segment. */ + /* First check any active connections. */ + for(uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1]; + ++uip_connr) { + if(uip_connr->tcpstateflags != UIP_CLOSED && + BUF->destport == uip_connr->lport && + BUF->srcport == uip_connr->rport && + uip_ipaddr_cmp(&BUF->srcipaddr, &uip_connr->ripaddr)) { + goto found; + } + } + + /* If we didn't find and active connection that expected the packet, + either this packet is an old duplicate, or this is a SYN packet + destined for a connection in LISTEN. If the SYN flag isn't set, + it is an old packet and we send a RST. */ + if((BUF->flags & TCP_CTL) != TCP_SYN) { + goto reset; + } + + tmp16 = BUF->destport; + /* Next, check listening connections. */ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + if(tmp16 == uip_listenports[c]) { + goto found_listen; + } + } + + /* No matching connection found, so we send a RST packet. */ + UIP_STAT(++uip_stat.tcp.synrst); + + reset: + /* We do not send resets in response to resets. */ + if(BUF->flags & TCP_RST) { + goto drop; + } + + UIP_STAT(++uip_stat.tcp.rst); + + BUF->flags = TCP_RST | TCP_ACK; + uip_len = UIP_IPTCPH_LEN; + BUF->tcpoffset = 5 << 4; + + /* Flip the seqno and ackno fields in the TCP header. */ + c = BUF->seqno[3]; + BUF->seqno[3] = BUF->ackno[3]; + BUF->ackno[3] = c; + + c = BUF->seqno[2]; + BUF->seqno[2] = BUF->ackno[2]; + BUF->ackno[2] = c; + + c = BUF->seqno[1]; + BUF->seqno[1] = BUF->ackno[1]; + BUF->ackno[1] = c; + + c = BUF->seqno[0]; + BUF->seqno[0] = BUF->ackno[0]; + BUF->ackno[0] = c; + + /* We also have to increase the sequence number we are + acknowledging. If the least significant byte overflowed, we need + to propagate the carry to the other bytes as well. */ + if(++BUF->ackno[3] == 0) { + if(++BUF->ackno[2] == 0) { + if(++BUF->ackno[1] == 0) { + ++BUF->ackno[0]; + } + } + } + + /* Swap port numbers. */ + tmp16 = BUF->srcport; + BUF->srcport = BUF->destport; + BUF->destport = tmp16; + + /* Swap IP addresses. */ + uip_ipaddr_copy(&BUF->destipaddr, &BUF->srcipaddr); + uip_ipaddr_copy(&BUF->srcipaddr, &uip_hostaddr); + + /* And send out the RST packet! */ + goto tcp_send_noconn; + + /* This label will be jumped to if we matched the incoming packet + with a connection in LISTEN. In that case, we should create a new + connection and send a SYNACK in return. */ + found_listen: + /* First we check if there are any connections avaliable. Unused + connections are kept in the same table as used connections, but + unused ones have the tcpstate set to CLOSED. Also, connections in + TIME_WAIT are kept track of and we'll use the oldest one if no + CLOSED connections are found. Thanks to Eddie C. Dost for a very + nice algorithm for the TIME_WAIT search. */ + uip_connr = 0; + for(c = 0; c < UIP_CONNS; ++c) { + if(uip_conns[c].tcpstateflags == UIP_CLOSED) { + uip_connr = &uip_conns[c]; + break; + } + if(uip_conns[c].tcpstateflags == UIP_TIME_WAIT) { + if(uip_connr == 0 || + uip_conns[c].timer > uip_connr->timer) { + uip_connr = &uip_conns[c]; + } + } + } + + if(uip_connr == 0) { + /* All connections are used already, we drop packet and hope that + the remote end will retransmit the packet at a time when we + have more spare connections. */ + UIP_STAT(++uip_stat.tcp.syndrop); + UIP_LOG("tcp: found no unused connections."); + goto drop; + } + uip_conn = uip_connr; + + /* Fill in the necessary fields for the new connection. */ + uip_connr->rto = uip_connr->timer = UIP_RTO; + uip_connr->sa = 0; + uip_connr->sv = 4; + uip_connr->nrtx = 0; + uip_connr->lport = BUF->destport; + uip_connr->rport = BUF->srcport; + uip_ipaddr_copy(&uip_connr->ripaddr, &BUF->srcipaddr); + uip_connr->tcpstateflags = UIP_SYN_RCVD; + + uip_connr->snd_nxt[0] = iss[0]; + uip_connr->snd_nxt[1] = iss[1]; + uip_connr->snd_nxt[2] = iss[2]; + uip_connr->snd_nxt[3] = iss[3]; + uip_connr->len = 1; + + /* rcv_nxt should be the seqno from the incoming packet + 1. */ + uip_connr->rcv_nxt[3] = BUF->seqno[3]; + uip_connr->rcv_nxt[2] = BUF->seqno[2]; + uip_connr->rcv_nxt[1] = BUF->seqno[1]; + uip_connr->rcv_nxt[0] = BUF->seqno[0]; + uip_add_rcv_nxt(1); + + /* Parse the TCP MSS option, if present. */ + if((BUF->tcpoffset & 0xf0) > 0x50) { + for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { + opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c]; + if(opt == TCP_OPT_END) { + /* End of options. */ + break; + } else if(opt == TCP_OPT_NOOP) { + ++c; + /* NOP option. */ + } else if(opt == TCP_OPT_MSS && + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { + /* An MSS option with the right option length. */ + tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | + (u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c]; + uip_connr->initialmss = uip_connr->mss = + tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; + + /* And we are done processing options. */ + break; + } else { + /* All other options have a length field, so that we easily + can skip past them. */ + if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) { + /* If the length field is zero, the options are malformed + and we don't process them further. */ + break; + } + c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; + } + } + } + + /* Our response will be a SYNACK. */ +#if UIP_ACTIVE_OPEN + tcp_send_synack: + BUF->flags = TCP_ACK; + + tcp_send_syn: + BUF->flags |= TCP_SYN; +#else /* UIP_ACTIVE_OPEN */ + tcp_send_synack: + BUF->flags = TCP_SYN | TCP_ACK; +#endif /* UIP_ACTIVE_OPEN */ + + /* We send out the TCP Maximum Segment Size option with our + SYNACK. */ + BUF->optdata[0] = TCP_OPT_MSS; + BUF->optdata[1] = TCP_OPT_MSS_LEN; + BUF->optdata[2] = (UIP_TCP_MSS) / 256; + BUF->optdata[3] = (UIP_TCP_MSS) & 255; + uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN; + BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4; + goto tcp_send; + + /* This label will be jumped to if we found an active connection. */ + found: + uip_conn = uip_connr; + uip_flags = 0; + /* We do a very naive form of TCP reset processing; we just accept + any RST and kill our connection. We should in fact check if the + sequence number of this reset is wihtin our advertised window + before we accept the reset. */ + if(BUF->flags & TCP_RST) { + uip_connr->tcpstateflags = UIP_CLOSED; + UIP_LOG("tcp: got reset, aborting connection."); + uip_flags = UIP_ABORT; + UIP_APPCALL(); + goto drop; + } + /* Calculate the length of the data, if the application has sent + any data to us. */ + c = (BUF->tcpoffset >> 4) << 2; + /* uip_len will contain the length of the actual TCP data. This is + calculated by subtracing the length of the TCP header (in + c) and the length of the IP header (20 bytes). */ + uip_len = uip_len - c - UIP_IPH_LEN; + + /* First, check if the sequence number of the incoming packet is + what we're expecting next. If not, we send out an ACK with the + correct numbers in, unless we are in the SYN_RCVD state and + receive a SYN, in which case we should retransmit our SYNACK + (which is done futher down). */ + if(!((((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) && + ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK))) || + (((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_RCVD) && + ((BUF->flags & TCP_CTL) == TCP_SYN)))) { + if((uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) && + (BUF->seqno[0] != uip_connr->rcv_nxt[0] || + BUF->seqno[1] != uip_connr->rcv_nxt[1] || + BUF->seqno[2] != uip_connr->rcv_nxt[2] || + BUF->seqno[3] != uip_connr->rcv_nxt[3])) { + goto tcp_send_ack; + } + } + + /* Next, check if the incoming segment acknowledges any outstanding + data. If so, we update the sequence number, reset the length of + the outstanding data, calculate RTT estimations, and reset the + retransmission timer. */ + if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) { + uip_add32(uip_connr->snd_nxt, uip_connr->len); + + if(BUF->ackno[0] == uip_acc32[0] && + BUF->ackno[1] == uip_acc32[1] && + BUF->ackno[2] == uip_acc32[2] && + BUF->ackno[3] == uip_acc32[3]) { + /* Update sequence number. */ + uip_connr->snd_nxt[0] = uip_acc32[0]; + uip_connr->snd_nxt[1] = uip_acc32[1]; + uip_connr->snd_nxt[2] = uip_acc32[2]; + uip_connr->snd_nxt[3] = uip_acc32[3]; + + /* Do RTT estimation, unless we have done retransmissions. */ + if(uip_connr->nrtx == 0) { + signed char m; + m = uip_connr->rto - uip_connr->timer; + /* This is taken directly from VJs original code in his paper */ + m = m - (uip_connr->sa >> 3); + uip_connr->sa += m; + if(m < 0) { + m = -m; + } + m = m - (uip_connr->sv >> 2); + uip_connr->sv += m; + uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv; + + } + /* Set the acknowledged flag. */ + uip_flags = UIP_ACKDATA; + /* Reset the retransmission timer. */ + uip_connr->timer = uip_connr->rto; + + /* Reset length of outstanding data. */ + uip_connr->len = 0; + } + + } + + /* Do different things depending on in what state the connection is. */ + switch(uip_connr->tcpstateflags & UIP_TS_MASK) { + /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not + implemented, since we force the application to close when the + peer sends a FIN (hence the application goes directly from + ESTABLISHED to LAST_ACK). */ + case UIP_SYN_RCVD: + /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and + we are waiting for an ACK that acknowledges the data we sent + out the last time. Therefore, we want to have the UIP_ACKDATA + flag set. If so, we enter the ESTABLISHED state. */ + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_ESTABLISHED; + uip_flags = UIP_CONNECTED; + uip_connr->len = 0; + if(uip_len > 0) { + uip_flags |= UIP_NEWDATA; + uip_add_rcv_nxt(uip_len); + } + uip_slen = 0; + UIP_APPCALL(); + goto appsend; + } + /* We need to retransmit the SYNACK */ + if((BUF->flags & TCP_CTL) == TCP_SYN) { + goto tcp_send_synack; + } + goto drop; +#if UIP_ACTIVE_OPEN + case UIP_SYN_SENT: + /* In SYN_SENT, we wait for a SYNACK that is sent in response to + our SYN. The rcv_nxt is set to sequence number in the SYNACK + plus one, and we send an ACK. We move into the ESTABLISHED + state. */ + if((uip_flags & UIP_ACKDATA) && + (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) { + + /* Parse the TCP MSS option, if present. */ + if((BUF->tcpoffset & 0xf0) > 0x50) { + for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { + opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c]; + if(opt == TCP_OPT_END) { + /* End of options. */ + break; + } else if(opt == TCP_OPT_NOOP) { + ++c; + /* NOP option. */ + } else if(opt == TCP_OPT_MSS && + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { + /* An MSS option with the right option length. */ + tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c]; + uip_connr->initialmss = + uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; + + /* And we are done processing options. */ + break; + } else { + /* All other options have a length field, so that we easily + can skip past them. */ + if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) { + /* If the length field is zero, the options are malformed + and we don't process them further. */ + break; + } + c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; + } + } + } + uip_connr->tcpstateflags = UIP_ESTABLISHED; + uip_connr->rcv_nxt[0] = BUF->seqno[0]; + uip_connr->rcv_nxt[1] = BUF->seqno[1]; + uip_connr->rcv_nxt[2] = BUF->seqno[2]; + uip_connr->rcv_nxt[3] = BUF->seqno[3]; + uip_add_rcv_nxt(1); + uip_flags = UIP_CONNECTED | UIP_NEWDATA; + uip_connr->len = 0; + uip_len = 0; + uip_slen = 0; + UIP_APPCALL(); + goto appsend; + } + /* Inform the application that the connection failed */ + uip_flags = UIP_ABORT; + UIP_APPCALL(); + /* The connection is closed after we send the RST */ + uip_conn->tcpstateflags = UIP_CLOSED; + goto reset; +#endif /* UIP_ACTIVE_OPEN */ + + case UIP_ESTABLISHED: + /* In the ESTABLISHED state, we call upon the application to feed + data into the uip_buf. If the UIP_ACKDATA flag is set, the + application should put new data into the buffer, otherwise we are + retransmitting an old segment, and the application should put that + data into the buffer. + + If the incoming packet is a FIN, we should close the connection on + this side as well, and we send out a FIN and enter the LAST_ACK + state. We require that there is no outstanding data; otherwise the + sequence numbers will be screwed up. */ + + if(BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) { + if(uip_outstanding(uip_connr)) { + goto drop; + } + uip_add_rcv_nxt(1 + uip_len); + uip_flags |= UIP_CLOSE; + if(uip_len > 0) { + uip_flags |= UIP_NEWDATA; + } + UIP_APPCALL(); + uip_connr->len = 1; + uip_connr->tcpstateflags = UIP_LAST_ACK; + uip_connr->nrtx = 0; + tcp_send_finack: + BUF->flags = TCP_FIN | TCP_ACK; + goto tcp_send_nodata; + } + + /* Check the URG flag. If this is set, the segment carries urgent + data that we must pass to the application. */ + if((BUF->flags & TCP_URG) != 0) { +#if UIP_URGDATA > 0 + uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1]; + if(uip_urglen > uip_len) { + /* There is more urgent data in the next segment to come. */ + uip_urglen = uip_len; + } + uip_add_rcv_nxt(uip_urglen); + uip_len -= uip_urglen; + uip_urgdata = uip_appdata; + uip_appdata += uip_urglen; + } else { + uip_urglen = 0; +#else /* UIP_URGDATA > 0 */ + uip_appdata = ((char *)uip_appdata) + ((BUF->urgp[0] << 8) | BUF->urgp[1]); + uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1]; +#endif /* UIP_URGDATA > 0 */ + } + + /* If uip_len > 0 we have TCP data in the packet, and we flag this + by setting the UIP_NEWDATA flag and update the sequence number + we acknowledge. If the application has stopped the dataflow + using uip_stop(), we must not accept any data packets from the + remote host. */ + if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) { + uip_flags |= UIP_NEWDATA; + uip_add_rcv_nxt(uip_len); + } + + /* Check if the available buffer space advertised by the other end + is smaller than the initial MSS for this connection. If so, we + set the current MSS to the window size to ensure that the + application does not send more data than the other end can + handle. + + If the remote host advertises a zero window, we set the MSS to + the initial MSS so that the application will send an entire MSS + of data. This data will not be acknowledged by the receiver, + and the application will retransmit it. This is called the + "persistent timer" and uses the retransmission mechanim. + */ + tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1]; + if(tmp16 > uip_connr->initialmss || + tmp16 == 0) { + tmp16 = uip_connr->initialmss; + } + uip_connr->mss = tmp16; + + /* If this packet constitutes an ACK for outstanding data (flagged + by the UIP_ACKDATA flag, we should call the application since it + might want to send more data. If the incoming packet had data + from the peer (as flagged by the UIP_NEWDATA flag), the + application must also be notified. + + When the application is called, the global variable uip_len + contains the length of the incoming data. The application can + access the incoming data through the global pointer + uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN + bytes into the uip_buf array. + + If the application wishes to send any data, this data should be + put into the uip_appdata and the length of the data should be + put into uip_len. If the application don't have any data to + send, uip_len must be set to 0. */ + if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) { + uip_slen = 0; + UIP_APPCALL(); + + appsend: + + if(uip_flags & UIP_ABORT) { + uip_slen = 0; + uip_connr->tcpstateflags = UIP_CLOSED; + BUF->flags = TCP_RST | TCP_ACK; + goto tcp_send_nodata; + } + + if(uip_flags & UIP_CLOSE) { + uip_slen = 0; + uip_connr->len = 1; + uip_connr->tcpstateflags = UIP_FIN_WAIT_1; + uip_connr->nrtx = 0; + BUF->flags = TCP_FIN | TCP_ACK; + goto tcp_send_nodata; + } + + /* If uip_slen > 0, the application has data to be sent. */ + if(uip_slen > 0) { + + /* If the connection has acknowledged data, the contents of + the ->len variable should be discarded. */ + if((uip_flags & UIP_ACKDATA) != 0) { + uip_connr->len = 0; + } + + /* If the ->len variable is non-zero the connection has + already data in transit and cannot send anymore right + now. */ + if(uip_connr->len == 0) { + + /* The application cannot send more than what is allowed by + the mss (the minumum of the MSS and the available + window). */ + if(uip_slen > uip_connr->mss) { + uip_slen = uip_connr->mss; + } + + /* Remember how much data we send out now so that we know + when everything has been acknowledged. */ + uip_connr->len = uip_slen; + } else { + + /* If the application already had unacknowledged data, we + make sure that the application does not send (i.e., + retransmit) out more than it previously sent out. */ + uip_slen = uip_connr->len; + } + } + uip_connr->nrtx = 0; + apprexmit: + uip_appdata = uip_sappdata; + + /* If the application has data to be sent, or if the incoming + packet had new data in it, we must send out a packet. */ + if(uip_slen > 0 && uip_connr->len > 0) { + /* Add the length of the IP and TCP headers. */ + uip_len = uip_connr->len + UIP_TCPIP_HLEN; + /* We always set the ACK flag in response packets. */ + BUF->flags = TCP_ACK | TCP_PSH; + /* Send the packet. */ + goto tcp_send_noopts; + } + /* If there is no data to send, just send out a pure ACK if + there is newdata. */ + if(uip_flags & UIP_NEWDATA) { + uip_len = UIP_TCPIP_HLEN; + BUF->flags = TCP_ACK; + goto tcp_send_noopts; + } + } + goto drop; + case UIP_LAST_ACK: + /* We can close this connection if the peer has acknowledged our + FIN. This is indicated by the UIP_ACKDATA flag. */ + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_CLOSED; + uip_flags = UIP_CLOSE; + UIP_APPCALL(); + } + break; + + case UIP_FIN_WAIT_1: + /* The application has closed the connection, but the remote host + hasn't closed its end yet. Thus we do nothing but wait for a + FIN from the other side. */ + if(uip_len > 0) { + uip_add_rcv_nxt(uip_len); + } + if(BUF->flags & TCP_FIN) { + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + uip_connr->len = 0; + } else { + uip_connr->tcpstateflags = UIP_CLOSING; + } + uip_add_rcv_nxt(1); + uip_flags = UIP_CLOSE; + UIP_APPCALL(); + goto tcp_send_ack; + } else if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_FIN_WAIT_2; + uip_connr->len = 0; + goto drop; + } + if(uip_len > 0) { + goto tcp_send_ack; + } + goto drop; + + case UIP_FIN_WAIT_2: + if(uip_len > 0) { + uip_add_rcv_nxt(uip_len); + } + if(BUF->flags & TCP_FIN) { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + uip_add_rcv_nxt(1); + uip_flags = UIP_CLOSE; + UIP_APPCALL(); + goto tcp_send_ack; + } + if(uip_len > 0) { + goto tcp_send_ack; + } + goto drop; + + case UIP_TIME_WAIT: + goto tcp_send_ack; + + case UIP_CLOSING: + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + } + } + goto drop; + + /* We jump here when we are ready to send the packet, and just want + to set the appropriate TCP sequence numbers in the TCP header. */ + tcp_send_ack: + BUF->flags = TCP_ACK; + + tcp_send_nodata: + uip_len = UIP_IPTCPH_LEN; + + tcp_send_noopts: + BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4; + + /* 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. */ + tcp_send: + BUF->ackno[0] = uip_connr->rcv_nxt[0]; + BUF->ackno[1] = uip_connr->rcv_nxt[1]; + BUF->ackno[2] = uip_connr->rcv_nxt[2]; + BUF->ackno[3] = uip_connr->rcv_nxt[3]; + + BUF->seqno[0] = uip_connr->snd_nxt[0]; + BUF->seqno[1] = uip_connr->snd_nxt[1]; + BUF->seqno[2] = uip_connr->snd_nxt[2]; + BUF->seqno[3] = uip_connr->snd_nxt[3]; + + BUF->proto = UIP_PROTO_TCP; + + BUF->srcport = uip_connr->lport; + BUF->destport = uip_connr->rport; + + uip_ipaddr_copy(&BUF->srcipaddr, &uip_hostaddr); + uip_ipaddr_copy(&BUF->destipaddr, &uip_connr->ripaddr); + + if(uip_connr->tcpstateflags & UIP_STOPPED) { + /* If the connection has issued uip_stop(), we advertise a zero + window so that the remote host will stop sending data. */ + BUF->wnd[0] = BUF->wnd[1] = 0; + } else { + BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8); + BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff); + } + + tcp_send_noconn: + BUF->ttl = UIP_TTL; +#if UIP_CONF_IPV6 + /* For IPv6, the IP length field does not include the IPv6 IP header + length. */ + BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); +#else /* UIP_CONF_IPV6 */ + BUF->len[0] = (uip_len >> 8); + BUF->len[1] = (uip_len & 0xff); +#endif /* UIP_CONF_IPV6 */ + + BUF->urgp[0] = BUF->urgp[1] = 0; + + /* Calculate TCP checksum. */ + BUF->tcpchksum = 0; + BUF->tcpchksum = ~(uip_tcpchksum()); + + ip_send_nolen: +#if UIP_CONF_IPV6 + BUF->vtc = 0x60; + BUF->tcflow = 0x00; + BUF->flow = 0x00; +#else /* UIP_CONF_IPV6 */ + BUF->vhl = 0x45; + BUF->tos = 0; + BUF->ipoffset[0] = BUF->ipoffset[1] = 0; + ++ipid; + BUF->ipid[0] = ipid >> 8; + BUF->ipid[1] = ipid & 0xff; + /* Calculate IP checksum. */ + BUF->ipchksum = 0; + BUF->ipchksum = ~(uip_ipchksum()); + DEBUG_PRINTF("uip ip_send_nolen: chkecum 0x%04x\n", uip_ipchksum()); +#endif /* UIP_CONF_IPV6 */ + UIP_STAT(++uip_stat.tcp.sent); +#if UIP_CONF_IPV6 + send: +#endif /* UIP_CONF_IPV6 */ + DEBUG_PRINTF("Sending packet with length %d (%d)\n", uip_len, + (BUF->len[0] << 8) | BUF->len[1]); + + UIP_STAT(++uip_stat.ip.sent); + /* Return and let the caller do the actual transmission. */ + uip_flags = 0; + return; + + drop: + uip_len = 0; + uip_flags = 0; + return; +} +/*---------------------------------------------------------------------------*/ +u16_t +uip_htons(u16_t val) +{ + return UIP_HTONS(val); +} + +u32_t +uip_htonl(u32_t val) +{ + return UIP_HTONL(val); +} +/*---------------------------------------------------------------------------*/ +void +uip_send(const void *data, int len) +{ + int copylen; +#define MIN(a,b) ((a) < (b)? (a): (b)) + copylen = MIN(len, UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN - + (int)((char *)uip_sappdata - (char *)&uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN])); + if(copylen > 0) { + uip_slen = copylen; + if(data != uip_sappdata) { + memcpy(uip_sappdata, (data), uip_slen); + } + } +} +/*---------------------------------------------------------------------------*/ +/** @} */ +#endif /* UIP_CONF_IPV6 */ diff -r 5c8404549cc0 -r 56d09a0969b5 network/uip.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/uip.h Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,2182 @@ + +/** + * \addtogroup uip + * @{ + */ + +/** + * \file + * Header file for the uIP TCP/IP stack. + * \author Adam Dunkels + * \author Julien Abeille (IPv6 related code) + * \author Mathilde Durvy (IPv6 related code) + * + * The uIP TCP/IP stack header file contains definitions for a number + * of C macros that are used by uIP programs as well as internal uIP + * structures, TCP/IP header structures and function declarations. + * + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip.h,v 1.35 2010/10/19 18:29:04 adamdunkels Exp $ + * + */ + +#ifndef __UIP_H__ +#define __UIP_H__ + +#include "uipopt.h" +#define CCIF + +/** + * Representation of an IP address. + * + */ +#if UIP_CONF_IPV6 +typedef union uip_ip6addr_t { + u8_t u8[16]; /* Initializer, must come first!!! */ + u16_t u16[8]; +} uip_ip6addr_t; + +typedef uip_ip6addr_t uip_ipaddr_t; +#else /* UIP_CONF_IPV6 */ +typedef union uip_ip4addr_t { + u8_t u8[4]; /* Initializer, must come first!!! */ + u16_t u16[2]; +#if 0 + u32_t u32; +#endif +} uip_ip4addr_t; +typedef uip_ip4addr_t uip_ipaddr_t; +#endif /* UIP_CONF_IPV6 */ + + +/*---------------------------------------------------------------------------*/ + +/** \brief 16 bit 802.15.4 address */ +typedef struct uip_802154_shortaddr { + u8_t addr[2]; +} uip_802154_shortaddr; +/** \brief 64 bit 802.15.4 address */ +typedef struct uip_802154_longaddr { + u8_t addr[8]; +} uip_802154_longaddr; + +/** \brief 802.11 address */ +typedef struct uip_80211_addr { + u8_t addr[6]; +} uip_80211_addr; + +/** \brief 802.3 address */ +typedef struct uip_eth_addr { + u8_t addr[6]; +} uip_eth_addr; + + +#if UIP_CONF_LL_802154 +/** \brief 802.15.4 address */ +typedef uip_802154_longaddr uip_lladdr_t; +#define UIP_802154_SHORTADDR_LEN 2 +#define UIP_802154_LONGADDR_LEN 8 +#define UIP_LLADDR_LEN UIP_802154_LONGADDR_LEN +#else /*UIP_CONF_LL_802154*/ +#if UIP_CONF_LL_80211 +/** \brief 802.11 address */ +typedef uip_80211_addr uip_lladdr_t; +#define UIP_LLADDR_LEN 6 +#else /*UIP_CONF_LL_80211*/ +/** \brief Ethernet address */ +typedef uip_eth_addr uip_lladdr_t; +#define UIP_LLADDR_LEN 6 +#endif /*UIP_CONF_LL_80211*/ +#endif /*UIP_CONF_LL_802154*/ + +//#include "net/tcpip.h" + +/*---------------------------------------------------------------------------*/ +/* First, the functions that should be called from the + * system. Initialization, the periodic timer, and incoming packets are + * handled by the following three functions. + */ +/** + * \defgroup uipconffunc uIP configuration functions + * @{ + * + * The uIP configuration functions are used for setting run-time + * parameters in uIP such as IP addresses. + */ + +/** + * Set the IP address of this host. + * + * The IP address is represented as a 4-byte array where the first + * octet of the IP address is put in the first member of the 4-byte + * array. + * + * Example: + \code + + uip_ipaddr_t addr; + + uip_ipaddr(&addr, 192,168,1,2); + uip_sethostaddr(&addr); + + \endcode + * \param addr A pointer to an IP address of type uip_ipaddr_t; + * + * \sa uip_ipaddr() + * + * \hideinitializer + */ +#define uip_sethostaddr(addr) uip_ipaddr_copy(&uip_hostaddr, (addr)) + +/** + * Get the IP address of this host. + * + * The IP address is represented as a 4-byte array where the first + * octet of the IP address is put in the first member of the 4-byte + * array. + * + * Example: + \code + uip_ipaddr_t hostaddr; + + uip_gethostaddr(&hostaddr); + \endcode + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the currently configured IP address. + * + * \hideinitializer + */ +#define uip_gethostaddr(addr) uip_ipaddr_copy((addr), &uip_hostaddr) + +/** + * Set the default router's IP address. + * + * \param addr A pointer to a uip_ipaddr_t variable containing the IP + * address of the default router. + * + * \sa uip_ipaddr() + * + * \hideinitializer + */ +#define uip_setdraddr(addr) uip_ipaddr_copy(&uip_draddr, (addr)) + +/** + * Set the netmask. + * + * \param addr A pointer to a uip_ipaddr_t variable containing the IP + * address of the netmask. + * + * \sa uip_ipaddr() + * + * \hideinitializer + */ +#define uip_setnetmask(addr) uip_ipaddr_copy(&uip_netmask, (addr)) + + +/** + * Get the default router's IP address. + * + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the IP address of the default router. + * + * \hideinitializer + */ +#define uip_getdraddr(addr) uip_ipaddr_copy((addr), &uip_draddr) + +/** + * Get the netmask. + * + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the value of the netmask. + * + * \hideinitializer + */ +#define uip_getnetmask(addr) uip_ipaddr_copy((addr), &uip_netmask) + +/** @} */ + +/** + * \defgroup uipinit uIP initialization functions + * @{ + * + * The uIP initialization functions are used for booting uIP. + */ + +/** + * uIP initialization function. + * + * This function should be called at boot up to initilize the uIP + * TCP/IP stack. + */ +void uip_init(void); + +/** + * uIP initialization function. + * + * This function may be used at boot time to set the initial ip_id. + */ +void uip_setipid(u16_t id); + +/** @} */ + +/** + * \defgroup uipdevfunc uIP device driver functions + * @{ + * + * These functions are used by a network device driver for interacting + * with uIP. + */ + +/** + * Process an incoming packet. + * + * This function should be called when the device driver has received + * a packet from the network. The packet from the device driver must + * be present in the uip_buf buffer, and the length of the packet + * should be placed in the uip_len variable. + * + * When the function returns, there may be an outbound packet placed + * in the uip_buf packet buffer. If so, the uip_len variable is set to + * the length of the packet. If no packet is to be sent out, the + * uip_len variable is set to 0. + * + * The usual way of calling the function is presented by the source + * code below. + \code + uip_len = devicedriver_poll(); + if(uip_len > 0) { + uip_input(); + if(uip_len > 0) { + devicedriver_send(); + } + } + \endcode + * + * \note If you are writing a uIP device driver that needs ARP + * (Address Resolution Protocol), e.g., when running uIP over + * Ethernet, you will need to call the uIP ARP code before calling + * this function: + \code + #define BUF ((struct uip_eth_hdr *)&uip_buf[0]) + uip_len = ethernet_devicedrver_poll(); + if(uip_len > 0) { + if(BUF->type == UIP_HTONS(UIP_ETHTYPE_IP)) { + uip_arp_ipin(); + uip_input(); + if(uip_len > 0) { + uip_arp_out(); + ethernet_devicedriver_send(); + } + } else if(BUF->type == UIP_HTONS(UIP_ETHTYPE_ARP)) { + uip_arp_arpin(); + if(uip_len > 0) { + ethernet_devicedriver_send(); + } + } + \endcode + * + * \hideinitializer + */ +#define uip_input() uip_process(UIP_DATA) + + +/** + * Periodic processing for a connection identified by its number. + * + * This function does the necessary periodic processing (timers, + * polling) for a uIP TCP conneciton, and should be called when the + * periodic uIP timer goes off. It should be called for every + * connection, regardless of whether they are open of closed. + * + * When the function returns, it may have an outbound packet waiting + * for service in the uIP packet buffer, and if so the uip_len + * variable is set to a value larger than zero. The device driver + * should be called to send out the packet. + * + * The usual way of calling the function is through a for() loop like + * this: + \code + for(i = 0; i < UIP_CONNS; ++i) { + uip_periodic(i); + if(uip_len > 0) { + devicedriver_send(); + } + } + \endcode + * + * \note If you are writing a uIP device driver that needs ARP + * (Address Resolution Protocol), e.g., when running uIP over + * Ethernet, you will need to call the uip_arp_out() function before + * calling the device driver: + \code + for(i = 0; i < UIP_CONNS; ++i) { + uip_periodic(i); + if(uip_len > 0) { + uip_arp_out(); + ethernet_devicedriver_send(); + } + } + \endcode + * + * \param conn The number of the connection which is to be periodically polled. + * + * \hideinitializer + */ +#if UIP_TCP +#define uip_periodic(conn) do { uip_conn = &uip_conns[conn]; \ + uip_process(UIP_TIMER); } while (0) + +/** + * + * + */ +#define uip_conn_active(conn) (uip_conns[conn].tcpstateflags != UIP_CLOSED) + +/** + * Perform periodic processing for a connection identified by a pointer + * to its structure. + * + * Same as uip_periodic() but takes a pointer to the actual uip_conn + * struct instead of an integer as its argument. This function can be + * used to force periodic processing of a specific connection. + * + * \param conn A pointer to the uip_conn struct for the connection to + * be processed. + * + * \hideinitializer + */ +#define uip_periodic_conn(conn) do { uip_conn = conn; \ + uip_process(UIP_TIMER); } while (0) + +/** + * Request that a particular connection should be polled. + * + * Similar to uip_periodic_conn() but does not perform any timer + * processing. The application is polled for new data. + * + * \param conn A pointer to the uip_conn struct for the connection to + * be processed. + * + * \hideinitializer + */ +#define uip_poll_conn(conn) do { uip_conn = conn; \ + uip_process(UIP_POLL_REQUEST); } while (0) + +#endif /* UIP_TCP */ + +#if UIP_UDP +/** + * Periodic processing for a UDP connection identified by its number. + * + * This function is essentially the same as uip_periodic(), but for + * UDP connections. It is called in a similar fashion as the + * uip_periodic() function: + \code + for(i = 0; i < UIP_UDP_CONNS; i++) { + uip_udp_periodic(i); + if(uip_len > 0) { + devicedriver_send(); + } + } + \endcode + * + * \note As for the uip_periodic() function, special care has to be + * taken when using uIP together with ARP and Ethernet: + \code + for(i = 0; i < UIP_UDP_CONNS; i++) { + uip_udp_periodic(i); + if(uip_len > 0) { + uip_arp_out(); + ethernet_devicedriver_send(); + } + } + \endcode + * + * \param conn The number of the UDP connection to be processed. + * + * \hideinitializer + */ +#define uip_udp_periodic(conn) do { uip_udp_conn = &uip_udp_conns[conn]; \ + uip_process(UIP_UDP_TIMER); } while(0) + +/** + * Periodic processing for a UDP connection identified by a pointer to + * its structure. + * + * Same as uip_udp_periodic() but takes a pointer to the actual + * uip_conn struct instead of an integer as its argument. This + * function can be used to force periodic processing of a specific + * connection. + * + * \param conn A pointer to the uip_udp_conn struct for the connection + * to be processed. + * + * \hideinitializer + */ +#define uip_udp_periodic_conn(conn) do { uip_udp_conn = conn; \ + uip_process(UIP_UDP_TIMER); } while(0) +#endif /* UIP_UDP */ + +/** \brief Abandon the reassembly of the current packet */ +void uip_reass_over(void); + +/** + * The uIP packet buffer. + * + * The uip_buf array is used to hold incoming and outgoing + * packets. The device driver should place incoming data into this + * buffer. When sending data, the device driver should read the link + * level headers and the TCP/IP headers from this buffer. The size of + * the link level headers is configured by the UIP_LLH_LEN define. + * + * \note The application data need not be placed in this buffer, so + * the device driver must read it from the place pointed to by the + * uip_appdata pointer as illustrated by the following example: + \code + void + devicedriver_send(void) + { + hwsend(&uip_buf[0], UIP_LLH_LEN); + if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) { + hwsend(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN); + } else { + hwsend(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN); + hwsend(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN); + } + } + \endcode +*/ + +typedef union { + uint32_t u32[(UIP_BUFSIZE + 3) / 4]; + uint8_t u8[UIP_BUFSIZE]; +} uip_buf_t; + +CCIF extern uip_buf_t uip_aligned_buf; +#define uip_buf (uip_aligned_buf.u8) + + +/** @} */ + +/*---------------------------------------------------------------------------*/ +/* Functions that are used by the uIP application program. Opening and + * closing connections, sending and receiving data, etc. is all + * handled by the functions below. + */ +/** + * \defgroup uipappfunc uIP application functions + * @{ + * + * Functions used by an application running of top of uIP. + */ + +/** + * Start listening to the specified port. + * + * \note Since this function expects the port number in network byte + * order, a conversion using UIP_HTONS() or uip_htons() is necessary. + * + \code + uip_listen(UIP_HTONS(80)); + \endcode + * + * \param port A 16-bit port number in network byte order. + */ +void uip_listen(u16_t port); + +/** + * Stop listening to the specified port. + * + * \note Since this function expects the port number in network byte + * order, a conversion using UIP_HTONS() or uip_htons() is necessary. + * + \code + uip_unlisten(UIP_HTONS(80)); + \endcode + * + * \param port A 16-bit port number in network byte order. + */ +void uip_unlisten(u16_t port); + +/** + * Connect to a remote host using TCP. + * + * This function is used to start a new connection to the specified + * port on the specified host. It allocates a new connection identifier, + * sets the connection to the SYN_SENT state and sets the + * retransmission timer to 0. This will cause a TCP SYN segment to be + * sent out the next time this connection is periodically processed, + * which usually is done within 0.5 seconds after the call to + * uip_connect(). + * + * \note This function is available only if support for active open + * has been configured by defining UIP_ACTIVE_OPEN to 1 in uipopt.h. + * + * \note Since this function requires the port number to be in network + * byte order, a conversion using UIP_HTONS() or uip_htons() is necessary. + * + \code + uip_ipaddr_t ipaddr; + + uip_ipaddr(&ipaddr, 192,168,1,2); + uip_connect(&ipaddr, UIP_HTONS(80)); + \endcode + * + * \param ripaddr The IP address of the remote host. + * + * \param port A 16-bit port number in network byte order. + * + * \return A pointer to the uIP connection identifier for the new connection, + * or NULL if no connection could be allocated. + * + */ +struct uip_conn *uip_connect(uip_ipaddr_t *ripaddr, u16_t port); + + + +/** + * \internal + * + * Check if a connection has outstanding (i.e., unacknowledged) data. + * + * \param conn A pointer to the uip_conn structure for the connection. + * + * \hideinitializer + */ +#define uip_outstanding(conn) ((conn)->len) + +/** + * Send data on the current connection. + * + * This function is used to send out a single segment of TCP + * data. Only applications that have been invoked by uIP for event + * processing can send data. + * + * The amount of data that actually is sent out after a call to this + * function is determined by the maximum amount of data TCP allows. uIP + * will automatically crop the data so that only the appropriate + * amount of data is sent. The function uip_mss() can be used to query + * uIP for the amount of data that actually will be sent. + * + * \note This function does not guarantee that the sent data will + * arrive at the destination. If the data is lost in the network, the + * application will be invoked with the uip_rexmit() event being + * set. The application will then have to resend the data using this + * function. + * + * \param data A pointer to the data which is to be sent. + * + * \param len The maximum amount of data bytes to be sent. + * + * \hideinitializer + */ +CCIF void uip_send(const void *data, int len); + +/** + * The length of any incoming data that is currently available (if available) + * in the uip_appdata buffer. + * + * The test function uip_data() must first be used to check if there + * is any data available at all. + * + * \hideinitializer + */ +/*void uip_datalen(void);*/ +#define uip_datalen() uip_len + +/** + * The length of any out-of-band data (urgent data) that has arrived + * on the connection. + * + * \note The configuration parameter UIP_URGDATA must be set for this + * function to be enabled. + * + * \hideinitializer + */ +#define uip_urgdatalen() uip_urglen + +/** + * Close the current connection. + * + * This function will close the current connection in a nice way. + * + * \hideinitializer + */ +#define uip_close() (uip_flags = UIP_CLOSE) + +/** + * Abort the current connection. + * + * This function will abort (reset) the current connection, and is + * usually used when an error has occurred that prevents using the + * uip_close() function. + * + * \hideinitializer + */ +#define uip_abort() (uip_flags = UIP_ABORT) + +/** + * Tell the sending host to stop sending data. + * + * This function will close our receiver's window so that we stop + * receiving data for the current connection. + * + * \hideinitializer + */ +#define uip_stop() (uip_conn->tcpstateflags |= UIP_STOPPED) + +/** + * Find out if the current connection has been previously stopped with + * uip_stop(). + * + * \hideinitializer + */ +#define uip_stopped(conn) ((conn)->tcpstateflags & UIP_STOPPED) + +/** + * Restart the current connection, if is has previously been stopped + * with uip_stop(). + * + * This function will open the receiver's window again so that we + * start receiving data for the current connection. + * + * \hideinitializer + */ +#define uip_restart() do { uip_flags |= UIP_NEWDATA; \ + uip_conn->tcpstateflags &= ~UIP_STOPPED; \ + } while(0) + + +/* uIP tests that can be made to determine in what state the current + connection is, and what the application function should do. */ + +/** + * Is the current connection a UDP connection? + * + * This function checks whether the current connection is a UDP connection. + * + * \hideinitializer + * + */ +#define uip_udpconnection() (uip_conn == NULL) + +/** + * Is new incoming data available? + * + * Will reduce to non-zero if there is new data for the application + * present at the uip_appdata pointer. The size of the data is + * available through the uip_len variable. + * + * \hideinitializer + */ +#define uip_newdata() (uip_flags & UIP_NEWDATA) + +/** + * Has previously sent data been acknowledged? + * + * Will reduce to non-zero if the previously sent data has been + * acknowledged by the remote host. This means that the application + * can send new data. + * + * \hideinitializer + */ +#define uip_acked() (uip_flags & UIP_ACKDATA) + +/** + * Has the connection just been connected? + * + * Reduces to non-zero if the current connection has been connected to + * a remote host. This will happen both if the connection has been + * actively opened (with uip_connect()) or passively opened (with + * uip_listen()). + * + * \hideinitializer + */ +#define uip_connected() (uip_flags & UIP_CONNECTED) + +/** + * Has the connection been closed by the other end? + * + * Is non-zero if the connection has been closed by the remote + * host. The application may then do the necessary clean-ups. + * + * \hideinitializer + */ +#define uip_closed() (uip_flags & UIP_CLOSE) + +/** + * Has the connection been aborted by the other end? + * + * Non-zero if the current connection has been aborted (reset) by the + * remote host. + * + * \hideinitializer + */ +#define uip_aborted() (uip_flags & UIP_ABORT) + +/** + * Has the connection timed out? + * + * Non-zero if the current connection has been aborted due to too many + * retransmissions. + * + * \hideinitializer + */ +#define uip_timedout() (uip_flags & UIP_TIMEDOUT) + +/** + * Do we need to retransmit previously data? + * + * Reduces to non-zero if the previously sent data has been lost in + * the network, and the application should retransmit it. The + * application should send the exact same data as it did the last + * time, using the uip_send() function. + * + * \hideinitializer + */ +#define uip_rexmit() (uip_flags & UIP_REXMIT) + +/** + * Is the connection being polled by uIP? + * + * Is non-zero if the reason the application is invoked is that the + * current connection has been idle for a while and should be + * polled. + * + * The polling event can be used for sending data without having to + * wait for the remote host to send data. + * + * \hideinitializer + */ +#define uip_poll() (uip_flags & UIP_POLL) + +/** + * Get the initial maximum segment size (MSS) of the current + * connection. + * + * \hideinitializer + */ +#define uip_initialmss() (uip_conn->initialmss) + +/** + * Get the current maximum segment size that can be sent on the current + * connection. + * + * The current maximum segment size that can be sent on the + * connection is computed from the receiver's window and the MSS of + * the connection (which also is available by calling + * uip_initialmss()). + * + * \hideinitializer + */ +#define uip_mss() (uip_conn->mss) + +/** + * Set up a new UDP connection. + * + * This function sets up a new UDP connection. The function will + * automatically allocate an unused local port for the new + * connection. However, another port can be chosen by using the + * uip_udp_bind() call, after the uip_udp_new() function has been + * called. + * + * Example: + \code + uip_ipaddr_t addr; + struct uip_udp_conn *c; + + uip_ipaddr(&addr, 192,168,2,1); + c = uip_udp_new(&addr, UIP_HTONS(12345)); + if(c != NULL) { + uip_udp_bind(c, UIP_HTONS(12344)); + } + \endcode + * \param ripaddr The IP address of the remote host. + * + * \param rport The remote port number in network byte order. + * + * \return The uip_udp_conn structure for the new connection or NULL + * if no connection could be allocated. + */ +struct uip_udp_conn *uip_udp_new(const uip_ipaddr_t *ripaddr, u16_t rport); + +/** + * Removed a UDP connection. + * + * \param conn A pointer to the uip_udp_conn structure for the connection. + * + * \hideinitializer + */ +#define uip_udp_remove(conn) (conn)->lport = 0 + +/** + * Bind a UDP connection to a local port. + * + * \param conn A pointer to the uip_udp_conn structure for the + * connection. + * + * \param port The local port number, in network byte order. + * + * \hideinitializer + */ +#define uip_udp_bind(conn, port) (conn)->lport = port + +/** + * Send a UDP datagram of length len on the current connection. + * + * This function can only be called in response to a UDP event (poll + * or newdata). The data must be present in the uip_buf buffer, at the + * place pointed to by the uip_appdata pointer. + * + * \param len The length of the data in the uip_buf buffer. + * + * \hideinitializer + */ +#define uip_udp_send(len) uip_send((char *)uip_appdata, len) + +/** @} */ + +/* uIP convenience and converting functions. */ + +/** + * \defgroup uipconvfunc uIP conversion functions + * @{ + * + * These functions can be used for converting between different data + * formats used by uIP. + */ + +/** + * Convert an IP address to four bytes separated by commas. + * + * Example: + \code + uip_ipaddr_t ipaddr; + printf("ipaddr=%d.%d.%d.%d\n", uip_ipaddr_to_quad(&ipaddr)); + \endcode + * + * \param a A pointer to a uip_ipaddr_t. + * \hideinitializer + */ +#define uip_ipaddr_to_quad(a) (a)->u8[0],(a)->u8[1],(a)->u8[2],(a)->u8[3] + +/** + * Construct an IP address from four bytes. + * + * This function constructs an IP address of the type that uIP handles + * internally from four bytes. The function is handy for specifying IP + * addresses to use with e.g. the uip_connect() function. + * + * Example: + \code + uip_ipaddr_t ipaddr; + struct uip_conn *c; + + uip_ipaddr(&ipaddr, 192,168,1,2); + c = uip_connect(&ipaddr, UIP_HTONS(80)); + \endcode + * + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the IP address. + * + * \param addr0 The first octet of the IP address. + * \param addr1 The second octet of the IP address. + * \param addr2 The third octet of the IP address. + * \param addr3 The forth octet of the IP address. + * + * \hideinitializer + */ +#define uip_ipaddr(addr, addr0,addr1,addr2,addr3) do { \ + (addr)->u8[0] = addr0; \ + (addr)->u8[1] = addr1; \ + (addr)->u8[2] = addr2; \ + (addr)->u8[3] = addr3; \ + } while(0) + +/** + * Construct an IPv6 address from eight 16-bit words. + * + * This function constructs an IPv6 address. + * + * \hideinitializer + */ +#define uip_ip6addr(addr, addr0,addr1,addr2,addr3,addr4,addr5,addr6,addr7) do { \ + (addr)->u16[0] = UIP_HTONS(addr0); \ + (addr)->u16[1] = UIP_HTONS(addr1); \ + (addr)->u16[2] = UIP_HTONS(addr2); \ + (addr)->u16[3] = UIP_HTONS(addr3); \ + (addr)->u16[4] = UIP_HTONS(addr4); \ + (addr)->u16[5] = UIP_HTONS(addr5); \ + (addr)->u16[6] = UIP_HTONS(addr6); \ + (addr)->u16[7] = UIP_HTONS(addr7); \ + } while(0) + +/** + * Construct an IPv6 address from eight 8-bit words. + * + * This function constructs an IPv6 address. + * + * \hideinitializer + */ +#define uip_ip6addr_u8(addr, addr0,addr1,addr2,addr3,addr4,addr5,addr6,addr7,addr8,addr9,addr10,addr11,addr12,addr13,addr14,addr15) do { \ + (addr)->u8[0] = addr0; \ + (addr)->u8[1] = addr1; \ + (addr)->u8[2] = addr2; \ + (addr)->u8[3] = addr3; \ + (addr)->u8[4] = addr4; \ + (addr)->u8[5] = addr5; \ + (addr)->u8[6] = addr6; \ + (addr)->u8[7] = addr7; \ + (addr)->u8[8] = addr8; \ + (addr)->u8[9] = addr9; \ + (addr)->u8[10] = addr10; \ + (addr)->u8[11] = addr11; \ + (addr)->u8[12] = addr12; \ + (addr)->u8[13] = addr13; \ + (addr)->u8[14] = addr14; \ + (addr)->u8[15] = addr15; \ + } while(0) + + +/** + * Copy an IP address to another IP address. + * + * Copies an IP address from one place to another. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2; + + uip_ipaddr(&ipaddr1, 192,16,1,2); + uip_ipaddr_copy(&ipaddr2, &ipaddr1); + \endcode + * + * \param dest The destination for the copy. + * \param src The source from where to copy. + * + * \hideinitializer + */ +#ifndef uip_ipaddr_copy +#define uip_ipaddr_copy(dest, src) (*(dest) = *(src)) +#endif + +/** + * Compare two IP addresses + * + * Compares two IP addresses. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2; + + uip_ipaddr(&ipaddr1, 192,16,1,2); + if(uip_ipaddr_cmp(&ipaddr2, &ipaddr1)) { + printf("They are the same"); + } + \endcode + * + * \param addr1 The first IP address. + * \param addr2 The second IP address. + * + * \hideinitializer + */ +#if !UIP_CONF_IPV6 +#define uip_ipaddr_cmp(addr1, addr2) ((addr1)->u16[0] == (addr2)->u16[0] && \ + (addr1)->u16[1] == (addr2)->u16[1]) +#else /* !UIP_CONF_IPV6 */ +#define uip_ipaddr_cmp(addr1, addr2) (memcmp(addr1, addr2, sizeof(uip_ip6addr_t)) == 0) +#endif /* !UIP_CONF_IPV6 */ + +/** + * Compare two IP addresses with netmasks + * + * Compares two IP addresses with netmasks. The masks are used to mask + * out the bits that are to be compared. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2, mask; + + uip_ipaddr(&mask, 255,255,255,0); + uip_ipaddr(&ipaddr1, 192,16,1,2); + uip_ipaddr(&ipaddr2, 192,16,1,3); + if(uip_ipaddr_maskcmp(&ipaddr1, &ipaddr2, &mask)) { + printf("They are the same"); + } + \endcode + * + * \param addr1 The first IP address. + * \param addr2 The second IP address. + * \param mask The netmask. + * + * \hideinitializer + */ +#if !UIP_CONF_IPV6 +#define uip_ipaddr_maskcmp(addr1, addr2, mask) \ + (((((u16_t *)addr1)[0] & ((u16_t *)mask)[0]) == \ + (((u16_t *)addr2)[0] & ((u16_t *)mask)[0])) && \ + ((((u16_t *)addr1)[1] & ((u16_t *)mask)[1]) == \ + (((u16_t *)addr2)[1] & ((u16_t *)mask)[1]))) +#else +#define uip_ipaddr_prefixcmp(addr1, addr2, length) (memcmp(addr1, addr2, length>>3) == 0) +#endif + + +/** + * Check if an address is a broadcast address for a network. + * + * Checks if an address is the broadcast address for a network. The + * network is defined by an IP address that is on the network and the + * network's netmask. + * + * \param addr The IP address. + * \param netaddr The network's IP address. + * \param netmask The network's netmask. + * + * \hideinitializer + */ +/*#define uip_ipaddr_isbroadcast(addr, netaddr, netmask) + ((uip_ipaddr_t *)(addr)).u16 & ((uip_ipaddr_t *)(addr)).u16*/ + + + +/** + * Mask out the network part of an IP address. + * + * Masks out the network part of an IP address, given the address and + * the netmask. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2, netmask; + + uip_ipaddr(&ipaddr1, 192,16,1,2); + uip_ipaddr(&netmask, 255,255,255,0); + uip_ipaddr_mask(&ipaddr2, &ipaddr1, &netmask); + \endcode + * + * In the example above, the variable "ipaddr2" will contain the IP + * address 192.168.1.0. + * + * \param dest Where the result is to be placed. + * \param src The IP address. + * \param mask The netmask. + * + * \hideinitializer + */ +#define uip_ipaddr_mask(dest, src, mask) do { \ + ((u16_t *)dest)[0] = ((u16_t *)src)[0] & ((u16_t *)mask)[0]; \ + ((u16_t *)dest)[1] = ((u16_t *)src)[1] & ((u16_t *)mask)[1]; \ + } while(0) + +/** + * Pick the first octet of an IP address. + * + * Picks out the first octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr1(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 1. + * + * \hideinitializer + */ +#define uip_ipaddr1(addr) ((addr)->u8[0]) + +/** + * Pick the second octet of an IP address. + * + * Picks out the second octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr2(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 2. + * + * \hideinitializer + */ +#define uip_ipaddr2(addr) ((addr)->u8[1]) + +/** + * Pick the third octet of an IP address. + * + * Picks out the third octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr3(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 3. + * + * \hideinitializer + */ +#define uip_ipaddr3(addr) ((addr)->u8[2]) + +/** + * Pick the fourth octet of an IP address. + * + * Picks out the fourth octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr4(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 4. + * + * \hideinitializer + */ +#define uip_ipaddr4(addr) ((addr)->u8[3]) + +/** + * Convert 16-bit quantity from host byte order to network byte order. + * + * This macro is primarily used for converting constants from host + * byte order to network byte order. For converting variables to + * network byte order, use the uip_htons() function instead. + * + * \hideinitializer + */ +#ifndef UIP_HTONS +# if UIP_BYTE_ORDER == UIP_BIG_ENDIAN +# define UIP_HTONS(n) (n) +# define UIP_HTONL(n) (n) +# else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */ +# define UIP_HTONS(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8)) +# define UIP_HTONL(n) (((u32_t)UIP_HTONS(n) << 16) | UIP_HTONS((u32_t)(n) >> 16)) +# endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */ +#else +#error "UIP_HTONS already defined!" +#endif /* UIP_HTONS */ + +/** + * Convert 16-bit quantity from host byte order to network byte order. + * + * This function is primarily used for converting variables from host + * byte order to network byte order. For converting constants to + * network byte order, use the UIP_HTONS() macro instead. + */ +#ifndef uip_htons +CCIF u16_t uip_htons(u16_t val); +#endif /* uip_htons */ +#ifndef uip_ntohs +#define uip_ntohs uip_htons +#endif + +#ifndef uip_htonl +CCIF u32_t uip_htonl(u32_t val); +#endif /* uip_htonl */ +#ifndef uip_ntohl +#define uip_ntohl uip_htonl +#endif + +/** @} */ + +/** + * Pointer to the application data in the packet buffer. + * + * This pointer points to the application data when the application is + * called. If the application wishes to send data, the application may + * use this space to write the data into before calling uip_send(). + */ +CCIF extern void *uip_appdata; + +#if UIP_URGDATA > 0 +/* u8_t *uip_urgdata: + * + * This pointer points to any urgent data that has been received. Only + * present if compiled with support for urgent data (UIP_URGDATA). + */ +extern void *uip_urgdata; +#endif /* UIP_URGDATA > 0 */ + + +/** + * \defgroup uipdrivervars Variables used in uIP device drivers + * @{ + * + * uIP has a few global variables that are used in device drivers for + * uIP. + */ + +/** + * The length of the packet in the uip_buf buffer. + * + * The global variable uip_len holds the length of the packet in the + * uip_buf buffer. + * + * When the network device driver calls the uIP input function, + * uip_len should be set to the length of the packet in the uip_buf + * buffer. + * + * When sending packets, the device driver should use the contents of + * the uip_len variable to determine the length of the outgoing + * packet. + * + */ +CCIF extern u16_t uip_len; + +/** + * The length of the extension headers + */ +extern u8_t uip_ext_len; +/** @} */ + +#if UIP_URGDATA > 0 +extern u16_t uip_urglen, uip_surglen; +#endif /* UIP_URGDATA > 0 */ + + +/** + * Representation of a uIP TCP connection. + * + * The uip_conn structure is used for identifying a connection. All + * but one field in the structure are to be considered read-only by an + * application. The only exception is the appstate field whose purpose + * is to let the application store application-specific state (e.g., + * file pointers) for the connection. The type of this field is + * configured in the "uipopt.h" header file. + */ +struct uip_conn { + uip_ipaddr_t ripaddr; /**< The IP address of the remote host. */ + + u16_t lport; /**< The local TCP port, in network byte order. */ + u16_t rport; /**< The local remote TCP port, in network byte + order. */ + + u8_t rcv_nxt[4]; /**< The sequence number that we expect to + receive next. */ + u8_t snd_nxt[4]; /**< The sequence number that was last sent by + us. */ + u16_t len; /**< Length of the data that was previously sent. */ + u16_t mss; /**< Current maximum segment size for the + connection. */ + u16_t initialmss; /**< Initial maximum segment size for the + connection. */ + u8_t sa; /**< Retransmission time-out calculation state + variable. */ + u8_t sv; /**< Retransmission time-out calculation state + variable. */ + u8_t rto; /**< Retransmission time-out. */ + u8_t tcpstateflags; /**< TCP state and flags. */ + u8_t timer; /**< The retransmission timer. */ + u8_t nrtx; /**< The number of retransmissions for the last + segment sent. */ + + /** The application state. */ + uip_tcp_appstate_t appstate; +}; + + +/** + * Pointer to the current TCP connection. + * + * The uip_conn pointer can be used to access the current TCP + * connection. + */ + +CCIF extern struct uip_conn *uip_conn; +#if UIP_TCP +/* The array containing all uIP connections. */ +CCIF extern struct uip_conn uip_conns[UIP_CONNS]; +#endif + +/** + * \addtogroup uiparch + * @{ + */ + +/** + * 4-byte array used for the 32-bit sequence number calculations. + */ +extern u8_t uip_acc32[4]; +/** @} */ + +/** + * Representation of a uIP UDP connection. + */ +struct uip_udp_conn { + uip_ipaddr_t ripaddr; /**< The IP address of the remote peer. */ + u16_t lport; /**< The local port number in network byte order. */ + u16_t rport; /**< The remote port number in network byte order. */ + u8_t ttl; /**< Default time-to-live. */ + + /** The application state. */ + uip_udp_appstate_t appstate; +}; + +/** + * The current UDP connection. + */ +extern struct uip_udp_conn *uip_udp_conn; +extern struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; + +struct uip_fallback_interface { + void (*init)(void); + void (*output)(void); +}; + +#if UIP_CONF_ICMP6 +struct uip_icmp6_conn { + uip_icmp6_appstate_t appstate; +}; +extern struct uip_icmp6_conn uip_icmp6_conns; +#endif /*UIP_CONF_ICMP6*/ + +/** + * The uIP TCP/IP statistics. + * + * This is the variable in which the uIP TCP/IP statistics are gathered. + */ +#if UIP_STATISTICS == 1 +extern struct uip_stats uip_stat; +#define UIP_STAT(s) s +#else +#define UIP_STAT(s) +#endif /* UIP_STATISTICS == 1 */ + +/** + * The structure holding the TCP/IP statistics that are gathered if + * UIP_STATISTICS is set to 1. + * + */ +struct uip_stats { + struct { + uip_stats_t recv; /**< Number of received packets at the IP + layer. */ + uip_stats_t sent; /**< Number of sent packets at the IP + layer. */ + uip_stats_t forwarded;/**< Number of forwarded packets at the IP + layer. */ + uip_stats_t drop; /**< Number of dropped packets at the IP + layer. */ + uip_stats_t vhlerr; /**< Number of packets dropped due to wrong + IP version or header length. */ + uip_stats_t hblenerr; /**< Number of packets dropped due to wrong + IP length, high byte. */ + uip_stats_t lblenerr; /**< Number of packets dropped due to wrong + IP length, low byte. */ + uip_stats_t fragerr; /**< Number of packets dropped since they + were IP fragments. */ + uip_stats_t chkerr; /**< Number of packets dropped due to IP + checksum errors. */ + uip_stats_t protoerr; /**< Number of packets dropped since they + were neither ICMP, UDP nor TCP. */ + } ip; /**< IP statistics. */ + struct { + uip_stats_t recv; /**< Number of received ICMP packets. */ + uip_stats_t sent; /**< Number of sent ICMP packets. */ + uip_stats_t drop; /**< Number of dropped ICMP packets. */ + uip_stats_t typeerr; /**< Number of ICMP packets with a wrong + type. */ + uip_stats_t chkerr; /**< Number of ICMP packets with a bad + checksum. */ + } icmp; /**< ICMP statistics. */ +#if UIP_TCP + struct { + uip_stats_t recv; /**< Number of recived TCP segments. */ + uip_stats_t sent; /**< Number of sent TCP segments. */ + uip_stats_t drop; /**< Number of dropped TCP segments. */ + uip_stats_t chkerr; /**< Number of TCP segments with a bad + checksum. */ + uip_stats_t ackerr; /**< Number of TCP segments with a bad ACK + number. */ + uip_stats_t rst; /**< Number of recevied TCP RST (reset) segments. */ + uip_stats_t rexmit; /**< Number of retransmitted TCP segments. */ + uip_stats_t syndrop; /**< Number of dropped SYNs due to too few + connections was avaliable. */ + uip_stats_t synrst; /**< Number of SYNs for closed ports, + triggering a RST. */ + } tcp; /**< TCP statistics. */ +#endif +#if UIP_UDP + struct { + uip_stats_t drop; /**< Number of dropped UDP segments. */ + uip_stats_t recv; /**< Number of recived UDP segments. */ + uip_stats_t sent; /**< Number of sent UDP segments. */ + uip_stats_t chkerr; /**< Number of UDP segments with a bad + checksum. */ + } udp; /**< UDP statistics. */ +#endif /* UIP_UDP */ +#if UIP_CONF_IPV6 + struct { + uip_stats_t drop; /**< Number of dropped ND6 packets. */ + uip_stats_t recv; /**< Number of recived ND6 packets */ + uip_stats_t sent; /**< Number of sent ND6 packets */ + } nd6; +#endif /*UIP_CONF_IPV6*/ +}; + + +/*---------------------------------------------------------------------------*/ +/* All the stuff below this point is internal to uIP and should not be + * used directly by an application or by a device driver. + */ +/*---------------------------------------------------------------------------*/ + + + +/* u8_t uip_flags: + * + * When the application is called, uip_flags will contain the flags + * that are defined in this file. Please read below for more + * information. + */ +CCIF extern u8_t uip_flags; + +/* The following flags may be set in the global variable uip_flags + before calling the application callback. The UIP_ACKDATA, + UIP_NEWDATA, and UIP_CLOSE flags may both be set at the same time, + whereas the others are mutually exclusive. Note that these flags + should *NOT* be accessed directly, but only through the uIP + functions/macros. */ + +#define UIP_ACKDATA 1 /* Signifies that the outstanding data was + acked and the application should send + out new data instead of retransmitting + the last data. */ +#define UIP_NEWDATA 2 /* Flags the fact that the peer has sent + us new data. */ +#define UIP_REXMIT 4 /* Tells the application to retransmit the + data that was last sent. */ +#define UIP_POLL 8 /* Used for polling the application, to + check if the application has data that + it wants to send. */ +#define UIP_CLOSE 16 /* The remote host has closed the + connection, thus the connection has + gone away. Or the application signals + that it wants to close the + connection. */ +#define UIP_ABORT 32 /* The remote host has aborted the + connection, thus the connection has + gone away. Or the application signals + that it wants to abort the + connection. */ +#define UIP_CONNECTED 64 /* We have got a connection from a remote + host and have set up a new connection + for it, or an active connection has + been successfully established. */ + +#define UIP_TIMEDOUT 128 /* The connection has been aborted due to + too many retransmissions. */ + + +/** + * \brief process the options within a hop by hop or destination option header + * \retval 0: nothing to send, + * \retval 1: drop pkt + * \retval 2: ICMP error message to send +*/ +/*static u8_t +uip_ext_hdr_options_process(); */ + +/* uip_process(flag): + * + * The actual uIP function which does all the work. + */ +void uip_process(u8_t flag); + + /* The following flags are passed as an argument to the uip_process() + function. They are used to distinguish between the two cases where + uip_process() is called. It can be called either because we have + incoming data that should be processed, or because the periodic + timer has fired. These values are never used directly, but only in + the macros defined in this file. */ + +#define UIP_DATA 1 /* Tells uIP that there is incoming + data in the uip_buf buffer. The + length of the data is stored in the + global variable uip_len. */ +#define UIP_TIMER 2 /* Tells uIP that the periodic timer + has fired. */ +#define UIP_POLL_REQUEST 3 /* Tells uIP that a connection should + be polled. */ +#define UIP_UDP_SEND_CONN 4 /* Tells uIP that a UDP datagram + should be constructed in the + uip_buf buffer. */ +#if UIP_UDP +#define UIP_UDP_TIMER 5 +#endif /* UIP_UDP */ + +/* The TCP states used in the uip_conn->tcpstateflags. */ +#define UIP_CLOSED 0 +#define UIP_SYN_RCVD 1 +#define UIP_SYN_SENT 2 +#define UIP_ESTABLISHED 3 +#define UIP_FIN_WAIT_1 4 +#define UIP_FIN_WAIT_2 5 +#define UIP_CLOSING 6 +#define UIP_TIME_WAIT 7 +#define UIP_LAST_ACK 8 +#define UIP_TS_MASK 15 + +#define UIP_STOPPED 16 + +/* The TCP and IP headers. */ +struct uip_tcpip_hdr { +#if UIP_CONF_IPV6 + /* IPv6 header. */ + u8_t vtc, + tcflow; + u16_t flow; + u8_t len[2]; + u8_t proto, ttl; + uip_ip6addr_t srcipaddr, destipaddr; +#else /* UIP_CONF_IPV6 */ + /* IPv4 header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + uip_ipaddr_t srcipaddr, destipaddr; +#endif /* UIP_CONF_IPV6 */ + + /* TCP header. */ + u16_t srcport, + destport; + u8_t seqno[4], + ackno[4], + tcpoffset, + flags, + wnd[2]; + u16_t tcpchksum; + u8_t urgp[2]; + u8_t optdata[4]; +}; + +/* The ICMP and IP headers. */ +struct uip_icmpip_hdr { +#if UIP_CONF_IPV6 + /* IPv6 header. */ + u8_t vtc, + tcf; + u16_t flow; + u8_t len[2]; + u8_t proto, ttl; + uip_ip6addr_t srcipaddr, destipaddr; +#else /* UIP_CONF_IPV6 */ + /* IPv4 header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + uip_ipaddr_t srcipaddr, destipaddr; +#endif /* UIP_CONF_IPV6 */ + + /* ICMP header. */ + u8_t type, icode; + u16_t icmpchksum; +#if !UIP_CONF_IPV6 + u16_t id, seqno; + u8_t payload[1]; +#endif /* !UIP_CONF_IPV6 */ +}; + + +/* The UDP and IP headers. */ +struct uip_udpip_hdr { +#if UIP_CONF_IPV6 + /* IPv6 header. */ + u8_t vtc, + tcf; + u16_t flow; + u8_t len[2]; + u8_t proto, ttl; + uip_ip6addr_t srcipaddr, destipaddr; +#else /* UIP_CONF_IPV6 */ + /* IP header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + uip_ipaddr_t srcipaddr, destipaddr; +#endif /* UIP_CONF_IPV6 */ + + /* UDP header. */ + u16_t srcport, + destport; + u16_t udplen; + u16_t udpchksum; +}; + +/* + * In IPv6 the length of the L3 headers before the transport header is + * not fixed, due to the possibility to include extension option headers + * after the IP header. hence we split here L3 and L4 headers + */ +/* The IP header */ +struct uip_ip_hdr { +#if UIP_CONF_IPV6 + /* IPV6 header */ + u8_t vtc; + u8_t tcflow; + u16_t flow; + u8_t len[2]; + u8_t proto, ttl; + uip_ip6addr_t srcipaddr, destipaddr; +#else /* UIP_CONF_IPV6 */ + /* IPV4 header */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + uip_ipaddr_t srcipaddr, destipaddr; +#endif /* UIP_CONF_IPV6 */ +}; + + +/* + * IPv6 extension option headers: we are able to process + * the 4 extension headers defined in RFC2460 (IPv6): + * - Hop by hop option header, destination option header: + * These two are not used by any core IPv6 protocol, hence + * we just read them and go to the next. They convey options, + * the options defined in RFC2460 are Pad1 and PadN, which do + * some padding, and that we do not need to read (the length + * field in the header is enough) + * - Routing header: this one is most notably used by MIPv6, + * which we do not implement, hence we just read it and go + * to the next + * - Fragmentation header: we read this header and are able to + * reassemble packets + * + * We do not offer any means to send packets with extension headers + * + * We do not implement Authentication and ESP headers, which are + * used in IPSec and defined in RFC4302,4303,4305,4385 + */ +/* common header part */ +typedef struct uip_ext_hdr { + u8_t next; + u8_t len; +} uip_ext_hdr; + +/* Hop by Hop option header */ +typedef struct uip_hbho_hdr { + u8_t next; + u8_t len; +} uip_hbho_hdr; + +/* destination option header */ +typedef struct uip_desto_hdr { + u8_t next; + u8_t len; +} uip_desto_hdr; + +/* We do not define structures for PAD1 and PADN options */ + +/* + * routing header + * the routing header as 4 common bytes, then routing header type + * specific data there are several types of routing header. Type 0 was + * deprecated as per RFC5095 most notable other type is 2, used in + * RFC3775 (MIPv6) here we do not implement MIPv6, so we just need to + * parse the 4 first bytes + */ +typedef struct uip_routing_hdr { + u8_t next; + u8_t len; + u8_t routing_type; + u8_t seg_left; +} uip_routing_hdr; + +/* fragmentation header */ +typedef struct uip_frag_hdr { + u8_t next; + u8_t res; + u16_t offsetresmore; + u32_t id; +} uip_frag_hdr; + +/* + * an option within the destination or hop by hop option headers + * it contains type an length, which is true for all options but PAD1 + */ +typedef struct uip_ext_hdr_opt { + u8_t type; + u8_t len; +} uip_ext_hdr_opt; + +/* PADN option */ +typedef struct uip_ext_hdr_opt_padn { + u8_t opt_type; + u8_t opt_len; +} uip_ext_hdr_opt_padn; + +/* TCP header */ +struct uip_tcp_hdr { + u16_t srcport; + u16_t destport; + u8_t seqno[4]; + u8_t ackno[4]; + u8_t tcpoffset; + u8_t flags; + u8_t wnd[2]; + u16_t tcpchksum; + u8_t urgp[2]; + u8_t optdata[4]; +}; + +/* The ICMP headers. */ +struct uip_icmp_hdr { + u8_t type, icode; + u16_t icmpchksum; +#if !UIP_CONF_IPV6 + u16_t id, seqno; +#endif /* !UIP_CONF_IPV6 */ +}; + + +/* The UDP headers. */ +struct uip_udp_hdr { + u16_t srcport; + u16_t destport; + u16_t udplen; + u16_t udpchksum; +}; + + +/** + * The buffer size available for user data in the \ref uip_buf buffer. + * + * This macro holds the available size for user data in the \ref + * uip_buf buffer. The macro is intended to be used for checking + * bounds of available user data. + * + * Example: + \code + snprintf(uip_appdata, UIP_APPDATA_SIZE, "%u\n", i); + \endcode + * + * \hideinitializer + */ +#define UIP_APPDATA_SIZE (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN) +#define UIP_APPDATA_PTR (void *)&uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN] + +#define UIP_PROTO_ICMP 1 +#define UIP_PROTO_TCP 6 +#define UIP_PROTO_UDP 17 +#define UIP_PROTO_ICMP6 58 + + +#if UIP_CONF_IPV6 +/** @{ */ +/** \brief extension headers types */ +#define UIP_PROTO_HBHO 0 +#define UIP_PROTO_DESTO 60 +#define UIP_PROTO_ROUTING 43 +#define UIP_PROTO_FRAG 44 +#define UIP_PROTO_NONE 59 +/** @} */ + +/** @{ */ +/** \brief Destination and Hop By Hop extension headers option types */ +#define UIP_EXT_HDR_OPT_PAD1 0 +#define UIP_EXT_HDR_OPT_PADN 1 +/** @} */ + +/** @{ */ +/** + * \brief Bitmaps for extension header processing + * + * When processing extension headers, we should record somehow which one we + * see, because you cannot have twice the same header, except for destination + * We store all this in one u8_t bitmap one bit for each header expected. The + * order in the bitmap is the order recommended in RFC2460 + */ +#define UIP_EXT_HDR_BITMAP_HBHO 0x01 +#define UIP_EXT_HDR_BITMAP_DESTO1 0x02 +#define UIP_EXT_HDR_BITMAP_ROUTING 0x04 +#define UIP_EXT_HDR_BITMAP_FRAG 0x08 +#define UIP_EXT_HDR_BITMAP_AH 0x10 +#define UIP_EXT_HDR_BITMAP_ESP 0x20 +#define UIP_EXT_HDR_BITMAP_DESTO2 0x40 +/** @} */ + + +#endif /* UIP_CONF_IPV6 */ + + +/* Header sizes. */ +#if UIP_CONF_IPV6 +#define UIP_IPH_LEN 40 +#define UIP_FRAGH_LEN 8 +#else /* UIP_CONF_IPV6 */ +#define UIP_IPH_LEN 20 /* Size of IP header */ +#endif /* UIP_CONF_IPV6 */ + +#define UIP_UDPH_LEN 8 /* Size of UDP header */ +#define UIP_TCPH_LEN 20 /* Size of TCP header */ +#ifdef UIP_IPH_LEN +#define UIP_ICMPH_LEN 4 /* Size of ICMP header */ +#endif +#define UIP_IPUDPH_LEN (UIP_UDPH_LEN + UIP_IPH_LEN) /* Size of IP + + * UDP + * header */ +#define UIP_IPTCPH_LEN (UIP_TCPH_LEN + UIP_IPH_LEN) /* Size of IP + + * TCP + * header */ +#define UIP_TCPIP_HLEN UIP_IPTCPH_LEN +#define UIP_IPICMPH_LEN (UIP_IPH_LEN + UIP_ICMPH_LEN) /* size of ICMP + + IP header */ +#define UIP_LLIPH_LEN (UIP_LLH_LEN + UIP_IPH_LEN) /* size of L2 + + IP header */ +#if UIP_CONF_IPV6 +/** + * The sums below are quite used in ND. When used for uip_buf, we + * include link layer length when used for uip_len, we do not, hence + * we need values with and without LLH_LEN we do not use capital + * letters as these values are variable + */ +#define uip_l2_l3_hdr_len (UIP_LLH_LEN + UIP_IPH_LEN + uip_ext_len) +#define uip_l2_l3_icmp_hdr_len (UIP_LLH_LEN + UIP_IPH_LEN + uip_ext_len + UIP_ICMPH_LEN) +#define uip_l3_hdr_len (UIP_IPH_LEN + uip_ext_len) +#define uip_l3_icmp_hdr_len (UIP_IPH_LEN + uip_ext_len + UIP_ICMPH_LEN) +#endif /*UIP_CONF_IPV6*/ + + +#if UIP_FIXEDADDR +CCIF extern const uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr; +#else /* UIP_FIXEDADDR */ +CCIF extern uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr; +#endif /* UIP_FIXEDADDR */ +CCIF extern const uip_ipaddr_t uip_broadcast_addr; +CCIF extern const uip_ipaddr_t uip_all_zeroes_addr; + +#if UIP_FIXEDETHADDR +CCIF extern const uip_lladdr_t uip_lladdr; +#else +CCIF extern uip_lladdr_t uip_lladdr; +#endif + + + + +#ifdef UIP_CONF_IPV6 +/** Length of the link local prefix */ +#define UIP_LLPREF_LEN 10 + +/** + * \brief Is IPv6 address a the unspecified address + * a is of type uip_ipaddr_t + */ +#define uip_is_addr_loopback(a) \ + ((((a)->u16[0]) == 0) && \ + (((a)->u16[1]) == 0) && \ + (((a)->u16[2]) == 0) && \ + (((a)->u16[3]) == 0) && \ + (((a)->u16[4]) == 0) && \ + (((a)->u16[5]) == 0) && \ + (((a)->u16[6]) == 0) && \ + (((a)->u16[7]) == 1)) +/** + * \brief Is IPv6 address a the unspecified address + * a is of type uip_ipaddr_t + */ +#define uip_is_addr_unspecified(a) \ + ((((a)->u16[0]) == 0) && \ + (((a)->u16[1]) == 0) && \ + (((a)->u16[2]) == 0) && \ + (((a)->u16[3]) == 0) && \ + (((a)->u16[4]) == 0) && \ + (((a)->u16[5]) == 0) && \ + (((a)->u16[6]) == 0) && \ + (((a)->u16[7]) == 0)) + +/** \brief Is IPv6 address a the link local all-nodes multicast address */ +#define uip_is_addr_linklocal_allnodes_mcast(a) \ + ((((a)->u8[0]) == 0xff) && \ + (((a)->u8[1]) == 0x02) && \ + (((a)->u16[1]) == 0) && \ + (((a)->u16[2]) == 0) && \ + (((a)->u16[3]) == 0) && \ + (((a)->u16[4]) == 0) && \ + (((a)->u16[5]) == 0) && \ + (((a)->u16[6]) == 0) && \ + (((a)->u8[14]) == 0) && \ + (((a)->u8[15]) == 0x01)) + +/** \brief Is IPv6 address a the link local all-routers multicast address */ +#define uip_is_addr_linklocal_allrouters_mcast(a) \ + ((((a)->u8[0]) == 0xff) && \ + (((a)->u8[1]) == 0x02) && \ + (((a)->u16[1]) == 0) && \ + (((a)->u16[2]) == 0) && \ + (((a)->u16[3]) == 0) && \ + (((a)->u16[4]) == 0) && \ + (((a)->u16[5]) == 0) && \ + (((a)->u16[6]) == 0) && \ + (((a)->u8[14]) == 0) && \ + (((a)->u8[15]) == 0x02)) + +/** + * \brief Checks whether the address a is link local. + * a is of type uip_ipaddr_t + */ +#define uip_is_addr_linklocal(a) \ + ((a)->u8[0] == 0xfe && \ + (a)->u8[1] == 0x80) + +/** \brief set IP address a to unspecified */ +#define uip_create_unspecified(a) uip_ip6addr(a, 0, 0, 0, 0, 0, 0, 0, 0) + +/** \brief set IP address a to the link local all-nodes multicast address */ +#define uip_create_linklocal_allnodes_mcast(a) uip_ip6addr(a, 0xff02, 0, 0, 0, 0, 0, 0, 0x0001) + +/** \brief set IP address a to the link local all-routers multicast address */ +#define uip_create_linklocal_allrouters_mcast(a) uip_ip6addr(a, 0xff02, 0, 0, 0, 0, 0, 0, 0x0002) +#define uip_create_linklocal_prefix(addr) do { \ + (addr)->u16[0] = UIP_HTONS(0xfe80); \ + (addr)->u16[1] = 0; \ + (addr)->u16[2] = 0; \ + (addr)->u16[3] = 0; \ + } while(0) + +/** + * \brief is addr (a) a solicited node multicast address, see RFC3513 + * a is of type uip_ipaddr_t* + */ +#define uip_is_addr_solicited_node(a) \ + ((((a)->u8[0]) == 0xFF) && \ + (((a)->u8[1]) == 0x02) && \ + (((a)->u16[1]) == 0x00) && \ + (((a)->u16[2]) == 0x00) && \ + (((a)->u16[3]) == 0x00) && \ + (((a)->u16[4]) == 0x00) && \ + (((a)->u8[10]) == 0x00) && \ + (((a)->u8[11]) == 0x01) && \ + (((a)->u8[12]) == 0xFF)) + +/** + * \briefput in b the solicited node address corresponding to address a + * both a and b are of type uip_ipaddr_t* + * */ +#define uip_create_solicited_node(a, b) \ + (((b)->u8[0]) = 0xFF); \ + (((b)->u8[1]) = 0x02); \ + (((b)->u16[1]) = 0); \ + (((b)->u16[2]) = 0); \ + (((b)->u16[3]) = 0); \ + (((b)->u16[4]) = 0); \ + (((b)->u8[10]) = 0); \ + (((b)->u8[11]) = 0x01); \ + (((b)->u8[12]) = 0xFF); \ + (((b)->u8[13]) = ((a)->u8[13])); \ + (((b)->u16[7]) = ((a)->u16[7])) + +/** + * \brief is addr (a) a link local unicast address, see RFC3513 + * i.e. is (a) on prefix FE80::/10 + * a is of type uip_ipaddr_t* + */ +#define uip_is_addr_link_local(a) \ + ((((a)->u8[0]) == 0xFE) && \ + (((a)->u8[1]) == 0x80)) + +/** + * \brief was addr (a) forged based on the mac address m + * a type is uip_ipaddr_t + * m type is uiplladdr_t + */ +#if UIP_CONF_LL_802154 +#define uip_is_addr_mac_addr_based(a, m) \ + ((((a)->u8[8]) == (((m)->addr[0]) ^ 0x02)) && \ + (((a)->u8[9]) == (m)->addr[1]) && \ + (((a)->u8[10]) == (m)->addr[2]) && \ + (((a)->u8[11]) == (m)->addr[3]) && \ + (((a)->u8[12]) == (m)->addr[4]) && \ + (((a)->u8[13]) == (m)->addr[5]) && \ + (((a)->u8[14]) == (m)->addr[6]) && \ + (((a)->u8[15]) == (m)->addr[7])) +#else + +#define uip_is_addr_mac_addr_based(a, m) \ + ((((a)->u8[8]) == (((m)->addr[0]) | 0x02)) && \ + (((a)->u8[9]) == (m)->addr[1]) && \ + (((a)->u8[10]) == (m)->addr[2]) && \ + (((a)->u8[11]) == 0xff) && \ + (((a)->u8[12]) == 0xfe) && \ + (((a)->u8[13]) == (m)->addr[3]) && \ + (((a)->u8[14]) == (m)->addr[4]) && \ + (((a)->u8[15]) == (m)->addr[5])) + +#endif /*UIP_CONF_LL_802154*/ + +/** + * \brief is address a multicast address, see RFC 3513 + * a is of type uip_ipaddr_t* + * */ +#define uip_is_addr_mcast(a) \ + (((a)->u8[0]) == 0xFF) + +/** + * \brief is group-id of multicast address a + * the all nodes group-id + */ +#define uip_is_mcast_group_id_all_nodes(a) \ + ((((a)->u16[1]) == 0) && \ + (((a)->u16[2]) == 0) && \ + (((a)->u16[3]) == 0) && \ + (((a)->u16[4]) == 0) && \ + (((a)->u16[5]) == 0) && \ + (((a)->u16[6]) == 0) && \ + (((a)->u8[14]) == 0) && \ + (((a)->u8[15]) == 1)) + +/** + * \brief is group-id of multicast address a + * the all routers group-id + */ +#define uip_is_mcast_group_id_all_routers(a) \ + ((((a)->u16[1]) == 0) && \ + (((a)->u16[2]) == 0) && \ + (((a)->u16[3]) == 0) && \ + (((a)->u16[4]) == 0) && \ + (((a)->u16[5]) == 0) && \ + (((a)->u16[6]) == 0) && \ + (((a)->u8[14]) == 0) && \ + (((a)->u8[15]) == 2)) + + +/** + * \brief are last three bytes of both addresses equal? + * This is used to compare solicited node multicast addresses + */ +#define uip_are_solicited_bytes_equal(a, b) \ + ((((a)->u8[13]) == ((b)->u8[13])) && \ + (((a)->u8[14]) == ((b)->u8[14])) && \ + (((a)->u8[15]) == ((b)->u8[15]))) + +#endif /*UIP_CONF_IPV6*/ + +/** + * Calculate the Internet checksum over a buffer. + * + * The Internet checksum is the one's complement of the one's + * complement sum of all 16-bit words in the buffer. + * + * See RFC1071. + * + * \param buf A pointer to the buffer over which the checksum is to be + * computed. + * + * \param len The length of the buffer over which the checksum is to + * be computed. + * + * \return The Internet checksum of the buffer. + */ +u16_t uip_chksum(u16_t *buf, u16_t len); + +/** + * Calculate the IP header checksum of the packet header in uip_buf. + * + * The IP header checksum is the Internet checksum of the 20 bytes of + * the IP header. + * + * \return The IP header checksum of the IP header in the uip_buf + * buffer. + */ +u16_t uip_ipchksum(void); + +/** + * Calculate the TCP checksum of the packet in uip_buf and uip_appdata. + * + * The TCP checksum is the Internet checksum of data contents of the + * TCP segment, and a pseudo-header as defined in RFC793. + * + * \return The TCP checksum of the TCP segment in uip_buf and pointed + * to by uip_appdata. + */ +u16_t uip_tcpchksum(void); + +/** + * Calculate the UDP checksum of the packet in uip_buf and uip_appdata. + * + * The UDP checksum is the Internet checksum of data contents of the + * UDP segment, and a pseudo-header as defined in RFC768. + * + * \return The UDP checksum of the UDP segment in uip_buf and pointed + * to by uip_appdata. + */ +u16_t uip_udpchksum(void); + +/** + * Calculate the ICMP checksum of the packet in uip_buf. + * + * \return The ICMP checksum of the ICMP packet in uip_buf + */ +u16_t uip_icmp6chksum(void); + + +#endif /* __UIP_H__ */ + + +/** @} */ diff -r 5c8404549cc0 -r 56d09a0969b5 network/uipopt.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/uipopt.h Fri Sep 07 23:53:53 2012 +0800 @@ -0,0 +1,699 @@ +/** + * \addtogroup uip + * @{ + */ + +/** + * \defgroup uipopt Configuration options for uIP + * @{ + * + * uIP is configured using the per-project configuration file + * "uipopt.h". This file contains all compile-time options for uIP and + * should be tweaked to match each specific project. The uIP + * distribution contains a documented example "uipopt.h" that can be + * copied and modified for each project. + * + * \note Contiki does not use the uipopt.h file to configure uIP, but + * uses a per-port uip-conf.h file that should be edited instead. + */ + +/** + * \file + * Configuration options for uIP. + * \author Adam Dunkels + * + * This file is used for tweaking various configuration options for + * uIP. You should make a copy of this file into one of your project's + * directories instead of editing this example "uipopt.h" file that + * comes with the uIP distribution. + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uipopt.h,v 1.14 2010/12/24 00:39:04 dak664 Exp $ + * + */ + +#ifndef __UIPOPT_H__ +#define __UIPOPT_H__ + +#ifndef UIP_LITTLE_ENDIAN +#define UIP_LITTLE_ENDIAN 3412 +#endif /* UIP_LITTLE_ENDIAN */ +#ifndef UIP_BIG_ENDIAN +#define UIP_BIG_ENDIAN 1234 +#endif /* UIP_BIG_ENDIAN */ + +//#include "contiki-conf.h" + +/*------------------------------------------------------------------------------*/ + +/** + * \defgroup uipoptstaticconf Static configuration options + * @{ + * + * These configuration options can be used for setting the IP address + * settings statically, but only if UIP_FIXEDADDR is set to 1. The + * configuration options for a specific node includes IP address, + * netmask and default router as well as the Ethernet address. The + * netmask, default router and Ethernet address are applicable only + * if uIP should be run over Ethernet. + * + * This options are meaningful only for the IPv4 code. + * + * All of these should be changed to suit your project. + */ + +/** + * Determines if uIP should use a fixed IP address or not. + * + * If uIP should use a fixed IP address, the settings are set in the + * uipopt.h file. If not, the macros uip_sethostaddr(), + * uip_setdraddr() and uip_setnetmask() should be used instead. + * + * \hideinitializer + */ +#define UIP_FIXEDADDR 0 + +/** + * Ping IP address assignment. + * + * uIP uses a "ping" packets for setting its own IP address if this + * option is set. If so, uIP will start with an empty IP address and + * the destination IP address of the first incoming "ping" (ICMP echo) + * packet will be used for setting the hosts IP address. + * + * \note This works only if UIP_FIXEDADDR is 0. + * + * \hideinitializer + */ +#ifdef UIP_CONF_PINGADDRCONF +#define UIP_PINGADDRCONF (UIP_CONF_PINGADDRCONF) +#else /* UIP_CONF_PINGADDRCONF */ +#define UIP_PINGADDRCONF 0 +#endif /* UIP_CONF_PINGADDRCONF */ + + +/** + * Specifies if the uIP ARP module should be compiled with a fixed + * Ethernet MAC address or not. + * + * If this configuration option is 0, the macro uip_setethaddr() can + * be used to specify the Ethernet address at run-time. + * + * \hideinitializer + */ +#define UIP_FIXEDETHADDR 0 + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipoptip IP configuration options + * @{ + * + */ +/** + * The IP TTL (time to live) of IP packets sent by uIP. + * + * This should normally not be changed. + */ +#define UIP_TTL 64 + +/** + * The maximum time an IP fragment should wait in the reassembly + * buffer before it is dropped. + * + */ +#define UIP_REASS_MAXAGE 60 /*60s*/ + +/** + * Turn on support for IP packet reassembly. + * + * uIP supports reassembly of fragmented IP packets. This features + * requires an additional amount of RAM to hold the reassembly buffer + * and the reassembly code size is approximately 700 bytes. The + * reassembly buffer is of the same size as the uip_buf buffer + * (configured by UIP_BUFSIZE). + * + * \note IP packet reassembly is not heavily tested. + * + * \hideinitializer + */ +#ifdef UIP_CONF_REASSEMBLY +#define UIP_REASSEMBLY (UIP_CONF_REASSEMBLY) +#else /* UIP_CONF_REASSEMBLY */ +#define UIP_REASSEMBLY 0 +#endif /* UIP_CONF_REASSEMBLY */ +/** @} */ + +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipoptipv6 IPv6 configuration options + * @{ + * + */ + +/** The maximum transmission unit at the IP Layer*/ +#define UIP_LINK_MTU 1280 + +#ifndef UIP_CONF_IPV6 +/** Do we use IPv6 or not (default: no) */ +#define UIP_CONF_IPV6 0 +#endif + +#ifndef UIP_CONF_IPV6_QUEUE_PKT +/** Do we do per %neighbor queuing during address resolution (default: no) */ +#define UIP_CONF_IPV6_QUEUE_PKT 0 +#endif + +#ifndef UIP_CONF_IPV6_CHECKS +/** Do we do IPv6 consistency checks (highly recommended, default: yes) */ +#define UIP_CONF_IPV6_CHECKS 1 +#endif + +#ifndef UIP_CONF_IPV6_REASSEMBLY +/** Do we do IPv6 fragmentation (default: no) */ +#define UIP_CONF_IPV6_REASSEMBLY 0 +#endif + +#ifndef UIP_CONF_NETIF_MAX_ADDRESSES +/** Default number of IPv6 addresses associated to the node's interface */ +#define UIP_CONF_NETIF_MAX_ADDRESSES 3 +#endif + +#ifndef UIP_CONF_ND6_MAX_PREFIXES +/** Default number of IPv6 prefixes associated to the node's interface */ +#define UIP_CONF_ND6_MAX_PREFIXES 3 +#endif + +#ifndef UIP_CONF_ND6_MAX_NEIGHBORS +/** Default number of neighbors that can be stored in the %neighbor cache */ +#define UIP_CONF_ND6_MAX_NEIGHBORS 4 +#endif + +#ifndef UIP_CONF_ND6_MAX_DEFROUTERS +/** Minimum number of default routers */ +#define UIP_CONF_ND6_MAX_DEFROUTERS 2 +#endif +/** @} */ + +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipoptudp UDP configuration options + * @{ + * + * \note The UDP support in uIP is still not entirely complete; there + * is no support for sending or receiving broadcast or multicast + * packets, but it works well enough to support a number of vital + * applications such as DNS queries, though + */ + +/** + * Toggles whether UDP support should be compiled in or not. + * + * \hideinitializer + */ +#ifdef UIP_CONF_UDP +#define UIP_UDP UIP_CONF_UDP +#else /* UIP_CONF_UDP */ +#define UIP_UDP 0 +#endif /* UIP_CONF_UDP */ + +/** + * Toggles if UDP checksums should be used or not. + * + * \note Support for UDP checksums is currently not included in uIP, + * so this option has no function. + * + * \hideinitializer + */ +#ifdef UIP_CONF_UDP_CHECKSUMS +#define UIP_UDP_CHECKSUMS (UIP_CONF_UDP_CHECKSUMS) +#else +#define UIP_UDP_CHECKSUMS (UIP_CONF_IPV6) +#endif + +/** + * The maximum amount of concurrent UDP connections. + * + * \hideinitializer + */ +#ifdef UIP_CONF_UDP_CONNS +#define UIP_UDP_CONNS (UIP_CONF_UDP_CONNS) +#else /* UIP_CONF_UDP_CONNS */ +#define UIP_UDP_CONNS 5 +#endif /* UIP_CONF_UDP_CONNS */ + +/** + * The name of the function that should be called when UDP datagrams arrive. + * + * \hideinitializer + */ + + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipopttcp TCP configuration options + * @{ + */ + +/** + * Toggles whether UDP support should be compiled in or not. + * + * \hideinitializer + */ +#ifdef UIP_CONF_TCP +#define UIP_TCP (UIP_CONF_TCP) +#else /* UIP_CONF_UDP */ +#define UIP_TCP 1 +#endif /* UIP_CONF_UDP */ + +/** + * Determines if support for opening connections from uIP should be + * compiled in. + * + * If the applications that are running on top of uIP for this project + * do not need to open outgoing TCP connections, this configuration + * option can be turned off to reduce the code size of uIP. + * + * \hideinitializer + */ +#ifndef UIP_CONF_ACTIVE_OPEN +#define UIP_ACTIVE_OPEN 1 +#else /* UIP_CONF_ACTIVE_OPEN */ +#define UIP_ACTIVE_OPEN (UIP_CONF_ACTIVE_OPEN) +#endif /* UIP_CONF_ACTIVE_OPEN */ + +/** + * The maximum number of simultaneously open TCP connections. + * + * Since the TCP connections are statically allocated, turning this + * configuration knob down results in less RAM used. Each TCP + * connection requires approximately 30 bytes of memory. + * + * \hideinitializer + */ +#ifndef UIP_CONF_MAX_CONNECTIONS +#define UIP_CONNS 5 +#else /* UIP_CONF_MAX_CONNECTIONS */ +#define UIP_CONNS (UIP_CONF_MAX_CONNECTIONS) +#endif /* UIP_CONF_MAX_CONNECTIONS */ + + +/** + * The maximum number of simultaneously listening TCP ports. + * + * Each listening TCP port requires 2 bytes of memory. + * + * \hideinitializer + */ +#ifndef UIP_CONF_MAX_LISTENPORTS +#define UIP_LISTENPORTS 2 +#else /* UIP_CONF_MAX_LISTENPORTS */ +#define UIP_LISTENPORTS (UIP_CONF_MAX_LISTENPORTS) +#endif /* UIP_CONF_MAX_LISTENPORTS */ + +/** + * Determines if support for TCP urgent data notification should be + * compiled in. + * + * Urgent data (out-of-band data) is a rarely used TCP feature that + * very seldom would be required. + * + * \hideinitializer + */ +#define UIP_URGDATA 0 + +/** + * The initial retransmission timeout counted in timer pulses. + * + * This should not be changed. + */ +#define UIP_RTO 3 + +/** + * The maximum number of times a segment should be retransmitted + * before the connection should be aborted. + * + * This should not be changed. + */ +#define UIP_MAXRTX 8 + +/** + * The maximum number of times a SYN segment should be retransmitted + * before a connection request should be deemed to have been + * unsuccessful. + * + * This should not need to be changed. + */ +#define UIP_MAXSYNRTX 5 + +/** + * The TCP maximum segment size. + * + * This is should not be to set to more than + * UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN. + */ +#ifdef UIP_CONF_TCP_MSS +#define UIP_TCP_MSS (UIP_CONF_TCP_MSS) +#else +#define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN) +#endif + +/** + * The size of the advertised receiver's window. + * + * Should be set low (i.e., to the size of the uip_buf buffer) if the + * application is slow to process incoming data, or high (32768 bytes) + * if the application processes data quickly. + * + * \hideinitializer + */ +#ifndef UIP_CONF_RECEIVE_WINDOW +#define UIP_RECEIVE_WINDOW (UIP_TCP_MSS) +#else +#define UIP_RECEIVE_WINDOW (UIP_CONF_RECEIVE_WINDOW) +#endif + +/** + * How long a connection should stay in the TIME_WAIT state. + * + * This can be reduced for faster entry into power saving modes. + */ +#ifndef UIP_CONF_WAIT_TIMEOUT +#define UIP_TIME_WAIT_TIMEOUT 120 +#else +#define UIP_TIME_WAIT_TIMEOUT UIP_CONF_WAIT_TIMEOUT +#endif + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipoptarp ARP configuration options + * @{ + */ + +/** + * The size of the ARP table. + * + * This option should be set to a larger value if this uIP node will + * have many connections from the local network. + * + * \hideinitializer + */ +#ifdef UIP_CONF_ARPTAB_SIZE +#define UIP_ARPTAB_SIZE (UIP_CONF_ARPTAB_SIZE) +#else +#define UIP_ARPTAB_SIZE 8 +#endif + +/** + * The maximum age of ARP table entries measured in 10ths of seconds. + * + * An UIP_ARP_MAXAGE of 120 corresponds to 20 minutes (BSD + * default). + */ +#define UIP_ARP_MAXAGE 120 + + +/** @} */ + +/*------------------------------------------------------------------------------*/ + +/** + * \defgroup uipoptmac layer 2 options (for ipv6) + * @{ + */ + +#define UIP_DEFAULT_PREFIX_LEN 64 + +/** @} */ + +/*------------------------------------------------------------------------------*/ + +/** + * \defgroup uipoptsics 6lowpan options (for ipv6) + * @{ + */ +/** + * Timeout for packet reassembly at the 6lowpan layer + * (should be < 60s) + */ +#ifdef SICSLOWPAN_CONF_MAXAGE +#define SICSLOWPAN_REASS_MAXAGE (SICSLOWPAN_CONF_MAXAGE) +#else +#define SICSLOWPAN_REASS_MAXAGE 20 +#endif + +/** + * Do we compress the IP header or not (default: no) + */ +#ifndef SICSLOWPAN_CONF_COMPRESSION +#define SICSLOWPAN_CONF_COMPRESSION 0 +#endif + +/** + * If we use IPHC compression, how many address contexts do we support + */ +#ifndef SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS +#define SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS 1 +#endif + +/** + * Do we support 6lowpan fragmentation + */ +#ifndef SICSLOWPAN_CONF_FRAG +#define SICSLOWPAN_CONF_FRAG 0 +#endif + +/** @} */ + +/*------------------------------------------------------------------------------*/ + +/** + * \defgroup uipoptgeneral General configuration options + * @{ + */ + +/** + * The size of the uIP packet buffer. + * + * The uIP packet buffer should not be smaller than 60 bytes, and does + * not need to be larger than 1514 bytes. Lower size results in lower + * TCP throughput, larger size results in higher TCP throughput. + * + * \hideinitializer + */ +#ifndef UIP_CONF_BUFFER_SIZE +#define UIP_BUFSIZE (UIP_LINK_MTU + UIP_LLH_LEN) +#else /* UIP_CONF_BUFFER_SIZE */ +#define UIP_BUFSIZE (UIP_CONF_BUFFER_SIZE) +#endif /* UIP_CONF_BUFFER_SIZE */ + + +/** + * Determines if statistics support should be compiled in. + * + * The statistics is useful for debugging and to show the user. + * + * \hideinitializer + */ +#ifndef UIP_CONF_STATISTICS +#define UIP_STATISTICS 0 +#else /* UIP_CONF_STATISTICS */ +#define UIP_STATISTICS (UIP_CONF_STATISTICS) +#endif /* UIP_CONF_STATISTICS */ + +/** + * Determines if logging of certain events should be compiled in. + * + * This is useful mostly for debugging. The function uip_log() + * must be implemented to suit the architecture of the project, if + * logging is turned on. + * + * \hideinitializer + */ +#ifndef UIP_CONF_LOGGING +#define UIP_LOGGING 0 +#else /* UIP_CONF_LOGGING */ +#define UIP_LOGGING (UIP_CONF_LOGGING) +#endif /* UIP_CONF_LOGGING */ + +/** + * Broadcast support. + * + * This flag configures IP broadcast support. This is useful only + * together with UDP. + * + * \hideinitializer + * + */ +#ifndef UIP_CONF_BROADCAST +#define UIP_BROADCAST 0 +#else /* UIP_CONF_BROADCAST */ +#define UIP_BROADCAST (UIP_CONF_BROADCAST) +#endif /* UIP_CONF_BROADCAST */ + +/** + * Print out a uIP log message. + * + * This function must be implemented by the module that uses uIP, and + * is called by uIP whenever a log message is generated. + */ +void uip_log(char *msg); + +/** + * The link level header length. + * + * This is the offset into the uip_buf where the IP header can be + * found. For Ethernet, this should be set to 14. For SLIP, this + * should be set to 0. + * + * \note we probably won't use this constant for other link layers than + * ethernet as they have variable header length (this is due to variable + * number and type of address fields and to optional security features) + * E.g.: 802.15.4 -> 2 + (1/2*4/8) + 0/5/6/10/14 + * 802.11 -> 4 + (6*3/4) + 2 + * \hideinitializer + */ +#ifdef UIP_CONF_LLH_LEN +#define UIP_LLH_LEN (UIP_CONF_LLH_LEN) +#else /* UIP_LLH_LEN */ +#define UIP_LLH_LEN 0 +#endif /* UIP_CONF_LLH_LEN */ + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipoptcpu CPU architecture configuration + * @{ + * + * The CPU architecture configuration is where the endianess of the + * CPU on which uIP is to be run is specified. Most CPUs today are + * little endian, and the most notable exception are the Motorolas + * which are big endian. The BYTE_ORDER macro should be changed to + * reflect the CPU architecture on which uIP is to be run. + */ + +/** + * The byte order of the CPU architecture on which uIP is to be run. + * + * This option can be either UIP_BIG_ENDIAN (Motorola byte order) or + * UIP_LITTLE_ENDIAN (Intel byte order). + * + * \hideinitializer + */ +#ifdef UIP_CONF_BYTE_ORDER +#define UIP_BYTE_ORDER (UIP_CONF_BYTE_ORDER) +#else /* UIP_CONF_BYTE_ORDER */ +#define UIP_BYTE_ORDER (UIP_LITTLE_ENDIAN) +#endif /* UIP_CONF_BYTE_ORDER */ + +/** @} */ +/*------------------------------------------------------------------------------*/ +#include +// +typedef uint8_t u8_t; +typedef uint16_t u16_t; +typedef uint32_t u32_t; +typedef uint32_t uip_stats_t; +/** + * \defgroup uipoptapp Application specific configurations + * @{ + * + * An uIP application is implemented using a single application + * function that is called by uIP whenever a TCP/IP event occurs. The + * name of this function must be registered with uIP at compile time + * using the UIP_APPCALL definition. + * + * uIP applications can store the application state within the + * uip_conn structure by specifying the type of the application + * structure by typedef:ing the type uip_tcp_appstate_t and uip_udp_appstate_t. + * + * The file containing the definitions must be included in the + * uipopt.h file. + * + * The following example illustrates how this can look. + \code + + void httpd_appcall(void); + #define UIP_APPCALL httpd_appcall + + struct httpd_state { + u8_t state; + u16_t count; + char *dataptr; + char *script; + }; + typedef struct httpd_state uip_tcp_appstate_t + \endcode +*/ + +/** + * \var #define UIP_APPCALL + * + * The name of the application function that uIP should call in + * response to TCP/IP events. + * + */ +#define UIP_APPCALL TCPIP_TCPCallback +void UIP_APPCALL(void); + +/** + * \var typedef uip_tcp_appstate_t + * + * The type of the application state that is to be stored in the + * uip_conn structure. This usually is typedef:ed to a struct holding + * application state information. + */ +typedef struct +{ + uint8_t RESERVED; +} uip_tcp_appstate_t; + +/** + * \var typedef uip_udp_appstate_t + * + * The type of the application state that is to be stored in the + * uip_conn structure. This usually is typedef:ed to a struct holding + * application state information. + */ +typedef struct +{ + uint8_t RESERVED; +} uip_udp_appstate_t; + +/** @} */ + +#endif /* __UIPOPT_H__ */ +/** @} */ +/** @} */